diff --git a/.claude/gh-workflow.md b/.claude/gh-workflow.md index ce41d5b..80da836 100644 --- a/.claude/gh-workflow.md +++ b/.claude/gh-workflow.md @@ -285,7 +285,8 @@ or summarise any of it. the last 10, whichever is more. - **Attention** fires on exactly three signals: an unread PM inbox, a finished review on a still-open PR that the PM has not answered, and a worker in - `awaiting`. The `awaiting` signal is claude-only for now. + `awaiting`. The `awaiting` signal is claude-only: kiro-cli (checked on + 2.32.0) has no hook that fires while it waits on the user (#278). ```bash task-monitor-snapshot --json # this repo diff --git a/CHANGELOG.md b/CHANGELOG.md index c4ea404..b6fec72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [Unreleased] ### Changed +- **kiro has no `awaiting` signal, and now the docs say why (#278, epic #272 6/6).** Investigated against kiro-cli 2.32.0, with the outcome that there is nothing to wire. An agent config's `hooks` field accepts only `agentSpawn`, `userPromptSubmit`, `preToolUse`, `postToolUse` and `stop`, with no permission or notification trigger. kiro has no ask-the-user tool, and its one confirm tool, `switch_to_execution`, belongs to the built-in `kiro_planner` agent, which no task-force agent includes. No hook payload field marks a tool as waiting for approval. So a kiro worker waiting on the user never shows `❓` and never trips the monitor's `worker-awaiting` signal: it reads `idle` after a question, and most likely `busy` during a tool-approval prompt. That second case is unverified, because the live probe (scratch `HOME` and `TASK_FORCE_HOME`) hit the account's monthly usage limit before the model replied. Docs: a new "No awaiting state on kiro" section in the README's kiro delivery part, plus a row in its kiro hook table; the README's monitor Attention paragraph, `docs/task-monitor-schema.md`, `.claude/gh-workflow.md` and all seven steering templates now name the gap and the kiro-cli version checked instead of "claude-only for now". No code changes. A doc test in `tests/task_monitor_snapshot.bats` pins the wording and the version in every workflow doc, the schema doc and the README's section and anchor; restoring one old doc and breaking the anchor each turned it red. **Upgrading:** nothing to run. Re-run `task-init ` only if you want the refreshed wording in your workflow doc. + - **Worker PR bodies open with a plain-language `## Summary` (#274, part of #272).** With ten or more tickets a session, a PR number stops meaning anything to the person driving the PM, and nothing said in plain words what a merged PR did. Every worker prompt — the four claude loadouts, the dogfood copy and the three kiro agents — now opens the PR with `gh pr create … --fill --body-file - <<'BODY'` and a body whose first section is `## Summary`: two or three plain sentences, written for the user rather than a reviewer, saying what changed and why. The tracker's `Closes` line follows it (`Closes #` on gh, the issue key on jira, the page URL on notion, the task file on local), then the rest of the description. `--fill` still supplies the title; before this it supplied the body too, from commit messages. The step also tells the worker to write the body flush left, since GitHub renders an indented `## Summary` as code. Every reviewer prompt (the four claude loadouts, the dogfood copy, kiro-gh) now calls a missing `## Summary` a nit that never blocks on its own. Docs: a `### PR Body` section in `.claude/gh-workflow.md` and all seven steering templates, and the README's PR step. `tests/worker_checklist.bats` pins, on all 8 worker prompts, that the example body's first line is `## Summary` and that the loadout's own `Closes` line follows it, and that no prompt keeps a bare `--fill`. It also pins the rule's wording as identical across the claude loadouts, the nit on all 6 reviewer prompts, and the section in every workflow doc and the README. **Upgrading: re-run `task-init `** on every loadout to pick up the new `commands/worker.md` / `commands/reviewer.md` (kiro: `agents/worker.json`, and `agents/reviewer.json` on kiro-gh) and the workflow doc. - **kiro-gh's `task-reviewer` is folded onto the canonical `bin/task-reviewer`; `kiro-gh/bin/task-reviewer` is gone (#146, #147).** It was the last per-loadout copy #170 did not reach, and it had drifted on three axes the canonical body had already fixed. The canonical script now branches on the agent (`${IMPL%%-*}`) for the parts that are the agent's: the flags (claude's `--auto` / `--no-auto`; kiro's `-m` / `--model`, `-a` / `--trust-all`, `--no-trust-all`, `TASK_WORK_TRUST_ALL`), kiro's #218 agent preflight and its #157 / #257 startup-gate warnings, and the launch line, `kiro-cli chat --agent reviewer … "Review PR [against spec issue ]"`. Spec resolution is the tracker module's on both, so kiro-gh calls `lib/trackers/gh.sh`'s `aw_tracker_review_spec` rather than its own `parse_issue_number` + PR-body scan. Declared behaviour changes on kiro-gh: diff --git a/README.md b/README.md index 0226f6d..5e46442 100644 --- a/README.md +++ b/README.md @@ -412,7 +412,7 @@ task-monitor-snapshot --local # disk only: no forge calls, merged with **In flight** is every worktree whose `..info` sidecar exists — not every fresh heartbeat, so a resumed or roleless worker still shows — with its session state, its PR and a status word (`implementing`, `pr-open`, `under-review`, `changes-requested`, `re-review`, `waiting-merge`, `merged`) derived from the latest review intent. **Next** is the PM's queue, written with [`task-monitor-queue`](#task-monitor-queue--the-pms-queue), else the tracker's backlog. **Done** is the merged PRs that delivered an item in the last 24 hours, or the last 10, whichever is more; merged PRs are fetched once and cached for good. -**Attention** fires on exactly three signals and nothing else: an unread PM inbox (`--also` aliases count toward the primary), a finished review on a still-open PR the PM has not answered, and a worker in `awaiting`. The third is claude-only for now: only the claude loadouts wire `radio awaiting`. +**Attention** fires on exactly three signals and nothing else: an unread PM inbox (`--also` aliases count toward the primary), a finished review on a still-open PR the PM has not answered, and a worker in `awaiting`. The third is claude-only: only the claude loadouts wire `radio awaiting`, and kiro-cli has no hook to wire it to (see [no awaiting state on kiro](#no-awaiting-state-on-kiro)). `--local` exists so a front end can refresh on every filesystem event without waiting on GitHub: it shadows `gh` with a function that fails, so every forge read falls back to the cache under `$TASK_FORCE_HOME/monitor//`. The schema (`"schema": 1`) is documented in [`docs/task-monitor-schema.md`](docs/task-monitor-schema.md), with a full example beside it. @@ -721,6 +721,7 @@ kiro-cli actually looks: | `userPromptSubmit` | `radio busy` | State flip only. Not `prompt-hook` — that is a deliberate hold, not a limitation (#221). | | `stop` | `radio ready` | State flip back to idle, once per turn. No block-and-drain: whether kiro honours Stop-hook block JSON is a separate contract from stdout injection and is untested (#221). | | — | *(no session-end trigger)* | Unchanged: nothing unregisters on tab close except `task-done`. `radio orphans` is the cleanup (#98). | +| — | *(no waiting-on-user trigger)* | No `radio awaiting`, so a kiro tab never shows `❓`. See [below](#no-awaiting-state-on-kiro) (#278). | **kiro does inject hook stdout into the model's context.** This README asserted the opposite for months, citing an issue that was about something else entirely. The @@ -745,6 +746,44 @@ register report — and the other two are open questions rather than dead ends: in the prompt box for a human Enter. It does not touch kiro's permission model — that is still `-a/--trust-all`. +#### No awaiting state on kiro + +On claude, `radio awaiting` paints the tab `❓` and trips the monitor's +`worker-awaiting` signal. Three hooks call it: `PermissionRequest`, and a +`PreToolUse` matcher on each of `AskUserQuestion` and `ExitPlanMode`. kiro-cli +offers none of the three, so the kiro loadouts don't wire `radio awaiting` at +all (#278). Checked against kiro-cli 2.32.0: + +- **No trigger.** An agent config's `hooks` field accepts exactly `agentSpawn`, + `userPromptSubmit`, `preToolUse`, `postToolUse` and `stop`. There is no + permission or notification trigger. +- **No tool to match.** kiro has no ask-the-user tool, so a question is plain + prose that ends the turn. Its one confirm-before-proceeding tool, + `switch_to_execution` (the "Ready to exit [plan] agent" prompt), belongs to + kiro's built-in `kiro_planner` agent. No task-force kiro agent lists it in + `tools`, and inside `kiro_planner` none of radio's hooks run, so a + `preToolUse` matcher on it would never fire for a task-force role. +- **No payload field.** A hook receives `hook_event_name`, `cwd`, `session_id`, + `tool_name`, `tool_input`, `tool_response` and `assistant_response`. Nothing + says a tool is waiting for approval, so `preToolUse` can't tell an approval + prompt from a tool that is about to run. + +So a kiro worker that is waiting on you shows one of the states it already has. +A question asked in prose ends the turn, so `stop` marks it `idle` (`⏸️`). A +tool-approval prompt comes mid-turn, so the tab should stay `busy` (`▶️`). That +one is unverified: whether kiro fires `stop` before an approval prompt could not +be observed, because the live probe hit the account's monthly usage limit before +the model replied. Either way, neither trips `worker-awaiting`. A worker launched +with `--trust-all` never sees an approval prompt, which leaves only the question +case. + +No file is a substitute either. The `sessions/cli/` log the live kiro sessions on +this machine write holds only finished prompts, replies and tool results. kiro's +V3 engine does keep an `awaiting_approval` status on a tool call in its own +session files, but whether that is written while the prompt is still up is +unverified, and reading it would mean polling files instead of running a hook. +Re-check when kiro-cli adds a trigger. + Re-deriving what kiro can now support — prompt-hook, the Stop drain, and whether #190's "declare kiro best-effort" decision still holds — is tracked in **#221**. A heartbeat-driven unregister for the missing session-end trigger is #127. diff --git a/claude-gh/steering/gh-workflow.example.md b/claude-gh/steering/gh-workflow.example.md index f7103a7..757e881 100644 --- a/claude-gh/steering/gh-workflow.example.md +++ b/claude-gh/steering/gh-workflow.example.md @@ -281,7 +281,8 @@ or summarise any of it. the last 10, whichever is more. - **Attention** fires on exactly three signals: an unread PM inbox, a finished review on a still-open PR that the PM has not answered, and a worker in - `awaiting`. The `awaiting` signal is claude-only for now. + `awaiting`. The `awaiting` signal is claude-only: kiro-cli (checked on + 2.32.0) has no hook that fires while it waits on the user (#278). ```bash task-monitor-snapshot --json # this repo diff --git a/claude-jira/steering/jira-workflow.example.md b/claude-jira/steering/jira-workflow.example.md index 88ee962..110509f 100644 --- a/claude-jira/steering/jira-workflow.example.md +++ b/claude-jira/steering/jira-workflow.example.md @@ -281,7 +281,8 @@ or summarise any of it. the last 10, whichever is more. - **Attention** fires on exactly three signals: an unread PM inbox, a finished review on a still-open PR that the PM has not answered, and a worker in - `awaiting`. The `awaiting` signal is claude-only for now. + `awaiting`. The `awaiting` signal is claude-only: kiro-cli (checked on + 2.32.0) has no hook that fires while it waits on the user (#278). ```bash task-monitor-snapshot --json # this repo diff --git a/claude-local/steering/local-workflow.example.md b/claude-local/steering/local-workflow.example.md index 333ed72..28ecbbc 100644 --- a/claude-local/steering/local-workflow.example.md +++ b/claude-local/steering/local-workflow.example.md @@ -303,7 +303,8 @@ or summarise any of it. the last 10, whichever is more. - **Attention** fires on exactly three signals: an unread PM inbox, a finished review on a still-open PR that the PM has not answered, and a worker in - `awaiting`. The `awaiting` signal is claude-only for now. + `awaiting`. The `awaiting` signal is claude-only: kiro-cli (checked on + 2.32.0) has no hook that fires while it waits on the user (#278). ```bash task-monitor-snapshot --json # this repo diff --git a/claude-notion/steering/notion-workflow.example.md b/claude-notion/steering/notion-workflow.example.md index e0182f0..e1cf38e 100644 --- a/claude-notion/steering/notion-workflow.example.md +++ b/claude-notion/steering/notion-workflow.example.md @@ -298,7 +298,8 @@ or summarise any of it. the last 10, whichever is more. - **Attention** fires on exactly three signals: an unread PM inbox, a finished review on a still-open PR that the PM has not answered, and a worker in - `awaiting`. The `awaiting` signal is claude-only for now. + `awaiting`. The `awaiting` signal is claude-only: kiro-cli (checked on + 2.32.0) has no hook that fires while it waits on the user (#278). ```bash task-monitor-snapshot --json # this repo diff --git a/docs/task-monitor-schema.md b/docs/task-monitor-schema.md index ae69d5f..218b12d 100644 --- a/docs/task-monitor-schema.md +++ b/docs/task-monitor-schema.md @@ -191,8 +191,11 @@ radio id cannot order two messages from the same second: after the timestamp it holds the sender and a random suffix. So messages sort by `created_at`, then by their position among the log's `send id=` lines, then by id. -`worker-awaiting` is claude-only for now. Only the claude loadouts wire -`radio awaiting`, and #272's sub-issue 6 looks into a kiro equivalent. +`worker-awaiting` is claude-only. Only the claude loadouts wire +`radio awaiting`. kiro-cli (checked on 2.32.0) has no hook that fires while it +waits on the user, so a waiting kiro worker reads `idle` after a question, and +most likely `busy` during a tool-approval prompt. The README's "No awaiting +state on kiro" section has the evidence (#278). A role belongs to the longest repo name it starts with, so `worker-task-force-x` is `task-force`'s even when a repo named `task` exists. diff --git a/kiro-gh/steering/gh-workflow.example.md b/kiro-gh/steering/gh-workflow.example.md index f350ecf..4c91bdd 100644 --- a/kiro-gh/steering/gh-workflow.example.md +++ b/kiro-gh/steering/gh-workflow.example.md @@ -279,7 +279,8 @@ or summarise any of it. the last 10, whichever is more. - **Attention** fires on exactly three signals: an unread PM inbox, a finished review on a still-open PR that the PM has not answered, and a worker in - `awaiting`. The `awaiting` signal is claude-only for now. + `awaiting`. The `awaiting` signal is claude-only: kiro-cli (checked on + 2.32.0) has no hook that fires while it waits on the user (#278). ```bash task-monitor-snapshot --json # this repo diff --git a/kiro-local/steering/local-workflow.example.md b/kiro-local/steering/local-workflow.example.md index 21b4452..98124b1 100644 --- a/kiro-local/steering/local-workflow.example.md +++ b/kiro-local/steering/local-workflow.example.md @@ -301,7 +301,8 @@ or summarise any of it. the last 10, whichever is more. - **Attention** fires on exactly three signals: an unread PM inbox, a finished review on a still-open PR that the PM has not answered, and a worker in - `awaiting`. The `awaiting` signal is claude-only for now. + `awaiting`. The `awaiting` signal is claude-only: kiro-cli (checked on + 2.32.0) has no hook that fires while it waits on the user (#278). ```bash task-monitor-snapshot --json # this repo diff --git a/kiro-notion/steering/notion-workflow.example.md b/kiro-notion/steering/notion-workflow.example.md index cdeb478..66633a8 100644 --- a/kiro-notion/steering/notion-workflow.example.md +++ b/kiro-notion/steering/notion-workflow.example.md @@ -276,7 +276,8 @@ or summarise any of it. the last 10, whichever is more. - **Attention** fires on exactly three signals: an unread PM inbox, a finished review on a still-open PR that the PM has not answered, and a worker in - `awaiting`. The `awaiting` signal is claude-only for now. + `awaiting`. The `awaiting` signal is claude-only: kiro-cli (checked on + 2.32.0) has no hook that fires while it waits on the user (#278). ```bash task-monitor-snapshot --json # this repo diff --git a/tests/task_monitor_snapshot.bats b/tests/task_monitor_snapshot.bats index ee90187..ad7c3eb 100644 --- a/tests/task_monitor_snapshot.bats +++ b/tests/task_monitor_snapshot.bats @@ -671,3 +671,32 @@ project_page() { run bash -c "source '$lib'; printf '%s\n' 'just this' | tm_pr_summary" assert_output "just this" } + +# #278: kiro-cli has no hook for "waiting on the user", so worker-awaiting is +# claude-only. Every doc that describes the signal says so and names the +# kiro-cli version that was checked, so the claim can be re-tested later. +@test "every doc describing worker-awaiting names the kiro gap and the kiro-cli version" { + local docs=( + "$REPO_ROOT_REAL/.claude/gh-workflow.md" + "$REPO_ROOT_REAL/claude-gh/steering/gh-workflow.example.md" + "$REPO_ROOT_REAL/claude-jira/steering/jira-workflow.example.md" + "$REPO_ROOT_REAL/claude-local/steering/local-workflow.example.md" + "$REPO_ROOT_REAL/claude-notion/steering/notion-workflow.example.md" + "$REPO_ROOT_REAL/kiro-gh/steering/gh-workflow.example.md" + "$REPO_ROOT_REAL/kiro-local/steering/local-workflow.example.md" + "$REPO_ROOT_REAL/kiro-notion/steering/notion-workflow.example.md" + ) + local f + for f in "${docs[@]}"; do + run grep -qF 'The `awaiting` signal is claude-only: kiro-cli (checked on' "$f" + assert_success + run grep -q 'claude-only for now' "$f" + assert_failure + done + run grep -qF 'kiro-cli (checked on 2.32.0) has no hook that fires while it' "$REPO_ROOT_REAL/docs/task-monitor-schema.md" + assert_success + run grep -qF '#### No awaiting state on kiro' "$REPO_ROOT_REAL/README.md" + assert_success + run grep -qF '(#no-awaiting-state-on-kiro)' "$REPO_ROOT_REAL/README.md" + assert_success +}