Skip to content

issue-worker: issues become pull requests, through Agent Orchestrator on rax - #4

Merged
h0ffmann merged 3 commits into
mainfrom
claude/agents-issue-worker
Nov 1, 2026
Merged

h0ffmann merged 3 commits into
mainfrom
claude/agents-issue-worker

Conversation

@h0ffmann

@h0ffmann h0ffmann commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

What

issue-worker turns one issue into one pull request per run. It's built on Agent Orchestrator (ao, Apache-2.0), running in a rax pod: the daemon lives only for the run, makes the worktree, and runs Claude Code in tmux.

  • Trigger: the oldest open issue labelled agent-ready by someone who can write to the repo. The worker reads its title and body, never its comments.
  • Labels: agent-working before work starts, so a dead run isn't paid for twice. agent-blocked, with the reason as a comment, when a person has to step in.
  • Result: a bilingual PR on agents/issue-<n> that closes the issue. It never merges.

Why the worker has no shell

Every task pod gets the App's private key in its environment, and on nix-os a merge is a deploy. A worker with a shell could read that key. So:

  1. rules/worker-settings.json, installed as Claude Code's managed settings, denies Bash, the web tools, sub-agents, reading /proc, and writing .claude/ or .git/. The agent refuses to start if the file is missing, writable or weaker.
  2. ao starts from an empty environment holding only Claude's token.
  3. The harness checks the diff (12 files, 400 lines, no .github/, .claude/, keys/, flake.lock, key files, stateVersion or credentials), and only then mints a write token, commits with repo hooks off, pushes and opens the PR.
  4. Every git call names the git directory in the clone, as gramatico-loop does: the worktree's .git file is never read, so one the worker rewrites can't run code in a pod holding the key.

The cost: AO's main feature, sending CI failures and review comments back to the worker, isn't used, because the session ends with the pod. The worker also can't run checks, so PR CI is the first real test of its work.

Verified

  • test/run.sh passes on Linux, with new scenarios for the happy path, an untrusted labeller, forbidden files, a blocked worker, a worker that stops without a result, a credential in the diff, a worker that can't be stopped, and missing settings.
  • Mutation checks: emptied environment removed, label check removed, diff check removed, settings check removed. The suite failed each time.

Not verified

  • The real ao has not been run. Its calls come from reading the v0.14.8 source, and test/fake-ao fakes them. Run test/ao-smoke.sh before merging: it runs the real ao from the image, in pod limits, with a stand-in for Claude.
  • The deny rules have not been tested against the real Claude Code, because that needs a real token. The first real run needs someone watching it. Check especially that a TUI session starts without a blocking dialog, that the prompt arrives, and that Bash really is denied.
  • Memory in a real session under 768 Mi.

The image grows by ao, tmux, and the managed settings, which apply to every agent. No other agent uses a denied tool.

🤖 Generated with Claude Code

…hrough Agent Orchestrator

The daemon lives for one run in a rax pod. The worker only edits files: managed settings take its
shell and network tools, and ao starts from an empty environment. The harness checks the diff,
commits, pushes and opens the pull request. It never merges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
h0ffmann and others added 2 commits November 1, 2026 14:20
Both sides kept. The harness now names the worktree's git directory, as gramatico-loop does, so a
.git the worker rewrites never runs as code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@h0ffmann
h0ffmann merged commit c1bbebb into main Nov 1, 2026
3 checks passed
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