A structured boilerplate for building Stateful Agentic Systems using LangGraph.
This project acts as the "Heart" of the A.S.G Stack (Atomic - Stateful - Generative). It is designed to bridge the gap between probabilistic LLM outputs and deterministic business processes. Unlike typical chatbots that rely on ephemeral conversation history, ASA treats user interactions as Stateful Business Transactions.
This project implements the "Controlled AI" paradigm, ensuring that agents follow strict architectural patterns rather than free-form conversation:
-
Sticky Routing (Contextual Integrity): We prevent "hallucinated context switching." Once a sub-agent (e.g., Daily Log) locks onto a user intent, the router enforces a "Sticky Lock" (
active_intent). The conversation stays within that specific domain until the task is explicitly completed or canceled. -
The Draft-Commit Protocol: Database writes are never immediate. User intent acts on a "Draft" layer first (an isolated sandbox state). This allows for multi-turn refinement, validation, and correction loops before any data is persisted to the "Real World" (Database/ERP).
-
Recall & Hydrate Pattern: We treat past data as "Living Entities," not dead text. To edit a past record, the system "Recalls" it from the database and "Hydrates" it back into the Active Draft state. This unifies the logic for Creating New and Editing Old data into a single, consistent workflow.
# 1. Install dependencies
cd atomic-stateful-agent
pip install -e .
# or
poetry install
# 2. Configure environment
cp .env.example .env
# Edit .env with your LLM API keys
# 3. Run interactive console
python main.py┌───────────────────────────────────────────────────────────────┐
│ ORCHESTRATION LAYER │
│ (LangGraph) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Orchestrator │ │
│ │ (Sticky Router + Intent Classification) │ │
│ └───────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌──────────────┼─────────────┐ │
│ │ │ │ │
│ ┌────▼─────┐ ┌────▼────┐ ┌────▼────┐ │
│ │ DailyLog │ │ Finance │ │ END │ │
│ │ Agent │ │ Agent │ │ │ │
│ └──────────┘ └─────────┘ └─────────┘ │
│ │
└───────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────▼─────────────────────────────────┐
│ EXECUTION LAYER │
│ (Atomic Inference) │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ AtomicUnit │ │ AtomicUnit │ │
│ │ (Intent Class.) │ │ (Task Extract) │ │
│ └─────────────────┘ └─────────────────┘ │
└───────────────────────────────────────────────────────────────┘
atomic-stateful-agent/
├── src/
│ ├── core/ # Core abstractions
│ │ ├── client.py # LLM Client wrapper
│ │ ├── renderer.py # Response rendering
│ │ ├── types.py # Core types
│ │ └── unit.py # AtomicUnit definition
│ ├── nodes/
│ │ ├── orchestrator.py # Sticky Router
│ │ ├── daily_log.py # Draft lifecycle for tasks
│ │ └── finance.py # Finance agent (placeholder)
│ ├── schemas/
│ │ ├── intents.py # Intent classification
│ │ ├── daily_log.py # Task schemas
│ │ └── finance.py # Finance schemas
│ ├── prompts/ # Jinja2 templates
│ ├── state.py # AgentState TypedDict
│ ├── mock_db.py # In-Memory Database
│ └── graph.py # LangGraph builder
├── main.py # CLI entry point
├── pyproject.toml # Project dependencies
└── README.md # Project documentation
When a user starts a task, the active_intent gets "locked" to that sub-agent. This prevents mid-draft context switches:
# State during drafting
{
"active_intent": "daily_log", # Locked!
"active_draft": {"title": "Review PR"},
"record_id": None
}Changes go through a draft phase before being committed:
- Create: Initialize
active_draftfrom user input - Refine: Update
active_draftbased on corrections - Commit: Persist to database (INSERT or UPDATE)
- Cancel: Discard draft
Editing existing records:
- User says "edit the previous task"
- System searches MockDB for matching record
- Hydrate: Load record data into
active_draft, setrecord_id - User refines the draft
- Commit triggers UPDATE (not INSERT)
| Command | Description |
|---|---|
quit |
Exit the console |
debug |
Show current state |
reset |
Clear all state and database |
db |
Show MockDB contents |
This demonstrates how the Draft-Commit Protocol prevents accidental writes and allows context-aware refinement.
You: Log task: Review PR for auth feature
Agent: ✅ Task recorded:
- Title: Review PR for auth feature
- Priority: Normal
- Status: Pending
You: Change priority to high
Agent: 📝 Draft updated:
- Title: Review PR for auth feature
- Priority: High ← (changed)
You: Done
Agent: 💾 Task saved successfully!
- ID: task-abc123
This demonstrates how Recall & Hydrate allows Natural Language Editing of existing records.
You: Edit the PR review task from earlier
Agent: 🔍 Task found:
- ID: task-abc123
- Title: Review PR for auth feature
- Priority: High
Open for editing. What do you want to change?
You: Change title to Review PR implementation plan
Agent: 📝 Draft updated:
- Title: Review PR implementation plan ← (changed)
- Priority: High
You: Ok save it
Agent: 💾 Task updated successfully!
- ID: task-abc123
MIT