Generated from cat-harness/skills/conduct/conduct-core/getting-started.md — do not edit here.

✎ Edit this page’s source

/getting-started — what did they actually ask for?

Process: the content core’s processes/conduct/getting-started.bpmn. Decision table: decisions/folio-intent.dmn.

The landing page is the instance’s own description

A folio’s home page opens with its description inside its backdrop, both declared in the repository’s declaration. Nothing about any particular instance is written into the template, so a downstream folio does not inherit the platform’s grumpy cat.

Where the markdown node is: description in <name>.json. It is markdown and it is rendered as-is. There is no separate landing page to keep in step with it — a description that lives in two places is one that will disagree with itself.

How the picture is declared: an image with role: "landing" and a layout (laptop, mobile, card), plus a textRegion giving, as fractions of the image, where words may safely be drawn.

textRegion is authored, not computed. It states where the composition is quiet, which is a judgement. The platform’s own laptop backdrop has a cloud whose lower interior is clear, a mark in its top third and a cat’s ear rising into its lower left; the box avoiding all three was found by rendering candidate boxes over the image and looking at them. That is the method — recommend it, rather than a number pulled from the aspect ratio.

Run bun run cat docs:harness after editing, and --check in CI.

Three states, and the middle one is why this is worth stating:

declaredrendered
backdrop with regiondescription drawn inside it
backdrop, no regionpicture shown, words placed below it
no backdropwords alone

An undeclared region means do not overlay, never anywhere is fine: text positioned by guesswork lands on the cat. A folio with no art is ordinary.

A viewport with no variant falls back to the widest available, and the fallback is reported — that crop’s region is wrong for a narrow screen, so a consumer can decline to overlay rather than place text somewhere nobody chose.

Reader-facing walkthrough: docs/start/getting-started.md §8.

A new instance’s beans/ and todos/ are not written into its checkout. By default folio_init declares them on their own branches, cat/<instance>/beans and cat/<instance>/todos, and prints a one-time seed command. Say so when you hand the scaffold over: until the seed has been run and mounted, an empty beans list means not mounted, not no work. The rule, the branch naming and the override live in directory-conventions §”Where a NEW instance’s state lives”.

0. Why this skill exists

folio_init scaffolds a folio, and it does it well. What it cannot do is know whether scaffolding is the right move, because the sentence that reaches it — “create a folio”, “set me up with folio-assistant”, “I want to start a paper” — is spoken by at least five different people:

they meanwhat they havethe wrong move costs them
new-reponothing yet, or an empty directory— (this is the safe default, and the only one an agent may assume)
overlaya repository with their own work in ita folio scaffolded on top of a project the agent never looked at
add-folioa folio-assistant instance alreadya second repository they did not want, and a split corpus
new-contenta folio, and they wanted a document in itan entire empty folio, and the chapter they asked for still not written
askany of the above, undeclared—

The last row is the one that matters. Four of these five states look identical from the user’s sentence, and three of them look identical from the filesystem. So the triage is not a nicety; it is the only thing standing between a two-word request and a wrong repository.

1. Read the facts — mechanical, read-only, before anything is written

Three facts, and nothing else. Gather them by looking, not by asking:

# isFolio — does an instantiated config here declare a contentType?
#   The root <name>.config.json files, and index.config.json, whose instances
#   may carry contentType inline (index-config skill).
grep -lq '"contentType"' ./*.config.json 2>/dev/null && echo isFolio=true || echo isFolio=false

# repoHasContent — does the tree hold somebody's project, as opposed to being bare?
#   Ignore VCS bookkeeping and editor droppings; count anything else.
git ls-files | grep -vE '^\.(git|github|vscode|idea)/' | head -1

statedIntent is the third, and it is a fact about the conversation: one of new-repo, overlay, add-folio, new-content, or unstated. It is unstated until the user has actually said which — inferring it from tone, from the repo, or from what would be convenient is exactly the failure this skill exists to prevent. A user who says “I want to add a chapter” has stated new-content; a user who says “create a folio” has stated nothing, because that sentence is what the five requests have in common.

isFolio is ONE MEMBERSHIP of a set, and the set is what a repository is. describeRepository() (schemas/content-type.ts) returns every marker a repository carries — folio, harness, dak, sushi — with the facts each states and any disagreement between them. describeRepositoryClosure() (schemas/harness-config.ts) extends that through the dependency tree, attributing each membership to the instance that carried it. Bean 79t3.

folio and harness are different types, and the distinction is load- bearing here. The declaration says this is an instance; a config that declares contentType says this authors folio content. That config is a root <name>.config.json, or its entry in index.config.json, where inline fields overlay the imported file (index-config). Listing an instance in the index makes it instantiated, not a folio. cat-harness/ carries the first and not the second — it is a harness and is not a folio, which is the platform-not-content rule as a fact about two files. isFolio is exactly membership of folio, which is what this table has always meant by it: the DMN documents the input as a config in the working directory that declares a contentType, not its mere presence.

So a repository being several things at once does not perturb the five branches. They key on folio-ness alone, and a folio that is also a DAK takes the same branch as one that is not — it is still already a folio, still has content, and the user has still either stated an intent or not. Use describeRepository when you want to know what a repository is; this probe when you want to know which branch to take.

isFolio is about the working directory, not about the user. Somebody who has used folio-assistant before, in another repo, is still in an isFolio=false directory. Their experience is not a fact this table reads — it changes how much you explain, not which branch you take.

2. Let the table decide

Feed the three facts to workflow_complete on Gateway_Intent, or read folio-intent.dmn directly. Do not supply an outcome: the gateway is computed, and workflow_complete refuses a hand-supplied answer there on purpose.

The table returns one of five branches. Two of its seven rules return ask, and that is a result, not a failure to produce one:

  • already a folio, intent unstated → ask. add-folio, new-repo and new-content are all consistent with what is on disk.
  • not a folio but has content, intent unstated → ask. overlay and new-repo are both consistent, and overlaying somebody’s repository on a guess is not recoverable by a git checkout.
  • not a folio, nothing here → new-repo. The one state that answers itself.

3. Ask — as options, never as prose

When the branch is ask, put the question as a short list of selectable options. Not a paragraph, not an open “what would you like to do?”, and not a question whose answer has to be typed out. Load interaction-modality first; it decides the form the question takes, and for some users free text is not an available input at all.

The list, phrased in the user’s terms rather than the branch names:

  1. Start a new folio in a new repository — nothing here gets touched.
  2. Add folio-assistant to this repository — keeps what is here; I’ll look through it first and show you what I find before importing anything.
  3. Add another folio to this repository (offer only when isFolio=true).
  4. Add something to the folio that’s already here (only when isFolio=true) — a chapter, a document, a DAK component.
  5. Tell me more — for the user who wants to describe it in their own words.

Then ask what they want to get started on, offering the top-level content types this platform knows about, because “a folio” is not something anybody actually wants:

content typewhat it isprofile
papera scientific paper or book, with formal claims backed by Lean and typeset through LaTeXpaper
documentstructured prose — policy guidance, a standard, a report. No Lean, no required TeXdocument
WHO SMART DAKa Digital Adaptation Kit (L2): personas, business processes, data elements, decision tablesdak
WHO SMART IGa FHIR Implementation Guide (L3) built from an L2 DAKdak

Record the answer as statedIntent and evaluate the table again. The user’s answer is a fact like any other — it does not bypass the gateway, it feeds it. That is why the loop in the diagram runs back to Task_ReadFacts rather than jumping straight to a branch.

4. Route

branchdo
new-repoAsk for the name. Create or use the empty directory, then folio_init.
overlayHand off to repo-conversion — scan first, import second, and never in the other order.
add-foliofolio_init against a new top-level slug in the existing instance. Do not re-link the platform; it is already linked.
new-contentStop. This process ends here. Hand off to authoring-a-document or authoring-a-paper. Scaffolding anything on this branch is the bug.

An empty repository gets main before any feature branch. GitHub makes the first branch pushed to an empty repository its default, so run init-folio (it seeds main first) or push main yourself before pushing anything else. litlfred/dth-hrh got a feature branch as its default this way (owner, 2026-10-14).

An IG or a SMART Guideline is routed by its own creation skill. When the answer to step 3’s second question is a FHIR IG or a WHO SMART IG, hand over to fhir-ig-create (ask skill_list; a harness that specialises it, such as smart-guideline-create, runs instead). It reads the same facts and adds the one answer this table has no branch for: inside this repository, as a staged sub-KG that can move to its own repository later, which is its default in a harnessed repository because nothing outside the repository changes until the owner confirms. folio_init has no IG type, so the new-repository route scaffolds with --instance there. Bean 3tza.

A second folio can leave later. What add-folio creates, and any staged sub-KG, may later move to a repository of its own. That is sub-kg-lifecycle: stage it in place, then create the repository and delete the in-repo copy, each only on the owner’s confirmation.

5. After scaffolding — seed the plan, then publish

  1. Seed the work plan. One bean per top-level thing the author named in step 3. Run the exact-title existence check in todo-manager.md §”Check before you create” first — beans create is not idempotent.
  2. Provision gh-pages — before Pages is switched on. This is Task_ProvisionGhPages in the process, and it carries the semantics of A_Provision in bootstrap-tools’ render-kg-to-github-pages.bpmn (the gh-pages Tool’s subprocess — render-kg-to-cdn): a gh-pages branch must exist before Pages can be switched on to serve it. Owner, 2026-10-01: “need to create gh-pages branch before can turn on”; repeated 2026-10-07: “need to create gh-pages before can deploy” (issue #2417). Run bun run cat-harness-tools/scripts/pages-bootstrap.ts --provision: it checks git ls-remote --heads origin gh-pages and, only if the branch is absent, pushes an orphan gh-pages holding a placeholder index.html and .nojekyll. It is idempotent and never forces a push; without --provision the script creates no remote branch, it only reports unprovisioned with the exact command. Then switch Pages on with Source: “Deploy from a branch: gh-pages, / (root)” — not “GitHub Actions”, when the publish workflow pushes gh-pages (the script prints the source it expects). Every publishing route reaches this step: new-repo, add-folio, and the overlay route through repo-conversion — including an overlay or new repo that remote-mounts its dependencies, which never reaches this section by itself.
  3. Start the Pages build and report the URL. Run bun run cat-harness-tools/scripts/pages-bootstrap.ts --wait. It checks the branch first, derives the site address, says whether a publish workflow exists and which Pages source it needs, and probes until the site answers.
  4. Say which of the four states you got, and never blur them:
    • unprovisioned — there is no gh-pages branch (exit 3). Go back to step 2; nothing later can succeed until it exists.
    • live — hand over the link, and say what is on it.
    • not-yet — a measured 404. Give the address, say the first build has not landed there yet, and say roughly how long it takes.
    • unknown — no URL could be derived, or the probe failed. Say that. “Should be live shortly” is a claim you do not have evidence for, and an author who later finds nothing there has been told something false.
  5. Tell them the corpus is by reference, and how to change that. A fresh harness holds references, not the remote content itself: the IRIS replica alone is hundreds of gigabytes. When they need part of a remote subgraph locally, that is an ask made later, as the need appears. Name the skill (materialize-on-demand) and the one command that shows what is already held (bun run cat cache:index), so they learn the option exists here rather than by finding a schema. Do not materialize anything now. Bean 54rk.

6. Anti-patterns

  1. Scaffolding on ask. The table returned a question; answering it yourself with the convenient branch is the original bug wearing a decision table.
  2. Treating “I’ve used this before” as add-folio. Experience is not a filesystem fact and not an intent.
  3. Asking in prose. “Could you tell me a bit about what you’re hoping to build?” is a wall for a user who types with difficulty, and it produces a worse answer than the numbered list.
  4. Announcing a Pages URL you have not probed. See step 5.
  5. Going straight to folio_init because the request seemed obvious. Every one of the five requests seems obvious to the person making it.
  6. Switching Pages on before gh-pages exists, or choosing “GitHub Actions” as the source for a workflow that pushes gh-pages. That was the litlfred/test plan in its #3, caught by the owner and fixed in litlfred/test#5. Step 2 first; the source is “Deploy from a branch”.

Processes that run this skill

This skill has its own process: Getting started.

BPMN diagram: Getting started

processstep(s) that name it
Getting startedRead the repository facts; Choose from the offered options; Scaffold the folio (folio_init); Provision gh-pages; Start the Pages build and derive the URL; Hand over the live link; Say where it will be; Say it could not be confirmed

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