@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.
- package/CHANGELOG.md +63 -0
- package/README.md +6 -4
- package/dist/cli.mjs +6347 -8
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +1 -36
- package/dist/src-CpDIVudJ.mjs +43 -0
- package/docs/index.md +4 -2
- package/package.json +18 -5
- package/schema/schema.sql +316 -0
- package/templates/scaffold/.agents/skills/format-checker/check.mjs +23 -0
- package/templates/scaffold/.agents/skills/intake-interview/SKILL.md +13 -8
- package/templates/scaffold/.claude/skills/format-checker/check.mjs +23 -0
- package/templates/scaffold/.claude/skills/intake-interview/SKILL.md +13 -8
- package/templates/scaffold/AGENTS.md +104 -10
- package/templates/scaffold/README.md +28 -3
- package/templates/scaffold/instance.md +3 -2
- package/templates/scaffold/package.json +8 -1
- package/templates/scaffold/pnpm-workspace.yaml +21 -5
|
@@ -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.
|
|
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
|
|
12
|
-
guesses — interview the owner, one
|
|
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
|
|
53
|
-
an audience model from question 6
|
|
54
|
-
list) and `default_visibility
|
|
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
|
|
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
|
-
|
|
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)
|
|
22
|
-
|
|
23
|
-
|
|
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).
|
|
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.
|
|
22
|
-
|
|
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.
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
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
|