diff --git a/docs/figures/family-dark.svg b/docs/figures/family-dark.svg
index af55724..507b8e2 100644
--- a/docs/figures/family-dark.svg
+++ b/docs/figures/family-dark.svg
@@ -16,7 +16,7 @@
chock-catalog
- the policies — 39, each labelled enforced or advisory, with replayed evals
+ the policies — each labelled enforced or advisory, with replayed evals
diff --git a/docs/figures/family-light.svg b/docs/figures/family-light.svg
index cb95f50..4775f14 100644
--- a/docs/figures/family-light.svg
+++ b/docs/figures/family-light.svg
@@ -16,7 +16,7 @@
chock-catalog
- the policies — 39, each labelled enforced or advisory, with replayed evals
+ the policies — each labelled enforced or advisory, with replayed evals
diff --git a/docs/figures/make_family.py b/docs/figures/make_family.py
index 6a70d5e..b053036 100644
--- a/docs/figures/make_family.py
+++ b/docs/figures/make_family.py
@@ -4,25 +4,56 @@
statement stays on one line under 88 characters.
"""
+import importlib
+import re
+import sys
+from pathlib import Path
+
import palette as p
+ROOT = Path(__file__).resolve().parents[2]
+REGISTRY = ROOT / "registry.yaml"
+MATRIX_SRC = ROOT / "src"
+
W, H = 800, 420
NAME, ROLE = 13, 11
WIDE, NARROW, ARM = 74, 34, 22
+
+def catalog_count():
+ """Policies in the catalog's registry.yaml, or None in a repo that carries none."""
+ if not REGISTRY.is_file():
+ return None
+ text = REGISTRY.read_text(encoding="utf-8").split("\nskills:\n", 1)[0]
+ return len(re.findall(r"^- id: \S+", text, re.MULTILINE)) or None
+
+
+def agent_count():
+ """Agents in agentseam's capability matrix, or None in a repo that has none."""
+ if not (MATRIX_SRC / "agentseam" / "matrix.py").is_file():
+ return None
+ sys.path.insert(0, str(MATRIX_SRC))
+ return len(importlib.import_module("agentseam.matrix").agents())
+
+
+# Only the repo holding each source names its count; the others say it without one.
+_N, _A = catalog_count(), agent_count()
+POLICIES = f"the policies \N{EM DASH} {_N}," if _N else "the policies \N{EM DASH}"
+AGENTS = f"across {_A} agents" if _A else "across the supported agents"
+
# Split into fragments joined with a space: a magic trailing comma keeps each list
# exploded, so `ruff format` leaves this alone at 88, 100 and 120 alike.
ROLES = {
"agentseam": [
"the primitives — one handler API and a verified capability",
- "matrix across 16 agents",
+ "matrix " + AGENTS,
],
"chock": [
"the compiler — one policy into git hooks, CI gates and",
"native pre-tool hooks",
],
"chock-catalog": [
- "the policies — 39, each labelled enforced or advisory,",
+ POLICIES + " each labelled enforced or advisory,",
"with replayed evals",
],
"context-report": [
diff --git a/llms.txt b/llms.txt
index b56f54e..dd3a010 100644
--- a/llms.txt
+++ b/llms.txt
@@ -1,7 +1,7 @@
# agentseam
-> The primitives layer for every coding agent — one handler API over per-agent hooks,
-> instruction files, plugin packaging, and config.
+> The primitives layer under Chock's guardrails for AI coding agents: one handler API over
+> per-agent hooks, instruction files, plugin packaging, and config.
Every coding agent (Claude Code, Cursor, VS Code Copilot, Codex CLI, Gemini CLI, Windsurf,
and more) invented its own hook system, instruction-file convention, and permission
@@ -10,8 +10,11 @@ language. agentseam normalizes them into one handler API, one decision type
`ask` and `rewrite` remain as deprecated aliases of `escalate` and `transform`), and an
explicit capability matrix that states what each agent can *actually* enforce — `enforced`,
`best-effort`, `enforceable`, `detect`, or `none` — rather than assuming they are equivalent.
-A matrix row is only claimed when a `verified: {version, date, method}` record backs it;
-most rows rest on vendor documentation and are marked as such, not on an observed live run.
+The matrix (`src/agentseam/matrix.py`) covers 16 agents by 12 events: 192 cells, of which 101
+are `none`, 55 `detect`, 34 `best-effort`, 2 `enforceable` and 0 `enforced`. A matrix row is
+only claimed when a `verified: {version, date, method}` record backs it; 10 of the 16 agents
+rest on vendor documentation, 1 on a live run, 3 on a partial live run, 1 on the vendor's
+source and 1 on a third-party install, and each is marked as such.
License: Apache-2.0. Status: pre-1.0 — the CLI surface, manifest schema, and compiled
output can change between MINOR releases.