Local guard layer for AI coding agents. Hooks into Claude Code, Codex, Cursor, Copilot CLI, and Gemini CLI; evaluates every tool call against deterministic rules; blocks the dangerous ones in milliseconds; keeps a local activity log you can grep.
Node 22+, macOS or Linux. No npm package yet — git clone is on purpose, until the public surface stabilizes.
$ claude ❯ clean up the build artifacts before deploy I'll remove the build output now. → Bash: rm -rf / ⚠ BLOCKED by interlinked harness rule: builtin-rm-rf-root (critical) reason: Recursive deletion of root-level or wildcard paths is dangerous. hint: Be more specific about what to delete. ms: 1 Let me try the project's build output instead. → Bash: rm -rf ./dist ✓ allowed Removed 14 files.
Illustrative. The rule (builtin-rm-rf-root) and reason text are loaded verbatim from src/harness/rules/builtin-rules-processes.ts; the surrounding agent dialogue is synthesized to show the block-and-recover flow.
The receipt
The author dogfooded the harness on his own machine for two weeks while writing it. The activity log captured 446 guard_block events; the rows below are the ones that survived a per-event audit against Claude Code's session transcripts to confirm the agent's actual tool_input.
Some early dramatic-looking categories (shutdown, root-level rm -rf, DROP TABLE) turned out to be false positives — the rules' substring matchers fired on commit-message bodies, echo arguments, and grep patterns. Those rules were tightened with command-start anchors and quote masking; the table reflects only blocks where the agent's resolved command actually matched the row's intent.
Data as of 2026-05-07. Audit method: npm run docs:audit-receipts (re-runs the per-event transcript correlation locally).
| Count | Severity | What the agent tried |
|---|---|---|
| 84 | high | Edits that introduced a new TypeScript error — blocked before the write landed (tsc-diff-overlay) |
| 35 | high | Used shell redirect (cat > file.ts) to dodge the content-quality gate |
| 29 | high | Created a new source file with no companion test |
| 25 | high | Empty catch {} blocks landing in code |
| 18 | critical | Wrote outside the repo root (e.g. /tmp/x.ts) |
| 4 | critical | Tried to kill a PID that turned out to be the harness or session process |
| 219 | — | Did not survive audit. Substring-matching FPs from older destructive-command rules (now fixed), unbucketed TypeScript advisories, and miscellaneous low-severity flags. Reported here for honest accounting; not counted in the headline. |
Verified blocks
195
Rule eval p50
2 ms
Total events logged
446
Built-in rules
105
How it works
Every PreToolUse hook fires a JSON-RPC message at .interlinked/harness.sock. The harness evaluates rules, returns a decision, and (optionally) attaches warnings the agent will see on its next turn.
Local-only
No cloud, no telemetry, no LLM in the hot path. The socket is on your machine; the activity log stays in your repo.
Multi-runner
Same harness for Claude Code, Codex, Cursor, Copilot CLI, and Gemini CLI. One config, every agent.
Deterministic
Regex + AST + a handful of compilers (tsc, biome, gitleaks, semgrep). Replayable from the JSONL log.
Configurable
Team-shared rules in .interlinked/guard-rules.json; personal overrides in guard-rules.local.json (gitignored).
# the hot path agent (Claude / Codex / Cursor / Copilot / Gemini) ├─→ interlinked-hook (~0.1 ms) │ ├─→ .interlinked/harness.sock │ │ └─→ guard eval (block / allow / warn) ............ ~1 ms │ │ └─→ post-edit quality + structural checks ........ ~50–600 ms │ │ │ └─→ .interlinked/activity.jsonl (append-only, ~0.1 ms) │ └─→ interlinked {status, activity, explain, doctor}
Why this and not …
| Capability | Interlinked | Husky / pre-commit | claude-code-action (CI) | No harness |
|---|---|---|---|---|
| Blocks tool calls before the agent runs them | ✓ PreToolUse hook | — | — (CI is post-action) | — |
| Runs locally, no network on hot path | ✓ | ✓ | ✗ runs in GitHub | — |
| Multi-agent runner support | ✓ 5 runners | — (git only) | — (Claude Code only) | — |
| Median rule-eval latency | ~1–2 ms | ~50–500 ms | 10s+ (CI startup) | — |
| Logs every PreToolUse / PostToolUse | ✓ JSONL, replayable | — | CI logs only | — |
| Catches dangerous shell commands (rm -rf, kubectl delete --all, …) | ✓ 105 rules | — (file lints, not commands) | depends on prompt | — |
| Compiles proposed file content before write lands | ✓ tsc / biome diff-overlay | post-commit only | CI only | — |
| Open-source, MIT | ✓ | ✓ | ✓ | — |
Husky and pre-commit are great at what they do — git-time linting on file content. They sit downstream of the moment the agent runs an arbitrary shell command. Interlinked sits at that moment.
FAQ
.interlinked/activity.jsonl in the repo it's instrumenting. The CLI makes no outbound network calls on its own — only the server-backed commands you explicitly run (login, sync, etc.) talk to the network.
git clone && npm link is a deliberate filter for serious users. A 0.2 release on npm is planned once the surface stabilizes.
balanced / lenient / strict) governs the second layer.
tsc, biome) take whatever the compiler takes; for a typical TS file that's a few hundred milliseconds, and the agent only pays it if the diff is suspicious. Latency budgets are enforced per tool class.
.interlinked/guard-rules.json is committed and read by every machine that has the harness; .interlinked/guard-rules.local.json is gitignored and used for personal overrides. The /enforce skill also distills imperative prose from AGENTS.md / CLAUDE.md into the same JSON format.
Five minutes from git clone to your first guard_block in .interlinked/activity.jsonl.