skynet-graph 1.2.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.
Files changed (213) hide show
  1. package/CONTRIBUTING.md +22 -0
  2. package/LICENSE +661 -0
  3. package/README.md +245 -0
  4. package/bin/sg +20 -0
  5. package/concepts/README.md +23 -0
  6. package/concepts/_substrate/Claim/Confidence/Trusted.json +6 -0
  7. package/concepts/_substrate/Claim/Confidence.json +10 -0
  8. package/concepts/_substrate/Claim/Freshness/Stale.json +7 -0
  9. package/concepts/_substrate/Claim/Freshness.json +5 -0
  10. package/concepts/_substrate/Claim/Verification/Refuted.json +6 -0
  11. package/concepts/_substrate/Claim/Verification.json +6 -0
  12. package/concepts/_substrate/Claim.json +4 -0
  13. package/concepts/_substrate/Frontier/InBeam.json +6 -0
  14. package/concepts/_substrate/Frontier/Stuck.json +6 -0
  15. package/concepts/_substrate/Frontier.json +5 -0
  16. package/concepts/_substrate/Intake/ToTask.json +22 -0
  17. package/concepts/_substrate/Intake/Typed.json +10 -0
  18. package/concepts/_substrate/Intake.json +27 -0
  19. package/concepts/_substrate/Task/Answer.json +12 -0
  20. package/concepts/_substrate/Task/Complexity/Atomic.json +5 -0
  21. package/concepts/_substrate/Task/Complexity/Compound/Expansion.json +7 -0
  22. package/concepts/_substrate/Task/Complexity/Compound.json +6 -0
  23. package/concepts/_substrate/Task/Complexity.json +6 -0
  24. package/concepts/_substrate/Task/EvalComplexity.json +13 -0
  25. package/concepts/_substrate/Task/ReportUp.json +6 -0
  26. package/concepts/_substrate/Task/Rollup.json +10 -0
  27. package/concepts/_substrate/Task.json +5 -0
  28. package/concepts/clinical/Diagnosis/Medication.json +6 -0
  29. package/concepts/clinical/Diagnosis.json +15 -0
  30. package/concepts/clinical/Observation/LabValue/OutOfRange.json +6 -0
  31. package/concepts/clinical/Observation/LabValue.json +5 -0
  32. package/concepts/clinical/Observation.json +6 -0
  33. package/concepts/common/Document/pathBasket.json +6 -0
  34. package/concepts/common/Document.json +3 -0
  35. package/concepts/common/Edge/Distance.json +13 -0
  36. package/concepts/common/Edge/Stay/LongStay.json +8 -0
  37. package/concepts/common/Edge/Stay.json +8 -0
  38. package/concepts/common/Edge/Travel/LongTravel.json +16 -0
  39. package/concepts/common/Edge/Travel/ShortTravel.json +11 -0
  40. package/concepts/common/Edge/Travel/targetNode.json +7 -0
  41. package/concepts/common/Edge/Travel.json +7 -0
  42. package/concepts/common/Edge.json +3 -0
  43. package/concepts/common/Vertice.json +3 -0
  44. package/concepts/supply/Fulfillment.json +10 -0
  45. package/concepts/supply/Inventory/Reorder.json +7 -0
  46. package/concepts/supply/Inventory.json +5 -0
  47. package/concepts/supply/Procurement/SupplierConfirm.json +6 -0
  48. package/concepts/supply/Procurement.json +8 -0
  49. package/concepts/supply/Transport.json +5 -0
  50. package/doc/API.md +556 -0
  51. package/doc/CAPABILITIES.md +373 -0
  52. package/doc/MODELISATION.md +511 -0
  53. package/doc/architecture.md +267 -0
  54. package/doc/concept-as-graph.md +379 -0
  55. package/doc/concept-learning.md +168 -0
  56. package/doc/creative-loop-map.md +202 -0
  57. package/doc/original-2016-doc.md +148 -0
  58. package/doc/usage.md +501 -0
  59. package/lib/authoring/abstract.js +401 -0
  60. package/lib/authoring/abstraction.js +190 -0
  61. package/lib/authoring/adapt.js +393 -0
  62. package/lib/authoring/ancestry.js +216 -0
  63. package/lib/authoring/author.js +147 -0
  64. package/lib/authoring/bounded-merge.js +57 -0
  65. package/lib/authoring/canon.js +158 -0
  66. package/lib/authoring/clock.js +123 -0
  67. package/lib/authoring/combinator.js +92 -0
  68. package/lib/authoring/compete.js +76 -0
  69. package/lib/authoring/compose-hotspot.js +314 -0
  70. package/lib/authoring/compress.js +279 -0
  71. package/lib/authoring/concept-net.js +254 -0
  72. package/lib/authoring/concepts.js +66 -0
  73. package/lib/authoring/context-project.js +277 -0
  74. package/lib/authoring/contract.js +476 -0
  75. package/lib/authoring/corpus-pack.js +125 -0
  76. package/lib/authoring/cost-probe.js +86 -0
  77. package/lib/authoring/crystallize.js +555 -0
  78. package/lib/authoring/dag-decompose.js +256 -0
  79. package/lib/authoring/dataset-adapter.js +253 -0
  80. package/lib/authoring/debug-provider.js +92 -0
  81. package/lib/authoring/decompose.js +343 -0
  82. package/lib/authoring/emittability.js +236 -0
  83. package/lib/authoring/equilibrium.js +160 -0
  84. package/lib/authoring/extract.js +153 -0
  85. package/lib/authoring/forest.js +55 -0
  86. package/lib/authoring/forge-fallback.js +116 -0
  87. package/lib/authoring/givens.js +121 -0
  88. package/lib/authoring/glossary.js +177 -0
  89. package/lib/authoring/grammar-graph.js +191 -0
  90. package/lib/authoring/granularity.js +80 -0
  91. package/lib/authoring/graph-net.js +108 -0
  92. package/lib/authoring/ground.js +148 -0
  93. package/lib/authoring/higher-order.js +85 -0
  94. package/lib/authoring/hotspot.js +132 -0
  95. package/lib/authoring/hysteresis.js +85 -0
  96. package/lib/authoring/index.js +106 -0
  97. package/lib/authoring/lattice-morphism.js +61 -0
  98. package/lib/authoring/lattice-pack.js +148 -0
  99. package/lib/authoring/leaf-io.js +77 -0
  100. package/lib/authoring/library.js +156 -0
  101. package/lib/authoring/lifecycle.js +92 -0
  102. package/lib/authoring/loop.js +193 -0
  103. package/lib/authoring/master-loop.js +132 -0
  104. package/lib/authoring/mdl.js +209 -0
  105. package/lib/authoring/memo-stability.js +122 -0
  106. package/lib/authoring/method-explorer.js +138 -0
  107. package/lib/authoring/method-pack.js +181 -0
  108. package/lib/authoring/method.js +202 -0
  109. package/lib/authoring/mine.js +510 -0
  110. package/lib/authoring/mount.js +119 -0
  111. package/lib/authoring/negotiate.js +100 -0
  112. package/lib/authoring/parametric.js +139 -0
  113. package/lib/authoring/reaggregate.js +75 -0
  114. package/lib/authoring/rebalance.js +157 -0
  115. package/lib/authoring/recall.js +135 -0
  116. package/lib/authoring/registry.js +350 -0
  117. package/lib/authoring/relearn.js +147 -0
  118. package/lib/authoring/retention.js +89 -0
  119. package/lib/authoring/segment-proxy.js +114 -0
  120. package/lib/authoring/serve-leaf.js +64 -0
  121. package/lib/authoring/slot-aware-serve.js +77 -0
  122. package/lib/authoring/sound-invoke.js +59 -0
  123. package/lib/authoring/split-serve.js +74 -0
  124. package/lib/authoring/ste.js +239 -0
  125. package/lib/authoring/stock.js +101 -0
  126. package/lib/authoring/store.js +94 -0
  127. package/lib/authoring/supervise.js +138 -0
  128. package/lib/authoring/support.js +131 -0
  129. package/lib/authoring/task-mirror.js +51 -0
  130. package/lib/authoring/typed-loop.js +160 -0
  131. package/lib/authoring/validate.js +569 -0
  132. package/lib/authoring/widen.js +88 -0
  133. package/lib/combos/appliance.js +189 -0
  134. package/lib/combos/critique.js +377 -0
  135. package/lib/combos/defaults.js +86 -0
  136. package/lib/combos/durable-runner.js +115 -0
  137. package/lib/combos/forge.js +209 -0
  138. package/lib/combos/index.js +86 -0
  139. package/lib/combos/learning-library.js +253 -0
  140. package/lib/combos/mixture-serve.js +193 -0
  141. package/lib/combos/plan-loop.js +192 -0
  142. package/lib/combos/proxy-cache.js +272 -0
  143. package/lib/combos/self-mod.js +94 -0
  144. package/lib/durable/audit.js +102 -0
  145. package/lib/durable/checkpoint-store.js +550 -0
  146. package/lib/durable/fold.js +62 -0
  147. package/lib/durable/interpreter.js +242 -0
  148. package/lib/durable/xlate.js +185 -0
  149. package/lib/graph/Graph.js +2486 -0
  150. package/lib/graph/expr.js +307 -0
  151. package/lib/graph/index.js +26 -0
  152. package/lib/graph/log.js +134 -0
  153. package/lib/graph/objects/Concept.js +382 -0
  154. package/lib/graph/objects/Entity.js +503 -0
  155. package/lib/graph/objects/Node.js +57 -0
  156. package/lib/graph/objects/PathMap.js +557 -0
  157. package/lib/graph/objects/Segment.js +100 -0
  158. package/lib/graph/tasks/stabilize.js +59 -0
  159. package/lib/graph/tasks/taskflow.js +247 -0
  160. package/lib/index.js +122 -0
  161. package/lib/load.js +132 -0
  162. package/lib/providers/backends.js +117 -0
  163. package/lib/providers/borderline.js +129 -0
  164. package/lib/providers/cache.js +226 -0
  165. package/lib/providers/canonicalize.js +198 -0
  166. package/lib/providers/constat.js +107 -0
  167. package/lib/providers/geo.js +53 -0
  168. package/lib/providers/index.js +116 -0
  169. package/lib/providers/intake.js +263 -0
  170. package/lib/providers/llm-local.js +88 -0
  171. package/lib/providers/llm.js +236 -0
  172. package/lib/providers/local-host.js +197 -0
  173. package/lib/providers/merge-consistency.js +162 -0
  174. package/lib/providers/nogood.js +149 -0
  175. package/lib/providers/reason-loop.js +223 -0
  176. package/lib/providers/semiring.js +285 -0
  177. package/lib/providers/solver-fork.js +163 -0
  178. package/lib/providers/stats.js +228 -0
  179. package/lib/providers/verify.js +120 -0
  180. package/lib/runtime/index.js +135 -0
  181. package/lib/runtime/invoke-pool.js +92 -0
  182. package/lib/runtime/protocol.js +210 -0
  183. package/lib/runtime/transport-socket.js +77 -0
  184. package/lib/runtime/worker-entry.js +31 -0
  185. package/lib/sg/cli.js +601 -0
  186. package/lib/sg/log-sinks.js +214 -0
  187. package/lib/sg/mcp.js +395 -0
  188. package/lib/sg/proxy-run.js +66 -0
  189. package/lib/sg/serve-demo.js +185 -0
  190. package/lib/sg/serve.js +205 -0
  191. package/lib/sg/trace.js +118 -0
  192. package/lib/studio/protocol.js +45 -0
  193. package/lib/studio/public/app.js +310 -0
  194. package/lib/studio/public/components/ConceptEditor.js +43 -0
  195. package/lib/studio/public/components/ConceptTree.js +43 -0
  196. package/lib/studio/public/components/CorpusPanel.js +68 -0
  197. package/lib/studio/public/components/ForkTree.js +36 -0
  198. package/lib/studio/public/components/GrammarGraph.js +99 -0
  199. package/lib/studio/public/components/GraphCanvas.js +156 -0
  200. package/lib/studio/public/components/Inspector.js +48 -0
  201. package/lib/studio/public/components/LearningPanel.js +85 -0
  202. package/lib/studio/public/components/PromptConsole.js +46 -0
  203. package/lib/studio/public/components/ProviderTrace.js +39 -0
  204. package/lib/studio/public/components/SessionSplit.js +47 -0
  205. package/lib/studio/public/components/TilingOverlay.js +40 -0
  206. package/lib/studio/public/components/Timeline.js +57 -0
  207. package/lib/studio/public/index.html +26 -0
  208. package/lib/studio/public/styles.css +185 -0
  209. package/lib/studio/public/ws.js +58 -0
  210. package/lib/studio/server.js +130 -0
  211. package/lib/studio/session.js +397 -0
  212. package/lib/studio/studio.js +149 -0
  213. package/package.json +42 -0
package/doc/usage.md ADDED
@@ -0,0 +1,501 @@
1
+ # Usage guide (Use 1 — the substrate)
2
+
3
+ > **R&D library.** Pure CommonJS, runs natively on Node 18+ — **no build step**. For the
4
+ > model see [architecture.md](architecture.md); for the concept schema see [original-2016-doc.md](original-2016-doc.md);
5
+ > for the full API surface see [API.md](API.md). The **concept-organization strategy is
6
+ > still WIP** — treat `concepts/common/` as an example, not a recommended ontology.
7
+
8
+ > **Scope of this guide — Use 1, the substrate, standalone.** §1–§9 below cover the foundational use:
9
+ > **authoring a concept grammar by hand** to model and enrich a domain, with deterministic
10
+ > providers and **no LLM required** (the geo `Distance` rule in §2/§3 is a complete worked
11
+ > example). This use stands on its own. The LLM-driven **Use 2** target system — concept-graphs as
12
+ > composable methods, forged / crystallized / reused on top, with a durable executor and a contract —
13
+ > is layered over exactly this substrate (**[concept-as-graph.md](concept-as-graph.md)**); it is
14
+ > additive, never a prerequisite for the above.
15
+
16
+ ## 1. Install & load
17
+
18
+ ```bash
19
+ npm install # deps only; no compile
20
+ npm test # 1350 tests — 0 failures, 2 known skips (node --test)
21
+ ```
22
+
23
+ ```js
24
+ const Graph = require('skynet-graph'); // the Graph constructor, with statics attached
25
+ ```
26
+
27
+ The engine core (`lib/graph`) is filesystem-free. The package facade (`lib/index.js`)
28
+ adds the standalone helpers below as statics on `Graph`.
29
+
30
+ ## 2. Boot from directories (the easy path)
31
+
32
+ `Graph.fromDirs` loads concept sets + providers from plain folders, registers them, and
33
+ returns a stabilizing graph.
34
+
35
+ ```js
36
+ const g = Graph.fromDirs({
37
+ concepts : './concepts', // dir of set sub-dirs, or a single set dir (auto-detected)
38
+ providers: './my-providers', // dir of provider modules (optional)
39
+ builtins : true, // also wire the packaged Geo + default LLM providers
40
+ seed : { conceptMaps: [ // initial objects (or a path to a JSON snapshot)
41
+ { _id: 'a', Node: true, Position: { lat: 48.85, lng: 2.35 } },
42
+ { _id: 'b', Node: true, Position: { lat: 1.35, lng: 103.8 } },
43
+ { _id: 's', Segment: true, originNode: 'a', targetNode: 'b' }
44
+ ]},
45
+ conf: {
46
+ onStabilize(graph) {
47
+ const objs = JSON.parse(graph.serialize().graph).conceptMaps;
48
+ // ... read stabilized facts; e.g. the segment now has Distance {inKm: 10728}
49
+ }
50
+ }
51
+ });
52
+ ```
53
+
54
+ `conf.conceptSets` defaults to every set found under `concepts`. Options: `concepts`,
55
+ `providers`, `providerCtx` (passed to provider factory modules), `builtins`, `seed`,
56
+ `conf`, or a pre-built `conceptMap`.
57
+
58
+ ### The low-level constructor
59
+
60
+ `fromDirs` is sugar over `new Graph(record, conf, conceptMap)`:
61
+
62
+ ```js
63
+ const { buildConceptTree } = Graph.authoring.concepts; // barrel; or require('skynet-graph/lib/authoring/concepts')
64
+ const conceptMap = { common: buildConceptTree('./concepts/common') };
65
+ Graph.register([{ CommonGeo: Graph.providers.CommonGeo }]); // wire providers
66
+ const g = new Graph(seed, { conceptSets: ['common'], autoMount: true }, conceptMap);
67
+ ```
68
+
69
+ > **Authoring toolkit.** `Graph.authoring` namespaces the R&D/authoring tools (parity with `Graph.providers`),
70
+ > so you reach them without deep paths — e.g. `Graph.authoring.concepts.buildConceptTree`, `.validate`,
71
+ > `.contract`, `.method`, `.abstract`, `.crystallize`, `.library` / `.combinator` / `.adapt` (the creative loop:
72
+ > dispatch → mount → **adapt-or-forge** → **antiUnify content-forge** → **blend** = combinational synthesis of a
73
+ > novel composite method, with a bounded `synthesizeByBlend`). The plan-loop bricks live there too:
74
+ > `dag-decompose` (the typed cutter prompt + archetype router), `context-project` (the bounded projection;
75
+ > `stratComplete` = the stratified CONTEXT/DONE/ROADMAP rendering), `givens` (the typed base-fact front door)
76
+ > and `leaf-io` (typed leaf output or a typed refusal). Each module also stays importable on its own
77
+ > (`require('skynet-graph/lib/authoring/<module>')`); the barrel is a convenience, not a gate. A runnable, offline
78
+ > end-to-end tour of the creative loop is `examples/creative-loop.js` (`node examples/creative-loop.js`); the
79
+ > example map is `examples/README.md`.
80
+
81
+ ## 3. Concept sets
82
+
83
+ A **set** is a directory of `*.json` concept files; sub-directories specialize a concept
84
+ via `childConcepts` (the dir name = the parent's child key). Engine invariants the loader
85
+ honors: a child's key **must** equal its `_id`; `_id` is globally unique; `_name` is the
86
+ flag written on entities (defaults to the file basename).
87
+
88
+ ```
89
+ concepts/common/
90
+ Vertice.json # entry for nodes
91
+ Edge.json # entry for segments
92
+ Edge/Distance.json # specializes Edge: require both Positions -> CommonGeo::Distance
93
+ Edge/Travel/... # deeper specializations
94
+ ```
95
+
96
+ `Graph.loadConceptMap('./concepts')` auto-detects: a dir with top-level `*.json` is a
97
+ single set (named by its basename); otherwise each immediate sub-dir holding `*.json` is a
98
+ set. See [original-2016-doc.md](original-2016-doc.md) for every schema field.
99
+
100
+ > **Typed-fact discipline (do not break it).** A `require`/`assert`/`ensure` must key only
101
+ > on **discrete, typed** facts (enums, ids, numbers, booleans) — never on free-text prose,
102
+ > or the memo never hits. An `LLM::complete` concept writes canonicalized keys as tracked
103
+ > facts and the reply text on an *untracked* `prose` key. `lib/authoring/validate.js`
104
+ > enforces this at author time.
105
+
106
+ ## 4. Providers
107
+
108
+ Providers do effectful work; the engine never auto-wires them (host opt-in). A provider fn
109
+ is `(graph, concept, scope, argz, cb)` calling `cb(err, mutationTemplate)`.
110
+
111
+ ```js
112
+ const { register, CommonGeo, createLLMProvider } = require('skynet-graph/lib/providers');
113
+ register(Graph, [
114
+ { CommonGeo }, // packaged great-circle distance
115
+ createLLMProvider({ ask: myModelBackend }) // backend-agnostic LLM::complete
116
+ ]);
117
+ ```
118
+
119
+ **Load from a directory.** A provider module exports a fragment `{ Namespace: { fn } }`, or
120
+ `{ default: fragment }`, or a **factory** `(ctx) => fragment` so it can self-configure from
121
+ `ctx` (e.g. an `ask` backend or env):
122
+
123
+ ```js
124
+ // my-providers/remote.js
125
+ module.exports = (ctx) => ({
126
+ Remote: { work(graph, concept, scope, argz, cb) {
127
+ Promise.resolve(ctx.ask({ q: 'work' })).then(r => cb(null, { $_id: '_parent', Remote: true, work: r }));
128
+ } }
129
+ });
130
+ ```
131
+
132
+ ```js
133
+ Graph.register(Graph.loadProviders('./my-providers', { ask: myModelBackend }));
134
+ ```
135
+
136
+ ## 5. Mutations & lifecycle
137
+
138
+ ```js
139
+ g.pushMutation(template, targetId); // create/update objects, mark unstable
140
+ ```
141
+
142
+ Key rules (hard-won):
143
+
144
+ - **A concept must self-flag** with its own `_name` (e.g. write `Distance: true` /
145
+ `{$_id:'_parent', <Name>: true}`) or it re-fires forever.
146
+ - **`$$_id` updates** an existing object (literal id); a plain `_id` creates a new one.
147
+ - **Arrays replace on update** — for race-free fan-in use the `{__push: x}` primitive.
148
+ - **Global node refs need double-`$`**: `$$clock:tick`, `$$budget:spent.length`.
149
+ - **`assert` vs `ensure`:** completion-gating / reactive re-test → `ensure`; budget /
150
+ "don't undo work already done" → `assert`.
151
+ - **`onStabilize` is a settle-hook** — it fires only after something actually wrote and the
152
+ graph then settled; a no-op never settles.
153
+
154
+ ## 6. History, fork, rollback, patch
155
+
156
+ ```js
157
+ g.getRevisions(); // revision list
158
+ g.getSnapshot(rev); // serialized state at rev
159
+ g.diffRevisions(a, b); // structural diff
160
+ g.rollbackTo(rev); // restore data AND rules to rev (defers if mid-stabilize)
161
+
162
+ const child = g.fork(seed, { reintegrateInto: targetId, project }); // sub-agent sub-graph
163
+ g.merge(child, targetId, project); // bring results back
164
+
165
+ g.patchConcept(nameOrId, updates); // hot-patch an expert + re-evaluate the frontier
166
+ g.addConcept(parentNameOrId, schema); // author a new expert live
167
+ g.getConceptByName(name);
168
+ ```
169
+
170
+ See [API.md](API.md) for exact signatures and semantics.
171
+
172
+ ## 7. The `sg` CLI
173
+
174
+ ```bash
175
+ # the FORGE — dataset + executable oracle → certified .sgc method stock behind the zero-false-admission
176
+ # gate, with a sha256 validation dossier (the fuel of F1):
177
+ node bin/sg forge --adapter <adapter.js> --data <dir> --model <path.gguf> --out stock.sgc --dossier out/
178
+
179
+ sg proxy # C6 one-shot/batch over the proxy cache sg methods # explore a stock's method classes
180
+ sg validate # author-time grammar pre-flight on a concept dir (structure, not grammar)
181
+ ```
182
+
183
+ ```bash
184
+ # boot a graph from folders and print the stabilized facts. A runnable seed ships in the repo
185
+ # (the Paris→Singapore/Versailles travel graph, the same one examples/run-basic.js builds inline):
186
+ node bin/sg run --concepts ./concepts/common --builtins --seed examples/seed-travel.json
187
+ # -> stabilized: 5 object(s); long -> Distance/Travel/LongTravel, short -> Distance.inKm=18/ShortTravel
188
+
189
+ # the general form:
190
+ node bin/sg run --concepts ./concepts --builtins --seed <file.json> [--sets common]
191
+ [--providers ./my-providers] [--trace out.json] [--json] [--timeout 8000]
192
+
193
+ # inspect a trace artifact (written by --trace, or by lib/sg/trace.js):
194
+ node bin/sg trace out.json # list every concept-apply (rev, concept, target, ms)
195
+ node bin/sg show out.json 3 # full detail of record 3 (prompt / reply / patch / why)
196
+ node bin/sg concepts out.json # per-concept rollup (count + total ms), heaviest first
197
+ node bin/sg errors out.json # applies whose patch flagged an llmError
198
+ ```
199
+
200
+ ### Logging
201
+
202
+ Both graph-running commands — `sg run` and `sg studio` — print the boot banner and stream the
203
+ engine's logs. Both default to the **dashboard** on a TTY (a fixed bottom status bar over scrolling
204
+ colored logs — stats live only in the bar) and fall back to **plain / log-only** off a TTY or with
205
+ `--log-plain` (no bar; the stats are emitted as periodic log lines instead). For `sg studio` the bar
206
+ reflects the **active session's** graph (root, a fork, or the selected session). The
207
+ `trace`/`show`/`concepts`/`errors` commands only inspect a saved artifact — there is no live graph, so
208
+ they print their data directly with no engine logs. `sg studio` also accepts `--log-level`/`--log-file`.
209
+
210
+ `sg run` takes the full set of logging flags:
211
+
212
+ ```bash
213
+ node bin/sg run --concepts ./concepts --builtins \
214
+ --log-level info # error|warn|log|info|verbose (default info)
215
+ --log-mode dashboard # dashboard | plain (default: dashboard on a TTY, else plain)
216
+ --log-file run.jsonl # journal (.jsonl = machine-readable, else formatted text)
217
+ --log-file-level verbose # separate level for the file (default verbose)
218
+ ```
219
+
220
+ A styled banner (`SKYNET·GRAPH v<version>`) prints at boot.
221
+
222
+ - **dashboard** — on a TTY: normal **colored logs scroll** as usual, with a live **status bar pinned at
223
+ the bottom** showing the graph state (`stable`/`stabilizing`), the unstable node/segment counts, the
224
+ main-loop queue size, current rev, applies, provider time and elapsed. Degrades to plain off a TTY.
225
+ - **plain** (`--log-plain`) — one clean line per record, no cursor control; logs go to **stderr** so the
226
+ stabilized-facts summary on **stdout** stays pipeable.
227
+
228
+ Programmatically, every graph exposes `graph.logger` (`addSink`/`tail(n, {concept|applyId})`/`setLevel`);
229
+ providers log with context via `scope.log` / `concept.log(scope)`. See `doc/API.md` → *Logging & diagnostics*.
230
+
231
+ With `package.json` `bin`, this is also available as `sg …` once installed.
232
+
233
+ ### The Studio (`sg studio`) — the web inspector & console
234
+
235
+ A browser front-end for the engine: a registry of live `Graph` sessions (a root + a tree of
236
+ forks) over WebSocket, with a no-build React UI.
237
+
238
+ ```bash
239
+ node bin/sg studio [--root <dir>] [--port 4848] [--open] [--log-level <lvl>] [--log-file <path>]
240
+ # corpora are auto-discovered under --root (default cwd); the prompt console uses LLM_BASE if set
241
+ ```
242
+
243
+ It visualizes and drives the full V1 API: the **graph canvas** (cast-concept flags on each edge,
244
+ a pulse on the target of the most recent `conceptApply`), the **concept tree** + a live **editor**
245
+ (edit → validate → patch), the **fork tree** (fork / switch / merge), the **revision timeline**
246
+ (rollback / diff), and a **prompt console** (the decompose → synthesize loop). The
247
+ `forkPlan` op exposes the tree-decomposition **tiling** (separators + tiles + frontier alphabets)
248
+ of the active corpus. The engine core stays fs-free — all fs/serving lives in `lib/studio`.
249
+
250
+ #### Grammar workbench & corpus exchange
251
+
252
+ A **data / grammar** view toggle in the toolbar switches the centre canvas between the *instance*
253
+ graph (the running objects, above) and the **grammar graph** — the second, orthogonal view of a
254
+ corpus: its **concepts ↔ facts** flux graph. A concept *writes* facts (green edges = self-flag +
255
+ `applyMutations` keys) and *reads* them (blue = positive support, **red dashed = a negated /
256
+ defeasance dependency**); separator facts (the narrow waist) are gold diamonds, external **entry
257
+ points** are hollow, and concepts are coloured by their set. The side panel surfaces the derived
258
+ **manifest** (the produces/consumes alphabet, the required providers), the **cross-corpus links**
259
+ (a fact one set produces and another consumes) and any silent **fact collisions** (a fact two sets
260
+ both write — the `leadTime` trap). This is the view for perfecting *grammars and their interactions*.
261
+
262
+ - **Corpus exchange (`.sgc`)** — *export .sgc* packs the live corpus (reflecting runtime
263
+ add/patchConcept edits) into a portable single-file bundle `{ manifest, conceptMap, seed? }`;
264
+ *import .sgc* validates it on load (hard errors block, warnings surface) and runs it. The on-disk
265
+ JSONC tree stays canonical for editing; `Graph.exportConcepts()` + `lib/load.js#exportConceptsToDir`
266
+ / `lib/authoring/corpus-pack.js` are the programmatic equivalents.
267
+ - **Provider trace** — the apply-correlated log records (`graph.logger.tail(n, { applyId })`) for the
268
+ active session, joining each apply's provider calls to its trace.
269
+ - **Retraction flash** — when a concept is *retracted* (JTMS defeasance / cascade), the affected
270
+ object flashes red on the canvas. The Studio derives this from the state diff (no engine change)
271
+ and emits a `retract` event.
272
+ - **Sub-graph split** — with a fork selected, *split* shows the parent and the fork side by side and
273
+ previews the **merge projection** (`validateMergeProjection`): what crosses the frontier and any
274
+ `frontier-leak` (a fact not in the declared alphabet) — before you merge.
275
+
276
+ New ops: `grammarGraph`, `corpusManifest`, `exportCorpus`, `importCorpus`, `providerTrace`,
277
+ `mergePreview`; new event: `retract`.
278
+
279
+ Embeddable as a library (not only via the CLI):
280
+
281
+ ```js
282
+ const Graph = require('skynet-graph');
283
+ const server = Graph.createStudioServer({ Graph, root: './', ask: myLLM, logger });
284
+ ```
285
+
286
+ The wire contract is `lib/studio/protocol.js` (`OPS` client→server, `EVENTS` server→client). The
287
+ browser pulls React/cytoscape from a CDN (esm.sh) — vendor them for an offline / air-gapped demo.
288
+
289
+ ## 8. Distributed execution
290
+
291
+ Stabilize sub-graphs in separate worker processes; dispatch graph parts to warm workers.
292
+
293
+ ```js
294
+ // one-shot: spawn a worker, dispatch a seed, get the stabilized snapshot back:
295
+ const snapshot = await Graph.spawnGraph({
296
+ conceptMap, // JSON concept map (or `concepts: <dir>` the worker can read)
297
+ geo: true, // register the packaged Geo provider on the worker
298
+ // llm: true, // register the LLM provider wired to the proxied `ask`
299
+ ask: myModelBackend, // parent answers proxied model calls
300
+ seed
301
+ });
302
+ const seg = JSON.parse(snapshot.graph).conceptMaps.find(o => o._id === 's');
303
+
304
+ // warm, reusable worker serving many independent dispatches:
305
+ const w = Graph.createGraphWorker({ conceptMap, geo: true, ask: myModelBackend });
306
+ const s1 = await w.dispatch(seedA);
307
+ const s2 = await w.dispatch(seedB);
308
+ w.terminate();
309
+ ```
310
+
311
+ Only JSON crosses the boundary (`conceptMap`, `seed`, provider **dir paths**, the
312
+ serialized snapshot). In-memory provider closures are **not** shipped — load them on the
313
+ worker from a directory, and proxy a parent-bound model backend via `ask`. The protocol is
314
+ plain-JSON (`init` / `dispatch` / `ask` / `result`), so a cross-instance transport
315
+ (child_process IPC, or TCP/WebSocket to a waiting remote instance) can replace
316
+ `worker_threads` behind the same shape.
317
+
318
+ ## 9. Examples
319
+
320
+ ```bash
321
+ node examples/integrated-demo/run.js --replay # the 4 capabilities assembled — 7 checks, deterministic, no GPU
322
+ node examples/run-basic.js # non-LLM stabilization over the real `common` set
323
+ node examples/run-prompt.js # decompose → synthesize vs a local LLM (set LLM_BASE), writes a trace
324
+ node examples/run-problem.js # LLM-driven plan decomposition
325
+ node examples/poc/appliance-typed-qa.js # the typed-QA appliance (combo C1), canned & deterministic
326
+ node examples/poc/appliance-typed-qa.js --local-model <gguf> # …same, over a real embedded model
327
+ ```
328
+
329
+ ### LLM backend (`ask`)
330
+
331
+ The packaged `LLM::complete` provider is backend-agnostic — a host injects an async
332
+ `ask({system,user,maxTokens})`. The bundled `makeAsk(opts)` dispatches on the API flavour
333
+ (`opts.api` or env `LLM_API`):
334
+
335
+ - **`anthropic`** (default) — `POST <LLM_BASE>/v1/messages` (default base `:3000`).
336
+ - **`openai`** — `POST <LLM_BASE>/v1/chat/completions` (vLLM / llama.cpp / LM Studio / any
337
+ OpenAI-compatible server). Reads `choices[0].message.content`, and for **reasoning models**
338
+ that return an empty `content` plus a separate `reasoning_content`, falls back to the latter.
339
+
340
+ ```bash
341
+ LLM_API=openai LLM_BASE=http://localhost:5000 LLM_MODEL=my-model node examples/run-prompt.js
342
+ ```
343
+
344
+ Env: `LLM_API` · `LLM_BASE` · `LLM_MODEL` · `LLM_KEY`. `makeOpenAIAsk` / `makeAnthropicAsk` are
345
+ exported directly too. A live end-to-end check of the canonicalization barrier against a real model
346
+ is the gated test `tests/integration/llm-live.test.js` (`LLM_LIVE=1`).
347
+
348
+ ### Embedded inference (in-process, no external endpoint)
349
+
350
+ The library can run its small functional model(s) **itself** (a self-contained appliance) via the same
351
+ `ask` seam — `makeLocalAsk` is a drop-in `ask` backed by **node-llama-cpp** (native, GGUF, GPU auto-detected).
352
+ It's an **optional** native dep (not committed; installed on demand) and GGUF models live in the **gitignored**
353
+ `models/` dir:
354
+
355
+ ```bash
356
+ npm run local-inference:setup # install the engine (node-llama-cpp) into node_modules
357
+ npm run local-inference:setup -- --turboquant # + guidance for the TheTom TurboQuant+ fork
358
+ # then drop a .gguf into models/ (or set LOCAL_MODEL / pass modelPath)
359
+ ```
360
+
361
+ ```js
362
+ const { register, createLLMProvider, makeLocalAsk } = require('skynet-graph/lib/providers');
363
+ register(Graph, [ createLLMProvider({ ask: makeLocalAsk({ modelPath: 'models/small.gguf' }) }) ]);
364
+ ```
365
+
366
+ **Grammar-constrained decoding is format INSURANCE, not a quality lever** (measured: constrained decoding
367
+ *hurt* signature stability — the shipped posture keeps it OFF by default): pass `jsonSchema` (or `gbnf`) only
368
+ when a malformed typed fact is worse than a distorted one, e.g. as a last-resort parse backstop. The real K1
369
+ signature-stability lever is the strong prompt + the canonicalization barrier (`prompt.facts`).
370
+ Grammar guarantees valid *format*, not correct *content* — keep the C-contract/verify pass as the content check,
371
+ and reserve a bigger/remote model for the META/supervisor tier. Per-concept **multi-model** = one `makeLocalAsk`
372
+ per `namespace` (a specialist GGUF, or one base + a per-context LoRA). The no-build/browser sibling is `wllama`
373
+ (same GGUF, WASM, CPU-only — no GPU) — a future `makeWasmAsk`.
374
+
375
+ **Centralized host (GPU/VRAM + prompt cache).** Every `makeLocalAsk` is a thin handle over a **process-wide shared
376
+ host** (`createLocalModelHost`): N handles / namespaces of the *same* GGUF share **one** VRAM load, several
377
+ constrained grammars share that load (grammar is applied per-call), identical deterministic (temp-0) prompts are
378
+ served from an in-memory cache, and VRAM is bounded by **LRU eviction** — set `SG_LOCAL_VRAM_BUDGET_GB` /
379
+ `SG_LOCAL_MAX_MODELS`, or pass `opts.host = createLocalModelHost({ vramBudgetGB, maxModels, cacheSize })` for a
380
+ dedicated budget. (In-process analogue of a grant-based GPU orchestrator; the model loader is injectable, so the
381
+ registry/cache/eviction logic is unit-testable without a GPU.)
382
+
383
+ **Request/response (`sg ask`).** Two modes. **`sg ask "<q>" --concepts <dir> --local-model <gguf>`** is the
384
+ **typed QA appliance** (`Graph.combos.createAppliance`): the prose→typed front door → the packaged reason loop
385
+ over `concepts/_substrate` → a durable memo → a typed answer OR a **typed refusal that names the missing
386
+ requirement** — the product posture ON by default (fail-closed, memo ON, validator ON, constrained grammar
387
+ OFF). It follows the typed *spec* (refuse when the input isn't faithfully typed) rather than world-plausibility,
388
+ and a repeat question replays from the persisted sub-graph at **0 model calls**. Without `--concepts`, `sg ask`
389
+ runs the legacy best-effort decompose→synthesize loop (kept for compat). `--json` prints the structured result.
390
+
391
+ Programmatically:
392
+
393
+ ```js
394
+ const Graph = require('skynet-graph');
395
+ const app = Graph.combos.createAppliance({ concepts: './concepts/mydomain', ask: { localModel: 'models/small.gguf' } });
396
+ const r = await app.answer('…'); // { status:'answered', answer, confBand } | { status:'refused', reason, missing:[…], prose }
397
+ ```
398
+
399
+ The underlying bricks stay usable "à nu" — the appliance is a thin, optional assembly. `session.answer(text)`
400
+ (the legacy loop) resolves with `{answer, state}` and `Graph.settle(g)` is the promise-returning settle verb.
401
+
402
+ ### Combos (`Graph.combos.*`) — thin, delivered assemblies over the bricks
403
+
404
+ Each combo composes existing bricks with the product posture ON by default (fail-closed, memo/store ON,
405
+ validator ON, constrained grammar OFF); none is a required path — the bricks stay usable "à nu".
406
+
407
+ ```js
408
+ // C1 — typed-QA appliance (above): intake → reason-loop → typed refusal → memo.
409
+ const app = Graph.combos.createAppliance({ concepts: './concepts/mydomain', ask });
410
+
411
+ // C2 — durable workflow runner: a compact spec → a crash-safe, memoizing, auditable run.
412
+ const runner = Graph.combos.createDurableRunner({ store: 'flow.db', runTask }); // file → SQLite, else in-memory
413
+ await runner.run('run-1', spec, records); // compile → ensureRun → inject → drain (task calls amortize)
414
+ await runner.resume('run-1', spec); // crash-recovery: reclaim orphaned tokens → finish (exactly-once)
415
+ const { summary } = runner.audit('run-1'); // the derivation forest + verdict + blame
416
+
417
+ // C3 — learning method library: the always-on cost ladder + a persistent, shippable, LEARNING library.
418
+ const lib = Graph.combos.createLearningLibrary({ signature, forge, store: 'lib.json',
419
+ learning: true, target, dispatchFacts }); // learning OPT-IN: the FORGE arm becomes dispatch→adapt→forge
420
+ await lib.solve(problem); // MATCH→RETRIEVE→FORGE→ESCALATE; a warm class replays at 0 calls
421
+ lib.crystallizeFrom(mt.records, { episodeTree, schemaGraph }); // distill methods from a REAL trace → catalog
422
+ lib.drift(problem); // a fallen premise → re-derive BOTH layers (exact cache + catalog template)
423
+ lib.blame({ contract, failedAtoms }); // localized per-slot blame (admissible iff ONE role) — credit() dual
424
+ const sgc = lib.pack({ name: 'methods', version: 'v1' }); // ship the warm library (version-gated)
425
+
426
+ // C4 — the reactive KG (the engine's original Use-1): a trivial preset over fromDirs (builtins ON).
427
+ const kg = Graph.combos.reactiveKG({ concepts: './concepts/common', seed }); // rule-KG + geo, usable à nu
428
+
429
+ // C5 — supervised self-modification (OPT-IN, guarded): edits the LIVE rules; rollbackTo is the guarantee.
430
+ const sm = Graph.combos.createSelfMod({ graph, propose }); // author() needs a proposer (the "judge")
431
+ await sm.author({ goal }); // CEGIS: propose→validate→install→test→refine
432
+ sm.rollbackTo(sm.revisions()[0]); // reversibility — restore any prior coherent revision
433
+
434
+ // C6 — the local-first PROXY CACHE / DISTILLER (the main use case): a verified stock in front of a
435
+ // FRONTIER model. Covered → served local (0 frontier calls); miss → escalate + enrich; 0 hallucination.
436
+ const px = Graph.combos.createProxyCache({
437
+ frontierAsk: Graph.combos.makeFrontierAsk(chatAsk), // any ({system,user}) -> text backend = the truth
438
+ store: './stock.json', retention: true, // durable cross-restart + usage-tracked eviction
439
+ ...Graph.combos.makeLocalCoverage({ localAsk }) // opt-in: a small model snaps paraphrases to one key
440
+ });
441
+ const { answer, source } = await px.answer('What is the capital of France?'); // source: 'local'|'frontier'
442
+
443
+ // C7 — the hierarchical PLAN LOOP (the piece-by-piece zoom): a task longer than the context is decomposed
444
+ // into typed leaves, each served with ONLY a projected digest, rebalanced to a fixpoint, reassembly verified.
445
+ // decompose + serveLeaf are INJECTED (typed-loop + createProxyCache.solve in production) — usable "à nu".
446
+ const loop = Graph.combos.createPlanLoop({ decompose, serveLeaf });
447
+ const { answer: a7, refused } = await loop.run(task, { givens, labels: labelsOf(givens) });
448
+ // givens: lib/authoring/givens.js#seedOf · labelsOf = the measured CELLS rule (label an input iff its
449
+ // provenance is a structured table cell — never prose, never producers)
450
+
451
+ // C8 — the MIXTURE-RUNTIME server: a cheap local model ORIENTED by a forged certified stock, escalating the
452
+ // rest to a bigger tier. NOTE: the runtime cross-agreement "trusted answers" tier documented in its header was
453
+ // REFUTED at scale — keep the fail-closed default (nothing auto-trusted); orientation lifts the score only.
454
+ const mx = Graph.combos.createMixtureServe({ certifiedShapes, small, big, proposeMenu });
455
+ // certifiedShapes is REQUIRED. Caution: injecting `predict` without `trust: () => false` re-enables the
456
+ // REFUTED cross-agreement default — keep fail-closed (nothing auto-trusted).
457
+
458
+ // C9 — the external CRITICAL MIND: declared viewpoints established through a witness gate over a statement
459
+ // pool, anchored generation of missing theses (0-fabrication measured), a typed LEDGER as the deliverable,
460
+ // and a certification-aware verdict — mechanical only at the measured margin bound, else an honest UNDECIDED.
461
+ const cm = Graph.combos.createCriticalMind({ ask });
462
+ const r = await cm.run({ topic, statements, viewpoints }); // frame FREE/MATERIAL/DECLARED, announced
463
+ ```
464
+
465
+ ## 10. Serving surfaces — OpenAI-compatible endpoint & MCP tools
466
+
467
+ The library serves its main use cases over two ZERO-INTEGRATION surfaces (both thin assemblies over the
468
+ combos; both zero-dep):
469
+
470
+ ```bash
471
+ # 1) sg serve — an OpenAI-COMPATIBLE endpoint over the C6 proxy. Point ANY OpenAI client's baseURL at it:
472
+ sg serve --frontier-model <path.gguf> --store ./stock.json # → http://127.0.0.1:4747/v1
473
+ # const client = new OpenAI({ baseURL: 'http://127.0.0.1:4747/v1', apiKey: 'sg-local' });
474
+ # A covered query is served from the verified local stock at 0 frontier calls; provenance rides EVERY
475
+ # completion (headers x-sg-served-from/-arm/-cost/-coverage/-saved/-sgc-version + usage.sg_*). stream:true is honored
476
+ # (simulated SSE). Add --studio to open the visual debugger on port+1 (live request lines in its trace
477
+ # panel); Ctrl-C prints the economy report.
478
+
479
+ # 2) sg mcp — the same capabilities as MCP TOOLS for an agent host (stdio JSON-RPC):
480
+ claude mcp add sg -- node bin/sg mcp --frontier-model <path.gguf> --store ./stock.json [--stock <f.sgc>]
481
+ # Base tools: ask (answer OR a STRUCTURED typed refusal naming the missing requirement), drift, metrics,
482
+ # lattice_load (learning through the version-gated admission — there is NO direct-write tool),
483
+ # methods_describe, lattice_rings, trace_tail (debug by applyId).
484
+ #
485
+ # The ASSISTANT lanes (--stock <f.sgc> wires hint/propose from a forged stock):
486
+ # SOFT — hint (the certified-shape menu, advisory) · state_recall / state_note (the certified task
487
+ # state) · plan_sync (the graph plan mirrored onto the HOST's task list — REOPEN included)
488
+ # HARD — propose (gate-tested: admitted, or refused with the reason + gate-tested options;
489
+ # force → recorded-untrusted, NEVER admission — the gate does not cede)
490
+ # C9 — critique (the external critical mind: viewpoints + witness gate + anchored generation +
491
+ # typed ledger + a verdict that is mechanical only at the measured margin, else UNDECIDED).
492
+ # Iteration contract: OPEN points + UNDECIDED = a typed DATA REQUEST — the host gathers real
493
+ # statements (web/docs) and re-calls critique with `statements` (the frame becomes MATERIAL).
494
+ # INSTANCES — graph_invoke / graph_instances.
495
+
496
+ # 3) sg flow run — a durable C2 workflow from a JS module (spec + tasks are code):
497
+ sg flow run examples/poc/durable-flow.js --store ./flow.sqlite # --resume = exactly-once recovery
498
+ ```
499
+
500
+ Runnable, deterministic, GPU-free demos of every combo and both surfaces live in `examples/bootstrap/`
501
+ (one file per use-case class, each printing the guarantee it demonstrates — run them with plain `node`).