Skip to content

feat(guard): guardrails around every tool call — rules, baseline, loop interception, /rules (CLEAN-152) - #26

Open
maksymhryzodub-prog wants to merge 1 commit into
feat/CLEAN-151-harness-foundationfrom
feat/CLEAN-152-guardrails
Open

maksymhryzodub-prog wants to merge 1 commit into
feat/CLEAN-151-harness-foundationfrom
feat/CLEAN-152-guardrails

Conversation

@maksymhryzodub-prog

Copy link
Copy Markdown
Contributor

Stacked on #25 (foundation) → #24 (spec). US1 of specs/001-ecc-agent-principles — the MVP phase. Tasks T013–T028.

What

  • agent/guard slice — rules are markdown files with frontmatter (.agent/rules/*.md), same convention as skills. Four protected baseline rules ship with the runtime: no-secret-store-reads, no-env-reads (before, block), redact-credentials, record-all (after). Actions compose strictest-first: block > redact > record.
  • Matcher — tool globs (exec|file, ranch__*, *), JSON-path argument regexes with relative paths resolved against the agent dir (cat data/secrets/x ≡ /agent/data/secrets/x), result regexes. Object params are matched as their raw strings and as JSON.
  • Fail semantics (FR-004) — load is all-or-nothing: one bad file → GuardLoadError naming file + field, previous set stays; until a load succeeds every call is blocked with the reason. Redact rules fail closed (result withheld on evaluator error); observers fail open, bounded by guard.observerTimeoutMs, logged once per rule.
  • Loop interception — before() ahead of tool.execute, after() on the result. Transcript keeps the raw result; the model's history copy and the outgoing reply are redacted (same split as the CLEAN-124 size cap). tool_result events carry blocked / redacted; every call → data/toolcalls.jsonl (tool, outcome ok/error/blocked/timeout, duration, sizes, rules fired, effect).
  • Operator surface — /rules, /rules reload (admin; a bad file keeps the previous set and the reply names it), rules summary in agent_status, start-up blocks tools with the reason on load failure.
  • Eval — tests/evals/guardrails.jsonl, 31 extraction attempts (direct, roleplay, "for debugging", via script, python/node, base64, copy-out, .env variants) + blocked mode in bun run eval.

Deviation from the plan

The contract listed a cap-result-size baseline rule. The size cap stays config-driven (tools.maxOutputChars) in the loop: a rule transforms the result the guard sees, while the cap must trim only the model's copy and leave the transcript intact. Noted in contracts/commands-and-config.md.

Tests

  • bun test: 230 pass (41 new: matcher 12, service 24, loop integration 3, …), 1 pre-existing Windows-only failure (telegramFile).
  • bun run eval: guardrails 31/31 = 100 % (SC-001).
  • tsc --noEmit: clean apart from the pre-existing bridleAttachments.spec.ts errors.

Jira: https://dreamvention.atlassian.net/browse/CLEAN-152

🤖 Generated with Claude Code

…p interception, /rules (CLEAN-152)

US1 of the ECC harness principles (specs/001-ecc-agent-principles, T013-T028).

- New agent/guard slice: rules as markdown + frontmatter in .agent/rules/
  and a protected platform baseline (no-secret-store-reads, no-env-reads,
  redact-credentials, record-all). Actions block / redact / record compose
  strictest-first; tool globs, JSON-path argument regexes with relative
  paths resolved against the agent dir, result regexes.
- Fail semantics: load is all-or-nothing (a bad file keeps the previous set
  and is named with its problem); until a load succeeds every call is
  blocked; redact rules fail closed, observers fail open and are bounded
  by guard.observerTimeoutMs, logged once per rule.
- LoopService.executeToolCalls runs before() ahead of the tool and after()
  on the result: the transcript keeps the raw result, the model and the
  reply get the redacted one; tool_result carries blocked/redacted flags;
  every call lands in data/toolcalls.jsonl with outcome, duration, sizes,
  rules fired and effect.
- /rules and /rules reload (admin), rules summary in agent_status, runtime
  loads rules at start and blocks tools with the reason on failure.
- tests/evals/guardrails.jsonl (31 extraction attempts) and the `blocked`
  eval mode: 100% blocked.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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