Enabling Caching
There are two ways to enable caching: On the<Workflow> element:
smithers() options:
How It Works
When caching is enabled, the engine checks for a cached result before executing each task:cached: true in _smithers_attempts, so you can distinguish cached results from fresh executions in your debugging.
Cache Key Components
The cache key is a SHA-256 hash of a JSON object containing all of these components:| Component | Source | Description |
|---|---|---|
workflowName | <Workflow name="..."> | Scopes caches to a specific workflow. |
nodeId | <Task id="..."> | Scopes caches to a specific task. |
outputTableName | Task’s output table name | Ensures different output schemas are not confused. |
schemaSig | SHA-256 of table column definitions | Invalidates cache when table structure changes. |
agentSig | agent.id or "agent" | Invalidates cache when the agent/model changes. |
toolsSig | Sorted, comma-joined tool names | Invalidates cache when available tools change. |
prompt | Task’s prompt text | Invalidates cache when the prompt changes. |
payload | Task’s static payload | Invalidates cache when static data changes. |
Schema Signatures
TheschemaSig deserves special attention. It is computed by the schemaSignature() function, which:
- Gets all columns from the Drizzle table.
- Sorts column names alphabetically.
- For each column, captures:
name,columnType,notNullflag, andprimaryflag. - Joins everything with
|separators. - Computes a SHA-256 hash of the result.
Cache Invalidation
The cache is automatically invalidated when any of these change:| Change | Why |
|---|---|
| Prompt text changes | Different input = different expected output. |
| Output table structure changes | Schema signature changes. |
| Agent model changes | Different model may produce different results. |
| Tool allowlist changes | Available tools affect agent behavior. |
| Static payload changes | Different data = different expected output. |
| Workflow name changes | Cache is scoped to workflow name. |
| Task node ID changes | Cache is scoped to node ID. |
_smithers_cache:
Database Storage
Cached results are stored in the_smithers_cache table:
| Column | Type | Description |
|---|---|---|
cache_key | TEXT (PK) | SHA-256 hash of all cache key components. |
created_at_ms | INTEGER | When the cache entry was created. |
workflow_name | TEXT | The workflow that produced this entry. |
node_id | TEXT | The task that produced this entry. |
output_table | TEXT | The output table name. |
schema_sig | TEXT | SHA-256 of the table column structure at cache time. |
agent_sig | TEXT | Agent identifier at cache time. |
tools_sig | TEXT | Tool allowlist signature at cache time. |
jj_pointer | TEXT | JJ version control pointer (if available). |
payload_json | TEXT | The cached output payload as JSON. |
Cache Validation on Read
When a cache hit is found, Smithers does not blindly use the stored payload. It validates the payload against the current output table schema. If validation fails (e.g., a required column was added since the cache was written), the cache entry is treated as a miss and the task executes normally. This means cache entries are self-healing — you do not need to manually purge stale entries after schema changes.When Not to Cache
Caching is best for:- Development iteration: Re-running a workflow while changing later tasks should not re-execute expensive early tasks.
- Idempotent agent tasks: Tasks where the same prompt reliably produces equivalent outputs.
- Resumption: Resuming a run after a crash should not re-execute already-completed agent calls.
- Tasks that depend on external state: If the agent reads from APIs, files, or databases that change between runs, cached results may be stale.
- Non-deterministic tasks: If you want fresh, varied outputs each time (e.g., creative writing with high temperature), caching defeats the purpose.
- Tasks with side effects via tools: If agent tools make external changes, replaying a cached result skips those side effects.