@panaversity/ksor 0.0.55 → 0.0.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: intake-interview
3
- description: The first conversation with the owner of this Knowledge System of Record — seven questions that define what it is authoritative for, who may read it and who may approve it, then write instance.md together. Use when the owner asks to set up, configure, or "get started with" this project, when instance.md still contains its scaffold placeholder text, or when the scope of the corpus is unclear.
3
+ description: The first conversation with the owner of this Knowledge System of Record — three questions that define what it is authoritative for, who may read it and who may approve it, then write instance.md together. Use when the owner asks to set up, configure, or "get started with" this project, when instance.md still contains its scaffold placeholder text, or when the scope of the corpus is unclear.
4
4
  metadata:
5
- version: "1.5.0"
5
+ version: "1.6.0"
6
6
  ---
7
7
 
8
8
  # Intake interview
@@ -123,9 +123,10 @@ never an email address.
123
123
  Leave `name:` and `toolchain:` alone. One block is added here only when
124
124
  the owner stands up the served MCP rung — `database:`/`embedding:`/
125
125
  `retrieval:` (see `AGENTS.md` → "Serving to agents"; that is a later
126
- climb, not part of this interview). The strictness answer from question 5
127
- is the intent behind the `retrieval.vector_floor` on that climb, measured
128
- by `ksor calibrate` — capture it in the prose now so it is ready.
126
+ climb, not part of this interview). The `declines` default above (or the owner's
127
+ correction to it) is the intent behind the `retrieval.vector_floor` on that
128
+ climb, measured by `ksor calibrate` — capture it in the prose now so it is
129
+ ready.
129
130
  - Write `.ksor/governance.yaml` from question 3: `version: "0.1"`,
130
131
  the `audiences:` registry if there is one, and the two authority sets with
131
132
  real actors. That file is the root of authority — every approval, every
@@ -134,12 +135,19 @@ never an email address.
134
135
  document is still in `knowledge/`.** Those five are approved by it, so a
135
136
  policy rewritten without it refuses the next build by name
136
137
  (`ksor-approver-unauthorised`). It leaves when the last sample does.
138
+ - **Re-attribute what `human:you` already did.** If any document carries
139
+ `human:you` as its approver, generator or deprecator — the hello-world
140
+ tutorial's own document does — rewrite those acts to the owner's handle in
141
+ the SAME change that retires the placeholder from the policy. It is the same
142
+ person. A policy that stops naming `human:you` beside a document that still
143
+ cites it turns a green record red (`ksor-approver-unauthorised`), and the
144
+ owner's first act after being interviewed should not be a refusal.
137
145
  - Write `.ksor/people.yaml` from question 3: `version: "0.1"` and a `people:`
138
146
  MAP from each actor to its natural name — `"human:bashiraziz": Bashir Aziz`.
139
147
  Keyed by the actor exactly as the record stores it, quoted because it
140
148
  contains a colon. Nothing else — the site looks the actor up at render time,
141
149
  so pages read "Owner · Bashir Aziz" instead of "Owner · human:bashiraziz". Every skill that records a governance
142
- act (this one, add-sources for `verified:` entries, `ksor takedown` for
150
+ act (this one, add-sources when it names a `ksor.owner`, `ksor takedown` for
143
151
  withdrawals) asks the owner for a natural name whenever it is about to write
144
152
  an actor that isn't in `people.yaml` yet — the owner is the only source of a
145
153
  display name, never a convention-based guess.
@@ -162,7 +170,7 @@ never an email address.
162
170
  the new title and refuses anything the profile does not accept.
163
171
  - Restart `pnpm dev` afterwards so the site picks the new title up, and
164
172
  show the owner their name on the page.
165
- - Offer to capture the source list from question 4 as the first real
166
- documents (the add-sources skill takes it from there).
173
+ - Offer to start on the owner's own documents: the add-sources skill takes
174
+ whatever material they have from there.
167
175
  - Read the result back to the owner and get an explicit yes before
168
176
  finishing. Their words, tightened — never your invention.
@@ -1,91 +1,136 @@
1
1
  ---
2
2
  name: add-sources
3
- description: Turn source materialdocuments, pages, pasted text, notes into governed knowledge in knowledge/. Use when the owner shares material to add, says "add this to the knowledge base", or asks how to get existing content in. Not for editing the site.
3
+ description: Turn what the owner has into governed knowledge in knowledge/ a document, a page, pasted text, notes, or something nobody ever wrote down that they tell you. Use when the owner shares material to add, says "add this to the knowledge base", asks how to get existing content in, or wants to write down what they know from memory with no source to hand. Not for editing the site.
4
4
  metadata:
5
- version: "1.3.0"
5
+ version: "2.0.0"
6
6
  ---
7
7
 
8
8
  # Add sources
9
9
 
10
- Converting material into the record is the everyday work of this project.
11
- The rules that make it _governed_ rather than merely stored:
12
-
13
- ## Placement and shape
14
-
15
- - One document per topic, under `knowledge/`, path = identity: lowercase,
16
- hyphens, a folder per natural grouping. Plain CommonMark `.md` if the
17
- source is rich (tables, images), tables become markdown tables and images
18
- land _beside the document_ with relative links.
19
- - A folder's `index.md` is GENERATED by `ksor build` and committed — never
20
- author one. A folder's own introduction is a named document inside it,
21
- such as `overview.md`. Reading order is the `order:` frontmatter key
22
- (ordered documents first, ascending; the rest follow alphabetically)
23
- never `meta.json` or `sidebar_position`.
24
- - Frontmatter is the KSoR Profile of OKF. Always: `type: Document`, `title`,
25
- `description` (one sentence), `status: draft`, and `ksor.audience` (a
26
- list). Reach for a reserved `type` `Policy`, `Procedure`, `Control`,
27
- `Standard`, `Definition`, `Decision Record`, `Example`,
28
- `Attested Computation` when the knowledge really is one; those additionally require `sources` and
29
- `ksor.owner`, which is the point of them.
30
-
31
- ```yaml
32
- ---
33
- type: Policy
34
- title: Purchase approval
35
- description: Who may approve a purchase, at which thresholds.
36
- status: draft
37
- sources:
38
- - id: fin-2025
39
- title: Finance policy manual §4.2, 2025 edition
40
- resource: https://intranet.example.com/finance/manual.pdf
41
- ksor:
42
- audience: [public]
43
- owner: team:finance
44
- ---
45
-
46
- A purchase above 10,000 needs a director's signature. [^fin-2025]
47
-
48
- [^fin-2025]: Finance policy manual §4.2, 2025 edition.
49
- ```
50
-
51
- Every source needs a `resource` a URL where one exists, otherwise the
52
- scope descriptor that names it ("Finance policy manual §4.2, 2025
53
- edition"). Precision matters: that governs; "internal docs" does not. A
54
- claim cites ONE of them by footnote, and the label must match a
55
- `sources[].id` or the checker refuses it.
56
-
57
- - `status: draft` always, and never anything else from here: `stable` needs
58
- `ksor.approval` by an actor `.ksor/governance.yaml` names, and recording
59
- an approval nobody gave is the one thing this skill must never do. Ask the
60
- owner; if they approve, THEY are the approver and you write down what they
61
- said.
62
- - When `.ksor/governance.yaml` registers audiences, ask the owner which of
63
- them may read the new material and list every one in `ksor.audience` —
64
- never guess that restricted material is public, and never write an
65
- identifier the registry does not declare (the checker refuses it, because
66
- a typo reads as a restriction).
67
-
68
- ## Fidelity rules
69
-
70
- - **Copy load-bearing values exactly** numbers, thresholds, dates, names.
71
- Never round, never paraphrase a figure.
72
- - **Two disagreeing sources stay two statements**, each with its own
73
- footnote never smooth a conflict into one invented truth; flag it to the
74
- owner.
75
- - **Do not fill gaps from general knowledge.** If the source doesn't cover
76
- something, the record doesn't either — that boundary is the product.
77
- - A document replacing an older one: mark the old one `status: deprecated`
78
- with `ksor.deprecated: { by, at }` (a takedown authority the policy names, or
79
- the owner an `ownership:` rule resolves — never the document's own
80
- `ksor.owner`; ask, never guess) and `ksor.superseded_by:` naming the
81
- successor by id (`policies/refunds-v2`, no `./` and no `.md`) never
82
- delete it. The successor must exist, be `stable`, and be readable by every
83
- reader of the deprecated one.
84
-
85
- ## Finish every batch
86
-
87
- Run `pnpm check` and fix what it reports (its errors explain themselves),
88
- then `ksor build` to regenerate every folder's `index.md` and write
89
- `build.lock.json`, and commit both with the documents. Then show the owner
90
- the rendered result (`pnpm dev`) the site is the review surface: you write,
91
- they check.
10
+ Getting knowledge into the record is the everyday work of this project. The
11
+ rules that make it _governed_ are in `AGENTS.md` → "Writing knowledge" (shape,
12
+ frontmatter, audience, `draft` until the owner approves, copy values exactly,
13
+ never invent). This file is the ACT: how a source becomes a document that
14
+ passes those rules, whatever kind of source it is.
15
+
16
+ ## The source is one of two kindsand usually both
17
+
18
+ **A file** PDF, Word, slides, HTML, a Notion export, pasted text — is
19
+ knowledge that already exists somewhere. Your job is to move it without losing
20
+ anything: convert it, structure it, and prove every load-bearing value survived.
21
+
22
+ **A person** "it's just how we do it" is knowledge that exists nowhere
23
+ yet. Your job is to draw it out by asking, write it as the record and not as a
24
+ transcript, and record only what they confirm.
25
+
26
+ A real owner has both: the policy PDF, and the exception everyone knows that
27
+ the PDF never mentions. So the person step runs EVERY time, after the file:
28
+ "what does this not cover?" is the question that finds the pages nobody wrote.
29
+
30
+ ## When the source is a file
31
+
32
+ 1. **Extract the text first, into a scratch file outside `knowledge/`.** The
33
+ extraction is what you convert from and what you verify against, so it has
34
+ to be a file you can grep, not something you remember reading:
35
+
36
+ | format | extractor |
37
+ | ------------------------ | ------------------------------------------------------------------- |
38
+ | PDF | `pdftotext -layout in.pdf /tmp/in.txt` (poppler) |
39
+ | docx / odt / html / epub | `pandoc in.docx -t gfm -o /tmp/in.md` |
40
+ | docx on macOS | `textutil -convert txt in.docx -output /tmp/in.txt` (built in) |
41
+ | anything | `markitdown in.pdf > /tmp/in.md`, if installed |
42
+ | Notion / Obsidian export | already markdown — no extraction needed; the file IS the extraction |
43
+
44
+ None on `PATH`? Read the file directly (your Read tool opens PDFs) and say so
45
+ in your report — there is then no extraction to verify against, and step 5
46
+ degrades to re-reading the source by eye. That is a weaker check, and the
47
+ owner must be told it was the check that ran.
48
+
49
+ **Empty extraction — whitespace, form-feeds, nothing — means the PDF has no
50
+ text layer.** Stop and tell the owner: "This is a scanned image. I can read it
51
+ as a picture, but I cannot promise the numbers in it are right, and a wrong
52
+ threshold in a system of record is worse than a missing page. Give me a text
53
+ PDF, or paste the section you need." Do not OCR it and hope.
54
+
55
+ 2. **Decide the shape of the RECORD, not of one file.** A 200-page manual is not
56
+ one document. One document per topic — the unit someone would ask a question
57
+ about placed where its path is the identity it should have, with `order:`
58
+ set to reading order. Show the owner the proposed tree before writing it.
59
+
60
+ 3. **Convert to CommonMark a person would have written.** Real headings from
61
+ the document's own structure (never an `# h1` — the title is the frontmatter),
62
+ real lists, real tables; images extracted and placed beside the document
63
+ with relative links. Strip page furniture: running headers and footers, page
64
+ numbers, "Page 4 of 12", the table of contents. Keep the source's own words
65
+ for anything load-bearing.
66
+
67
+ 4. **Name the source precisely** in `sources` — a URL where one exists,
68
+ otherwise the descriptor that governs ("Finance policy manual §4.2, 2025
69
+ edition"; "internal docs" governs nothing) — and cite it from the claim with
70
+ a footnote whose label is that source's `id`.
71
+
72
+ 5. **Verify do not trust yourself.** Run the shipped check against the
73
+ extraction from step 1:
74
+
75
+ ```sh
76
+ node .agents/skills/add-sources/verify.mjs /tmp/in.txt knowledge/<path>.md
77
+ ```
78
+
79
+ It lists every load-bearing token in the document's body — numbers, dates,
80
+ thresholds, codes, capitalised names that does not appear in the
81
+ extraction. Each one is either a value you changed (fix it, verbatim) or a
82
+ value you introduced (delete it, or turn it into an `Open question:` line
83
+ for the owner). A value that passes was in the source; nothing more is
84
+ claimed. Frontmatter is exempt, because its title and description are your
85
+ words by design.
86
+
87
+ ## When the source is a person
88
+
89
+ 1. **Ask, one question at a time, in their words.** Who triggers this? What
90
+ happens first, then next? Who has to approve, and at what threshold? What
91
+ goes wrong, and what is the exception? Follow up until each answer is
92
+ concrete enough that someone who was not in the room could act on it —
93
+ "what would someone actually ask this?" gets further than "define the
94
+ boundary".
95
+
96
+ 2. **Draft as the record, not as a transcript.** One document per topic. Their
97
+ sentences, tightened — never your inference about what they must have
98
+ meant. Anything they did not say, or said they were not sure of, becomes an
99
+ `Open question:` line in the document. It does not become prose.
100
+
101
+ 3. **The source is the conversation, and it is named like any other.** No
102
+ `provenance:` key exists; the attestation goes in `sources`:
103
+
104
+ ```yaml
105
+ sources:
106
+ - id: ops-interview-2026-08-21
107
+ title: Interview with J. Smith, Head of Operations
108
+ resource: "Interview with human:jsmith (Head of Operations), 2026-08-21T10:00:00Z, conducted by human:you"
109
+ ```
110
+
111
+ Who, their role, the instant, and who asked. That is a claim nobody can
112
+ check against a file, and the pull request that adds it is the only thing
113
+ standing behind it — say so if the owner asks what "verified" would mean
114
+ here. No transcript is kept: raw unreviewed speech does not belong in a
115
+ governed record, and the checker refuses a `.txt` there anyway.
116
+
117
+ 4. **Two people describe one process differently — surface it, never smooth
118
+ it.** Two cited statements, each with its own footnote, and the
119
+ disagreement flagged to the owner. Which one becomes `stable` is an
120
+ approval, not an edit.
121
+
122
+ ## Finish — every batch, either kind
123
+
124
+ - `pnpm check`, and obey what it prints.
125
+ - `ksor build`: it regenerates every folder's `index.md` and writes the lock.
126
+ - **Read it back on the site.** `pnpm dev` renders the real page, drafts
127
+ marked; that page is what the owner confirms against, not a message in a
128
+ terminal. "Their words, tightened — never your invention" is the standard,
129
+ and it is theirs to say whether you met it.
130
+ - **Then ask them to approve it — and write down what they said.** A draft
131
+ reaches no machine surface: no `llms.txt`, no `/md/` twin, nothing for an
132
+ agent to cite. Until the owner says "approved" and you record
133
+ `ksor.approval: { by: <their handle>, at: <now> }` with `status: stable`,
134
+ the record still publishes nothing of theirs. Never record an approval
135
+ nobody gave.
136
+ - Commit the documents, the indexes and the lock together.
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ // Did the document keep its source's load-bearing values?
3
+ //
4
+ // node verify.mjs <extraction.txt> <document.md>
5
+ //
6
+ // Exit 0 when every load-bearing token in the document's BODY appears in the
7
+ // extraction; exit 1 and print each one that does not, one per line.
8
+ //
9
+ // What "load-bearing" means here: numbers (with their separators — 10,000 and
10
+ // 10000 are different claims about the source), dates, codes, and runs of two
11
+ // or more capitalised words (a name). Matched case-folded and with whitespace
12
+ // collapsed, because an extraction shouts its headings and wraps its lines.
13
+ //
14
+ // What this proves, and no more: a token that PASSES is present in the source.
15
+ // A token that FAILS was changed or introduced — either way, look at it. It
16
+ // cannot tell a paraphrase from an invention, and it cannot see a value that
17
+ // was dropped. It is a floor under model-driven conversion, which is highest
18
+ // fidelity for layout and lowest for exact values (issue #31).
19
+ //
20
+ // Plain Node, no dependencies, safe to copy: `.agents/skills/` is the owner's.
21
+
22
+ import { readFileSync } from "node:fs";
23
+
24
+ const [, , extractionPath, documentPath] = process.argv;
25
+ if (!extractionPath || !documentPath) {
26
+ console.error("usage: node verify.mjs <extraction.txt> <document.md>");
27
+ process.exit(2);
28
+ }
29
+
30
+ const fold = (s) => s.toLowerCase().replace(/\s+/g, " ");
31
+
32
+ const extraction = fold(readFileSync(extractionPath, "utf8"));
33
+ const raw = readFileSync(documentPath, "utf8");
34
+
35
+ // Body only: frontmatter is the agent's own words by design (title,
36
+ // description, ids). Footnote labels and definition prefixes are ids too.
37
+ const body = raw.replace(/^---\n[\s\S]*?\n---\n?/, "").replace(/\[\^[^\]]+\]:?/g, " ");
38
+
39
+ const tokens = new Set();
40
+ for (const m of body.matchAll(/\d[\d,.:/-]*\d|\d/g)) tokens.add(m[0]);
41
+ for (const m of body.matchAll(/\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+)+\b/g)) tokens.add(m[0]);
42
+
43
+ const missing = [...tokens].filter((t) => !extraction.includes(fold(t))).sort();
44
+ for (const t of missing) console.log(t);
45
+ process.exit(missing.length === 0 ? 0 : 1);
@@ -2,54 +2,26 @@
2
2
  name: format-checker
3
3
  description: The record's format rules as a runnable check — frontmatter, filenames, links, structure. Use before handing off any change to knowledge/, when a check fails and you need to fix it, or when unsure whether a document is well-formed. Run with `pnpm check` (or node .agents/skills/format-checker/check.mjs).
4
4
  metadata:
5
- version: "2.1.0"
5
+ version: "3.0.0"
6
6
  ---
7
7
 
8
8
  # Format checker
9
9
 
10
- `pnpm check` runs `check.mjs` a self-contained Node program that needs no
11
- install. It is **generated** by ksor from the same rule set `ksor build` and
12
- `ksor ingest` run, so the three can never disagree about what a well-formed
13
- record is. Do not edit it: `ksor init` writes it and `ksor migrate` rewrites
14
- both copies of it when you upgrade the tool, so an edit is overwritten rather
15
- than kept. It is read-only in the other direction too — it reports, and never
16
- rewrites a file.
10
+ `pnpm check` runs `check.mjs`. The rules it holds the record to are the ones in
11
+ `AGENTS.md` "Writing knowledge"; this file says only what that section does
12
+ not, which is how to relate to the program.
17
13
 
18
- If its refusals contradict this document, the checker is older than the record:
19
- upgrade `@panaversity/ksor` and re-run `ksor migrate`, and never "fix" the
20
- record by undoing what the migration wrote.
21
-
22
- What it holds the record to (the full contract is ksor's record spec):
23
-
24
- - Every document in `knowledge/` is a concept in the KSoR Profile of OKF:
25
- frontmatter is real YAML carrying `type`, `title`, `description`, `status`
26
- (`draft | stable | deprecated`) and `ksor.audience` (a list; `public` or
27
- audiences registered in `.ksor/governance.yaml`). A `stable` concept carries
28
- `generated` and an approval by an authorised actor; a `deprecated` one says
29
- who deprecated it and usually names its successor; a reserved type (`Policy`,
30
- `Procedure`, …) names `sources` and `ksor.owner`. Every timestamp is an
31
- instant with an offset; every footnote label matches a `sources[].id`.
32
- - `.ksor/governance.yaml` exists and names approval and takedown authorities;
33
- `.ksor/takedowns.yaml` is append-only, every entry by a takedown authority,
34
- and never names a concept that no longer exists.
35
- - `index.md` files are generated by `ksor build`, never authored — a stale or
36
- missing one is refused (`ksor-index-stale`; run `ksor build`). `log.md` and
37
- `README.md` are reserved names.
38
- - Filenames are portable identities: lowercase ascii, no spaces, no
39
- case-collisions, no `x.md` beside `x/`, no parentheses or leading
40
- underscore. `knowledge/` holds `.md`, companions (`<doc>.summary.md`,
41
- `<doc>.{flashcards,quiz,slides}.yaml`) and images only.
42
- - Links resolve inside `knowledge/` — inline, `<angle-bracketed>` and
43
- reference-style alike; code is never a link — and never reach a document
44
- that not every reader of the source may read (the widening rule).
45
- - `instance.md` is `format: 2` with the closed key set the profile defines.
46
- - `CLAUDE.md` stays a one-line pointer; `.agents/skills/` and
47
- `.claude/skills/` hold the same files byte for byte in both directions; the
48
- site contains no content files.
49
-
50
- Every failure prints where, the rule's slug (`problem: ksor-…`), why the rule
51
- exists, and the fix — obey the printed fix literally; if it doesn't resolve
52
- the problem, that is a bug worth reporting to ksor.
53
-
54
- When you edit any skill under `.agents/skills/`, re-copy it to
55
- `.claude/skills/` — the checker holds the two trees identical.
14
+ - **It is generated, and it is the same rule set** `ksor build` and
15
+ `ksor ingest` run, so the three can never disagree about a well-formed
16
+ record. Do not edit it: `ksor init` writes it and `ksor migrate` rewrites both
17
+ copies when you upgrade, so an edit is overwritten rather than kept. It
18
+ reports and never rewrites a file.
19
+ - **Obey the printed fix literally.** Every refusal prints where, the rule's
20
+ slug (`problem: ksor-…`), why the rule exists, and the fix. If the fix does
21
+ not resolve the problem, that is a bug worth reporting to ksor.
22
+ - **If its refusals contradict `AGENTS.md`, the checker is older than the
23
+ record**: upgrade `@panaversity/ksor` and re-run `ksor migrate`. Never "fix"
24
+ the record by undoing what a migration wrote.
25
+ - **When you edit any skill under `.agents/skills/`, re-copy it to
26
+ `.claude/skills/`** the checker holds the two trees byte-identical in both
27
+ directions.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: intake-interview
3
- description: The first conversation with the owner of this Knowledge System of Record — seven questions that define what it is authoritative for, who may read it and who may approve it, then write instance.md together. Use when the owner asks to set up, configure, or "get started with" this project, when instance.md still contains its scaffold placeholder text, or when the scope of the corpus is unclear.
3
+ description: The first conversation with the owner of this Knowledge System of Record — three questions that define what it is authoritative for, who may read it and who may approve it, then write instance.md together. Use when the owner asks to set up, configure, or "get started with" this project, when instance.md still contains its scaffold placeholder text, or when the scope of the corpus is unclear.
4
4
  metadata:
5
- version: "1.5.0"
5
+ version: "1.6.0"
6
6
  ---
7
7
 
8
8
  # Intake interview
@@ -123,9 +123,10 @@ never an email address.
123
123
  Leave `name:` and `toolchain:` alone. One block is added here only when
124
124
  the owner stands up the served MCP rung — `database:`/`embedding:`/
125
125
  `retrieval:` (see `AGENTS.md` → "Serving to agents"; that is a later
126
- climb, not part of this interview). The strictness answer from question 5
127
- is the intent behind the `retrieval.vector_floor` on that climb, measured
128
- by `ksor calibrate` — capture it in the prose now so it is ready.
126
+ climb, not part of this interview). The `declines` default above (or the owner's
127
+ correction to it) is the intent behind the `retrieval.vector_floor` on that
128
+ climb, measured by `ksor calibrate` — capture it in the prose now so it is
129
+ ready.
129
130
  - Write `.ksor/governance.yaml` from question 3: `version: "0.1"`,
130
131
  the `audiences:` registry if there is one, and the two authority sets with
131
132
  real actors. That file is the root of authority — every approval, every
@@ -134,12 +135,19 @@ never an email address.
134
135
  document is still in `knowledge/`.** Those five are approved by it, so a
135
136
  policy rewritten without it refuses the next build by name
136
137
  (`ksor-approver-unauthorised`). It leaves when the last sample does.
138
+ - **Re-attribute what `human:you` already did.** If any document carries
139
+ `human:you` as its approver, generator or deprecator — the hello-world
140
+ tutorial's own document does — rewrite those acts to the owner's handle in
141
+ the SAME change that retires the placeholder from the policy. It is the same
142
+ person. A policy that stops naming `human:you` beside a document that still
143
+ cites it turns a green record red (`ksor-approver-unauthorised`), and the
144
+ owner's first act after being interviewed should not be a refusal.
137
145
  - Write `.ksor/people.yaml` from question 3: `version: "0.1"` and a `people:`
138
146
  MAP from each actor to its natural name — `"human:bashiraziz": Bashir Aziz`.
139
147
  Keyed by the actor exactly as the record stores it, quoted because it
140
148
  contains a colon. Nothing else — the site looks the actor up at render time,
141
149
  so pages read "Owner · Bashir Aziz" instead of "Owner · human:bashiraziz". Every skill that records a governance
142
- act (this one, add-sources for `verified:` entries, `ksor takedown` for
150
+ act (this one, add-sources when it names a `ksor.owner`, `ksor takedown` for
143
151
  withdrawals) asks the owner for a natural name whenever it is about to write
144
152
  an actor that isn't in `people.yaml` yet — the owner is the only source of a
145
153
  display name, never a convention-based guess.
@@ -162,7 +170,7 @@ never an email address.
162
170
  the new title and refuses anything the profile does not accept.
163
171
  - Restart `pnpm dev` afterwards so the site picks the new title up, and
164
172
  show the owner their name on the page.
165
- - Offer to capture the source list from question 4 as the first real
166
- documents (the add-sources skill takes it from there).
173
+ - Offer to start on the owner's own documents: the add-sources skill takes
174
+ whatever material they have from there.
167
175
  - Read the result back to the owner and get an explicit yes before
168
176
  finishing. Their words, tightened — never your invention.
@@ -801,9 +801,9 @@ CI — and a first deploy without it serves an empty record. Full walkthrough:
801
801
  quiz had every correct answer in the same position across 451 questions.
802
802
 
803
803
  A **presentation** is slides the record owns. Ask your coding agent for one
804
- rather than writing it by hand `make slides for knowledge/<path>.md` runs
805
- the `make-slides` skill, which reads the document, writes the deck, checks
806
- every claim back against it, and tells you what it left out:
804
+ rather than writing it by hand: it reads the document whole, writes the
805
+ deck, checks every claim and every number back against the document, and
806
+ tells you what it left out because the document did not support it:
807
807
 
808
808
  ```yaml
809
809
  slides:
@@ -918,6 +918,11 @@ SAMEORIGIN`, which forbids any other site from framing them, and a browser
918
918
  - Copy load-bearing values (numbers, thresholds, dates) exactly from their
919
919
  source, name the source in `sources`, and cite it from the claim with a GFM
920
920
  footnote whose label is that source's `id`.
921
+ - **The record says only what its source says.** A gap is an open question
922
+ written into the document — never filled from general knowledge — and two
923
+ sources that disagree stay two cited statements: flag the disagreement to
924
+ the owner rather than choosing. That boundary is the product; a record that
925
+ quietly knows more than its sources is a chatbot with a sidebar.
921
926
 
922
927
  ### Structuring the record
923
928
 
@@ -940,12 +945,10 @@ SAMEORIGIN`, which forbids any other site from framing them, and a browser
940
945
 
941
946
  - `.agents/skills/intake-interview/` — first run: interview the owner and
942
947
  write `instance.md` together.
943
- - `.agents/skills/add-sources/` — turn source material (documents, pages,
944
- notes) into governed knowledge.
945
- - `.agents/skills/make-slides/` generate a presentation from one document
946
- and attach it, so it renders on that document's page.
947
- - `.agents/skills/make-summary/` — write a document's summary and attach it,
948
- so it renders as a second tab on that document's page.
948
+ - `.agents/skills/add-sources/` — turn what the owner has into governed
949
+ knowledge: a document, a page, notes, or what they tell you that nobody
950
+ wrote down. Converts files with a verified extraction, interviews a person
951
+ for the rest, and ends with the owner's approval.
949
952
  - `.agents/skills/format-checker/` — the rules above, as a program;
950
953
  `pnpm check` runs it and its errors explain how to fix themselves.
951
954
 
@@ -111,9 +111,9 @@ Before changing anything, get a feel for how the record behaves. With
111
111
  - **Ask your coding agent to do the same.** `AGENTS.md` carries the working
112
112
  rules; read it before you change how documents are written here. The kit in
113
113
  `.agents/skills/` already knows this project: `intake-interview` (define the
114
- record with you), `add-sources` (turn source material into governed
115
- documents), `make-slides`, `make-summary`, and `format-checker` (the rules,
116
- as a program — also what `pnpm check` runs).
114
+ record with you), `add-sources` (turn what you have — files, or what you
115
+ know — into governed documents), and `format-checker` (the rules, as a program — also what
116
+ `pnpm check` runs).
117
117
 
118
118
  **Treat the starters as scratch paper.** They ship approved by
119
119
  `ksor-starter/KSOR-STAMP-VERSION` — a tool, not a person. Edit the body and that
@@ -400,11 +400,22 @@ wrong thing describes it on every surface. So replace them, in this order:
400
400
  approve or withdraw a document — then it writes `instance.md` with you and
401
401
  replaces the `human:you` placeholder in `.ksor/governance.yaml` with your
402
402
  real handle.
403
- 2. **Delete each starter document** as your own knowledge arrives.
404
- 3. **When the last one is gone, delete `ksor-starter/KSOR-STAMP-VERSION` from
403
+ 2. **Write and approve at least one document of your own** ask your agent
404
+ to add it (the `add-sources` skill), read it on `pnpm dev`, then approve it.
405
+ A record is never empty: delete all five starters before this and the next
406
+ build refuses `ksor-record-empty` and writes nothing.
407
+ 3. **Delete each starter document** as your own knowledge arrives.
408
+ 4. **When the last one is gone, delete `ksor-starter/KSOR-STAMP-VERSION` from
405
409
  `approval_authorities` in `.ksor/governance.yaml`.** Nothing of yours should
406
410
  be approved by a tool.
407
411
 
412
+ If you did the hello-world tutorial first, your document is approved by
413
+ `human:you`. The interview replaces that placeholder with your real handle —
414
+ and re-attributes every act already recorded under it to you in the same
415
+ change, because it is the same person. A policy that no longer names
416
+ `human:you` beside a document that still cites it refuses
417
+ `ksor-approver-unauthorised`.
418
+
408
419
  ---
409
420
 
410
421
  ## Writing knowledge
@@ -470,7 +481,7 @@ record:
470
481
  make slides for knowledge/expenses/approvals.md
471
482
  ```
472
483
 
473
- The `make-slides` skill reads the document whole, writes the deck into
484
+ Your agent reads the document whole, writes the deck into
474
485
  `knowledge/expenses/approvals.slides.yaml`, checks every claim and every number
475
486
  back against the document, and tells you what it left out because the document
476
487
  did not support it — which is usually how you find out a document has a gap. The
@@ -494,7 +505,7 @@ way:
494
505
  summarise knowledge/expenses/approvals.md
495
506
  ```
496
507
 
497
- The `make-summary` skill reads the document whole, writes
508
+ Your agent reads the document whole, writes
498
509
  `knowledge/expenses/approvals.summary.md`, and checks every line back against
499
510
  the document — every number, every rule, and every `##` section, because a
500
511
  summary that covers the opening and trails off is worse than none: a reader who
@@ -505,7 +516,7 @@ The summary is part of its document, not a document of its own: no route, no
505
516
  sidebar row, no line in `llms.txt`, and it takes its governance from its parent.
506
517
  Ask for one only where there is something to compress — under about two screens,
507
518
  a summary that restates the page teaches readers the tab is not worth opening,
508
- and the skill will say so rather than write one.
519
+ and a good agent will say so rather than write one.
509
520
 
510
521
  ---
511
522
 
@@ -682,7 +693,7 @@ different coding agent's way of finding the same working contract.
682
693
  | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
683
694
  | `AGENTS.md` | the working contract every coding agent reads first — the rules for writing knowledge here. |
684
695
  | `CLAUDE.md` | one line, pointing at `AGENTS.md`. Claude Code looks for this filename, not that one. |
685
- | `.agents/skills/` | the agent kit: `intake-interview` (define the record with you), `add-sources` (turn source material into governed documents), `make-slides`, `make-summary`, `format-checker` (the rules, as a program). |
696
+ | `.agents/skills/` | the agent kit: `intake-interview` (define the record with you), `add-sources` (turn files, or what you know, into governed documents), `format-checker` (the rules, as a program). |
686
697
  | `.claude/skills/` | byte-identical copies of the kit — Claude Code discovers skills only here. The checker enforces the mirror, so the two cannot drift. |
687
698
  | `.gemini/settings.json` | points Gemini CLI at `AGENTS.md`; Gemini does not read that filename on its own. |
688
699
  | `.github/workflows/validate.yml` | your CI: runs the same checker on every pull request and push to main. |
@@ -711,6 +722,8 @@ map rather than a substitute.
711
722
  | the agent answers questions 2 and 3 instead of declining | no floor is measured, so the gate is off (`abstain OFF`, `gate: "off"`) — step 3's `calibrate` was skipped | `pnpm exec ksor calibrate --instance instance.md`, paste the block, restart |
712
723
  | a deployed door serves an empty record | deploying does not publish — and a laptop DSN is unreachable from the host | point both at one hosted Postgres, then `pnpm refresh` |
713
724
  | the home page and `/llms.txt` are empty | every document is still a draft — correct, not broken | approve one and rebuild |
725
+ | `ksor-record-empty` | every document was deleted — a record is never empty, so nothing was written | add one document of your own (or restore one from git) before deleting the last starter |
726
+ | `ksor-approver-unauthorised` | a document is approved by an actor `.ksor/governance.yaml` no longer names — usually `human:you` after the interview | re-attribute the approval to your handle, or restore the actor to `approval_authorities` |
714
727
  | a new document never appears on the built site | drafts reach no built surface at all | publish it — `status: stable` plus both governance keys |
715
728
  | an expired document still shows on the site but not through the door | the static build evaluated `stale_after` at build time | rebuild and redeploy; schedule a rebuild if you use it |
716
729
  | Vercel: `no services are declared` | Root Directory was auto-filled with `system/site` | set it to `./` |