@lucern/sdk 0.2.0-alpha.2 → 0.2.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,16 +1,22 @@
1
1
  # @lucern/sdk
2
2
 
3
- The TypeScript SDK for Lucern, the reasoning operating system.
3
+ The reasoning operating system for AI-native applications.
4
4
 
5
- Lucern gives your application a knowledge graph that thinks. Beliefs evolve. Evidence compounds. Contradictions surface. Your software does not just store data. It reasons about it.
5
+ Your AI agent reads 50 documents, generates insights, and forgets everything by tomorrow. Every session starts from zero. The same questions get re-investigated. The same dead ends get explored. Nothing compounds.
6
6
 
7
- ## Install
7
+ Lucern gives your agents a reasoning graph that accumulates understanding across sessions, across agents, and across time. Beliefs have confidence scores that change as evidence arrives. Contradictions are detected and tracked. Investigations are structured with hypotheses, evidence, and outcomes. Every mutation is traceable, every decision auditable.
8
8
 
9
9
  ```bash
10
10
  npm install @lucern/sdk
11
11
  ```
12
12
 
13
- ## Quickstart
13
+ ## The Full Developer Journey
14
+
15
+ This walkthrough mirrors what a developer building an AI-powered code review system would experience in a real coding session. Every API call is something you would actually use.
16
+
17
+ ### 1. Set Up Your Reasoning Scope
18
+
19
+ Topics are how you organize knowledge. They nest hierarchically, like folders that think.
14
20
 
15
21
  ```typescript
16
22
  import { createLucernClient } from "@lucern/sdk";
@@ -20,261 +26,661 @@ const lucern = createLucernClient({
20
26
  baseUrl: "https://api.lucern.ai",
21
27
  });
22
28
 
23
- // 1. Create a topic (a scope for reasoning)
24
- const topic = await lucern.topics.create({
25
- name: "Climate Tech Market Analysis",
29
+ // Create a parent topic for your domain
30
+ const codeQuality = await lucern.topics.create({
31
+ name: "Code Quality Intelligence",
26
32
  type: "domain",
27
33
  });
28
34
 
29
- // 2. State a belief (what you think is true)
30
- const belief = await lucern.beliefs.create({
31
- topicId: topic.data.topicId,
32
- canonicalText: "Carbon capture will reach cost parity with offsets by 2028",
35
+ // Create child topics for specific areas
36
+ const securityTopic = await lucern.topics.create({
37
+ name: "Security Patterns",
38
+ type: "theme",
39
+ parentTopicId: codeQuality.data.topicId,
33
40
  });
34
41
 
35
- // 3. Ground it in evidence
36
- await lucern.evidence.create({
37
- topicId: topic.data.topicId,
38
- text: "DOE report shows capture costs fell 40% in 2025, projecting $80/ton by 2027",
39
- sourceUrl: "https://energy.gov/reports/carbon-capture-2025",
40
- targetId: belief.data.nodeId,
41
- weight: 0.85,
42
+ const performanceTopic = await lucern.topics.create({
43
+ name: "Performance Patterns",
44
+ type: "theme",
45
+ parentTopicId: codeQuality.data.topicId,
42
46
  });
47
+ ```
48
+
49
+ ### 2. Populate the Graph With What You Know
43
50
 
44
- // 4. Score your confidence
45
- await lucern.beliefs.modulateConfidence(belief.data.nodeId, {
46
- confidence: 0.78,
51
+ Beliefs represent understanding at different epistemic levels: facts (verified), beliefs (confident), hypotheses (testing), and assumptions (untested).
52
+
53
+ ```typescript
54
+ const topicId = securityTopic.data.topicId;
55
+
56
+ // A fact — verified and anchored
57
+ const sqlFact = await lucern.beliefs.create({
58
+ topicId,
59
+ canonicalText: "Parameterized queries prevent SQL injection in all major database drivers",
60
+ beliefType: "fact",
61
+ });
62
+ await lucern.beliefs.modulateConfidence(sqlFact.data.nodeId, {
63
+ confidence: 0.95,
47
64
  trigger: "evidence_added",
48
- rationale: "DOE data supports the trajectory, but assumes continued policy support",
65
+ rationale: "OWASP verified, industry standard for 20+ years",
49
66
  });
50
67
 
51
- // 5. Ask what would change your mind
52
- await lucern.questions.create({
53
- topicId: topic.data.topicId,
54
- text: "What happens to capture economics if the IRA tax credits expire in 2026?",
55
- priority: "high",
56
- linkedBeliefId: belief.data.nodeId,
68
+ // A belief confident from observation
69
+ const patternBelief = await lucern.beliefs.create({
70
+ topicId,
71
+ canonicalText: "Most security vulnerabilities in our codebase come from unvalidated user input at API boundaries, not from cryptographic weaknesses",
72
+ });
73
+ await lucern.beliefs.modulateConfidence(patternBelief.data.nodeId, {
74
+ confidence: 0.82,
75
+ trigger: "evidence_added",
76
+ rationale: "Last 6 months of security audits: 14 input validation issues, 1 crypto issue",
77
+ });
78
+
79
+ // A hypothesis — under active testing
80
+ const hypothesis = await lucern.beliefs.create({
81
+ topicId,
82
+ canonicalText: "Automated static analysis catches fewer than 30% of the input validation vulnerabilities that human reviewers find",
83
+ beliefType: "hypothesis",
84
+ });
85
+ await lucern.beliefs.modulateConfidence(hypothesis.data.nodeId, {
86
+ confidence: 0.6,
87
+ trigger: "manual",
88
+ rationale: "Anecdotal — need to run a proper comparison study",
89
+ });
90
+
91
+ // An assumption — untested but used as a basis for decisions
92
+ const assumption = await lucern.beliefs.create({
93
+ topicId,
94
+ canonicalText: "Our CI pipeline runs all static analysis rules on every PR",
95
+ beliefType: "assumption",
57
96
  });
58
97
  ```
59
98
 
60
- Five calls. A living knowledge graph with a belief grounded in evidence, scored with confidence, and tested by a question. The graph remembers everything: what you believed, when you believed it, and why.
99
+ ### 3. Connect Beliefs With Edges
100
+
101
+ Edges express the reasoning relationships between beliefs.
102
+
103
+ ```typescript
104
+ // The pattern belief depends on the SQL injection fact
105
+ await lucern.graph.createEdge({
106
+ topicId,
107
+ sourceId: patternBelief.data.nodeId,
108
+ targetId: sqlFact.data.nodeId,
109
+ edgeType: "depends_on",
110
+ reasoning: "Input validation pattern includes SQL injection as a subclass",
111
+ reasoningMethod: "deductive",
112
+ });
113
+
114
+ // The hypothesis is derived from the pattern belief
115
+ await lucern.graph.createEdge({
116
+ topicId,
117
+ sourceId: hypothesis.data.nodeId,
118
+ targetId: patternBelief.data.nodeId,
119
+ edgeType: "derived_from",
120
+ reasoning: "If most vulns are input validation, and static analysis misses them, the tooling gap is at the input boundary",
121
+ reasoningMethod: "inductive",
122
+ });
123
+
124
+ // The hypothesis depends on an untested assumption
125
+ await lucern.graph.createEdge({
126
+ topicId,
127
+ sourceId: hypothesis.data.nodeId,
128
+ targetId: assumption.data.nodeId,
129
+ edgeType: "depends_on",
130
+ reasoning: "If the CI pipeline is not running all rules, the comparison would be invalid",
131
+ reasoningMethod: "deductive",
132
+ });
133
+ ```
134
+
135
+ ### 4. Open an Investigation With a Worktree
136
+
137
+ Worktrees are focused investigations — like a feature branch for knowledge. You test beliefs, gather evidence, and merge the findings.
138
+
139
+ ```typescript
140
+ const investigation = await lucern.worktrees.create({
141
+ topicId,
142
+ title: "Static analysis vs human review comparison",
143
+ hypothesis: "Running the same 50 PRs through both static analysis and manual review will show static analysis catches less than 30% of what humans find",
144
+ beliefIds: [hypothesis.data.nodeId],
145
+ });
146
+
147
+ // Create tasks to drive the investigation
148
+ await lucern.tasks.create({
149
+ topicId,
150
+ title: "Run Semgrep + CodeQL on the last 50 merged PRs and log findings",
151
+ linkedWorktreeId: investigation.data.worktreeId,
152
+ linkedQuestionId: comparisonQuestion.data.questionId,
153
+ taskType: "data_collection",
154
+ });
155
+
156
+ await lucern.tasks.create({
157
+ topicId,
158
+ title: "Have two senior engineers independently review the same 50 PRs",
159
+ linkedWorktreeId: investigation.data.worktreeId,
160
+ taskType: "research",
161
+ });
162
+ ```
61
163
 
62
- ## What Makes This Different
164
+ ### 5. Add Evidence as You Work
63
165
 
64
- Most knowledge tools store facts. Lucern tracks how understanding evolves.
166
+ Your agent processes the results and commits evidence to the graph.
65
167
 
66
168
  ```typescript
67
- // New evidence contradicts your belief
169
+ // Static analysis results
170
+ await lucern.evidence.create({
171
+ topicId,
172
+ text: "Semgrep + CodeQL found 23 issues across 50 PRs. 18 were true positives. Categories: 12 input validation, 4 auth bypass patterns, 2 information disclosure.",
173
+ sourceUrl: "ci://semgrep-run/batch-50pr-comparison",
174
+ targetId: hypothesis.data.nodeId,
175
+ weight: 0.6, // partially supports
176
+ });
177
+
178
+ // Human review results
68
179
  await lucern.evidence.create({
69
180
  topicId,
70
- text: "Shell exits direct air capture citing unfavorable unit economics at scale",
71
- sourceUrl: "https://reuters.com/shell-dac-exit-2026",
72
- targetId: belief.data.nodeId,
73
- weight: -0.6,
181
+ text: "Two senior engineers found 41 issues across the same 50 PRs (34 unique after dedup). Categories: 22 input validation, 7 business logic flaws, 3 auth, 2 race conditions.",
182
+ sourceUrl: "review://manual-audit/batch-50pr",
183
+ targetId: hypothesis.data.nodeId,
184
+ weight: 0.9, // strongly supports — 18/34 = 53%, even worse than hypothesized
185
+ });
186
+
187
+ // Answer the question with data
188
+ const comparisonQuestion = await lucern.questions.create({
189
+ topicId,
190
+ text: "What percentage of vulnerabilities does static analysis catch compared to human reviewers?",
191
+ priority: "high",
192
+ linkedBeliefId: hypothesis.data.nodeId,
74
193
  });
75
194
 
76
- // Your confidence changes
77
- await lucern.beliefs.modulateConfidence(belief.data.nodeId, {
78
- confidence: 0.55,
195
+ await lucern.questions.answer(comparisonQuestion.data.questionId, {
196
+ text: "Static analysis caught 18 of 34 unique issues (53%). However, it missed all 7 business logic flaws and both race conditions — categories where it found 0%.",
197
+ confidence: "strong",
198
+ evidenceIds: [staticEvidence.data.nodeId, humanEvidence.data.nodeId],
199
+ });
200
+ ```
201
+
202
+ ### 6. Fork a Belief When Understanding Evolves
203
+
204
+ The original hypothesis said "less than 30%." The data shows 53% — but the story is more nuanced. Fork the belief to capture the evolved understanding.
205
+
206
+ ```typescript
207
+ // Drop confidence on the original (it was too pessimistic about overall catch rate)
208
+ await lucern.beliefs.modulateConfidence(hypothesis.data.nodeId, {
209
+ confidence: 0.2,
79
210
  trigger: "evidence_added",
80
- rationale: "Major industry exit signals real-world cost barriers beyond DOE projections",
211
+ rationale: "Static analysis catches 53% overall, not <30%. But the category breakdown reveals something more important.",
81
212
  });
82
213
 
83
- // Flag the tension explicitly
84
- await lucern.contradictions.flag({
214
+ // Fork into a more precise belief
215
+ const evolved = await lucern.beliefs.fork(hypothesis.data.nodeId, {
216
+ newFormulation: "Static analysis catches 53% of vulnerabilities overall, but has a complete blind spot for business logic flaws and race conditions — the hardest categories to detect",
217
+ forkReason: "refinement",
218
+ });
219
+
220
+ await lucern.beliefs.modulateConfidence(evolved.data.nodeId, {
221
+ confidence: 0.88,
222
+ trigger: "evidence_added",
223
+ rationale: "Direct comparison data: 0/7 business logic flaws caught, 0/2 race conditions caught, while input validation catch rate was 12/22 (55%)",
224
+ });
225
+
226
+ // This creates a new actionable belief
227
+ const actionable = await lucern.beliefs.create({
85
228
  topicId,
86
- beliefA: belief.data.nodeId,
87
- beliefB: optimisticBelief.nodeId,
88
- description: "DOE projections vs Shell operational exit: lab costs vs deployed costs",
89
- severity: "high",
90
- defeatType: "undercuts",
229
+ canonicalText: "Human code review should focus on business logic and concurrency — the categories where static analysis provides zero coverage",
230
+ beliefType: "belief",
91
231
  });
232
+
233
+ await lucern.beliefs.modulateConfidence(actionable.data.nodeId, {
234
+ confidence: 0.85,
235
+ trigger: "worktree_outcome",
236
+ rationale: "Direct implication of the comparison study findings",
237
+ });
238
+
239
+ // Link them
240
+ await lucern.graph.createEdge({
241
+ topicId,
242
+ sourceId: actionable.data.nodeId,
243
+ targetId: evolved.data.nodeId,
244
+ edgeType: "derived_from",
245
+ reasoning: "The review focus recommendation follows directly from the coverage gap data",
246
+ reasoningMethod: "deductive",
247
+ });
248
+ ```
249
+
250
+ ### 7. Compile Context for Your Next Agent Session
251
+
252
+ Before your agent starts its next session, it reads the graph:
253
+
254
+ ```typescript
255
+ const context = await lucern.context.compile(topicId, {
256
+ query: "code review strategy and static analysis coverage",
257
+ ranking: "weighted_v1",
258
+ tokenBudget: 2000,
259
+ });
260
+
261
+ // context.data contains:
262
+ // - activeBeliefs: ranked by confidence and relevance
263
+ // - openQuestions: what still needs investigation
264
+ // - contradictions: tensions the agent should address
265
+ // - recentEvidence: latest findings for grounding
266
+
267
+ // Your agent starts from understanding, not from zero
268
+ console.log(`
269
+ ${context.data.summary.totalBeliefs} beliefs in scope
270
+ ${context.data.summary.openQuestions} open questions
271
+ ${context.data.summary.contradictions} unresolved contradictions
272
+ `);
92
273
  ```
93
274
 
94
- You started at 78% confidence. New evidence dropped you to 55%. There is an unresolved contradiction between the optimistic projection and the market reality. Every step is traceable. Every change has a rationale. Nothing is silently overwritten.
275
+ This is the compound intelligence loop. Every session reads the graph, reasons against it, and writes findings back. The graph gets smarter every cycle.
276
+
277
+ ---
95
278
 
96
279
  ## Core Concepts
97
280
 
98
- | Concept | What It Is | Git Analogy |
99
- |---------|-----------|-------------|
100
- | **Topic** | A scope for reasoning about something | A repository |
101
- | **Belief** | A statement held to be true, with confidence | A commit (immutable once scored) |
102
- | **Evidence** | A fact that supports or contradicts a belief | A test result |
103
- | **Question** | Something that needs investigation | An open issue |
104
- | **Contradiction** | Two beliefs in tension | A merge conflict that may stay unresolved |
105
- | **Worktree** | A focused investigation into specific beliefs | A feature branch |
106
- | **Confidence** | How sure you are (0 to 1), append-only history | Build status, changes with every test |
281
+ | Concept | What It Does |
282
+ |---------|-------------|
283
+ | **Topic** | Scopes reasoning into a domain. Topics nest hierarchically. |
284
+ | **Belief** | A statement with a confidence score. Types: fact, belief, hypothesis, assumption. |
285
+ | **Evidence** | A weighted fact linked to beliefs. Positive weight supports, negative contradicts. |
286
+ | **Question** | An open investigation. Linked to the belief it tests. |
287
+ | **Contradiction** | An explicit tension between two beliefs. May remain permanently unresolved. |
288
+ | **Worktree** | A focused investigation. Create hypotheses, gather evidence, merge findings. |
289
+ | **Edge** | A typed relationship: supports, informs, depends_on, derived_from, contains, tests. |
290
+ | **Confidence** | 0 to 1 score with append-only history. Every change has a trigger and rationale. |
291
+ | **Task** | Execution work linked to a question or worktree. |
292
+ | **Context Pack** | The graph compiled into ranked, budgeted context for LLM injection. |
107
293
 
108
294
  ## SDK Surface
109
295
 
110
296
  ```typescript
111
297
  const lucern = createLucernClient({ apiKey, baseUrl });
112
298
 
113
- // Knowledge primitives
114
- lucern.beliefs // Create, fork, archive, score beliefs
115
- lucern.evidence // Add evidence, link to beliefs and questions
116
- lucern.questions // Ask questions, answer them, track status
117
- lucern.contradictions // Flag and manage tensions between beliefs
118
-
119
- // Structure
120
- lucern.topics // Scope your reasoning into domains
121
- lucern.worktrees // Focused investigations (feature branches for knowledge)
122
- lucern.ontologies // Define your domain vocabulary
123
-
124
- // Intelligence
125
- lucern.graph // Traverse, analyze, detect bias, find gaps
126
- lucern.context // Compile context packs for AI agents
127
- lucern.search // Semantic search across the graph
128
-
129
- // Operations
130
- lucern.tasks // Track execution work tied to questions
131
- lucern.audit // Full audit trail, every mutation, every actor
132
- lucern.identity // Manage principals, sessions, API keys
299
+ lucern.beliefs // Create, fork, score, archive
300
+ lucern.evidence // Add weighted evidence, link to beliefs
301
+ lucern.questions // Ask, answer, track status
302
+ lucern.contradictions // Flag tensions between beliefs
303
+ lucern.topics // Nested topic hierarchy
304
+ lucern.worktrees // Focused investigations
305
+ lucern.graph // Edges, traversal, structural analysis
306
+ lucern.context // Compile graph into agent-ready context
307
+ lucern.ontologies // Domain vocabulary
308
+ lucern.tasks // Execution tracking
309
+ lucern.audit // Full mutation history
310
+ lucern.identity // API keys and sessions
311
+ ```
312
+
313
+ ## Graph Intelligence
314
+
315
+ The graph doesn't just store knowledge — it analyzes itself.
316
+
317
+ ### Structural Analysis
318
+
319
+ ```typescript
320
+ // Run the full analysis suite: PageRank, Louvain clustering,
321
+ // Tarjan SCC, spectral analysis, confirmation bias detection
322
+ const analysis = await lucern.graph.analyze({ topicId });
323
+
324
+ // Which beliefs are most central to your reasoning?
325
+ analysis.data.pageRank.topNodes.forEach(node => {
326
+ console.log(`${node.canonicalText} — centrality: ${node.score}`);
327
+ });
328
+
329
+ // Are there isolated belief clusters that should be connected?
330
+ analysis.data.communities.forEach(cluster => {
331
+ console.log(`Cluster "${cluster.label}": ${cluster.nodeCount} beliefs`);
332
+ });
333
+
334
+ // Any circular dependencies in your reasoning?
335
+ if (analysis.data.cycles.length > 0) {
336
+ console.warn(`Found ${analysis.data.cycles.length} circular reasoning chains`);
337
+ }
133
338
  ```
134
339
 
135
- ## Build Agents That Reason
340
+ ### Confirmation Bias Detection
341
+
342
+ ```typescript
343
+ // Are you only collecting evidence that supports your beliefs?
344
+ const bias = await lucern.graph.detectBias({ topicId });
345
+
346
+ bias.data.beliefs.forEach(b => {
347
+ if (b.riskLevel === "critical") {
348
+ console.warn(
349
+ `"${b.canonicalText}" has ${b.supportingEvidence} supporting ` +
350
+ `and ${b.contradictingEvidence} contradicting evidence — ` +
351
+ `one-sided evidence base`
352
+ );
353
+ }
354
+ });
355
+ ```
136
356
 
137
- Lucern is built for AI agents that need to think, not just retrieve.
357
+ ### Find Gaps in Your Reasoning
358
+
359
+ ```typescript
360
+ // What beliefs have no evidence? What questions have no answers?
361
+ const gaps = await lucern.graph.findGaps({ topicId });
362
+
363
+ console.log(`Beliefs without evidence: ${gaps.data.unsupportedBeliefs.length}`);
364
+ console.log(`Beliefs without questions: ${gaps.data.untestedBeliefs.length}`);
365
+ console.log(`Orphan evidence: ${gaps.data.unlinkedEvidence.length}`);
366
+ ```
367
+
368
+ ### Falsification — What Would Disprove Your Beliefs?
369
+
370
+ ```typescript
371
+ // Generate the questions most likely to disprove your strongest beliefs
372
+ const questions = await lucern.graph.falsify({ topicId });
373
+
374
+ questions.data.forEach(q => {
375
+ console.log(`To disprove "${q.beliefText}", ask: "${q.question}"`);
376
+ });
377
+ ```
378
+
379
+ ### Traverse the Graph
380
+
381
+ ```typescript
382
+ // Walk the reasoning chain from a belief down to its evidence
383
+ const traversal = await lucern.graph.traverse({
384
+ startNodeId: belief.data.nodeId,
385
+ direction: "down", // L3 belief -> L2 evidence -> L1 sources
386
+ maxDepth: 3,
387
+ });
388
+
389
+ traversal.data.nodes.forEach(node => {
390
+ console.log(`[${node.epistemicLayer}] ${node.canonicalText}`);
391
+ });
392
+ ```
393
+
394
+ ## LLM Integration Patterns
395
+
396
+ ### Inject Reasoning Context Into Any LLM Call
138
397
 
139
398
  ```typescript
140
- // Compile the current understanding into a context pack
141
399
  const context = await lucern.context.compile(topicId, {
142
- query: "What do we know about carbon capture economics?",
400
+ query: "security review priorities",
143
401
  ranking: "weighted_v1",
144
- tokenBudget: 2000,
402
+ tokenBudget: 3000,
403
+ includeEntities: true,
145
404
  });
146
405
 
147
- // Feed it to your LLM as grounded context
148
- const response = await llm.generate({
149
- system: `You are a research analyst. Here is your current knowledge state:
406
+ // The context pack is structured for direct prompt injection
407
+ const systemPrompt = `
408
+ You are a security-focused code reviewer. Your reasoning state:
409
+
410
+ FACTS (high confidence, treat as ground truth):
411
+ ${context.data.invariants
412
+ .map(b => `- [${b.confidence}] ${b.canonicalText}`)
413
+ .join("\n")}
414
+
415
+ ACTIVE BELIEFS (current understanding, may evolve):
416
+ ${context.data.activeBeliefs
417
+ .map(b => `- [${b.confidence}] ${b.canonicalText}`)
418
+ .join("\n")}
419
+
420
+ OPEN QUESTIONS (unresolved — investigate these):
421
+ ${context.data.openQuestions
422
+ .map(q => `- [${q.priority}] ${q.text}`)
423
+ .join("\n")}
424
+
425
+ CONTRADICTIONS (tensions you must address):
426
+ ${context.data.contradictions
427
+ .map(c => `- [${c.severity}] ${c.description}`)
428
+ .join("\n")}
429
+
430
+ RULES:
431
+ - If your analysis contradicts an active belief, flag it explicitly
432
+ - If you discover evidence for an open question, answer it
433
+ - Never silently override a high-confidence belief without evidence
434
+ - When uncertain, create a new question rather than stating a conclusion
435
+ `;
436
+ ```
150
437
 
151
- Beliefs (ranked by relevance):
152
- ${context.data.activeBeliefs
153
- .map((b) => `[${b.confidence}] ${b.canonicalText}`)
154
- .join("\n ")}
438
+ ### Let the LLM Write Back to the Graph
439
+
440
+ ```typescript
441
+ // After your LLM generates analysis, parse its output
442
+ // and write structured findings back to the graph
443
+
444
+ const findings = await llm.generate({
445
+ system: systemPrompt,
446
+ prompt: `Review this PR diff and identify security concerns:\n${prDiff}`,
447
+ tools: [{
448
+ name: "record_finding",
449
+ description: "Record a security finding as evidence in the reasoning graph",
450
+ parameters: {
451
+ finding: { type: "string" },
452
+ severity: { type: "string", enum: ["low", "medium", "high", "critical"] },
453
+ relatedBeliefId: { type: "string", description: "ID of the belief this relates to" },
454
+ supportsOrContradicts: { type: "number", description: "-1 to 1" },
455
+ },
456
+ }],
457
+ });
458
+
459
+ // Each tool call becomes evidence in the graph
460
+ for (const call of findings.toolCalls) {
461
+ await lucern.evidence.create({
462
+ topicId,
463
+ text: call.args.finding,
464
+ sourceUrl: `pr://review/${prNumber}`,
465
+ targetId: call.args.relatedBeliefId,
466
+ weight: call.args.supportsOrContradicts,
467
+ });
468
+ }
469
+ ```
155
470
 
156
- Open Questions:
157
- ${context.data.openQuestions.map((q) => q.text).join("\n ")}
471
+ ### Search the Graph Semantically
158
472
 
159
- Unresolved Contradictions:
160
- ${context.data.contradictions.map((c) => c.description).join("\n ")}
473
+ ```typescript
474
+ // Find beliefs related to a natural language query
475
+ const results = await lucern.search.beliefs({
476
+ topicId,
477
+ query: "race conditions in authentication",
478
+ minConfidence: 0.5,
479
+ limit: 10,
480
+ });
161
481
 
162
- Reason from this foundation. When your analysis conflicts with
163
- existing beliefs, say so explicitly.`,
164
- prompt: userQuery,
482
+ results.data.forEach(b => {
483
+ console.log(`[${b.confidence}] ${b.canonicalText}`);
165
484
  });
166
485
 
167
- // Write the agent findings back to the graph
168
- await lucern.evidence.create({
486
+ // Search evidence
487
+ const evidence = await lucern.search.evidence({
169
488
  topicId,
170
- text: response.analysis,
171
- sourceUrl: "agent://research-analyst/session-42",
172
- targetId: relevantBeliefId,
173
- weight: 0.7,
489
+ query: "token refresh timing data",
490
+ limit: 5,
174
491
  });
175
492
  ```
176
493
 
177
- Every time an agent reads from the graph and writes back, the graph gets smarter. This is the compound intelligence loop.
494
+ ## Agent Configuration
178
495
 
179
- ## Evolving Understanding
496
+ ### CLAUDE.md / AGENTS.md Integration
180
497
 
181
- Beliefs are immutable once scored, like git commits. When understanding evolves, you fork:
498
+ Add Lucern context to your coding agent's system instructions:
182
499
 
183
- ```typescript
184
- const forked = await lucern.beliefs.fork(originalBelief.nodeId, {
185
- newFormulation:
186
- "Carbon capture will remain 2-3x more expensive than offsets through 2030, " +
187
- "with deployment limited to regulated industries where offsets are not accepted",
188
- forkReason: "contradiction_response",
500
+ ```markdown
501
+ <!-- In your CLAUDE.md or AGENTS.md -->
502
+
503
+ ## Reasoning Graph
504
+
505
+ This project uses Lucern for knowledge management. Before making
506
+ architectural decisions, check the reasoning graph:
507
+
508
+ - Read current beliefs: `lucern.beliefs.list({ topicId: "..." })`
509
+ - Check for contradictions: `lucern.contradictions.list({ topicId: "..." })`
510
+ - Compile context before analysis: `lucern.context.compile(topicId, { query: "..." })`
511
+
512
+ After making decisions, write them back:
513
+ - Create beliefs for architectural decisions
514
+ - Add evidence linking to the code/PR that validates them
515
+ - Flag contradictions when new evidence conflicts with existing beliefs
516
+ - Answer open questions when your work resolves them
517
+
518
+ Confidence scale:
519
+ - 0.90+: Verified in production
520
+ - 0.80-0.90: Strong evidence, working implementation
521
+ - 0.70-0.80: Directionally right, needs validation
522
+ - Below 0.70: Hypothesis, needs investigation
523
+ ```
524
+
525
+ ### Claude Code Skill
526
+
527
+ Create a Lucern skill for your coding agents at `~/.claude/skills/lucern-sdk/SKILL.md`:
528
+
529
+ ```markdown
530
+ # Lucern SDK Skill
531
+
532
+ Use this skill when building features that read or write to the
533
+ reasoning graph, or when the user asks about beliefs, evidence,
534
+ contradictions, or knowledge state.
535
+
536
+ ## Before Starting Work
537
+
538
+ Compile the current context to understand what the graph knows:
539
+
540
+ \`\`\`typescript
541
+ const context = await lucern.context.compile(topicId, {
542
+ query: "<what you're working on>",
543
+ tokenBudget: 2000,
189
544
  });
545
+ \`\`\`
190
546
 
191
- await lucern.beliefs.modulateConfidence(forked.data.nodeId, {
192
- confidence: 0.82,
193
- trigger: "evidence_added",
194
- rationale: "Three independent operator reports confirm cost barriers persist",
547
+ Check for open questions related to your task. If one exists, your work
548
+ should aim to answer it.
549
+
550
+ ## After Completing Work
551
+
552
+ Record what you learned:
553
+
554
+ \`\`\`typescript
555
+ // Create a belief for decisions made
556
+ await lucern.beliefs.create({
557
+ topicId,
558
+ canonicalText: "<what you now believe to be true>",
195
559
  });
196
560
 
197
- await lucern.beliefs.modulateConfidence(originalBelief.nodeId, {
198
- confidence: 0,
199
- trigger: "evidence_added",
200
- rationale: "Superseded by forked belief incorporating operator data",
561
+ // Add evidence from your implementation
562
+ await lucern.evidence.create({
563
+ topicId,
564
+ text: "<what you observed or built>",
565
+ sourceUrl: "commit://<sha>",
566
+ targetId: beliefId,
567
+ weight: 0.8,
201
568
  });
202
- ```
203
569
 
204
- The lineage is permanent. You can trace how understanding moved from one belief to another, through what evidence, at what confidence.
570
+ // Answer questions your work resolved
571
+ await lucern.questions.answer(questionId, {
572
+ text: "<the answer>",
573
+ confidence: "strong",
574
+ });
575
+ \`\`\`
576
+ ```
205
577
 
206
- ## Custom Tools
578
+ ### Custom Tool Registration for Agents
207
579
 
208
- Extend the graph with domain-specific operations that any agent can invoke:
580
+ Give your agents domain-specific capabilities that interact with the graph:
209
581
 
210
582
  ```typescript
211
- import { z } from "zod";
212
-
213
583
  lucern.tools.register({
214
- namespace: "research",
215
- name: "analyze_transcript",
216
- description: "Extract beliefs and evidence from a meeting transcript",
584
+ namespace: "codebase",
585
+ name: "trace_dependency",
586
+ description: "Trace how a code change would affect beliefs in the reasoning graph",
217
587
  inputSchema: z.object({
218
- transcriptUrl: z.string().url(),
588
+ filePath: z.string(),
589
+ changeDescription: z.string(),
219
590
  topicId: z.string(),
220
591
  }),
221
592
  outputSchema: z.object({
222
- beliefs: z.array(z.object({ text: z.string(), confidence: z.number() })),
223
- evidence: z.array(z.object({ text: z.string(), sourceUrl: z.string() })),
593
+ affectedBeliefs: z.array(z.object({
594
+ beliefId: z.string(),
595
+ text: z.string(),
596
+ currentConfidence: z.number(),
597
+ impact: z.enum(["strengthens", "weakens", "invalidates"]),
598
+ })),
224
599
  }),
225
- handler: async ({ transcriptUrl, topicId }) => {
226
- const transcript = await fetchTranscript(transcriptUrl);
227
- return extractInsights(transcript, topicId);
600
+ handler: async ({ filePath, changeDescription, topicId }) => {
601
+ // Search for beliefs related to this file/area
602
+ const related = await lucern.search.beliefs({
603
+ topicId,
604
+ query: `${filePath} ${changeDescription}`,
605
+ });
606
+ // Analyze impact...
607
+ return { affectedBeliefs: analyzeImpact(related, changeDescription) };
228
608
  },
229
609
  });
230
-
231
- await lucern.extensions.research.analyze_transcript({
232
- transcriptUrl: "https://...",
233
- topicId,
234
- });
235
610
  ```
236
611
 
237
- ## Authentication
612
+ ## Worktree Patterns
613
+
614
+ ### List and Resume Investigations
238
615
 
239
616
  ```typescript
240
- // Service principal (server-to-server)
241
- const lucern = createLucernClient({
242
- apiKey: "lk_your_service_principal_key",
243
- baseUrl: "https://api.lucern.ai",
617
+ // See all active investigations
618
+ const worktrees = await lucern.worktrees.list({
619
+ topicId,
620
+ status: "active",
244
621
  });
245
622
 
246
- // Tenant API key (application-level)
247
- const lucern = createLucernClient({
248
- apiKey: "luc_your_tenant_api_key",
249
- baseUrl: "https://api.lucern.ai",
623
+ worktrees.data.forEach(wt => {
624
+ console.log(`${wt.title} phase: ${wt.phase}, beliefs: ${wt.beliefCount}`);
250
625
  });
626
+
627
+ // Get the full state of an investigation
628
+ const investigation = await lucern.worktrees.get(worktreeId);
629
+ console.log(`Hypothesis: ${investigation.data.hypothesis}`);
630
+ console.log(`Questions: ${investigation.data.questionCount} open`);
631
+ console.log(`Evidence: ${investigation.data.evidenceCount} collected`);
251
632
  ```
252
633
 
253
- ## Confidence Scale
634
+ ### Merge an Investigation
635
+
636
+ When the investigation is complete, merge findings into the main graph:
254
637
 
255
- | Range | Meaning |
256
- |-------|---------|
257
- | 0.90-0.95 | Structural law, verified by multiple independent sources |
258
- | 0.85-0.90 | Strong conviction, working implementation validates it |
259
- | 0.80-0.85 | Confident, evidence supports it, not yet stress-tested |
260
- | 0.70-0.80 | Directionally right, good signal, details still emerging |
261
- | 0.50-0.70 | Hypothesis, plausible but needs investigation |
262
- | Below 0.50 | Weak signal, more question than answer |
263
- | 0 | Superseded, replaced by evolved understanding |
638
+ ```typescript
639
+ await lucern.worktrees.merge(worktreeId, {
640
+ summary: "Static analysis catches 53% of vulns overall but has zero coverage for business logic flaws",
641
+ outcomes: [
642
+ {
643
+ beliefId: hypothesis.data.nodeId,
644
+ confidence: 0.2,
645
+ rationale: "Overall catch rate was 53%, not <30% but the category breakdown is more important",
646
+ },
647
+ {
648
+ beliefId: evolved.data.nodeId,
649
+ confidence: 0.88,
650
+ rationale: "Direct comparison data confirms the coverage gap hypothesis at category level",
651
+ },
652
+ ],
653
+ });
654
+ ```
264
655
 
265
- ## TypeScript First
656
+ ## Confidence History
266
657
 
267
- Every response is fully typed. Every parameter has IntelliSense.
658
+ Every confidence change is recorded with full provenance:
268
659
 
269
660
  ```typescript
270
- const belief = await lucern.beliefs.create({
271
- topicId: "...",
272
- canonicalText: "...",
661
+ const history = await lucern.beliefs.confidenceHistory(beliefId);
662
+
663
+ history.data.forEach(entry => {
664
+ console.log(
665
+ `${new Date(entry.timestamp).toISOString()} ` +
666
+ `${entry.previousConfidence} -> ${entry.confidence} ` +
667
+ `[${entry.trigger}] ${entry.rationale}`
668
+ );
273
669
  });
274
670
 
275
- belief.data.nodeId; // string
276
- belief.data.confidence; // number | null
277
- belief.data.status; // "unscored" | "scored" | "archived"
671
+ // Example output:
672
+ // 2026-04-10T14:00:00Z null -> 0.60 [manual] Anecdotal observation
673
+ // 2026-04-11T09:30:00Z 0.60 -> 0.75 [evidence_added] Semgrep data supports
674
+ // 2026-04-11T16:00:00Z 0.75 -> 0.20 [evidence_added] Comparison study contradicted
675
+ ```
676
+
677
+ ## Authentication
678
+
679
+ ```typescript
680
+ const lucern = createLucernClient({
681
+ apiKey: "lk_your_key",
682
+ baseUrl: "https://api.lucern.ai",
683
+ });
278
684
  ```
279
685
 
280
686
  ## Links