Guide: run operate agents automatically in CI
The operate agents (tester, documentation, interaction) can run by hand (operate-goose) or automatically in CI. Automating them is safe only under one rule, so read the classification first.
The security classification (read this before automating anything)โ
Whether an operate agent may run automatically depends on two things: what it can do, and what it runs on.
- Input is trusted or untrusted. Post-merge content (a human already reviewed and merged it) is trusted. Pre-merge content from a pull request, especially a fork, is untrusted, the same membrane as the review lenses.
- The agent is tool-using or execution-free. A tool-using agent has a shell (the Goose
developerbuiltin): it can run commands and reach the network. An execution-free agent has no shell, only read-only knowledge and thespec_checkgate (for examplerecipes/interaction-public.yaml).
The rule: a tool-using agent must not run automatically on untrusted input. A prompt injection in that input could use the shell to exfiltrate the model credential. A tool-using agent runs automatically only on trusted input (post-merge), or, on untrusted input, only if it is execution-free or sandboxed with no network egress.
This is not left to a comment. cli/operate-guard.py enforces it, and every
operate runner calls it:
python3 cli/operate-guard.py recipes/documentation.yaml --input trusted # ok (tool-using, trusted)
python3 cli/operate-guard.py recipes/documentation.yaml --input untrusted # REFUSED (exit 1)
python3 cli/operate-guard.py recipes/interaction-public.yaml --input untrusted # ok (execution-free)
The shipped pattern: post-merge doc syncโ
init.sh --goose installs one worked example: the documentation agent, run post-merge (on: push: main, so trusted input), which posts its proposed doc updates as an advisory comment on the merged PR.
It proposes only; it never merges and never edits code, and it dry-runs until a model is wired.
- Workflow:
.github/workflows/asdd-docsync.yml - Runner:
.github/asdd/operate/docsync.sh(calls the guard, then the documentation recipe)
Because the trigger is post-merge, the tool-using documentation agent is allowed. The runner still asserts it through the guard, so the classification holds even if someone changes the trigger later.
Adding another agentโ
Copy the pattern and keep the rule:
- A tool-using agent (tester, documentation) automates only on a trusted trigger (post-merge). The tester on an open PR needs the sandboxed path (no network egress, isolated secrets), not this single-workflow shape.
- An execution-free agent (the public interaction agent) may automate on an untrusted trigger, because it has no shell to exfiltrate through.
Wire a live model by setting the repo ASDD_MODEL_URL + ASDD_MODEL variables and the
ASDD_RUNTIME_TOKEN secret (the same config the review gate uses); until then the runner dry-runs.