A config-driven LLM framework built on top of PocketFlow
npm install backpackflowA TypeScript-first, config-driven LLM framework built on top of PocketFlow.
BackpackFlow extends PocketFlow with a specific philosophy: The Code is the Engine, the Config is the Steering Wheel.


> โก v2.0 "The Observable Agent" - Build production-ready AI agents with complete observability, Zod-based type safety, and nested flow composition. TypeScript-first, config-driven, and ready for visual builders.
---
Most LLM development hits three major walls:
---
We solve these pain points with a TypeScript-First, Config-Driven architecture.
Think of Backpack as "Git for your agent's memory."
Just like Git tracks every code change with commits, Backpack tracks every data change in your agent:
``mermaid`
graph LR
subgraph Git["๐ง Git (Code Versioning)"]
G1["git commit"]
G2["git log"]
G3["git checkout abc123"]
G4["git diff"]
end
subgraph Backpack["๐ Backpack (State Versioning)"]
B1["backpack.pack('key', value)"]
B2["backpack.getHistory()"]
B3["backpack.getSnapshot()"]
B4["backpack.diff(before, after)"]
end
G1 -.->|"Same Concept"| B1
G2 -.->|"Same Concept"| B2
G3 -.->|"Same Concept"| B3
G4 -.->|"Same Concept"| B4
style Git fill:#f0f0f0,stroke:#333,stroke-width:2px
style Backpack fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
Why "Backpack"? Because your agent carries explicit data from node to node:
- ๐ Nothing is hidden - if it's not in the Backpack, the agent can't use it
- ๐ Every item is tagged with who packed it, when, and why
- ๐ซ Nodes declare access permissions - can't accidentally read debug data or PII
- โฑ๏ธ Complete audit trail - trace any data back to its source
The Result: Instead of debugging "black box" state mutations, you have:
- โ
Immutable History - Every data change is tracked (like Git commits)
- โ
Time-Travel Debugging - Rewind to any previous state (git checkout)git blame
- โ
Complete Auditability - Know exactly who changed what, when ()
- โ
Access Control - Nodes declare what they can read/write (unlike SharedStore)
If Git made code development manageable, Backpack makes agent development manageable.
We are building a "bridge" where Code and Config are interchangeable.
- The Engine: You write complex logic in TypeScript Nodes
- The Steering Wheel: The framework serializes your Nodes into JSON Config
- The Result: Build a UI Layer that can visualize and edit your flow, but allows you to "eject" to raw code whenever needed
`mermaid`
graph LR
A[TypeScript Code] -->|Compiles to| B(The Engine)
A -->|Serializes to| C{JSON Config}
C -->|Hydrates| B
C <-->|Syncs with| D[Future Web GUI]
style A fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#bbf,stroke:#333,stroke-width:2px
Build your backend logic AND your web UI in the same language. Share types, schemas, and validation logic seamlessly.
---
"The Observable Agent" - Complete rewrite with production-ready observability
- Architecture: Git-like state management with immutable history
- Type Safety: Full Zod schema validation with type inference
- Observability: Automatic event emission and time-travel debugging
- Composition: Nested flows with recursive serialization
- Config-Driven: Complete JSON serialization for visual builders
๐ See Full Roadmap | Migration from v1.x
#### ๐ Backpack: Git-Like State Management
๐ Documentation
Think of it as "Git for your agent's memory" - every data change is tracked with full history:
- Immutable History: Every state change recorded like Git commits
- Time-Travel Debugging: Rewind to any previous state to see what the agent "knew"
- Source Tracking: Know exactly which node added/modified each piece of data
- Access Control: Nodes declare what they can read/write with wildcard support
- State Quarantine: Isolate failed operations from downstream nodes
`mermaid`
%%{init: {'theme':'base'}}%%
timeline
title Backpack State History (Like Git Log)
section Node A
Commit 1 : pack('query', 'AI agents')
section Node B
Commit 2 : pack('results', [...])
Commit 3 : pack('filtered', [...])
section Node C
Commit 4 : pack('summary', 'Analysis...')
section Time-Travel
Checkpoint : getSnapshot() โ Rewind to any point
#### ๐ก Event Streaming: Complete Observability
๐ Documentation
Automatic event emission for every node lifecycle event - no manual logging needed:
- 5 Event Types: NODE_START, PREP_COMPLETE, EXEC_COMPLETE, NODE_END, ERRORPREP_COMPLETE
- Prompt Inspection: See exact LLM prompts via events
- Parse Error Visibility: Inspect raw responses before JSON parsing fails
- Namespace Filtering: Subscribe to events with wildcard patterns
- Event History: Built-in event storage for post-mortem debugging
`mermaid`
graph LR
A[NODE_START] --> B[PREP_COMPLETE]
B --> C[EXEC_COMPLETE]
C --> D[NODE_END]
B -.->|"Error in prep()"| E[ERROR]
C -.->|"Error in _exec()"| E
B -->|"๐ Emits"| B1["Input data
LLM prompts"]
C -->|"๐ Emits"| C1["Execution result
Raw LLM response"]
D -->|"๐ Emits"| D1["Final action
Duration"]
E -->|"๐ Emits"| E1["Error details
Stack trace"]
style A fill:#4caf50,stroke:#333,color:#fff
style D fill:#2196f3,stroke:#333,color:#fff
style E fill:#f44336,stroke:#333,color:#fff
style B1 fill:#fff3cd,stroke:#856404
style C1 fill:#fff3cd,stroke:#856404
style D1 fill:#d1ecf1,stroke:#0c5460
style E1 fill:#f8d7da,stroke:#721c24
#### ๐ Config-Driven Architecture
๐ Documentation
Bidirectional conversion between TypeScript code and JSON configs:
- JSON Serialization: Export complete flows to JSON for storage/transfer
- Type-Safe Loading: Zod-validated configs prevent runtime errors
- Dependency Injection: Clean handling of non-serializable objects (LLM clients, DBs)
- Round-Trip Guarantee: fromConfig(toConfig()) preserves node identity
- UI-Ready: Foundation for drag-and-drop flow builders
`mermaid`
graph LR
subgraph Code["๐ป TypeScript Code"]
Node["class MyNode extends BackpackNode {
params = {...}
async _exec() {...}
}"]
end
subgraph Config["๐ JSON Config"]
JSON["{
type: 'MyNode',
id: 'node1',
params: {...},
internalFlow: {...}
}"]
end
subgraph UI["๐จ Visual Builder"]
Drag["Drag & Drop
Flow Editor"]
end
Node -->|"toConfig()"| JSON
JSON -->|"fromConfig()"| Node
JSON <-->|"Edit/View"| UI
Check["โ
Round-Trip Verified:
Node identity preserved"]
JSON -.-> Check
Node -.-> Check
style Code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
style Config fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
style UI fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style Check fill:#c8e6c9,stroke:#388e3c
#### ๐ Nested Flows & Composition
๐ Documentation
Build complex agents from reusable components with standard patterns:
- createInternalFlow(): Auto-wiring of namespace, backpack, and events
- Recursive Serialization: Complete nested structure in JSON
- Convenience Methods: .onComplete(), .onError() instead of string-based routingflattenNodes()
- FlowAction Enum: Type-safe routing with standardized actions
- Query API: , findNode(), getMaxDepth() for flow introspection
`mermaid`
graph TB
Entry["๐ Entry Node"] --> Agent
subgraph Agent["๐ฆ YouTubeResearchAgent (Composite Node)"]
direction TB
AgentStart["โถ๏ธ _exec() called"] --> CreateFlow["createInternalFlow()"]
subgraph InternalFlow["๐ Internal Flow
(Auto-wired: namespace, backpack, eventStreamer)"]
direction LR
Search["๐ YouTube
Search"] -->|"onComplete()"| Analysis["๐ Data
Analysis"]
Analysis -->|"onComplete()"| Summary["๐ค LLM
Summary"]
end
CreateFlow --> InternalFlow
InternalFlow --> AgentComplete["โ
return 'complete'"]
end
Agent --> Exit["๐ฏ Exit Node"]
style Entry fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#fff
style Agent fill:#fff59d,stroke:#f57f17,stroke-width:3px
style InternalFlow fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
style Search fill:#4fc3f7,stroke:#0277bd,stroke-width:2px
style Analysis fill:#81c784,stroke:#388e3c,stroke-width:2px
style Summary fill:#ffb74d,stroke:#e65100,stroke-width:2px
style AgentStart fill:#e0e0e0,stroke:#616161
style CreateFlow fill:#e0e0e0,stroke:#616161
style AgentComplete fill:#c8e6c9,stroke:#388e3c,stroke-width:2px
style Exit fill:#2196f3,stroke:#0d47a1,stroke-width:2px,color:#fff
#### ๐ Data Contracts & Type Safety
๐ Documentation
Zod-powered input/output contracts for bulletproof type safety:
- Explicit Contracts: Nodes declare expected inputs and outputs with Zod schemas
- Runtime Validation: Automatic validation with detailed error messages
- Type Inference: Full TypeScript types inferred from schemas
- Data Mappings: Edge-level key remapping for flexible composition
- JSON Schema Export: Generate schemas for UI form builders
`mermaid`
graph LR
subgraph NodeA["๐ท Search Node"]
A1["outputs: {
query: z.string()
results: z.array(...)
}"]
end
subgraph Edge["๐ Edge Mapping"]
E1["mappings: {
results โ data
}"]
end
subgraph NodeB["๐ถ Analysis Node"]
B1["inputs: {
data: z.array(...)
}"]
B2["โ
Validated!"]
end
NodeA -->|"results"| Edge
Edge -->|"data"| NodeB
B1 --> B2
style NodeA fill:#e3f2fd,stroke:#1976d2
style NodeB fill:#fff3e0,stroke:#e65100
style Edge fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
style B2 fill:#c8e6c9,stroke:#388e3c
``
backpackflow/
โโโ src/ # Source code
โ โโโ pocketflow.ts # PocketFlow core (ported)
โ โโโ index.ts # Main entry point
โโโ tests/ # Test files
โโโ tutorials/ # Learning guides and examples
โโโ dist/ # Compiled output
โโโ docs/ # Documentation
`bash`
npm install backpackflow zod
Dependencies:
- zod - Required for data contracts and validation (v2.0+)
`mermaid`
sequenceDiagram
participant F as Flow
participant N as Node
participant B as Backpack
participant E as EventStreamer
F->>N: Start execution
N->>E: Emit NODE_START
rect rgb(230, 240, 255)
Note over N,B: prep() - Read inputs
N->>B: unpack('name')
B-->>N: 'World'
N->>E: Emit PREP_COMPLETE
end
rect rgb(240, 255, 230)
Note over N: _exec() - Process
N->>N: Execute logic
N->>E: Emit EXEC_COMPLETE
end
rect rgb(255, 240, 230)
Note over N,B: post() - Write outputs
N->>B: pack('greeting', result)
B-->>B: Commit to history
N->>E: Emit NODE_END
end
N-->>F: Return action ('complete')
`typescript
import { BackpackNode, NodeConfig, NodeContext } from 'backpackflow';
import { z } from 'zod';
// Define your node with Zod contracts
class GreetingNode extends BackpackNode {
static namespaceSegment = "greeting";
// โจ Explicit input/output contracts
static inputs = {
name: z.string().min(1).describe('User name')
};
static outputs = {
greeting: z.string().describe('Generated greeting')
};
async prep(shared: any) {
return this.unpackRequired('name'); // Runtime validation!
}
async _exec(name: string) {
return Hello, ${name}! Welcome to BackpackFlow v2.0!;`
}
async post(shared: any, prep: any, greeting: string) {
this.pack('greeting', greeting); // Tracked in Backpack history
return 'complete';
}
}
`typescript
import { Flow, Backpack, EventStreamer } from 'backpackflow';
// Create observable flow
const backpack = new Backpack({});
const eventStreamer = new EventStreamer({ enableHistory: true });
const flow = new Flow({
namespace: 'demo',
backpack,
eventStreamer
});
// Add node
const greetNode = flow.addNode(GreetingNode, { id: 'greet' });
// Listen to events
eventStreamer.on('*', (event) => {
console.log([${event.type}] ${event.nodeName});
});
// Pack input and run
backpack.pack('name', 'World');
await flow.run({});
// Access result
const greeting = backpack.unpack('greeting');
console.log(greeting); // "Hello, World! Welcome to BackpackFlow v2.0!"
`
`typescript
// Get complete history
const history = backpack.getHistory();
console.log('All state changes:', history);
// Get snapshot at specific point
const snapshot = backpack.getSnapshot();
console.log('Current state:', snapshot);
// Diff between states
const before = backpack.getSnapshot();
// ... make changes ...
const after = backpack.getSnapshot();
const diff = backpack.diff(before, after);
console.log('What changed:', diff);
`
`typescript
import { FlowLoader } from 'backpackflow/serialization';
const loader = new FlowLoader();
loader.register('GreetingNode', GreetingNode);
// Export complete flow structure
const config = loader.exportFlow(flow);
console.log(JSON.stringify(config, null, 2));
// Load from config
const loadedFlow = await loader.loadFlow(config, deps);
`
`bashInstall dependencies
npm install
๐ Learning & Examples
$3
tutorials/youtube-research-agent/ - Production-ready agent showcasing all v2.0 features:`typescript
class YouTubeResearchAgentNode extends BackpackNode {
async _exec(input: any) {
// โจ Create internal flow with auto-wiring
const flow = this.createInternalFlow();
const searchNode = flow.addNode(YouTubeSearchNode, { id: 'search' });
const analysisNode = flow.addNode(DataAnalysisNode, { id: 'analysis' });
const summaryNode = flow.addNode(BaseChatCompletionNode, { id: 'summary' });
// โจ Clean routing with convenience methods
searchNode.onComplete(analysisNode);
analysisNode.onComplete(summaryNode);
await flow.run({});
}
}
``mermaid
graph LR
User["๐ค User
'AI agents'"] --> Search["๐ YouTube Search
Contract:
in: query
out: videos[]"]
Search -->|"onComplete()"| Analysis["๐ Data Analysis
Contract:
in: videos[]
out: statistics"]
Analysis -->|"onComplete()"| Summary["๐ค LLM Summary
Contract:
in: statistics
out: summary"]
Summary --> Result["๐ Result
'Found 45 videos...'"]
subgraph Events["๐ก Event Stream"]
E1["NODE_START ร 3"]
E2["PREP_COMPLETE ร 3"]
E3["EXEC_COMPLETE ร 3"]
E4["NODE_END ร 3"]
end
Search -.->|"Emits"| Events
Analysis -.->|"Emits"| Events
Summary -.->|"Emits"| Events
style Search fill:#4fc3f7,stroke:#0277bd,stroke-width:2px
style Analysis fill:#81c784,stroke:#388e3c,stroke-width:2px
style Summary fill:#ffb74d,stroke:#e65100,stroke-width:2px
style Events fill:#f3e5f5,stroke:#7b1fa2
style User fill:#fff9c4,stroke:#f57f17
style Result fill:#c8e6c9,stroke:#388e3c
`Features demonstrated:
- ๐ Composite nodes with nested flows
- โ
Zod-based data contracts with type inference
- ๐ก Event streaming with hierarchical visualization
- ๐พ Complete flow serialization to JSON
- ๐ฏ Channel-relative outlier detection algorithm
$3
Advanced Patterns:
- PocketFlow Cookbook - Advanced workflow patterns
Legacy Examples (v1.x):
- Simple Sales Agent - Tool integration and streaming
- Building AI from First Principles - Foundational concepts
- Simple Chatbot - Basic chatbot implementation
See the
tutorials/ directory for all examples.๐ What's New
$3
Major architectural rewrite with production-grade observability and type safety.
`mermaid
graph TB
subgraph Flow["๐ Flow Orchestration"]
N1[Node A] -->|"onComplete()"| N2[Node B]
N2 --> N3[Node C]
end
subgraph Backpack["๐ Backpack (State)"]
H1["๐ Immutable History"]
H2["๐ฏ Access Control"]
H3["โฑ๏ธ Time Travel"]
end
subgraph Events["๐ก Event Streaming"]
E1["NODE_START"]
E2["EXEC_COMPLETE"]
E3["ERROR"]
end
subgraph Serialization["๐พ Serialization"]
S1["toConfig() โ JSON"]
S2["fromConfig() โ Code"]
end
subgraph Contracts["๐ Data Contracts"]
C1["Zod Validation"]
C2["Edge Mappings"]
end
N1 -.->|"pack()/unpack()"| Backpack
N2 -.->|"pack()/unpack()"| Backpack
N3 -.->|"pack()/unpack()"| Backpack
N1 -.->|"emit"| Events
N2 -.->|"emit"| Events
N3 -.->|"emit"| Events
Flow -->|"exportFlow()"| Serialization
Serialization -->|"loadFlow()"| Flow
N1 --> Contracts
N2 --> Contracts
N3 --> Contracts
style Flow fill:#e3f2fd,stroke:#1976d2,stroke-width:3px
style Backpack fill:#fff3e0,stroke:#e65100,stroke-width:2px
style Events fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
style Serialization fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
style Contracts fill:#fce4ec,stroke:#c2185b,stroke-width:2px
`#### ๐ฏ Core Systems
Backpack Architecture
- Git-like state management with immutable commit history
- Time-travel debugging with state snapshots
- Fine-grained access control with namespace wildcards
- State quarantine for isolating failed operations
Event Streaming
- 5 standardized event types for complete lifecycle visibility
- Automatic emission - zero manual logging required
- Namespace-based filtering with wildcard support
- Built-in event history for debugging
Config-Driven Serialization
- Bidirectional TypeScript โ JSON conversion
- Zod-powered validation for type safety
- Dependency injection for non-serializable objects
- Round-trip guarantee for config preservation
Nested Flows & Composition
-
createInternalFlow() with automatic context inheritance
- Recursive serialization for complete flow structure
- .onComplete() / .onError() convenience methods
- Query utilities for flow introspectionZod Data Contracts
- Explicit input/output declarations on nodes
- Runtime validation with detailed error messages
- Full TypeScript type inference
- Edge-level data mappings for key remapping
#### ๐ง Developer Experience
- Type Safety: End-to-end TypeScript with Zod schema validation
- Observability: See everything - prompts, responses, state changes, errors
- Debugging: Time-travel to any point in execution history
- Composition: Build complex agents from simple, reusable nodes
- UI-Ready: Complete serialization for visual flow builders
#### ๐ Resources
- Migration Guide from v1.x
- v2.0 Completion Summary
- Full PRD Documentation
---
$3
v1.2.0 - Event-Driven Architecture (Legacy)
- Explicit LLM client injection
- Enhanced event streaming with
StreamEventType enum
- Azure OpenAI support
- Improved AgentNode with better defaults
v1.1.0 - Event-Driven Streaming (Legacy)
-
EventStreamer for centralized event management
- Real-time streaming support
- High-level AgentNode orchestration
v1.0.x - Initial Release (Legacy)
- Basic PocketFlow integration
- OpenAI provider integration
- Core node types (Chat, Decision, utilities)
๐ค Join the Community
Want to contribute, get help, or share what you're building?
๐ Join our community - Connect with other developers building AI applications
๐ ๏ธ Contributing
Contributions are welcome! BackpackFlow v2.0 is feature-complete, but there's always room for:
- ๐ Bug fixes and improvements
- ๐ Documentation enhancements
- ๐ฏ More example agents and tutorials
- ๐งช Additional test coverage
- ๐ Performance optimizations
$3
Want to contribute? Start by understanding the core systems:
1. Backpack Architecture - State management with Git-like history
2. Event Streaming - Observability and telemetry
3. Serialization Bridge - Config-driven flows
4. Composite Nodes - Nested flow composition
5. Flow Observability - Data contracts and mappings
$3
1. Fork the repository
2. Create a feature branch (
git checkout -b feat/amazing-feature)
3. Make your changes
4. Run tests (npm test)
5. Build the project (npm run build`)๐ See the Roadmap for planned features and improvements.
Apache-2.0 - see the LICENSE file for details.
Copyright 2024 BackpackFlow