@clawnet/template-minimal 0.0.1
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/.agents/skills/claude-agent-sdk/.claude-plugin/plugin.json +13 -0
- package/.agents/skills/claude-agent-sdk/SKILL.md +954 -0
- package/.agents/skills/claude-agent-sdk/references/mcp-servers-guide.md +387 -0
- package/.agents/skills/claude-agent-sdk/references/permissions-guide.md +429 -0
- package/.agents/skills/claude-agent-sdk/references/query-api-reference.md +437 -0
- package/.agents/skills/claude-agent-sdk/references/session-management.md +419 -0
- package/.agents/skills/claude-agent-sdk/references/subagents-patterns.md +464 -0
- package/.agents/skills/claude-agent-sdk/references/top-errors.md +503 -0
- package/.agents/skills/claude-agent-sdk/rules/claude-agent-sdk.md +96 -0
- package/.agents/skills/claude-agent-sdk/scripts/check-versions.sh +55 -0
- package/.agents/skills/claude-agent-sdk/templates/basic-query.ts +55 -0
- package/.agents/skills/claude-agent-sdk/templates/custom-mcp-server.ts +161 -0
- package/.agents/skills/claude-agent-sdk/templates/error-handling.ts +283 -0
- package/.agents/skills/claude-agent-sdk/templates/filesystem-settings.ts +211 -0
- package/.agents/skills/claude-agent-sdk/templates/multi-agent-workflow.ts +318 -0
- package/.agents/skills/claude-agent-sdk/templates/package.json +30 -0
- package/.agents/skills/claude-agent-sdk/templates/permission-control.ts +211 -0
- package/.agents/skills/claude-agent-sdk/templates/query-with-tools.ts +54 -0
- package/.agents/skills/claude-agent-sdk/templates/session-management.ts +151 -0
- package/.agents/skills/claude-agent-sdk/templates/subagents-orchestration.ts +166 -0
- package/.agents/skills/claude-agent-sdk/templates/tsconfig.json +22 -0
- package/.claude/settings.local.json +70 -0
- package/.claude/skills/moltbook-example/SKILL.md +79 -0
- package/.claude/skills/post/SKILL.md +130 -0
- package/.env.example +4 -0
- package/.vercel/README.txt +11 -0
- package/.vercel/project.json +1 -0
- package/AGENTS.md +114 -0
- package/CLAUDE.md +532 -0
- package/README.md +44 -0
- package/api/index.ts +3 -0
- package/biome.json +14 -0
- package/clark_avatar.jpeg +0 -0
- package/package.json +21 -0
- package/scripts/wake.ts +38 -0
- package/skills/clawbook/HEARTBEAT.md +142 -0
- package/skills/clawbook/SKILL.md +219 -0
- package/skills/moltbook-example/SKILL.md +79 -0
- package/skills/moltbook-example/bot/index.ts +61 -0
- package/src/agent/prompts.ts +98 -0
- package/src/agent/runner.ts +526 -0
- package/src/agent/tool-definitions.ts +1151 -0
- package/src/agent-options.ts +14 -0
- package/src/bot-identity.ts +41 -0
- package/src/constants.ts +15 -0
- package/src/handlers/heartbeat.ts +21 -0
- package/src/handlers/openai-compat.ts +95 -0
- package/src/handlers/post.ts +21 -0
- package/src/identity.ts +83 -0
- package/src/index.ts +30 -0
- package/src/middleware/cron-auth.ts +53 -0
- package/src/middleware/sigma-auth.ts +147 -0
- package/src/runs.ts +49 -0
- package/tests/agent/prompts.test.ts +172 -0
- package/tests/agent/runner.test.ts +353 -0
- package/tests/agent/tool-definitions.test.ts +171 -0
- package/tests/constants.test.ts +24 -0
- package/tests/handlers/openai-compat.test.ts +128 -0
- package/tests/handlers.test.ts +133 -0
- package/tests/identity.test.ts +66 -0
- package/tests/index.test.ts +108 -0
- package/tests/middleware/cron-auth.test.ts +99 -0
- package/tests/middleware/sigma-auth.test.ts +198 -0
- package/tests/runs.test.ts +56 -0
- package/tests/skill.test.ts +71 -0
- package/tsconfig.json +14 -0
- package/vercel.json +9 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
# Session Management Guide
|
|
2
|
+
|
|
3
|
+
Complete guide to sessions, resuming, and forking in Claude Agent SDK.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What Are Sessions?
|
|
8
|
+
|
|
9
|
+
Sessions enable:
|
|
10
|
+
- **Persistent conversations** - Resume where you left off
|
|
11
|
+
- **Context preservation** - Agent remembers everything
|
|
12
|
+
- **Alternative paths** - Fork to explore different approaches
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Session Lifecycle
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
Start → Capture Session ID → Resume → Resume → ... → End
|
|
20
|
+
↓
|
|
21
|
+
Fork (alternative path)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Starting a Session
|
|
27
|
+
|
|
28
|
+
Every `query()` call creates a session.
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
let sessionId: string | undefined;
|
|
32
|
+
|
|
33
|
+
const response = query({
|
|
34
|
+
prompt: "Build a REST API",
|
|
35
|
+
options: { model: "sonnet" }
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
for await (const message of response) {
|
|
39
|
+
if (message.type === 'system' && message.subtype === 'init') {
|
|
40
|
+
sessionId = message.session_id;
|
|
41
|
+
console.log(`Session started: ${sessionId}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**CRITICAL**: Capture `session_id` from `system` init message.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Resuming a Session
|
|
51
|
+
|
|
52
|
+
Continue a previous conversation.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
const resumed = query({
|
|
56
|
+
prompt: "Now add authentication",
|
|
57
|
+
options: {
|
|
58
|
+
resume: sessionId, // Resume previous session
|
|
59
|
+
model: "sonnet"
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**What's preserved**:
|
|
65
|
+
- All previous messages
|
|
66
|
+
- Agent's understanding of context
|
|
67
|
+
- Files created/modified
|
|
68
|
+
- Decisions made
|
|
69
|
+
|
|
70
|
+
**What's NOT preserved**:
|
|
71
|
+
- Environment variables
|
|
72
|
+
- Tool availability (specify again)
|
|
73
|
+
- Permission settings (specify again)
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Forking a Session
|
|
78
|
+
|
|
79
|
+
Create alternative path without modifying original.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const forked = query({
|
|
83
|
+
prompt: "Actually, make it GraphQL instead",
|
|
84
|
+
options: {
|
|
85
|
+
resume: sessionId,
|
|
86
|
+
forkSession: true, // Creates new branch
|
|
87
|
+
model: "sonnet"
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Result**:
|
|
93
|
+
- New session created
|
|
94
|
+
- Starts from same point as original
|
|
95
|
+
- Original session unchanged
|
|
96
|
+
- Can compare approaches
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Use Case Patterns
|
|
101
|
+
|
|
102
|
+
### Pattern 1: Sequential Development
|
|
103
|
+
|
|
104
|
+
Step-by-step feature building.
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// Step 1: Initial implementation
|
|
108
|
+
let session = await startSession("Create user authentication");
|
|
109
|
+
|
|
110
|
+
// Step 2: Add feature
|
|
111
|
+
session = await resumeSession(session, "Add OAuth support");
|
|
112
|
+
|
|
113
|
+
// Step 3: Add tests
|
|
114
|
+
session = await resumeSession(session, "Write integration tests");
|
|
115
|
+
|
|
116
|
+
// Step 4: Deploy
|
|
117
|
+
session = await resumeSession(session, "Deploy to production");
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Pattern 2: Exploration & Decision
|
|
121
|
+
|
|
122
|
+
Try multiple approaches, choose best.
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// Start main conversation
|
|
126
|
+
let mainSession = await startSession("Design payment system");
|
|
127
|
+
|
|
128
|
+
// Explore option A
|
|
129
|
+
let optionA = await forkSession(mainSession, "Use Stripe");
|
|
130
|
+
|
|
131
|
+
// Explore option B
|
|
132
|
+
let optionB = await forkSession(mainSession, "Use PayPal");
|
|
133
|
+
|
|
134
|
+
// Explore option C
|
|
135
|
+
let optionC = await forkSession(mainSession, "Use Square");
|
|
136
|
+
|
|
137
|
+
// Choose winner
|
|
138
|
+
let chosenSession = optionA; // Decision made
|
|
139
|
+
await resumeSession(chosenSession, "Implement chosen approach");
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Pattern 3: Multi-User Collaboration
|
|
143
|
+
|
|
144
|
+
Multiple developers, independent work.
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// Developer A starts work
|
|
148
|
+
let sessionA = await startSession("Implement user profile page");
|
|
149
|
+
|
|
150
|
+
// Developer B forks for different feature
|
|
151
|
+
let sessionB = await forkSession(sessionA, "Add avatar upload");
|
|
152
|
+
|
|
153
|
+
// Developer C forks for another feature
|
|
154
|
+
let sessionC = await forkSession(sessionA, "Implement search");
|
|
155
|
+
|
|
156
|
+
// All can work independently
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Pattern 4: Error Recovery
|
|
160
|
+
|
|
161
|
+
Backup and restore points.
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// Save checkpoint before risky operation
|
|
165
|
+
let checkpoint = sessionId;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
await resumeSession(checkpoint, "Refactor entire auth system");
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.log("Refactor failed, restoring from checkpoint");
|
|
171
|
+
await forkSession(checkpoint, "Try safer incremental refactor");
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Pattern 5: A/B Testing
|
|
176
|
+
|
|
177
|
+
Test different implementations.
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
let baseline = await startSession("Implement feature X");
|
|
181
|
+
|
|
182
|
+
// Approach A
|
|
183
|
+
let approachA = await forkSession(baseline, "Use algorithm A");
|
|
184
|
+
const metricsA = await measurePerformance(approachA);
|
|
185
|
+
|
|
186
|
+
// Approach B
|
|
187
|
+
let approachB = await forkSession(baseline, "Use algorithm B");
|
|
188
|
+
const metricsB = await measurePerformance(approachB);
|
|
189
|
+
|
|
190
|
+
// Compare and choose
|
|
191
|
+
const winner = metricsA.better(metricsB) ? approachA : approachB;
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Session Best Practices
|
|
197
|
+
|
|
198
|
+
### ✅ Do
|
|
199
|
+
|
|
200
|
+
- Always capture `session_id` from init message
|
|
201
|
+
- Store session IDs for later use
|
|
202
|
+
- Use descriptive prompts when resuming
|
|
203
|
+
- Fork for alternative approaches
|
|
204
|
+
- Test resuming before deploying
|
|
205
|
+
- Consider session lifetime limits
|
|
206
|
+
|
|
207
|
+
### ❌ Don't
|
|
208
|
+
|
|
209
|
+
- Forget to capture session ID
|
|
210
|
+
- Assume sessions last forever
|
|
211
|
+
- Resume with completely unrelated prompts
|
|
212
|
+
- Fork excessively (creates many branches)
|
|
213
|
+
- Rely on sessions for critical state
|
|
214
|
+
- Skip testing resume functionality
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Helper Functions
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
async function startSession(prompt: string): Promise<string> {
|
|
222
|
+
let sessionId: string | undefined;
|
|
223
|
+
|
|
224
|
+
const response = query({ prompt, options: { model: "sonnet" } });
|
|
225
|
+
|
|
226
|
+
for await (const message of response) {
|
|
227
|
+
if (message.type === 'system' && message.subtype === 'init') {
|
|
228
|
+
sessionId = message.session_id;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (!sessionId) throw new Error('Failed to start session');
|
|
233
|
+
return sessionId;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function resumeSession(
|
|
237
|
+
sessionId: string,
|
|
238
|
+
prompt: string
|
|
239
|
+
): Promise<void> {
|
|
240
|
+
const response = query({
|
|
241
|
+
prompt,
|
|
242
|
+
options: { resume: sessionId, model: "sonnet" }
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
for await (const message of response) {
|
|
246
|
+
if (message.type === 'assistant') {
|
|
247
|
+
console.log(message.content);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function forkSession(
|
|
253
|
+
sessionId: string,
|
|
254
|
+
prompt: string
|
|
255
|
+
): Promise<string> {
|
|
256
|
+
let newSessionId: string | undefined;
|
|
257
|
+
|
|
258
|
+
const response = query({
|
|
259
|
+
prompt,
|
|
260
|
+
options: {
|
|
261
|
+
resume: sessionId,
|
|
262
|
+
forkSession: true,
|
|
263
|
+
model: "sonnet"
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
for await (const message of response) {
|
|
268
|
+
if (message.type === 'system' && message.subtype === 'init') {
|
|
269
|
+
newSessionId = message.session_id;
|
|
270
|
+
} else if (message.type === 'assistant') {
|
|
271
|
+
console.log(message.content);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (!newSessionId) throw new Error('Failed to fork session');
|
|
276
|
+
return newSessionId;
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Session Storage
|
|
283
|
+
|
|
284
|
+
Store sessions for later use:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// In-memory storage
|
|
288
|
+
const sessions = new Map<string, { id: string; created: Date }>();
|
|
289
|
+
|
|
290
|
+
async function saveSession(prompt: string) {
|
|
291
|
+
const id = await startSession(prompt);
|
|
292
|
+
sessions.set(id, { id, created: new Date() });
|
|
293
|
+
return id;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function getSession(id: string) {
|
|
297
|
+
return sessions.get(id);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Database storage
|
|
301
|
+
async function saveSessionToDb(sessionId: string, metadata: any) {
|
|
302
|
+
await db.insert('sessions', {
|
|
303
|
+
id: sessionId,
|
|
304
|
+
created_at: new Date(),
|
|
305
|
+
metadata
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Session Limits
|
|
313
|
+
|
|
314
|
+
### Context Window
|
|
315
|
+
|
|
316
|
+
Sessions have context window limits (200k tokens for Sonnet).
|
|
317
|
+
|
|
318
|
+
**Strategies**:
|
|
319
|
+
- SDK auto-compacts context
|
|
320
|
+
- Fork to start fresh from a point
|
|
321
|
+
- Summarize and start new session
|
|
322
|
+
|
|
323
|
+
### Lifetime
|
|
324
|
+
|
|
325
|
+
Sessions may expire after inactivity.
|
|
326
|
+
|
|
327
|
+
**Strategies**:
|
|
328
|
+
- Don't rely on sessions lasting indefinitely
|
|
329
|
+
- Store important state separately
|
|
330
|
+
- Test resume functionality
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Troubleshooting
|
|
335
|
+
|
|
336
|
+
### Session Not Found
|
|
337
|
+
|
|
338
|
+
**Problem**: `"Invalid session ID"`
|
|
339
|
+
|
|
340
|
+
**Causes**:
|
|
341
|
+
- Session expired
|
|
342
|
+
- Invalid session ID
|
|
343
|
+
- Session from different CLI instance
|
|
344
|
+
|
|
345
|
+
**Solution**: Start new session
|
|
346
|
+
|
|
347
|
+
### Context Preserved Incorrectly
|
|
348
|
+
|
|
349
|
+
**Problem**: Agent doesn't remember previous work
|
|
350
|
+
|
|
351
|
+
**Causes**:
|
|
352
|
+
- Different settings/tools specified
|
|
353
|
+
- Context window exceeded
|
|
354
|
+
- Fork instead of resume
|
|
355
|
+
|
|
356
|
+
**Solution**: Verify using `resume` not `forkSession`
|
|
357
|
+
|
|
358
|
+
### Too Many Forks
|
|
359
|
+
|
|
360
|
+
**Problem**: Hard to track branches
|
|
361
|
+
|
|
362
|
+
**Solution**: Limit forking, clean up unused branches
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Complete Example
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
class SessionManager {
|
|
370
|
+
private sessions = new Map<string, string>();
|
|
371
|
+
|
|
372
|
+
async start(name: string, prompt: string): Promise<string> {
|
|
373
|
+
const id = await startSession(prompt);
|
|
374
|
+
this.sessions.set(name, id);
|
|
375
|
+
console.log(`✨ Started: ${name}`);
|
|
376
|
+
return id;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async resume(name: string, prompt: string): Promise<void> {
|
|
380
|
+
const id = this.sessions.get(name);
|
|
381
|
+
if (!id) throw new Error(`Session ${name} not found`);
|
|
382
|
+
console.log(`↪️ Resuming: ${name}`);
|
|
383
|
+
await resumeSession(id, prompt);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async fork(
|
|
387
|
+
fromName: string,
|
|
388
|
+
newName: string,
|
|
389
|
+
prompt: string
|
|
390
|
+
): Promise<string> {
|
|
391
|
+
const fromId = this.sessions.get(fromName);
|
|
392
|
+
if (!fromId) throw new Error(`Session ${fromName} not found`);
|
|
393
|
+
console.log(`🔀 Forking: ${fromName} → ${newName}`);
|
|
394
|
+
const newId = await forkSession(fromId, prompt);
|
|
395
|
+
this.sessions.set(newName, newId);
|
|
396
|
+
return newId;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
list(): string[] {
|
|
400
|
+
return Array.from(this.sessions.keys());
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Usage
|
|
405
|
+
const manager = new SessionManager();
|
|
406
|
+
|
|
407
|
+
await manager.start("main", "Build a web app");
|
|
408
|
+
await manager.resume("main", "Add authentication");
|
|
409
|
+
await manager.fork("main", "option-a", "Use JWT tokens");
|
|
410
|
+
await manager.fork("main", "option-b", "Use sessions");
|
|
411
|
+
|
|
412
|
+
console.log("Sessions:", manager.list());
|
|
413
|
+
// ["main", "option-a", "option-b"]
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
**For more details**: See SKILL.md
|
|
419
|
+
**Template**: templates/session-management.ts
|