Skip to content

Fix #249: project rules (ratchet) from agent failures with incident and expiry - #254

Merged
vicgupta merged 1 commit into
mainfrom
amf/issue-249
Oct 30, 2026
Merged

vicgupta merged 1 commit into
mainfrom
amf/issue-249

Conversation

@vicgupta

Copy link
Copy Markdown
Owner

Closes #249

Summary

Adds project rules ("ratchet"): when an agent fails, record a rule in .tinyagent/ratchet.toml with the incident that caused it and an expiry date or review condition.

  • tinyagent ratchet add "<rule>" --incident "..." [--expires YYYY-MM-DD | --review "..."] [--deny-command|--deny-path|--deny-host|--deny-tool ...], plus ratchet list [--json], ratchet remove <id>, ratchet path (flag forms --ratchet-*). No model request, no credentials.
  • Fresh runs load the file automatically when it exists: active rules become a "Project rules" system prompt section (after project memory), each with its id and incident.
  • Rules with a deny matcher are also enforced as permission deny rules (blocked by project rule <id>: ...); deny wins over every allow.
  • Expired rules are skipped with a warning naming how to prune or renew them.
  • ratchet.loaded JSON event (path, loaded, ids, expired, enforced); --verbose summary line.
  • --no-ratchet skips the rules for a run.

New code lives in internal/ratchet and cmd/tinyagent/ratchet_cmd.go; main.go gets only registration, dispatch and the load/start calls. No dependency changes (TOML via the existing BurntSushi dep).

Testing

  • gofmt -l . clean, go build ./..., go vet ./..., go test -count=1 ./... all pass locally.
  • internal/ratchet: load/validate (unknown keys, duplicate ids, bad dates, expires-or-review, one matcher), expiry split, prompt section, permission rule mapping, add/remove with atomic save, missing file and .tinyagent being a file.
  • cmd/tinyagent (fake model server only): add/list/list --json/path/remove via both subcommand and flags; usage errors exit 2 without creating the file; a run injects active rules, omits expired ones, warns, emits ratchet.loaded, and blocks a denied bash command before it runs; no file means no event and nothing created; --no-ratchet; an invalid file exits 2.

Docs updated

  • New docs/ratchet.md (file format, commands, run behavior, enforcement, limits).
  • README.md: feature list entry with link, documentation table row, subcommand examples.
  • docs/subcommands.md: ratchet subcommand rows, subcommand lists, and all 12 new flags in the full flag reference.
  • docs/json-output.md: ratchet.loaded event.
  • docs/permissions.md: notes that ratchet deny rules are the one repository-sourced (deny-only) addition to the policy.
  • docs/config.md: unchanged, since no new config keys were added.

Decisions on open questions

  • Storage: .tinyagent/ratchet.toml at the project root (plain, reviewable TOML); the docs recommend committing it and un-ignoring it if .tinyagent/ is gitignored.
  • Loading: automatic only when the file exists (zero cost otherwise, nothing created); --no-ratchet opts out. No config key, to keep the surface small.
  • No expiry given: a rule without --expires or --review defaults to expiring in 90 days, so nothing lives forever by accident.
  • Expired rules: skipped (not enforced, not in the prompt) with one warning each, and listed in the event's expired field; nothing is deleted automatically.
  • Enforcement: optional and deny-only, so repository content can restrict but never widen what a run may do. Patterns are validated when a rule is added.
  • Invalid file: stops the run with exit 2 before any model request, rather than silently losing enforcement.
  • Scope: fresh runs only; --resume/follow-ups replay the checkpoint's saved system prompt, and ACP sessions don't load rules yet (documented).
  • IDs: sequential r1, r2, ...; ratchet remove <id> for pruning. No automatic rule drafting from failures, to keep humans in the loop.

Rules in .tinyagent/ratchet.toml keep their incident and an expiry date
or review condition. Active rules go into the system prompt, rules with a
deny matcher are enforced as permission deny rules, expired rules are
skipped with a warning, and tinyagent ratchet add|list|remove|path
manages the file.
@vicgupta
vicgupta merged commit f4e3f0a into main Oct 30, 2026
1 check passed
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.

Ratchet: turn agent failures into rules with incident and expiry

1 participant