Skip to content

Try it live

This is the actual cogpin.py that ships — no demo reimplementation, no server. It runs in your browser (CPython compiled to WebAssembly), reading the diff you type as the same DiffFacts the engine reads from git. Edit the policy on the left and the change on the right, or hit a preset. The verdict splits into two layers: the agent layer (what Claude Code denies in real time as the agent works — bypassable) and the change layer (the un-bypassable pre-push + CI gate).

A/M/D path file · + line added · - line removed · $ cmd command · @ branch · write> path · commit> msg

try:
booting the real engine in your browser…

The left pane is a cogpin.toml policy. The right pane is a tiny stand-in for a diff — because the engine reads facts, not raw text, you describe the change as facts:

you type the fact
A path / M path / D path a file added / modified / deleted
+ <code> an added line in the current file
- <code> a removed line in the current file
$ <command> a command the agent is about to run (agent layer)
@ <branch> the current branch (for forbid_commit_on_branch)
write> <path> a Write/Edit target (for self_protect)
commit> <message> a commit message (require_message_pattern / forbid_in_message)

Hit run and the engine reports two layers: agent layer denials (what the PreToolUse hook would block in real time) and change layer findings (what pre-push + CI would catch).

  • strip an assert removes an assert line under tests/forbid_removal blocks. The added-line scanners of every other tool are blind to a deletion; this is the - side of the diff.
  • delete the test removes the whole test file → forbid_delete blocks. Add a second A tests/... line and it passes — unless_paired_add reads that as a rename/reorg.
  • commit to main is denied at the agent layer — change @ main to @ feature/x and it’s allowed.
  • scope creep touches a path outside the allowlist → scope_lock blocks. The structural inverse of a denylist: it gates “any file not in the allow-set.”
  • lower coverage flips fail_under 85→75 → numeric_floor blocks. If you only scan the added lines that’s byte-identical to a raise; pairing the number across the removed and added lines is the whole point.
  • edit the gate is a write> cogpin.toml — denied at the agent layer by self_protect, so the agent can’t loosen its own gate mid-session.
  • an un-blockable rule loads a policy that tries to hard-block on a judge (an LLM-judge the agent could sway). The engine refuses to load itseverity="block" requires kind="fact". That error is the moat, enforced at parse time. Flip its severity to warn and it loads.

Everything you can do here, python3 cogpin.py check does in CI — the only difference is CI reads the facts from real git instead of your textarea.