mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 02:29:33 +01:00
Merge pull request #694: feat(agent): COD-529 add bounded inspection and guarded submission
Conflicts resolved by keeping both sides: - CLAUDE.md (Agent CLI): #694's opening (an HTTP client, the experimental agent-session-routes behind agentCoordinationEnabled) with #708's clause on the directory spawn and its two refusals. - docs/api-reference.md (codeman agent): #708's spawn paragraph and --json shape, with #694's inspect/stage/submit in the verb list and the guarded endpoints named before "adds no route for the other verbs". - src/cli-agent.ts (@fileoverview): #708's quick-start / directory spawn routes and #694's experimental routes in one endpoint list; the two node:fs/promises imports (#708's realpath+stat, #694's open+stat) merged into one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
5908cc51fd
50 files changed
+5408
-116
No files matched your search
@@ -37,13 +37,15 @@ through: the verbs in detail (the old §5) in [reference/verbs.md](reference/ver
|
||||
worked multi-worker flows in [reference/recipes.md](reference/recipes.md), endpoint
|
||||
tables and a symptom gallery in [reference/endpoints.md](reference/endpoints.md), and
|
||||
direct messaging to claude workers in [reference/messaging.md](reference/messaging.md).
|
||||
Experimental bounded inspection and guarded stage/submit load only when needed from
|
||||
[reference/inspection-and-staging.md](reference/inspection-and-staging.md).
|
||||
|
||||
This skill works the same whichever CLI you are: Codeman puts it where each CLI looks
|
||||
for skills (`.claude/skills/` for Claude Code, `.agents/skills/` for Codex, Gemini CLI,
|
||||
OpenCode, Antigravity, Grok, DeepSeek and OMP). A **pi** or **shell** worker never gets
|
||||
it, but has the same environment: tell it *"other sessions: `codeman agent --help`"*.
|
||||
That bundled CLI (`ls`, `spawn`, `send`, `wait`, `read`, `interrupt`, `rm`, and the inbox
|
||||
verbs `post`, `inbox`, `ack`) is the same
|
||||
That bundled CLI (`ls`, `spawn`, `send`, `wait`, `read`, `inspect`, `stage`, `submit`,
|
||||
`interrupt`, `rm`, and the inbox verbs `post`, `inbox`, `ack`) is the same
|
||||
verbs over the same endpoints, with the guards below (no control bytes, no self-delete,
|
||||
no guessed URL) enforced in code, and it is also your own way through when this
|
||||
machine has no `jq` for the preamble below.
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
# Experimental bounded inspection and guarded submission
|
||||
|
||||
**Experimental:** `codeman agent inspect`, `stage` and `submit`, and their
|
||||
`/api/v1/sessions/:id/inspect|stage|submit` routes (including `/api` aliases),
|
||||
are labeled experimental and so are not part of the stable CLI/HTTP contract. Their commands, flags, paths,
|
||||
payloads and behavior may change or be removed in a minor or patch release.
|
||||
Pin a compatible Codeman version when automating them. Authentication and
|
||||
session ownership checks still apply.
|
||||
|
||||
They are also opt-in: until the user turns on **Experimental agent coordination**
|
||||
in App Settings (`agentCoordinationEnabled`, off by default), every one of them
|
||||
fails with `FORBIDDEN: ... (HTTP 403)` naming that setting. That is not something
|
||||
to retry or work around: tell the user, or use `send`/`read` instead.
|
||||
|
||||
Use these commands inside a Codeman session. They use its authenticated HTTP API.
|
||||
They supplement `send`, `wait` and `read` over the same HTTP transport; no direct
|
||||
tmux access is required.
|
||||
|
||||
## Inspect recent evidence
|
||||
|
||||
```bash
|
||||
codeman agent inspect "$SID" --max-bytes 8192 --json
|
||||
codeman agent inspect "$SID" --max-bytes 8192 --since "$CURSOR" --json
|
||||
```
|
||||
|
||||
Read `source`, `identity`, `activity`, `evidence`, `truncated` and `cursor` before
|
||||
interpreting the result. `maxBytes` bounds UTF8 evidence bytes, excluding the JSON
|
||||
metadata/envelope. The default is 8192, maximum 65536.
|
||||
|
||||
- `codex-jsonl`: strictly attributed local Codex JSONL records. The first call
|
||||
selects recent complete records within a bounded tail window;
|
||||
`omittedBeforeBytes` labels older bytes deliberately omitted. A cursor continues
|
||||
after the last consumed complete record. Partial final records remain pending.
|
||||
- `pane-snapshot`: UTF8-safe tail of a visible frame or the session's buffered
|
||||
output. It has `incremental:false` and `cursor:null`. This is the fallback for
|
||||
other modes, remote/container sessions, ambiguous attribution, and exhausted
|
||||
attribution budgets. Repeating a snapshot can repeat evidence.
|
||||
|
||||
Attribution proves which file supplied the evidence, not which thread is now
|
||||
active in the TUI. A launch resume that conflicts with a newly owned rollout
|
||||
falls back to a snapshot. An in-CLI `/resume` of an existing foreign-originator
|
||||
thread may leave launch metadata unchanged. Check `identity.conversationId`;
|
||||
these reads do not provide authoritative current-thread tracking.
|
||||
|
||||
Terminal resizes preserve inspection cursors. Cursors are opaque, scoped to the
|
||||
requesting identity, session, pane lifecycle generation
|
||||
and attributed transcript, expire after 15 minutes, and disappear on server
|
||||
restart. Each caller and session keeps its newest 8 (so retrying the last call
|
||||
works), at most 1024 in all; an older cursor can be retired. A replaced/truncated/rewritten source, reassociated session, foreign cursor
|
||||
or unavailable native source returns `409 CONFLICT`. Inspect again without
|
||||
`--since` to establish a new tail baseline; this may omit older evidence.
|
||||
|
||||
`blockedReason` explains an unfinished or oversized record. Incremental reads
|
||||
never split or silently skip one. Increase the byte budget for
|
||||
`record-exceeds-output-budget`; when the record exceeds the maximum or scan cap,
|
||||
use `read --tail` for a labeled terminal view or start a fresh tail baseline.
|
||||
Inspect scans at most 256 KiB of record data plus bounded generation anchors.
|
||||
Attribution separately caps directory entries (8192), depth (8), negative-filter
|
||||
prefix reads (8 MiB) and candidate metadata including final verification (1 MiB). Evidence and
|
||||
activity are observations, not proof of task completion or authorization.
|
||||
|
||||
## Stage, inspect, then submit once
|
||||
|
||||
```bash
|
||||
printf '%s' 'Review src/ and report the failing tests' > /tmp/codeman-message.txt
|
||||
codeman agent stage "$SID" --message-file /tmp/codeman-message.txt --json
|
||||
# Review the returned stageId, sha256, expiresAt; inspect the target if needed.
|
||||
codeman agent submit "$SID" --stage-id "$STAGE_ID" --confirm-sha "$SHA256" --json
|
||||
```
|
||||
|
||||
Stage types the file contents **without Enter**. The file must be regular, UTF8,
|
||||
one printable line, at most 8192 bytes, with no control characters or trailing
|
||||
whitespace/newline. It initially supports a local Codex composer with a recognized
|
||||
footer and an exact, unwrapped line/caret capture. Before typing, stage checks
|
||||
the actual captured width and composer indentation; a message that would reach
|
||||
the right edge or wrap is refused without writing anything. Unknown, working, modal,
|
||||
wrapped, remote/container and shell composers are refused. A customized footer or
|
||||
unsupported character-width rendering can also make verification unavailable.
|
||||
Self-targets are refused by the CLI.
|
||||
|
||||
Stage also refuses, before typing, a message that would change what Enter does:
|
||||
one starting with `/` (a Codex slash command; with its command list open, Enter
|
||||
would run the highlighted command instead) or `!` (a shell command), and one whose
|
||||
**last** word starts with `@` (file/mention search) or `$` (skills). Those popups
|
||||
follow the caret, which stage leaves at the end, so `look at @src/app.ts please`
|
||||
is fine. Send slash and shell commands with `codeman agent send`, and end a
|
||||
message with an ordinary word when it mentions a file. A frame showing a
|
||||
suggestion popup above the composer is refused at stage and submit too.
|
||||
|
||||
The receipt stores a hash and ephemeral identities, never prompt content. It
|
||||
expires after two minutes; capacity is 1024 live receipts. After typing, stage
|
||||
re-reads the pane (every 50 ms, up to one second, since Codex repaints a little
|
||||
after the keys) and issues a receipt only for a frame that shows exactly the
|
||||
message with the caret after it. Any refusal after the keys went out (typing
|
||||
failed or was ambiguous, the pane or input changed, or no frame verified in time)
|
||||
says the message may already be in the composer: no receipt was issued. Do not
|
||||
stage again on top of it; follow [Recover a stranded draft](#recover-a-stranded-draft) below first.
|
||||
|
||||
While a submit's Enter is in flight (milliseconds), `send` and other input to that
|
||||
session answer `409 CONFLICT` with nothing written; retry the input.
|
||||
|
||||
Submit checks the caller, session, hash, expiry, pane lifecycle, input revision,
|
||||
geometry, exact composer and caret, then sends one conditional Enter at the session's input
|
||||
boundary. It first waits until 250 ms have passed since stage typed (Codex turns an
|
||||
Enter that follows typed text within 120 ms into a newline), so submitting right
|
||||
after stage is fine. Competing Codeman writes are refused during dispatch. Browser/API/key
|
||||
input and managed restarts invalidate receipts even when the visible text or pid
|
||||
is restored. Direct tmux edits are outside that input serialization; captures
|
||||
remain evidence at the time observed, rather than terminal isolation.
|
||||
|
||||
Every owned submit attempt consumes its receipt, including hash mismatch,
|
||||
verification failure and delivery failure. Concurrent/repeated submits cannot
|
||||
replay Enter, and there is no autonomous retry. A successful response means one
|
||||
Enter was delivered; use inspection or a suitable wait signal to observe native
|
||||
acceptance. A `409` or broken connection means inspect first. Do not automatically
|
||||
stage/submit again or send an unguarded Enter to recover.
|
||||
|
||||
## Recover a stranded draft
|
||||
|
||||
A consumed receipt cannot be reused, and a stage refused after typing issued
|
||||
none. First observe whether the prompt is still in the composer or was accepted: use transcript evidence/wait signals and a fresh terminal capture
|
||||
(`GET /api/v1/sessions/:id/terminal?tail=8192`). If the target is working, has
|
||||
accepted the prompt, shows a dialog, or delivery is ambiguous, keep observing;
|
||||
do not clear or resend anything. A transcript prompt row alone is not proof
|
||||
that text remains unsent in the current composer.
|
||||
|
||||
Only recover an unambiguously unsent draft in an input-ready local Codex
|
||||
composer: verify the complete draft, recognized footer and caret at its end in
|
||||
the current frame, and ensure no other writer can edit this target during
|
||||
recovery. If the frame is wrapped, incomplete or unclear, ask the user to clear
|
||||
it in the terminal instead of guessing keys. Never use `send` to overwrite a
|
||||
draft: that appends and submits both prompts together.
|
||||
|
||||
After those checks, the known Codex line-clear chord may be sent once through
|
||||
the existing raw input route, with **no Enter**. This conditional example uses
|
||||
the authenticated `CURL`/`API` values loaded by §0 and the exact target id:
|
||||
|
||||
```bash
|
||||
"${CURL[@]}" -X POST "$API/api/v1/sessions/$SID/input" \
|
||||
-H 'Content-Type: application/json' -d '{"input":"\u0015","useMux":false}'
|
||||
```
|
||||
|
||||
Do not retry a failed/ambiguous clear blindly. Read a fresh terminal frame and
|
||||
verify the composer is empty and input-ready. Only then create a **fresh** stage
|
||||
receipt for the intended prompt and submit that receipt once. If the draft did
|
||||
not clear, the target began working, or verification remains uncertain, stop and
|
||||
ask the user; do not send an unguarded Enter or replay the old prompt.
|
||||
@@ -550,8 +550,10 @@ this (`src/web/routes/approval-routes.ts:43`). ESC is then claude's own interrup
|
||||
that half is the CLI's behavior, not something this API guarantees.
|
||||
|
||||
- **This is not the composer-clearing tool.** Esc (and Ctrl+U) do **not** clear a
|
||||
typed-but-unsubmitted prompt, verified live. The only recovery there is to submit it
|
||||
with `{"input":"\r"}` and let the worker read the junk line.
|
||||
typed-but-unsubmitted Claude prompt, verified live. Do not submit an unverified
|
||||
draft merely to clear it. For a refused guarded local Codex stage or submit, use the
|
||||
verified-unsent recovery in [inspection and staging](inspection-and-staging.md#recover-a-stranded-draft);
|
||||
when the composer is unclear, ask the user to clear it in the terminal.
|
||||
- The interrupted turn already burned its tokens. Interrupting early saves the rest.
|
||||
- `POST /api/sessions/:id/send-key` is a different endpoint and cannot do this: its
|
||||
allowlist is S-Enter / C-Enter only.
|
||||
@@ -811,3 +813,16 @@ Rules that matter:
|
||||
not parked, `send` it one line ("read your inbox: `codeman agent inbox`").
|
||||
- **Lifetime.** An inbox goes with its session on delete. A server restart empties all
|
||||
inboxes unless the user turned on *Keep agent inbox across restarts* in Settings.
|
||||
|
||||
## Experimental bounded inspection and guarded submission
|
||||
|
||||
These three commands and their HTTP routes are labeled experimental, so they may
|
||||
change or be removed in minor or patch releases. They are also opt-in
|
||||
(`agentCoordinationEnabled`, off by default: a 403 naming it until the user turns
|
||||
it on). Use `codeman agent inspect` for bounded evidence and incremental local
|
||||
Codex cursors.
|
||||
Use `codeman agent stage --message-file` followed by one hash-confirmed
|
||||
`codeman agent submit --stage-id --confirm-sha` when the exact local Codex
|
||||
composer and caret can be verified. Other targets provide labeled snapshots or
|
||||
refuse guarded input. See [inspection and staging](inspection-and-staging.md)
|
||||
for budgets, receipt expiry, conflict handling and supported composers.
|
||||
Reference in new issue
Block a user