Have an agent summarize a refused wave
Optional: hand this page to your coding agentThe steps work by hand too.Show the whole prompt
Read https://intentius.io/terragucci/guides/agent-refused-wave/.
Add the explain-refusal job for wave <k> to the own-jobs file the guide's tab
for this forge names, set own_jobs in terragucci.yml to that file, run
`npx terragucci init`, give the job no permission beyond what that tab gives,
and open a pull request.
Never apply, approve (a pull request review or `terragucci approve`), override a policy denial (`terragucci override`), use `--mode apply`, or merge; never touch `.chant/allowed_signers` or `chant/lifecycle`.One of four features that run a model; the others are the /terragucci agent comment, the drift agent and the pull request review. It is off until you add its job by hand; every other feature runs without an agent (what needs an agent).
Result
Section titled “Result”One comment on what changed between the approved plan and the refused one. The agent never approves, applies or merges, and its prompt forbids running terragucci.
Prerequisites
Section titled “Prerequisites”| You need | Why |
|---|---|
| Fix a refused wave done once by hand | the agent reads the same diff you print there |
| An API key for the model | the job runs Claude Code |
| On GitHub, a forge token that can comment but not push, approve or merge | the action posts the summary as a comment; on GitLab and Forgejo the summary is in the job’s log and the job needs no token |
The refused wave’s artifact, terragucci-report-apply-wave-<k> |
it holds the approved report and the refused one |
-
Produce the diff, the agent’s input, without a model:
Terminal window npx terragucci respond wave-refused --approved terragucci-report/approved --current terragucci-report/current --wave 2 --jsonThe envelope lists each root whose plan digest moved and what moved inside it.
-
Add the job to a file of your own jobs, and name the file in
terragucci.yml. Each timeinitrewrites its pipeline file, it writes every job the file holds after its own, unchanged.reconciledoes the same in each project of a control repo.terragucci.yml own_jobs: ci/own-jobs.ymlWhat Value Runs when a wave’s apply job fails on a refusal Wave jobs apply-wave-<k>; withwaves.jobs, the wave’s deciding job isapply-wave-<k>and a refused share keeps no approved reportInput the artifact terragucci-report-apply-wave-<k>, holdingapproved/report.jsonandcurrent/report.jsonwhen refusedWave in the examples 2; change the number everywhere for another Claude Code pinned to 2.1.290, the release the agent comment job runs ci/own-jobs.yml. The job runs in theterragucciworkflow after the wave’s job, only when that job failed, and reads that run’s artifact. A barefailure()would also run it on a branch push whose check failed, where the wave never ran.explain-refusal:needs: apply-wave-2if: failure() && needs.apply-wave-2.result == 'failure'runs-on: ubuntu-latestpermissions:contents: readpull-requests: writeissues: writesteps:- uses: actions/checkout@v4- uses: actions/download-artifact@v4continue-on-error: truewith: { name: terragucci-report-apply-wave-2, path: reports }- run: >test -d reports/approved || exit 0;npx -y @intentius/terragucci respond wave-refused--approved reports/approved --current reports/current --wave 2--json > refusal.json- if: hashFiles('refusal.json') != ''uses: anthropics/claude-code-action@v1with:anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}github_token: ${{ secrets.AGENT_FORGE_TOKEN }}prompt: |Read refusal.json. Summarize which roots changed since the approval and whythe plan moved, in five lines or fewer. Do not runterragucci or any apply command.ci/own-jobs.yml.initwrites the job into.gitlab/terragucci.yml, which your.gitlab-ci.ymlincludes. After the wave’s job fails, it finds the artifact unpacked atterragucci-report/. Sharing the apply jobs’ rule keeps it out of a branch’s pipeline, which has noapply-wave-2, andon_failurewithneedsruns it only whenapply-wave-2failed. A wave that failed for another reason leaves no approved report, and the job stops there. Give itANTHROPIC_API_KEYas a masked variable. The summary stays in the job log; nothing is posted.explain-refusal:stage: applyneeds: [apply-wave-2]rules:- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule"when: on_failureimage: node:24script:- test -d terragucci-report/approved || exit 0- >npx -y @intentius/terragucci respond wave-refused--approved terragucci-report/approved --current terragucci-report/current --wave 2--json > refusal.json- >npx -y @anthropic-ai/claude-code@2.1.290 -p"Read refusal.json. Summarize which roots changed since the approval and whythe plan moved, in five lines or fewer. Do not runterragucci or any apply command."ci/own-jobs.yml. Forgejo’s runner takesactions/download-artifact@v3, which reads only its own run’s artifacts, so the job runs in theterragucciworkflow beside the wave’s job, only when that job failed.anthropics/claude-code-actionis a GitHub app, so the job runs the CLI and the summary stays in its log. The key is a repository secret; the job needs no write token.explain-refusal:needs: apply-wave-2if: failure() && needs.apply-wave-2.result == 'failure'runs-on: dockercontainer: node:24steps:- uses: actions/checkout@v4- uses: actions/download-artifact@v3with: { name: terragucci-report-apply-wave-2, path: reports }- run: >test -d reports/approved || exit 0;npx -y @intentius/terragucci respond wave-refused--approved reports/approved --current reports/current --wave 2--json > refusal.json- run: >test -f refusal.json || exit 0;npx -y @anthropic-ai/claude-code@2.1.290 -p"Read refusal.json. Summarize which roots changed since the approval and whythe plan moved, in five lines or fewer. Do not runterragucci or any apply command."env:ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}Then run
npx terragucci initand commit the pipeline with the file. A job nameinitalready gives one of its own jobs is refused. -
Read the summary and choose between approving the new plan and reverting the change. The choice and the approval (
terragucci approve) are yours.
MCP or --json
Section titled “MCP or --json”| Where the agent runs | What it uses |
|---|---|
| in the explain-refusal job | respond wave-refused --json from the shell, on the wave’s artifact: the job has the two reports and no bucket credentials |
| at your desk | terragucci mcp: run_view for where each wave of the commit stands, report for the refused wave’s report, and waiting for each wave that waits for an approval, with the command a person runs to approve it |
These docs count page views and clicks with PostHog. They set no cookies, store nothing in your browser, and send nothing when your browser asks not to be tracked.