Skip to content

docs(readme): modernize README for headless agent automation and benchmark positioning - #249

Merged
byapparov merged 4 commits into
mainfrom
docs/headless-agent-harness-readme
Oct 20, 2026
Merged

byapparov merged 4 commits into
mainfrom
docs/headless-agent-harness-readme

Conversation

@byapparov

Copy link
Copy Markdown
Member

Summary

Updates README.md and packages/cli/README.md to align with the headless agent positioning and the public 6-CLI benchmark:

  • Positioning: Replaces the generic tagline with a clear category headline: "The headless agent harness for CI, cron jobs, and container workflows".
  • Why a dedicated headless harness: Adds a concrete problem/solution table addressing common automation pitfalls in CI/batch jobs (silent hangs, false exit 0, markdown formatting breaking JSON parsers, unconstrained permissions in CI, token/cost blind spots).
  • GitHub Actions PR Review Quickstart: Adds a copy-paste split-secret workflow pattern (gh pr diff + aictrl run --format json + gh pr comment) using restricted permissions (read, glob, grep only).
  • Benchmark Summary Table: Embeds the fresh-container benchmark results across the six CLIs (startup time, 50-read session duration, turn overhead, memory, image footprint, tokens, and event coverage) linking to reproduction artifacts.
  • Automation Contracts: Highlights --output-schema, versioned NDJSON event streaming (--format json), declarative tool permissions, and model stream idle timeouts.
  • Visuals: Adds light/dark theme-adaptive header logo via <picture> (.github/logo-dark.svg).

Test plan

  • Tested packages/cli/test/flag/flag.test.ts to verify README contract assertions pass.
  • Verified pre-push Bun semver verification and typecheck pass cleanly.

@byapparov byapparov self-assigned this Oct 20, 2026
Comment thread README.md Outdated
- 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 PR-authored .opencode/AGENTS.md bypasses isolation claim.

Suggested change
# 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"

Comment thread README.md Outdated

on:
pull_request:
types: [opened, synchronize, ready_for_review]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Comment thread README.md Outdated
"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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Comment thread README.md Outdated
- name: Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
MODEL: ${{ vars.AICTRL_MODEL }} # e.g. anthropic/claude-sonnet-4-5

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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\"

Comment thread README.md
## License

[aictrl.dev](https://aictrl.dev/?utm_medium=referral&utm_source=github&utm_campaign=cli&utm_content=readme)
MIT License — see [LICENSE](LICENSE).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Comment thread README.md
env:
GH_TOKEN: ${{ github.token }}

- run: npm install -g @aictrl/[email protected]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚪ 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,

@aictrl-dev

aictrl-dev Bot commented Oct 20, 2026

Copy link
Copy Markdown

Code review

Verdict: Address the major findings before merging. · 🔴 0 · 🟠 1 · 🟡 5 · ⚪ 2 · 0/8 resolved

  • 🟡 packages/cli/package.json:4 — npm description keeps old tagline after rebrand
  • ⚪ packages/cli/README.md:83 — Relative EVENTS.md link at line 83 404s on npm
  • 🟡 README.md:71 — Workflow never runs for reopened PRs (missing trigger)
  • ⚪ README.md:99 — Quickstart pins @0.5.4; will rot without a hint
  • 🟠 README.md:102-107 — PR-authored .opencode/AGENTS.md bypasses isolation claim
  • 🟡 README.md:106 — Unset AICTRL_MODEL var silently changes the model used
  • 🟡 README.md:116-117 — jq `last` posts only final text block, can drop review
  • 🟡 README.md:252 — Fork attribution dropped; LICENSE still credits OpenCode
🤖 Fix all 8 open findings with your agent
Fix the following code review findings on aictrl-dev/cli PR #249 (head branch).
Run the relevant tests/linters after each change.

1. packages/cli/package.json:4 — npm description keeps old tagline after rebrand
   Detail: Both READMEs are rebranded to "The headless agent harness for CI, cron jobs, and container workflows", but the @aictrl/cli package description (packages/cli/package.json, verified at HEAD) still reads "Headless execution engine for AI agent skills". On npmjs.com the description renders directly above the rewritten package README (packages/cli/README.md is the published npm doc), so the old and new positioning appear side by side — the rebrand this PR drives is incomplete at its most visible surface.
   Suggested fix: Update packages/cli/package.json "description" to the new tagline ("The headless agent harness for CI, cron jobs, and container workflows") in this PR.
2. packages/cli/README.md:83 — Relative EVENTS.md link at line 83 404s on npm
   Detail: This PR adds an absolute GitHub link to EVENTS.md at the top of packages/cli/README.md (correct for the npm-rendered page), but the pre-existing relative link "[EVENTS.md](../../EVENTS.md)" at line 83 remains. On npmjs.com the relative link resolves outside the package and 404s, so the same document is now linked two ways and one is broken in exactly the context (npm) the new absolute link was added for.
   Suggested fix: Replace the line-83 link with the absolute URL already used at the top: [EVENTS.md](https://github.com/aictrl-dev/cli/blob/main/EVENTS.md).
3. README.md:71 — 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]`.
4. README.md:99 — 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.
5. README.md:102-107 — 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.
6. README.md:106 — 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; }`.
7. README.md:116-117 — 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.
8. README.md:252 — 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."
📋 Out-of-diff findings (8)
Sev Location Finding
🟡 packages/cli/package.json:4 npm description keeps old tagline after rebrand
⚪ packages/cli/README.md:83 Relative EVENTS.md link at line 83 404s on npm
🟡 README.md:71 Workflow never runs for reopened PRs (missing trigger)
⚪ README.md:99 Quickstart pins @0.5.4; will rot without a hint
🟠 README.md:102-107 PR-authored .opencode/AGENTS.md bypasses isolation claim
🟡 README.md:106 Unset AICTRL_MODEL var silently changes the model used
🟡 README.md:116-117 jq `last` posts only final text block, can drop review
🟡 README.md:252 Fork attribution dropped; LICENSE still credits OpenCode

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

byapparov and others added 2 commits October 20, 2026 23:48
- 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]>
@byapparov

Copy link
Copy Markdown
Member Author

Review response — PR #249

Replies 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)

  • PR-authored AGENTS.md can steer the review — README.md: confirmed, and the gap is wider than .opencode/AGENTS.md. AICTRL_DISABLE_PROJECT_CONFIG gates config and the root AGENTS.md lookup (packages/cli/src/session/instruction.ts:71, config/paths.ts:25), but globalFiles() always adds <cwd>/.opencode/AGENTS.md (instruction.ts:22), and read attaches any nested AGENTS.md it finds above a file it reads (tool/read.ts:138 → InstructionPrompt.resolve), also ungated. The workflow now deletes every AGENTS.md in the checkout before the review step (find . -name AGENTS.md -not -path './.git/*' -delete), and the step comment now says "no project config or plugins from the pull request". The CLI fix (gate both paths behind the flag, with tests) is AICTRL_DISABLE_PROJECT_CONFIG still loads AGENTS.md from .opencode/ and from directories the agent reads #250. No other instruction file names are loaded (FILES = ["AGENTS.md"]). (commit 0e1b2a1)
  • No reopened trigger — README.md: added reopened to types. (commit 0e1b2a1)
  • jq last keeps only the final text block — README.md: confirmed with a synthetic stream (text → tool_use → "Done."): the old filter writes "Done.". The suggested filter (text after the last tool_use) also writes "Done." for that same stream, so it does not fix the repro. Structured output is not an option here either: --output-schema needs the model to write a file, and this job denies write. The workflow now joins all non-empty text blocks and drops empty output so test -s still fails on no review; the prompt asks the model not to narrate its steps. Checked: actionlint passes, and the Review step run against a stub aictrl posts the full review. (commit 0e1b2a1)
  • Unset AICTRL_MODEL changes the model — README.md: the empty-string fallthrough is real (cli/cmd/run.ts:1132 treats "" as unset, then Provider.defaultModel() picks a model). The auth-error part is less likely than stated, because the default comes from providers that have credentials, but the run still uses a model the user did not choose. MODEL now defaults at the expression level: ${{ vars.AICTRL_MODEL || 'anthropic/claude-sonnet-4-5' }}. (commit 0e1b2a1)
  • Version pin with no explanation — README.md: kept the pin, since reproducible runs need it, and added a comment saying to update it when you upgrade. (commit 0e1b2a1)
  • npm description still has the old tagline — packages/cli/package.json (and the root package.json): updated to "The headless agent harness for CI, cron jobs, and container workflows". (commit 7e08c79)
  • Relative EVENTS.md link breaks on npm — packages/cli/README.md: confirmed (line 89 at head, not 83). It is now the absolute GitHub URL. No other relative links remain in that file. (commit 7e08c79)

Review claims verified false (no change needed)

  • "Fork attribution dropped; LICENSE still credits OpenCode" — no change needed. MIT requires the copyright and permission notice in copies of the software. LICENSE keeps both copyright lines unchanged. The published package ships it too: packages/cli/script/build.ts:106 copies LICENSE into the package, and the 0.5.4 tarball contains package/LICENSE with both lines. A README section is not part of that requirement, and the License section links LICENSE.

Not addressed here

Verification: bun test test/flag/flag.test.ts (README contract) 2 pass, 0 fail; pre-push hook (typecheck) 6/6 tasks successful; actionlint on the extracted workflow is clean.

Comment thread README.md Outdated
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`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Event list omits 8 types EVENTS.md documents.

Suggested change
- **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`

Comment thread README.md
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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Comment thread README.md
AICTRL_CONFIG_CONTENT: >-
{"permission": {"*": "deny", "read": "allow", "glob": "allow", "grep": "allow"}}
run: |
aictrl run --format json --model "$MODEL" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚪ 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

Comment thread README.md
env:
GH_TOKEN: ${{ github.token }}

- uses: actions/upload-artifact@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚪ 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

Comment thread README.md Outdated
```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).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚪ "Hermes v0.22.2" vs table's "Hermes 0.22.2".

Suggested change
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 |

@aictrl-dev

aictrl-dev Bot commented Oct 20, 2026

Copy link
Copy Markdown

Code review

Verdict: Address the major findings before merging. · 🔴 0 · 🟠 1 · 🟡 1 · ⚪ 3 · 0/5 resolved

  • ⚪ README.md:117-123 — Flagship example skips the advertised --output-schema
  • 🟡 README.md:126 — Injection egress via auto-posted comment undocumented
  • ⚪ README.md:130-135 — Events artifact duplicates all file contents the agent read
  • ⚪ README.md:140 — "Hermes v0.22.2" vs table's "Hermes 0.22.2"
  • 🟠 README.md:179-182 — Event list omits 8 types EVENTS.md documents
🤖 Fix all 5 open findings with your agent
Fix the following code review findings on aictrl-dev/cli PR #249 (head branch).
Run the relevant tests/linters after each change.

1. README.md:117-123 — 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.
2. README.md:126 — 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`).
3. README.md:130-135 — 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.
4. README.md:140 — "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…"
5. README.md:179-182 — 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.
📋 Out-of-diff findings (5)
Sev Location Finding
⚪ README.md:117-123 Flagship example skips the advertised --output-schema
🟡 README.md:126 Injection egress via auto-posted comment undocumented
⚪ README.md:130-135 Events artifact duplicates all file contents the agent read
⚪ README.md:140 "Hermes v0.22.2" vs table's "Hermes 0.22.2"
🟠 README.md:179-182 Event list omits 8 types EVENTS.md documents

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]>
@byapparov

Copy link
Copy Markdown
Member Author

Review response — PR #249 (second review, 7e08c79)

Replies to the 5 findings in the review of 7e08c79. All five are fixed in 7657442. Each claim below was checked against README.md and EVENTS.md at that head, and against events from a real run: the CLI built from this branch, run against a scripted local model with the example's permission config.

Finding Verdict Action Commit
Event list omits types EVENTS.md documents (README.md:179) TRUE FIX 7657442
Prompt-injected output is posted as the bot's comment (README.md:126) TRUE FIX (note) 7657442
Example uses prose while the table sells --output-schema (README.md:117) TRUE FIX (note) 7657442
Events artifact holds the contents of files the agent read (README.md:130) TRUE FIX (note) 7657442
"Hermes v0.22.2" vs "Hermes 0.22.2" (README.md:140) TRUE FIX 7657442

Issues addressed (pushed to this PR)

  • Event list incomplete — README.md: the list now names every type EVENTS.md documents (26, counting step_start and step_finish separately). It adds session_complete, error, user_message, text, reasoning, step_start, step_finish and skill_resource_loaded. A diff of the list against the ### headings in EVENTS.md is empty. (commit 7657442)
  • Posted review is PR-influenced — README.md: added one sentence: the review is model output shaped by the pull request and is posted as written, so treat it as untrusted text, not an approval. I looked for a control worth adding and found the read surface already closed. With "*": "deny", a read of /proc/self/environ, or of an in-checkout symlink pointing to it or to any file outside the checkout, is rejected by the external_directory rule, and the run output contained no environment canary. The model controls only the comment body, because the post step runs a fixed gh pr comment. Pattern denies such as **/.env* would only cover files already in the checkout, so I left them out. (commit 7657442)
  • Prose vs --output-schema — README.md: added the reason. A schema result is a file the agent writes and then passes to StructuredOutput (session/prompt.ts:58), and this job denies write. (commit 7657442)
  • Events artifact contents — README.md: added a note. The artifact holds the output of every tool call, reads are limited to the checkout, and the artifact has the repository's visibility, so remove the upload step if the record is not needed. On real events, read content sits in part.state.output and part.state.metadata.preview, not metadata.output. The suggested del(.part.state.metadata.output) would therefore remove nothing from read results, so I did not add a strip step. (commit 7657442)
  • Hermes label — README.md: now Hermes 0.22.2, matching the table. (commit 7657442)

Review claims verified false (no change needed)

  • None.

Not addressed here

  • None.

Verification: bun test test/flag/flag.test.ts 2 pass, 0 fail; actionlint on the extracted workflow is clean; pre-push hook 6/6 tasks successful; remote head is 7657442f558895147735ad2471bd87715d5453e1.

@byapparov
byapparov merged commit 47dd3e0 into main Oct 20, 2026
4 checks passed
@byapparov
byapparov deleted the docs/headless-agent-harness-readme branch October 20, 2026 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant