agent-relay 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +18 -6
  2. package/dist/cli/index.d.ts +2 -0
  3. package/dist/cli/index.d.ts.map +1 -1
  4. package/dist/cli/index.js +344 -3
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/daemon/agent-registry.d.ts +60 -0
  7. package/dist/daemon/agent-registry.d.ts.map +1 -0
  8. package/dist/daemon/agent-registry.js +158 -0
  9. package/dist/daemon/agent-registry.js.map +1 -0
  10. package/dist/daemon/connection.d.ts +11 -1
  11. package/dist/daemon/connection.d.ts.map +1 -1
  12. package/dist/daemon/connection.js +31 -2
  13. package/dist/daemon/connection.js.map +1 -1
  14. package/dist/daemon/index.d.ts +2 -0
  15. package/dist/daemon/index.d.ts.map +1 -1
  16. package/dist/daemon/index.js +2 -0
  17. package/dist/daemon/index.js.map +1 -1
  18. package/dist/daemon/registry.d.ts +9 -0
  19. package/dist/daemon/registry.d.ts.map +1 -0
  20. package/dist/daemon/registry.js +9 -0
  21. package/dist/daemon/registry.js.map +1 -0
  22. package/dist/daemon/router.d.ts +34 -2
  23. package/dist/daemon/router.d.ts.map +1 -1
  24. package/dist/daemon/router.js +111 -1
  25. package/dist/daemon/router.js.map +1 -1
  26. package/dist/daemon/server.d.ts +1 -0
  27. package/dist/daemon/server.d.ts.map +1 -1
  28. package/dist/daemon/server.js +60 -13
  29. package/dist/daemon/server.js.map +1 -1
  30. package/dist/dashboard/public/index.html +625 -16
  31. package/dist/dashboard/server.d.ts +1 -1
  32. package/dist/dashboard/server.d.ts.map +1 -1
  33. package/dist/dashboard/server.js +125 -7
  34. package/dist/dashboard/server.js.map +1 -1
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/protocol/types.d.ts +15 -1
  38. package/dist/protocol/types.d.ts.map +1 -1
  39. package/dist/storage/adapter.d.ts +53 -0
  40. package/dist/storage/adapter.d.ts.map +1 -1
  41. package/dist/storage/adapter.js +3 -0
  42. package/dist/storage/adapter.js.map +1 -1
  43. package/dist/storage/sqlite-adapter.d.ts +58 -1
  44. package/dist/storage/sqlite-adapter.d.ts.map +1 -1
  45. package/dist/storage/sqlite-adapter.js +374 -47
  46. package/dist/storage/sqlite-adapter.js.map +1 -1
  47. package/dist/utils/project-namespace.d.ts.map +1 -1
  48. package/dist/utils/project-namespace.js +22 -1
  49. package/dist/utils/project-namespace.js.map +1 -1
  50. package/dist/wrapper/client.d.ts +22 -3
  51. package/dist/wrapper/client.d.ts.map +1 -1
  52. package/dist/wrapper/client.js +59 -9
  53. package/dist/wrapper/client.js.map +1 -1
  54. package/dist/wrapper/parser.d.ts +110 -4
  55. package/dist/wrapper/parser.d.ts.map +1 -1
  56. package/dist/wrapper/parser.js +296 -84
  57. package/dist/wrapper/parser.js.map +1 -1
  58. package/dist/wrapper/tmux-wrapper.d.ts +100 -9
  59. package/dist/wrapper/tmux-wrapper.d.ts.map +1 -1
  60. package/dist/wrapper/tmux-wrapper.js +441 -83
  61. package/dist/wrapper/tmux-wrapper.js.map +1 -1
  62. package/docs/AGENTS.md +27 -27
  63. package/docs/CHANGELOG.md +1 -1
  64. package/docs/DESIGN_V2.md +1079 -0
  65. package/docs/INTEGRATION-GUIDE.md +926 -0
  66. package/docs/PROPOSAL-trajectories.md +1582 -0
  67. package/docs/PROTOCOL.md +3 -3
  68. package/docs/SCALING_ANALYSIS.md +280 -0
  69. package/docs/TMUX_IMPLEMENTATION_NOTES.md +9 -9
  70. package/docs/TMUX_IMPROVEMENTS.md +968 -0
  71. package/docs/competitive-analysis-mcp-agent-mail.md +389 -0
  72. package/package.json +6 -2
@@ -0,0 +1,926 @@
1
+ # Agent Infrastructure Integration Guide
2
+
3
+ How to integrate agent-relay, claude-mem, and agent-trajectories into a cohesive stack.
4
+
5
+ ---
6
+
7
+ ## The Stack at a Glance
8
+
9
+ ```
10
+ ┌─────────────────────────────────────────────────────────────────┐
11
+ │ YOUR AGENT (Claude Code, Codex, Gemini, etc.) │
12
+ ├─────────────────────────────────────────────────────────────────┤
13
+ │ │ │
14
+ │ ┌────────────┴────────────┐ │
15
+ │ ▼ ▼ │
16
+ │ ┌─────────────────┐ ┌─────────────────┐ │
17
+ │ │ CLAUDE-MEM │ │ AGENT-RELAY │ │
18
+ │ │ (Observations) │ │ (Messaging) │ │
19
+ │ │ │ │ │ │
20
+ │ │ • Tool calls │ │ • ->relay:Agent │ │
21
+ │ │ • Concepts │ │ • Broadcasting │ │
22
+ │ │ • Sessions │ │ • Persistence │ │
23
+ │ └────────┬────────┘ └────────┬────────┘ │
24
+ │ │ │ │
25
+ │ └──────────┬─────────────┘ │
26
+ │ ▼ │
27
+ │ ┌─────────────────────┐ │
28
+ │ │ AGENT-TRAJECTORIES │ │
29
+ │ │ (Narratives) │ │
30
+ │ │ │ │
31
+ │ │ • Task stories │ │
32
+ │ │ • Decisions │ │
33
+ │ │ • Retrospectives │ │
34
+ │ │ • Workspace │ │
35
+ │ └─────────────────────┘ │
36
+ │ │
37
+ └─────────────────────────────────────────────────────────────────┘
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Phase 0: Current State (What Exists)
43
+
44
+ ### agent-relay (✅ Ready)
45
+
46
+ **What it does:** Real-time agent-to-agent messaging via Unix sockets.
47
+
48
+ **Installation:**
49
+ ```bash
50
+ npm install -g agent-relay
51
+ ```
52
+
53
+ **Usage:**
54
+ ```bash
55
+ # Start daemon
56
+ agent-relay up
57
+
58
+ # Wrap agent
59
+ agent-relay -n Alice claude
60
+ ```
61
+
62
+ **What it provides for integration:**
63
+ ```typescript
64
+ import { StoredMessage, MessageQuery, StorageAdapter } from 'agent-relay';
65
+
66
+ // Query messages for a time range
67
+ const messages = await storage.getMessages({
68
+ sinceTs: startTime,
69
+ order: 'asc'
70
+ });
71
+ ```
72
+
73
+ ### claude-mem (✅ Exists, needs integration)
74
+
75
+ **What it does:** Captures tool observations with semantic concepts.
76
+
77
+ **Installation:**
78
+ ```bash
79
+ # Clone and setup
80
+ git clone https://github.com/thedotmack/claude-mem
81
+ cd claude-mem
82
+ bun install
83
+ ```
84
+
85
+ **How it works:**
86
+ - Hooks into Claude Code lifecycle (SessionStart, PostToolUse, SessionEnd)
87
+ - Stores observations in SQLite + Chroma (vector search)
88
+ - Provides `mem-search` skill for natural language queries
89
+
90
+ **What it provides for integration:**
91
+ - Tool call history with semantic tags
92
+ - Session continuity
93
+ - Concept-based search
94
+
95
+ ---
96
+
97
+ ## Phase 1: Install claude-mem
98
+
99
+ ### Step 1.1: Clone and Configure
100
+
101
+ ```bash
102
+ # From your project root
103
+ git clone https://github.com/thedotmack/claude-mem .claude-mem
104
+
105
+ # Install dependencies
106
+ cd .claude-mem
107
+ bun install
108
+
109
+ # Start the worker service
110
+ bun run start
111
+ ```
112
+
113
+ ### Step 1.2: Configure Claude Code Hooks
114
+
115
+ Add to your `~/.claude/settings.json` (or project `.claude/settings.json`):
116
+
117
+ ```json
118
+ {
119
+ "hooks": {
120
+ "SessionStart": [
121
+ {
122
+ "command": "node .claude-mem/hooks/session-start.js",
123
+ "timeout": 5000
124
+ }
125
+ ],
126
+ "PostToolUse": [
127
+ {
128
+ "command": "node .claude-mem/hooks/post-tool-use.js",
129
+ "timeout": 3000
130
+ }
131
+ ],
132
+ "SessionEnd": [
133
+ {
134
+ "command": "node .claude-mem/hooks/session-end.js",
135
+ "timeout": 5000
136
+ }
137
+ ]
138
+ }
139
+ }
140
+ ```
141
+
142
+ ### Step 1.3: Verify It's Working
143
+
144
+ ```bash
145
+ # Start a Claude Code session
146
+ claude
147
+
148
+ # Do some work...
149
+
150
+ # Check the web viewer
151
+ open http://localhost:37777
152
+ ```
153
+
154
+ You should see observations being captured.
155
+
156
+ ---
157
+
158
+ ## Phase 2: Create agent-trajectories
159
+
160
+ ### Step 2.1: Initialize the Project
161
+
162
+ ```bash
163
+ # Create new repo
164
+ mkdir agent-trajectories
165
+ cd agent-trajectories
166
+ npm init -y
167
+
168
+ # Install dependencies
169
+ npm install better-sqlite3 commander uuid
170
+ npm install -D typescript @types/node @types/better-sqlite3 vitest
171
+ ```
172
+
173
+ ### Step 2.2: Project Structure
174
+
175
+ ```
176
+ agent-trajectories/
177
+ ├── src/
178
+ │ ├── core/
179
+ │ │ ├── types.ts # Trajectory, Chapter, Event types
180
+ │ │ ├── schema.ts # JSON schema for .trajectory format
181
+ │ │ └── trajectory.ts # Trajectory class
182
+ │ │
183
+ │ ├── storage/
184
+ │ │ ├── file-storage.ts # .trajectories/ directory
185
+ │ │ └── sqlite-storage.ts # SQLite for indexing
186
+ │ │
187
+ │ ├── adapters/
188
+ │ │ ├── adapter.ts # TaskSourceAdapter interface
189
+ │ │ ├── beads.ts # Beads integration
190
+ │ │ ├── github.ts # GitHub Issues integration
191
+ │ │ ├── linear.ts # Linear integration
192
+ │ │ └── plain.ts # Standalone trajectories
193
+ │ │
194
+ │ ├── integrations/
195
+ │ │ ├── relay.ts # Import from agent-relay
196
+ │ │ └── claude-mem.ts # Import from claude-mem
197
+ │ │
198
+ │ ├── workspace/
199
+ │ │ ├── decisions.ts # Decision log
200
+ │ │ ├── patterns.ts # Pattern library
201
+ │ │ └── extract.ts # Auto-extraction
202
+ │ │
203
+ │ ├── export/
204
+ │ │ ├── markdown.ts # Notion-style export
205
+ │ │ └── timeline.ts # Linear-style export
206
+ │ │
207
+ │ ├── cli/
208
+ │ │ └── index.ts # CLI commands
209
+ │ │
210
+ │ └── index.ts # Main exports
211
+
212
+ ├── package.json
213
+ └── tsconfig.json
214
+ ```
215
+
216
+ ### Step 2.3: Core Types
217
+
218
+ ```typescript
219
+ // src/core/types.ts
220
+
221
+ export interface Trajectory {
222
+ id: string;
223
+ version: 1;
224
+
225
+ task: TaskReference;
226
+
227
+ startedAt: string;
228
+ completedAt?: string;
229
+ status: 'active' | 'completed' | 'abandoned';
230
+
231
+ agents: AgentParticipation[];
232
+ chapters: Chapter[];
233
+ retrospective?: Retrospective;
234
+
235
+ commits: string[];
236
+ filesChanged: string[];
237
+
238
+ projectId: string;
239
+ tags: string[];
240
+ }
241
+
242
+ export interface TaskReference {
243
+ title: string;
244
+ description?: string;
245
+ source?: {
246
+ system: string; // 'beads' | 'linear' | 'github' | 'plain'
247
+ id: string;
248
+ url?: string;
249
+ };
250
+ }
251
+
252
+ export interface Chapter {
253
+ id: string;
254
+ title: string;
255
+ agentName: string;
256
+ startedAt: string;
257
+ endedAt?: string;
258
+ events: TrajectoryEvent[];
259
+ }
260
+
261
+ export interface TrajectoryEvent {
262
+ ts: number;
263
+ type: EventType;
264
+ content: string;
265
+ raw?: unknown;
266
+ significance?: 'low' | 'medium' | 'high' | 'critical';
267
+ tags?: string[];
268
+ source?: 'relay' | 'claude-mem' | 'manual';
269
+ }
270
+
271
+ export type EventType =
272
+ | 'prompt'
273
+ | 'thinking'
274
+ | 'tool_call'
275
+ | 'tool_result'
276
+ | 'message_sent'
277
+ | 'message_received'
278
+ | 'decision'
279
+ | 'observation' // From claude-mem
280
+ | 'error';
281
+
282
+ export interface Retrospective {
283
+ summary: string;
284
+ approach: string;
285
+ decisions: Decision[];
286
+ challenges: string[];
287
+ learnings: string[];
288
+ suggestions: string[];
289
+ confidence: number;
290
+ }
291
+
292
+ export interface Decision {
293
+ question: string;
294
+ chosen: string;
295
+ alternatives: string[];
296
+ reasoning: string;
297
+ }
298
+ ```
299
+
300
+ ### Step 2.4: CLI Commands
301
+
302
+ ```typescript
303
+ // src/cli/index.ts
304
+
305
+ import { Command } from 'commander';
306
+
307
+ const program = new Command();
308
+
309
+ program
310
+ .name('trajectory')
311
+ .description('Agent trajectory management')
312
+ .version('1.0.0');
313
+
314
+ // Create new trajectory
315
+ program
316
+ .command('new <title>')
317
+ .description('Start a new trajectory')
318
+ .option('--beads <id>', 'Link to Beads task')
319
+ .option('--linear <id>', 'Link to Linear issue')
320
+ .option('--github <id>', 'Link to GitHub issue')
321
+ .action(async (title, options) => {
322
+ // Implementation
323
+ });
324
+
325
+ // Show current trajectory status
326
+ program
327
+ .command('status')
328
+ .description('Show active trajectory')
329
+ .action(async () => {
330
+ // Implementation
331
+ });
332
+
333
+ // Add a chapter
334
+ program
335
+ .command('chapter <title>')
336
+ .description('Start a new chapter')
337
+ .action(async (title) => {
338
+ // Implementation
339
+ });
340
+
341
+ // Record a decision
342
+ program
343
+ .command('decision <title>')
344
+ .description('Record a decision')
345
+ .option('--chosen <choice>', 'What was chosen')
346
+ .option('--alternatives <alts...>', 'Alternatives considered')
347
+ .option('--reasoning <reason>', 'Why this choice')
348
+ .action(async (title, options) => {
349
+ // Implementation
350
+ });
351
+
352
+ // Complete trajectory
353
+ program
354
+ .command('complete')
355
+ .description('Complete the active trajectory')
356
+ .option('--retrospective', 'Prompt for retrospective')
357
+ .action(async (options) => {
358
+ // Implementation
359
+ });
360
+
361
+ // Import from sources
362
+ program
363
+ .command('import')
364
+ .description('Import events from external sources')
365
+ .option('--relay', 'Import from agent-relay')
366
+ .option('--claude-mem', 'Import from claude-mem')
367
+ .option('--since <timestamp>', 'Import since timestamp')
368
+ .action(async (options) => {
369
+ // Implementation
370
+ });
371
+
372
+ // Export trajectory
373
+ program
374
+ .command('export <id>')
375
+ .description('Export trajectory')
376
+ .option('--format <format>', 'Export format (markdown, json, timeline)')
377
+ .action(async (id, options) => {
378
+ // Implementation
379
+ });
380
+
381
+ // Search trajectories
382
+ program
383
+ .command('search <query>')
384
+ .description('Search trajectories')
385
+ .action(async (query) => {
386
+ // Implementation
387
+ });
388
+
389
+ program.parse();
390
+ ```
391
+
392
+ ---
393
+
394
+ ## Phase 3: agent-relay Integration
395
+
396
+ ### Step 3.1: Import Relay Messages
397
+
398
+ ```typescript
399
+ // src/integrations/relay.ts
400
+
401
+ import { StoredMessage, MessageQuery } from 'agent-relay';
402
+ import { TrajectoryEvent } from '../core/types.js';
403
+
404
+ interface RelayImportOptions {
405
+ sinceTs: number;
406
+ untilTs?: number;
407
+ agentName?: string;
408
+ topic?: string;
409
+ }
410
+
411
+ export async function importFromRelay(
412
+ storage: StorageAdapter,
413
+ options: RelayImportOptions
414
+ ): Promise<TrajectoryEvent[]> {
415
+ const query: MessageQuery = {
416
+ sinceTs: options.sinceTs,
417
+ order: 'asc',
418
+ limit: 1000
419
+ };
420
+
421
+ if (options.agentName) {
422
+ query.from = options.agentName;
423
+ }
424
+ if (options.topic) {
425
+ query.topic = options.topic;
426
+ }
427
+
428
+ const messages = await storage.getMessages(query);
429
+
430
+ return messages
431
+ .filter(m => !options.untilTs || m.ts <= options.untilTs)
432
+ .map(messageToEvent);
433
+ }
434
+
435
+ function messageToEvent(msg: StoredMessage): TrajectoryEvent {
436
+ return {
437
+ ts: msg.ts,
438
+ type: msg.kind === 'thinking' ? 'thinking' :
439
+ msg.to === '*' ? 'message_sent' :
440
+ 'message_received',
441
+ content: msg.body,
442
+ raw: {
443
+ from: msg.from,
444
+ to: msg.to,
445
+ kind: msg.kind,
446
+ data: msg.data
447
+ },
448
+ significance: 'medium',
449
+ source: 'relay'
450
+ };
451
+ }
452
+ ```
453
+
454
+ ### Step 3.2: Real-time Relay Subscription
455
+
456
+ ```typescript
457
+ // src/integrations/relay-listener.ts
458
+
459
+ import { RelayClient } from 'agent-relay';
460
+ import { TrajectoryCapture } from '../capture/trajectory-capture.js';
461
+
462
+ export class RelayListener {
463
+ private client: RelayClient;
464
+ private capture: TrajectoryCapture;
465
+
466
+ constructor(capture: TrajectoryCapture) {
467
+ this.capture = capture;
468
+ }
469
+
470
+ async connect(agentName: string): Promise<void> {
471
+ this.client = new RelayClient({ agentName });
472
+
473
+ this.client.on('message', (envelope) => {
474
+ this.capture.recordEvent({
475
+ type: envelope.from === agentName ? 'message_sent' : 'message_received',
476
+ content: envelope.payload.body,
477
+ raw: envelope,
478
+ source: 'relay'
479
+ });
480
+ });
481
+
482
+ await this.client.connect();
483
+ }
484
+
485
+ async disconnect(): Promise<void> {
486
+ await this.client.disconnect();
487
+ }
488
+ }
489
+ ```
490
+
491
+ ---
492
+
493
+ ## Phase 4: claude-mem Integration
494
+
495
+ ### Step 4.1: Query claude-mem Observations
496
+
497
+ ```typescript
498
+ // src/integrations/claude-mem.ts
499
+
500
+ import { TrajectoryEvent } from '../core/types.js';
501
+
502
+ interface ClaudeMemObservation {
503
+ id: string;
504
+ timestamp: string;
505
+ type: 'decision' | 'bugfix' | 'feature' | 'refactor' | 'discovery' | 'change';
506
+ content: string;
507
+ concepts: string[];
508
+ files?: string[];
509
+ tokens?: number;
510
+ }
511
+
512
+ interface ClaudeMemImportOptions {
513
+ sinceTs: number;
514
+ untilTs?: number;
515
+ types?: string[];
516
+ concepts?: string[];
517
+ }
518
+
519
+ const CLAUDE_MEM_API = 'http://localhost:37777';
520
+
521
+ export async function importFromClaudeMem(
522
+ options: ClaudeMemImportOptions
523
+ ): Promise<TrajectoryEvent[]> {
524
+ const params = new URLSearchParams({
525
+ since: new Date(options.sinceTs).toISOString(),
526
+ });
527
+
528
+ if (options.untilTs) {
529
+ params.set('until', new Date(options.untilTs).toISOString());
530
+ }
531
+ if (options.types?.length) {
532
+ params.set('types', options.types.join(','));
533
+ }
534
+ if (options.concepts?.length) {
535
+ params.set('concepts', options.concepts.join(','));
536
+ }
537
+
538
+ const response = await fetch(`${CLAUDE_MEM_API}/api/observations?${params}`);
539
+ const observations: ClaudeMemObservation[] = await response.json();
540
+
541
+ return observations.map(observationToEvent);
542
+ }
543
+
544
+ function observationToEvent(obs: ClaudeMemObservation): TrajectoryEvent {
545
+ return {
546
+ ts: new Date(obs.timestamp).getTime(),
547
+ type: 'observation',
548
+ content: obs.content,
549
+ raw: obs,
550
+ significance: mapTypeToSignificance(obs.type),
551
+ tags: obs.concepts,
552
+ source: 'claude-mem'
553
+ };
554
+ }
555
+
556
+ function mapTypeToSignificance(type: string): 'low' | 'medium' | 'high' | 'critical' {
557
+ switch (type) {
558
+ case 'decision': return 'high';
559
+ case 'bugfix': return 'high';
560
+ case 'feature': return 'medium';
561
+ case 'discovery': return 'medium';
562
+ case 'refactor': return 'low';
563
+ case 'change': return 'low';
564
+ default: return 'medium';
565
+ }
566
+ }
567
+
568
+ // Search claude-mem for relevant observations
569
+ export async function searchClaudeMem(query: string): Promise<ClaudeMemObservation[]> {
570
+ const response = await fetch(`${CLAUDE_MEM_API}/api/search`, {
571
+ method: 'POST',
572
+ headers: { 'Content-Type': 'application/json' },
573
+ body: JSON.stringify({ query })
574
+ });
575
+
576
+ return response.json();
577
+ }
578
+ ```
579
+
580
+ ### Step 4.2: Enrich Trajectories with Observations
581
+
582
+ ```typescript
583
+ // src/integrations/enrichment.ts
584
+
585
+ import { Trajectory, Chapter } from '../core/types.js';
586
+ import { importFromClaudeMem } from './claude-mem.js';
587
+ import { importFromRelay } from './relay.js';
588
+
589
+ export async function enrichTrajectory(
590
+ trajectory: Trajectory,
591
+ relayStorage?: StorageAdapter
592
+ ): Promise<Trajectory> {
593
+ const startTs = new Date(trajectory.startedAt).getTime();
594
+ const endTs = trajectory.completedAt
595
+ ? new Date(trajectory.completedAt).getTime()
596
+ : Date.now();
597
+
598
+ // Import from claude-mem
599
+ const claudeMemEvents = await importFromClaudeMem({
600
+ sinceTs: startTs,
601
+ untilTs: endTs,
602
+ types: ['decision', 'discovery', 'bugfix']
603
+ });
604
+
605
+ // Import from agent-relay (if available)
606
+ let relayEvents = [];
607
+ if (relayStorage) {
608
+ relayEvents = await importFromRelay(relayStorage, {
609
+ sinceTs: startTs,
610
+ untilTs: endTs
611
+ });
612
+ }
613
+
614
+ // Merge events into chapters by timestamp
615
+ const allEvents = [...claudeMemEvents, ...relayEvents]
616
+ .sort((a, b) => a.ts - b.ts);
617
+
618
+ // Distribute events to appropriate chapters
619
+ for (const event of allEvents) {
620
+ const chapter = findChapterForTimestamp(trajectory.chapters, event.ts);
621
+ if (chapter) {
622
+ chapter.events.push(event);
623
+ chapter.events.sort((a, b) => a.ts - b.ts);
624
+ }
625
+ }
626
+
627
+ return trajectory;
628
+ }
629
+
630
+ function findChapterForTimestamp(chapters: Chapter[], ts: number): Chapter | null {
631
+ for (const chapter of chapters) {
632
+ const start = new Date(chapter.startedAt).getTime();
633
+ const end = chapter.endedAt
634
+ ? new Date(chapter.endedAt).getTime()
635
+ : Date.now();
636
+
637
+ if (ts >= start && ts <= end) {
638
+ return chapter;
639
+ }
640
+ }
641
+
642
+ // Return last chapter if no match
643
+ return chapters[chapters.length - 1] || null;
644
+ }
645
+ ```
646
+
647
+ ---
648
+
649
+ ## Phase 5: Hook Integration
650
+
651
+ ### Step 5.1: Trajectory Hooks for Claude Code
652
+
653
+ ```typescript
654
+ // src/hooks/session-start.ts
655
+
656
+ import { TrajectoryStore } from '../storage/trajectory-store.js';
657
+
658
+ async function onSessionStart(): Promise<{ context?: string }> {
659
+ const store = new TrajectoryStore();
660
+ const active = await store.getActive();
661
+
662
+ if (!active) {
663
+ return {};
664
+ }
665
+
666
+ const context = `
667
+ ## Active Trajectory
668
+
669
+ **Task:** ${active.task.title}
670
+ **Status:** ${active.status}
671
+ **Chapter:** ${active.chapters[active.chapters.length - 1]?.title || 'Starting'}
672
+
673
+ ### Key Decisions So Far
674
+ ${active.chapters
675
+ .flatMap(c => c.events.filter(e => e.type === 'decision'))
676
+ .map(d => `- ${d.content}`)
677
+ .join('\n') || 'None yet'}
678
+
679
+ ### Recent Activity
680
+ ${active.chapters[active.chapters.length - 1]?.events
681
+ .slice(-5)
682
+ .map(e => `- [${e.type}] ${e.content.slice(0, 100)}`)
683
+ .join('\n') || 'None'}
684
+
685
+ ---
686
+ To record a decision: [[TRAJECTORY:decision]]{"title": "...", "chosen": "...", "alternatives": [...], "reasoning": "..."}[[/TRAJECTORY]]
687
+ To start a new chapter: [[TRAJECTORY:chapter]]{"title": "..."}[[/TRAJECTORY]]
688
+ `.trim();
689
+
690
+ return { context };
691
+ }
692
+ ```
693
+
694
+ ### Step 5.2: Combined Hook Configuration
695
+
696
+ ```json
697
+ // .claude/settings.json
698
+ {
699
+ "hooks": {
700
+ "SessionStart": [
701
+ {
702
+ "command": "node .claude-mem/hooks/session-start.js",
703
+ "timeout": 5000
704
+ },
705
+ {
706
+ "command": "npx trajectory hook:session-start",
707
+ "timeout": 3000
708
+ }
709
+ ],
710
+ "PostToolUse": [
711
+ {
712
+ "command": "node .claude-mem/hooks/post-tool-use.js",
713
+ "timeout": 3000
714
+ }
715
+ ],
716
+ "Stop": [
717
+ {
718
+ "command": "npx trajectory hook:stop",
719
+ "timeout": 5000
720
+ }
721
+ ],
722
+ "SessionEnd": [
723
+ {
724
+ "command": "node .claude-mem/hooks/session-end.js",
725
+ "timeout": 5000
726
+ },
727
+ {
728
+ "command": "npx trajectory hook:session-end",
729
+ "timeout": 5000
730
+ }
731
+ ]
732
+ }
733
+ }
734
+ ```
735
+
736
+ ### Step 5.3: Stop Hook - Prompt for Retrospective
737
+
738
+ ```typescript
739
+ // src/hooks/stop.ts
740
+
741
+ import { TrajectoryStore } from '../storage/trajectory-store.js';
742
+
743
+ async function onStop(): Promise<{ decision: 'allow' | 'block'; reason?: string }> {
744
+ const store = new TrajectoryStore();
745
+ const active = await store.getActive();
746
+
747
+ if (!active) {
748
+ return { decision: 'allow' };
749
+ }
750
+
751
+ // Check if trajectory has a retrospective
752
+ if (!active.retrospective) {
753
+ return {
754
+ decision: 'block',
755
+ reason: `
756
+ Active trajectory "${active.task.title}" needs a retrospective before completing.
757
+
758
+ Please output a retrospective:
759
+
760
+ [[TRAJECTORY:retrospective]]
761
+ {
762
+ "summary": "What was accomplished?",
763
+ "approach": "How did you approach it?",
764
+ "decisions": [
765
+ {"question": "Key choice made", "chosen": "What you picked", "alternatives": ["Other options"], "reasoning": "Why"}
766
+ ],
767
+ "challenges": ["What was difficult?"],
768
+ "learnings": ["What would you do differently?"],
769
+ "suggestions": ["Improvements for codebase/process?"],
770
+ "confidence": 0.85
771
+ }
772
+ [[/TRAJECTORY]]
773
+
774
+ Or run: trajectory complete --skip-retrospective
775
+ `.trim()
776
+ };
777
+ }
778
+
779
+ return { decision: 'allow' };
780
+ }
781
+ ```
782
+
783
+ ---
784
+
785
+ ## Phase 6: Putting It All Together
786
+
787
+ ### Complete Setup Checklist
788
+
789
+ ```bash
790
+ # 1. Install agent-relay
791
+ npm install -g agent-relay
792
+
793
+ # 2. Clone and setup claude-mem
794
+ git clone https://github.com/thedotmack/claude-mem .claude-mem
795
+ cd .claude-mem && bun install && bun run start &
796
+ cd ..
797
+
798
+ # 3. Install agent-trajectories (once published)
799
+ npm install -g agent-trajectories
800
+
801
+ # 4. Configure hooks
802
+ cat > .claude/settings.json << 'EOF'
803
+ {
804
+ "hooks": {
805
+ "SessionStart": [
806
+ {"command": "node .claude-mem/hooks/session-start.js", "timeout": 5000},
807
+ {"command": "npx trajectory hook:session-start", "timeout": 3000}
808
+ ],
809
+ "PostToolUse": [
810
+ {"command": "node .claude-mem/hooks/post-tool-use.js", "timeout": 3000}
811
+ ],
812
+ "Stop": [
813
+ {"command": "npx trajectory hook:stop", "timeout": 5000}
814
+ ],
815
+ "SessionEnd": [
816
+ {"command": "node .claude-mem/hooks/session-end.js", "timeout": 5000},
817
+ {"command": "npx trajectory hook:session-end", "timeout": 5000}
818
+ ]
819
+ }
820
+ }
821
+ EOF
822
+
823
+ # 5. Start the relay daemon
824
+ agent-relay up
825
+
826
+ # 6. Start working!
827
+ agent-relay -n Alice claude
828
+ ```
829
+
830
+ ### Typical Workflow
831
+
832
+ ```bash
833
+ # Start a task
834
+ trajectory new "Implement user authentication" --linear ENG-456
835
+
836
+ # Work in Claude Code...
837
+ # - claude-mem captures tool observations automatically
838
+ # - agent-relay captures messages automatically
839
+ # - You can add decisions manually via [[TRAJECTORY:decision]]
840
+
841
+ # Check status
842
+ trajectory status
843
+
844
+ # Start a new chapter when switching focus
845
+ trajectory chapter "Testing"
846
+
847
+ # When done, complete with retrospective
848
+ trajectory complete
849
+
850
+ # View the result
851
+ trajectory export ENG-456 --format markdown
852
+ ```
853
+
854
+ ### Data Flow Diagram
855
+
856
+ ```
857
+ ┌──────────────────────────────────────────────────────────────────┐
858
+ │ AGENT SESSION │
859
+ ├──────────────────────────────────────────────────────────────────┤
860
+ │ │
861
+ │ Agent works... │
862
+ │ │ │
863
+ │ ├──────────────────┬───────────────────┐ │
864
+ │ ▼ ▼ ▼ │
865
+ │ ┌─────────┐ ┌───────────┐ ┌────────────┐ │
866
+ │ │ Tool │ │ ->relay: │ │[[TRAJECTORY│ │
867
+ │ │ Calls │ │ messages │ │ :decision]]│ │
868
+ │ └────┬────┘ └─────┬─────┘ └──────┬─────┘ │
869
+ │ │ │ │ │
870
+ │ ▼ ▼ ▼ │
871
+ │ ┌─────────┐ ┌───────────┐ ┌────────────┐ │
872
+ │ │claude- │ │agent-relay│ │agent- │ │
873
+ │ │mem │ │SQLite │ │trajectories│ │
874
+ │ │SQLite + │ │ │ │.trajectory/│ │
875
+ │ │Chroma │ │ │ │ │ │
876
+ │ └────┬────┘ └─────┬─────┘ └──────┬─────┘ │
877
+ │ │ │ │ │
878
+ │ └────────────┬────┴───────────────────┘ │
879
+ │ ▼ │
880
+ │ ┌─────────────────┐ │
881
+ │ │ trajectory │ │
882
+ │ │ complete │ │
883
+ │ │ │ │
884
+ │ │ Enriches with: │ │
885
+ │ │ - relay msgs │ │
886
+ │ │ - claude-mem │ │
887
+ │ │ observations │ │
888
+ │ └────────┬────────┘ │
889
+ │ ▼ │
890
+ │ ┌─────────────────┐ │
891
+ │ │ .trajectory.json│ │
892
+ │ │ .trajectory.md │ │
893
+ │ │ │ │
894
+ │ │ Complete story │ │
895
+ │ │ of the work │ │
896
+ │ └─────────────────┘ │
897
+ │ │
898
+ └──────────────────────────────────────────────────────────────────┘
899
+ ```
900
+
901
+ ---
902
+
903
+ ## Summary: What Each Piece Does
904
+
905
+ | Component | Captures | Storage | Query |
906
+ |-----------|----------|---------|-------|
907
+ | **agent-relay** | Agent messages | SQLite | By time, sender, topic |
908
+ | **claude-mem** | Tool observations | SQLite + Chroma | Semantic search |
909
+ | **agent-trajectories** | Task narratives | Files + SQLite | By task, decision, pattern |
910
+
911
+ | Component | Hooks | Real-time | Export |
912
+ |-----------|-------|-----------|--------|
913
+ | **agent-relay** | Stop (inbox check) | Yes (sockets) | JSON |
914
+ | **claude-mem** | All lifecycle | No | JSON |
915
+ | **agent-trajectories** | Start, Stop, End | Optional | Markdown, JSON, Timeline |
916
+
917
+ ---
918
+
919
+ ## Next Steps
920
+
921
+ 1. **Phase 1:** Get claude-mem working in your project
922
+ 2. **Phase 2:** Create agent-trajectories repo with core types
923
+ 3. **Phase 3:** Add relay integration
924
+ 4. **Phase 4:** Add claude-mem integration
925
+ 5. **Phase 5:** Build CLI and hooks
926
+ 6. **Phase 6:** Test end-to-end flow