feat(loops): external scheduler + scheduler-side kill switch (phy, 8cj) - #22
Merged
Merged
Conversation
…y-triage (phy, 8cj) Workflow .github/workflows/loop-triage.yml: daily cron 09:17 UTC + workflow_dispatch, caps in-file (timeout-minutes 15 + --max-turns 25), deterministic report-only guard step enforcing the STATE.md/run-log.md surface, minimal contents:write permissions. Three-layer kill switch documented in LOOP.md, budget.md, safety.md: LOOP_PAUSE_ALL variable (scheduler pause) / gh workflow disable (hard-off) / STATE.md flag (in-band). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d-team) Security review (2 codex passes + 1 confirm + RED-TEAM lens) drove a re-architecture: - Two separated jobs (gh-aw safe-outputs pattern): agent runs contents:read + no push token, emits only STATE.md/run-log.md as an artifact; a fresh-checkout commit job the agent never touched holds the write token and transplants exactly those two paths. Kills the whole 'untrusted agent contaminates a later privileged step' class ($GITHUB_ENV poisoning, planted git hooks, push-before-guard, diff-HEAD-misses-commit). - persist-credentials:false; all 4 actions SHA-pinned; ubuntu-24.04; input-discipline prompt (public text AND prior STATE.md prose = untrusted data); doc precision on max-turns!=spend and LOOP_PAUSE_ALL fail-open semantics. Accepted residual (bead builder-guild-bgo): API-key egress (bounded: credit-burn only). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
adithya0597
added a commit
that referenced
this pull request
Jul 20, 2026
…ts, loops/ restructure, PR #22 scheduler+kill-switch Append session block on top; refresh Next Steps 0 (merge #22 -> bead 006 ops proof -> bgo egress decision -> ye0 settings-fix), Key Files (scheduler on #22 branch + local audits), Tracker Delta (opened 13 / closed 3 / 23 open of 145), Status + Branch graph verified live. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, $0 marginal) The scheduled loop-triage job needs a stored credential to run Claude in headless CI (no interactive subscription session on a runner). Wire the claude-code-action to claude_code_oauth_token (from `claude setup-token`) instead of the metered anthropic_api_key: reuses the Claude Code subscription at $0 marginal, so there is no per-token billing to exfiltrate/cap (bgo moot). Founder still sets the secret; this only changes which input the workflow reads. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Founder highlights — this PR touches t2 (highest-risk) surface. Files that triggered t2:
|
adithya0597
added a commit
that referenced
this pull request
Jul 21, 2026
…ublish gate, guard, env)
Cherry-set of the pure bug-fix layer from feat/loop-engineering-v3, split out
per adversarial review so fixes are not bundled with loop automation infra:
- tools/publish_gate.sh: NUL-delimited staged-file loop — the previous
`for f in $FILES` word-split let a secret in a spaced filename exit CLEAN
(P1; functionally re-proven: spaced-filename ghp_ token now BLOCKS exit 1)
- 03-evals/src/eval_{corrective,ocr,planner}.py: diagnostics interpolate the
resolved Neo4j URI instead of hardcoded bolt://localhost:7688
- 03-evals/{golden_v1_review.md,src/{golden_v1_draft,test_g3,h3_instr}.py}:
stale claims corrected (6 roles -> 3 roles; docstring drift)
- tools/run_guard.py: self_test docstring matches ALLOWLIST-exemption behavior
(GUARD_SELFTEST_OK)
- 01-context/setup_a2.sh: pin neo4j-graphrag
- .env.example: correct Neo4j/paperclip facts; add LANGFUSE_HOST/BG_EMBED_MODEL
- .gitignore: ignore .claude/lessons.md (local working notes)
Loop scheduler/heartbeat/rulesets stay on the feature branch (PR #21/#22).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
adithya0597
added a commit
that referenced
this pull request
Jul 21, 2026
…ublish gate, guard, env) (#23) Cherry-set of the pure bug-fix layer from feat/loop-engineering-v3, split out per adversarial review so fixes are not bundled with loop automation infra: - tools/publish_gate.sh: NUL-delimited staged-file loop — the previous `for f in $FILES` word-split let a secret in a spaced filename exit CLEAN (P1; functionally re-proven: spaced-filename ghp_ token now BLOCKS exit 1) - 03-evals/src/eval_{corrective,ocr,planner}.py: diagnostics interpolate the resolved Neo4j URI instead of hardcoded bolt://localhost:7688 - 03-evals/{golden_v1_review.md,src/{golden_v1_draft,test_g3,h3_instr}.py}: stale claims corrected (6 roles -> 3 roles; docstring drift) - tools/run_guard.py: self_test docstring matches ALLOWLIST-exemption behavior (GUARD_SELFTEST_OK) - 01-context/setup_a2.sh: pin neo4j-graphrag - .env.example: correct Neo4j/paperclip facts; add LANGFUSE_HOST/BG_EMBED_MODEL - .gitignore: ignore .claude/lessons.md (local working notes) Loop scheduler/heartbeat/rulesets stay on the feature branch (PR #21/#22). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the first two loop-operationalization beads (epic `builder-guild-tic`) via `/buildloop` run `bl-20260720-sched`. Turns the daily-triage loop from configured-but-dormant into scheduled — with enforcement in the platform layer, not the agent's prompt.
What lands
phy— external scheduler:.github/workflows/loop-triage.yml—on: schedulecron (09:17 UTC) +workflow_dispatch; caps in-file (timeout-minutes: 15+--max-turns 25);concurrencygroup forbidding overlap.8cj— scheduler-side kill switch: job-levelif: vars.LOOP_PAUSE_ALL != 'true'(GitHub evaluates it before any agent code runs) +gh workflow disableas the unconditional hard-off; three-layer kill-switch documented consistently in LOOP.md / safety.md / budget.md.Security architecture (two separated jobs — the safe-outputs pattern)
Three review rounds (2 codex passes + 1 confirm + a RED-TEAM lens) found and closed a real guard-bypass class. Final design:
triagejob:contents: read,persist-credentials: false, runs the agent with no push token; emits onlySTATE.md+run-log.mdas an artifact.commitjob:needs: triage,contents: write, a fresh checkout the agent never touched, transplants exactly those two paths, guards (working tree may differ only on the two files), commits + pushes.This structurally kills "untrusted agent contaminates a later privileged step" (
$GITHUB_ENVpoisoning, planted git hooks, push-before-guard,diff HEADmissing agent commits). All 4 actions SHA-pinned;ubuntu-24.04; input-discipline prompt (public text and prior STATE.md prose treated as untrusted data).Report-only, gated, honest
Accepted residual (founder decision — bead `builder-guild-bgo`)
API-key egress from the agent job: bounded to credit-burn (rotatable; the write token never meets untrusted code), so not auto-hardened at L1. Options (harden-runner egress-allowlist / org spend cap) filed for your call.
🤖 Generated with Claude Code