The minimum cat-harness — and what moves where

  1. The revised repo set
  2. What “not self-documenting” actually constrains
    1. The falsifier, stated up front
  3. cat-harness — the minimum
    1. Schemas (.ts, minimal)
    2. Skills — 24: 21 from folio-core, plus 3 written for MCP projection
    3. Documentation — the smallest set
    4. Tools — four nodes, and no MCP
  4. The tools layer — the minimum
  5. The Tools schema — built, and where the strawperson bent
  6. Strawperson: the Tools-repo schema
    1. Carrying it — authored once in Zod, rendered downstream
      1. Why not the other three, including the one I first recommended
      2. What “as many renderings as make sense” means in practice
  7. The documentation move-table
    1. Top-level pages (docs/*.md)
    2. Guides (docs/guides/)
    3. BPMN processes (processes/) — 20 files
    4. Skills (115 across 9 packages)
  8. User todo management — suggestions
  9. Decided: 17 stays, and the forge is isolated at the Tool layer
    1. No MCP in the harness — but the harness knows how to emit one
  10. The kg/ layout — group them, do not flatten them
  11. What is deliberately not here

Proposal, nothing built. Answers #223 comment 16:13 (minimum contents, Tools strawperson, documentation move-table) as revised by comment 16:28 (the harness is not self-documenting). Inventory measured on main at d8632b6, 2026-09-18.

The revised repo set

The 16:28 revision changes the shape from the five-repo future state. Rendering moves out of the harness, and each layer gains a Tools sibling:

flowchart TD
    AH["<b>cat-harness</b><br/>workflow state · guardrails<br/><i>not self-documenting</i><br/>one tool: beans"]
    AHT["<b>tools layer</b><br/>beans CLI Tool node"]
    C["<b>content core</b><br/>justthedocs pipeline · webpage<br/><i>self-documenting</i>"]
    CT["<b>folio-assistant-core-tools</b><br/>BPMN/DMN/Todo renderers"]
    FA["<b>folio-assistant</b><br/>(what remains today)"]

    AHT --> AH
    C --> AH
    CT --> C
    FA --> C
    FA -.uses.-> CT

    classDef h fill:#1f3b52,stroke:#4a90c2,color:#fff
    classDef c fill:#2d4a2b,stroke:#6aa84f,color:#fff
    classDef t fill:#4a3b52,stroke:#a274c2,color:#fff
    class AH h
    class C c
    class AHT,CT,FA t

What “not self-documenting” actually constrains

This is the load-bearing sentence in the revision, and it is worth converting into a test rather than a slogan.

The harness cannot render a website. The just-the-docs pipeline, the webpage content type, and every renderer belong to the content core. So the harness cannot document itself as a folio — its documentation is prose files an agent reads, not pages a reader browses.

That yields a one-line admission test for every candidate:

If it produces something a human looks at, it is not the harness.

Applied honestly it removes a great deal from the 16:13 list. The webpage content type, the sticky-note Todo rendering, the QR code, dark/light mode, the six UN languages, the audit-sidecar iconography, “links to edit in GitHub” — all of these are things a reader sees, so all of them are the content core or folio-assistant-core-tools, not the minimum harness.

What survives in the harness is the part with no pixels: schemas, process definitions, and skills that tell an agent how to behave.

The falsifier, stated up front

If cat-harness ends up with dozens of skills and no crisp line against core, “not self-documenting” has not constrained anything and the split is still notional. Measured below: 17 of 55 folio-core skills. That is a real constraint — it excludes 38 — but it is more than “a handful”, and §”What I would cut further” says where I would push if you want it smaller.

cat-harness — the minimum

Schemas (.ts, minimal)

The harness owns the vocabulary of work, not of content.

schemawhy the harness
Skillwhat an actor knows how to do
Toolhow work actually gets done; a KG node, not a shell string
Taskthe unit assigned to an actor in a swimlane
Actor / Rolewho may do what — RBAC
Process (BPMN) / Decision (DMN)the deterministic workflow itself
Todouser/agent workflow state (16:28, explicit). Already exists — TodoItem, schemas/types.ts:1330. It moves; it does not need writing.
Beanditto, and this one is genuinely missing. BeanRef (src/workflow/bean-link.ts:40) is a reference to a bean, not a schema for one.
CatHarness declarationwhich directories an instance scans, and each one’s graph typology — already built, schemas/cat-harness.ts
Content (abstract)the base only: identity, label, provenance. No block kinds, no profiles.

Of the two, only Bean is the gap — I checked rather than assuming, and the answer changed the recommendation below.

TodoItem already exists at schemas/types.ts:1330 and carries id, summary, comment, status, priority, origin, targetLabel, assignee, timestamps, updatedBy, data, related, author. Its TodoStatus union already includes blocked. So the Todo half of 16:28’s “add if not exists” is a move, not a write.

Bean is genuinely absent. Beans are markdown files with YAML front matter and no TypeScript schema; the only Bean-shaped type is BeanRef (src/workflow/bean-link.ts:40), which is a reference to a bean rather than a schema for one. A workflow-state format with no schema cannot be validated, cannot carry a QA sidecar, and cannot be a KG node.

Skills — 24: 21 from folio-core, plus 3 written for MCP projection

The count was wrong and is corrected here. This heading read “17” while the table below it listed 19 rows, and named a twentieth — the narrative process skill — as not yet written. That skill now exists as process-state, and skills-and-tools was added with it, bringing the moved-from-folio-core figure to 19 + 2 = 21. The “17” was never recomputed after rows were appended. Three further skills — mcp-projection, mcp-assembly, mcp-contract — are new writing rather than moves, for a harness total of 24. Counted 2026-09-18 with grep -c over the table; the grouping below sums to the same number, which is the check that catches the next drift.

Classified by reading each skill’s description, not its filename — the bean dh4f lesson.

skillwhy the harness
bean-coordinationcross-session claim discipline
todo-managerwork-plan maintenance: the CLI, the STRICT create-check, coordination
opening-briefbrief a bean or topic before touching anything
turn-reportingsay which bean you are on, every turn
pending-showread-only view of session pending work
session-intentsession-start intent, session-end results
continual-progressPR from the first commit; visibility of in-flight work
coordinatemulti-PR coordination toward a shared goal
pickupresume an existing open PR
watchbackground-watch a branch or PR
prepare-merge-autothe merge pipeline as a process
idle-backlogwhat an agent does while blocked
dispatch-agentbackground sub-agents — the swarm entry point
interaction-modalityhow to talk to the person before deciding what to say
symbiotic-interactionthe three epistemic registers of author input
crdm-detectfeature-request detection (16:16, explicit)
crdm-requirements-workflowthe six-phase process (16:16, explicit)
getting-startedfolio-creation triage (16:13, explicit)
repo-conversionlaying the harness over an existing repo — bootstrap
integration-watcher (abstract parent only)the shared watcher mechanics; the concrete watchers are downstream
directory-conventionsthe declaration and its graph typologies
process-statereading a BPMN swimlane as process state for the role you are playing, and recovering when you find yourself outside it
skills-and-toolsthe skill/Tool separation — the SOP every other skill follows
mcp-projection (new)mapping a Tool node onto the MCP standard — how an agent stands a service up from a CLI tool
mcp-assembly (new)composing many Tools into one service: naming, collisions, prefixes, versioning
mcp-contract (new)verifying a served tool still matches the node it was projected from

process-state and skills-and-tools were the 16:13 comment’s “narrative skill that does not yet exist”; both are now written, which is why the moved-from-folio-core figure is 21 rather than 17. The three mcp-* skills are new writing, not moves — nothing in folio-core covered projection.

Documentation — the smallest set

Prose an agent reads, not pages a reader browses:

  • the data models above, described as one deterministic workflow: Actors with Skills work Tasks in a Business Process, assigned by swimlane role;
  • context-handling expectations, and bean info/workflow/management;
  • a minimal coding policy (#243);
  • how Tools are made available in shell/CLI and optionally as MCP, and how a Task’s I/O corresponds to a Tool’s inputs and outputs (16:28).

Tools — four nodes, and no MCP

Per 16:28 the harness holds beans and nothing else as a dependency. That is still true, and it is about what must be installed — not about how many Tool nodes exist. The forge decision below adds a second subject, and beans turns out to need two nodes rather than one:

Tool nodesatisfiesinvocation
beans-clithe six work-plan skillsshell — installed by scripts/install-beans.sh
beans-manualthe same sixshell — scripts/beans-fallback.ts, or a hand edit of the front matter
githubthe four PR-choreography skillsshell — gh, or the REST call it wraps
pages-publishkg-exportshell — push a directory to the gh-pages branch

Two beans nodes, not one. The CLI is absent from a fresh container, and an agent that knows only the CLI reads the plan and touches nothing — the 2026-09-18 failure where a session completed two merged PRs’ worth of durable work unclaimed. The fallback is a Tool of equal standing, not a footnote, and modelling it as one is what forces the skill to say when to reach for it.

pages-publish is where the harness’s visibility problem is solved. The harness has no renderer — folio is the only renderable kind and it belongs to core — so its knowledge graph is published as data, not as a page: kg-export serializes it to one JSON document and this Tool puts the document somewhere. That does not make the harness self-documenting; it makes it inspectable, which is the property that was actually missing. A GitLab Pages or object-store node satisfies the same skill later, which is the forge decision above applied a second time.

No MCP. None of these needs a tool server: ToolDefinition.invoke carries mcp as one optional arm beside shell and container, and the harness relies on shell. A Tool whose only invocation is an MCP call is not usable by the harness that defines it. MCP is acknowledged as a transport a downstream instance may offer, and assumed nowhere.

The Tool KG stays in the harness, per 16:13 — that is what makes the harness bootstrappable: it can describe its own tools in its own vocabulary, with no renderer and no server.

The tools layer — the minimum

Almost empty by construction, and that is the point.

itemnote
beans CLI Tool nodeinstall, invoke, I/O contract
install-beans.shthe one script

All code snippets live here, not in skills (16:13). Skills should carry minimal code; a snippet in a skill is a Tool that has not been declared. That is a QA audit criterion, not a style note — see the strawperson below.

The Tools schema — built, and where the strawperson bent

No longer a strawperson. schemas/tool.ts is real, tools/ holds four nodes, and bun run cat check:tools gates them in CI. The shape below is what shipped; three things changed in contact with the first real Tools, and each is the kind of thing only writing them would have surfaced:

  • invoke.manual was added. beans-manual — editing a bean’s front matter by hand — is a real mechanism with equal standing to the CLI, and modelling it as an absent shell would have made it indistinguishable from an unfinished record.
  • install.none for the same reason: “nothing to install” and “not filled in” must not render identically.
  • invoke is refined to require an arm the harness can run. A Tool whose only invocation is invoke.mcp is unusable by the layer that defines it and would make a projector emit a server that proxies itself. Rejected at parse time.

The two fields flagged below as too loose are both tightened: io.*.schema is an absolute IRI into a published $defs document (schemas/tool-types.ts), and satisfies must be non-empty — with check:tools resolving the names, which a schema cannot do because it does not get to read the tree.

Strawperson: the Tools-repo schema

The 16:13 comment asks for a schema for Tools-repo contents plus options with pros and cons. Here is the shape, written in the carrier the section below settles on — Zod is the authoritative form, and the TypeScript type is inferred from it rather than declared alongside it, so there is one definition and not two that can drift.

// schemas/tool.ts
export const ToolDefinitionSchema = z.object({
  id: z.string(),                                   // stable KG node id
  title: z.string(),
  summary: z.string(),

  /** How to obtain it. */
  install: z.object({
    cli:       z.string().optional(),
    container: z.string().optional(),
    service:   z.string().optional(),
  }),

  /** How to run it, per environment. */
  invoke: z.object({
    shell:     z.string().optional(),
    mcp:       z.object({ tool: z.string() }).optional(),
    container: z.string().optional(),
  }),

  /** The contract a Task binds against — the 16:28 requirement. */
  io: z.object({
    inputs:  z.array(z.object({
      name: z.string(), schema: z.string(), required: z.boolean(),
    })),
    outputs: z.array(z.object({
      name: z.string(), schema: z.string(),
    })),
  }),

  /** Skills this tool can satisfy. One skill may have several tools. */
  satisfies: z.array(z.string()),

  requires: z.object({
    os:      z.array(z.string()).optional(),
    runtime: z.array(z.string()).optional(),
    network: z.boolean().optional(),
  }).optional(),
});

export type ToolDefinition = z.infer<typeof ToolDefinitionSchema>;

The io block is the part that earns its keep: it is what lets a Task’s inputs and outputs be checked against the Tool that will execute it, rather than hoping they line up.

Two fields are deliberately loose at this stage and should be tightened before anything is built on them. io.*.schema is a string — presumably an IRI into the schema graph, but nothing yet says which, and an unresolvable reference is the failure mode the io block exists to prevent. satisfies is a bare array of skill ids with no check that the skills exist; that is the same declared-but-absent defect dh4f found in the pipeline scripts, where a consumer scans nothing and reports a clean run.

Carrying it — authored once in Zod, rendered downstream

Decided (2026-09-18, by the repository owner): the .ts Zod schema is authoritative, and as many downstream renderings are generated from it as make sense — JSON-LD and JSON Schema to begin with. That is how every other schema in this repository is defined, and the Tools schema gets no exception.

schemas/tool.ts            ← AUTHORITATIVE.  Zod + the inferred TS type.
  │
  ├─→ schemas/generated/Tool.schema.json      JSON Schema  (validation, editors)
  └─→ kg/tools/<id>.jsonld                    JSON-LD      (KG node, queryable)

The generation direction is the whole decision. scripts/generate-schemas.ts already walks a map of Zod schemas through zodToJsonSchema into schemas/generated/*.schema.json; adding Tool is one entry in that map, not a new mechanism. The JSON-LD side has its precedent too — toJsonLd() in schemas/cat-harness.ts projects a Zod-validated declaration into the folio namespace. Both renderings are derived artefacts: regenerate, never hand-edit, exactly as docs/reference/skills/ and docs/reference/skill-instructions/ are already treated.

Zod .ts, rendered downJSON-LD authoredTS, no renderingsSkill front-matter
shapeone Zod schema; per-tool instances validated against itone hand-written .jsonld per toolone .ts per tool, and nothing elseYAML block in the skill .md
author-time checkingyesno — a typo is a runtime discoveryyesno
KG nodeyes, generatedyes, nativelyno — needs a projection nobody wroteno — unqueryable without parsing Markdown
readable without a TS toolchainyes, via the renderingsyesnono
number of truthsoneoneoneone
verdictdecidedsupersededinsufficientdo not

An earlier draft of this page recommended authoring the JSON-LD directly, with Zod validating it in CI. That is the same two artefacts with the authority pointing the wrong way, and the difference is not cosmetic:

  • A hand-authored JSON-LD node is unchecked until CI runs. Under the decided direction the Zod schema is the type, so a malformed tool definition fails at tsc, in the editor, before it is committed. Validation-after-the-fact catches the same error strictly later and only if CI is green — and this repository has just spent a bean (dzl3) on a suite that was not running at all, so “CI will catch it” is a claim with a poor local record.
  • It would have been a fourth pattern in a repo that already has one. Zod → JSON Schema is generate-schemas.ts; Zod → docs is generate-docs.ts; Zod → JSON-LD is toJsonLd. Authoring the rendering and validating backwards is the only shape here that would have run against all three.
  • “Language-agnostic” was never the trade it looked like. A shell or Python consumer reads the generated JSON-LD and JSON Schema under the decided direction just as well as it reads a hand-authored one. Nothing is lost by generating them; what is gained is that they cannot disagree with the type.

C — front-matter in the skill — is still worth rejecting explicitly, and for unchanged reasons: it is the least work today, it directly contradicts the instruction that code snippets belong in tools rather than skills, and it caps the model at one tool per skill, which kills “several Tools may satisfy one Skill” before it is built.

What “as many renderings as make sense” means in practice

Two now, and a test for any third. A rendering earns its place when a real consumer cannot read the ones that exist: JSON Schema because editors and validators speak it, JSON-LD because the KG query path does. A third — SHACL, an OpenAPI fragment, a Turtle serialisation — is added when something needs it, not in anticipation. Each one is another file to regenerate and another chance for a stale artefact to be read as current, so the bar is a consumer, not a possibility.

The corresponding rule: a rendering is never the place a fix lands. If a generated Tool.schema.json is wrong, schemas/tool.ts is wrong; edit that and regenerate. A --check mode in CI (the pattern gen-skill-docs.ts --check already uses) is what makes that enforceable rather than merely stated.

The documentation move-table

Measured on main at d8632b6: 18 top-level pages, 8 guides, 20 BPMN processes, 115 skills across 9 packages.

Legend — AH cat-harness · AHT the tools layer · C the content core · CT folio-assistant-core-tools · S the science layer · W the DAK layer/smart-kg · FA stays put

Top-level pages (docs/*.md)

pagelines→reasoning
cat-harness.md349AH + CSplits. The interaction model, session lifecycle and request classification are harness; the published page is core. This is the clearest example of the whole exercise: the content is harness, the rendering is core.
crdm-methodology.md768AHFeature-request process, explicit at 16:16. Largest single doc.
beans-and-todos.md169AHWorkflow state, explicit at 16:28.
accessibility.md219AH + CSplits. User modalities are harness (how to talk to a person); dark/light, QR, contrast are core UI.
publication-workflow.md505AH + CSplits. The BPMN index and the HCI validation gate are harness guardrails; draft→publish is core.
architecture.md + architecture/*131 + 4 pagesCDescribes the platform for readers; self-documentation is core’s job.
content-types.md265CBlock kinds, profiles.
skills.md256AHSkills, roles, RBAC composition — harness vocabulary.
getting-started.md271AH16:13, explicit (#232).
installation.md186AH + AHTHarness install story; the scripts are tools.
translation-support.md684CRendering-facing; six UN languages are a core UI default.
document-ingestion.md241CContent intake.
evidence.md205SEvidence/provenance for formal claims.
sage-mcp.md70SSage.
qou-migration-checklist.md70FAOne folio’s checklist; should not survive the split at all.
folio-assistant-migration.md289FAHistorical record of the beans migration.
contributing.md86AHCoding policy (#243).
index.md118CSite landing page.

Guides (docs/guides/)

guidelines→reasoning
agent-onboarding.md202AHOrientation for an agent — the harness’s core job.
new-content-type.md117CAdding an adapter.
writing-a-document.md303CAuthoring.
writing-a-paper.md342SLean + LaTeX.
reseeding-the-lean-cache.md288SLean toolchain.
who-smart-dak.md97WL2.
who-smart-ig.md144WL3.

BPMN processes (processes/) — 20 files

process→reasoning
crdm-requirementsAH16:16.
bean-lifecycleAHWorkflow state.
getting-startedAHCatBootstrap.
editing-hci-validationAHThe validation gate is a guardrail.
content-lifecycle, draft-to-publication, content-change-reviewAH (definition) + CT (rendering)The process is a guardrail; the diagram a reader looks at is core-tools. Per 16:28: skills on how they are guardrails stay in cat-harness.
authoring-a-documentCPer content type.
authoring-a-paperS
l2-dak-authoring, l3-fhir-pipeline, ig-incremental-buildW
document-ingestion, ingest-* (4), evidence-retrievalCIngestion pipeline.
translation-workflow, human-translation-workflowC

Skills (115 across 9 packages)

packagecount→
folio-core5517 → AH, ~30 → C, ~8 → S (table above)
folio-paper-adapter47S
content-lifecycle8C
folio-document-adapter4C
authoring-who-smart-guidelines1W
framework, remote-packages, authoring-math, folio-document-adapter0 .mdmanifests only — follow their package

User todo management — suggestions

The 16:28 comment asks for these explicitly, so they are proposals rather than findings.

1. Todo and Bean are the same object at different audiences — and TodoItem is already most of it. A bean is agent work-plan state; a Todo note is a user-authored sticky. Both are “a unit of intent with status, provenance and hierarchy”, and TodoItem already has everything except hierarchy. I would extend TodoItem with an audience discriminator (agent | human) rather than write a second schema, and make the bean store a serialisation of it. Two schemas means two answers to “what is outstanding”, free to disagree — the exact defect AGENTS.md records for the todos-vs-beans split that beans resolved once already.

2. Hierarchy is the one field genuinely missing. TodoItem has related[] for threading but no parent — I checked. The 16:13 comment wants child Todos with navigation into the hierarchy, and 14:48 wants sub-beans for parallel work; both are parent?: string plus an ordering key. That is a one-field change to an existing schema, not a new mechanism.

3. Blocking exists but is untimed. TodoStatus already includes "blocked" — “waiting on external input (author, upstream change)”. What it lacks is 14:48’s timeout and handoff. I would add blockedOn?: { what, since, expires, handoff }, so an expired block becomes a signal rather than a bean that quietly sits forever, and so a second agent knows what it is inheriting.

4. The rendering is core’s, the state is the harness’s. Sticky-note styling, drag/resize, and the metadata for position belong in folio-assistant-core-tools; the Todo schema stays in the harness. This is the 16:28 rule applied consistently, and it is what keeps a headless agent able to read and write Todos with no renderer present.

Decided: 17 stays, and the forge is isolated at the Tool layer

Settled 2026-09-18 by the repository owner. All 17 skills stay in cat-harness. There is no sixth repository.

The proposal was to split the four PR-choreography skills — prepare-merge-auto, pickup, watch, coordinate — into an cat-harness-github sibling, so the harness could run on GitLab or on sovereign compute with no forge at all. The goal was right and the mechanism was wrong, which the measurement makes plain.

Measured on main, 2026-09-18. The four skills total 1,404 lines. coordinate.md alone is 731 lines carrying 94 matches for GitHub-ish terms — of which 12 are concrete invocations (mcp__github__*, gh pr, gh api) and the other 82 are conceptual: “pull request”, “PR”, “GitHub” as a noun.

# what was actually counted
grep -ciE 'github|gh pr|pull request|\bPR\b|mcp__github' skills/sdlc/sdlc-core/coordinate.md   # 94
grep -cE  'mcp__github|gh api|gh pr|gh issue'             skills/sdlc/sdlc-core/coordinate.md   # 12

So the split would have moved 1,404 lines of portable prose to isolate on the order of a few dozen lines of mechanism — and would have done it by cutting along a repository boundary, the most expensive cut available, to separate things that are not actually separable at that grain. The skills are already forge-neutral; only their invocations are not.

Isolate at the Tool layer instead. A skill states the capability generically; Tool nodes, one per forge operation, carry the invocations and name the skills they satisfy. Adding GitLab is more Tool nodes against the same skills — not a repository, not a fork, not a rewrite. The SOP is skills-and-tools; the Tool schema is the strawperson above, whose satisfies field is exactly this edge.

The two consolidations also considered — repo-conversion into getting-started, and symbiotic-interaction into interaction-modality — are not taken. Both pairs overlap, but merging them is editorial tidying with no architectural consequence, and the grouping below addresses the find-the-right-one problem that motivated it.

No MCP in the harness — but the harness knows how to emit one

cat-harness assumes no MCP server. Everything it needs is files in declared directories, readable with a filesystem and <name>.json alone. ToolDefinition.invoke carries mcp as one optional arm beside shell and container, and the harness relies on shell; a Tool whose only invocation is an MCP call is not usable by the harness that defines it.

That is a statement about dependency, not about ignorance. MCP is an output of this harness, not an input to it: the three mcp-* skills above are how an agent takes a Tool node describing a CLI and produces a working MCP service from it. The harness is the thing that knows the mapping; it just does not need the result in order to run.

The projection is close to free, and that is the carrier decision paying off rather than a coincidence. An MCP tool declaration is a name, a description and a JSON Schema for its input — and schemas/tool.ts is authoritative Zod, whose JSON Schema rendering is already generated (§”Carrying it”). io.inputs and io.outputs are already the I/O contract; invoke.shell is already the mechanism. The projection is a rename, not a translation, which is the sign the Tool schema was shaped correctly.

Stating it this way settles what would otherwise look like a contradiction — “no MCP” alongside three MCP skills — and it is the reason sovereign-compute and air-gapped operation are reachable later without a second design: an instance with no server loses a transport, not a capability.

The kg/ layout — group them, do not flatten them

Keeping all of them raises the problem the cuts were partly aimed at: a flat directory of 24 files gives a reader no way to tell which one governs the task in front of them. So the kg graph is grouped, and the group is part of the address:

kg/
  work-plan/          bean-coordination, todo-manager, pending-show,          [6]
                      session-intent, continual-progress, idle-backlog
  pr-choreography/    prepare-merge-auto, pickup, watch, coordinate           [4]
  interaction/        interaction-modality, symbiotic-interaction             [2]
  process/            crdm-detect, crdm-requirements-workflow,                [4]
                      process-state, dispatch-agent
  bootstrap/          getting-started, repo-conversion,                       [7]
                      directory-conventions, skills-and-tools,
                      mcp-projection, mcp-assembly, mcp-contract
  watchers/           integration-watcher (abstract parent; the concrete       [1]
                      watchers are downstream)
                                                                        total  24

The three mcp-* skills sit in bootstrap/ because standing a service up is bootstrapping — that is the owner’s classification, and it is the right one: an agent looking for “how do I make this tool reachable” is asking a setup question, not an MCP question. If bootstrap/ keeps growing, an mcp/ subgroup under it is the natural split, and splitting a group is a git mv rather than a decision to relitigate.

The totals are written down deliberately. The figure above this section was wrong for as long as it took someone to append rows without recounting; a grouping whose parts sum to a stated whole is the cheapest guard against that happening again, and it is checkable by eye.

Two things this buys beyond tidiness. pr-choreography/ is the group the forge Tools attach to, so the boundary the sixth repo would have drawn is still legible — as a directory, reversible for the price of a git mv, rather than as a repository. And a group is the natural unit for the “which skill governs this?” question, which is the one a flat list answers worst.

The grouping is not implemented here. This repo is pre-split and its kg id points at skills/, flat. The layout above is the target for cat-harness, recorded so the split does not land as a flat dump of 17.

What is deliberately not here

  • No implementation. Nothing in this page creates a repo or moves a file.
  • The folio graph typology is currently mis-sited. schemas/cat-harness.ts lists folio among the harness’s graph typologies, which contradicts 16:28 — a renderable kind belongs to core. Tracked separately; it is a small correction, not a rewrite.
  • Swarm management (14:48 — model levels, swarm size, CPU) is named as a separate skill set and is not designed here.
  • The L1/L2 boundary still needs WHO domain context, unchanged from the migration plan.

folio-assistant — code under the Apache License 2.0, documentation under CC BY 3.0. Generated schema and API references are rebuilt from source on every push to main.

deployed dev