@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 +572 -166
- package/dist/index.js +26 -98
- package/dist/index.js.map +1 -1
- package/dist/packages/sdk/src/contracts/api-enums.contract.d.ts +50 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
# @lucern/sdk
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The reasoning operating system for AI-native applications.
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
//
|
|
24
|
-
const
|
|
25
|
-
name: "
|
|
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
|
-
//
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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: "
|
|
65
|
+
rationale: "OWASP verified, industry standard for 20+ years",
|
|
49
66
|
});
|
|
50
67
|
|
|
51
|
-
//
|
|
52
|
-
await lucern.
|
|
53
|
-
topicId
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
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
|
-
|
|
164
|
+
### 5. Add Evidence as You Work
|
|
63
165
|
|
|
64
|
-
|
|
166
|
+
Your agent processes the results and commits evidence to the graph.
|
|
65
167
|
|
|
66
168
|
```typescript
|
|
67
|
-
//
|
|
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: "
|
|
71
|
-
sourceUrl: "
|
|
72
|
-
targetId:
|
|
73
|
-
weight:
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
confidence:
|
|
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: "
|
|
211
|
+
rationale: "Static analysis catches 53% overall, not <30%. But the category breakdown reveals something more important.",
|
|
81
212
|
});
|
|
82
213
|
|
|
83
|
-
//
|
|
84
|
-
await lucern.
|
|
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
|
-
|
|
87
|
-
|
|
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
|
-
|
|
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
|
|
99
|
-
|
|
100
|
-
| **Topic** |
|
|
101
|
-
| **Belief** | A statement
|
|
102
|
-
| **Evidence** | A fact
|
|
103
|
-
| **Question** |
|
|
104
|
-
| **Contradiction** |
|
|
105
|
-
| **Worktree** | A focused investigation
|
|
106
|
-
| **
|
|
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
|
-
//
|
|
114
|
-
lucern.
|
|
115
|
-
lucern.
|
|
116
|
-
lucern.
|
|
117
|
-
lucern.
|
|
118
|
-
|
|
119
|
-
//
|
|
120
|
-
lucern.
|
|
121
|
-
lucern.
|
|
122
|
-
lucern.
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: "
|
|
400
|
+
query: "security review priorities",
|
|
143
401
|
ranking: "weighted_v1",
|
|
144
|
-
tokenBudget:
|
|
402
|
+
tokenBudget: 3000,
|
|
403
|
+
includeEntities: true,
|
|
145
404
|
});
|
|
146
405
|
|
|
147
|
-
//
|
|
148
|
-
const
|
|
149
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
157
|
-
${context.data.openQuestions.map((q) => q.text).join("\n ")}
|
|
471
|
+
### Search the Graph Semantically
|
|
158
472
|
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
prompt: userQuery,
|
|
482
|
+
results.data.forEach(b => {
|
|
483
|
+
console.log(`[${b.confidence}] ${b.canonicalText}`);
|
|
165
484
|
});
|
|
166
485
|
|
|
167
|
-
//
|
|
168
|
-
await lucern.evidence
|
|
486
|
+
// Search evidence
|
|
487
|
+
const evidence = await lucern.search.evidence({
|
|
169
488
|
topicId,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
targetId: relevantBeliefId,
|
|
173
|
-
weight: 0.7,
|
|
489
|
+
query: "token refresh timing data",
|
|
490
|
+
limit: 5,
|
|
174
491
|
});
|
|
175
492
|
```
|
|
176
493
|
|
|
177
|
-
|
|
494
|
+
## Agent Configuration
|
|
178
495
|
|
|
179
|
-
|
|
496
|
+
### CLAUDE.md / AGENTS.md Integration
|
|
180
497
|
|
|
181
|
-
|
|
498
|
+
Add Lucern context to your coding agent's system instructions:
|
|
182
499
|
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
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
|
-
|
|
578
|
+
### Custom Tool Registration for Agents
|
|
207
579
|
|
|
208
|
-
|
|
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: "
|
|
215
|
-
name: "
|
|
216
|
-
description: "
|
|
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
|
-
|
|
588
|
+
filePath: z.string(),
|
|
589
|
+
changeDescription: z.string(),
|
|
219
590
|
topicId: z.string(),
|
|
220
591
|
}),
|
|
221
592
|
outputSchema: z.object({
|
|
222
|
-
|
|
223
|
-
|
|
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 ({
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
##
|
|
612
|
+
## Worktree Patterns
|
|
613
|
+
|
|
614
|
+
### List and Resume Investigations
|
|
238
615
|
|
|
239
616
|
```typescript
|
|
240
|
-
//
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
617
|
+
// See all active investigations
|
|
618
|
+
const worktrees = await lucern.worktrees.list({
|
|
619
|
+
topicId,
|
|
620
|
+
status: "active",
|
|
244
621
|
});
|
|
245
622
|
|
|
246
|
-
|
|
247
|
-
|
|
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
|
-
|
|
634
|
+
### Merge an Investigation
|
|
635
|
+
|
|
636
|
+
When the investigation is complete, merge findings into the main graph:
|
|
254
637
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
##
|
|
656
|
+
## Confidence History
|
|
266
657
|
|
|
267
|
-
Every
|
|
658
|
+
Every confidence change is recorded with full provenance:
|
|
268
659
|
|
|
269
660
|
```typescript
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|