Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:45:35 +08:00
commit fcf1961dfa
7 changed files with 1286 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
{
"name": "claude-agent-lifecycle",
"description": "Persistent agent lifecycle management for Claude Code. Provides 6 agent lifespans (ephemeral, turn, context, session, workflow, project) with automatic disposal via hooks.",
"version": "1.0.0",
"author": {
"name": "Hendrik Geldenhuys",
"url": "https://github.com/hgeldenhuys"
},
"skills": [
"./.claude/skills/"
],
"hooks": {
"Stop": "hooks/lifecycle-manager.ts",
"SessionEnd": "hooks/lifecycle-manager.ts"
}
}

View File

@@ -0,0 +1,212 @@
---
name: managing-agent-lifecycles
description: Implements persistent agent lifecycle management with 6 lifespans (ephemeral, turn, context, session, workflow, project). Use when creating agents that survive across turns, managing workflow-scoped execution, or needing automatic cleanup at lifecycle boundaries.
---
# Managing Agent Lifecycles
Persistent agent lifecycle management for Claude Code projects. Creates agents with defined lifespans and automatic disposal.
## When to Use
- Creating agents that persist beyond a single call
- Managing workflow-scoped agents (story execution, feature development)
- Automatic agent cleanup at lifecycle boundaries (Stop, SessionEnd)
- Building systems with multiple cooperating agents
## Quick Start
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
const registry = new AgentRegistry();
// Create session-scoped agent (survives until session ends)
const { agent, isNew } = await registry.create({
lifespan: 'session',
name: 'my-advisor',
model: 'haiku',
});
// Resume later in same session
const advisor = await registry.resume('my-advisor');
```
## The 6 Lifespans
| Lifespan | Auto-Disposal | Use Case |
|----------|---------------|----------|
| `ephemeral` | Immediately | Fire-and-forget tasks |
| `turn` | Stop event | Per-response helpers |
| `context` | Context reset | Multi-turn conversations |
| `session` | SessionEnd | Knowledge advisors |
| `workflow` | Manual/complete | Story/feature execution |
| `project` | Manual only | Singleton services |
### Choosing a Lifespan
```
How long should the agent live?
├── Just this one call? → ephemeral
├── Until response completes? → turn
├── Until context resets? → context
├── Until session ends? → session
├── Until work unit completes? → workflow
└── Forever (manual disposal)? → project
```
## Implementation Checklist
When implementing agent lifecycle management:
- [ ] Install package: `bun add claude-agent-lifecycle`
- [ ] Choose appropriate lifespan for each agent type
- [ ] Configure hooks for automatic disposal (Stop, SessionEnd)
- [ ] Use descriptive agent names (e.g., `backend-dev` not `agent1`)
- [ ] Store role and capabilities in metadata
- [ ] Test with debug mode enabled
## Common Patterns
### Pattern 1: Session-Scoped Advisor
For agents persisting throughout a Claude Code session:
```typescript
const { agent, isNew } = await registry.create({
lifespan: 'session',
name: 'shadow-advisor',
model: 'haiku',
metadata: { role: 'knowledge-retrieval' },
});
```
### Pattern 2: Workflow-Scoped Execution
For agents tied to a unit of work:
```typescript
// Start executor for story
await registry.startWorkflow({
lifespan: 'workflow',
workflowId: 'FEAT-001',
name: 'executor',
});
// Add specialists
await registry.startWorkflow({
lifespan: 'workflow',
workflowId: 'FEAT-001',
name: 'backend-dev',
});
// Complete when done (disposes all workflow agents)
await registry.completeWorkflow('FEAT-001');
```
### Pattern 3: Turn-Scoped Helper
For short-lived per-response agents:
```typescript
const { agent } = await registry.create({
lifespan: 'turn',
name: 'code-analyzer',
});
// Automatically disposed when Stop hook fires
```
See `patterns.md` for detailed implementations.
## Hook Integration
Hooks automatically dispose agents at lifecycle boundaries.
### hooks/hooks.json
```json
{
"Stop": [{
"hooks": [{
"type": "command",
"command": "bun \"${CLAUDE_PLUGIN_ROOT}/hooks/lifecycle-manager.ts\""
}]
}],
"SessionEnd": [{
"hooks": [{
"type": "command",
"command": "bun \"${CLAUDE_PLUGIN_ROOT}/hooks/lifecycle-manager.ts\""
}]
}]
}
```
### hooks/lifecycle-manager.ts
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
import { getHookEvent } from 'claude-hooks-sdk';
const event = getHookEvent();
const registry = new AgentRegistry();
if (event.type === 'Stop') {
await registry.disposeByLifespan('turn');
}
if (event.type === 'SessionEnd') {
await registry.disposeByScope(event.session.sessionId);
}
```
## Storage Structure
```
.agent/agents/
├── session/{session-id}/{agent-name}.json
├── workflow/{workflow-id}/{agent-name}.json
└── project/{agent-name}.json
```
## Debug Mode
Enable for troubleshooting:
```bash
AGENT_LIFECYCLE_DEBUG=true claude
```
Output:
```
[agent-lifecycle] Created: shadow-advisor (session)
[agent-lifecycle] Stop: Disposed 1 turn-scoped agents
```
## API Summary
| Method | Purpose |
|--------|---------|
| `create(config)` | Create or resume agent |
| `resume(name)` | Resume by name |
| `dispose(id)` | Dispose specific agent |
| `startWorkflow(config)` | Start workflow agent |
| `completeWorkflow(id)` | Complete and dispose workflow |
See `api-reference.md` for complete API documentation.
## Installation
```bash
# As plugin (recommended)
/plugin marketplace add hgeldenhuys/claude-agent-lifecycle
/plugin install claude-agent-lifecycle
# As package
bun add claude-agent-lifecycle
```
## Related Files
- `api-reference.md` - Complete API documentation
- `patterns.md` - Detailed pattern implementations
- `examples.md` - Real-world usage examples

View File

@@ -0,0 +1,270 @@
# API Reference
Complete API documentation for claude-agent-lifecycle.
## Table of Contents
1. [AgentRegistry](#agentregistry)
2. [Methods](#methods)
3. [Types](#types)
4. [Storage Backends](#storage-backends)
---
## AgentRegistry
Main class for managing agent lifecycles.
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
const registry = new AgentRegistry(options?: RegistryOptions);
```
### RegistryOptions
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `storagePath` | `string` | `.agent/agents` | Base path for file storage |
| `debug` | `boolean` | `false` | Enable debug logging |
---
## Methods
### create(config)
Creates a new agent or resumes an existing one.
```typescript
const { agent, isNew } = await registry.create({
lifespan: 'session',
name: 'my-agent',
sessionId?: string, // Auto-detected if not provided
model?: string, // 'haiku', 'sonnet', 'opus'
metadata?: Record<string, unknown>,
});
```
**Returns**: `{ agent: Agent, isNew: boolean }`
**Behavior**:
- If agent with same name exists in scope, resumes it
- If not, creates new agent
- `isNew` indicates whether agent was created or resumed
### resume(name, scope?)
Resumes an existing agent by name.
```typescript
const agent = await registry.resume('my-agent');
const agent = await registry.resume('my-agent', 'session-123');
```
**Returns**: `Agent | null`
**Throws**: If agent not found and no scope provided
### dispose(agentId)
Disposes a specific agent by ID.
```typescript
await registry.dispose('agent-uuid-here');
```
**Returns**: `void`
### disposeByLifespan(lifespan)
Disposes all agents of a specific lifespan type.
```typescript
const count = await registry.disposeByLifespan('turn');
```
**Returns**: `number` - Count of disposed agents
### disposeByScope(scope)
Disposes all agents in a specific scope.
```typescript
const count = await registry.disposeByScope('session-123');
```
**Returns**: `number` - Count of disposed agents
### list(filter?)
Lists agents matching optional filter criteria.
```typescript
// List all agents
const all = await registry.list();
// Filter by lifespan
const sessionAgents = await registry.list({ lifespan: 'session' });
// Filter by scope
const workflowAgents = await registry.list({ scope: 'FEAT-001' });
```
**Returns**: `Agent[]`
### startWorkflow(config)
Starts a workflow-scoped agent.
```typescript
const agent = await registry.startWorkflow({
lifespan: 'workflow',
workflowId: 'FEAT-001',
name: 'executor',
workflowType?: string, // e.g., 'loom-story'
model?: string,
metadata?: Record<string, unknown>,
});
```
**Returns**: `Agent`
### completeWorkflow(workflowId)
Completes a workflow and disposes all its agents.
```typescript
const disposed = await registry.completeWorkflow('FEAT-001');
```
**Returns**: `number` - Count of disposed agents
### getWorkflowAgents(workflowId)
Gets all agents for a specific workflow.
```typescript
const agents = await registry.getWorkflowAgents('FEAT-001');
```
**Returns**: `Agent[]`
---
## Types
### Agent
```typescript
interface Agent {
agentId: string; // Unique identifier (UUID)
name: string; // Human-readable name
lifespan: Lifespan; // One of 6 lifespans
scope: string; // Scope identifier
model?: string; // Model preference
turnCount: number; // Interaction count
metadata?: Record<string, unknown>;
createdAt: string; // ISO timestamp
lastActiveAt: string; // ISO timestamp
}
```
### Lifespan
```typescript
type Lifespan =
| 'ephemeral' // Single use
| 'turn' // Until Stop event
| 'context' // Until context reset
| 'session' // Until SessionEnd event
| 'workflow' // Until workflow completes
| 'project'; // Until manually disposed
```
### CreateConfig
```typescript
interface CreateConfig {
lifespan: Lifespan;
name: string;
sessionId?: string;
model?: string;
metadata?: Record<string, unknown>;
}
```
### WorkflowConfig
```typescript
interface WorkflowConfig {
lifespan: 'workflow';
workflowId: string;
name: string;
workflowType?: string;
model?: string;
metadata?: Record<string, unknown>;
}
```
### ListFilter
```typescript
interface ListFilter {
lifespan?: Lifespan;
scope?: string;
name?: string;
}
```
---
## Storage Backends
### MemoryStorage
Used for ephemeral, turn, and context lifespans.
- Data stored in memory
- Lost on process restart
- Fast access, no I/O
### FileStorage
Used for session, workflow, and project lifespans.
- Data persisted to JSON files
- Survives process restarts
- Structure:
```
.agent/agents/
├── lifecycle.log # Debug logs (when enabled)
├── session/
│ └── {session-id}/
│ └── {agent-name}.json
├── workflow/
│ └── {workflow-id}/
│ └── {agent-name}.json
└── project/
└── {agent-name}.json
```
### Agent JSON Format
```json
{
"agentId": "550e8400-e29b-41d4-a716-446655440000",
"name": "shadow-advisor",
"lifespan": "session",
"scope": "abc-123",
"model": "haiku",
"turnCount": 5,
"metadata": {
"role": "knowledge-retrieval",
"preloadedKnowledge": ["patterns", "pain-points"]
},
"createdAt": "2025-01-15T10:30:00Z",
"lastActiveAt": "2025-01-15T11:45:00Z"
}
```

View File

@@ -0,0 +1,372 @@
# Real-World Examples
Practical examples of agent lifecycle management in production systems.
## Table of Contents
1. [Shadow Advisor (claude-weave)](#example-1-shadow-advisor)
2. [Story Execution (claude-loom)](#example-2-story-execution)
3. [Custom Hook Handler](#example-3-custom-hook-handler)
4. [Debug Logging Setup](#example-4-debug-logging-setup)
---
## Example 1: Shadow Advisor
From claude-weave: A session-scoped knowledge retrieval agent.
### agents/shadow-advisor-lifecycle.ts
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
import { getSessionId } from 'claude-hooks-sdk';
const SHADOW_ADVISOR_CONFIG = {
lifespan: 'session' as const,
name: 'shadow-advisor',
model: 'haiku',
metadata: {
role: 'knowledge-retrieval',
preloadedKnowledge: [
'qualia', // Pain points, solutions
'epistemology', // Patterns, validations
'praxeology', // WoW patterns
],
capabilities: [
'query-11d-knowledge',
'synthesize-across-dimensions',
'recommend-patterns',
],
},
};
export async function getShadowAdvisor() {
const registry = new AgentRegistry();
const sessionId = getSessionId();
const { agent, isNew } = await registry.create({
...SHADOW_ADVISOR_CONFIG,
sessionId,
});
return { agent, isNew };
}
export async function resumeShadowAdvisor() {
const registry = new AgentRegistry();
return await registry.resume('shadow-advisor');
}
export async function disposeShadowAdvisor() {
const registry = new AgentRegistry();
const agent = await registry.resume('shadow-advisor');
if (agent) {
await registry.dispose(agent.agentId);
return true;
}
return false;
}
```
### Usage in Weave Hooks
```typescript
// hooks/weave-hooks.ts
import { getHookEvent } from 'claude-hooks-sdk';
import { getShadowAdvisor } from '../agents/shadow-advisor-lifecycle';
async function handleSessionStart() {
const { agent, isNew } = await getShadowAdvisor();
if (isNew) {
console.log('Shadow Advisor created for session');
// Load 11D knowledge into agent context...
} else {
console.log(`Shadow Advisor resumed (turn ${agent.turnCount})`);
}
}
```
---
## Example 2: Story Execution
From claude-loom: Workflow-scoped agents for story execution.
### agents/story-lifecycle.ts
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
interface StoryConfig {
storyId: string;
title: string;
acceptanceCriteria: string[];
}
export class StoryLifecycle {
private registry: AgentRegistry;
private storyId: string;
constructor(storyId: string) {
this.registry = new AgentRegistry();
this.storyId = storyId;
}
async start(config: StoryConfig) {
// Create main executor
const executor = await this.registry.startWorkflow({
lifespan: 'workflow',
workflowId: this.storyId,
name: 'story-executor',
workflowType: 'loom-story',
model: 'sonnet',
metadata: {
title: config.title,
acceptanceCriteria: config.acceptanceCriteria,
status: 'in-progress',
startedAt: new Date().toISOString(),
},
});
return executor;
}
async addSpecialist(
role: 'backend-dev' | 'frontend-dev' | 'backend-qa' | 'frontend-qa'
) {
const modelMap = {
'backend-dev': 'sonnet',
'frontend-dev': 'sonnet',
'backend-qa': 'haiku',
'frontend-qa': 'haiku',
};
return await this.registry.startWorkflow({
lifespan: 'workflow',
workflowId: this.storyId,
name: role,
model: modelMap[role],
metadata: {
role,
assignedAt: new Date().toISOString(),
},
});
}
async getActiveAgents() {
return await this.registry.getWorkflowAgents(this.storyId);
}
async complete(outcome: 'success' | 'failed' | 'cancelled') {
const agents = await this.getActiveAgents();
// Log completion stats
console.log(`Story ${this.storyId} ${outcome}`);
console.log(`Agents used: ${agents.length}`);
for (const agent of agents) {
console.log(` - ${agent.name}: ${agent.turnCount} turns`);
}
// Dispose all workflow agents
return await this.registry.completeWorkflow(this.storyId);
}
}
// Usage
async function executeStory() {
const story = new StoryLifecycle('FEAT-001');
await story.start({
storyId: 'FEAT-001',
title: 'Add user authentication',
acceptanceCriteria: [
'Users can sign up with email',
'Users can log in',
'Sessions persist across page reloads',
],
});
await story.addSpecialist('backend-dev');
await story.addSpecialist('backend-qa');
// ... execute story tasks ...
await story.complete('success');
}
```
---
## Example 3: Custom Hook Handler
Complete hook handler managing multiple agent types.
### hooks/lifecycle-manager.ts
```typescript
#!/usr/bin/env bun
import { AgentRegistry } from 'claude-agent-lifecycle';
import { getHookEvent, getSessionId } from 'claude-hooks-sdk';
const DEBUG = process.env.AGENT_LIFECYCLE_DEBUG === 'true'
|| process.argv.includes('--debug');
function log(message: string) {
if (DEBUG) {
console.log(`[agent-lifecycle] ${message}`);
}
}
async function main() {
const event = getHookEvent();
const registry = new AgentRegistry({ debug: DEBUG });
switch (event.type) {
case 'SessionStart': {
const sessionId = getSessionId();
log(`SessionStart: ${sessionId} (source: ${event.source})`);
// List active agents
const agents = await registry.list();
if (agents.length > 0) {
log(`Active agents: ${agents.map(a => `${a.name}(${a.lifespan})`).join(', ')}`);
}
break;
}
case 'Stop': {
// Dispose turn-scoped agents
const turnCount = await registry.disposeByLifespan('turn');
if (turnCount > 0) {
log(`Stop: Disposed ${turnCount} turn-scoped agents`);
}
break;
}
case 'SessionEnd': {
const sessionId = event.session?.sessionId;
if (sessionId) {
// Dispose session-scoped agents
const sessionCount = await registry.disposeByScope(sessionId);
log(`SessionEnd: Disposed ${sessionCount} agents for session ${sessionId}`);
}
break;
}
}
}
main().catch(error => {
console.error('[agent-lifecycle] Error:', error.message);
process.exit(1);
});
```
---
## Example 4: Debug Logging Setup
Setting up comprehensive debug logging.
### Enable Debug Mode
```bash
# Option 1: Environment variable
export AGENT_LIFECYCLE_DEBUG=true
claude
# Option 2: Per-session
AGENT_LIFECYCLE_DEBUG=true claude
# Option 3: In hook command
# hooks/hooks.json
{
"Stop": [{
"hooks": [{
"type": "command",
"command": "bun hooks/lifecycle-manager.ts --debug"
}]
}]
}
```
### Custom Debug Logger
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
import * as fs from 'fs';
class DebugRegistry extends AgentRegistry {
private logPath: string;
constructor(logPath = '.agent/agents/debug.log') {
super({ debug: true });
this.logPath = logPath;
}
private writeLog(entry: object) {
const line = JSON.stringify({
timestamp: new Date().toISOString(),
...entry,
});
fs.appendFileSync(this.logPath, line + '\n');
}
async create(config: any) {
const result = await super.create(config);
this.writeLog({
event: result.isNew ? 'agent:created' : 'agent:resumed',
agentId: result.agent.agentId,
name: result.agent.name,
lifespan: result.agent.lifespan,
});
return result;
}
async dispose(agentId: string) {
this.writeLog({
event: 'agent:disposed',
agentId,
});
return super.dispose(agentId);
}
async completeWorkflow(workflowId: string) {
const agents = await this.getWorkflowAgents(workflowId);
this.writeLog({
event: 'workflow:completed',
workflowId,
agentCount: agents.length,
agents: agents.map(a => a.name),
});
return super.completeWorkflow(workflowId);
}
}
// Usage
const registry = new DebugRegistry();
```
### Debug Log Output
```jsonl
{"timestamp":"2025-01-15T10:30:00Z","event":"agent:created","agentId":"abc-123","name":"shadow-advisor","lifespan":"session"}
{"timestamp":"2025-01-15T10:30:05Z","event":"agent:created","agentId":"def-456","name":"backend-dev","lifespan":"workflow"}
{"timestamp":"2025-01-15T10:45:00Z","event":"workflow:completed","workflowId":"FEAT-001","agentCount":3,"agents":["executor","backend-dev","backend-qa"]}
{"timestamp":"2025-01-15T11:00:00Z","event":"agent:disposed","agentId":"abc-123"}
```
---
## Integration Checklist
When integrating agent lifecycle into your project:
- [ ] Install: `bun add claude-agent-lifecycle`
- [ ] Create hooks directory with `hooks.json`
- [ ] Implement `lifecycle-manager.ts` hook handler
- [ ] Define agent configurations (lifespan, name, metadata)
- [ ] Add debug logging for development
- [ ] Test all lifecycle events (SessionStart, Stop, SessionEnd)
- [ ] Verify automatic disposal at boundaries
- [ ] Document agent roles and lifespans

View File

@@ -0,0 +1,356 @@
# Agent Lifecycle Patterns
Detailed implementations of common agent lifecycle patterns.
## Table of Contents
1. [Session-Scoped Advisor](#pattern-1-session-scoped-advisor)
2. [Workflow-Scoped Execution](#pattern-2-workflow-scoped-execution)
3. [Turn-Scoped Helper](#pattern-3-turn-scoped-helper)
4. [Project Singleton](#pattern-4-project-singleton)
5. [Multi-Agent Orchestration](#pattern-5-multi-agent-orchestration)
---
## Pattern 1: Session-Scoped Advisor
Agents that persist throughout a Claude Code session, ideal for knowledge retrieval and advisory roles.
### Use Cases
- Knowledge advisors (Shadow Advisor, Librarian)
- Context-aware assistants
- Session-wide configuration managers
### Implementation
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
export async function getSessionAdvisor(role: string) {
const registry = new AgentRegistry();
const { agent, isNew } = await registry.create({
lifespan: 'session',
name: `${role}-advisor`,
model: 'haiku',
metadata: {
role,
capabilities: ['knowledge-retrieval', 'pattern-matching'],
preloadedAt: new Date().toISOString(),
},
});
if (isNew) {
// First creation - load initial context
console.log(`Created new ${role} advisor`);
// Initialize with domain knowledge...
} else {
// Resumed - increment interaction count
console.log(`Resumed ${role} advisor (turn ${agent.turnCount})`);
}
return agent;
}
// Usage
const shadow = await getSessionAdvisor('shadow');
const librarian = await getSessionAdvisor('librarian');
```
### Hook Integration
Automatically disposed at SessionEnd:
```typescript
// hooks/session-cleanup.ts
import { AgentRegistry } from 'claude-agent-lifecycle';
import { getHookEvent } from 'claude-hooks-sdk';
const event = getHookEvent();
if (event.type === 'SessionEnd') {
const registry = new AgentRegistry();
const count = await registry.disposeByScope(event.session.sessionId);
console.log(`Disposed ${count} session agents`);
}
```
---
## Pattern 2: Workflow-Scoped Execution
Agents tied to a bounded unit of work (story, feature, task). Multiple specialists collaborate on a shared workflow.
### Use Cases
- Story execution (Loom)
- Feature development
- Multi-step task orchestration
### Implementation
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
export class WorkflowOrchestrator {
private registry: AgentRegistry;
private workflowId: string;
constructor(workflowId: string) {
this.registry = new AgentRegistry();
this.workflowId = workflowId;
}
async start() {
// Create main executor
return await this.registry.startWorkflow({
lifespan: 'workflow',
workflowId: this.workflowId,
name: 'executor',
workflowType: 'story-execution',
model: 'sonnet',
metadata: {
startedAt: new Date().toISOString(),
status: 'in-progress',
},
});
}
async addSpecialist(role: string) {
const validRoles = [
'backend-dev',
'frontend-dev',
'backend-qa',
'frontend-qa',
'cli-dev',
];
if (!validRoles.includes(role)) {
throw new Error(`Invalid role: ${role}`);
}
return await this.registry.startWorkflow({
lifespan: 'workflow',
workflowId: this.workflowId,
name: role,
model: role.includes('qa') ? 'haiku' : 'sonnet',
metadata: { role, assignedAt: new Date().toISOString() },
});
}
async getStatus() {
const agents = await this.registry.getWorkflowAgents(this.workflowId);
return {
workflowId: this.workflowId,
agentCount: agents.length,
agents: agents.map(a => ({
name: a.name,
turnCount: a.turnCount,
lastActive: a.lastActiveAt,
})),
};
}
async complete() {
const count = await this.registry.completeWorkflow(this.workflowId);
console.log(`Completed workflow ${this.workflowId}, disposed ${count} agents`);
return count;
}
}
// Usage
const orchestrator = new WorkflowOrchestrator('FEAT-001');
await orchestrator.start();
await orchestrator.addSpecialist('backend-dev');
await orchestrator.addSpecialist('backend-qa');
// ... execute work ...
await orchestrator.complete();
```
---
## Pattern 3: Turn-Scoped Helper
Short-lived agents that assist with a single response cycle. Automatically disposed when Stop hook fires.
### Use Cases
- Code analysis helpers
- One-off data processors
- Temporary computation agents
### Implementation
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
export async function createTurnHelper(task: string) {
const registry = new AgentRegistry();
const { agent } = await registry.create({
lifespan: 'turn',
name: `helper-${task}`,
model: 'haiku',
metadata: {
task,
createdFor: 'single-response',
},
});
return agent;
}
// Usage - agent disposed automatically at Stop
const analyzer = await createTurnHelper('code-analysis');
const formatter = await createTurnHelper('output-formatting');
```
### Hook Integration
```typescript
// hooks/turn-cleanup.ts
import { AgentRegistry } from 'claude-agent-lifecycle';
import { getHookEvent } from 'claude-hooks-sdk';
const event = getHookEvent();
if (event.type === 'Stop') {
const registry = new AgentRegistry();
const count = await registry.disposeByLifespan('turn');
if (count > 0) {
console.log(`Disposed ${count} turn-scoped agents`);
}
}
```
---
## Pattern 4: Project Singleton
Agents that persist indefinitely, shared across all sessions. Requires manual disposal.
### Use Cases
- Project configuration managers
- Shared knowledge bases
- Cross-session state holders
### Implementation
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
export async function getProjectSingleton(name: string) {
const registry = new AgentRegistry();
const { agent, isNew } = await registry.create({
lifespan: 'project',
name,
metadata: {
singleton: true,
initVersion: '1.0.0',
},
});
if (isNew) {
console.log(`Created project singleton: ${name}`);
} else {
console.log(`Using existing singleton: ${name} (${agent.turnCount} turns)`);
}
return agent;
}
// Manual disposal when needed
export async function disposeProjectSingleton(name: string) {
const registry = new AgentRegistry();
const agent = await registry.resume(name);
if (agent) {
await registry.dispose(agent.agentId);
console.log(`Disposed project singleton: ${name}`);
}
}
```
---
## Pattern 5: Multi-Agent Orchestration
Coordinating multiple agents across different lifespans.
### Implementation
```typescript
import { AgentRegistry } from 'claude-agent-lifecycle';
export class MultiAgentSystem {
private registry: AgentRegistry;
constructor() {
this.registry = new AgentRegistry({ debug: true });
}
async initialize(sessionId: string, workflowId: string) {
// Session-scoped: knowledge advisors
await this.registry.create({
lifespan: 'session',
name: 'shadow-advisor',
sessionId,
model: 'haiku',
});
await this.registry.create({
lifespan: 'session',
name: 'librarian',
sessionId,
model: 'haiku',
});
// Workflow-scoped: execution agents
await this.registry.startWorkflow({
lifespan: 'workflow',
workflowId,
name: 'executor',
model: 'sonnet',
});
// Turn-scoped: temporary helpers created as needed
// (created per-request, not at initialization)
}
async getSystemStatus() {
const agents = await this.registry.list();
return {
total: agents.length,
byLifespan: {
session: agents.filter(a => a.lifespan === 'session').length,
workflow: agents.filter(a => a.lifespan === 'workflow').length,
turn: agents.filter(a => a.lifespan === 'turn').length,
project: agents.filter(a => a.lifespan === 'project').length,
},
agents: agents.map(a => ({
name: a.name,
lifespan: a.lifespan,
scope: a.scope,
turns: a.turnCount,
})),
};
}
}
```
---
## Best Practices Summary
| Pattern | Lifespan | Model | Disposal |
|---------|----------|-------|----------|
| Knowledge Advisor | session | haiku | SessionEnd hook |
| Workflow Executor | workflow | sonnet | completeWorkflow() |
| Workflow Specialist | workflow | sonnet/haiku | completeWorkflow() |
| Turn Helper | turn | haiku | Stop hook |
| Project Singleton | project | varies | Manual |

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# claude-agent-lifecycle
Persistent agent lifecycle management for Claude Code. Provides 6 agent lifespans (ephemeral, turn, context, session, workflow, project) with automatic disposal via hooks.

57
plugin.lock.json Normal file
View File

@@ -0,0 +1,57 @@
{
"$schema": "internal://schemas/plugin.lock.v1.json",
"pluginId": "gh:hgeldenhuys/claude-agent-lifecycle:",
"normalized": {
"repo": null,
"ref": "refs/tags/v20251128.0",
"commit": "e52859c64f43f3adcef60fe99cd72a6608c55146",
"treeHash": "92549440c37c3cb2ce5cf5f7780b4a6f0b5e1b43720e6ada92266117de29d829",
"generatedAt": "2025-11-28T10:17:25.928386Z",
"toolVersion": "publish_plugins.py@0.2.0"
},
"origin": {
"remote": "git@github.com:zhongweili/42plugin-data.git",
"branch": "master",
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
},
"manifest": {
"name": "claude-agent-lifecycle",
"description": "Persistent agent lifecycle management for Claude Code. Provides 6 agent lifespans (ephemeral, turn, context, session, workflow, project) with automatic disposal via hooks.",
"version": "1.0.0"
},
"content": {
"files": [
{
"path": "README.md",
"sha256": "1e317d0ac04c5ae7eb5a95db05b52299b3764d7c3babf7c9c51d5221f3834794"
},
{
"path": ".claude/skills/managing-agent-lifecycles/examples.md",
"sha256": "7e03cd6f07583e953e41e20bcc263bcb0c915a524a912ae5b4412753241d13ce"
},
{
"path": ".claude/skills/managing-agent-lifecycles/patterns.md",
"sha256": "5480f50288cdcd684ae20a2b582b8cd8e7c0128e6be1e38740ec5f91bceabaca"
},
{
"path": ".claude/skills/managing-agent-lifecycles/SKILL.md",
"sha256": "defd9e354a411cc475ef01bd31e048386f916490c2ec4c87cf482f13bbcd03c8"
},
{
"path": ".claude/skills/managing-agent-lifecycles/api-reference.md",
"sha256": "2dc50f3cc8520c8ab7cb80d7d4ac5cf42d151c87c8cc0d8c494fd1720793f6db"
},
{
"path": ".claude-plugin/plugin.json",
"sha256": "fa8d24e52608648ac23cffabb26471380aa872f9909a7ae605de6458a663e97c"
}
],
"dirSha256": "92549440c37c3cb2ce5cf5f7780b4a6f0b5e1b43720e6ada92266117de29d829"
},
"security": {
"scannedAt": null,
"scannerVersion": null,
"flags": []
}
}