@atrib/trace 0.5.14 → 0.5.16

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,8 +1,8 @@
1
1
  # @atrib/trace
2
2
 
3
- MCP server exposing the `trace` tool, walks a record's `informed_by` chain backward to surface the reasoning chain that led to it.
3
+ MCP server exposing the `trace` tool, walks a record's `informed_by` chain backward to surface the signed relationship path that led to it.
4
4
 
5
- Closes the consumer-side cognitive-loop primitive: recall returns raw records; trace returns the causal chain, so an agent asking "why did I do X?" can see "X was informed by Y, which was informed by Z" without manually walking `informed_by` hash-by-hash.
5
+ Closes the consumer-side cognitive-loop primitive: recall returns raw records; trace returns the declared-relationship trace, so an agent asking "why did I do X?" can see "X was claimed to be informed by Y, which was claimed to be informed by Z" without manually walking `informed_by` hash-by-hash.
6
6
 
7
7
  ## Tools
8
8
 
@@ -43,7 +43,7 @@ mcp__atrib-trace__trace_forward({ // FORWARD — what was informed by this?
43
43
  }
44
44
  ```
45
45
 
46
- - `trace` walks `informed_by` BACKWARD (toward causal ancestors). Answers "what informed this record?"
46
+ - `trace` walks `informed_by` BACKWARD (toward declared ancestors). Answers "what did the signer claim informed this record?"
47
47
  - `trace_forward` walks `informed_by` FORWARD (records that cited this one). Answers "I made decision X, what did I do because of it?" The dual of `trace`. Same input schema, same response shape.
48
48
  - For forward walks, `next_informed_by` carries the CHILDREN visited at the next hop (records citing this one) rather than this record's own informed_by — field name kept for shape-compat with `trace`.
49
49
 
package/dist/index.d.ts CHANGED
@@ -3,9 +3,9 @@
3
3
  * informed_by chain backward to surface the reasoning chain that led to it.
4
4
  *
5
5
  * Closes the consumer-side cognitive-loop primitive: recall returns raw
6
- * records; trace returns the causal chain, so an agent asking "why did
7
- * I do X?" can see "X was informed by Y, which was informed by Z" without
8
- * manually walking informed_by hash-by-hash.
6
+ * records; trace returns the declared-relationship path, so an agent asking
7
+ * "why did I do X?" can see "X claimed Y as input, and Y claimed Z as input"
8
+ * without manually walking informed_by hash-by-hash.
9
9
  *
10
10
  * Reads only the local mirror (~/.atrib/records/*.jsonl) for v1, same scope
11
11
  * as recall. v2 will fall back to log.atrib.dev/v1/lookup/<hash> for hashes
@@ -42,6 +42,8 @@ interface CompactVisited {
42
42
  model_name?: string;
43
43
  prompt_version?: string;
44
44
  topics?: string[];
45
+ intent?: string;
46
+ rationale?: string;
45
47
  /**
46
48
  * First 200 chars of the record's human-readable content, derived
47
49
  * per event_type from the @atrib/mcp normative shapes (D086):
package/dist/index.js CHANGED
@@ -4,9 +4,9 @@
4
4
  * informed_by chain backward to surface the reasoning chain that led to it.
5
5
  *
6
6
  * Closes the consumer-side cognitive-loop primitive: recall returns raw
7
- * records; trace returns the causal chain, so an agent asking "why did
8
- * I do X?" can see "X was informed by Y, which was informed by Z" without
9
- * manually walking informed_by hash-by-hash.
7
+ * records; trace returns the declared-relationship path, so an agent asking
8
+ * "why did I do X?" can see "X claimed Y as input, and Y claimed Z as input"
9
+ * without manually walking informed_by hash-by-hash.
10
10
  *
11
11
  * Reads only the local mirror (~/.atrib/records/*.jsonl) for v1, same scope
12
12
  * as recall. v2 will fall back to log.atrib.dev/v1/lookup/<hash> for hashes
@@ -15,30 +15,55 @@
15
15
  */
16
16
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
17
17
  import { z } from 'zod';
18
- import { resolveEnvContextId, logReadPrimitiveCall, } from '@atrib/mcp';
18
+ import { resolveEnvContextId, logReadPrimitiveCall } from '@atrib/mcp';
19
19
  import { loadAllRecords } from './storage.js';
20
20
  import { traceBackward, traceForward } from './trace.js';
21
21
  const SHA256_REF_PATTERN = /^sha256:[0-9a-f]{64}$/;
22
22
  const HEX_32_PATTERN = /^[0-9a-f]{32}$/;
23
23
  const TraceInput = z.object({
24
- record_hash: z.string().regex(SHA256_REF_PATTERN).describe("The 'sha256:<64-hex>' record_hash to start from. Walks backward via " +
24
+ record_hash: z
25
+ .string()
26
+ .regex(SHA256_REF_PATTERN)
27
+ .describe("The 'sha256:<64-hex>' record_hash to start from. Walks backward via " +
25
28
  'informed_by edges from this record.'),
26
- context_id: z.string().regex(HEX_32_PATTERN).optional().describe('Optional 32-hex context_id scope. When set, edges crossing into a ' +
29
+ context_id: z
30
+ .string()
31
+ .regex(HEX_32_PATTERN)
32
+ .optional()
33
+ .describe('Optional 32-hex context_id scope. When set, edges crossing into a ' +
27
34
  'different context_id surface as dangling rather than expanding the ' +
28
35
  'walk. Defaults to process.env.ATRIB_CONTEXT_ID when valid; omit at ' +
29
36
  'the env-var level to walk cross-context. Used by Inspect-style ' +
30
- 'harnesses to keep each arm\'s trace inside its own context per D072.'),
31
- depth: z.number().int().min(0).max(10).optional().describe('Maximum hop count from the starting record. Use 0 to return only ' +
37
+ "harnesses to keep each arm's trace inside its own context per D072."),
38
+ depth: z
39
+ .number()
40
+ .int()
41
+ .min(0)
42
+ .max(10)
43
+ .optional()
44
+ .describe('Maximum hop count from the starting record. Use 0 to return only ' +
32
45
  'the start record. Defaults to 3. Bounded ' +
33
46
  'at 10 to keep responses tractable; deeper chains should be walked ' +
34
47
  'in pieces by re-rooting at a returned upstream hash.'),
35
- max_nodes: z.number().int().min(1).max(500).optional().describe('Hard cap on total visited records. Defaults to 200. Prevents pathological ' +
48
+ max_nodes: z
49
+ .number()
50
+ .int()
51
+ .min(1)
52
+ .max(500)
53
+ .optional()
54
+ .describe('Hard cap on total visited records. Defaults to 200. Prevents pathological ' +
36
55
  'fan-out (a record with hundreds of informed_by entries) from exploding ' +
37
56
  'the response.'),
38
- compact: z.boolean().optional().describe('When true (the default), per-record output omits signature/content_id/' +
57
+ compact: z
58
+ .boolean()
59
+ .optional()
60
+ .describe('When true (the default), per-record output omits signature/content_id/' +
39
61
  'spec_version/chain_root to keep the response small. Set false for full ' +
40
62
  'record bytes (useful for re-verification).'),
41
- include_content: z.boolean().optional().describe('When true and compact=true, include the D062 local mirror body as ' +
63
+ include_content: z
64
+ .boolean()
65
+ .optional()
66
+ .describe('When true and compact=true, include the D062 local mirror body as ' +
42
67
  'local_content and local_producer on each visited record. Defaults false ' +
43
68
  'so trace stays cheap for ordinary causal walks.'),
44
69
  });
@@ -65,8 +90,17 @@ export function summarizeSidecar(loadedRecord) {
65
90
  out.model_name = c['model_name'];
66
91
  if (c && typeof c['prompt_version'] === 'string')
67
92
  out.prompt_version = c['prompt_version'];
93
+ if (c && typeof c['intent'] === 'string') {
94
+ out.intent = c['intent'].length > 200 ? c['intent'].slice(0, 197) + '...' : c['intent'];
95
+ }
96
+ if (c && typeof c['rationale'] === 'string') {
97
+ out.rationale =
98
+ c['rationale'].length > 200 ? c['rationale'].slice(0, 197) + '...' : c['rationale'];
99
+ }
68
100
  if (c && Array.isArray(c['topics'])) {
69
- out.topics = c['topics'].filter((t) => typeof t === 'string').slice(0, 6);
101
+ out.topics = c['topics']
102
+ .filter((t) => typeof t === 'string')
103
+ .slice(0, 6);
70
104
  }
71
105
  // Per-event_type human-readable text. The `what` slot here is generic
72
106
  // (it's the human-scannable summary regardless of event_type); the
@@ -146,8 +180,9 @@ export function extractRecordHashFieldsFromMcpResult(result) {
146
180
  const seen = new Set();
147
181
  const pattern = /^sha256:[0-9a-f]{64}$/;
148
182
  const content = result?.content;
149
- const text = Array.isArray(content) && typeof content[0]?.text === 'string'
150
- ? (content[0].text)
183
+ const text = Array.isArray(content) &&
184
+ typeof content[0]?.text === 'string'
185
+ ? content[0].text
151
186
  : undefined;
152
187
  let root = result;
153
188
  if (text) {
@@ -202,7 +237,7 @@ export async function createAtribTraceServer() {
202
237
  }
203
238
  mcp.registerTool('trace', {
204
239
  title: 'trace informed_by chain backward',
205
- description: 'Walk a record\'s informed_by chain backward to surface the reasoning ' +
240
+ description: "Walk a record's informed_by chain backward to surface the reasoning " +
206
241
  'chain that led to it. Reads from the local signed-record mirror ' +
207
242
  '(~/.atrib/records/*.jsonl). Returns the records visited, parent links ' +
208
243
  'so the caller can reconstruct the tree, and dangling hashes (records ' +
@@ -226,7 +261,12 @@ export async function createAtribTraceServer() {
226
261
  ...(contextId ? { contextId } : {}),
227
262
  });
228
263
  return {
229
- content: [{ type: 'text', text: JSON.stringify(buildPayload(result, byHash, compact, includeContent), null, 2) }],
264
+ content: [
265
+ {
266
+ type: 'text',
267
+ text: JSON.stringify(buildPayload(result, byHash, compact, includeContent), null, 2),
268
+ },
269
+ ],
230
270
  };
231
271
  }, extractRecordHashFieldsFromMcpResult));
232
272
  // Sibling tool: forward walk (records that cited THIS one). Mirrors
@@ -254,7 +294,12 @@ export async function createAtribTraceServer() {
254
294
  ...(contextId ? { contextId } : {}),
255
295
  });
256
296
  return {
257
- content: [{ type: 'text', text: JSON.stringify(buildPayload(result, byHash, compact, includeContent), null, 2) }],
297
+ content: [
298
+ {
299
+ type: 'text',
300
+ text: JSON.stringify(buildPayload(result, byHash, compact, includeContent), null, 2),
301
+ },
302
+ ],
258
303
  };
259
304
  }, extractRecordHashFieldsFromMcpResult));
260
305
  return { mcp };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@atrib/trace",
3
- "version": "0.5.14",
4
- "description": "MCP server for atrib. Walks informed_by chains backward from a record_hash to surface the reasoning chain that produced it.",
3
+ "version": "0.5.16",
4
+ "description": "MCP server for atrib. Walks informed_by chains backward from a record_hash to surface the signed relationship path that produced it.",
5
5
  "author": "atrib <hello@atrib.dev>",
6
6
  "keywords": [
7
7
  "atrib",
@@ -13,7 +13,7 @@
13
13
  "cognitive-primitive",
14
14
  "trace",
15
15
  "provenance",
16
- "causal-chain"
16
+ "lineage"
17
17
  ],
18
18
  "homepage": "https://atrib.dev",
19
19
  "license": "Apache-2.0",
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "@modelcontextprotocol/sdk": "^1.29.0",
27
27
  "zod": "^3.25.76",
28
- "@atrib/mcp": "0.17.5"
28
+ "@atrib/mcp": "0.18.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^25.9.2",