@polycode-projects/the-mechanical-code-talker 1.9.2 → 1.10.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.
- package/README.md +441 -202
- package/bin/tmct.mjs +126 -1
- package/package.json +4 -2
- package/src/answer-variants.mjs +8 -36
- package/src/ask-browser-entry.mjs +5 -23
- package/src/ask-browser.bundle.js +1 -2
- package/src/ask-nlp.mjs +9 -23
- package/src/ask-vocab.mjs +139 -589
- package/src/ask.mjs +627 -1729
- package/src/chat.mjs +1684 -2872
- package/src/cli-args.mjs +14 -28
- package/src/codegraph.mjs +236 -644
- package/src/completions/complete.mjs +18 -62
- package/src/completions/graph-adapter.mjs +14 -60
- package/src/completions/group.mjs +12 -68
- package/src/completions/infer.mjs +38 -126
- package/src/completions/prune.mjs +17 -70
- package/src/completions/rank.mjs +16 -69
- package/src/completions/search.mjs +8 -31
- package/src/concept.mjs +32 -88
- package/src/conformance.mjs +11 -15
- package/src/corpus/conceptnet.mjs +31 -89
- package/src/corpus/templates.mjs +19 -45
- package/src/corpus/unknown-ingest.mjs +31 -92
- package/src/embed.mjs +10 -22
- package/src/extensions.mjs +50 -154
- package/src/finish.mjs +35 -91
- package/src/grammar/ace.mjs +16 -40
- package/src/grammar/assert.mjs +1 -1
- package/src/grammar/lexicon-core.json +1 -1
- package/src/grammar/lexicon.mjs +9 -27
- package/src/graph-merge.mjs +2 -3
- package/src/hash.mjs +6 -14
- package/src/index.mjs +6 -10
- package/src/init.mjs +38 -125
- package/src/interpret/fuzzy.mjs +10 -29
- package/src/interpret/merge.mjs +9 -27
- package/src/interpret/normalize.mjs +137 -585
- package/src/interpret/pipeline.mjs +23 -71
- package/src/interpret/strategies/ace.mjs +7 -31
- package/src/interpret/strategies/constructions.mjs +14 -41
- package/src/interpret/strategies/grammar.mjs +21 -60
- package/src/interpret/strategies/keywords.mjs +42 -131
- package/src/interpret/strategies/noise-strip.mjs +18 -89
- package/src/memory/bias.mjs +11 -54
- package/src/memory/blocks.mjs +18 -69
- package/src/memory/core.mjs +171 -591
- package/src/memory/fold.mjs +0 -0
- package/src/memory/inspect.mjs +7 -25
- package/src/memory/shacl.mjs +10 -39
- package/src/memory/trust.mjs +26 -127
- package/src/memory-ask-browser-entry.mjs +7 -30
- package/src/memory-ask-browser.bundle.js +1 -1
- package/src/paraphrase.mjs +20 -53
- package/src/planning.mjs +15 -157
- package/src/prose-nlp.mjs +4 -17
- package/src/prose.mjs +19 -67
- package/src/providers/bootstrap.mjs +1 -2
- package/src/providers/fixture.mjs +1 -2
- package/src/providers/graph-service.mjs +28 -59
- package/src/repository-interface.mjs +6 -8
- package/src/router/drive.mjs +183 -0
- package/src/router/goal-reasoner.mjs +66 -231
- package/src/router/guardrail.mjs +20 -58
- package/src/router/planner.mjs +15 -46
- package/src/router/registry.mjs +13 -43
- package/src/router/resolver.mjs +46 -131
- package/src/router/results.mjs +231 -0
- package/src/schema-docs.mjs +10 -27
- package/src/server-http.mjs +10 -19
- package/src/server.mjs +22 -28
- package/src/sessions.mjs +15 -30
- package/src/source-slice.mjs +5 -7
- package/src/source.mjs +10 -20
- package/src/syllogise.mjs +187 -575
- package/src/telemetry.mjs +3 -3
- package/src/toml-config.mjs +4 -4
- package/src/tui/app.mjs +9 -19
- package/src/viz.mjs +66 -123
- package/src/wink-model.mjs +10 -24
package/README.md
CHANGED
|
@@ -3,161 +3,117 @@
|
|
|
3
3
|
`@polycode-projects/the-mechanical-code-talker`
|
|
4
4
|
|
|
5
5
|
A pure-JS, **no-LLM**, offline, **$0** chatbot in the ELIZA/PARRY lineage:
|
|
6
|
-
pattern-driven, best-efforts, and
|
|
7
|
-
|
|
6
|
+
pattern-driven, best-efforts, and focused on software as its subject matter.
|
|
7
|
+
It makes no model calls.
|
|
8
8
|
|
|
9
9
|
tmct turns natural language directly into a graph database. On first run it
|
|
10
|
-
seeds an everyday **human-world persona
|
|
11
|
-
time
|
|
10
|
+
seeds an everyday **human-world persona**: people, places, objects, nature,
|
|
11
|
+
time. It already has a vocabulary before you teach it anything. A
|
|
12
12
|
code-focused persona is available as an opt-in alternative: a software
|
|
13
13
|
**ontology** (real definitions), a **lexicon** (everyday words mapped onto
|
|
14
14
|
it), and a wider ConceptNet **corpus**. Point tmct at a real codebase's graph
|
|
15
|
-
and it reasons over that too, whichever persona is active.
|
|
16
|
-
|
|
17
|
-
it
|
|
18
|
-
|
|
15
|
+
and it reasons over that too, whichever persona is active.
|
|
16
|
+
|
|
17
|
+
Teach it a fact in plain English and it mints a node. Ask it a question and
|
|
18
|
+
it answers from what it was seeded with, what you taught it, and what it can
|
|
19
|
+
derive by rule from both. Every answer is either grounded or an honest miss.
|
|
19
20
|
|
|
20
21
|
## Teach it, then ask it to reason
|
|
21
22
|
|
|
22
23
|
This is real, runnable output. No cherry-picking, no model anywhere in the
|
|
23
|
-
loop.
|
|
24
|
+
loop. The script lives at `examples/teach-and-infer.mjs` in this repo; run it
|
|
25
|
+
yourself with `node examples/teach-and-infer.mjs`, or copy the source below:
|
|
24
26
|
|
|
25
27
|
```js
|
|
26
28
|
import { runChat } from "@polycode-projects/the-mechanical-code-talker";
|
|
27
29
|
import { Readable, PassThrough } from "node:stream";
|
|
28
|
-
import { mkdtemp,
|
|
30
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
29
31
|
import { tmpdir } from "node:os";
|
|
30
32
|
import { join } from "node:path";
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
await mkdir(join(repoPath, ".tmct"), { recursive: true });
|
|
51
|
-
await writeFile(join(repoPath, ".tmct", "graph.json"), JSON.stringify(graph));
|
|
52
|
-
|
|
53
|
-
// tmct has one API surface for both teaching and asking: a chat turn, in
|
|
54
|
-
// English. Each call below is a short session over the same repo, so what
|
|
55
|
-
// gets taught in the first call is still remembered in the second.
|
|
56
|
-
async function tell(line) {
|
|
57
|
-
const out = new PassThrough();
|
|
58
|
-
let transcript = "";
|
|
59
|
-
out.on("data", (chunk) => { transcript += chunk; });
|
|
60
|
-
await runChat({ repoPath, input: Readable.from([line + "\n", "/exit\n"]), output: out });
|
|
61
|
-
return transcript.split("\n").find((l) => l.startsWith("tmct> "));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
await tell("a controller is a kind of handler"); // Learn
|
|
65
|
-
console.log(await tell("is TaskController a handler")); // Infer from learnings
|
|
34
|
+
const TEACH = [
|
|
35
|
+
"ahab is the father of john",
|
|
36
|
+
"john is the father of ishmael",
|
|
37
|
+
"a father is a kind of parent",
|
|
38
|
+
"remember that ahab is male",
|
|
39
|
+
"a grandparent is a parent of a parent",
|
|
40
|
+
"a grandfather is a grandparent who is male",
|
|
41
|
+
];
|
|
42
|
+
const ASK = "is ahab the grandfather of ishmael";
|
|
43
|
+
|
|
44
|
+
// memoryBackend: "memory" keeps this whole session in the live handle only —
|
|
45
|
+
// no repo, no graph file, no disk write.
|
|
46
|
+
const repoPath = await mkdtemp(join(tmpdir(), "tmct-example-"));
|
|
47
|
+
const output = new PassThrough();
|
|
48
|
+
let transcript = "";
|
|
49
|
+
output.on("data", (chunk) => { transcript += chunk; });
|
|
50
|
+
const lines = [...TEACH, ASK].map((line) => line + "\n");
|
|
51
|
+
await runChat({ repoPath, memoryBackend: "memory", input: Readable.from([...lines, "/exit\n"]), output });
|
|
66
52
|
```
|
|
67
53
|
|
|
54
|
+
(`examples/teach-and-infer.mjs` adds the parsing that turns `transcript` into
|
|
55
|
+
the answers below, plus cleanup — see the file for the full script.)
|
|
56
|
+
|
|
68
57
|
Output, captured from an actual run:
|
|
69
58
|
|
|
70
59
|
```
|
|
71
|
-
tmct>
|
|
72
|
-
|
|
73
|
-
```
|
|
60
|
+
tmct> ahab is the father of john
|
|
61
|
+
noted — remembered: ahab fathers john
|
|
74
62
|
|
|
75
|
-
|
|
76
|
-
fact already in the graph (`TaskController inherits Controller`) with a fact
|
|
77
|
-
you just taught it in English (`controller is a kind of handler`) and wrote
|
|
78
|
-
the connecting sentence itself, citing both sources. The `source: ace:chat:…`
|
|
79
|
-
part is a real provenance receipt. Every fact tmct stores records where it
|
|
80
|
-
came from and when (more on that below).
|
|
63
|
+
Goal (inferred): Teach/remember a new fact.
|
|
81
64
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
part in parentheses is a paraphrase. tmct generates it and checks it against
|
|
85
|
-
its own inference rules before showing it, so it never just guesses at
|
|
86
|
-
prose.
|
|
65
|
+
tmct> john is the father of ishmael
|
|
66
|
+
noted — remembered: john fathers ishmael
|
|
87
67
|
|
|
88
|
-
|
|
89
|
-
$ tmct
|
|
90
|
-
tmct> what talks to the payment module?
|
|
91
|
-
…
|
|
92
|
-
tmct> /callers checkout
|
|
93
|
-
…
|
|
94
|
-
tmct> /exit
|
|
95
|
-
```
|
|
68
|
+
Goal (inferred): Teach/remember a new fact.
|
|
96
69
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
actual query engine against a small example codebase, no server, no install.
|
|
70
|
+
tmct> a father is a kind of parent
|
|
71
|
+
noted — remembered 1 fact: father rdfs:subClassOf parent (father is a type of parent)
|
|
100
72
|
|
|
101
|
-
|
|
73
|
+
Goal (inferred): Teach/remember a new fact.
|
|
102
74
|
|
|
103
|
-
|
|
104
|
-
English, reason over a seeded ontology, answer in English, with no model call
|
|
105
|
-
anywhere. Three kinds of library each cover one piece of it well.
|
|
75
|
+
Canonical: does "father" inherits "parent"? — ask(inherits, subject="father", "parent")
|
|
106
76
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
processing") is the general-purpose NLP toolkit of the three. Its own README
|
|
110
|
-
example:
|
|
77
|
+
tmct> remember that ahab is male
|
|
78
|
+
noted — remembered: ahab is male
|
|
111
79
|
|
|
112
|
-
|
|
113
|
-
import nlp from 'compromise'
|
|
114
|
-
let doc = nlp('she sells seashells by the seashore.')
|
|
115
|
-
doc.verbs().toPastTense()
|
|
116
|
-
doc.text()
|
|
117
|
-
// 'she sold seashells by the seashore.'
|
|
118
|
-
```
|
|
80
|
+
Goal (inferred): Teach/remember a new fact.
|
|
119
81
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
memory between calls. Each call is stateless text in, text out.
|
|
82
|
+
tmct> a grandparent is a parent of a parent
|
|
83
|
+
noted — remembered: a grandparent is a parent of a parent
|
|
123
84
|
|
|
124
|
-
|
|
125
|
-
spec-compliant RDF/OWL toolkit: parsing, writing, and in-memory storage of
|
|
126
|
-
triples. Its own README example:
|
|
85
|
+
Goal (inferred): Teach/remember a new fact.
|
|
127
86
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
87
|
+
tmct> a grandfather is a grandparent who is male
|
|
88
|
+
noted — remembered: a grandfather is a grandparent who is male
|
|
89
|
+
|
|
90
|
+
Goal (inferred): Teach/remember a new fact.
|
|
91
|
+
|
|
92
|
+
tmct> is ahab the grandfather of ishmael
|
|
93
|
+
yes — you told me: ahab fathers john (source: teach:chat:<session-id>@<timestamp>); father is a kind of parent (source: ace:chat:<session-id>@<timestamp>); you told me: john fathers ishmael (source: teach:chat:<session-id>@<timestamp>); you told me: ahab is male (source: teach:chat:<session-id>@<timestamp>)
|
|
134
94
|
```
|
|
135
95
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
96
|
+
Nobody told tmct that ahab is ishmael's grandfather. It combined four facts
|
|
97
|
+
taught across six turns: the two father facts, the father-is-a-kind-of-parent
|
|
98
|
+
alias, and the ahab-is-male property, then cited all four. The `source: …`
|
|
99
|
+
parts are real provenance receipts. Every fact tmct stores records where it
|
|
100
|
+
came from and when (more on that below).
|
|
141
101
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
in. Its own README example:
|
|
102
|
+
`test/examples-teach-and-infer.test.mjs` pins this exact output. If the
|
|
103
|
+
underlying chat behavior ever drifts, that test fails and says so.
|
|
145
104
|
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
105
|
+
```
|
|
106
|
+
$ tmct
|
|
107
|
+
tmct> what talks to the payment module?
|
|
108
|
+
…
|
|
109
|
+
tmct> /callers checkout
|
|
110
|
+
…
|
|
111
|
+
tmct> /exit
|
|
150
112
|
```
|
|
151
113
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
Put together: broad NLP without a graph (compromise), a graph without a
|
|
157
|
-
natural-language front end (N3.js), or a conversational front end without a
|
|
158
|
-
graph (elizabot). Combining ontology-seeded graph memory, English teaching,
|
|
159
|
-
and rule-based inference into one no-model pipeline is what looks distinctive
|
|
160
|
-
about tmct as of this writing.
|
|
114
|
+
**[Try it live in your browser →](https://polycode-projects.gitlab.io/the-mechanical-code-talker/)**
|
|
115
|
+
is a real, interactive chat demo running client-side. Your browser runs the
|
|
116
|
+
actual query engine against a small example codebase, no server, no install.
|
|
161
117
|
|
|
162
118
|
## How it interprets you
|
|
163
119
|
|
|
@@ -168,7 +124,7 @@ results are grouped by class.
|
|
|
168
124
|
One of the strategies is an **ACE-inspired controlled grammar**: when your
|
|
169
125
|
text fits the controlled fragment, tmct emits OWL-labelled triples from it.
|
|
170
126
|
Those triples are statements it can store, retrieve, and answer from later.
|
|
171
|
-
Text that doesn't fit the grammar still gets the tolerant strategies
|
|
127
|
+
Text that doesn't fit the grammar still gets the tolerant strategies. Nothing
|
|
172
128
|
is rejected for being loose, fuzzy, or misspelled.
|
|
173
129
|
|
|
174
130
|
**Everyday question shapes.** Bare "what is Commit" (no article) now resolves
|
|
@@ -182,9 +138,9 @@ you to remember X" teaches like bare "remember X"; "please tell me about X"
|
|
|
182
138
|
and "search for X" describe and find exactly as their direct forms do.
|
|
183
139
|
|
|
184
140
|
**Negation and passive.** "Which modules do *not* import X?" computes a bounded
|
|
185
|
-
**set complement** over the graph
|
|
186
|
-
|
|
187
|
-
|
|
141
|
+
**set complement** over the graph. An empty result stays a miss rather than a
|
|
142
|
+
fabricated list (a non-enumerable type, like arbitrary *changes*, is refused
|
|
143
|
+
outright). Reversible-passive questions traverse the right direction:
|
|
188
144
|
"what is imported by Y" and "what does Y import" are understood as opposite
|
|
189
145
|
edges, not the same one.
|
|
190
146
|
|
|
@@ -223,13 +179,13 @@ still import Y" when it no longer does.
|
|
|
223
179
|
spans: prose versus *protected* entities, paths, numbers, code, provenance, and
|
|
224
180
|
receipts. A small data-driven grammar pass then runs on the prose spans only,
|
|
225
181
|
under a guard that proves the protected spans came through byte-for-byte. Today
|
|
226
|
-
that pass fixes the a/an article defect
|
|
182
|
+
that pass fixes the a/an article defect. Broader voice and agreement rules are
|
|
227
183
|
implemented but parked until they earn their place on the benchmark.
|
|
228
184
|
|
|
229
185
|
A frozen regression suite plays out full multi-turn dialogues built from these
|
|
230
|
-
phrasings, at every complexity level this project defines
|
|
231
|
-
question up to a messy, typo-ridden real user. Tier-by-tier detail is
|
|
232
|
-
`HANDOVER.md` and `ROADMAP.md`.
|
|
186
|
+
phrasings, at every complexity level this project defines. That ranges from a
|
|
187
|
+
single question up to a messy, typo-ridden real user. Tier-by-tier detail is
|
|
188
|
+
in `HANDOVER.md` and `ROADMAP.md`.
|
|
233
189
|
|
|
234
190
|
## How it guides you
|
|
235
191
|
|
|
@@ -250,11 +206,11 @@ bands instead of dead-ending:
|
|
|
250
206
|
|
|
251
207
|
It fires for both **noun** concepts (class, module, function, method) and
|
|
252
208
|
**relation** concepts (imports, calls, contains, inherits, tests), and only
|
|
253
|
-
when tmct
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
209
|
+
when tmct knows the concept and has instances of it. Otherwise the honest miss
|
|
210
|
+
stands. This lets you start from a vague opener and still reach a useful
|
|
211
|
+
answer. Natural phrasings are routed to the capability you meant: *"what
|
|
212
|
+
functions are in Task"* → its members, *"what defined saveStore"* → where
|
|
213
|
+
it's defined.
|
|
258
214
|
|
|
259
215
|
## Detailed, grounded answers
|
|
260
216
|
|
|
@@ -262,7 +218,7 @@ Ask a precise question and tmct gives you a precise answer. Ask for more and
|
|
|
262
218
|
it gives you more: "give me a detailed summary of how X works" (or "explain
|
|
263
219
|
in detail how X works", or "...detailed overview/explanation of X") gets a
|
|
264
220
|
longer, multi-sentence account instead of one line. Every sentence in it is
|
|
265
|
-
lifted from a real graph edge, attribute, or taught fact
|
|
221
|
+
lifted from a real graph edge, attribute, or taught fact. tmct never generates
|
|
266
222
|
free text.
|
|
267
223
|
|
|
268
224
|
The wording varies a little too. A small, curated, deterministic pool swaps a
|
|
@@ -305,6 +261,73 @@ doc = In-memory record store. [seon:hasDoc]. Other matches: src/core/store.mjs
|
|
|
305
261
|
|
|
306
262
|
Full pipeline design in `archive/PLAN_COMPLETIONS.md`.
|
|
307
263
|
|
|
264
|
+
## Planning across the graph
|
|
265
|
+
|
|
266
|
+
Some questions need more than one lookup. `tmct plan` is a small STRIPS/PDDL-style
|
|
267
|
+
planner over the same read-only graph-query tools chat/serve use
|
|
268
|
+
(`src/router/*`): it decomposes a compound request, resolves and executes each
|
|
269
|
+
step in order with a provable causal-link proof chain, and folds the results
|
|
270
|
+
into one answer. A request neither the planner nor a single lookup can ground
|
|
271
|
+
escalates to a closed-world goal-reasoner, which deduces maintenance goals
|
|
272
|
+
(coverage gaps, change-coupling risk) straight from the graph — never from
|
|
273
|
+
keywords in your question. Anything none of that grounds is an honest "no plan
|
|
274
|
+
found", the same "grounded or an honest miss" rule as everywhere else in tmct.
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
$ node bin/tmct.mjs plan "of the modules impacted by src/lib/http.mjs, which are untested" --repo examples/mini-webapp
|
|
278
|
+
tmct plan: "of the modules impacted by src/lib/http.mjs, which are untested"
|
|
279
|
+
driver: resolver-0.8.0
|
|
280
|
+
|
|
281
|
+
steps:
|
|
282
|
+
1. tmct_impact {"module":"src/lib/http.mjs"}
|
|
283
|
+
Impact of changing src/lib/http.mjs (reverse closure over imports/calls edges, module- and function-level):
|
|
284
|
+
total: 5 dependent(s) across 2 depth level(s) (lists capped for brevity).
|
|
285
|
+
depth 1 (3 direct dependents):
|
|
286
|
+
- src/handlers/base.mjs (imports it) — tests: none recorded
|
|
287
|
+
- src/handlers/tasks.mjs (imports it) — tests: test/tasks.test.mjs
|
|
288
|
+
- src/server/router.mjs (imports it) — tests: none recorded
|
|
289
|
+
depth 2 (2):
|
|
290
|
+
- src/handlers/users.mjs (imports it) — tests: none recorded
|
|
291
|
+
- src/server/app.mjs (imports it) — tests: none recorded
|
|
292
|
+
2. tmct_untested {}
|
|
293
|
+
7 source module(s) with no covering test module:
|
|
294
|
+
src/core/validate.mjs
|
|
295
|
+
src/handlers/base.mjs
|
|
296
|
+
src/handlers/users.mjs
|
|
297
|
+
src/lib/http.mjs
|
|
298
|
+
src/lib/logger.mjs
|
|
299
|
+
src/server/app.mjs
|
|
300
|
+
src/server/router.mjs
|
|
301
|
+
|
|
302
|
+
composed answer (4): src/handlers/base.mjs, src/handlers/users.mjs, src/server/app.mjs, src/server/router.mjs
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
tmct planned two calls (`tmct_impact` then `tmct_untested`), ran both against the
|
|
306
|
+
real graph, and intersected the results itself — you get the four modules that
|
|
307
|
+
are both downstream of the change AND missing coverage, not two separate lists
|
|
308
|
+
you'd have to cross-reference by hand.
|
|
309
|
+
|
|
310
|
+
Leave the entity out and ask a maintenance question instead, and the goal-reasoner
|
|
311
|
+
picks up where the planner refuses:
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
$ node bin/tmct.mjs plan "what most needs a test in this codebase" --repo examples/mini-webapp
|
|
315
|
+
tmct plan: "what most needs a test in this codebase"
|
|
316
|
+
driver: goal-0.8.1
|
|
317
|
+
...
|
|
318
|
+
composed answer (1): src/lib/http.mjs
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
It deduced the goal ("an impactful module must be tested"), gathered every
|
|
322
|
+
untested module, ranked each by blast radius, and named the one worth testing
|
|
323
|
+
first — `src/lib/http.mjs`, the module with the widest reach.
|
|
324
|
+
|
|
325
|
+
`--tools tmct_impact,tmct_untested` restricts which capabilities the planner is
|
|
326
|
+
allowed to use; `--json` prints the full machine-readable loop result (calls,
|
|
327
|
+
proof chain, composed answer) for a caller that wants to consume this
|
|
328
|
+
programmatically rather than read the report. `tmct plan --help` has the full
|
|
329
|
+
flag reference.
|
|
330
|
+
|
|
308
331
|
## How it remembers
|
|
309
332
|
|
|
310
333
|
tmct's memory has two layers, both fed by every parsed request and response and
|
|
@@ -318,10 +341,10 @@ by cleaned session logs:
|
|
|
318
341
|
With no graph at all, tmct starts empty and remembers what you tell it. The
|
|
319
342
|
`.tmct/` graph is created from the conversation. On a first run it seeds the
|
|
320
343
|
committed vocabulary so it knows what it's talking about from turn one: an
|
|
321
|
-
everyday **human-world** persona
|
|
322
|
-
events, body
|
|
323
|
-
and bridged to Schema.org's top-level classes
|
|
324
|
-
offline, from disk, on turn one. A code-domain persona (a curated **SEON**
|
|
344
|
+
everyday **human-world** persona covering people, places, objects, nature,
|
|
345
|
+
time and events, body and food, and mind vocabulary. It's hand-curated from
|
|
346
|
+
Open English WordNet and bridged to Schema.org's top-level classes, so "what
|
|
347
|
+
is a dog?" answers offline, from disk, on turn one. A code-domain persona (a curated **SEON**
|
|
325
348
|
software ontology plus the whole filtered **ConceptNet slice**, CC-BY-SA 4.0)
|
|
326
349
|
is available opt-in: `tmct init --with-persona code`. `--ephemeral` (used by
|
|
327
350
|
the shipped `npm run example:*` demos) reads a graph but writes nothing back.
|
|
@@ -338,7 +361,7 @@ Two more exist: `memory` keeps taught facts in the process only, nothing
|
|
|
338
361
|
written to disk; `sqlite` persists them to a local SQLite file instead
|
|
339
362
|
(`.tmct/memory/graph.sqlite`).
|
|
340
363
|
|
|
341
|
-
Pick one at init time and it sticks
|
|
364
|
+
Pick one at init time and it sticks. `tmct init --memory-backend sqlite`
|
|
342
365
|
writes the choice into `tmct.toml`, and every later `tmct chat` in that repo
|
|
343
366
|
uses it with no flag needed:
|
|
344
367
|
|
|
@@ -360,10 +383,10 @@ New vocabulary compounds as you teach it. "redis is a cache" mints "redis" as
|
|
|
360
383
|
a class-level concept even though it was never in the built-in lexicon, and a
|
|
361
384
|
later "every cache is a store" does the same for "store," the other way
|
|
362
385
|
round, as long as one side of the sentence is already grounded. tmct never
|
|
363
|
-
mints a fact between two totally ungrounded terms
|
|
364
|
-
to ground one side first. Quantified teaching works too: "some
|
|
365
|
-
risky" stores the quantifier, and a later "how many functions
|
|
366
|
-
answers "A few."
|
|
386
|
+
mints a fact between two totally ungrounded terms. It declines instead, and
|
|
387
|
+
nudges you to ground one side first. Quantified teaching works too: "some
|
|
388
|
+
functions are risky" stores the quantifier, and a later "how many functions
|
|
389
|
+
are risky" answers "A few."
|
|
367
390
|
|
|
368
391
|
Once you've taught a few facts, "how many facts are there" counts them back.
|
|
369
392
|
That's the same count phrasing a code graph answers "how many classes are
|
|
@@ -376,9 +399,9 @@ first-class individuals: operator chat, a curated corpus, a provider graph, a
|
|
|
376
399
|
web scrape, a rule-derived entailment. A fact links back to *all* of them
|
|
377
400
|
(`mgx:derivedFrom` / `mgx:statedBy` / `mgx:canonicalisedFrom`), timestamped with
|
|
378
401
|
`mgx:createdAt`. From those links tmct computes a **deterministic, explainable
|
|
379
|
-
trust score
|
|
380
|
-
independent sources agree) and recency. It is never hand-set
|
|
381
|
-
to its inputs. Retrieval then ranks by **relevance × trust**, so a corroborated,
|
|
402
|
+
trust score**, combining a source-type prior with corroboration (how many
|
|
403
|
+
independent sources agree) and recency. It is never hand-set. Every value
|
|
404
|
+
traces back to its inputs. Retrieval then ranks by **relevance × trust**, so a corroborated,
|
|
382
405
|
operator-stated fact outranks a lone web scrape on the same question. When two
|
|
383
406
|
trusted sources *disagree*, the `/memory` inspector shows **both sides with their
|
|
384
407
|
provenance** rather than silently picking a winner.
|
|
@@ -408,7 +431,7 @@ Inside the chat: `/help` lists commands, `/memory` inspects what tmct remembers
|
|
|
408
431
|
`TMCT_GRAPH_FILE` overrides the graph location.
|
|
409
432
|
|
|
410
433
|
`tmct --help` (or `npm run help` from a clone of this repo) is the full,
|
|
411
|
-
up-to-date flag reference for every subcommand
|
|
434
|
+
up-to-date flag reference for every subcommand. A bare `npm run` only lists
|
|
412
435
|
script names, so `npm run help` is the documented way in from there.
|
|
413
436
|
|
|
414
437
|
`tmct init` is the onboarding surface for the repository interface below: it
|
|
@@ -419,57 +442,262 @@ package or a bare user gets a working install in one command.
|
|
|
419
442
|
> Install-size note: tmct depends on wink-nlp's deterministic English language
|
|
420
443
|
> model (~3.8 MB installed). That model is a lookup table, not an LLM.
|
|
421
444
|
|
|
422
|
-
###
|
|
445
|
+
### Full command reference (`tmct --help`)
|
|
423
446
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
beats the `--repo`-derived `<repo>/.tmct/graph.json` default.
|
|
447
|
+
`tmct --help` always prints the real, current flags. What follows is that
|
|
448
|
+
same output, split into one block per command with a short note on what each
|
|
449
|
+
one is for, so it is easier to scan than the raw dump.
|
|
428
450
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
tmct
|
|
437
|
-
tmct
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
tmct
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
451
|
+
Every subcommand shares one flag/config resolver (`src/cli-args.mjs`), which
|
|
452
|
+
is why `--repo`, `--graph`, and `--config` behave the same way everywhere.
|
|
453
|
+
|
|
454
|
+
The bare command and `tmct chat` open the interactive session:
|
|
455
|
+
|
|
456
|
+
```
|
|
457
|
+
Usage:
|
|
458
|
+
tmct interactive chat (the headline surface)
|
|
459
|
+
tmct chat [--repo <abs>] chat over a specific repo's graph
|
|
460
|
+
[--graph <path>] explicit graph file (repeatable — multiple graphs merge;
|
|
461
|
+
see src/graph-merge.mjs); wins over --repo/TMCT_GRAPH_FILE/tmct.toml
|
|
462
|
+
[--config <path>] an alternate tmct.toml location (a file or a directory)
|
|
463
|
+
[--ephemeral] read the graph but write nothing back (demo/read-only)
|
|
464
|
+
[--narrate] start with narrate mode on — a verbose, developer-facing
|
|
465
|
+
trace of decision points/matched pattern/results/goal per
|
|
466
|
+
turn, appended under a "--- narrate ---" marker (also
|
|
467
|
+
TMCT_NARRATE=1; toggle mid-session with /narrate on|off)
|
|
468
|
+
[--plain] force the plain readline shell (the default when
|
|
469
|
+
stdin/stdout is not a terminal)
|
|
470
|
+
[--memory-backend <default|memory|sqlite>] storage backend for taught facts this
|
|
471
|
+
session (CLI flag > TMCT_MEMORY_BACKEND env > tmct.toml's
|
|
472
|
+
[memory] backend > "default", the flat .tmct/ JSON file)
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
`tmct memory` is the CLI-side view of the same data the `/memory` chat command shows:
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
tmct memory [--repo <abs>] what tmct remembers: facts, utterances, sessions,
|
|
479
|
+
[--config <path>] folded blocks (the /memory chat command, from the shell)
|
|
480
|
+
[--verbose]
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
`tmct init` sets up a repo for the first time: `.tmct/`, `tmct.toml`, a seed, and a
|
|
484
|
+
provenance record. Most of its flags choose what gets seeded and where config is written:
|
|
485
|
+
|
|
486
|
+
```
|
|
487
|
+
tmct init [--repo <abs>] initialize a repo for tmct (default: cwd): .tmct/,
|
|
488
|
+
[--force] tmct.toml, tier-1 corpus seed, provenance record
|
|
489
|
+
[--corpus <id|path>] also seed a corpus — a tier-2 manifest id (aws|python|java|
|
|
490
|
+
general) or a jsonl file path — opt-in, offline, $0
|
|
491
|
+
[--ontology <name|path>] activate+seed an ontology bundle (a recognized name or a path)
|
|
492
|
+
[--lexicon <name|path>] activate a lexicon bundle (recognized name or a path;
|
|
493
|
+
merged read-time, never seeded — see mergedLexiconExtra)
|
|
494
|
+
[--graph <path>] set graph_file/graph_files in tmct.toml (repeatable)
|
|
495
|
+
[--config <path>] write to an alternate tmct.toml location
|
|
496
|
+
[--detect] suggest a tier-2 corpus from the repo's manifests
|
|
497
|
+
(pyproject.toml → python, pom.xml → java); never seeds unasked
|
|
498
|
+
[--with-persona <name>] write an explicit [extensions]/[bias] preset into tmct.toml
|
|
499
|
+
("code" — today's implicit default, made explicit)
|
|
500
|
+
[--persona-size <medium|large>] grow the default "human" persona's fact count
|
|
501
|
+
beyond Small (the default): "medium" activates
|
|
502
|
+
human-medium.jsonl (~1,608 facts total), "large" also
|
|
503
|
+
activates human-large.jsonl (~13,600 facts total,
|
|
504
|
+
with genuine multi-hop hypernym chains) — additive
|
|
505
|
+
size tiers of the SAME bundle, not separate personas
|
|
506
|
+
[--memory-backend <default|memory|sqlite>] write tmct.toml's [memory] backend
|
|
507
|
+
(same flag name as `tmct chat`) — a later `tmct chat`
|
|
508
|
+
in this repo picks it up with no flag needed
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
`tmct import` does the same activation as `tmct init`, but against a repo that is
|
|
512
|
+
already set up. Its `--graph` flag works differently from the others: it appends to
|
|
513
|
+
`tmct.toml`'s `graph_files` array instead of activating a bundle.
|
|
514
|
+
|
|
515
|
+
```
|
|
516
|
+
tmct import [--repo <abs>] activate+seed into an ALREADY-initialized repo (any
|
|
517
|
+
[--corpus <id|path>] combination of these flags in one call). --graph is a
|
|
518
|
+
[--ontology <name|path>] DIFFERENT operation from the others: it APPENDS to
|
|
519
|
+
[--lexicon <name|path>] tmct.toml's graph_files array (multi-graph growth),
|
|
520
|
+
[--graph <path>] never an extensions-bundle activation.
|
|
521
|
+
[--memory-backend <default|memory|sqlite>] same knob as `tmct init`
|
|
522
|
+
[--config <path>]
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
`tmct extend --validate` checks a third-party extension pack's declared resources
|
|
526
|
+
before you switch any repo's `tmct.toml` over to it:
|
|
527
|
+
|
|
528
|
+
```
|
|
529
|
+
tmct extend --validate <dir> validate a third-party extension pack's declared
|
|
530
|
+
[--config <path>] resources (corpus/lexicon/templates) before activating
|
|
531
|
+
it in any repo's tmct.toml; exits non-zero on failure
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
`tmct syllogise` is the offline maintenance job described under "Speculative
|
|
535
|
+
inference" above:
|
|
536
|
+
|
|
537
|
+
```
|
|
538
|
+
tmct syllogise [--repo <abs>] speculative inference (offline maintenance job): forward-
|
|
539
|
+
[--depth <n>] [--budget <n>] chain the memory's rdfs:subClassOf closure, materialising
|
|
540
|
+
[--config <path>] bounded, low-trust, retractable entailed facts (never on the chat path)
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
`tmct viz` renders the memory graph to a single HTML file you can open in a browser:
|
|
544
|
+
|
|
545
|
+
```
|
|
546
|
+
tmct viz [--repo <abs>] write one self-contained, navigable HTML file rendering the
|
|
547
|
+
[--focus <id>] memory graph: pan/zoom, click a node for its label/class/
|
|
548
|
+
[--term <word>] timestamps. Seeds from the most recently created individual
|
|
549
|
+
[--depth <n>] by default (--focus <id> or --term <word> override it);
|
|
550
|
+
[--limit <n>] --output defaults to graph.html in the cwd.
|
|
551
|
+
[--hub-degree <n>] --depth = max arcs (hops) from the focus node (default 3);
|
|
552
|
+
[--edge-kind <mode>] --limit = spiral length, total nodes walked (default 300);
|
|
553
|
+
[--output <path>] --hub-degree = stop expanding THROUGH a node above N
|
|
554
|
+
[--config <path>] connections, still shows it (default 40); --edge-kind =
|
|
555
|
+
meta|relation|both (default both) — which edge kinds the
|
|
556
|
+
walk follows (provenance-only, concept-relations-only, or
|
|
557
|
+
both — see the page's own edge-kind toggle to change this
|
|
558
|
+
live); --term <word> resolves to the Fact(s) whose subject/
|
|
559
|
+
object normalizes to that word and seeds from there.
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
`tmct serve` runs an Anthropic Messages API-compatible HTTP endpoint over the graph,
|
|
563
|
+
so a tool-loop client can call tmct like a model, at $0:
|
|
564
|
+
|
|
565
|
+
```
|
|
566
|
+
tmct serve [--repo <abs>] run the Anthropic Messages API-compatible endpoint
|
|
567
|
+
[--host <h>] [--port <n>] (POST /v1/messages) over the graph — a deterministic,
|
|
568
|
+
[--graph <path>] no-LLM "model" a tool-loop client can call; $0 usage.
|
|
569
|
+
[--config <path>] Defaults: host 127.0.0.1, port 8787. Ctrl+C to stop.
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
`tmct cli` is a lower-level, carry-over surface for invoking a graph tool directly:
|
|
573
|
+
|
|
574
|
+
```
|
|
575
|
+
tmct cli <tool> '{…}' invoke a graph tool directly (carry-over, de-emphasized)
|
|
576
|
+
tmct cli digest '{…}' architecture map + per-module context bundles
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
Two precedence chains apply across every command above, in this order:
|
|
580
|
+
|
|
581
|
+
```
|
|
582
|
+
Shared graph-path precedence (chat/serve; see src/cli-args.mjs): --graph flag(s) >
|
|
583
|
+
TMCT_GRAPH_FILE env > tmct.toml graph_file/graph_files > --repo-derived
|
|
584
|
+
<repo>/.tmct/graph.json > git-root/cwd default.
|
|
585
|
+
|
|
586
|
+
Memory-backend precedence (chat; see src/chat.mjs createSession): --memory-backend
|
|
587
|
+
flag > TMCT_MEMORY_BACKEND env > tmct.toml [memory] backend > "default" (the flat
|
|
588
|
+
.tmct/ JSON file). Set it once with `tmct init --memory-backend <...>` and every
|
|
589
|
+
later `tmct chat` in that repo picks it up with no flag needed.
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
`npm run init:large` in `package.json` chains one `init` and five `import --corpus`
|
|
593
|
+
calls to combine every shipped bundle (human persona + seon + conceptnet +
|
|
594
|
+
aws/python/java) into ~7,380 facts on the default flat-JSON backend, a working
|
|
595
|
+
example to copy from.
|
|
596
|
+
|
|
597
|
+
### tmct.toml reference
|
|
598
|
+
|
|
599
|
+
`tmct init` writes a sparse `tmct.toml` with just the keys it needs. The file
|
|
600
|
+
recognizes more keys than that default covers. Below is one config with every
|
|
601
|
+
recognized key set, so you can see the full surface in one place
|
|
602
|
+
(`src/toml-config.mjs` is the source of truth; `src/extensions.mjs` defines the
|
|
603
|
+
`[extensions.*]`/`[bias]` shape).
|
|
604
|
+
|
|
605
|
+
```toml
|
|
606
|
+
# Newline-delimited-file form is also accepted: repositories = "repos.txt"
|
|
607
|
+
repositories = ["../other-service", "../another-service"]
|
|
608
|
+
|
|
609
|
+
# Where generated output (e.g. tmct viz's default graph.html) resolves to.
|
|
610
|
+
out_root = "./out"
|
|
611
|
+
|
|
612
|
+
# The code-graph JSON artifact. TMCT_GRAPH_FILE overrides this at runtime.
|
|
613
|
+
graph_file = ".tmct/graph.json"
|
|
614
|
+
# Extra graphs, merged alongside graph_file (ids that collide are auto-prefixed).
|
|
615
|
+
graph_files = [".tmct/graph.json", ".tmct/legacy-graph.json"]
|
|
616
|
+
|
|
617
|
+
[corpus]
|
|
618
|
+
# "tier1" (committed slice only, $0/offline, the default), "tier2" (also fetch
|
|
619
|
+
# growable corpora at seed time), or "tier3" (also consult live sources per query).
|
|
620
|
+
tier = "tier1"
|
|
621
|
+
|
|
622
|
+
[seed]
|
|
623
|
+
enabled = true # seed the committed corpus into .tmct/memory during init
|
|
624
|
+
limit = 500 # cap the seeded fact count (definitional band first); unset = no cap
|
|
625
|
+
|
|
626
|
+
# One [extensions.<name>] table per bundle. A recognized name (human, seon,
|
|
627
|
+
# conceptnet, human-medium, human-large, tier2-aws, tier2-python, tier2-java,
|
|
628
|
+
# tier2-general, wordnet-xl, wordnet-full, namenet) overrides that bundle's
|
|
629
|
+
# shipped defaults. Any other name declares a new bundle and must set `kind`.
|
|
630
|
+
[extensions.human]
|
|
631
|
+
active = true
|
|
632
|
+
|
|
633
|
+
[extensions.seon]
|
|
634
|
+
active = true
|
|
635
|
+
|
|
636
|
+
[extensions.conceptnet]
|
|
637
|
+
active = true
|
|
638
|
+
|
|
639
|
+
[extensions.tier2-aws]
|
|
640
|
+
active = true
|
|
641
|
+
|
|
642
|
+
[extensions.my-custom-pack]
|
|
643
|
+
kind = "pack" # corpus | lexicon | templates | pack | ontology
|
|
644
|
+
active = true
|
|
645
|
+
corpus_path = "./vendor/my-pack/corpus.jsonl"
|
|
646
|
+
lexicon_path = "./vendor/my-pack/lexicon.json"
|
|
647
|
+
templates_path = "./vendor/my-pack/templates"
|
|
648
|
+
phrasebook_path = "./vendor/my-pack/phrasebook.json"
|
|
649
|
+
provenance_prefix = "corpus:my-custom-pack"
|
|
650
|
+
|
|
651
|
+
# Flat bundle-name -> weight table, consumed by src/memory/bias.mjs's ranking.
|
|
652
|
+
[bias]
|
|
653
|
+
human = 1.0
|
|
654
|
+
seon = 0.8
|
|
655
|
+
conceptnet = 0.6
|
|
656
|
+
my-custom-pack = 1.2
|
|
657
|
+
|
|
658
|
+
[index]
|
|
659
|
+
languages = ["js", "py"] # restrict indexing to these languages
|
|
660
|
+
exclude = ["**/node_modules/**", "**/dist/**"]
|
|
661
|
+
secret_exclude = ["**/*.env", "**/secrets/**"] # never indexed, even under a broad include
|
|
662
|
+
history_depth = 200 # commits of git history to consider
|
|
663
|
+
# The five keys below parse and normalize but have no consumer wired up yet:
|
|
664
|
+
include_text = true
|
|
665
|
+
include_structure = true
|
|
666
|
+
respect_gitignore = true
|
|
667
|
+
markdown_sections = true
|
|
668
|
+
vue = true
|
|
669
|
+
|
|
670
|
+
[tune]
|
|
671
|
+
score_gap_k = 0.25 # retrieval score-gap threshold
|
|
672
|
+
literal_mention = true # boost literal-name mentions
|
|
673
|
+
demote_non_prod = true # rank test/fixture code below production code
|
|
674
|
+
call_adjacency = true # boost callers/callees of a matched symbol
|
|
675
|
+
impl_of_interface = true # boost an interface's implementations
|
|
676
|
+
beam_search = true # use beam search over the graph walk
|
|
677
|
+
beam_width = 8
|
|
678
|
+
embed_rank = false # rerank by embedding similarity (off by default)
|
|
679
|
+
prose_layers = 2 # how many prose-generation passes to run
|
|
680
|
+
|
|
681
|
+
[tune.expansion]
|
|
682
|
+
strategy = "beam" # graph-walk expansion strategy
|
|
683
|
+
nodes = 50 # node budget for the walk
|
|
684
|
+
q = 0.5 # expansion breadth parameter
|
|
685
|
+
depth = 3 # max hops
|
|
686
|
+
|
|
687
|
+
[telemetry]
|
|
688
|
+
enabled = false # local-only counters; never phones home
|
|
689
|
+
|
|
690
|
+
[memory]
|
|
691
|
+
retention_versions = 5 # snapshot generations memory/core.mjs keeps on manifest bootstrap
|
|
692
|
+
backend = "sqlite" # default | memory | sqlite (see "Memory backends" above)
|
|
693
|
+
```
|
|
466
694
|
|
|
467
695
|
### Try it on an example graph
|
|
468
696
|
|
|
469
|
-
tmct *consumes* a code graph at `<repo>/.tmct/graph.json
|
|
470
|
-
one. Two ready-made example graphs live in `examples/` in this repo (
|
|
471
|
-
|
|
472
|
-
real questions with no setup:
|
|
697
|
+
tmct *consumes* a code graph at `<repo>/.tmct/graph.json`. It does not build
|
|
698
|
+
one. Two ready-made example graphs live in `examples/` in this repo (clone the
|
|
699
|
+
repo to use them; they are not in the published npm package), so you can see
|
|
700
|
+
it answer real questions with no setup:
|
|
473
701
|
|
|
474
702
|
```bash
|
|
475
703
|
npm run example:mini # "Questboard" — a small task-tracker web app (12 modules)
|
|
@@ -507,28 +735,38 @@ import { runChat, ask, resolveObject, fetchEntities } from "@polycode-projects/t
|
|
|
507
735
|
```
|
|
508
736
|
|
|
509
737
|
`runChat` is the full teach-and-ask surface (see "Teach it, then ask it to
|
|
510
|
-
reason" above
|
|
511
|
-
session the same way the tests do
|
|
738
|
+
reason" above). It works over injectable streams, so a script can drive a
|
|
739
|
+
session the same way the tests do. `ask`/`resolveObject` are the lower-level,
|
|
512
740
|
read-only query primitives over an already-loaded graph, for a caller that
|
|
513
741
|
wants to query without a chat session. The `exports` map and the chat
|
|
514
742
|
primitives (`ask`, `resolveObject`, `relationKind`, `impactClosure`,
|
|
515
743
|
`dispatchTool`, `fetchEntities`) are the extension surface.
|
|
516
744
|
|
|
745
|
+
```js
|
|
746
|
+
import { buildCapabilityPlanCtx, runCapabilityPlan, declaredCapabilityNames } from "@polycode-projects/the-mechanical-code-talker/plan";
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
The same planner `tmct plan` runs, callable directly: `buildCapabilityPlanCtx`
|
|
750
|
+
loads a repo's graph into a `{ dispatch, resolve, graph }` context,
|
|
751
|
+
`runCapabilityPlan(request, tools, ctx)` runs a request through it, and
|
|
752
|
+
`declaredCapabilityNames()` lists every capability a caller can declare. See
|
|
753
|
+
"Planning across the graph" above.
|
|
754
|
+
|
|
517
755
|
## The repository interface
|
|
518
756
|
|
|
519
757
|
tmct is not an indexer, so it consumes a graph through a typed contract any
|
|
520
758
|
producer can implement. That contract is first-class: a **versioned (1.0.0),
|
|
521
759
|
OWL-grounded, machine-readable service definition** (`docs/repository-interface.md`
|
|
522
760
|
plus a JSON schema) of every service, its arguments, result types, and error
|
|
523
|
-
contract.
|
|
524
|
-
|
|
761
|
+
contract. The interface returns a miss as a normal value. It never throws to
|
|
762
|
+
signal "no answer." tmct ships **reference providers** (a fixture graph and the
|
|
525
763
|
empty/bootstrap graph) that implement every service, and a **runnable conformance
|
|
526
764
|
suite**. tmct's own providers pass it in `npm test`. Any external graph producer
|
|
527
765
|
(seonix first) runs the same suite against its native implementation to claim
|
|
528
|
-
conformance.
|
|
529
|
-
relationship: tmct was lifted out of seonix, and seonix now reorients
|
|
530
|
-
that imports the tmct library and exposes its graph to tmct as a
|
|
531
|
-
agent stays outside tmct, as the no-LLM ethos requires.
|
|
766
|
+
conformance. Passing the suite is what conformance means here. This inverts the
|
|
767
|
+
original relationship: tmct was lifted out of seonix, and seonix now reorients
|
|
768
|
+
as a *user* that imports the tmct library and exposes its graph to tmct as a
|
|
769
|
+
service. The LLM agent stays outside tmct, as the no-LLM ethos requires.
|
|
532
770
|
|
|
533
771
|
## Security and supply chain
|
|
534
772
|
|
|
@@ -546,16 +784,17 @@ cross-version-stable fact-id contract has exactly one definition.
|
|
|
546
784
|
## Provenance
|
|
547
785
|
|
|
548
786
|
tmct began as a whole-package lift of the seonix chat surface (v0.1.0, then
|
|
549
|
-
published as `@polycode-projects/mct`), and was then reshaped
|
|
550
|
-
fallback, the code-extraction stack, and the MCP server were all removed
|
|
787
|
+
published as `@polycode-projects/mct`), and was then reshaped. The LLM
|
|
788
|
+
fallback, the code-extraction stack, and the MCP server were all removed. The
|
|
551
789
|
naming, license, and memory model were reset to the vision above. See
|
|
552
790
|
`ROADMAP.md` for the phase plan.
|
|
553
791
|
|
|
554
792
|
## Licensing
|
|
555
793
|
|
|
556
|
-
**MPL-2.0.** Free for commercial use
|
|
794
|
+
**MPL-2.0.** Free for commercial use. If you modify the covered files and
|
|
557
795
|
distribute them, you must publish those files' source under the MPL with
|
|
558
|
-
attribution. The copyleft
|
|
796
|
+
attribution. The copyleft applies file by file, not to the whole project. See
|
|
797
|
+
`LICENSE`.
|
|
559
798
|
|
|
560
799
|
Corpus data carries its own licenses, separate from the code: the shipped
|
|
561
800
|
ConceptNet slice is **CC-BY-SA 4.0**, with its own notice alongside it.
|