Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Changelog

## 1.0.2-beta.0 — 2026-08-19
## 1.0.2-beta.0 — 2026-08-20

### Docs

- Reposition the project from "runtime failure resolution for coding agents" to observability and enforcement for agent harnesses, across the surfaces that render its identity. The product was never coding-only — `INTEGRATION_TYPES` holds twelve harnesses and two of them (Hermes, a Slack/Telegram gateway; OpenClaw, a self-hosted assistant) were never coding tools — but the strings a stranger reads said otherwise, and the breadth evidence sat under labels that converted it back: README's twelve-logo grid, containing both gateways, was headed "Supported agent CLIs". The README hero, `package.json`'s description and keywords, `SECURITY.md`, `types.ts`, the docs index and quickstart, `reference/harnesses`, the sessions captions, the local dashboard, and the audit share templates now name the harness and define it ostensively on first use, with coding CLIs framed as the class covered deepest rather than the category. `reference/harnesses` is promoted onto the onboarding path in all fifteen locale navs, since it is the only page that answers which kinds of agent are covered and it sat in the last tab. (#731)

- Correct three counts that had rotted silently, and add the test that stops it recurring. README advertised "30 built-in policies" in three places; the real number is 40, and had been for some time. `__tests__/scripts/copy-counts.test.ts` now derives every count in copy — harnesses, policies, canonical events, and the harnesses on which `PreToolUse` and `Stop` blocking is verified — from `types.ts`, `builtin-policies.ts` and `enforcement-capability.ts`, and fails when prose disagrees. It also asserts that the README names no harness absent from `INTEGRATION_TYPES`, which is what makes the twelve-harness claim checkable by the engineer most likely to check it. (#731)

- Point the fourteen translation links at the tree the translation pipeline actually maintains. They resolved to `docs-old/i18n/`, frozen when the Mintlify site replaced it, while `.github/workflows/translate-docs.yml` writes `docs/i18n/` — so every non-English reader got a README that would never be updated again, and the two sets had already diverged. The drift guard asserts the link target. (#731)

### Fixes

Expand Down
92 changes: 71 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
[![Docs](https://img.shields.io/badge/docs-befailproof.ai-002CA7?style=flat-square)](https://docs.befailproof.ai/)
[![License](https://img.shields.io/badge/license-MIT%20%2B%20Commons%20Clause-blue?style=flat-square)](./LICENSE)

**Translations:** [简体中文](./docs-old/i18n/README.zh.md) · [日本語](./docs-old/i18n/README.ja.md) · [한국어](./docs-old/i18n/README.ko.md) · [Español](./docs-old/i18n/README.es.md) · [Português](./docs-old/i18n/README.pt-br.md) · [Deutsch](./docs-old/i18n/README.de.md) · [Français](./docs-old/i18n/README.fr.md) · [Руссий](./docs-old/i18n/README.ru.md) · [हिन्दी](./docs-old/i18n/README.hi.md) · [Türkçe](./docs-old/i18n/README.tr.md) · [Tiếng Việt](./docs-old/i18n/README.vi.md) · [Italiano](./docs-old/i18n/README.it.md) · [العربية](./docs-old/i18n/README.ar.md) · [עברית](./docs-old/i18n/README.he.md)
**Translations:** [简体中文](./docs/i18n/README.zh.md) · [日本語](./docs/i18n/README.ja.md) · [한국어](./docs/i18n/README.ko.md) · [Español](./docs/i18n/README.es.md) · [Português](./docs/i18n/README.pt-br.md) · [Deutsch](./docs/i18n/README.de.md) · [Français](./docs/i18n/README.fr.md) · [Руссий](./docs/i18n/README.ru.md) · [हिन्दी](./docs/i18n/README.hi.md) · [Türkçe](./docs/i18n/README.tr.md) · [Tiếng Việt](./docs/i18n/README.vi.md) · [Italiano](./docs/i18n/README.it.md) · [العربية](./docs/i18n/README.ar.md) · [עברית](./docs/i18n/README.he.md)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

**Runtime failure resolution for coding agents.**
Hooks into Claude Code and Codex. Catches loops, dangerous actions, and secret leaks
before they become incidents. Zero latency. Runs locally.
**Observability and enforcement for every harness your agents run in.**
Wherever your agents run, we see it — and we can say no. Failproof hooks 12 agent
harnesses — coding CLIs like Claude Code and Codex, chat gateways like Hermes,
self-hosted assistants like OpenClaw — capturing every run and blocking dangerous
tool calls before they execute. 40 built-in policies. Zero latency. Runs locally.

</div>

Expand All @@ -25,7 +27,12 @@ before they become incidents. Zero latency. Runs locally.

---

## Supported agent CLIs
## Supported harnesses

Twelve harnesses across three classes — coding CLIs, chat and assistant gateways
(Hermes, OpenClaw), and agent runtimes. Same events, same policies, same session
history, whichever one your agent runs in. Not on the list? Instrument your own
agent with the Python SDK.

<!-- A 6-column table instead of inline <img> runs: table columns never re-wrap,
so the grid stays 2×6 at any window width (scrolling on very narrow screens
Expand Down Expand Up @@ -129,21 +136,27 @@ failproofai policies --install # or just run `failproofai` and accept the firs
failproofai
```

30 built-in policies activate immediately. Dashboard at `localhost:8020`. Disable the first-run prompt with `FAILPROOFAI_NO_FIRST_RUN=1`.
40 built-in policies activate immediately. Dashboard at `localhost:8020`. Disable the first-run prompt with `FAILPROOFAI_NO_FIRST_RUN=1`.

---

## What it stops

| Policy | What it blocks |
|---|---|
| `block-push-master` | Direct pushes to `main` / `master` |
| `block-force-push` | `git push --force` |
| `block-work-on-main` | Commits, merges, rebases on `main` / `master` |
| `sanitize-api-keys` | API keys leaking into the agent's context |
| `block-env-files` | Reads of `.env` and other secret files |
| `warn-repeated-tool-calls` | The agent looping on the same call |
| `block-sudo` | Privilege escalation |
| `warn-destructive-sql` | `DROP`, `TRUNCATE`, unbounded `DELETE` |
| `block-terraform` / `block-kubectl` | Unreviewed changes to live infrastructure |
| `block-rm-rf` | Recursive file deletion |
| `sanitize-api-keys` | API keys leaking into agent context |
| `block-force-push` / `block-push-master` | `git push --force`, direct pushes to `main` |

The first five apply to any agent that can call a tool. The last three are the
developer favourites — coding CLIs are the harness class we cover deepest.

→ [All 30 built-in policies](https://docs.befailproof.ai/policies/builtin)
→ [All 40 built-in policies](https://docs.befailproof.ai/policies/builtin)

---

Expand Down Expand Up @@ -178,24 +191,61 @@ Three decisions available to every policy:

---

## Session visibility
## Observability

Enforcement is one half. The other half is seeing what the agent actually did.

Run `failproofai` with no arguments and it serves a dashboard on `localhost:8020`
reading the run history already on your machine — no account, no signup, nothing
leaving the box. You get the session list, the sequence of model calls, tool calls
and hook decisions inside each run, what was blocked and what the policy told the
agent, and an offline audit (`failproofai audit`) that scans your history for risky
patterns and suggests policies to stop them.

→ [Local dashboard](https://docs.befailproof.ai/reference/local-dashboard) ·
[Read a trace](https://docs.befailproof.ai/sessions/read-a-trace) ·
[Local audit](https://docs.befailproof.ai/audits/local-audit)

**Failproof AI Observability** is the hosted side of the same data model, for teams
running agents across a fleet: every run from every harness in one place, an
execution graph with parallel sub-agents on their own lanes, p50/p95/p99 latency
for models, tools and hooks, per-model cost and context-window tracking, error
tracking, SQL over your own traces with shareable dashboards, evaluations scored by
your own service, scheduled audits that turn recurring failures into evidence-backed
findings, and alerts routed to Slack, email or a signed webhook. Self-hosting in your
own cluster is available on the Enterprise plan.

Every tool call your agent makes is logged locally. The dashboard shows what ran,
what was blocked, and what the policy told the agent — so you're not guessing
when something goes wrong. → [Dashboard guide](https://docs.befailproof.ai/sessions/overview)
→ [Sessions](https://docs.befailproof.ai/sessions/overview) ·
[Audits](https://docs.befailproof.ai/audits/overview) ·
[Book a demo](https://befailproof.ai/get-a-demo)

---

## Documentation

| | |
| Start | |
|---|---|
| [Getting Started](https://docs.befailproof.ai/start/quickstart) | Installation and first steps |
| [Built-in Policies](https://docs.befailproof.ai/policies/builtin) | All 30 policies with parameters |
| [Custom Policies](https://docs.befailproof.ai/policies/custom) | Write your own |
| [Quickstart](https://docs.befailproof.ai/start/quickstart) | Install, connect a harness, see the first run |
| [Concepts](https://docs.befailproof.ai/start/concepts) | How the hook system works |
| [Supported harnesses](https://docs.befailproof.ai/reference/harnesses) | All 12, and what each one can enforce |

| Observe | |
|---|---|
| [Sessions](https://docs.befailproof.ai/sessions/overview) | Follow a run: models, tools, errors, latency |
| [Read a trace](https://docs.befailproof.ai/sessions/read-a-trace) | What the execution graph is telling you |
| [Audits](https://docs.befailproof.ai/audits/overview) | Find failure patterns across many sessions |
| [Local dashboard](https://docs.befailproof.ai/reference/local-dashboard) | `localhost:8020`, no account needed |

| Enforce | |
|---|---|
| [Built-in policies](https://docs.befailproof.ai/policies/builtin) | All 40 policies with parameters |
| [Custom policies](https://docs.befailproof.ai/policies/custom) | Write your own |
| [Configuration](https://docs.befailproof.ai/policies/local-configuration) | Config scopes and merge rules |
| [Dashboard](https://docs.befailproof.ai/sessions/overview) | Session monitor and policy activity |
| [Architecture](https://docs.befailproof.ai/start/concepts) | How the hook system works |

| Instrument your own agent | |
|---|---|
| [Python SDK](https://docs.befailproof.ai/reference/python-sdk) | Report runs from an agent with no harness |
| [Policy SDK](https://docs.befailproof.ai/reference/policy-sdk) | `allow` / `deny` / `instruct` reference |

---

Expand Down
9 changes: 5 additions & 4 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Security Policy

failproofai is an npm package that installs hooks into AI coding agents (Claude
Code, Codex, and others) and runs locally in developers' environments, observing
and gating agent actions. A compromised dependency would therefore run on our
users' machines, inside their agent sessions — so we treat our supply chain as
failproofai is an npm package that installs hooks into AI agent harnesses
(Claude Code, Codex, Cursor, the Hermes and OpenClaw gateways, and others) and
runs locally in the environment the agent runs in, observing and gating agent
actions. A compromised dependency would therefore run on our
users' machines and servers, inside their agent sessions — so we treat our supply chain as
part of our users' trust boundary. This document covers how to report a
vulnerability and how our dependency supply-chain scanning works.

Expand Down
103 changes: 103 additions & 0 deletions __tests__/scripts/copy-counts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// @vitest-environment node
/**
* Drift guard for the NUMBERS AND HARNESS NAMES in user-facing prose.
*
* The positioning rewrite put four counts into copy read by nearly everyone who
* meets this project — 12 harnesses, 40 built-in policies, 29 canonical events,
* and blocking verified on 12/12 PreToolUse and 8/12 Stop. Those counts are only
* worth printing flat, without hedging, because `enforcement-capability.ts` is a
* machine-readable matrix with the probed version on every row. A stale count
* turns that asset into a liability: an engineer who checks one number and finds
* it wrong has a reason to discount the whole claim.
*
* This is not hypothetical. Before this file existed, README.md advertised "30
* built-in policies" in three places and the landing site's schema.org block said
* 39 — while the real count was 40, and had been for some time. Both were
* hand-maintained, nothing read them, so both rotted silently. Same failure mode
* __tests__/hooks/dogfood-configs.test.ts was written to catch for the dogfood
* configs.
*
* SCOPE: this repo only. The landing site (befailproof.ai) lives in a different
* repo and carries the same counts in app/layout.js and app/llms.txt/route.js;
* it needs its own check. See FailproofAI/agenteye#629.
*/
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { INTEGRATION_TYPES, HOOK_EVENT_TYPES } from "@/src/hooks/types";
import { ENFORCEMENT_CAPABILITY } from "@/src/hooks/enforcement-capability";
import { BUILTIN_POLICIES } from "@/src/hooks/builtin-policies";

const ROOT = process.cwd();
const read = (p: string) => readFileSync(resolve(ROOT, p), "utf8");

/** Every count asserted below, derived from source rather than restated. */
const TRUTH = {
harnesses: INTEGRATION_TYPES.length,
policies: BUILTIN_POLICIES.length,
events: HOOK_EVENT_TYPES.length,
preToolUseBlocks: INTEGRATION_TYPES.filter(
(c) => ENFORCEMENT_CAPABILITY[c]?.PreToolUse === "block",
).length,
stopBlocks: INTEGRATION_TYPES.filter((c) => ENFORCEMENT_CAPABILITY[c]?.Stop === "block").length,
};

/**
* Files that state a count in prose a reader acts on. Deliberately short: this
* guards the strings with the most readers, not every mention in the tree.
*/
const COPY_FILES = ["README.md", "package.json", "docs/index.mdx"];

describe("copy counts match source", () => {
it("the derived counts are what the copy claims", () => {
// Fails loudly if someone adds a harness or a policy without re-reading the
// copy. Update this block ONLY together with every string it guards.
expect(TRUTH).toEqual({
harnesses: 12,
policies: 40,
events: 29,
preToolUseBlocks: 12,
stopBlocks: 8,
});
});

it.each(COPY_FILES)("%s states no stale policy count", (file) => {
const text = read(file);
const claimed = [...text.matchAll(/(\d+)\s+built-in polic/gi)].map((m) => Number(m[1]));
for (const n of claimed) expect(n).toBe(TRUTH.policies);
});
Comment thread
NiveditJain marked this conversation as resolved.

it.each(COPY_FILES)("%s states no stale harness count", (file) => {
const text = read(file);
const claimed = [...text.matchAll(/(\d+)\s+(?:agent\s+)?harness(?:es)?\b/gi)].map((m) =>
Number(m[1]),
);
for (const n of claimed) expect(n).toBe(TRUTH.harnesses);
});

it("README names only harnesses that ship", () => {
const text = read("README.md").toLowerCase();
// Named on marketing surfaces but absent from INTEGRATION_TYPES. Keeping
// them out of the README is what makes the harness list checkable.
for (const absent of ["gemini cli", "langgraph", "deep agents"]) {
expect(text).not.toContain(absent);
}
});

it("README names the two harnesses that prove the product is not coding-only", () => {
// The whole positioning rests on the harness list spanning classes. Hermes
// (Slack/Telegram gateway) and OpenClaw (self-hosted assistant) are the two
// shipped integrations that were never coding tools; if a future edit drops
// them from the hero, the breadth claim silently loses its evidence.
const text = read("README.md").toLowerCase();
expect(text).toContain("hermes");
expect(text).toContain("openclaw");
});

it("the translated READMEs are linked from the tree the pipeline maintains", () => {
// docs-old/i18n/ was frozen when the Mintlify site replaced it; the
// translation workflow writes docs/i18n/. Linking the frozen copies means
// non-English readers get a README that is never updated again.
expect(read("README.md")).not.toContain("docs-old/i18n/");
});
});
Loading