Merge W9C — /spawn-agent skill
This commit is contained in:
commit
4fdb1ec1e3
5 changed files with 687 additions and 0 deletions
131
skills/spawn-agent/SKILL.md
Normal file
131
skills/spawn-agent/SKILL.md
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
name: spawn-agent
|
||||
description: Prepare a composed Agent-tool invocation via kei-spawn. Click-only wizard — pick role, describe task, set scope. Emits ready-to-paste prompt + subagent_type + isolation + DNA.
|
||||
argument-hint: (no arguments)
|
||||
---
|
||||
|
||||
# /spawn-agent — Click-only Agent-tool composer (index)
|
||||
|
||||
You convert a user's intent into a ready-to-paste `Agent`-tool invocation
|
||||
via the `kei-spawn` CLI. Every decision is a click; only the task description
|
||||
(Phase 2) is typed. No git, no side-effects on disk beyond the task.toml the
|
||||
CLI consumes.
|
||||
|
||||
This `SKILL.md` is the INDEX. Each phase lives in its own file and is
|
||||
executed in order. Never skip a phase. Never re-order phases.
|
||||
|
||||
---
|
||||
|
||||
## Pipeline overview
|
||||
|
||||
| Phase | File | Purpose | AskUserQuestion |
|
||||
|---|---|---|---|
|
||||
| 1 | [phase-1-role.md](phase-1-role.md) | Pick agent role (capability tier) | 1× AskUserQuestion |
|
||||
| 2 | [phase-2-task.md](phase-2-task.md) | Free-text task description (ONE paragraph) | 0× (only free-text in the skill) |
|
||||
| 3 | [phase-3-scope.md](phase-3-scope.md) | Files whitelist glob patterns | 2× AskUserQuestion |
|
||||
| 4 | [phase-4-emit.md](phase-4-emit.md) | Write task.toml, run kei-spawn, emit Agent-tool invocation | 1× AskUserQuestion (confirm-emit) |
|
||||
|
||||
**Minimum AskUserQuestion count: 4** — pure-click contract.
|
||||
|
||||
---
|
||||
|
||||
## Variables the pipeline produces
|
||||
|
||||
| Name | Set in | Meaning |
|
||||
|---|---|---|
|
||||
| `ROLE` | Phase 1 | One of `read-only` / `explorer` / `edit-local` / `edit-shared` |
|
||||
| `TASK` | Phase 2 | Free-text task description (1-3 sentences) |
|
||||
| `WHITELIST` | Phase 3 | List of glob patterns (relative to repo root) |
|
||||
| `DENYLIST` | Phase 3 | Optional list of glob patterns (auto-derived from role if skipped) |
|
||||
| `TASK_TOML` | Phase 4 | Path `tasks/<uuid>.toml` relative to current repo |
|
||||
| `AGENT_ID` | Phase 4 | UUID returned by `kei-spawn spawn` |
|
||||
| `DNA` | Phase 4 | SHA-256 fingerprint returned by `kei-spawn spawn` |
|
||||
| `SUBAGENT_TYPE` | Phase 4 | Resolved by kei-spawn from ROLE (e.g. `code-implementer` / `researcher`) |
|
||||
| `ISOLATION` | Phase 4 | Resolved by kei-spawn from ROLE (`worktree` or `shared`) |
|
||||
| `WORKTREE_PATH` | Phase 4 | Returned when isolation=worktree |
|
||||
|
||||
---
|
||||
|
||||
## Role → defaults map (LOAD-BEARING)
|
||||
|
||||
| ROLE | subagent_type | isolation | Bash? | Writes? |
|
||||
|---|---|---|---|---|
|
||||
| read-only | researcher | shared | no | no |
|
||||
| explorer | researcher | shared | read-only bash | no |
|
||||
| edit-local | code-implementer | worktree | cargo/test only | yes (whitelist) |
|
||||
| edit-shared | code-implementer | worktree | cargo/test only | yes (whitelist) |
|
||||
|
||||
`kei-spawn` owns the resolution — this table is reference only. The skill
|
||||
passes the ROLE string verbatim; the CLI returns the resolved values.
|
||||
|
||||
---
|
||||
|
||||
## Final report (emit after Phase 4)
|
||||
|
||||
```
|
||||
=== /SPAWN-AGENT REPORT ===
|
||||
Role: <ROLE>
|
||||
Task (first 80): <first 80 chars of TASK>...
|
||||
Whitelist: <N globs> — <first 3 shown>
|
||||
Denylist: <auto / explicit — N globs>
|
||||
Agent ID: <UUID>
|
||||
DNA: <sha256:first-12>...
|
||||
subagent_type: <SUBAGENT_TYPE>
|
||||
isolation: <ISOLATION>
|
||||
Worktree: <WORKTREE_PATH or n/a>
|
||||
|
||||
Ready-to-paste Agent-tool invocation:
|
||||
|
||||
<JSON block — see phase-4-emit.md §4 for exact shape>
|
||||
|
||||
Next step on return:
|
||||
kei-spawn verify <AGENT_ID> <WORKTREE_PATH>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Runtime binary resolution
|
||||
|
||||
`kei-spawn` must be on `PATH` OR reachable via `$KEI_RUNTIME_BIN_DIR`. The
|
||||
phases call `kei-spawn <cmd>` directly; if the shell returns `command not
|
||||
found`, fall back to `"$KEI_RUNTIME_BIN_DIR/kei-spawn" <cmd>`. If both fail,
|
||||
STOP and surface the error to the user with three constructive paths:
|
||||
|
||||
- (A) Build `kei-spawn` from the kit source (`cd _primitives/_rust/kei-spawn && cargo build --release`).
|
||||
- (B) Export `KEI_RUNTIME_BIN_DIR` to point at an existing build.
|
||||
- (C) Install via `install.sh` which wires both.
|
||||
|
||||
Never silently substitute a mock.
|
||||
|
||||
---
|
||||
|
||||
## Rules (enforced at every phase)
|
||||
|
||||
- **Pure-click contract.** Only `TASK` (Phase 2) is typed. Every other
|
||||
decision is an `AskUserQuestion`. Count them in the final report.
|
||||
- **NO DOWNGRADE (RULE -1).** Any phase that fails returns 2-3 constructive
|
||||
paths, never "can't be done".
|
||||
- **NO HALLUCINATION (RULE 0.4).** Never fabricate a DNA or agent_id — they
|
||||
come from `kei-spawn spawn --format=json` verbatim. Never emit an Agent
|
||||
invocation without a successful spawn call first.
|
||||
- **Plan Mode First (RULE 0.5).** This skill IS the plan; each phase file
|
||||
has its own verify-criterion. No `kei-spawn spawn` call before Phase 4's
|
||||
confirm click.
|
||||
- **Orchestrator branch first (RULE 0.13).** The skill NEVER invokes git.
|
||||
The emitted prompt MUST contain the phrase "MUST NOT invoke git" so the
|
||||
spawned agent respects the rule. Phase 4 inserts this automatically.
|
||||
- **Constructor Pattern (RULE ZERO).** One file per phase. This SKILL.md
|
||||
stays <200 LOC; each phase file stays <200 LOC.
|
||||
- **Surgical Changes.** The skill only writes `tasks/<uuid>.toml`. It does
|
||||
not modify project source, does not commit, does not push.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [phase-1-role.md](phase-1-role.md) · [phase-2-task.md](phase-2-task.md) · [phase-3-scope.md](phase-3-scope.md) · [phase-4-emit.md](phase-4-emit.md)
|
||||
- `_primitives/_rust/kei-spawn/` — CLI source (task.toml schema + spawn/verify commands)
|
||||
- `skills/new-agent/SKILL.md` — sister skill: generates agent *manifests*; this skill spawns *instances* of existing agents
|
||||
- `skills/hooks-control/SKILL.md` — reference click-only pattern
|
||||
- RULE 0.12 (agent-git-model) — ledger row auto-written by `kei-spawn spawn`
|
||||
- RULE 0.13 (orchestrator-branch-first) — ban-phrase injected by Phase 4
|
||||
84
skills/spawn-agent/phase-1-role.md
Normal file
84
skills/spawn-agent/phase-1-role.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Phase 1 — Role selection
|
||||
|
||||
> Goal: pick the agent role (capability tier). This single choice resolves
|
||||
> `subagent_type` + `isolation` + Bash/Write permissions via `kei-spawn`.
|
||||
> **Verify criterion:** `ROLE` set to one of the four fixed labels.
|
||||
|
||||
---
|
||||
|
||||
## 1.a — Single AskUserQuestion
|
||||
|
||||
Send ONE `AskUserQuestion` call. `multiSelect: false`. Do NOT fall through
|
||||
to a default — the user must click.
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "Agent role / capability tier?",
|
||||
"header": "Role",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{
|
||||
"label": "read-only",
|
||||
"description": "Researcher. Read + Grep + Glob only. No Bash. No writes. Shared worktree. Use for: literature lookup, prior art, code exploration reports."
|
||||
},
|
||||
{
|
||||
"label": "explorer",
|
||||
"description": "Researcher + read-only Bash (ls, cat, rg, git log — no state changes). Shared worktree. Use for: audits, diagnostics, benchmark snapshots."
|
||||
},
|
||||
{
|
||||
"label": "edit-local",
|
||||
"description": "Code-implementer with worktree isolation. Can Write/Edit within a narrow whitelist (usually one module). Bash limited to cargo/test runners. Use for: single-crate changes, localized refactors."
|
||||
},
|
||||
{
|
||||
"label": "edit-shared",
|
||||
"description": "Code-implementer with worktree isolation + broader whitelist (multiple modules / cross-cutting). Bash limited to cargo/test. Use for: workspace-wide refactors, feature-slice work touching ≥2 crates."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Store the clicked label verbatim as `ROLE`.
|
||||
|
||||
---
|
||||
|
||||
## 1.b — Guidance (for the user, shown WITH the question)
|
||||
|
||||
Before sending the question, print one short paragraph:
|
||||
|
||||
> Pick the capability tier. Read-only and explorer never modify disk and
|
||||
> are cheap to spawn. Edit-local and edit-shared get their own git worktree
|
||||
> (per RULE 0.12) and inherit a Bash allowlist restricted to test runners.
|
||||
> If unsure, pick `explorer` — it's the safest writeable-ish tier and
|
||||
> covers most audit / diagnostic requests.
|
||||
|
||||
---
|
||||
|
||||
## 1.c — Verify criterion
|
||||
|
||||
`ROLE ∈ {read-only, explorer, edit-local, edit-shared}`. If the user
|
||||
dismissed the question or picked something else, loop back. Do NOT proceed
|
||||
to Phase 2 without ROLE set.
|
||||
|
||||
Emit a single-line confirmation: `Role locked: <ROLE>`. Proceed to Phase 2.
|
||||
|
||||
---
|
||||
|
||||
## 1.d — Failure paths (NO DOWNGRADE)
|
||||
|
||||
If the user wants a role outside the four fixed tiers (e.g. "I want a
|
||||
writer with full Bash"):
|
||||
|
||||
- (A) Explain that the 4 tiers are the full capability grid in `kei-spawn`
|
||||
— anything else would need a new role added to the CLI. Offer to open
|
||||
a task for that.
|
||||
- (B) Suggest the closest existing tier (usually `edit-shared` with a
|
||||
broader whitelist covers 90% of "I need more power" requests).
|
||||
- (C) Abort this skill invocation and escalate to `/new-agent` if the user
|
||||
actually needs a new *agent manifest*, not a new *role tier*.
|
||||
|
||||
Never invent a fifth tier. `kei-spawn` will reject any ROLE not in the
|
||||
fixed set.
|
||||
91
skills/spawn-agent/phase-2-task.md
Normal file
91
skills/spawn-agent/phase-2-task.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Phase 2 — Task description (the only typed phase)
|
||||
|
||||
> Goal: capture a 1-3 sentence task description. This is the SOLE free-text
|
||||
> input in the skill.
|
||||
> **Verify criterion:** `TASK` non-empty, ≤2000 chars, not a single word.
|
||||
|
||||
---
|
||||
|
||||
## 2.a — Prompt
|
||||
|
||||
Print this exact message to the user (NOT an AskUserQuestion — regular chat):
|
||||
|
||||
> Describe the task in 1-3 sentences. Be concrete about the deliverable.
|
||||
>
|
||||
> Good: "Add a --verbose flag to kei-ledger list that prints the parent_branch and dna columns. Update the integration test accordingly."
|
||||
>
|
||||
> Weak: "Improve ledger output" (too vague, agent will ask clarifying questions and burn turns).
|
||||
>
|
||||
> Excellent tasks name: (1) the target file or module, (2) the verifiable
|
||||
> deliverable, (3) any existing pattern to mirror.
|
||||
|
||||
Wait for the user's reply. Capture the full message as `TASK`.
|
||||
|
||||
---
|
||||
|
||||
## 2.b — Validation
|
||||
|
||||
Apply these checks in order. On any failure, re-print the guidance and
|
||||
ask again. Do NOT fall through to Phase 3 on failure.
|
||||
|
||||
1. **Non-empty.** `len(TASK.trim()) > 0`.
|
||||
2. **Minimum length.** `len(TASK.trim()) >= 20`. Shorter than 20 chars is
|
||||
almost certainly a single-word request — ask for more detail.
|
||||
3. **Maximum length.** `len(TASK) <= 2000`. If longer, ask the user to
|
||||
trim: `kei-spawn` accepts up to 4000 chars but tasks >2000 typically
|
||||
indicate the user is trying to write the agent's plan for it. Push back.
|
||||
4. **No secrets.** Quick regex scan for `sk-`, `ghp_`, `Bearer `, `AKIA`,
|
||||
`xoxb-`, `-----BEGIN`, `:AAG` (Telegram bot token infix). If any hits,
|
||||
STOP and ask the user to remove — tokens belong in `~/.claude/secrets/.env`
|
||||
per RULE 0.8, never in task descriptions.
|
||||
5. **No git commands.** If `TASK` contains `git commit`, `git push`,
|
||||
`git add`, `git merge`, warn the user that per RULE 0.13 the spawned
|
||||
agent will be explicitly banned from git — if the task REQUIRES git
|
||||
operations, this skill is the wrong tool (use `/new-project` or
|
||||
orchestrator-meta flow instead).
|
||||
|
||||
---
|
||||
|
||||
## 2.c — Auto-augmentation
|
||||
|
||||
Before storing `TASK`, prepend a fixed preamble so the spawned agent sees
|
||||
the orchestrator-branch-first rule verbatim. This is NOT optional — RULE
|
||||
0.13 requires the ban-phrase in every non-trivial agent prompt:
|
||||
|
||||
```
|
||||
You MUST NOT invoke git, bash state-changing commands, or shell commands
|
||||
that mutate the repo. Tools allowed: Read, Write, Edit, Glob, Grep (plus
|
||||
read-only Bash for explorer role; test-runners only for edit-* roles).
|
||||
Write files to the paths inside the whitelist. Return a file-list block
|
||||
in your final report. Orchestrator owns git.
|
||||
|
||||
--- TASK ---
|
||||
|
||||
<user's TASK here, verbatim>
|
||||
```
|
||||
|
||||
Store the composed prompt as `TASK_FULL`. Keep the raw user text as
|
||||
`TASK` for the report.
|
||||
|
||||
---
|
||||
|
||||
## 2.d — Verify criterion
|
||||
|
||||
Both `TASK` and `TASK_FULL` populated. `TASK` passes all 5 validation
|
||||
checks. Emit a single-line confirmation:
|
||||
|
||||
`Task captured: <first 60 chars of TASK>... (<N> chars)`
|
||||
|
||||
Proceed to Phase 3.
|
||||
|
||||
---
|
||||
|
||||
## 2.e — Failure paths (NO DOWNGRADE)
|
||||
|
||||
If the user cannot articulate the task after two prompts:
|
||||
|
||||
- (A) Suggest invoking `/research` or `/debug-deep` first to clarify the
|
||||
problem, then return to `/spawn-agent` once the deliverable is concrete.
|
||||
- (B) Offer to scaffold a skeleton task description from the user's rough
|
||||
words — show the skeleton, ask for approval.
|
||||
- (C) Abort this invocation — better no agent than a confused one.
|
||||
163
skills/spawn-agent/phase-3-scope.md
Normal file
163
skills/spawn-agent/phase-3-scope.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
# Phase 3 — Scope (files whitelist + optional denylist)
|
||||
|
||||
> Goal: produce a concrete `WHITELIST` (glob patterns the agent may touch)
|
||||
> and optionally an explicit `DENYLIST`. For read-only / explorer roles
|
||||
> the whitelist is advisory; for edit-* roles it is ENFORCED by kei-spawn.
|
||||
> **Verify criterion:** `WHITELIST` non-empty list of glob strings.
|
||||
|
||||
---
|
||||
|
||||
## 3.a — First AskUserQuestion: scope preset
|
||||
|
||||
Send ONE `AskUserQuestion` call. Presets cover ≥80% of real invocations;
|
||||
pick "Custom" only if none fit.
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "Scope preset?",
|
||||
"header": "Scope",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{
|
||||
"label": "Single crate (Rust)",
|
||||
"description": "crates/<name>/** — typical edit-local scope. Also includes that crate's tests/ and Cargo.toml."
|
||||
},
|
||||
{
|
||||
"label": "Single skill (Markdown)",
|
||||
"description": "skills/<name>/** — pure-markdown skill authoring. No code compilation."
|
||||
},
|
||||
{
|
||||
"label": "Single agent manifest",
|
||||
"description": "agents/_manifests/<name>.toml + agents/_blocks/*.md — agent fleet authoring."
|
||||
},
|
||||
{
|
||||
"label": "Docs / rules only",
|
||||
"description": "**/*.md — read-only or explorer roles that only touch documentation."
|
||||
},
|
||||
{
|
||||
"label": "Whole project (read-only)",
|
||||
"description": "** — read-only or explorer roles. Not valid for edit-* (too broad; use edit-shared with explicit globs)."
|
||||
},
|
||||
{
|
||||
"label": "Custom",
|
||||
"description": "Enter glob patterns as one free-text line (comma- or newline-separated)."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Store the clicked label as `SCOPE_PRESET`.
|
||||
|
||||
---
|
||||
|
||||
## 3.b — Resolve preset to `WHITELIST`
|
||||
|
||||
- **Single crate (Rust)** → follow up with ONE free-text prompt: `Crate name?`
|
||||
Validate `[a-z0-9-]+`. Build: `[ "crates/<name>/**", "Cargo.toml" ]`.
|
||||
- **Single skill (Markdown)** → follow up: `Skill name?` Validate `[a-z0-9-]+`.
|
||||
Build: `[ "skills/<name>/**" ]`.
|
||||
- **Single agent manifest** → follow up: `Agent name?` Validate `[a-z0-9-]+`.
|
||||
Build: `[ "agents/_manifests/<name>.toml", "agents/_blocks/*.md" ]`.
|
||||
- **Docs / rules only** → Build: `[ "**/*.md" ]`. Warn if ROLE is edit-* —
|
||||
docs-only edits rarely need worktree isolation; suggest `explorer` or
|
||||
`read-only` instead.
|
||||
- **Whole project (read-only)** → BLOCK if ROLE is edit-local or edit-shared.
|
||||
Print: "Whole-project scope is not allowed for edit roles. Use edit-shared
|
||||
with explicit globs naming the ≥2 modules you will touch." Loop back to 3.a.
|
||||
Otherwise build: `[ "**" ]`.
|
||||
- **Custom** → follow up: `Enter glob patterns (comma- or newline-separated).`
|
||||
Parse, trim, validate each glob against the rules in 3.c. Build the list.
|
||||
|
||||
---
|
||||
|
||||
## 3.c — Glob validation rules
|
||||
|
||||
Apply to every pattern in `WHITELIST`:
|
||||
|
||||
1. **No absolute paths.** Must not start with `/` or `~/`. globs are
|
||||
repo-relative.
|
||||
2. **No parent traversal.** Reject any pattern containing `..`.
|
||||
3. **No leading dot-dir unless explicit.** `.git/**`, `.claude/**` must
|
||||
be typed in full; reject accidental `.**`.
|
||||
4. **At least one literal char.** Reject `**` alone without a scoping prefix
|
||||
unless ROLE is read-only or explorer AND SCOPE_PRESET was "Whole project".
|
||||
5. **Max count.** ≤20 globs. If the user pastes more, ask them to consolidate.
|
||||
|
||||
On any failure, print the offending pattern and the rule that tripped;
|
||||
re-prompt for that one line; do NOT fall through.
|
||||
|
||||
---
|
||||
|
||||
## 3.d — Second AskUserQuestion: explicit denylist?
|
||||
|
||||
Send the second `AskUserQuestion` call:
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "Denylist?",
|
||||
"header": "Deny",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{
|
||||
"label": "Auto (recommended)",
|
||||
"description": "kei-spawn applies the role-default denylist: secrets/**, **/*.env, target/**, node_modules/**, .git/**, dist/**, .keisei/** — covers 95% of cases."
|
||||
},
|
||||
{
|
||||
"label": "Explicit",
|
||||
"description": "Enter additional deny globs on top of the auto default. Use when the task whitelist accidentally includes sensitive subpaths."
|
||||
},
|
||||
{
|
||||
"label": "None (override auto)",
|
||||
"description": "Override the auto defaults and pass an empty denylist. BLOCKED for edit-* roles — read-only / explorer only."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Resolve:
|
||||
|
||||
- **Auto** → `DENYLIST = []`, let `kei-spawn` apply its role defaults. Most
|
||||
common path.
|
||||
- **Explicit** → follow up: `Enter deny globs (comma- or newline-separated).`
|
||||
Validate via 3.c rules. `DENYLIST = [ "<user globs>" ]`. `kei-spawn` will
|
||||
UNION these with the role defaults (not replace).
|
||||
- **None (override auto)** → if ROLE ∈ {edit-local, edit-shared} BLOCK and
|
||||
loop back. Otherwise set a marker `DENYLIST_OVERRIDE = true`; Phase 4
|
||||
will pass `--no-default-deny` to `kei-spawn`. Warn the user that this
|
||||
disables the `secrets/**` and `.env` safety nets.
|
||||
|
||||
---
|
||||
|
||||
## 3.e — Verify criterion
|
||||
|
||||
- `WHITELIST` is a non-empty list (length ≥ 1).
|
||||
- Every pattern passes 3.c validation.
|
||||
- `DENYLIST` resolved (may be empty list — Auto path).
|
||||
- If ROLE is edit-* and WHITELIST == `[ "**" ]`, REJECT and loop to 3.a.
|
||||
|
||||
Emit confirmation:
|
||||
|
||||
`Scope locked: <N> whitelist globs, deny=<auto|explicit:N|override>`
|
||||
|
||||
Proceed to Phase 4.
|
||||
|
||||
---
|
||||
|
||||
## 3.f — Failure paths (NO DOWNGRADE)
|
||||
|
||||
If the user cannot choose a preset and Custom produces invalid globs twice:
|
||||
|
||||
- (A) Offer to inspect the current repo with `rg --files | head -50` and
|
||||
propose 2-3 concrete whitelists based on what's actually there.
|
||||
- (B) Suggest downgrading ROLE from `edit-shared` to `explorer` — explorer
|
||||
accepts `[ "**" ]` and still reads everything, without write risk.
|
||||
- (C) Abort this invocation and ask the user to run `/spawn-agent` again
|
||||
once the target files are clearer.
|
||||
218
skills/spawn-agent/phase-4-emit.md
Normal file
218
skills/spawn-agent/phase-4-emit.md
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
# Phase 4 — Write task.toml, spawn via kei-spawn, emit Agent-tool invocation
|
||||
|
||||
> Goal: serialize `ROLE / TASK_FULL / WHITELIST / DENYLIST` into a
|
||||
> `task.toml`, call `kei-spawn spawn --format=json`, parse the JSON, and
|
||||
> emit a ready-to-paste Agent-tool invocation. One confirm click before
|
||||
> the spawn call (it writes a ledger row).
|
||||
> **Verify criterion:** `AGENT_ID`, `DNA`, `SUBAGENT_TYPE`, `ISOLATION`
|
||||
> all set; Agent-tool invocation printed.
|
||||
|
||||
---
|
||||
|
||||
## 4.a — Compute `TASK_TOML` path
|
||||
|
||||
Generate a short UUID (v4, first 8 hex chars is sufficient — kei-spawn
|
||||
validates uniqueness on write). Path:
|
||||
|
||||
```
|
||||
tasks/<uuid8>.toml
|
||||
```
|
||||
|
||||
Relative to the current repo root. If `tasks/` does not exist, do NOT
|
||||
create it from this skill — `kei-spawn spawn` will fail loudly and the
|
||||
constructive path is to run `mkdir tasks && git add tasks/.gitkeep` in
|
||||
the orchestrator session.
|
||||
|
||||
---
|
||||
|
||||
## 4.b — Render task.toml
|
||||
|
||||
Use this exact schema (verify against `_primitives/_rust/kei-spawn/src/task.rs`
|
||||
before any drift; if the CLI schema changes, this phase file updates too):
|
||||
|
||||
```toml
|
||||
# Generated by /spawn-agent skill — do not hand-edit.
|
||||
# kei-spawn consumes this file; the spawn ceremony writes a ledger row
|
||||
# (RULE 0.12) and returns agent_id + dna in JSON.
|
||||
|
||||
role = "<ROLE>"
|
||||
|
||||
task = """
|
||||
<TASK_FULL verbatim, triple-quoted>
|
||||
"""
|
||||
|
||||
[scope]
|
||||
whitelist = [
|
||||
"<glob 1>",
|
||||
"<glob 2>",
|
||||
# ...
|
||||
]
|
||||
denylist = [
|
||||
# empty if Auto; populated if Explicit; absent if Override (see 4.c)
|
||||
]
|
||||
```
|
||||
|
||||
TOML rules:
|
||||
|
||||
- Use triple-quoted `"""..."""` for `task` so newlines in TASK_FULL survive.
|
||||
- Escape any triple-quote inside TASK_FULL as `\"\"\"` (unlikely but
|
||||
validate before write).
|
||||
- Every whitelist entry is a TOML string (double-quoted, 4-space indented,
|
||||
trailing comma).
|
||||
- If `DENYLIST_OVERRIDE = true` from Phase 3.d, OMIT the `denylist` key
|
||||
entirely — `kei-spawn` distinguishes "empty list" (union with defaults)
|
||||
from "absent" (no defaults applied) via the `--no-default-deny` flag
|
||||
passed in 4.d.
|
||||
|
||||
Write the file via the `Write` tool.
|
||||
|
||||
---
|
||||
|
||||
## 4.c — Confirm-emit click
|
||||
|
||||
Send ONE `AskUserQuestion` before calling `kei-spawn`:
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "Spawn agent with this configuration?",
|
||||
"header": "Confirm",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{
|
||||
"label": "Yes — spawn now",
|
||||
"description": "Writes ledger row, returns agent_id + DNA + subagent_type + isolation. The Agent-tool invocation will be emitted for you to paste."
|
||||
},
|
||||
{
|
||||
"label": "No — show me the task.toml first",
|
||||
"description": "Print the generated tasks/<uuid>.toml contents verbatim, then re-ask."
|
||||
},
|
||||
{
|
||||
"label": "Abort",
|
||||
"description": "Delete the task.toml and exit the skill."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Resolve:
|
||||
|
||||
- **Yes** → proceed to 4.d.
|
||||
- **No** → Read the file back and print it in a fenced code block; loop
|
||||
the same AskUserQuestion.
|
||||
- **Abort** → delete `tasks/<uuid>.toml` and emit a short summary: no
|
||||
spawn, no ledger row, no Agent invocation.
|
||||
|
||||
---
|
||||
|
||||
## 4.d — Run kei-spawn
|
||||
|
||||
Call exactly one command (no chaining, so errors surface cleanly):
|
||||
|
||||
```bash
|
||||
kei-spawn spawn tasks/<uuid>.toml --format=json
|
||||
```
|
||||
|
||||
If `DENYLIST_OVERRIDE = true`, append `--no-default-deny`.
|
||||
|
||||
If `kei-spawn` is not on PATH, fall back to `"$KEI_RUNTIME_BIN_DIR/kei-spawn"`.
|
||||
If both fail, surface the SKILL.md runtime-resolution paths (A/B/C) and
|
||||
STOP — do NOT fabricate a response.
|
||||
|
||||
Parse the stdout JSON. Expected shape (exact field names per
|
||||
`_primitives/_rust/kei-spawn/src/spawn.rs`):
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_id": "6a48ca7b-...",
|
||||
"dna": "sha256:b37e2d1e9a...",
|
||||
"subagent_type": "code-implementer",
|
||||
"isolation": "worktree",
|
||||
"worktree_path": ".claude/worktrees/agent-6a48ca7b",
|
||||
"branch": "agent/<slug>-<ts>"
|
||||
}
|
||||
```
|
||||
|
||||
Store each field as named (`AGENT_ID`, `DNA`, `SUBAGENT_TYPE`, `ISOLATION`,
|
||||
`WORKTREE_PATH`, `BRANCH`). If `isolation == "shared"`, `worktree_path`
|
||||
and `branch` may be absent — handle that gracefully.
|
||||
|
||||
On non-zero exit from `kei-spawn`: print stderr verbatim, surface the
|
||||
error, offer three constructive paths:
|
||||
|
||||
- (A) Fix the task.toml and re-spawn (show the diff first).
|
||||
- (B) Fall back to a smaller scope (loop back to Phase 3).
|
||||
- (C) Abort — delete task.toml, no ledger row written.
|
||||
|
||||
---
|
||||
|
||||
## 4.e — Emit the Agent-tool invocation
|
||||
|
||||
Print a single fenced code block with the ready-to-paste JSON. Use the
|
||||
Agent tool's exact parameter names:
|
||||
|
||||
```json
|
||||
{
|
||||
"subagent_type": "<SUBAGENT_TYPE>",
|
||||
"description": "<first 60 chars of TASK>",
|
||||
"prompt": "<TASK_FULL verbatim, with the orchestrator-branch-first preamble>",
|
||||
"isolation": "<ISOLATION>"
|
||||
}
|
||||
```
|
||||
|
||||
Plus a short annotation under the block:
|
||||
|
||||
```
|
||||
Agent ID: <AGENT_ID>
|
||||
DNA: <DNA>
|
||||
Branch: <BRANCH or n/a for shared>
|
||||
Worktree: <WORKTREE_PATH or n/a>
|
||||
|
||||
Paste the JSON above into an Agent tool call. On return, run:
|
||||
|
||||
kei-spawn verify <AGENT_ID> <WORKTREE_PATH>
|
||||
|
||||
to check the 6-file artefact bundle (RULE 0.12) and merge-readiness.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4.f — Final report
|
||||
|
||||
Emit the SKILL.md-defined `=== /SPAWN-AGENT REPORT ===` block. Populate
|
||||
every field from the variables above. Do NOT invent any field value — if
|
||||
something is absent (e.g. worktree for shared isolation), print `n/a`.
|
||||
|
||||
---
|
||||
|
||||
## 4.g — Verify criterion
|
||||
|
||||
- `AGENT_ID` non-empty UUID
|
||||
- `DNA` non-empty sha256 prefix
|
||||
- `SUBAGENT_TYPE ∈ {researcher, code-implementer, ...}` (whatever kei-spawn
|
||||
returns — the skill does not enforce a specific set)
|
||||
- `ISOLATION ∈ {shared, worktree}`
|
||||
- The Agent-tool invocation JSON is printed in a fenced block
|
||||
- `TASK_FULL` in the `prompt` field contains the literal phrase
|
||||
`MUST NOT invoke git` (RULE 0.13 ban-phrase — added in Phase 2.c)
|
||||
|
||||
If the ban-phrase check fails (should be impossible after Phase 2.c), STOP
|
||||
and surface a bug report — do NOT emit the invocation.
|
||||
|
||||
---
|
||||
|
||||
## 4.h — Failure paths (NO DOWNGRADE)
|
||||
|
||||
Covered inline in 4.d. Additionally, if the user tries to paste the
|
||||
emitted JSON but the Agent tool rejects it:
|
||||
|
||||
- (A) Likely `subagent_type` mismatch — run `kei-spawn roles` to list
|
||||
valid subagent_type values in the current runtime and reconcile.
|
||||
- (B) Likely `isolation` unsupported in the caller's Claude Code version
|
||||
— fall back to `shared` and loop back to Phase 1 to re-pick a
|
||||
read-only / explorer role.
|
||||
- (C) Escalate to `/new-agent` if the user actually needs a new agent
|
||||
manifest rather than a new instance.
|
||||
Loading…
Reference in a new issue