feat: agent guardrails (verify_commit, dispatch audit, opencode guardrails plugin) #110

Merged
alee merged 45 commits from feat/agent-guardrails into main 2026-10-05 01:31:12 +00:00

45 Commits

Author SHA1 Message Date
adlee-was-taken
2c84417062 docs: guardrails replay report regenerated at HEAD 2026-10-04 12:46:09 -04:00
adlee-was-taken
d7134337ab fix(opencode-plugin): git commit -a detection reads flags, not words 2026-10-04 12:46:04 -04:00
adlee-was-taken
14365f493c fix(opencode-plugin): bash_main_checkout redirects ignore quoted text 2026-10-04 12:45:56 -04:00
adlee-was-taken
1cfc4ff49c style: fix import block spacing in tests/test_oc_dispatch_audit.py 2026-10-04 11:38:27 -04:00
adlee-was-taken
2ae39063a0 style: fix import sorting in tests/test_oc_dispatch_audit.py 2026-10-04 11:29:36 -04:00
adlee-was-taken
4d7efd4b2c fix(opencode-plugin): bash_protected_port ignores text that only mentions the port 2026-10-04 11:02:30 -04:00
adlee-was-taken
3425e827a2 docs: final guardrails replay report, every blocked call labelled 2026-10-04 10:43:38 -04:00
adlee-was-taken
8e09c9c2ff fix(opencode-plugin): bash_main_checkout sees git -c and env wrappers 2026-10-04 09:56:44 -04:00
adlee-was-taken
f5b732ad14 docs: complete guardrails replay report from a real read-only run 2026-10-04 08:06:33 -04:00
adlee-was-taken
4de2260d79 test(scripts): restore the check_lint SKIP and integration tests deleted in R13 2026-10-04 08:03:00 -04:00
adlee-was-taken
3ef3d2d246 fix: R19 - redirect exemption, replay cleanup, and R15 missing tests
Fix defect t: checkBashMainCheckout redirect exemption now uses
join(directory, '.omo') matching checkWriteOutsideWorktree.

Fix defect u: replay deletes its temp omoDir on exit via try/finally.

Add R15 missing tests:
- read-only --directory: verifies .omo files unchanged, no new files
- one-call-per-rule: fixture triggers each rule, checks Always/(B) tables
- per-session scope: two sessions with different worktrees don't block
2026-10-04 07:53:09 -04:00
adlee-was-taken
cacddebd91 fix(opencode-plugin): bash_main_checkout matches git operations, not words 2026-10-04 07:42:19 -04:00
adlee-was-taken
a64bcc5e03 chore: fix RUF059 unused unpacked variable detail in test_verify_commit.py 2026-10-04 07:19:55 -04:00
adlee-was-taken
970bdd7602 docs: guardrails replay calibration report from a real read-only run 2026-10-04 06:46:31 -04:00
adlee-was-taken
5271a97f14 fix(opencode-plugin): bash segments are quote-aware across newlines
Defect r: a newline inside a quoted string was splitting bash commands, causing false blocks.
- Replaced regex split with a manual parser tracking single, double, and backtick quotes.
- Added support for heredocs (<<EOF ... EOF) so their bodies stay as single segments.
- All existing tests pass; added cases for multi-line node/python calls and heredocs.
2026-10-04 06:43:09 -04:00
adlee-was-taken
6fb89e2693 fix(opencode-plugin): replay isolation, omoDir, ruleId enrichment, per-session scope
Defect p: guardrails-replay writes synthetic config/boulder to a temp
directory (mkdtempSync) via new omoDir parameter, never under --directory.

Defect q: getStatBucket groups "bash_banned" and "bash_protected_port"
into "Always-Scope" table; all other rules into "(B) Scoped".

ruleId enrichment: every Error thrown by a guardrail rule now carries
err.ruleId (one of the 8 config IDs).

omoDir threading: Guardrails factory takes an omoDir param (defaults to
<directory>/.omo). loadConfig, readBoulder, _openLog, and all scope-gated
checks (checkWorktreeLine, checkWriteOutsideWorktree, checkBashMainCheckout,
checkPlanTickGate) thread a 'base' arg so they read artifacts from omoDir.

Cache invalidation: added _boulderBase and _configBase alongside _boulderDir
/_configDir. Cache key is (directory, base, mtime) to prevent stale reads
when omoDir differs across sessions.

Per-session scope in replay: Guardrails reads boulder.json once at factory
creation. Replay loop creates one factory per session, writing that session's
boulder to disk before instantiation.

Tests: 219 pass (guardrails.test 184 + guardrails-replay.test 5 +
guardrails.contract.test 30).
2026-10-04 06:23:04 -04:00
adlee-was-taken
d6c4eb4f8f fix(scripts): verify_commit.py caps failure detail at 20 lines
Defect o: When tests FAIL, the detail is at most 20 lines total.
- Fixed ERROR prefix: pytest prints 'ERROR ' (not 'ERRORS ')
- Truncation with '... and N more' when summary exceeds 20 lines
- Fallback (last 20 lines) unchanged
2026-10-04 06:06:46 -04:00
adlee-was-taken
5802c7b7c5 fix(scripts): verify_commit.py lint ignores ruff summary lines
Defect n: check_lint now filters ruff output to only match real finding
lines (pattern: <path>:<line>:<col>: <CODE> <message>). Summary lines
like 'All checks passed!', 'Found N error(s).', and '[*] N fixable ...'
are ignored.
2026-10-04 06:02:24 -04:00
adlee-was-taken
ddb1ebb377 fix(opencode-plugin): task_worktree_line rewrites output.args and parses the real line forms
Defects fixed:
- (k) Rewrite targets output.args.prompt, not output.prompt
- (l) Prepended line uses actual main checkout directory, not parent of worktree
- (m) Parser accepts 'path. cd there', 'path -- cd there', 'path' forms;
      dotted paths (e.g. feat.v2) are no longer truncated
2026-10-04 05:56:15 -04:00
adlee-was-taken
7076d23808 chore: fix F841 unused variable in test_verify_commit.py 2026-10-04 05:16:06 -04:00
adlee-was-taken
a6bb66b168 chore: fix F841 unused variable in test_verify_commit.py 2026-10-04 05:15:17 -04:00
adlee-was-taken
cee45dff8f chore: fix F841 unused variable in test_verify_commit.py 2026-10-04 05:14:19 -04:00
adlee-was-taken
53fb342645 chore: rm stale pre-tool-advisory-throttle state files 2026-10-04 05:02:22 -04:00
adlee-was-taken
ff365cf493 chore: clear the new ruff findings in the guardrails scripts and tests 2026-10-04 05:02:13 -04:00
adlee-was-taken
981d76aa7f fix(opencode-plugin): replay reads the real opencode API; add the real calibration report 2026-10-04 04:44:20 -04:00
adlee-was-taken
99b203e82d fix(scripts): verify_commit.py shows the failing tests, not the warnings tail 2026-10-04 04:12:39 -04:00
adlee-was-taken
a414ed4238 test(opencode-plugin): restore the guardrails unit tests deleted in R4, on the real hook shapes 2026-10-04 04:09:17 -04:00
adlee-was-taken
c5114c5bbc fix(guardrails): relax task_needs_agent to allow any of category, subagent_type, or task_id 2026-10-04 02:59:54 -04:00
adlee-was-taken
8842fb3e1a fix(scripts): verify_commit.py lint check crashes on ruff full-format output 2026-10-04 01:38:14 -04:00
adlee-was-taken
80b7fd3dd6 docs: agent guardrails, verify_commit and dispatch audit 2026-10-04 01:14:32 -04:00
adlee-was-taken
ee806f3974 feat(opencode-plugin): replay recorded sessions through the guardrails; calibration results 2026-10-04 01:04:57 -04:00
adlee-was-taken
aaa14f5258 test(opencode-plugin): contract test drives the plugin with opencode's real hook shapes 2026-10-04 00:26:32 -04:00
adlee-was-taken
e996de335e fix(opencode-plugin): an unlisted rule defaults to block 2026-10-04 00:18:11 -04:00
adlee-was-taken
4047f104f9 fix(opencode-plugin): read the boulder from .omo/boulder.json and scope (B) rules to the active work 2026-10-04 00:13:35 -04:00
adlee-was-taken
1780090b84 fix(opencode-plugin): read tool args from output.args, the real hook signature 2026-10-03 23:50:34 -04:00
adlee-was-taken
1d3e5076f2 fix(scripts): verify_commit.py takes the commit as a positional SHA, per Design A
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-10-03 23:39:47 -04:00
adlee-was-taken
eb8707cea4 chore: untrack the .omc state file committed with oc_dispatch_audit
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-10-03 23:33:47 -04:00
adlee-was-taken
976f2801a2 feat(opencode-plugin): refuse to tick a todo while verify_commit fails 2026-10-03 13:21:39 -04:00
adlee-was-taken
11a3b77585 feat(opencode-plugin): bash_banned and bash_protected_port guardrails 2026-10-03 12:55:37 -04:00
adlee-was-taken
1276461504 feat(opencode-plugin): guardrails keep boulder work out of the main checkout 2026-10-03 12:31:49 -04:00
adlee-was-taken
c38712197c feat(opencode-plugin): guardrails for task dispatch 2026-10-03 12:21:41 -04:00
adlee-was-taken
2de8820cce feat(opencode-plugin): guardrails plugin skeleton, config, log and failure policy 2026-10-03 12:05:19 -04:00
adlee-was-taken
cc7e51d0f5 feat(scripts): oc_dispatch_audit.py flags dead, banned and worktree-less dispatches 2026-10-03 11:45:55 -04:00
adlee-was-taken
4c8f1b115f feat(scripts): verify_commit.py gates new ruff findings in touched files 2026-10-03 11:41:02 -04:00
adlee-was-taken
221515ce32 feat(scripts): verify_commit.py runs the tests a commit touched, against the committed tree 2026-10-03 11:08:08 -04:00