agents-core.md
benchbook — Agent Contract
Operating contract for the agent that maintains this wiki: the single source of truth for
structure, conventions, and workflows. Co-owned — the agent proposes changes, the human
approves. Detail lives in satellite files (agents-page-conventions.md,
agents-domain-*.md), loaded on demand rather than restated here.
Owner: (your name) · Dates: YYYY-MM-DD
Working style (applies to everything below). Never assume — ask when anything is unclear; state how many questions, present them one at a time with options and a recommendation, and ask before starting a task. Don’t just agree: push back on legitimate concerns, but don’t be nit-picky.
1. Session Start
- Read this file (
agents-core.md). - Greet the owner and confirm the contract loaded.
Index files load lazily (QUERY reads them at its step 1; INGEST touches the domain index in post-flight) — don’t preload them.
2. Hard Rules (non-negotiable)
- Read
agents-core.mdat session start. - Read
wiki/index.md+ the relevantwiki/index-<domain>.mdbefore answering questions — they are your map of what exists. - Never modify
raw/— immutable sources. LINT may move files toraw/_archived/after 14 days; never delete. - Always use relative markdown links (
[text](relative/path.md)) between wiki pages. - Always include YAML frontmatter on new pages,
publish: falseby default. - Update the relevant
wiki/index-<domain>.mdwhen creating or significantly updating a page. - Append to
wiki/log/log.mdonly for wiki-structural events —ingest,create,lint,query,skill— in 1–3 lines. Notupdate: project progress belongs in that project’s## Log, and entity state changes belong in that entity’s## Change History. See § 6 Log for the rule and why. - Flag contradictions explicitly — never silently overwrite conflicting information.
- Ask before creating pages during interactive ingest — discuss with the human first.
- Keep pages concise — split rather than bloat (past ~500 words, ~3,000 for
entitypages, consider splitting). Measured excluding append-only sections (## Log,## Change History,## Modifications) — a project’s build history growing is not bloat — andproject,sourceandreferencepages are exempt: a project’s own template mandates six sections, a source page transcribes external material so its length is inherent, and every shape a reference takes (install runbook, multi-entity comparison, project-attached analysis) is long by construction. Theentitylimit is 6× higher because operational hub pages are dense on purpose, and splitting one lookup into three is a downgrade. LINT warns on the rest. (Every carve-out here was added after measuring which pages the rule actually flagged — seedocs/11-keeping-it-honest.mdRule 3.) - Propose changes to this file — don’t modify the schema silently.
- Deployed-code commit rule. If any code in this repo (or a linked infrastructure repo) is a live checkout running on a machine, it MUST be committed and pushed before the session ends — a live checkout is not an auto-committing daemon, so an uncommitted fix silently rots. Never in-place-edit a symlinked live-checkout path; it replaces the symlink with a plain file.
- No-Deletion Rule. Before deleting a file or omitting content, stop and ask: “About to delete / not carry over [X], which contains [summary] — does it belong somewhere else, or is it safe to discard?” Applies to migration deletes, content that doesn’t fit the target page, removed or collapsed sections, and links that would break. Never silently discard; when in doubt, ask.
- Never link to a
raw/path from a page body. Body links are online URLs (source_url) only; raw paths live in frontmatter (raw_file:).
3. Operations
INGEST
Pre-flight (universal): (1) read the raw file; (2) propose domain (+subdomain) — human
confirms before any page is created; (3) read agents-domain-<name>.md; (4) extract
source_url from the raw if obvious, else leave empty and set raw_file; (5) discuss key
takeaways; (6) read agents-page-conventions.md before writing.
Chat-dictation domains (projects) skip steps 1 & 4.
Dispatch (domain-specific) — run the ordered steps in that domain’s rules file. Installed domains only; a domain not listed here is not installed, and its pack is never loaded.
| Domain | Rules file | Flow |
|---|---|---|
| knowledge | domains/knowledge/agents-domain-knowledge.md | source → entities (Entity Placement Rule) → 3-source channel trigger → reference only if 4+ entities |
| home | domains/home/agents-domain-home.md | source → owned/considered/referenced checkpoint → entities → reference only if 4+ entities |
| projects | domains/projects/agents-domain-projects.md | new vs existing → confirm status → write/update project page |
Further packs — books, cooking — ship in domains/ and are not installed. See
domains/README.md to install one.
Post-flight (universal): flag contradictions; update index-<domain>.md (master
index.md changes only when a domain or meta page is added); update overview.md if the big
picture shifted; append to log.md only if a page was created or a source ingested (1–3
lines — see § 6 Log); report what was created, updated, and flagged.
QUERY
Read wiki/index.md, then the relevant index-<domain>.md, then the pages themselves →
synthesize with markdown-link citations. Offer to file substantial, reusable answers. If the
wiki is insufficient, fall back to raw/ then general knowledge — always disclose non-wiki
sources. Append to log.md if significant (1–3 lines) — a query op is one of the few
things git history can’t capture, so it genuinely belongs there.
LINT
Manual trigger only. Report-only for wiki content — never edits page bodies or
frontmatter; writes a full report to wiki/log/lint-YYYY-MM-DD.md, prints an inline summary,
and appends one line to log.md. Write-capable only for two mechanical operations:
- Raw-file archival: for each page with a
raw_file:, if that file exists inraw/andmtime < now−14 days,mvit toraw/_archived/<domain>/. Never delete. - Log archival: when
log.mdexceeds 500 lines, move the oldest entries towiki/log/log-archive/YYYY-MM.mduntil ≤350 lines remain.
Mechanical checks live in scripts/lint.py (python3 scripts/lint.py; exit 1 = findings). The
LLM-judgment checks — entity placement, contradictions, staleness — live in
agents-lint-checks.md; read it before running LINT.
The error-class mechanical checks gate commits via scripts/pre-commit.sh (install:
ln -s ../../scripts/pre-commit.sh .git/hooks/pre-commit). Errors block; warnings never block;
the judgment checks are not involved. Bypass deliberately with git commit --no-verify. This is
the one place LINT is not purely advisory, and it is deliberately restricted to checks with
exactly one correct answer.
4. Architecture & Structure
Layers: raw/ (immutable drop zone, read-only to the agent) → wiki/ (agent-owned pages)
→ scripts/ (code store) → agents-core.md (co-owned schema).
Folders:
- Domains installed:
knowledge(what exists in the world),home(what you own and operate),projects(what you’re building). These three are the minimum coherent set — see “Why three” below. Further packs available indomains/. - Globals:
sources/(all source pages, flat, regardless of domain),people/(humans only). - Domain-local:
<domain>/entities/+<domain>/references/. Subdomain distinctions live insubdomain:frontmatter, not folders. - Meta:
index.md,index-<domain>.md,overview.md,log/log.md(overflow →log/log-archive/YYYY-MM.md; LINT reports →log/lint-YYYY-MM-DD.md). There is deliberately no todo file — see § 6.
Entity Placement Rule — decided at first ingest by what the entity is (not how many domains reference it); existing entities are reviewed only when next touched:
| Entity | Folder |
|---|---|
| Concrete humans | wiki/people/ |
| Owned/specific instances (your particular server, your specific device) | wiki/home/entities/, or another domain’s entities/ if one fits better |
| General concepts / products / tools | wiki/knowledge/entities/ |
Cross-folder relations are first-class and expected — the general product and your specific instance of it are two pages that link to each other.
Why three domains ship installed. The rule above has three branches, and each needs a
destination. people/ covers humans and knowledge/ covers general things; without home/,
an owned thing has nowhere correct to go — projects/ is wrong, because a project is something
you’re building, not something you have. Drop any of the three and the rule becomes
unsatisfiable.
Adding a domain. Domains ship as packs in domains/<name>/ — rules file, skills, and
an install note in that pack’s README. knowledge, home and projects are installed;
books and cooking are available and inert.
To install one, read domains/<name>/README.md and follow its steps: add a dispatch row above,
add the domain to the folder list, create its folders and index, copy its skills, and — if the
pack extends the schema — add its page types to agents-page-conventions.md. The human may
simply ask “install the books domain pack”; do the steps and report what changed.
Stop at three for a while. The installed set already covers the Entity Placement Rule. Add a fourth only when an existing domain genuinely can’t hold something — not merely when you have a lot of pages about a subject. Domains are cheap to add and expensive to abandon half-populated.
scripts/ — Code Store
Holds code that is not a live deployed service: wiki tooling loose at root, and per-project
build recipes or firmware source whose deployed form is a separate artifact (scripts/<slug>/,
each with a README.md linking back to its wiki page).
Shipped tooling:
| Script | What it does |
|---|---|
lint.py | All mechanical LINT checks. python3 scripts/lint.py; exit 1 = findings |
pre-commit.sh | Git hook wrapper — runs lint.py and blocks the commit on errors only |
relations.py | Neighbourhood lookup over the ## Relations graph: ./scripts/relations.py <slug> reports a page’s inbound and outbound edges. Needed because each edge is stored exactly once, on whichever page reads naturally, so a page’s own table shows only half its relations. --depth walks further (capped); depth 1 is the usable unit |
Continuously-running deployed services belong in their own infrastructure repo, where the on-host path is the git working tree — so a field hotfix is a real commit rather than a copy that rots.
Conventions: (1) faithful backup — byte-for-byte copies, no added headers; re-copy after any edit. (2) No secrets — only environment variables, secret references, or vault indirection. (3) Two-way link — the page links to the files, the subfolder README links back; never paste standalone code into a page body. (4) Not a wiki page — no frontmatter, not indexed.
5. Page Conventions
Full frontmatter field tables and per-page-type templates are in
agents-page-conventions.md — read it before creating or editing a page. Core rules:
Structure: one H1 matching frontmatter title; ## Summary (2–4 sentences) required;
## Sources required on source pages; relative markdown links throughout; filenames
lowercase-with-hyphens; split beyond ~500 words (see Hard Rule 10 for how that’s measured);
never link a raw/ path from the body.
Page types & locations:
| Type | Location |
|---|---|
| source | wiki/sources/ (global, flat) |
| entity | people/ (humans), <domain>/entities/ (owned/specific), or knowledge/entities/ (general) |
| reference | <domain>/references/ (only when a source ranks/compares 4+ entities) |
| project | wiki/projects/ (+ completed/, abandoned/) |
| overview | wiki/overview.md |
Channel/author entity trigger — propose at the 3rd source from one origin, tracked via
the channel: frontmatter field. Template → agents-domain-knowledge.md.
6. Index, Log, Overview
Index (split): wiki/index.md (master, ~50 lines) = ## People + ## Domain Indexes
pointer list + ## Meta; changes only when a domain or meta page is added.
wiki/index-<domain>.md = that domain’s full catalog, ### order Sources / Entities /
References / Projects. Each entry: - [Title](path.md) — one-line summary. Frontmatter:
type: overview, domain: <domain>, tags: [meta, index]. An empty domain has no index file
until it has content.
Log (wiki/log/log.md): chronological, append-only. Entry:
## [YYYY-MM-DD] <op> | Subject followed by 1–3 lines, ~40 words max. Ops: ingest,
create, lint, query, skill. Never delete entries; LINT archives overflow.
What belongs here — and what doesn’t. This log tracks wiki-structural events: a page created, a source ingested, a LINT run, a significant query answered, a skill run. It is not a general activity log. The two things most often mis-filed here:
| Kind of change | Belongs in | Why not log.md |
|---|---|---|
| Project progress, decisions, build narrative | that project’s ## Log | you’d look for it on the project page, not by date |
| Entity state change (versions, config, deployments) | that entity’s ## Change History | the entity page is the single source for its own state |
update is deliberately not a valid op — it was the escape hatch that made this file grow
~10× faster than intended. An audit of the original wiki found 17 of 26 recent entries were
update, averaging 139 words against a 1–3 line spec, largely duplicating content already
written to a project ## Log in the same session. If an event seems to need a long log entry,
that’s the signal it belongs on a page instead — with at most a one-line pointer here.
Overview (wiki/overview.md): ## Themes (cross-cutting synthesis) + ## By Domain (one
paragraph each).
Todo — there is deliberately no todo file. Open work lives where the work lives:
| Open work | Lives in |
|---|---|
| Project todos | that project page’s required ## Open Questions |
| Entity / people todos | the entity or person page |
| Contradictions needing a human decision | wiki/log/review.md — drained by LINT before it looks for new work |
| LINT findings | the dated wiki/log/lint-YYYY-MM-DD.md report |
| Schema proposals | wherever you track wiki-meta work — a project page, not a list |
Why there is no list. The original wiki had one, and it failed twice in the same way. First as a mirror: it copied project open-items, and a lint pass found 60 of ~76 had silently drifted from the pages they came from. So it was cut back to pointer-only — links to project pages, nothing duplicated. That version failed too, just more slowly: measured four times over four weeks, roughly a third of its remaining entries had a stale or wrong premise, and of the last five deferred items, every single one turned out on inspection to be already resolved or based on something no longer true.
The lesson is sharper than “don’t duplicate state”. A file whose whole job is to tell you what is open, and which is a third wrong, actively misleads — it is worse than no file, because you trust it. Pointer-only fixed the drift and left the rot. Both versions were a second index over work that already had a home.
If you want one view of everything open, generate it — grep the unchecked boxes out of
## Open Questions across the project folder. A derived view can be stale for exactly as long
as it takes to re-run it.
7. Domain Rules
Per-domain dispatch flows and conventions live in domains/<name>/agents-domain-<name>.md —
load the relevant one at INGEST pre-flight, and only for installed domains.
Shared Flow — source-style domains:
- Create the source page (
wiki/sources/<slug>.md; body## Summary→## Key Takeaways→## Sources). - Domain checkpoint (per that domain’s file).
- Propose entity page(s) if warranted — apply the Entity Placement Rule; create only approved ones; update existing entities silently and note it in the report.
- Two-way link — entity
sources:frontmatter (plain slug) ↔ source-body relative link to the entity. - References — flag, don’t auto-update. A new reference needs human approval and 4+
entities. If a source adds to an existing reference, never edit silently: ask to (a) update
now, (b) record it as an open question on the reference page itself, or (c) deprecate →
split into entities with
## Compared Tocross-links.
8. Reference
Standing facts, connection details, and environment-specific notes that don’t belong anywhere else. Keep this short — anything that grows a structure of its own belongs on a page.
(Empty in a fresh wiki. Add yours.)