The Forge
The Forge is a problem-first idea workshop shared by bio-Zack and silicon-Zack. It forces discipline: start with problems, not solutions. Ideas flow through four active stages with strict WIP limits, preventing the graveyard problem where ideas accumulate without progress.
The Jeopardy Principle
People naturally start with solutions. "What if we built X?" The Forge makes you go back to the question, like Jeopardy: start with the answer, then articulate what the question was.
When bio-Zack drops a solution ("what if we built async council deliberation?"), the forge captures it immediately as a spark, then asks: "What problem does this solve?" If the problem can be articulated with evidence, the idea advances to smelt. If not, it stays as a spark until the problem emerges naturally.
This is the core forcing function. Capture is always free and immediate. Problem articulation is the gate.
Stages
Spark --> Smelt --> Shape --> Forge
\
[shipped] [killed] [archived]
Spark
Anything goes. Problems, solutions, friction, hunches. Low friction capture. Either bio-Zack or silicon-Zack can originate sparks. Solution-first entry is fine because smelting forces the problem trace-back later.
A spark file contains a title, description, origin, and optional tags. No problem statement required yet.
Smelt
The Jeopardy phase. Extract the real problem behind the idea. Requires:
- Problem statement - One sentence describing the specific pain or opportunity
- Evidence - One concrete instance of this problem occurring
- Complexity triage - Cynefin-lite classification:
- clear - Known fix. Idea is killed and routed to the task list. The forge is for problems that need exploration, not known solutions.
- spike - Needs investigation before we even understand the solution space.
- complex - Goes into smelt for problem definition, then shape for solution exploration.
When an idea is smelted, the file is renamed to reflect the problem (not the original solution title). The original spark content is preserved under "Original Spark" in the body.
Shape
Explore the solution space. Multiple approaches at fat-marker level (broad strokes, not detailed specs). The appetite field must be set before advancing to forge. Appetite values: tiny, small, medium, large, unknown.
Forge
Converge on one approach. Appetite and boundaries are locked. The idea is ready to build. Only one idea should be in forge stage at a time.
Terminal States
- shipped - Built and deployed. The idea is done.
- killed - Decided against, with reason and optional learnings recorded. Killing is gardening, not failure. A killed idea is a decision made.
- archived - Not killed but not active. Can be resurrected.
WIP Limits
The forge enforces work-in-progress limits to maintain focus:
| Stage | Limit |
|---|---|
| spark | 7 |
| smelt | 4 |
| shape | 2 |
| forge | 1 |
If any stage exceeds its limit, the status dashboard shows a WIP warning. If total active ideas exceed 15, the system flags a "system smell" indicating the forge needs pruning.
Ideas untouched for 14+ days are flagged as stale and considered kill candidates.
Silicon-Zack Origination
Silicon-Zack can create sparks too, using origin: "silicon-zack". Three channels, ranked by intrusiveness:
- Silent (default) - File spark during
/sleep. Bio-Zack discovers it naturally. - Bundled - Mention in weekly forge status via telegram. "2 new sparks this week."
- Interrupt (rare, max 1/week) - Telegram nudge for high-conviction, time-sensitive ideas only.
Every AI-originated spark must include a "why now" line. Rate limiting: if the forge has 3+ unengaged silicon-Zack sparks, stop generating new ones and develop existing ones instead.
Python API
All functions are importable from scripts.forge:
from scripts.forge import (
create_spark,
smelt_idea,
list_ideas,
get_idea,
add_entry,
advance_stage,
kill_idea,
forge_status,
rebuild_index,
COMPLEXITY_VALUES,
)
create_spark
Create a new spark in the forge.
idea = create_spark(
title="Async Council Deliberation",
description="What if council could run overnight during /sleep?",
origin="bio-zack", # or "silicon-zack"
tags=["vita-system", "council"],
related_ideas=["003"], # optional
problem_statement=None, # optional, for problem-first entry
project=None, # optional, links to a project-registry id
)
# Returns: {"id": "020", "title": "...", "filename": "020-async-council-deliberation.md", "path": "..."}
If problem_statement is provided, the spark is created with a Problem section already included in the body.
Note: The optional
project=argument links an idea to a project in the project registry. It is part ofcore.py's frontmatter key order, but it is Python-API-only β the RESTCreateSparkRequestdoes not expose it.
smelt_idea
The Jeopardy flip. Advance a spark to smelt by articulating the problem.
smelt_idea(
"003",
problem_statement="Voice mode architecture is too complex for the actual use case",
evidence="Realtime API has 5 failure modes for what should be a simple record-process-speak flow",
complexity="complex", # "clear", "spike", or "complex"
)
# Returns: True on success
If complexity is "clear", the idea is killed with reason "Routed to task list" instead of advancing to smelt.
The file is renamed so the slug reflects the problem statement rather than the original solution title.
add_entry
Add a dated entry to any idea's body. Used for research notes, thoughts, progress updates.
add_entry(
"003",
"Explored three approaches: turn-based, streaming, and hybrid...",
author="silicon-zack",
section="Research Notes", # optional section header
)
advance_stage
Move an idea to a new stage. Valid transitions: smelt to shape, shape to forge (requires appetite set), forge to shipped.
advance_stage("003", "shape")
Use smelt_idea() for the spark to smelt transition, since it requires problem statement and evidence.
Shape to forge is blocked if appetite is still "unknown".
kill_idea
Kill an idea with dignity. Records reason and optional learnings.
kill_idea(
"005",
reason="Superseded by forge system",
learned="The capture pattern was useful though",
)
forge_status
Generate a forge dashboard with counts, active ideas, stale ideas, and WIP warnings.
status = forge_status()
# Returns:
# {
# "total_active": 7,
# "counts": {"spark": 2, "smelt": 3, "shape": 2, "forge": 0, "shipped": 1, "killed": 0, "archived": 0},
# "active_ideas": [...],
# "stale": [{"id": "003", "title": "...", "stage": "smelt", "days_stale": 18}],
# "wip_warnings": ["shape: 3/2 (over limit)"],
# "origin_breakdown": {"bio-zack": 5, "silicon-zack": 2},
# "system_smell": False,
# }
list_ideas / get_idea
# List active ideas, optionally filtered by stage
ideas = list_ideas(stage="smelt")
ideas = list_ideas(include_terminal=True) # include shipped/killed/archived
# Get a single idea with full body
idea = get_idea("003")
# Returns full dict with frontmatter fields + "_body", "_path", "_filename"
rebuild_index
Regenerate the _index.md dashboard file. Called automatically during /sleep. The generated index opens with the active-idea count and origin breakdown, then emits a > WARNING line if the system smell trips and one > WIP line per over-limit stage. It follows with a per-stage section (## Spark (N), ## Smelt (N), β¦) listing each active idea with its origin tag (b/s), appetite, problem statement, and last-touched date, and closes with a ## Kill Candidates (stale >14 days) section.
content = rebuild_index()
Skill Commands
The forge skill (.claude/skills/forge/SKILL.md) auto-triggers when bio-Zack mentions ideas or uses /forge.
| Command | What it does |
|---|---|
/forge |
Show forge status dashboard |
/forge spark [title]: [description] |
Create a new spark |
/forge list [stage?] |
List ideas, optionally filtered |
/forge [id] |
Display a specific idea |
/forge smelt [id] |
Attempt to smelt a spark |
/forge entry [id]: [thought] |
Add a thought/entry |
/forge advance [id] [stage] |
Move idea to next stage |
/forge kill [id]: [reason] |
Kill with dignity |
Auto-triggers also fire when bio-Zack says things like "I have an idea", "what if we", or uses the "idea:" prefix in telegram.
API Endpoints
The forge is exposed via REST at /api/v1/forge:
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/forge |
List ideas. Query params: stage, include_terminal |
GET |
/api/v1/forge/status |
Dashboard with counts, WIP warnings, staleness |
GET |
/api/v1/forge/{idea_id} |
Get single idea with full body |
POST |
/api/v1/forge |
Create a spark. Body: {title, description, origin, tags, problem_statement} |
POST |
/api/v1/forge/{idea_id}/smelt |
Smelt a spark. Body: {problem_statement, evidence, complexity} |
POST |
/api/v1/forge/{idea_id}/entries |
Add entry. Body: {text, author, section} |
PUT |
/api/v1/forge/{idea_id}/stage |
Advance stage. Body: {new_stage} |
POST |
/api/v1/forge/{idea_id}/kill |
Kill idea. Body: {reason, learned} |
Briefing Integration
Active forge ideas surface in the living briefing dashboard as Opportunity items. ForgeAdapter (scripts/briefing/adapters/forge.py) calls list_ideas() and maps each active idea's stage onto a briefing state and importance score:
| Forge stage | Briefing state | Importance |
|---|---|---|
| spark | spotted | 0.30 |
| smelt | evaluating | 0.50 |
| shape | evaluating | 0.70 |
| forge | pursued | 0.85 |
Terminal-stage ideas (shipped/killed/archived) are skipped, since list_ideas() excludes them by default. Each candidate carries the idea's stage, origin, complexity, appetite, tags, and last-touched date in its metadata, with the problem statement (if any) as the summary. This is how an idea moving through the pipeline becomes visible in the daily briefing without any extra wiring.
File Format
Each idea is a markdown file with YAML frontmatter at data/forge/NNN-slug.md. The three-digit ID is zero-padded and sequential. The slug is derived from the title (for sparks) or the problem statement (after smelting).
Frontmatter Fields
---
id: "007"
title: "Example Idea Title"
stage: "smelt"
origin: "bio-zack"
project: "proj_abc123"
created: "2026-02-21"
last_touched: "2026-02-24"
appetite: "unknown"
complexity: "complex"
problem_statement: "One-sentence statement of the underlying problem."
evidence: "A concrete instance of the problem occurring."
last_author: "silicon-zack"
tags: ["example", "placeholder"]
related_ideas: []
---
The fields are emitted in a fixed order by _write_idea() (core.py); any unrecognized keys are appended after the known ones.
| Field | Values | Notes |
|---|---|---|
id |
3-digit string | Sequential, zero-padded |
title |
string | Short descriptive title |
stage |
spark, smelt, shape, forge, shipped, killed, archived | Current stage |
origin |
bio-zack, silicon-zack | Who created the idea |
project |
string | Optional project-registry id (Python-API-only; not set via REST) |
created |
YYYY-MM-DD | Creation date |
last_touched |
YYYY-MM-DD | Last modification date |
appetite |
tiny, small, medium, large, unknown | Size/effort estimate (required before forge) |
complexity |
clear, spike, complex | Cynefin-lite classification (defaults to complex on create) |
problem_statement |
string | Added during smelt |
evidence |
string | Concrete instance of the problem |
last_author |
string | Who last modified the idea |
tags |
list of strings | Categorization |
related_ideas |
list of strings | IDs of related ideas |
Body Structure
The markdown body evolves as the idea progresses:
Spark:
# Title
## Spark
*2026-02-24 | bio-zack*
Description of the idea.
After smelt:
# Title
## Problem
Problem statement here.
**Evidence:** Concrete example.
## Original Spark
*2026-02-24 | bio-zack*
Original description.
### Smelted - 2026-02-24
Entries are appended:
### 2026-02-24 | silicon-zack
Research notes or thoughts added via add_entry().
### Research Notes - 2026-02-24 | silicon-zack
Entry with an explicit section header.
Stage transitions are recorded (the body uses a unicode arrow):
### Stage: smelt β shape (2026-02-24)
Kill notes:
### Killed - 2026-02-24
**Reason:** Superseded by newer approach
**Learned:** The capture pattern was useful
Data Files
| Path | Purpose |
|---|---|
data/forge/NNN-slug.md |
Individual idea files |
data/forge/_index.md |
Auto-generated dashboard (rebuilt during /sleep) |
scripts/forge/core.py |
Core implementation |
scripts/forge/__init__.py |
Public API exports |
api/src/routers/forge.py |
REST API router |
scripts/briefing/adapters/forge.py |
Briefing adapter (ideas β Opportunity items) |
.claude/skills/forge/SKILL.md |
Skill definition for auto-triggers |
Integration with /sleep
During the nightly /sleep cycle (00:30 PT), the forge gets a full review:
- Sparks >3 days old - Silicon-Zack attempts to smelt them by articulating the problem and evidence. If the spark was solution-first, trace back to the underlying problem.
- Smelts - Add research, explore the solution space, attempt advance to shape if promising.
- Shapes - Check appetite, verify solutions are still relevant.
- Forges - Check progress, verify scope has not crept.
- Stale ideas >14 days - Recommend kill or archive.
- Complexity triage - Route any "clear" items to the task list during review.
- Silicon-Zack origination - If fewer than 3 unengaged silicon sparks exist and a pattern or idea emerged tonight, create a new spark.
- Weekly (Sundays) - Generate forge status summary. Flag kill candidates. Resurface one random archived idea.
rebuild_index() runs at the end to keep the dashboard fresh.
Design Principles
- Sparks are free. Never hesitate to capture. Cost of loss far exceeds cost of noise.
- Smelting is the gate. Can you articulate the problem and show evidence? If not, keep sparking.
- Known fixes don't belong here. If complexity is "clear", route to the task list.
- Killing is gardening. A killed idea is a decision made.
- Small forge, high temperature. Few ideas, frequently touched, beats many ideas gathering dust.
Where to go next
- Executive Loop β the autonomous OODA cycle that runs
/sleep, where the forge gets its nightly review. - Living Briefing β where active forge ideas surface as Opportunity items.
- Project Registry β the
projectfield links an idea back to a registered project. - Improve β the sibling system for system-improvement proposals.