dojo CLI v1.1 — fully agent-navigable + headless - #4
Merged
Conversation
… JSON envelope + discovery
Wave 1 foundation for the v1.1 agent-drivability cut (DGS-74 stream). The CLI's
35-command surface was unreachable to any non-interactive caller: --one-shot sent
its string straight to the chat stream, so `dojo --one-shot "/health"` chatted the
literal text "/health" instead of running the command.
- internal/output: new Emitter + stable {ok,command,data,error} Envelope + NDJSON
seam. Nil-safe; Human mode inert, JSON mode accumulates data / streams lines.
- Registry.RunHeadless: JSON dispatch that redirects os.Stdout during the handler
(stray fmt.Printf becomes a data.text fallback, no JSON corruption) and wraps the
terminal envelope. printKV/colorStatus consult a package emitter, so ~119 printKV
sites populate `data` for free with zero per-site change.
- cmd/dojo/main.go: A1 — one-shot "/cmd" now routes through Registry.Dispatch;
--commands emits the machine-readable catalog; exit codes 0 ok / 1 runtime /
2 usage (unknown command, config).
- Registry.Commands(): discovery accessor — one source of truth for the catalog.
- docs/v1.1-scout-dossier.md: the informing scout (3-agent recon synthesis).
Verified: go test ./... -race green; REPL output byte-unchanged; live against
gateway 3.2.2 — /health --json returns a structured envelope, unknown → exit 2,
--commands --json lists 36 commands.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nt injection
The `prompt` and `agent` hook types were parsed but no-op'd (warn + return nil).
They now execute against the Gateway: `prompt` buffers a ChatStream, `agent` does
CreateAgent + AgentChatStream. Advisory-only by design — they run and log but
cannot veto the caller; only `command` hooks retain the blocking gate (unchanged).
- inject *client.Client into hooks.Runner (it held only []plugins.Plugin); the
switch-case was trivial, the wiring was the work. hooks.New(plgs) → New(plgs, gw)
- nil-gw guard falls back to the prior warn-once no-op (tests unaffected)
- small opt-in payload templating ({{.command}}, {{.prompt}}); output via log
(stderr), never stdout, so it can't corrupt a --json stream
- HookDef.Model honored for prompt; forward-compat no-op for agent (gateway
ignores AgentChatRequest.Model today) — documented, not blocked
- docs(TODO): flip the stale DAG-polling line (shipped as pollDAGUntilTerminal)
Part of the v1.1 agent-navigable cut (DGS-77). Advisory-only leaves the
veto-semantics decision for a future pass; noted in the follow-up.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ers, integrity
Wave 2 of the v1.1 agent-navigable cut (DGS-77): every command now emits the
{ok,command,data,error} envelope in --json mode (NDJSON for streamers), plus the
capability + hygiene riders. Built by 4 parallel tracks against the Wave-1 seam,
integrated + verified together (make all green, live vs gateway 3.2.2).
Output conversion (~23 command files):
- list/table commands emit structured data via r.out.Data(...); printKV-based
ones inherit data from the Wave-1 foundation; streaming commands (/agent,
/workflow, /run, /pilot, /craft, /skill package-all) emit NDJSON via r.out.Emit
- TUI-only /warroom, /bloom return an "unsupported in headless" envelope; /home,
/pilot fall back to plain; stdin-blocking commands (/plugin install, /protocol
install, /craft prune·elevate·scaffold, /code undo) refuse cleanly unless --yolo
Capability riders:
- B1 /trail edit <id> <text>; B2 /tools <name> input-schema inspector
- B3 CAS pinning /skill get <name>@<ver>, package-all <dir> [ver]
- B5 /run --plan <file> (hand-authored ExecutionPlan, no chat fallback)
- B6 /snapshot export <id> [path]; D1 unknown-subcommand errors on 5 commands
- C2 plugin-install integrity: source allowlist + optional --sha256 pin, never
bypassed by --yes (internal/plugins/installer.go)
Integration fixes (main thread):
- headless dispatch seeds a session id (orchestration/agent need session_id)
- /run propagates a mid-stream gateway error to ok=false / exit 1 (was ok=true)
- errcheck: discard hash/Fprint returns (installer.go, runner_test.go)
- docs: /help table + CHANGELOG for the new modes
- tests: internal/output envelope/NDJSON tests, headless dispatch + discovery tests
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ithout --yolo
Foundation for the headless-maximization pass. headlessRefuse is now consent-aware:
a command reaches its y/N prompt in headless mode only after headlessRefuse lets it
past, which now requires explicit consent (--yes, this run only; narrower than the
blunt --yolo which also skips the permissions gate). New r.autoConfirmed() (==
r.headless) is the guard commands use to treat a prompt as pre-answered when
consented — `if !r.autoConfirmed() && !confirm() { … }`.
Safe default preserved: headless WITHOUT --yes/--yolo still refuses. Wiring
autoConfirmed() into each interactive command's gate is a follow-on track.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A plain --one-shot "/cmd" (without --json) called Dispatch directly and never marked the registry headless, so /warroom, /bloom and other alt-screen commands tried to open a TTY (and failed) instead of using their plain-text headless branch. RunHeadless already sets this for --json; the plain path now does too. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirrors the /run fix: a mid-stream SSE error event is captured and the command returns non-nil, so the headless envelope reports ok=false / exit 1 instead of a false ok=true, while still emitting the NDJSON error line. (/pilot stays a live monitor — error events are content, not a command failure.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eam fidelity Wires r.autoConfirmed() into the confirmation gates so a consented headless run proceeds instead of dying at the permission gate / hanging on a y/N read: - /code undo, /craft adr, /craft claude-md, /craft scaffold: permissionGate now receives autoConfirmed() instead of a hardcoded false - /craft memory prune, /craft seed elevate: craftConfirm guarded by !autoConfirmed() - craftStream: drop the out.Len()==0 guard that suppressed a mid-stream error once any text had streamed — a partial-then-error run now reports ok=false too Safe default preserved: without --yes/--yolo these still refuse headlessly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…EDITOR Adds --content <text> / --content=<text> / --content - (stdin) so the protocol overlay is editable non-interactively. Explicit opt-in only — never auto-reads stdin (which would hang a headless caller). No --content falls through to the unchanged interactive $EDITOR flow; protocolEdit stays byte-identical so its existing tests are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ript envelope
Replaces the 'interactive-only, unsupported in headless' refusal with a real
headless debate. New tui.RunWarRoomHeadless runs the same two agent streams the
TUI uses (Scout 'measured' + Challenger 'adversarial' via streamAgentToChannel),
serializing onChunk so NDJSON lines never interleave. --json streams
{stream:warroom,agent,content} per chunk then a {topic,scout,challenger}
envelope; plain headless prints a linear transcript. Interactive TUI unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/bloom's animation has no terminal headless, but it visualizes real spirit state, so a headless dispatch now emits belt/xp/streak/sessions/next-belt/koan (structured data in --json, a plain summary otherwise) rather than refusing. The interactive animated TUI is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ang) The y/N gate only skipped on the per-command noConfirm, so a headless run with global --yes passed headlessRefuse and then hung on the stdin read. Gate it on !autoConfirmed() too, matching the /craft and /code undo pattern. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ng tree) /code undo reverts all unstaged changes — destructive enough that a broad per-run --yes should not fire it. New headlessRefuseStrict requires --yolo (or the REPL); --yes alone is refused. Other confirm-gated commands keep the narrower --yes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Makes the entire CLI command surface runnable non-interactively with a uniform, machine-parseable contract, and maximizes headless coverage — including the interactive/TUI commands.
Fixes DGS-77
Agent-navigable spine
dojo --one-shot "/cmd"runs the command through the dispatcher (was: chatted the literal string to a model). Plain one-shot is headless too.--jsonemits a stable{ok,command,data,error}envelope; streaming commands emit NDJSON then a terminal envelope.--commandsmachine-readable catalog (from the registry); exit codes0ok /1runtime /2usage.Capability + hygiene riders
/tools <name>schema ·/run --plan <file>·/trail edit·/snapshot export <path>· CAS@verpinning · unknown-subcommand errors.prompt/agenthooks (advisory) with Gateway client injection.--sha256pin.Maximum headless (this branch's second half)
/warroom— real headless debate: Scout + Challenger as labeled NDJSON + a transcript envelope (plain: linear transcript). Interactive TUI unchanged./bloom— emits belt/XP/streak/sessions/koan instead of refusing.--yeslets confirm-gated commands (/craft,/protocol install) run headless; safe default (refuse) preserved./code undorequires--yolo(not--yes) because it reverts the working tree./protocol edit --content— edit the overlay with no$EDITOR(-reads stdin for multi-line)./run,/agent,/workflow,/craft) propagate mid-stream gateway errors took:false/ exit 1.Verification
make allgreen ·go test ./... -raceall packages · golangci-lint clean on changed non-test code · live against gateway 3.2.2 (envelope, NDJSON,/warroomdebate, discovery, exit codes, consent refuse/proceed). Interactive REPL output byte-unchanged.🤖 Generated with Claude Code