Repository navigation
docs(readme): modernize README for headless agent automation and benchmark positioning - #249
Conversation
… benchmark, CI workflow, and dark logo
| - run: npm install -g @aictrl/[email protected] | ||
|
|
||
| # 2. Review with the model key only: no GitHub token, no shell, read-only tools, | ||
| # and no config or plugins from the pull request's .aictrl directory. |
There was a problem hiding this comment.
🟠 PR-authored .opencode/AGENTS.md bypasses isolation claim.
| # and no config or plugins from the pull request's .aictrl directory. | |
| Either gate the Instance.directory/.opencode/AGENTS.md entry in globalFiles() behind Flag.AICTRL_DISABLE_PROJECT_CONFIG (CLI fix), or harden the embedded workflow: add `- run: rm -rf .opencode .claude .agents .aictrl` between checkout and the Review step, and soften the README comment to match what the flag actually covers. |
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:102-107):
Problem: PR-authored .opencode/AGENTS.md bypasses isolation claim
Detail: The workflow's Review step comment claims "no config or plugins from the pull request's .aictrl directory" via AICTRL_DISABLE_PROJECT_CONFIG, but that flag only gates project config discovery (packages/cli/src/session/instruction.ts:27,71 — the findUp of project files). globalFiles() unconditionally pushes path.join(Instance.directory, ".opencode", "AGENTS.md") (instruction.ts:22) and is consumed unconditionally at instruction.ts:83 — and the working directory of this job is the PR's own checkout. A same-repo PR can therefore add .opencode/AGENTS.md and have it loaded as agent instructions during the review run, steering the review that is auto-posted to the PR via `gh pr comment`. This contradicts the isolation claim the README pattern sells, and this README is the product's copy-paste security template. (External skill dirs are also scanned, but the skill tool is denied by the "*": "deny" rule, so it is inert here.)
Suggested fix: Either gate the Instance.directory/.opencode/AGENTS.md entry in globalFiles() behind Flag.AICTRL_DISABLE_PROJECT_CONFIG (CLI fix), or harden the embedded workflow: add `- run: rm -rf .opencode .claude .agents .aictrl` between checkout and the Review step, and soften the README comment to match what the flag actually covers.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The workflow's Review step comment claims "no config or plugins from the pull request's .aictrl directory" via AICTRL_DISABLE_PROJECT_CONFIG, but that flag only gates project config discovery (packages/cli/src/session/instruction.ts:27,71 — the findUp of project files). globalFiles() unconditionally pushes path.join(Instance.directory, ".opencode", "AGENTS.md") (instruction.ts:22) and is consumed unconditionally at instruction.ts:83 — and the working directory of this job is the PR's own checkout. A same-repo PR can therefore add .opencode/AGENTS.md and have it loaded as agent instructions during the review run, steering the review that is auto-posted to the PR via gh pr comment. This contradicts the isolation claim the README pattern sells, and this README is the product's copy-paste security template. (External skill dirs are also scanned, but the skill tool is denied by the "*": "deny" rule, so it is inert here.)
- run: gh pr diff "$PR" > pr.diff
env:
GH_TOKEN: ${{ github.token }}
- run: npm install -g @aictrl/[email protected]
# 2. Review with the model key only: no GitHub token, no shell, read-only tools,
# and no config or plugins from the pull request's .aictrl directory.
- name: Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
MODEL: ${{ vars.AICTRL_MODEL }} # e.g. anthropic/claude-sonnet-4-5
AICTRL_DISABLE_PROJECT_CONFIG: "true"
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, ready_for_review] |
There was a problem hiding this comment.
🟡 Workflow never runs for reopened PRs (missing trigger).
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@
on:
pull_request:
- types: [opened, synchronize, ready_for_review]
+ types: [opened, reopened, synchronize, ready_for_review]
permissions:🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:71):
Problem: Workflow never runs for reopened PRs (missing trigger)
Detail: The copy-paste PR-review workflow triggers only on [opened, synchronize, ready_for_review]; `reopened` is missing and no other type fires on reopen, so a closed-then-reopened PR with no new pushes gets no aictrl review at all — a silent coverage gap for every user who pastes this template. Repro: copy the workflow from the README; open a PR (review comment posted); close it; reopen it without pushing — no workflow run triggers and the reopened PR carries no review.
Suggested fix: Add `reopened` to the types list: `types: [opened, reopened, synchronize, ready_for_review]`.
Suggested patch:
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@
on:
pull_request:
- types: [opened, synchronize, ready_for_review]
+ types: [opened, reopened, synchronize, ready_for_review]
permissions:
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The copy-paste PR-review workflow triggers only on [opened, synchronize, ready_for_review]; reopened is missing and no other type fires on reopen, so a closed-then-reopened PR with no new pushes gets no aictrl review at all — a silent coverage gap for every user who pastes this template. Repro: copy the workflow from the README; open a PR (review comment posted); close it; reopen it without pushing — no workflow run triggers and the reopened PR carries no review.
name: aictrl review
on:
pull_request:
types: [opened, synchronize, ready_for_review]
permissions:
contents: read
pull-requests: write
| "Review the change in pr.diff. Read files in this repository for context. | ||
| Report bugs, security and reliability problems with file and line; skip style. | ||
| Reply with the review only, in Markdown." > aictrl-events.jsonl | ||
| jq -rs '[.[] | select(.type == "text") | .part.text] | last // empty' aictrl-events.jsonl > review.md |
There was a problem hiding this comment.
🟡 jq `last` posts only final text block, can drop review.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:116-117):
Problem: jq `last` posts only final text block, can drop review
Detail: Per EVENTS.md, the CLI emits one `text` event per completed text block, and a multi-tool review run interleaves text blocks with tool calls. `[.[] | select(.type == "text") | .part.text] | last` keeps only the final block: if the model writes the review, makes one more read/grep call, then emits a short closing block ("Done — see above."), review.md contains only that fragment while `test -s` still passes, so the fragment is what gets posted to the PR — the full review is silently dropped. Repro: run the workflow on a PR where the model emits text → grep call → closing text; the posted comment is just the closing line.
Suggested fix: Collect text blocks emitted after the last tool_use event, e.g. `jq -rs '[.[] | select(.type=="text" or .type=="tool_use")] | (map(select(.type=="tool_use")) | length) as $n | .[$n:] | map(select(.type=="text") | .part.text) | join("\n\n") // empty'`, or join all text blocks and instruct the model to put the entire review in its final message.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
Per EVENTS.md, the CLI emits one text event per completed text block, and a multi-tool review run interleaves text blocks with tool calls. [.[] | select(.type == "text") | .part.text] | last keeps only the final block: if the model writes the review, makes one more read/grep call, then emits a short closing block ("Done — see above."), review.md contains only that fragment while test -s still passes, so the fragment is what gets posted to the PR — the full review is silently dropped. Repro: run the workflow on a PR where the model emits text → grep call → closing text; the posted comment is just the closing line.
\"Reply with the review only, in Markdown.\" > aictrl-events.jsonl\n jq -rs '[.[] | select(.type == \"text\") | .part.text] | last // empty' aictrl-events.jsonl > review.md\n test -s review.md\n\n # 3. Post with the GitHub token. The model key is not in this step.\n - run: gh pr comment \"$PR\" --body-file review.md --edit-last --create-if-none
| - name: Review | ||
| env: | ||
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | ||
| MODEL: ${{ vars.AICTRL_MODEL }} # e.g. anthropic/claude-sonnet-4-5 |
There was a problem hiding this comment.
🟡 Unset AICTRL_MODEL var silently changes the model used.
--- a/README.md
+++ b/README.md
@@ -104,7 +104,7 @@
- name: Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- MODEL: ${{ vars.AICTRL_MODEL }} # e.g. anthropic/claude-sonnet-4-5
+ MODEL: ${{ vars.AICTRL_MODEL || 'anthropic/claude-sonnet-4-5' }}
AICTRL_DISABLE_PROJECT_CONFIG: "true"🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:106):
Problem: Unset AICTRL_MODEL var silently changes the model used
Detail: MODEL comes only from `${{ vars.AICTRL_MODEL }}` with no fallback. If the repository variable is not configured, the step runs `aictrl run --model ""`; in packages/cli/src/cli/cmd/run.ts the model is resolved via a falsy check (`args.model ? Provider.parseModel(...) : undefined`), so the empty string is treated as unset and the run silently uses the default agent model rather than the commented example. If that default targets a provider whose key the repo didn't configure, the run fails mid-flight with a confusing auth error (exit 1) after minutes of setup. Also, the step hardcodes ANTHROPIC_API_KEY while the variable may select another provider. Repro: add the workflow, set only ANTHROPIC_API_KEY, leave AICTRL_MODEL unset, open a PR — the Review step silently runs the default model, not claude-sonnet-4-5.
Suggested fix: Default at the expression level — `MODEL: ${{ vars.AICTRL_MODEL || 'anthropic/claude-sonnet-4-5' }}` — or fail fast in the script: `test -n "$MODEL" || { echo "Set the AICTRL_MODEL repository variable" >&2; exit 2; }`.
Suggested patch:
--- a/README.md
+++ b/README.md
@@ -104,7 +104,7 @@
- name: Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- MODEL: ${{ vars.AICTRL_MODEL }} # e.g. anthropic/claude-sonnet-4-5
+ MODEL: ${{ vars.AICTRL_MODEL || 'anthropic/claude-sonnet-4-5' }}
AICTRL_DISABLE_PROJECT_CONFIG: "true"
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
MODEL comes only from ${{ vars.AICTRL_MODEL }} with no fallback. If the repository variable is not configured, the step runs aictrl run --model ""; in packages/cli/src/cli/cmd/run.ts the model is resolved via a falsy check (args.model ? Provider.parseModel(...) : undefined), so the empty string is treated as unset and the run silently uses the default agent model rather than the commented example. If that default targets a provider whose key the repo didn't configure, the run fails mid-flight with a confusing auth error (exit 1) after minutes of setup. Also, the step hardcodes ANTHROPIC_API_KEY while the variable may select another provider. Repro: add the workflow, set only ANTHROPIC_API_KEY, leave AICTRL_MODEL unset, open a PR — the Review step silently runs the default model, not claude-sonnet-4-5.
# 2. Review with the model key only: no GitHub token, no shell, read-only tools,\n # and no config or plugins from the pull request's .aictrl directory.\n - name: Review\n env:\n ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}\n MODEL: ${{ vars.AICTRL_MODEL }} # e.g. anthropic/claude-sonnet-4-5\n AICTRL_DISABLE_PROJECT_CONFIG: \"true\"\n AICTRL_MODEL_STREAM_IDLE_TIMEOUT_MS: \"300000\"
| ## License | ||
|
|
||
| [aictrl.dev](https://aictrl.dev/?utm_medium=referral&utm_source=github&utm_campaign=cli&utm_content=readme) | ||
| MIT License — see [LICENSE](LICENSE). |
There was a problem hiding this comment.
🟡 Fork attribution dropped; LICENSE still credits OpenCode.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:252):
Problem: Fork attribution dropped; LICENSE still credits OpenCode
Detail: The PR deletes the "Attribution" section ("Aictrl is a fork of the OpenCode project") and the new License section says only "MIT License — see LICENSE", yet the LICENSE file at HEAD still carries "Copyright (c) 2025 opencode" alongside the Aictrl notice. After this change no user-facing doc mentions the fork (packages/cli/README.md has no attribution either), which reads as inconsistent with the LICENSE's upstream copyright and drops the fork disclosure the project previously displayed.
Suggested fix: Keep a one-line note under ## License, e.g. "MIT License — see [LICENSE](LICENSE). aictrl is a fork of the [OpenCode](https://opencode.ai) project."
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The PR deletes the "Attribution" section ("Aictrl is a fork of the OpenCode project") and the new License section says only "MIT License — see LICENSE", yet the LICENSE file at HEAD still carries "Copyright (c) 2025 opencode" alongside the Aictrl notice. After this change no user-facing doc mentions the fork (packages/cli/README.md has no attribution either), which reads as inconsistent with the LICENSE's upstream copyright and drops the fork disclosure the project previously displayed.
- **[CLI Package & Configuration Reference (`packages/cli/README.md`)](packages/cli/README.md)** — detailed `--output-schema`, `--skill`, and permission contracts\n\n## License\n\nMIT License — see [LICENSE](LICENSE).\n
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
|
|
||
| - run: npm install -g @aictrl/[email protected] |
There was a problem hiding this comment.
⚪ Quickstart pins @0.5.4; will rot without a hint.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:99):
Problem: Quickstart pins @0.5.4; will rot without a hint
Detail: The copy-paste-ready workflow hard-pins @aictrl/[email protected] while the README's own Install section says `npm i -g @aictrl/cli` (unpinned). The pin matches today's benchmark numbers, but nothing in the example says the version is intentional, so copy-pasters stay on 0.5.4 indefinitely and silently miss fixes.
Suggested fix: Keep the pin for benchmark parity but add a comment (e.g. `# pinned to the benchmarked version; bump with releases`), or use `@^0.5` if moving tags are preferred.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The copy-paste-ready workflow hard-pins @aictrl/[email protected] while the README's own Install section says npm i -g @aictrl/cli (unpinned). The pin matches today's benchmark numbers, but nothing in the example says the version is intentional, so copy-pasters stay on 0.5.4 indefinitely and silently miss fixes.
# 1. Fetch the diff with the GitHub token. The model key is not in this step.\n - run: gh pr diff \"$PR\" > pr.diff\n env:\n GH_TOKEN: ${{ github.token }}\n\n - run: npm install -g @aictrl/[email protected]\n\n # 2. Review with the model key only: no GitHub token, no shell, read-only tools,
Code reviewVerdict: Address the major findings before merging. · 🔴 0 · 🟠 1 · 🟡 5 · ⚪ 2 · 0/8 resolved
🤖 Fix all 8 open findings with your agent📋 Out-of-diff findings (8)
Reviewed 3 files · 0 inline · view all 8 findings ↗ · AI-generated — verify findings before acting · AI guidance and feedback aictrl · AI code review for fast-moving teams · aictrl.dev |
- Remove AGENTS.md files from the checkout before the review step: the harness loads them as instructions even with project config disabled. - Trigger on reopened pull requests. - Default MODEL when the AICTRL_MODEL variable is unset. - Join all text blocks so a review followed by another tool call is not reduced to the closing sentence. - Say why the CLI version is pinned. Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Package description uses the headless agent harness tagline. - The EVENTS.md link in the npm README is absolute, so it resolves on npmjs.com. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Review response — PR #249Replies to the 8 findings in the review of 34c17d5. Six are fixed on this branch, one is fixed here with a follow-up issue for the CLI, and one needs no change. Issues addressed (pushed to this PR)
Review claims verified false (no change needed)
Not addressed here
Verification: |
| Passing `--format json` writes one JSON event per line to stdout (`schemaVersion: "1"`), covering: | ||
|
|
||
| ### Skill Scope | ||
| - **Lifecycle:** `invocation_start`, `session_start`, `retry`, `session_error`, `invocation_error`, `invocation_complete` |
There was a problem hiding this comment.
🟠 Event list omits 8 types EVENTS.md documents.
| - **Lifecycle:** `invocation_start`, `session_start`, `retry`, `session_error`, `invocation_error`, `invocation_complete` | |
| Either add the missing types (`session_complete` under Lifecycle; `user_message`, `text`, `reasoning` under a model-output bullet; `step_start`/`step_finish`; `skill_resource_loaded`; `error`), or reword "covering:" to "key events include:" so the list does not read as exhaustive. |
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:179-182):
Problem: Event list omits 8 types EVENTS.md documents
Detail: The "covering:" bullets in the `--format json` section read as an exhaustive list, but EVENTS.md documents additional event types they omit: `session_complete` (lifecycle), `user_message`, `text`, `reasoning`, `step_start`/`step_finish`, `skill_resource_loaded`, and `error`. The omission is also self-contradictory: the README's own GitHub Actions example (line 122) filters the stream with `select(.type == "text")`, yet `text` is absent from this list.
Suggested fix: Either add the missing types (`session_complete` under Lifecycle; `user_message`, `text`, `reasoning` under a model-output bullet; `step_start`/`step_finish`; `skill_resource_loaded`; `error`), or reword "covering:" to "key events include:" so the list does not read as exhaustive.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The "covering:" bullets in the --format json section read as an exhaustive list, but EVENTS.md documents additional event types they omit: session_complete (lifecycle), user_message, text, reasoning, step_start/step_finish, skill_resource_loaded, and error. The omission is also self-contradictory: the README's own GitHub Actions example (line 122) filters the stream with select(.type == "text"), yet text is absent from this list.
Passing `--format json` writes one JSON event per line to stdout (`schemaVersion: "1"`), covering:
- **Lifecycle:** `invocation_start`, `session_start`, `retry`, `session_error`, `invocation_error`, `invocation_complete`
- **Model & cost accounting:** `message_complete` and `subagent_message_complete` with input/output/reasoning/cache tokens, cost, and context-window utilization
- **Tools & permissions:** `tool_catalog`, `permission_granted`, `permission_rejected`, `tool_use` (with start/end timestamps), `skill_discovered`, `skill_loaded`
- **Subagents & results:** `subagent_start`, `subagent_complete`, `structured_output`, `structured_output_rejected`
| test -s review.md | ||
|
|
||
| # 3. Post with the GitHub token. The model key is not in this step. | ||
| - run: gh pr comment "$PR" --body-file review.md --edit-last --create-if-none |
There was a problem hiding this comment.
🟡 Injection egress via auto-posted comment undocumented.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:126):
Problem: Injection egress via auto-posted comment undocumented
Detail: The model's input is PR-controlled (pr.diff plus files in the PR-merged checkout readable via read/glob/grep) and its verbatim text output is auto-posted as the bot's PR comment. A prompt injection planted in the diff or a reviewed file can therefore publish arbitrary markdown/links under the repo's identity (e.g. phishing or "maintainer approved" text), and `--edit-last` lets later runs rewrite it. The split-secret pattern blocks token abuse but not this output channel, and the README presents the example as safe without mentioning the residual risk.
Suggested fix: Add one sentence next to the example noting the residual prompt-injection risk (model output is PR-influenced and posted verbatim; review comments before trusting them), and/or constrain the read surface with pattern denies (e.g. deny read on `**/.env*`, `**/*.key`, `**/*.pem`).
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The model's input is PR-controlled (pr.diff plus files in the PR-merged checkout readable via read/glob/grep) and its verbatim text output is auto-posted as the bot's PR comment. A prompt injection planted in the diff or a reviewed file can therefore publish arbitrary markdown/links under the repo's identity (e.g. phishing or "maintainer approved" text), and --edit-last lets later runs rewrite it. The split-secret pattern blocks token abuse but not this output channel, and the README presents the example as safe without mentioning the residual risk.
# 3. Post with the GitHub token. The model key is not in this step.
- run: gh pr comment "$PR" --body-file review.md --edit-last --create-if-none
env:
GH_TOKEN: ${{ github.token }}
- uses: actions/upload-artifact@v4
| AICTRL_CONFIG_CONTENT: >- | ||
| {"permission": {"*": "deny", "read": "allow", "glob": "allow", "grep": "allow"}} | ||
| run: | | ||
| aictrl run --format json --model "$MODEL" \ |
There was a problem hiding this comment.
⚪ Flagship example skips the advertised --output-schema.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:117-123):
Problem: Flagship example skips the advertised --output-schema
Detail: The "Why a dedicated headless harness" table sells enforced JSON Schema with corrective turns and "No prose fallback" as the differentiator, but the flagship example runs free-form prose output guarded only by `test -s`. Prose is arguably the right format for a PR review, yet the example never acknowledges the tension, and using `--output-schema` here would also structurally bound what reaches the PR comment.
Suggested fix: Either use the structured path in the example (`--output-schema review.schema.json --output-result review.json`, render the comment from review.json) or add a sentence explaining when free-form prose output is appropriate vs. schema-validated results.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The "Why a dedicated headless harness" table sells enforced JSON Schema with corrective turns and "No prose fallback" as the differentiator, but the flagship example runs free-form prose output guarded only by test -s. Prose is arguably the right format for a PR review, yet the example never acknowledges the tension, and using --output-schema here would also structurally bound what reaches the PR comment.
AICTRL_CONFIG_CONTENT: >-
{"permission": {"*": "deny", "read": "allow", "glob": "allow", "grep": "allow"}}
run: |
aictrl run --format json --model "$MODEL" \
"Review the change in pr.diff. Read files in this repository for context.
Report bugs, security and reliability problems with file and line; skip style.
Do not narrate your steps. Reply with the review only, in Markdown." > aictrl-events.jsonl
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
|
|
||
| - uses: actions/upload-artifact@v4 |
There was a problem hiding this comment.
⚪ Events artifact duplicates all file contents the agent read.
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:130-135):
Problem: Events artifact duplicates all file contents the agent read
Detail: Per EVENTS.md, each `tool_use` event carries `state.input` and `state.metadata.output`, so aictrl-events.jsonl contains the full contents of every file the reviewer read plus reasoning traces, and it is uploaded `if: always()` (including failed runs) for 7 days. Anyone with repo read access can download it — for public repos that is everyone. The contents only mirror the already-checkoutable repo, but the example should say so or redact tool outputs, since adopters may not realize the artifact duplicates their source tree.
Suggested fix: Strip tool outputs before upload (e.g. `jq 'del(.part.state.metadata.output)' aictrl-events.jsonl > upload.jsonl`) or note that the artifact mirrors repository contents and can be dropped for public repos.
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
Per EVENTS.md, each tool_use event carries state.input and state.metadata.output, so aictrl-events.jsonl contains the full contents of every file the reviewer read plus reasoning traces, and it is uploaded if: always() (including failed runs) for 7 days. Anyone with repo read access can download it — for public repos that is everyone. The contents only mirror the already-checkoutable repo, but the example should say so or redact tool outputs, since adopters may not realize the artifact duplicates their source tree.
- uses: actions/upload-artifact@v4
if: always()
with:
name: aictrl-events
path: aictrl-events.jsonl
retention-days: 7
| ```bash | ||
| cat logs.txt | aictrl run "summarize these errors" | ||
| ``` | ||
| We benchmarked six coding-agent CLIs (`aictrl 0.5.4`, `pi 1.3.0`, `Goose 1.55.0`, `Codex 0.163.0`, `OpenCode 2.1.0`, and `Hermes v0.22.2`) in fresh 2-CPU Docker containers against a deterministic 50 ms local stub model to isolate harness overhead from remote LLM latency. Full runner, raw JSON captures, and methodology are open in [`aictrl-dev/skill-md-research`](https://github.com/aictrl-dev/skill-md-research/tree/main/experiments/headless-cli-benchmark) and analyzed in the [benchmark post](https://aictrl.dev/blog/headless-coding-agent-cli-benchmark?utm_source=github&utm_medium=readme&utm_campaign=headless-readme). |
There was a problem hiding this comment.
⚪ "Hermes v0.22.2" vs table's "Hermes 0.22.2".
| We benchmarked six coding-agent CLIs (`aictrl 0.5.4`, `pi 1.3.0`, `Goose 1.55.0`, `Codex 0.163.0`, `OpenCode 2.1.0`, and `Hermes v0.22.2`) in fresh 2-CPU Docker containers against a deterministic 50 ms local stub model to isolate harness overhead from remote LLM latency. Full runner, raw JSON captures, and methodology are open in [`aictrl-dev/skill-md-research`](https://github.com/aictrl-dev/skill-md-research/tree/main/experiments/headless-cli-benchmark) and analyzed in the [benchmark post](https://aictrl.dev/blog/headless-coding-agent-cli-benchmark?utm_source=github&utm_medium=readme&utm_campaign=headless-readme). | |
| Drop the "v": "…and `Hermes 0.22.2`) in fresh 2-CPU Docker containers…" |
🤖 Fix with your agent
Fix this code review finding (aictrl-dev/cli PR #249, README.md:140):
Problem: "Hermes v0.22.2" vs table's "Hermes 0.22.2"
Detail: The benchmark prose introduces "`Hermes v0.22.2`" while the table header and every other CLI label use bare versions without a "v" prefix (pi 1.3.0, Goose 1.55.0, Codex 0.163.0, OpenCode 2.1.0, Hermes 0.22.2). Label drift in an otherwise strictly formatted comparison.
Suggested fix: Drop the "v": "…and `Hermes 0.22.2`) in fresh 2-CPU Docker containers…"
Implement the fix on the PR head branch and add a regression test that fails before the fix and passes after.
Why this matters
The benchmark prose introduces "Hermes v0.22.2" while the table header and every other CLI label use bare versions without a "v" prefix (pi 1.3.0, Goose 1.55.0, Codex 0.163.0, OpenCode 2.1.0, Hermes 0.22.2). Label drift in an otherwise strictly formatted comparison.
We benchmarked six coding-agent CLIs (`aictrl 0.5.4`, `pi 1.3.0`, `Goose 1.55.0`, `Codex 0.163.0`, `OpenCode 2.1.0`, and `Hermes v0.22.2`) in fresh 2-CPU Docker containers against a deterministic 50 ms local stub model to isolate harness overhead from remote LLM latency.
| Metric (lower is better, except coverage) | **aictrl 0.5.4** | pi 1.3.0 | Goose 1.55.0 | Codex 0.163.0 | OpenCode 2.1.0 | Hermes 0.22.2 |
Code reviewVerdict: Address the major findings before merging. · 🔴 0 · 🟠 1 · 🟡 1 · ⚪ 3 · 0/5 resolved
🤖 Fix all 5 open findings with your agent📋 Out-of-diff findings (5)
Reviewed 5 files · 0 inline · view all 5 findings ↗ · AI-generated — verify findings before acting · AI guidance and feedback aictrl · AI code review for fast-moving teams · aictrl.dev |
…mple - List all event types EVENTS.md documents. - Note that the posted review is untrusted model output, why the example posts Markdown instead of --output-schema, and that the events artifact holds the contents of files the agent read. - Use the same Hermes version label as the table. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Review response — PR #249 (second review, 7e08c79)Replies to the 5 findings in the review of 7e08c79. All five are fixed in
Issues addressed (pushed to this PR)
Review claims verified false (no change needed)
Not addressed here
Verification: |
Summary
Updates
README.mdandpackages/cli/README.mdto align with the headless agent positioning and the public 6-CLI benchmark:exit 0, markdown formatting breaking JSON parsers, unconstrained permissions in CI, token/cost blind spots).gh pr diff+aictrl run --format json+gh pr comment) using restricted permissions (read,glob,greponly).--output-schema, versioned NDJSON event streaming (--format json), declarative tool permissions, and model stream idle timeouts.<picture>(.github/logo-dark.svg).Test plan
packages/cli/test/flag/flag.test.tsto verify README contract assertions pass.