@panaversity/ksor 0.0.3 → 0.0.4

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.
@@ -2,15 +2,15 @@
2
2
  name: intake-interview
3
3
  description: The first conversation with the owner of this Knowledge System of Record — six questions that define what it is authoritative for and who may read 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.2.0"
5
+ version: "1.3.0"
6
6
  ---
7
7
 
8
8
  # Intake interview
9
9
 
10
10
  `instance.md` is the identity of this Knowledge System of Record, and its
11
- prose will one day be the agent surface's system prompt. Do not draft it from
12
- guesses — interview the owner, one question at a time, and write down what
13
- they actually say.
11
+ prose IS the agent surface's system prompt (`ksor serve` wires it into the MCP
12
+ server's instructions). Do not draft it from guesses — interview the owner, one
13
+ question at a time, and write down what they actually say.
14
14
 
15
15
  ## The six questions
16
16
 
@@ -49,10 +49,15 @@ act on:
49
49
  record's **display title**, the human name every page will lead with
50
50
  ("Acme Operations Handbook", not the slug) — then the authority sentence,
51
51
  boundary, audience, and strictness — plain prose, written for a reader
52
- who must act on it. Leave the frontmatter keys alone, with one exception:
53
- an audience model from question 6 is written there as `audiences:` (a
54
- list) and `default_visibility:`, and `pnpm check` will hold the record to
55
- it from that moment on.
52
+ who must act on it. Leave the identity frontmatter keys alone; two things
53
+ are written there when they apply: an audience model from question 6, as
54
+ `audiences:` (a list) and `default_visibility:` (`pnpm check` holds the
55
+ record to it from that moment on); and — only when the owner stands up the
56
+ served MCP rung — the `database:`/`embedding:`/`retrieval:` blocks (see
57
+ `AGENTS.md` → "Serving to agents"; that is a later climb, not part of this
58
+ interview). The strictness answer from question 5 is the intent behind the
59
+ `retrieval.vector_floor` on that climb, measured by `ksor calibrate` — capture
60
+ it in the prose now so it is ready.
56
61
  - Restart `pnpm dev` afterwards so the site picks the new title up, and
57
62
  show the owner their name on the page.
58
63
  - Offer to capture the source list from question 4 as the first real
@@ -5,22 +5,25 @@ here; every coding agent reads this file first.
5
5
 
6
6
  ## The two worlds
7
7
 
8
- | Path | What it is |
9
- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
10
- | `knowledge/` | **the record** — governed markdown, the owner's world, the product |
11
- | `system/` | **the system** — all code that serves the record |
12
- | `instance.md` | what this SoR is authoritative for; its prose is the future agent surface's system prompt. Its `name:` is the machine identity (llms.txt, future citations) and its body `# H1` is the DISPLAY TITLE every page leads with — both read when the server or build STARTS, so restart `pnpm dev` after changing either (found live 2026-08-18) |
8
+ | Path | What it is |
9
+ | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
10
+ | `knowledge/` | **the record** — governed markdown, the owner's world, the product |
11
+ | `system/` | **the system** — all code that serves the record |
12
+ | `instance.md` | what this SoR is authoritative for; its prose IS the agent surface's system prompt (`ksor serve` wires the body into the MCP server's instructions). Its `name:` is the machine identity (llms.txt, citations) and its body `# H1` is the DISPLAY TITLE every page leads with — both read when the server or build STARTS, so restart `pnpm dev` after changing either (found live 2026-08-18) |
13
13
 
14
14
  The record survives the system: `knowledge/` must stay readable and complete
15
15
  even if `system/` is deleted. Dependency flows one way — the system reads the
16
16
  record; the record never references the system.
17
17
 
18
18
  `instance.md` carries a closed key set — `format`, `name`, `ksor`, `site`,
19
- and the optional pair `audiences` + `default_visibility` (the record's reader
19
+ the optional pair `audiences` + `default_visibility` (the record's reader
20
20
  audiences, ordered least- to most-restricted with `public` first, and the one
21
- a document takes when it names none — declared together or not at all) and
22
- everything that matters about it is the prose below that frontmatter;
23
- `pnpm check` names any other key rather than ignoring it.
21
+ a document takes when it names none — declared together or not at all), and
22
+ the four serve-config blocks `database` / `embedding` / `retrieval` / `budgets`
23
+ (present only once you climb to the served MCP rung — see "Serving to agents"
24
+ below; a `pnpm dev`-only project declares none). Everything else that matters
25
+ about the instance is the prose below the frontmatter; `pnpm check` names any
26
+ other key rather than ignoring it.
24
27
 
25
28
  ## Critical rules
26
29
 
@@ -37,12 +40,103 @@ everything that matters about it is the prose below that frontmatter;
37
40
  ## Commands (run at the repo root)
38
41
 
39
42
  ```sh
40
- pnpm install # once, after cloning or scaffolding
43
+ pnpm install # once, after cloning or scaffolding (also fetches the pinned `ksor` tool)
41
44
  pnpm dev # the site, hot-reloading, at http://localhost:3000
42
45
  pnpm build # static site into system/site/out/
43
46
  pnpm check # the format checker — run before handing off any knowledge change
44
47
  ```
45
48
 
49
+ ## Serving to agents — the MCP rung (needs Postgres + a provider key)
50
+
51
+ `ksor serve` runs an MCP server over the record so agents get cited retrieval
52
+ with honest abstention. It is the climbed rung — not required for `pnpm dev`.
53
+ Stand it up in this order (each step's errors explain how to fix themselves):
54
+
55
+ 1. **Configure `instance.md`.** Add the serve blocks to the frontmatter
56
+ (`pnpm check` accepts them; the kernel validates their values):
57
+
58
+ ```yaml
59
+ database:
60
+ dsn_env: KSOR_DB_URL # the NAME of the env var holding the DSN — never the DSN itself
61
+ embedding:
62
+ provider: gemini # default; the seam, not the vendor, is the contract
63
+ model: gemini-embedding-001
64
+ dim: 1536 # ≤ 2000 for the pgvector HNSW index
65
+ retrieval:
66
+ vector_floor: uncalibrated # see step 6; `uncalibrated` REFUSES every serve until you paste a number
67
+ ```
68
+
69
+ 2. **Provision Postgres** with the `vector` extension (`CREATE EXTENSION vector`),
70
+ e.g. a Neon database. Export the DSN under the name `dsn_env` chose, plus the
71
+ provider key:
72
+
73
+ ```sh
74
+ export KSOR_DB_URL='postgresql://…' # the var instance.md names
75
+ export GEMINI_API_KEY='…' # the embedding provider key
76
+ ```
77
+
78
+ 3. **Apply the schema:** `pnpm schema` (creates tables, indexes, and the
79
+ ingest role).
80
+
81
+ 4. **Authorize ingest:** `pnpm grant` — writes the one row row-level security
82
+ requires before any write to this corpus is allowed. Idempotent, and
83
+ `pnpm exec ksor grant --instance instance.md --revoke` withdraws it.
84
+
85
+ This is a separate, named act on purpose: applying the schema and
86
+ authorizing writes are different decisions, and a schema step that granted
87
+ itself write access would make the tool its own authorizer. Apply the schema
88
+ and ingest as the SAME Postgres login (the ingest role is granted to whoever
89
+ applied the DDL).
90
+
91
+ 5. **Ingest:** `pnpm ingest` — embeds `knowledge/` into a fresh generation and
92
+ activates it (`--flip`). Safe to re-run (see the generation model below).
93
+
94
+ 6. **Calibrate the abstention floor** (only if `vector_floor: uncalibrated`):
95
+ `pnpm exec ksor calibrate --instance instance.md` prints a recommended
96
+ `vector_floor` measurement; paste the number into `instance.md`'s `retrieval:`
97
+ block and re-run. A corpus that declares no `retrieval:` block serves with the
98
+ gate OFF (honest: it will not refuse out-of-corpus questions).
99
+
100
+ 7. **Serve:** `pnpm serve`.
101
+
102
+ ```sh
103
+ pnpm schema # apply the DDL (once)
104
+ pnpm grant # authorize ingest for this corpus (once)
105
+ pnpm ingest # embed knowledge/ into a generation and activate it
106
+ pnpm serve # run the MCP server; any other verb: pnpm exec ksor <verb>
107
+ ```
108
+
109
+ ### How serving updates work (the generation model)
110
+
111
+ Each `ksor ingest` builds a **fresh generation** (invisible until activated) and
112
+ carries every unchanged embedding forward from the last complete generation —
113
+ so **re-ingest is safe and cheap**; only changed or failed chunks re-embed.
114
+ `--flip` swaps the active pointer, guarded by a catastrophic-shrink check
115
+ (`KSOR_MAX_SHRINK`, default `0.15` — a flip that drops more than 15% of nodes
116
+ refuses; override with `KSOR_ALLOW_SHRINK=1` when the shrink is intended). The
117
+ previous generation stays as a rollback target; `pnpm exec ksor gc` collects
118
+ abandoned ones.
119
+
120
+ ### Serving safely (fail-closed posture)
121
+
122
+ `pnpm serve` binds **loopback with auth off** — safe for local use. A **public**
123
+ bind refuses to boot unless auth is configured (`KSOR_SSO_URL` +
124
+ `KSOR_MCP_RESOURCE_URL` + `KSOR_JWT_ALLOWED_AUDIENCES`, making it an OAuth
125
+ Resource Server) OR you deliberately set `KSOR_ALLOW_PUBLIC_UNAUTHENTICATED=1`.
126
+ Never let a dropped auth variable silently ship an open door. On a non-loopback
127
+ bind, set `KSOR_ALLOWED_HOSTS` / `KSOR_ALLOWED_ORIGINS`; on more than one
128
+ replica, set a shared `KSOR_SNAPSHOT_KEYS` (unset ⇒ a per-process key, so a
129
+ search token minted by one replica fails on another).
130
+
131
+ Two things worth being deliberate about:
132
+
133
+ - **`KSOR_ALLOW_PUBLIC_UNAUTHENTICATED=1` serves your whole record to anyone
134
+ who can reach the port.** It exists for deployments fronted by your own
135
+ gateway or network policy. If nothing else is in front, do not set it.
136
+ - **Set `KSOR_SSO_ISSUER` when your SSO stamps a stable `iss`.** Audience is
137
+ always enforced against `KSOR_JWT_ALLOWED_AUDIENCES`; naming the issuer adds
138
+ one more check for the cost of one variable.
139
+
46
140
  ## Publishing
47
141
 
48
142
  `pnpm build` emits a fully static site (`system/site/out/`) deployable to
@@ -18,7 +18,32 @@ pnpm dev # browse the knowledge at http://localhost:3000
18
18
  ```
19
19
 
20
20
  No pnpm? Run `npm install -g pnpm` — or `corepack enable pnpm` on Node
21
- versions that bundle corepack.
21
+ versions that bundle corepack. The first `pnpm install` also fetches the
22
+ `ksor` tool (pinned in `package.json`) and writes it into your lockfile —
23
+ commit the updated lockfile.
24
+
25
+ ### Serving to agents
26
+
27
+ The record's other surface is an MCP server for AI agents — the same
28
+ knowledge, cited, with honest abstention. It is the climbed rung: it needs a
29
+ Postgres store (with pgvector) and an embedding provider key, so it is not
30
+ part of `pnpm dev`. The ordered path is:
31
+
32
+ ```sh
33
+ export KSOR_DB_URL='postgresql://…' # the DSN var your instance.md names
34
+ export GEMINI_API_KEY='…' # the embedding provider key
35
+ pnpm schema # apply the database schema (once)
36
+ pnpm grant # authorize ingest for this corpus (once)
37
+ pnpm ingest # embed knowledge/ into a generation and activate it
38
+ pnpm serve # run the MCP server over the record
39
+ ```
40
+
41
+ One setup step comes before this — adding the `database:`/`embedding:` blocks
42
+ to `instance.md` — and there is more to know about the generation model and the
43
+ fail-closed security posture. `AGENTS.md` → "Serving to agents" is the
44
+ full runbook; your coding agent reads it first. `pnpm serve` binds loopback
45
+ with auth off for local use; a public bind fails closed unless auth is
46
+ configured. Any other operation is `pnpm exec ksor <verb>`.
22
47
 
23
48
  Then talk to your coding agent — `AGENTS.md` carries the working rules, and
24
49
  the agent kit in `.agents/skills/` knows how to interview you
@@ -34,7 +59,7 @@ different coding agent's way of finding the same working contract.
34
59
  | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
35
60
  | `knowledge/` | **the record** — your governed markdown. The product; everything else serves it. |
36
61
  | `system/` | the code that serves the record: the site today, more as you need it. |
37
- | `instance.md` | what this record is authoritative for; its `name:` is the identity every surface publishes (read at server/build start — restart `pnpm dev` after renaming). When the agent surface ships, this prose becomes its system prompt. |
62
+ | `instance.md` | what this record is authoritative for; its `name:` is the identity every surface publishes (read at server/build start — restart `pnpm dev` after renaming). This prose IS the agent surface's system prompt `ksor serve` wires it into the MCP server's instructions. |
38
63
  | `AGENTS.md` | the working contract every coding agent reads first — the rules for writing knowledge here. |
39
64
  | `CLAUDE.md` | one line, pointing at `AGENTS.md`. Claude Code looks for this filename, not that one. |
40
65
  | `.agents/skills/` | the agent kit: `intake-interview` (define the record with you), `add-sources` (turn source material into governed documents), `format-checker` (the rules, as a program). |
@@ -43,7 +68,7 @@ different coding agent's way of finding the same working contract.
43
68
  | `.github/workflows/validate.yml` | your CI: runs the same checker on every pull request and push to main. |
44
69
  | `.gitattributes` | markdown is checked out byte-stable on every platform, so the same commit hashes the same everywhere. |
45
70
  | `.gitignore` | keeps build output, `node_modules/`, and `.env*` out of the record's history. |
46
- | `package.json` | the `pnpm dev` / `pnpm build` / `pnpm check` commands, and the pnpm version this project pins. |
71
+ | `package.json` | the `pnpm dev` / `pnpm build` / `pnpm check` / `pnpm schema` / `pnpm grant` / `pnpm ingest` / `pnpm serve` commands, the pinned `@panaversity/ksor` tool, and the pnpm version this project pins. |
47
72
  | `pnpm-workspace.yaml` | where the workspace looks for code (`system/site`, plus reserved `system/gateways/*` and `system/packages/*`), and the supply-chain policy for installs. |
48
73
  | `pnpm-lock.yaml` | the exact dependency versions — the reason two machines build the same site. |
49
74
 
@@ -18,8 +18,9 @@ the single most important sentence in the project._
18
18
 
19
19
  Everything below this frontmatter is the identity of this instance: what the
20
20
  corpus covers, who it serves, and how strictly it should decline questions it
21
- does not cover. When the agent surface ships, this prose becomes its system
22
- prompt — write it for a reader who must act on it.
21
+ does not cover. This prose IS the agent surface's system prompt `ksor serve`
22
+ wires it into the MCP server's instructions so write it for a reader who must
23
+ act on it.
23
24
 
24
25
  Ask your coding agent to run the **intake interview** (it knows how — see
25
26
  `.agents/skills/intake-interview/`), answer its questions, and let it write
@@ -6,7 +6,14 @@
6
6
  "scripts": {
7
7
  "dev": "pnpm -C system/site dev",
8
8
  "build": "pnpm -C system/site build",
9
- "check": "node .agents/skills/format-checker/check.mjs"
9
+ "check": "node .agents/skills/format-checker/check.mjs",
10
+ "schema": "ksor schema --instance instance.md --apply",
11
+ "grant": "ksor grant --instance instance.md",
12
+ "ingest": "ksor ingest --instance instance.md --knowledge knowledge --flip",
13
+ "serve": "ksor serve"
14
+ },
15
+ "dependencies": {
16
+ "@panaversity/ksor": "KSOR-STAMP-VERSION"
10
17
  },
11
18
  "engines": {
12
19
  "node": ">=24"
@@ -8,12 +8,28 @@ packages:
8
8
  # `pnpm install` here never picks up a day-zero compromised release.
9
9
  minimumReleaseAge: 2880
10
10
 
11
+ # The one exception is the tool that scaffolded this project: `ksor init` pins
12
+ # `@panaversity/ksor` to the EXACT version the adopter deliberately ran, so the
13
+ # quarantine (a defense against unknown third-party releases) must not block the
14
+ # first install for 48 hours after every ksor release. Remove this line only if
15
+ # you unpin the dependency.
16
+ minimumReleaseAgeExclude:
17
+ - "@panaversity/ksor"
18
+
11
19
  # Dependency install scripts are denied by default. Flip an entry to true
12
- # only with a comment naming what breaks without it. esbuild and sharp are
13
- # reviewed and stay denied: both ship prebuilt platform binaries as
14
- # optionalDependencies, so their install scripts are download fallbacks the
15
- # site never needs — but pnpm 11 exits 1 on every install/dev until each is
16
- # explicitly decided. (found live: fresh-scaffold pnpm dev, 2026-08-18)
20
+ # only with a comment naming what breaks without it. pnpm 11 exits 1 on every
21
+ # install until each build script is explicitly decided (found live:
22
+ # fresh-scaffold pnpm dev, 2026-08-18). All four below are reviewed and stay
23
+ # denied:
24
+ # esbuild, sharp prebuilt platform binaries ship as optionalDependencies,
25
+ # so their install scripts are download fallbacks the site never needs.
26
+ # @google/genai, protobufjs — pulled in by the `@panaversity/ksor` serve
27
+ # tool. genai's flagged script is its own dev `prepare` (nothing the
28
+ # published tarball needs built); protobufjs's postinstall is a
29
+ # version-compat warning, nothing built. (Same review as the root
30
+ # workspace, 2026-08-19; serve works with both denied — verified live.)
17
31
  allowBuilds:
18
32
  esbuild: false
19
33
  sharp: false
34
+ "@google/genai": false
35
+ protobufjs: false