diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index de6e31c..9787ad8 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,14 +7,14 @@ }, "metadata": { "description": "ERPAVal — autonomous software development workflow for Claude Code.", - "version": "1.2.0" + "version": "1.3.0" }, "plugins": [ { "name": "erpaval", "source": "./", "description": "Six-phase Explore/Research/Plan/Act/Validate/Compound workflow with classifier-driven routing and a compounding lessons store.", - "version": "1.2.0", + "version": "1.3.0", "author": { "name": "Laith Al-Saadoon" }, "homepage": "https://github.com/theagenticguy/erpaval", "repository": "https://github.com/theagenticguy/erpaval", diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 1da8640..9b94ea9 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "erpaval", - "version": "1.2.0", + "version": "1.3.0", "description": "ERPAVal — autonomous software development workflow for Claude Code. Comprehensive standalone bundle: the erpaval workflow plus 10 vendored companion skills (product-discovery, research, ultraplan, tech-stack-builder, product-strategy, working-backwards, customer-research, meta-prompt-optimizer, product-design-shared, agent-ux-patterns) so the six-phase Explore/Research/Plan/Act/Validate/Compound loop routes resolve out of the box. Designed to be forked.", "author": { "name": "Laith Al-Saadoon" diff --git a/.erpaval/solutions/api-patterns/kiro-cli-port-playbook.md b/.erpaval/solutions/api-patterns/kiro-cli-port-playbook.md index ff96cc2..8d80c5e 100644 --- a/.erpaval/solutions/api-patterns/kiro-cli-port-playbook.md +++ b/.erpaval/solutions/api-patterns/kiro-cli-port-playbook.md @@ -21,8 +21,10 @@ pattern: | - Hook events: SessionStart→agentSpawn, PostToolUse→postToolUse, Stop→stop, PreToolUse→preToolUse, UserPromptSubmit→userPromptSubmit - Subagents: `.kiro/agents/.json` + `subagent` built-in tool, max 4 parallel - - Tools: fs_read↔Read, fs_write↔Write+Edit, execute_bash↔Bash, glob↔Glob, - grep↔Grep, web_fetch↔WebFetch, web_search↔WebSearch + - Tools (emit the canonical Kiro names; `fs_*`/`execute_bash`/`use_aws` are + deprecated Q-era aliases that still resolve): read↔Read, write↔Write+Edit, + shell↔Bash, aws↔(no CC equiv), glob↔Glob, grep↔Grep, web_fetch↔WebFetch, + web_search↔WebSearch ### Folder renames (3 of them) - `templates/` → `assets/` @@ -46,8 +48,11 @@ pattern: | to act. Acceptable degradation. - Task dependencies: Kiro `/todo` lacks `addBlockedBy` / status workflow. Use filesystem state in task packets as authoritative, `/todo` for UI mirror. - - `Edit` tool: Kiro has no separate Edit. `fs_write` overwrites. Hook matchers - target `fs_write` only. + - `Edit` tool: Kiro has no separate Edit. The `write` tool overwrites. Hook + matchers target `write` only. + - `postToolUse` cannot block: a `postToolUse` validation hook can only warn, + not reject a write. For hard rejection, move the check to `preToolUse` + + exit code 2 (Kiro's single blocking path). - SessionEnd / SubagentStop / PreCompact / Notification hooks: not present in Kiro. erpaval doesn't use them, so no shim needed. diff --git a/.erpaval/solutions/best-practices/kiro-subagent-vs-spawn-summary-return-path.md b/.erpaval/solutions/best-practices/kiro-subagent-vs-spawn-summary-return-path.md index 107ac0a..22138ec 100644 --- a/.erpaval/solutions/best-practices/kiro-subagent-vs-spawn-summary-return-path.md +++ b/.erpaval/solutions/best-practices/kiro-subagent-vs-spawn-summary-return-path.md @@ -39,9 +39,14 @@ pattern: | can return to later."* - **Not for orchestrator-driven delegation.** - ### Failure mode: silent "No result" - Symptoms: a subagent dispatch returns `Pipeline completed ... No result` - or an empty summary, even though the configs look correct. + ### Failure mode: silent empty / "No result" + Symptoms: a subagent dispatch returns an empty summary (observed as + `Pipeline completed ... No result` in practice), even though the configs + look correct. NOTE: the literal string "No result" is an empirical + observation, not documented in current kiro.dev docs (the Q ancestor used + "Summary unavailable - see full details in agent execution file"), and may + vary by Kiro version. Don't pattern-match on the exact string — treat any + empty/missing summary as this failure class. The fix is the same regardless. Common causes: 1. **Subagent finished without calling `summary`.** The summary tool is @@ -81,7 +86,7 @@ pattern: | And on each subagent: ```json { - "tools": ["fs_read", "grep", "glob", "execute_bash", "..."], + "tools": ["read", "grep", "glob", "shell", "..."], "allowedTools": ["*"] } ``` diff --git a/.gitignore b/.gitignore index 3dec545..a7b16a5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__/ *.pyo .DS_Store .erpaval/sessions/ +research/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e360aa..3442107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,41 @@ # Changelog +## 1.3.0 — 2026-05-29 · Kiro mirror refresh (latest CLI) + +Refresh of the `kiro/` Claude Code → Kiro CLI port to track the latest +Kiro CLI features, backed by a `/research` pass over kiro.dev docs +(captured findings: fan-out, hooks, subagents, agent-config surface as +of 2026-05-29). + +- Modernized built-in tool names across all three agent JSONs and every + hook matcher: `fs_read`→`read`, `fs_write`→`write`, + `execute_bash`→`shell`, `use_aws`→`aws`. The Q-era aliases still + resolve, but the canonical names are forward-safe. The + `kiro_validate_packet.py` runtime check accepts both spellings. +- Dropped the experimental `delegate` tool from the orchestrator and + researcher agents — Kiro is replacing it with the official `subagent` + tool (already wired). +- `postToolUse` packet validation documented as **advisory** — Kiro + `postToolUse` cannot block, so a malformed `.erpaval/` packet is + warned, not rejected (move to `preToolUse` + exit 2 for hard + rejection). Updated KIRO-COMPATIBILITY, AGENTS, SKILL mirror, and + context-packets to match. +- Orchestrator prompt adopts the latest subagent patterns: the 4-per- + DAG-level concurrency cap, v2.5.0 in-pipeline review loops for the + Act→Validate→re-Act cycle, and v2.3 `$AGENT_DISPLAY_OUT` / + `$AGENT_CONTEXT_OUT` progress side-channels (alongside `wc -l` / + Ctrl+G monitoring). +- KIRO-COMPATIBILITY headline + hook table rewritten for the nuanced + capability map (shell-only hooks, single blocking path, prompt-based + hooks gap), with a dated "re-check the changelog" caveat and a + `KIRO_HOME` note. +- Corrected two lessons-store assumptions: the literal "No result" + subagent string is an empirical observation, not documented (don't + pattern-match on it); `/spawn --name` labels the session, not an agent + (already reflected in the runbook). +- Synced `kiro/install.sh` `ERPAVAL_VERSION` (was stranded at 1.1.1). +- Bump 1.2.0 → 1.3.0 (plugin.json + marketplace.json + install.sh). + ## 1.2.0 — 2026-05-29 · fan-out + grounding sync Sync of the upstream `erpaval` and `product-discovery` skills, porting diff --git a/kiro/AGENTS.md b/kiro/AGENTS.md index b0c920d..d005b68 100644 --- a/kiro/AGENTS.md +++ b/kiro/AGENTS.md @@ -50,7 +50,9 @@ kiro-cli chat --agent erpaval-orchestrator --trust-all-tools `--trust-all-tools` auto-approves every tool call so subagents can write, shell out, and call MCP servers without prompting. For unattended runs add `--no-interactive` and set `KIRO_API_KEY`. For least-privilege scoping use -`--trust-tools=read,grep,glob,write,execute_bash` instead. +`--trust-tools=read,grep,glob,write,shell` instead. (Trusted-command matching +is a prefix string match, so prefer scoped `allowedTools` + `toolsSettings` in +the agent JSON over a blanket `--trust-all-tools` for anything beyond dev/test.) All three agents pin `model: claude-opus-4-7`. Override per-invocation with `--model ` or edit the JSONs. @@ -67,7 +69,7 @@ relative to it. This is the Kiro-distribution analogue of Claude Code's Three of Kiro's five hook events are wired (per the orchestrator agent JSON): - `agentSpawn` → `kiro_session_start_bootstrap.py` — emits prior-lesson summary on session start -- `postToolUse` (matcher: `fs_write`) → `kiro_validate_packet.py` — Pydantic schema check on `.erpaval/` writes +- `postToolUse` (matcher: `write`) → `kiro_validate_packet.py` — **advisory** Pydantic schema check on `.erpaval/` writes; Kiro `postToolUse` cannot block, so a malformed packet is warned, not rejected (move to `preToolUse` + exit 2 if hard rejection is ever needed) - `stop` → `kiro_compound_nudge.py` — **advisory only**; Kiro stop hooks cannot block-and-re-prompt the agent the way Claude Code's `Stop` channel does All hooks are fail-open (`framework.run_hook` catches exceptions and exits 0). diff --git a/kiro/KIRO-COMPATIBILITY.md b/kiro/KIRO-COMPATIBILITY.md index 329c2f4..d175d29 100644 --- a/kiro/KIRO-COMPATIBILITY.md +++ b/kiro/KIRO-COMPATIBILITY.md @@ -5,16 +5,27 @@ gap shims, and migration playbook. ## Headline -Three of erpaval's primitives are 1:1 with Kiro: Skills (the open Agent -Skills standard), MCP, and the three hook events erpaval uses. Six gaps -exist. All have shipped shims documented below. - -The 1:1 hook mapping is: `SessionStart` → `agentSpawn`, `PostToolUse` → -`postToolUse`, `Stop` → `stop`. - -The six gaps are: `${CLAUDE_PLUGIN_ROOT}` env var, plugin manifest, plugin -namespacing, Stop-hook re-prompt channel, built-in `Explore` subagent, and -`addBlockedBy` task deps. +Two of erpaval's primitives are clean 1:1 with Kiro: Skills (the open Agent +Skills standard) and MCP. Subagents map closely (the `subagent` tool, the 4-per- +DAG-level cap, the `summary` return channel). Hooks map by event name but +**lose capability**: Kiro hooks are shell-only (no prompt-based hooks), only +`preToolUse` can block (via exit code 2), and `postToolUse`/`stop` are +advisory. All gaps have shipped shims documented below. + +The hook event mapping is: `SessionStart` → `agentSpawn` (1:1), +`UserPromptSubmit` → `userPromptSubmit` (1:1), `PreToolUse` → `preToolUse` +(block via exit 2 only), `PostToolUse` → `postToolUse` (cannot block — +packet validation is advisory), `Stop` → `stop` (advisory channel). + +The gaps are: `${CLAUDE_PLUGIN_ROOT}` env var, plugin manifest, plugin +namespacing, prompt-based hooks, blocking `PostToolUse`/`Stop` channels, +built-in `Explore` subagent, and `addBlockedBy` task deps. Four Claude Code +hook events — `SessionEnd`, `SubagentStop`, `PreCompact`, `Notification` — +have no Kiro equivalent (erpaval uses none of them). + +> Verified against Kiro CLI docs as of 2026-05-29. Kiro CLI is on a fast +> minor-version cadence (v2.2 → v2.5 in May 2026 alone) — re-check +> [kiro.dev/changelog](https://kiro.dev/changelog/) before each refresh. ## Capability mapping @@ -41,15 +52,17 @@ namespacing, Stop-hook re-prompt channel, built-in `Explore` subagent, and ### Hooks -| Capability | Status | -| -------------------------------------------------- | ---------------------- | -| SessionStart → agentSpawn | 1:1 | -| PostToolUse → postToolUse | 1:1 | -| Stop → stop | 1:1, channel-different | -| PreToolUse, UserPromptSubmit | 1:1 | -| SessionEnd, SubagentStop, PreCompact, Notification | gap, unused by erpaval | -| Hook config location | partial | -| Plugin-root env var | gap, shimmed | +| Capability | Status | +| -------------------------------------------------- | ----------------------- | +| SessionStart → agentSpawn | 1:1 | +| PostToolUse → postToolUse | partial, cannot block | +| Stop → stop | partial, advisory only | +| PreToolUse → preToolUse | partial, exit-2 only | +| UserPromptSubmit → userPromptSubmit | 1:1 | +| SessionEnd, SubagentStop, PreCompact, Notification | gap, unused by erpaval | +| Hook config location | inline in agent JSON | +| Hook trigger model (prompt-based hooks) | gap, shell-only on Kiro | +| Plugin-root env var | gap, shimmed | ### MCP @@ -157,9 +170,10 @@ This is the cost of a softer channel. Claude Code provides a built-in read-only Explore subagent. Kiro does not. `kiro/agents/erpaval-explorer.json` ships a custom agent with read-only -tools (`read`, `grep`, `glob`, `execute_bash` with a deny list for -destructive commands) and a system prompt that mirrors Claude Code's Explore -behavior. +tools (`read`, `grep`, `glob`, `shell` with a deny list for destructive +commands) and a system prompt that mirrors Claude Code's Explore behavior. +Kiro's read-only **Plan Agent** (`/plan`, v1.23.0) is an alternative for +structured read-only planning. ### `addBlockedBy` task dependencies @@ -171,10 +185,26 @@ progress only. The packets remain the source of truth. ### `Edit` tool separate from `Write` -Kiro has no separate `Edit` tool. `fs_write` overwrites. Hook matchers -target `fs_write` only, not `Write|Edit|MultiEdit` like Claude Code. Skills -that document file edits use `fs_write` semantics: rewrite the file with -the new content. +Kiro has no separate `Edit` tool — the `write` tool (canonical name; `fs_write` +is the deprecated Q-era alias) overwrites. Hook matchers target `write` only, +not `Write|Edit|MultiEdit` like Claude Code. Skills that document file edits +use `write` semantics: rewrite the file with the new content. + +> Tool-name modernization: this distribution emits the current canonical +> built-in names (`read`, `write`, `shell`, `aws`) in every agent JSON and hook +> matcher, not the deprecated Q-era aliases (`fs_read`, `fs_write`, +> `execute_bash`, `use_aws`). The old names still resolve as aliases, but the +> canonical names are forward-safe. + +### `postToolUse` cannot block — packet validation is advisory + +Claude Code's `PostToolUse` hook can reject a write. Kiro's `postToolUse` +**cannot block** — any non-zero exit surfaces a warning but the write stands. +`kiro_validate_packet.py` therefore runs as an advisory schema check: it warns +on a malformed `.erpaval/` packet but does not reject it. If hard rejection is +ever required, move the check to `preToolUse` on `write` and return exit code 2 +(the single blocking path in Kiro's hook model). The fail-open design is +unchanged — `framework.run_hook` still catches exceptions and exits 0. ## Migration playbook @@ -185,7 +215,8 @@ If you fork this plugin and want to maintain both distributions: 2. Mirror updates into `kiro/skills/erpaval/` with the documented surface rewrites. `${CLAUDE_PLUGIN_ROOT}` becomes `${ERPAVAL_HOME}`. `templates/` becomes `assets/`. `tools/` becomes `scripts/`. Task tool refs become - filesystem state plus `/todo`. + filesystem state plus `/todo`. Built-in tool names use the canonical + forms (`read`/`write`/`shell`/`aws`), not the Q-era aliases. 3. Run `bash kiro/install.sh --dry-run` to verify the install path. 4. Install into a workspace `.kiro/` and run `kiro-cli chat --agent erpaval-orchestrator`. @@ -198,7 +229,11 @@ by reading `skills/` and emitting `kiro/skills/`. Kiro's documented agent JSON schema does not specify `${VAR}` interpolation on field values. The installer sidesteps this by `sed`-substituting at install time. If Kiro ever adds first-class env-var expansion, the JSONs -can be shipped verbatim. +can be shipped verbatim. (Kiro's `mcp.json` *does* expand `${VAR}` in `env` +and `headers`; agent-JSON field values do not, which is why `${ERPAVAL_HOME}` +is resolved at install time, not by Kiro.) To relocate the whole Kiro home, +Kiro honors `KIRO_HOME` (v2.3.0) — the installer's `--workspace`/default +target is the analogue here. `kiro-cli` does not have a `kiro install` subcommand. Install is via cloning the repo and running `install.sh`. diff --git a/kiro/README.md b/kiro/README.md index 3ceb36a..49d4995 100644 --- a/kiro/README.md +++ b/kiro/README.md @@ -39,8 +39,9 @@ kiro-cli chat --agent erpaval-orchestrator --trust-all-tools The `--trust-all-tools` flag auto-approves every tool call, so subagents can write files, run shell commands, and call MCP servers without prompting. For unattended overnight runs, also pass `--no-interactive` and set -`KIRO_API_KEY`. For tighter scoping, use `--trust-tools=read,grep,glob,write` -instead of `--trust-all-tools`. +`KIRO_API_KEY`. For tighter scoping, use `--trust-tools=read,grep,glob,write,shell` +instead of `--trust-all-tools` — trusted-command matching is a prefix string +match, so least-privilege scoping in the agent JSON is safer than a blanket flag. Then state your request. The orchestrator runs the classifiers (CL-SCOPE, CL-COMPLEXITY, CL-RESUME, CL-DIR, CL-RIGOR, CL-SPEC) to decide which phases diff --git a/kiro/agents/README.md b/kiro/agents/README.md index d38cf75..a906ebe 100644 --- a/kiro/agents/README.md +++ b/kiro/agents/README.md @@ -16,7 +16,7 @@ with `--trust-all-tools` on the CLI, the orchestrator and its subagents run without permission prompts — necessary for the autonomous overnight loop. For headless runs add `--no-interactive` and set `KIRO_API_KEY`. For -least-privilege scoping use `--trust-tools=read,grep,glob,write,execute_bash` +least-privilege scoping use `--trust-tools=read,grep,glob,write,shell` instead of `--trust-all-tools`. System prompts live as sibling Markdown files under `prompts/` and are pulled in via `file://` URIs in each agent JSON. @@ -39,7 +39,7 @@ If you install by hand, replace every `${ERPAVAL_HOME}` in the JSONs with the ab The orchestrator hosts the three ERPAVal hooks inline (Kiro stores hooks per-agent rather than in a global `hooks.json`): - `agentSpawn` → `kiro_session_start_bootstrap.py` (emits prior-lesson summary) -- `postToolUse` (matcher: `fs_write`) → `kiro_validate_packet.py` (Pydantic-checks `.erpaval/` writes) +- `postToolUse` (matcher: `write`) → `kiro_validate_packet.py` (advisory Pydantic check on `.erpaval/` writes — `postToolUse` cannot block) - `stop` → `kiro_compound_nudge.py` (one-shot Compound-pending nudge) The researcher and explorer agents inherit no hooks — they are leaf subagents and don't drive the session loop. diff --git a/kiro/agents/erpaval-explorer.json b/kiro/agents/erpaval-explorer.json index 8c9967f..a01669a 100644 --- a/kiro/agents/erpaval-explorer.json +++ b/kiro/agents/erpaval-explorer.json @@ -4,10 +4,10 @@ "prompt": "file://./prompts/erpaval-explorer.md", "model": "claude-opus-4-7", "tools": [ - "fs_read", + "read", "grep", "glob", - "execute_bash", + "shell", "code", "introspect", "tool_search", diff --git a/kiro/agents/erpaval-orchestrator.json b/kiro/agents/erpaval-orchestrator.json index b7a106f..794873e 100644 --- a/kiro/agents/erpaval-orchestrator.json +++ b/kiro/agents/erpaval-orchestrator.json @@ -4,16 +4,15 @@ "prompt": "file://./prompts/erpaval-orchestrator.md", "model": "claude-opus-4-7", "tools": [ - "fs_read", - "fs_write", + "read", + "write", "glob", "grep", - "execute_bash", - "use_aws", + "shell", + "aws", "code", "introspect", "tool_search", - "delegate", "subagent", "summary", "knowledge", @@ -56,7 +55,7 @@ ], "postToolUse": [ { - "matcher": "fs_write", + "matcher": "write", "command": "${ERPAVAL_HOME}/hooks/kiro_validate_packet.py", "timeout_ms": 10000 } diff --git a/kiro/agents/erpaval-researcher.json b/kiro/agents/erpaval-researcher.json index 4056eb5..4ae6e5c 100644 --- a/kiro/agents/erpaval-researcher.json +++ b/kiro/agents/erpaval-researcher.json @@ -4,16 +4,15 @@ "prompt": "file://./prompts/erpaval-researcher.md", "model": "claude-opus-4-7", "tools": [ - "fs_read", - "fs_write", + "read", + "write", "grep", "glob", - "execute_bash", - "use_aws", + "shell", + "aws", "code", "introspect", "tool_search", - "delegate", "knowledge", "thinking", "todo", diff --git a/kiro/agents/prompts/erpaval-orchestrator.md b/kiro/agents/prompts/erpaval-orchestrator.md index 8e1c8a2..9c01640 100644 --- a/kiro/agents/prompts/erpaval-orchestrator.md +++ b/kiro/agents/prompts/erpaval-orchestrator.md @@ -8,9 +8,9 @@ You are the ERPAVal orchestrator. ERPAVal is an adaptive methodology for autonom 1. Run the four classifiers (scope, complexity, directory state, spec readiness) before committing to a phase plan. 2. Optional substeps when complexity warrants: HMW reframing and EARS specification (delegate to the `product-discovery` skill). -3. Dispatch the right subagents via in-chat NL: `> Use the erpaval-explorer agent to ...` for read-only codebase reconnaissance, `> Use the erpaval-researcher agent to ...` for external doc / library / API grounding, `> Use a general-purpose agent to act as the T-AC-X-Y subagent ...` for parallel implementation tracks. Every dispatch prompt must end with `Final step: call the built-in`summary`tool with a 1-2 paragraph result.` That `summary` call is the only return path; without it the dispatch reads as "No result" even when the packet on disk is correct. -4. Monitor task packets in `.erpaval/sessions//tasks/T*-*.md` — use the Ctrl+G crew monitor for live subagent state and `wc -l` for filesystem snapshots (see SKILL.md write protocol). -5. Validate, then run the Compound step to extract and persist lessons. +3. Dispatch the right subagents via in-chat NL: `> Use the erpaval-explorer agent to ...` for read-only codebase reconnaissance, `> Use the erpaval-researcher agent to ...` for external doc / library / API grounding, `> Use a general-purpose agent to act as the T-AC-X-Y subagent ...` for parallel implementation tracks. The `subagent` tool runs as a **blocking parallel fan-out** — you wait for the whole task graph, capped at **4 concurrent subagents per DAG level**, so batch Act waves accordingly. Every dispatch prompt must end with `Final step: call the built-in summary tool with a 1-2 paragraph result.` The `summary` call is the subagent's only return channel — the parent sees the summary text, not the on-disk packet. A subagent that writes its packet and exits without calling `summary` returns nothing usable to you, even when the packet on disk is correct. Make the packet the durable record and have the `summary` point at it. +4. Monitor subagents two ways: the **Ctrl+G crew monitor** for live state in interactive sessions, and `wc -l` over `.erpaval/sessions//tasks/T*-*.md` for filesystem snapshots in headless runs (see SKILL.md write protocol). When a subagent task reports progress, prefer the `$AGENT_DISPLAY_OUT` side-channel (rich TUI progress, no parent-context bloat) and `$AGENT_CONTEXT_OUT` (surfaced in the tool result's `agent_notes`) over folding status into the summary. +5. Validate, then run the Compound step to extract and persist lessons. For the Act→Validate→re-Act loop, prefer an in-pipeline **subagent review loop** — a reviewer stage that hands a task back to the implementer before the summary returns — over re-dispatching from scratch. A subagent runs once and ends, so there is no live re-message channel; the review loop is how a subagent self-corrects within one dispatch. **Do NOT use `/spawn`** to delegate. `/spawn` is a user-driven command that starts a fresh long-running session for the human to revisit; it is not the agent's delegation primitive. The orchestrator's primitive is the `subagent` built-in tool, which fires when you write `> Use the X agent to ...` in the chat. diff --git a/kiro/hooks/framework.py b/kiro/hooks/framework.py index 40c93f3..350533e 100755 --- a/kiro/hooks/framework.py +++ b/kiro/hooks/framework.py @@ -25,7 +25,7 @@ from framework import run_hook, emit_context, HookState, PostToolUseInput def handle(input, state): - if isinstance(input, PostToolUseInput) and input.tool_name == "fs_write": + if isinstance(input, PostToolUseInput) and input.tool_name == "write": emit_context("noted") # exits 0 if __name__ == "__main__": diff --git a/kiro/hooks/kiro_validate_packet.py b/kiro/hooks/kiro_validate_packet.py index f792ff3..992c827 100755 --- a/kiro/hooks/kiro_validate_packet.py +++ b/kiro/hooks/kiro_validate_packet.py @@ -6,8 +6,9 @@ """postToolUse hook: validate `.erpaval/sessions//*.yaml` writes. Kiro fires `postToolUse` after each tool execution. This hook is intended -to be wired with `matcher: "fs_write"` in the agent JSON, so it runs only -after Kiro's canonical write tool. We still defensive-check `tool_name`. +to be wired with `matcher: "write"` in the agent JSON (the canonical built-in +write tool; `fs_write` is the deprecated Q-era alias), so it runs only after +a write. We still defensive-check `tool_name` and accept either spelling. Early-exits for non-`.erpaval` paths and non-YAML/MD files. On schema violation, emits the error to STDOUT (Kiro's context channel) so the agent @@ -198,9 +199,9 @@ def _mark_erpaval_active(session_id: str) -> None: def handle(input, state: HookState) -> None: if not isinstance(input, PostToolUseInput): return - # Defensive: agent JSON should already gate this with matcher: "fs_write", - # but accept the canonical name and the `write` alias. - if input.tool_name not in ("fs_write", "write"): + # Defensive: agent JSON should already gate this with matcher: "write", + # but accept the deprecated `fs_write` Q-era alias too. + if input.tool_name not in ("write", "fs_write"): return file_path = input.tool_input.get("file_path") or input.tool_input.get("path") or "" diff --git a/kiro/install.sh b/kiro/install.sh index dffec65..05916d3 100755 --- a/kiro/install.sh +++ b/kiro/install.sh @@ -20,7 +20,7 @@ set -euo pipefail # Constants # --------------------------------------------------------------------------- -ERPAVAL_VERSION="1.1.1" +ERPAVAL_VERSION="1.3.0" ERPAVAL_BUNDLE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Symlinks the installer manages. Format: "::". diff --git a/kiro/skills/erpaval/SKILL.md b/kiro/skills/erpaval/SKILL.md index 6981292..07c9e87 100644 --- a/kiro/skills/erpaval/SKILL.md +++ b/kiro/skills/erpaval/SKILL.md @@ -227,11 +227,11 @@ Compound can also run ad-hoc when the user wants to force-extract lessons mid-se Hooks are configured **inline** in the `hooks` field of `kiro/agents/erpaval-orchestrator.json` — Kiro has no plugin-global `hooks.json`. All three hooks are UV-shebang Python scripts built on a Kiro-shaped fork of `framework.py`. Every hook is fail-open via `framework.run_hook` — any uncaught exception logs to stderr and exits 0, so a broken hook cannot wedge a session. -| Hook | Kiro event | Role | -| --------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `kiro_session_start_bootstrap.py` | `agentSpawn` | Emit `.erpaval/solutions/` category counts to STDOUT (Kiro folds STDOUT into conversation context). Fires once per session and only when a `sessions/session-/` dir was modified in the last 24h — cold repos stay silent. | -| `kiro_validate_packet.py` | `postToolUse` (matcher=`fs_write`) | Pydantic schema-check writes under `.erpaval/`. Early-exits on non-erpaval paths. Also drops `/tmp/kiro-erpaval-active-` as a cross-hook "this Kiro session touched ERPAVal" marker. | -| `kiro_compound_nudge.py` | `stop` | One-shot **advisory** STDERR warning when Compound is pending. Six gates: erpaval-active marker, `session-` name, fresh `validation.yaml` (<2h), no `lessons.yaml`, not nudged this session (HookState), not in `.erpaval/sessions/.nudged` ledger. The warning is informational — Kiro cannot block on `stop`. | +| Hook | Kiro event | Role | +| --------------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `kiro_session_start_bootstrap.py` | `agentSpawn` | Emit `.erpaval/solutions/` category counts to STDOUT (Kiro folds STDOUT into conversation context). Fires once per session and only when a `sessions/session-/` dir was modified in the last 24h — cold repos stay silent. | +| `kiro_validate_packet.py` | `postToolUse` (matcher=`write`) | **Advisory** Pydantic schema-check on writes under `.erpaval/` — `postToolUse` cannot block, so a malformed packet is warned, not rejected. Early-exits on non-erpaval paths. Also drops `/tmp/kiro-erpaval-active-` as a cross-hook "this Kiro session touched ERPAVal" marker. | +| `kiro_compound_nudge.py` | `stop` | One-shot **advisory** STDERR warning when Compound is pending. Six gates: erpaval-active marker, `session-` name, fresh `validation.yaml` (<2h), no `lessons.yaml`, not nudged this session (HookState), not in `.erpaval/sessions/.nudged` ledger. The warning is informational — Kiro cannot block on `stop`. | Imperative tools under `scripts/` — PEP 723 scripts invoked via `uv run` by the orchestrator: @@ -253,7 +253,7 @@ This skill is the Kiro distribution of erpaval. The Claude Code distribution liv | Concurrency cap | No documented cap | **Max 4 parallel** subagents (Kiro hard limit) — large waves dispatch in batches of 4 | | Task primitive | `TaskCreate` / `TaskUpdate` / `TaskList` / `addBlockedBy` | Filesystem-driven (`tasks/T-AC-X-Y.md` `status:` frontmatter) authoritative; Kiro `/todo` mirrors UI | | Hook config location | `hooks/hooks.json` at plugin root (plugin-global) | Inline `hooks` field in `kiro/agents/erpaval-orchestrator.json` (per-agent) | -| Hook event names | `SessionStart`, `PostToolUse(Write\|Edit\|MultiEdit)`, `Stop` | `agentSpawn`, `postToolUse(matcher=fs_write)`, `stop` | +| Hook event names | `SessionStart`, `PostToolUse(Write\|Edit\|MultiEdit)`, `Stop` | `agentSpawn`, `postToolUse(matcher=write)`, `stop` | | Stop hook semantics | Can re-prompt the model via `decision: "block"` + reason | **Advisory only** — STDERR warning, non-blocking. User runs `/erpaval` to invoke Compound when warned. | | Worktree isolation | `isolation: "worktree"` per Agent call | **No Kiro primitive.** Subagents run in the same working tree; rely on `Scope` discipline in packets. | | Plugin namespacing | `plugin:skill` syntax | Flat — skills live as sibling dirs under `~/.kiro/skills/` or `/.kiro/skills/` | diff --git a/kiro/skills/erpaval/references/context-packets.md b/kiro/skills/erpaval/references/context-packets.md index e204896..02f7acb 100644 --- a/kiro/skills/erpaval/references/context-packets.md +++ b/kiro/skills/erpaval/references/context-packets.md @@ -201,7 +201,7 @@ merge: ## Validation hook -The `postToolUse` hook with `matcher: fs_write` (`kiro/hooks/kiro_validate_packet.py`, configured inline in `kiro/agents/erpaval-orchestrator.json`) runs on every write, early-exits on non-`.erpaval/` paths, and Pydantic-checks YAML packets plus per-task `.md` frontmatter against their schemas. On failure the hook prints a warning to STDERR — advisory, not blocking. Fail-open by construction so a hook bug can never wedge a session. +The `postToolUse` hook with `matcher: write` (`kiro/hooks/kiro_validate_packet.py`, configured inline in `kiro/agents/erpaval-orchestrator.json`) runs on every write, early-exits on non-`.erpaval/` paths, and Pydantic-checks YAML packets plus per-task `.md` frontmatter against their schemas. On failure the hook prints a warning to STDERR — advisory, not blocking (Kiro `postToolUse` cannot reject a write). Fail-open by construction so a hook bug can never wedge a session. Per-task Markdown packet bodies (the 10 sections + work log) are intentionally unchecked — they're narrative work logs. Only the YAML frontmatter at the top carries validated structured metadata. Committed HMW/EARS outputs under `brainstorms/` and `specs/` are not validated — they're human-readable durables. Secrets scanning is a separate concern — use `gitleaks`, `trufflehog`, or GitHub push protection at repo level. diff --git a/kiro/skills/erpaval/references/orchestrator.md b/kiro/skills/erpaval/references/orchestrator.md index b082e52..842ae1c 100644 --- a/kiro/skills/erpaval/references/orchestrator.md +++ b/kiro/skills/erpaval/references/orchestrator.md @@ -310,7 +310,7 @@ Each subagent JSON must declare: ```json { - "tools": ["fs_read", "grep", "glob", "execute_bash", "..."], + "tools": ["read", "grep", "glob", "shell", "..."], "allowedTools": ["*"] } ``` @@ -331,7 +331,7 @@ In-chat NL is the *only* dispatch primitive for the orchestrator: `> Use the erp Subagents cannot dispatch sub-subagents (Kiro requires the `subagent` built-in tool to be in the agent's `tools` array; only the orchestrator has it). If a task needs nested delegation, break it into separate tasks. -Tool access for Act subagents: `read` (`fs_read`), `write` (`fs_write`), `shell` (`execute_bash`), `glob`, `grep`. They do not need `web_fetch`, `web_search`, MCP tools, or `subagent` — if a subagent needs to research, the Research phase was incomplete. Go back and fill the gap. +Tool access for Act subagents: `read`, `write`, `shell`, `glob`, `grep` (the canonical built-in names; `fs_read`/`fs_write`/`execute_bash` are deprecated Q-era aliases that still resolve). They do not need `web_fetch`, `web_search`, MCP tools, or `subagent` — if a subagent needs to research, the Research phase was incomplete. Go back and fill the gap. ---