@panaversity/ksor 0.0.43 → 0.0.45
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 +100 -0
- package/dist/cli.mjs +1 -0
- package/docs/deploying.md +28 -0
- package/docs/ingesting.md +15 -0
- package/package.json +1 -1
- package/templates/scaffold/.agents/skills/intake-interview/SKILL.md +69 -43
- package/templates/scaffold/.claude/skills/intake-interview/SKILL.md +69 -43
- package/templates/scaffold/README.md +512 -287
- package/templates/scaffold/package.json +1 -0
- package/templates/scaffold/system/site/preview.mjs +93 -0
- package/templates/scaffold/knowledge/what-is-a-ksor.flashcards.yaml +0 -25
- package/templates/scaffold/knowledge/what-is-a-ksor.quiz.yaml +0 -90
- package/templates/scaffold/knowledge/what-is-a-ksor.slides.yaml +0 -65
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,105 @@
|
|
|
1
1
|
# @panaversity/ksor
|
|
2
2
|
|
|
3
|
+
## 0.0.45
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1875d06: **`pnpm preview` — somewhere for `pnpm build` to land.**
|
|
8
|
+
|
|
9
|
+
The site is a static export, so there is no server to start; that is what makes
|
|
10
|
+
the record hostable anywhere. But it also means the natural thing to try after a
|
|
11
|
+
build — `pnpm start` — answers `ERR_PNPM_NO_SCRIPT_OR_SERVER`, which explains
|
|
12
|
+
none of that. `pnpm preview` serves `system/site/out` on the same bytes a host
|
|
13
|
+
would. It is `node:http` and nothing else: no dependency, no network fetch, works
|
|
14
|
+
offline and behind a firewall, for the same reason the build downloads nothing.
|
|
15
|
+
Run before a build, it says so and exits `3`.
|
|
16
|
+
|
|
17
|
+
**And the Vercel dashboard import now says what actually goes wrong.** Vercel
|
|
18
|
+
auto-detects a root directory by looking for a framework, finds the Next app, and
|
|
19
|
+
fills the field with `system/site`. The build then reads
|
|
20
|
+
`system/site/vercel.json`, which does not exist, and fails with
|
|
21
|
+
`Project framework is set to "services", but no services are declared` — even
|
|
22
|
+
though the import screen just listed both services, because that step reads the
|
|
23
|
+
root file and the build step uses the Root Directory override. The fix is one
|
|
24
|
+
field: set Root Directory to the repository root. `docs/deploying.md` now names
|
|
25
|
+
the error, the cause and the fix, plus the site-only fallback.
|
|
26
|
+
|
|
27
|
+
Found by an adopter, and it will recur on every dashboard import until Vercel's
|
|
28
|
+
detection changes — the layout that triggers it is decision 8 and is not moving.
|
|
29
|
+
|
|
30
|
+
**And the intake interview asks three questions, not seven.** Seven did not
|
|
31
|
+
survive contact: an agent running the skill decided five were too many,
|
|
32
|
+
defaulted them, and reported "answered: all seven" — including the one that
|
|
33
|
+
decides who may approve a document, which it filled from a git handle. A
|
|
34
|
+
process the tool executing it shortcuts is too long.
|
|
35
|
+
|
|
36
|
+
Scope, Boundary and Authority are asked, because none can be defaulted: the
|
|
37
|
+
first two give the abstention gate an edge to be outside of, and the third is
|
|
38
|
+
a governance act, which never gets guessed (decision 21). The other four are
|
|
39
|
+
STATED as defaults in one block — read by both, declines firmly, one `public`
|
|
40
|
+
audience, no sources yet — written only if the owner does not object, and the
|
|
41
|
+
write-back must name which were answered and which were defaulted. Reporting a
|
|
42
|
+
default as an answer is now called out in the skill as the thing not to do.
|
|
43
|
+
|
|
44
|
+
**The scaffold README no longer tells you to uncomment something that ships
|
|
45
|
+
uncommented.** 0.0.42 filled in `instance.md`'s `database:` block; the README
|
|
46
|
+
kept instructing the adopter to uncomment it, and named a refusal
|
|
47
|
+
(`instance.md declares no database: block`) they could no longer reach. The
|
|
48
|
+
emitted `AGENTS.md` had already been corrected and the README had not — two
|
|
49
|
+
documents describing one file, and only one of them updated. Vercel is three
|
|
50
|
+
steps ending in the Root Directory fix, `preview` sits beside `build`, and a
|
|
51
|
+
"When something refuses you" table maps every refusal an adopter meets to what
|
|
52
|
+
to do about it.
|
|
53
|
+
|
|
54
|
+
**The scaffold README is restructured around what the record is FOR.** It now
|
|
55
|
+
opens on the agent interface — an MCP door that answers with citations and
|
|
56
|
+
declines what the record does not cover — rather than on an architecture
|
|
57
|
+
diagram, because a reader classifies the project in the first fifteen seconds
|
|
58
|
+
and "governed markdown plus a site" puts it in the wrong bucket.
|
|
59
|
+
|
|
60
|
+
`ksor calibrate` moves into the main command path, between `refresh` and
|
|
61
|
+
`serve`. It was a parenthetical and a remedy-after-the-fact, which meant the
|
|
62
|
+
README's own three-question test failed at exactly the question it says
|
|
63
|
+
matters. Verified on the five-document starter: calibrate needs an ingested
|
|
64
|
+
corpus but NO running server, produces `vector_floor: 0.609`, and with it
|
|
65
|
+
applied the test passes as written — the paraphrased in-corpus question is
|
|
66
|
+
answered at 0.701 while an adjacent miss abstains at 0.550 and a far-outside
|
|
67
|
+
one at 0.512. The "expect answers, not refusals" note moves from postscript to
|
|
68
|
+
precondition, where it prevents the disappointment instead of explaining it.
|
|
69
|
+
|
|
70
|
+
Also: Neon is named for hosted Postgres rather than leaving it abstract (it is
|
|
71
|
+
already what this project's own docs are measured against, and pgvector is on
|
|
72
|
+
its free tier), the deploy section ends at the Root Directory fix, and a
|
|
73
|
+
"When something refuses you" table maps every refusal an adopter meets to the
|
|
74
|
+
one thing to do about it.
|
|
75
|
+
|
|
76
|
+
## 0.0.44
|
|
77
|
+
|
|
78
|
+
### Patch Changes
|
|
79
|
+
|
|
80
|
+
- 2ece135: **A lighter starter, and `refresh` finally says what it does** (issues #173, #171).
|
|
81
|
+
|
|
82
|
+
`ksor init` put five of `knowledge/`'s eleven files onto a single concept — 199
|
|
83
|
+
lines of companions against a 40-line document — so the first thing an adopter
|
|
84
|
+
opened was one document wearing four attachments. The flashcards, quiz and
|
|
85
|
+
slides companions are gone; `what-is-a-ksor.summary.md` stays, because it is the
|
|
86
|
+
only companion carrying a governance rule (exactly `type: Summary`, one key), so
|
|
87
|
+
the profile marker is still demonstrated. `knowledge/` goes from 11 files to 8.
|
|
88
|
+
|
|
89
|
+
What that costs, stated rather than glossed: the recall, quiz and slides tabs are
|
|
90
|
+
no longer shown by the starter, and an adopter meets those features in the docs
|
|
91
|
+
instead. Nothing about the companion mechanism changed — decision 24 is
|
|
92
|
+
untouched, and the migrate fixture that proves a deck migrates byte-identically
|
|
93
|
+
is frozen from an older tree, so it still covers the case.
|
|
94
|
+
|
|
95
|
+
And `pnpm refresh` was a name the constitution never defined, sitting beside
|
|
96
|
+
`pnpm ingest` and `ksor ingest` with nothing saying how the three relate. It has
|
|
97
|
+
a vocabulary entry now, and `docs/ingesting.md` opens with the model: `ksor
|
|
98
|
+
build` makes the SITE correct with no database, `ksor ingest` makes the AGENT
|
|
99
|
+
DOOR correct, and `pnpm refresh` runs both. The split between the scaffold's
|
|
100
|
+
script and the underlying verb is deliberate, and now it is written down instead
|
|
101
|
+
of inferred.
|
|
102
|
+
|
|
3
103
|
## 0.0.43
|
|
4
104
|
|
|
5
105
|
### Patch Changes
|
package/dist/cli.mjs
CHANGED
|
@@ -11329,6 +11329,7 @@ function transformManifest(source, manager) {
|
|
|
11329
11329
|
const SCRIPT_NAMES = [
|
|
11330
11330
|
"dev",
|
|
11331
11331
|
"build",
|
|
11332
|
+
"preview",
|
|
11332
11333
|
"check",
|
|
11333
11334
|
"serve",
|
|
11334
11335
|
"provision",
|
package/docs/deploying.md
CHANGED
|
@@ -113,6 +113,34 @@ What the image deliberately does NOT contain (see `.dockerignore`):
|
|
|
113
113
|
|
|
114
114
|
## Deploying both surfaces to Vercel
|
|
115
115
|
|
|
116
|
+
> **Importing from the Vercel dashboard: clear the Root Directory first.**
|
|
117
|
+
> Vercel auto-detects a root directory by looking for a framework, finds the
|
|
118
|
+
> Next app, and fills the field with **`system/site`**. The build then reads
|
|
119
|
+
> `system/site/vercel.json`, which does not exist, and fails with:
|
|
120
|
+
>
|
|
121
|
+
> ```
|
|
122
|
+
> Error: Project framework is set to "services", but no services are declared.
|
|
123
|
+
> ```
|
|
124
|
+
>
|
|
125
|
+
> The services ARE declared — in `vercel.json` at the repository root, which is
|
|
126
|
+
> the only place they can be, because one of them builds the site and the other
|
|
127
|
+
> builds a container from the root `Dockerfile`. The import screen even lists
|
|
128
|
+
> both, because that step reads the root file; the BUILD step uses the Root
|
|
129
|
+
> Directory override instead.
|
|
130
|
+
>
|
|
131
|
+
> **Set Root Directory to the repository root (`./`) and redeploy.** Nothing in
|
|
132
|
+
> the record changes. Found by an adopter on 2026-08-26, and it will happen on
|
|
133
|
+
> every dashboard import until Vercel's detection changes — the layout that
|
|
134
|
+
> triggers it, code under `system/`, is decision 8 and is not moving.
|
|
135
|
+
>
|
|
136
|
+
> Also confirm **Application Preset is `Services`**; with any other preset the
|
|
137
|
+
> `services` key is ignored and `/mcp` never exists. Vercel Services is in Beta.
|
|
138
|
+
>
|
|
139
|
+
> **If it still argues, deploy the site alone** — it needs no preset and no
|
|
140
|
+
> services: build command `pnpm -C system/site build`, output directory
|
|
141
|
+
> `system/site/out`. That is the stricter posture decision 29 describes, and
|
|
142
|
+
> the door can be deployed separately.
|
|
143
|
+
|
|
116
144
|
The emitted `vercel.json` declares both services and routes between them:
|
|
117
145
|
|
|
118
146
|
```json
|
package/docs/ingesting.md
CHANGED
|
@@ -14,6 +14,21 @@ embedding cost on every cold start and would need write credentials at runtime.
|
|
|
14
14
|
So **a first deploy with no ingest serves an empty record.** It is not broken;
|
|
15
15
|
nothing was ever published to it.
|
|
16
16
|
|
|
17
|
+
## `ksor ingest` or `pnpm refresh`?
|
|
18
|
+
|
|
19
|
+
Both, and they are not alternatives — one contains the other.
|
|
20
|
+
|
|
21
|
+
| | makes correct | needs a database |
|
|
22
|
+
| -------------- | ----------------------------------------------------------------------------------- | ---------------- |
|
|
23
|
+
| `ksor build` | the **site** — checks the record, regenerates the indexes, writes `build.lock.json` | no |
|
|
24
|
+
| `ksor ingest` | the **agent door** — embeds, loads Postgres, flips a generation | yes |
|
|
25
|
+
| `pnpm refresh` | both, in order: `ksor build` → `ksor ingest --flip` → `ksor gc` | yes |
|
|
26
|
+
|
|
27
|
+
`pnpm refresh` is the scaffold's script and the one to reach for by hand — it
|
|
28
|
+
is a single command that leaves every surface current. `ksor ingest` is the
|
|
29
|
+
verb underneath it, and it is what CI, a deploy step, or an agent calls when
|
|
30
|
+
the individual step is the subject. The rest of this page is about that verb.
|
|
31
|
+
|
|
17
32
|
## Before the first command
|
|
18
33
|
|
|
19
34
|
Ingest reads your markdown, sends each new chunk to an embedding provider, and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panaversity/ksor",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.45",
|
|
4
4
|
"description": "Knowledge System of Record — compile governed markdown into a static site for people and an MCP server for AI agents, with citations and measured abstention.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"abstention",
|
|
@@ -12,49 +12,75 @@ prose IS the agent surface's system prompt (`ksor serve` wires it into the MCP
|
|
|
12
12
|
server's instructions). Do not draft it from guesses — interview the owner, one
|
|
13
13
|
question at a time, and write down what they actually say.
|
|
14
14
|
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
15
|
+
## Ask THREE questions, one at a time
|
|
16
|
+
|
|
17
|
+
Seven questions is where this skill used to start, and it did not survive
|
|
18
|
+
contact: an agent running it decided five were too many, defaulted them, and
|
|
19
|
+
reported "answered: all seven" — including the one that decides who may
|
|
20
|
+
approve a document. A process the tool executing it shortcuts is too long.
|
|
21
|
+
|
|
22
|
+
So three are asked, and they are the three that cannot be defaulted:
|
|
23
|
+
|
|
24
|
+
1. **Scope** — "What should this record be the _final word_ on? Finish the
|
|
25
|
+
sentence: when someone here disagrees with this corpus, the corpus wins
|
|
26
|
+
about ___."
|
|
27
|
+
2. **Boundary** — "What is just _outside_ that — the near-miss topics people
|
|
28
|
+
will ask about here that the record should refuse rather than guess at?"
|
|
29
|
+
3. **Authority** — "Who may approve a document for publication, and who may
|
|
30
|
+
withdraw one?"
|
|
31
|
+
|
|
32
|
+
Scope and Boundary are asked because the abstention gate is meaningless
|
|
33
|
+
without an edge: a record authoritative for everything has no outside, so an
|
|
34
|
+
agent asked something the owner never wrote about reaches for its training
|
|
35
|
+
instead of declining. Authority is asked because a governance act names its
|
|
36
|
+
actor and the tool never guesses one — the scaffold ships `human:you` in
|
|
37
|
+
both authority lists, and a placeholder that survives this conversation is a
|
|
38
|
+
person who was never there.
|
|
39
|
+
|
|
40
|
+
Follow up until each is concrete. "Our engineering docs" is not yet an
|
|
41
|
+
answer; "our leave, expense and conduct policies — the current ones, not
|
|
42
|
+
historical versions" is.
|
|
43
|
+
|
|
44
|
+
## Then STATE the defaults; do not ask them
|
|
45
|
+
|
|
46
|
+
Show these as a block, say they are defaults, and invite a correction. Do not
|
|
47
|
+
walk them one at a time — they are near-constant, and asking makes the
|
|
48
|
+
interview feel like a form.
|
|
49
|
+
|
|
50
|
+
| | default |
|
|
51
|
+
| --------- | ------------------------------------------------- |
|
|
52
|
+
| read by | people and agents both |
|
|
53
|
+
| declines | firmly — "not in this corpus" is a correct answer |
|
|
54
|
+
| audiences | one, `public` — every reader sees every document |
|
|
55
|
+
| sources | none yet — the corpus is still the samples |
|
|
56
|
+
|
|
57
|
+
Each is written only if the owner does not object, and the write-back names
|
|
58
|
+
which were answered and which were defaulted. **Never report a default as an
|
|
59
|
+
answer.** Two answered and four defaulted is an honest sentence; "all seven
|
|
60
|
+
answered" is not, and it is what happened the first time this skill ran.
|
|
61
|
+
|
|
62
|
+
**If the owner says NOT every reader sees every document**, then and only
|
|
63
|
+
then: register each audience in `.ksor/governance.yaml` under `audiences:`
|
|
64
|
+
with a one-line `description:` of who is in it — `public` is reserved and
|
|
65
|
+
never registered. There is no ranking and no default: a document lists the
|
|
66
|
+
audiences that may read it, a reader holds a list that always includes
|
|
67
|
+
`public`, and the document is visible when the two lists OVERLAP. Tell them
|
|
68
|
+
what this does and does not do: builds are made per audience, but anyone who
|
|
69
|
+
can clone the repository reads everything in it — if someone must not read a
|
|
70
|
+
document and can clone, that document belongs in a different repository.
|
|
71
|
+
|
|
72
|
+
## What the answers become
|
|
73
|
+
|
|
74
|
+
Scope and Boundary become the BODY of `instance.md`, which `ksor serve` wires
|
|
75
|
+
into the MCP server's instructions — so it is read by every agent that
|
|
76
|
+
connects, and vague prose there is vague instructions everywhere.
|
|
77
|
+
|
|
78
|
+
Authority becomes `approval_authorities` and `takedown_authorities` in
|
|
79
|
+
`.ksor/governance.yaml`. Names, not roles-in-the-abstract: the checker refuses
|
|
80
|
+
an approval or a takedown by anyone the policy does not name. An actor is
|
|
81
|
+
`human:<handle>`, `process:<name>` or `<producer>/<version>`; handles are
|
|
82
|
+
published with the record, so use the handle the owner would put in a commit,
|
|
83
|
+
never an email address.
|
|
58
84
|
|
|
59
85
|
## Then write
|
|
60
86
|
|
|
@@ -12,49 +12,75 @@ prose IS the agent surface's system prompt (`ksor serve` wires it into the MCP
|
|
|
12
12
|
server's instructions). Do not draft it from guesses — interview the owner, one
|
|
13
13
|
question at a time, and write down what they actually say.
|
|
14
14
|
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
15
|
+
## Ask THREE questions, one at a time
|
|
16
|
+
|
|
17
|
+
Seven questions is where this skill used to start, and it did not survive
|
|
18
|
+
contact: an agent running it decided five were too many, defaulted them, and
|
|
19
|
+
reported "answered: all seven" — including the one that decides who may
|
|
20
|
+
approve a document. A process the tool executing it shortcuts is too long.
|
|
21
|
+
|
|
22
|
+
So three are asked, and they are the three that cannot be defaulted:
|
|
23
|
+
|
|
24
|
+
1. **Scope** — "What should this record be the _final word_ on? Finish the
|
|
25
|
+
sentence: when someone here disagrees with this corpus, the corpus wins
|
|
26
|
+
about ___."
|
|
27
|
+
2. **Boundary** — "What is just _outside_ that — the near-miss topics people
|
|
28
|
+
will ask about here that the record should refuse rather than guess at?"
|
|
29
|
+
3. **Authority** — "Who may approve a document for publication, and who may
|
|
30
|
+
withdraw one?"
|
|
31
|
+
|
|
32
|
+
Scope and Boundary are asked because the abstention gate is meaningless
|
|
33
|
+
without an edge: a record authoritative for everything has no outside, so an
|
|
34
|
+
agent asked something the owner never wrote about reaches for its training
|
|
35
|
+
instead of declining. Authority is asked because a governance act names its
|
|
36
|
+
actor and the tool never guesses one — the scaffold ships `human:you` in
|
|
37
|
+
both authority lists, and a placeholder that survives this conversation is a
|
|
38
|
+
person who was never there.
|
|
39
|
+
|
|
40
|
+
Follow up until each is concrete. "Our engineering docs" is not yet an
|
|
41
|
+
answer; "our leave, expense and conduct policies — the current ones, not
|
|
42
|
+
historical versions" is.
|
|
43
|
+
|
|
44
|
+
## Then STATE the defaults; do not ask them
|
|
45
|
+
|
|
46
|
+
Show these as a block, say they are defaults, and invite a correction. Do not
|
|
47
|
+
walk them one at a time — they are near-constant, and asking makes the
|
|
48
|
+
interview feel like a form.
|
|
49
|
+
|
|
50
|
+
| | default |
|
|
51
|
+
| --------- | ------------------------------------------------- |
|
|
52
|
+
| read by | people and agents both |
|
|
53
|
+
| declines | firmly — "not in this corpus" is a correct answer |
|
|
54
|
+
| audiences | one, `public` — every reader sees every document |
|
|
55
|
+
| sources | none yet — the corpus is still the samples |
|
|
56
|
+
|
|
57
|
+
Each is written only if the owner does not object, and the write-back names
|
|
58
|
+
which were answered and which were defaulted. **Never report a default as an
|
|
59
|
+
answer.** Two answered and four defaulted is an honest sentence; "all seven
|
|
60
|
+
answered" is not, and it is what happened the first time this skill ran.
|
|
61
|
+
|
|
62
|
+
**If the owner says NOT every reader sees every document**, then and only
|
|
63
|
+
then: register each audience in `.ksor/governance.yaml` under `audiences:`
|
|
64
|
+
with a one-line `description:` of who is in it — `public` is reserved and
|
|
65
|
+
never registered. There is no ranking and no default: a document lists the
|
|
66
|
+
audiences that may read it, a reader holds a list that always includes
|
|
67
|
+
`public`, and the document is visible when the two lists OVERLAP. Tell them
|
|
68
|
+
what this does and does not do: builds are made per audience, but anyone who
|
|
69
|
+
can clone the repository reads everything in it — if someone must not read a
|
|
70
|
+
document and can clone, that document belongs in a different repository.
|
|
71
|
+
|
|
72
|
+
## What the answers become
|
|
73
|
+
|
|
74
|
+
Scope and Boundary become the BODY of `instance.md`, which `ksor serve` wires
|
|
75
|
+
into the MCP server's instructions — so it is read by every agent that
|
|
76
|
+
connects, and vague prose there is vague instructions everywhere.
|
|
77
|
+
|
|
78
|
+
Authority becomes `approval_authorities` and `takedown_authorities` in
|
|
79
|
+
`.ksor/governance.yaml`. Names, not roles-in-the-abstract: the checker refuses
|
|
80
|
+
an approval or a takedown by anyone the policy does not name. An actor is
|
|
81
|
+
`human:<handle>`, `process:<name>` or `<producer>/<version>`; handles are
|
|
82
|
+
published with the record, so use the handle the owner would put in a commit,
|
|
83
|
+
never an email address.
|
|
58
84
|
|
|
59
85
|
## Then write
|
|
60
86
|
|