Enforce agent-state UX for app→agent features - #21
Open
ahmad-ajmal wants to merge 1 commit into
Open
ahmad-ajmal wants to merge 1 commit into
ahmad-ajmal wants to merge 1 commit into
Conversation
ahmad-ajmal
marked this pull request as ready for review
October 2, 2026 16:08
ahmad-ajmal
added this pull request to stack #26
October 5, 2026 13:20
ahmad-ajmal
force-pushed
the
ahmad/enforce-agent-state
branch
from
October 5, 2026 15:22
e02e0a5 to
05c88a8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #13.
Work an app queues for an agent now stays visible in the View until it is done.
validateenforces it, walk-verify checks it, and every blueprint with a queue and a View ships a component that does it, so the default path is the good one. Getting a real agent to complete a task on Windows also needed three bridge fixes, included here.What it looks like
The react-node starter, with "Ask an agent" on each task. The badge beside the title and the panel under the row follow the task live, with no reload.
Waiting. Shown the moment the work is queued, with elapsed time.
No agent listening. After ~20 s unclaimed, it says so and names the command that starts one, instead of "waiting" forever.
Working. The agent's own step, its progress, and how long it has been running.
Done. The answer gets its own full-width block, never the title cell. Line breaks are kept, links are clickable, and long text is clamped behind "Show more".
Failed. The reason in words, and "Ask again", which queues new work rather than returning the old failure. Codes the queue and the bridge write themselves (
redelivery_exhausted,harness_exited_nonzero, …) are translated into a sentence.Phone width. The row badge steps aside so the title keeps its room. The panel carries the state.
Real agents, through
agent-app <dir> bridge start. Claude Code (first) and Pi (second) each picked up tasks queued from the UI, did the triage through thea2appCLI, and completed with summaries the View showed as they arrived.What changed
1. Validate gate: new step, "agent work shown in the View" (
framework/cli/src/lib/agentState.ts).trigger(…)calls in app-owned code that name a capability. It recognises the JS, Go, Ruby, Python (capability=) and Rust (Some(…)) spellings, plus the adapter's object form./api/_a2app/tasks/. The failure names each call site and points at the creator-skill rule.trigger, system-owned files, dependencies, build output and tests. The component's own file doesn't count, so shipping it is not using it.A View that queues work and only shows a toast now fails the gate like this:
2. UI kit: an agent-task panel, badge and
useAgentTaskhook.AgentTask.jsxfor react-node, go-react and rust-react; Vue components plusagentTask.jsfor rails-vue.3. Starters (react-node, go-react, rust-react, rails-vue, python-fastapi):
agentTaskfield set byrequest-triage.4. Skills:
5. Bridge (
framework/cli/src/lib/bridge.ts,harness.ts). Needed for a real agent to complete a task on Windows:.cmdshims and one-line node wrappers (Pi'spi.cmd) are started by running their target directly, never through a shell. Before this, every delivery failed withspawn EINVALand left the task claimed until it ran out of redeliveries.a2appCLI, with file edits denied. Without that grant, everya2appcall needed an approval nobody could give.6. rails-vue: ships
ui/public/tokens.cssandui.css. The template's unanchoredpublic/ignore rule had kept them out of the repo, so scaffolded apps were unstyled.How it was verified
framework/cli/test/agent-state.test.mjscovers every stack spelling, the false-positive cases, the View verdicts, and all five starters passing their own gate.bridge.test.mjscovers shim parsing, delivery through an npm-style shim with a payload of cmd.exe metacharacters (arrives verbatim, nothing executed), a non-shim.batrefused before any claim, a spawn that throws, and heartbeats that carry no step.validatefailed with the output above, and passed once the panel was rendered.node pi-launcher.jsroute) completed real tasks through the bridge.Not covered
lib/a2app_schema.rb) has not been executed (no Ruby on the test machine).App.jsx/AgentTask.jsxas react-node.