@sporhq/spor 0.21.0 → 0.22.0

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,7 +2,7 @@
2
2
  "name": "spor",
3
3
  "displayName": "Spor Context Compiler",
4
4
  "description": "Maintains a typed, versioned knowledge graph and compiles compact briefings from it: session-start injection, per-prompt relevance digests, capture at discovery, end-of-session distillation, decision queue.",
5
- "version": "0.21.0",
5
+ "version": "0.22.0",
6
6
  "author": {
7
7
  "name": "losthammer"
8
8
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spor",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Maintains a typed, versioned knowledge graph and compiles compact briefings from it: session-start injection, per-prompt relevance digests, capture at discovery, end-of-session distillation, decision queue.",
5
5
  "author": {
6
6
  "name": "Spor",
package/API.md CHANGED
@@ -69,6 +69,21 @@ neighbor → neighbor); `render_lens` lineage lenses trace why a node exists,
69
69
  and `render_lens` with no `lens_id` returns the lens catalog (the discovery
70
70
  step before rendering).
71
71
 
72
+ **Per-viewer language register** (task-spor-viewer-register-adaptation): when
73
+ the authenticated viewer's person node carries a free-text `register:` field
74
+ (GRAPH.md "person" — role + preferred language style), the server renders it
75
+ on two channels so the host's model adapts how it explains graph content to
76
+ that user. (1) The initialize `instructions` gain a trailing **`AUDIENCE`**
77
+ section quoting the field; (2) the conversational read tools — `query_graph`,
78
+ `get_node`, `explore_graph`, `show_queue` — prepend one line to their TEXT
79
+ content: `Audience note — how to communicate with this user: <register>`.
80
+ Both channels because host support for instructions is uneven. The preamble
81
+ is presentation-only: `structuredContent` is never touched, `isError` results
82
+ are exempt, and content is never filtered or reordered by it. The field is
83
+ capped at 500 chars on render; agent-scoped identities (dispatch tokens) get
84
+ neither channel — the register describes the human reader. Absent the field,
85
+ both channels are byte-identical to before.
86
+
72
87
  ### `query_graph`
73
88
 
74
89
  The compiler over the wire. Input:
package/GRAPH.md CHANGED
@@ -640,6 +640,8 @@ email: losthammer@gmail.com
640
640
  github: losthammer
641
641
  roles: [reviewer, maintainer]
642
642
  queue_mute: [some-noisy-project, task-noisy-job@2026-07-01]
643
+ register: Non-technical founder. Plain everyday language, no graph jargon;
644
+ use node titles, never raw ids. Analogies over precision.
643
645
  date: 2026-06-10
644
646
  edges:
645
647
  - {type: stewards, to: norm-cc-registry-is-contract}
@@ -653,6 +655,14 @@ edges:
653
655
  (issue-cc-identity-email-mutable-primary-key). The token's `{name, email}`
654
656
  attribution is read from the bound node, never from a caller parameter
655
657
  (dec-viewer-token-binding, dec-cc-attribution-from-token).
658
+ - **`register` is the language-register field** (free-text folded scalar): the
659
+ reader's role and preferred language style. Viewer-facing surfaces (the
660
+ server's MCP instructions block and the conversational read tools' `Audience
661
+ note` preamble) render it verbatim so the model adapts how it talks about
662
+ graph content to this person — a non-technical user gets plain language
663
+ instead of node-type jargon (task-spor-viewer-register-adaptation).
664
+ Presentation only: it never changes what is returned. Settable from chat by
665
+ updating your own person node.
656
666
  - **`stewards` edges are the routing key.** A `person → node` `stewards` edge
657
667
  declares ownership of an area, spec, or norm. When a question can't be
658
668
  answered from the graph and is filed (`ask_question` / `POST /v1/questions`),
@@ -2,7 +2,7 @@
2
2
  id: schema-person
3
3
  type: schema
4
4
  kind: node-schema
5
- schema_version: 2026.06.23.1
5
+ schema_version: 2026.07.14.1
6
6
  title: Seed schema for person nodes
7
7
  summary: Node schema for the person type — a member of the org, with a mutable display name plus the identity anchor for $viewer binding and Tier-2 question routing. Seed-pack default; a graph-resident schema node for this type overrides it.
8
8
  date: 2026-06-10
@@ -41,6 +41,25 @@ node may reach a resolving/done state. Declarative data only — absent it, a
41
41
  person holds no roles and the field has no effect, so this register is purely
42
42
  additive (existing person nodes are unchanged).
43
43
 
44
+ `register` (2026.07.14.1) is the person node's language-register field (folded
45
+ scalar, free-text prose): how to communicate with this user — their role and
46
+ preferred language style, e.g. `register: Non-technical founder. Plain
47
+ everyday language, no graph jargon; use node titles, never raw ids.` Consumers
48
+ that render graph content *to* this person (the server's MCP instructions
49
+ block and conversational tool-result preambles; API.md §2) surface it verbatim
50
+ so the model adapts its language to the reader
51
+ (task-spor-viewer-register-adaptation). Free text on purpose — the model
52
+ follows prose directly, so no enum→instruction translation table exists to
53
+ drift. When setting it on a user's behalf, don't transcribe a vague
54
+ preference ("keep it simple") — interview briefly, compose 2–4 directive
55
+ sentences a model can act on (vocabulary level, node titles vs raw ids,
56
+ analogies vs precision, detail depth), and confirm the draft with the user
57
+ before writing. Per-viewer presentation only, read via the same `$viewer` binding as
58
+ `queue_mute`; it never changes what content is returned, only how the
59
+ assistant is told to talk about it. Declarative data only — absent it, nothing
60
+ is injected and the field has no effect, so this register is purely additive
61
+ (existing person nodes are unchanged).
62
+
44
63
  `github` (2026.06.21.1) is the person node's GitHub-handle register (flat inline
45
64
  scalar): `github: octocat`. It is the login→person key the Spor server's GitHub
46
65
  review reflection maps by: when a GitHub review or merge is reflected into the
@@ -77,6 +96,10 @@ register is purely additive (existing person nodes are unchanged).
77
96
  "kind": "inline-list",
78
97
  "description": "role-list register consumed by policy quorum gates"
79
98
  },
99
+ "register": {
100
+ "kind": "scalar",
101
+ "description": "free-text language register — the reader's role and preferred language style, rendered to the model on viewer-facing surfaces"
102
+ },
80
103
  "github": {
81
104
  "kind": "scalar",
82
105
  "aliases": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sporhq/spor",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Spor — a shared memory substrate for teams and agents. Decisions, their reasons, and the traces they leave. Knowledge-graph context compiler: session-start briefings, per-prompt digests, capture at discovery, end-of-session distillation, decision queue.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Anthony Allen",
@@ -66,20 +66,43 @@ attribute to you and your queue and question-routing work.
66
66
  hand it over; the user then re-runs step 1 with it. Don't paper over it — silent
67
67
  identity degradation is exactly the failure this check exists to catch
68
68
  (issue-cc-onboarding-email-mismatch-silent-degradation).
69
- 4. **Enable this repo.** `spor enable` writes `.spor.json {enabled: true}` so the
69
+ 4. **Ask how assistants should talk to them the `register` field.** First
70
+ check `spor get <person-id>` — if the node already carries a `register:`,
71
+ this step is done (mention it exists and move on; don't re-interview a
72
+ returning user). Otherwise interview briefly, then **draft the field
73
+ yourself — never transcribe the user's first answer**. People
74
+ under-specify this in the moment ("just keep it simple" encodes nothing a
75
+ model can act on), so extract the substance: what's their role, how
76
+ technical are they, and what does a useful explanation look like to them —
77
+ asking for an example of an explanation they liked or hated works well.
78
+ From that, compose 2–4 directive sentences a model can follow mechanically
79
+ (vocabulary level, node titles vs raw ids, analogies vs precision, detail
80
+ depth — e.g. `register: Non-technical founder. Plain everyday language, no
81
+ graph jargon; use node titles, never raw ids. Analogies over precision.`),
82
+ read the draft back for approval, and write the approved version to their
83
+ person node (GRAPH.md "person"): `spor get <person-id> --json` for the
84
+ revision, add the field, then
85
+ `spor put-node - --if-exists update --revision <sha>`. The server renders it
86
+ to every graph-reading assistant (MCP instructions + an Audience note on
87
+ reads), so a non-technical user gets answers they can actually use — for
88
+ them this is the highest-value step here
89
+ (task-spor-viewer-register-adaptation). Presentation only, editable any time
90
+ by updating their person node; a technical user happy with the default
91
+ needs no field — skip without ceremony.
92
+ 5. **Enable this repo.** `spor enable` writes `.spor.json {enabled: true}` so the
70
93
  plugin actually runs here — without a marker every hook no-ops (the opt-in
71
94
  default), even in remote mode. Commit the file to share the setting. If the
72
95
  inferred project slug is wrong, `spor link <slug>` writes a `.spor` marker.
73
- 5. **(Optional) a dispatch identity**, if the user will run background agents.
96
+ 6. **(Optional) a dispatch identity**, if the user will run background agents.
74
97
  Two explicit steps: `spor agent create <label>` writes the agent node owned by
75
98
  your person, then `spor agent use <agent-id>` makes it **this machine's**
76
99
  default — that's what turns on session-start capability auto-publish and the
77
100
  liveness heartbeat. Creating does not activate; both are needed. Use the full
78
101
  `agent-<slug>` id from `spor agent list`, not the bare label.
79
- 6. **State the data reality correctly.** In remote mode your captures and
102
+ 7. **State the data reality correctly.** In remote mode your captures and
80
103
  distilled nodes land in the **shared team graph on the server** — visible to
81
104
  teammates and attributed to you. It is *not* local-only.
82
- 7. **Hand off to populate the repo:** `/spor:backfill` (mine history, group
105
+ 8. **Hand off to populate the repo:** `/spor:backfill` (mine history, group
83
106
  repos). Tracker/MCP consent happens there — see step 6 of the local branch,
84
107
  which applies equally.
85
108
 
@@ -166,8 +166,9 @@ token — the node reads "agent on behalf of person"). Other
166
166
  type-specific fields exist (`wake:` dormancy date; `commits:` linked git shas;
167
167
  `pin:`/`exclude:` on corrections; `slugs:`/`fingerprints:`/`tags:` on repo nodes;
168
168
  `applies_to_tags:`/`applies_to_repos:`/`applies_to_projects:` ride-along
169
- selectors on norms; `roles:`/`queue_mute:` on person nodes) see GRAPH.md for
170
- the complete list.
169
+ selectors on norms; `roles:`/`queue_mute:`/`register:` on person nodes, `register` being the
170
+ free-text "how to talk to this reader" language-style field viewer-facing
171
+ surfaces render verbatim) — see GRAPH.md for the complete list.
171
172
 
172
173
  Validate any local node you write: `spor validate` (or
173
174
  `node lib/validate.js`), and fix what it flags.
@@ -237,6 +237,17 @@ item(s) to spend it on; don't sweep the whole backlog unprompted. Skip an item
237
237
  that's needs-human only because it's someone's assigned work (`assigned →
238
238
  person`) — there is no gap to close there.
239
239
 
240
+ **Entering this pass, proposing candidates is mandatory — never wait for the
241
+ human to name items** (issue-spor-triage-make-ready-pass-never-triggers: the
242
+ first live run skipped the whole pass because nothing solicited a pick). Pull
243
+ the untriaged and needs-human slices (`spor next --readiness untriaged`,
244
+ `--readiness human`, or the `counts_by_readiness` lead you already have from
245
+ pass 1), present the top ~5 as make-ready candidates — one line each: the item
246
+ and the gap you can already see from its why-line/reasons — and ask which to
247
+ work, recommending the highest-ranked unblockers. Picking stays the human's;
248
+ skipping the proposal is not an option unless both buckets are empty (then say
249
+ so in the outcome).
250
+
240
251
  For each chosen item:
241
252
 
242
253
  - **Brief it** — `spor brief <id>` (or `query_graph root_id=<id>`) — pulling