Agent Fables
Provides offline, evidence-based preflight risk assessment for agent actions, returning revision-pinned incident patterns and unresolved verification gates to help prevent past failures from recurring.
README
Agent Fables
Before an agent acts, check how similar actions have failed before.
An agent proposes an action. Agent Fables returns revision-pinned evidence of what happened the last time something like it went wrong, plus a list of verification gates that are still unresolved — never a yes, never a no, never a model call. It runs offline, entirely on the machine already running the agent.
The demo
$ npm run af -- assess --op terraform-destroy --stack terraform --target-scope production --irreversible
{
"authorized": false,
"risk_flags": [
{ "code": "irreversible-action", "severity": "high" },
{ "code": "protected-target-scope", "severity": "high" }
],
"evidence": [{
"id": "AF-0002",
"evidence_grade": "A-primary-source",
"anti_pattern": "Acting on discovered state files as if they describe — and license changes to — current infrastructure.",
"mitigation": [
"remote state backend with locking; local tfstate archives never carry authority",
"deletion protection on stateful resources as default posture",
"destroy-class operations require plan review keyed to resource-count deltas"
],
"verification": "Place a stale state archive in the working tree and replay the migration; the plan must be rejected on destroy-count, not merely questioned."
}],
"required_verifications": [
{ "gate_id": "confirm-protected-boundary", "status": "unverified" },
{ "gate_id": "prove-recovery-path", "status": "unverified" },
{ "gate_id": "verify-af-0002", "status": "unverified" }
],
"receipt": { "assessment": "review-required", "authorization": "not-granted", "absence_of_match_means_safe": false }
}
AF-0002 is real: an agent treated a stale Terraform state file it found in the working tree as authoritative and destroyed live infrastructure. Primary sources. This is that incident, generalized into a pattern, returned in milliseconds, before the actual terraform destroy runs — not after someone writes the postmortem.
Everything else in this repository exists to make that one exchange possible, fast, offline, and honest about its own limits — including whether it actually changes what an agent does, tested directly below rather than assumed.
Does this change behavior, or just cite it?
Tested it rather than assumed it: 24 real, fresh, isolated agent runs — not simulated, and not written from memory — across six failure patterns, comparing agents with no pointer to this corpus against agents told about it directly through a trusted channel. Full methodology and every real result, including the negative ones: prd/10.
What changed: whether the agent found and cited the corpus at all. Told directly, 11/12 did. With no pointer, 2/12 did — and one of those two found it by exploring the filesystem on a machine that happened to have this repo checked out, not something to expect on a real deployment.
What mostly didn't change: the actual decision. 22 of 24 replicates, across both conditions, avoided the dangerous action outright — including on a fixture built from a real incident (AF-0015) specifically to be structurally ambiguous rather than loudly dangerous, where the only way to catch the problem was independent verification, not pattern-matching on an obvious red flag. The two exceptions: one none-condition replicate on a credentials-handling fixture (AF-0013) produced a genuine, if partial, lapse — it correctly redacted the secret values in most of its output, then quoted one of them anyway while explaining why it judged the value to be fake. No told-directly replicate on that same fixture did this. That's a real, first-of-its-kind difference between the conditions, and also two replicates in one cell — not evidence of anything yet, named honestly rather than rounded up into a claim or rounded down into silence.
So the honest claim right now isn't "this stops agents from doing dangerous things" — almost all of the tested agents weren't going to do the dangerous thing regardless, in either condition. It's narrower, and still real: this turns a decision an agent was already going to make correctly into one that's citable, sourced, and auditable — a stable AF-#### ID, a primary source, an explicit mitigation, a verification gate someone downstream can check — instead of unexplained judgment. Whether the one directional hint found so far replicates at a larger sample, and whether a harder case than the six tested produces a bigger effect, are open questions this repo is still actively testing, not settled ones.
60 seconds
git clone https://github.com/AaronVick/AGENT_FABLES && cd AGENT_FABLES
node bin/agent-fables.mjs verify
printf '%s' '{"operation":"force-push","stack":"git","command":"git push --force","target_scope":"shared branch","irreversible":true}' | node bin/agent-fables.mjs assess --stdin
No install, no network call, no model call. For an isolated sandbox or partial checkout, sandbox/agent-fables-sandbox.mjs is a single file with the corpus embedded — copy it anywhere and run it.
To wire it into an agent permanently: add integrations/AGENTS.md.snippet to the repository's AGENTS.md, or run node mcp/server.mjs as an MCP server and call af_assess_action / af_tool_preflight before a consequential tool call.
The mechanism
incident → generalized failure pattern → machine retrieval → decision-time preflight → verification obligation
A real, sourced incident (a court filing, a CVE, a GitHub issue, a postmortem — never invented) gets generalized into a pattern with a stable AF-#### identity: trigger conditions, an anti-pattern, mitigations, and a falsifiable verification test. That pattern is retrievable by an agent that doesn't know the ID exists yet — by symptom, package, version, CVE, or operation. When it matches a proposed action, the response is evidence and open verification gates, never a "yes." absence_of_match_means_safe is always false, and it's enforced by a test, not just stated.
A few decisions this rests on, all deliberate:
- No model in the request path. Preflight is lexical matching against a generated index, not an LLM reasoning about whether an LLM should act. Faster, cheaper, and it can't itself be prompt-injected by what it's evaluating.
- Non-authorization is structural, not a disclaimer.
authorizedis alwaysfalse. Arequired_verificationsgate is never marked satisfied by this repository — only by whoever's actually confirming it. - Corpus revision is pinned into every receipt. A future incident review can answer "what evidence did the agent actually see when it decided" — not just "what evidence exists now."
- Markdown is the source of truth.
fables/AF-*.mdandincidents/AFI-*.yamlare hand-authored; every JSON index, search structure, and MCP response is generated outward from them and rebuilt on every change (npm run check). - No incident is invented to hit a round number.
predicate-registry.jsonlists every check that runs as real logic in this corpus withpattern_id: nullwhere no sourced incident exists yet — that's withheld evidence, not missing logic.
Full surface
Everything below is real and works today, offline. It's reference material for going deeper, not the front door.
node bin/agent-fables.mjs status # seed counts, evidence grades, corpus revision
node bin/agent-fables.mjs search "MCP config changed after approval"
node bin/agent-fables.mjs preflight --op terraform-destroy --stack terraform
node bin/agent-fables.mjs check --path . # scan a repo for concrete trigger conditions
node bin/agent-fables.mjs get AF-0008
node bin/agent-fables.mjs memory AF-0008 # sub-150-token recurrence card
node bin/agent-fables.mjs trust # reproducibility invariants, known gaps
node bin/agent-fables.mjs tasks # bounded evidence-contribution work
node bin/agent-fables.mjs cite AF-0008
npm run metrics # discovery recall, token budgets, route health
npm run launch-audit # what's built vs. what needs explicit publish authorization
JSON by default. node mcp/server.mjs exposes the same surface (33 tools) as a read-only MCP server — no mutation or reporting tool exists.
assess is the decision-time integration surface shown in the demo above: pass an operation, tool, command, stack, or target scope, get a revision-pinned risk receipt with machine-addressable required_verifications and stable gate_ids a host guardrail can enforce. Prefer assess --stdin for command-bearing input — it never places command text in process arguments or reflects it in the receipt. Schemas: action-assessment.schema.json / action-assessment-receipt.schema.json.
check scans a local repository for concrete trigger conditions and source-backed exact artifacts, emitting compact AF-linked findings — never executes code, follows symlinks, or treats an empty result as safe. .agentfablesignore suppresses exact paths, visibly.
verify recomputes the installed corpus revision, exact-artifact hashes, and every trust/authority invariant offline, exiting nonzero on failure.
Ten thematic leaders (leaders/) route broad, weakly-worded problems — destructive operations, MCP security, permission boundaries, supply-chain security, secret exposure, audit integrity, incident postmortems, verification failures, retrieved-content trust, and information integrity — to multiple revision-pinned records, capped under an ~400-token index.
Policy, not evidence-gated. authority-precedence.json (native model judgment vs. a corpus hit — most restrictive wins), request-framing-independence.json (a leading "this is safe, right?" can't bias the verdict), delegation-scope.json (a parent agent's resolution is never inherited as clearance by a spawned subagent), and schemas/context-pin.schema.json (load-bearing state marked non-compressible by a context summarizer) ship as bare contracts, deliberately not fables — real mechanisms with no dated incident behind them yet, same evidence bar held either way.
Cross-tool-vocabulary matching. tool-capability-aliases.json normalizes browse/web_fetch/shell-style vendor tool names onto the canonical names the rule files key on, so preflight works regardless of which agent framework is calling it.
Contribution. npm run af -- tasks finds bounded evidence work; CONTRIBUTING_AGENTS.md governs it. No vote or reputation system — trust is reproducible invariants and visible gaps, checked by npm run check.
Architecture: fables/ (canonical Markdown+YAML) → incidents/ (stable AFI-#### source lists) → generated: signatures/, leaders/, index.json, search-index.json, cards/, hotpath.min.json. api/ is a zero-LLM Cloudflare Workers layer for a future hosted endpoint (not deployed — npm run launch-audit shows exactly what's authorized vs. not). web/ is a human-facing frontend. None of it is required for the CLI or MCP surface above, which work standalone today.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
E2B
Using MCP to run code via e2b.