Smelt ideas, skim the bugs, forge the product.

Task orchestrator for AI-powered development. Breaks requirements into S-expression ingots and forges them with its own agentic engine speaking straight to the OpenRouter API: tool loop, retries, re-smelt recovery, proof-gated commits. One binary, one key, no vendor CLI to install first.

🧱 ore 🔥 forge done fail? ♻️ re-smelt

Quick Start

# install curl -sSf https://slag.dev/install.sh | sh
# paste your OpenRouter key, once slag key
# forge slag "Build a REST API with auth and rate limiting"
# or watch and steer it live in the dashboard slag --tui "Build a REST API with auth and rate limiting"

One OpenRouter key is the whole setup. No Claude CLI, no vendor login, no model to pick: every role runs on openrouter/auto until you override it. The key is verified before it is saved, and lives in ~/.config/slag/config.toml at mode 0600. Already have OPENROUTER_API_KEY exported? Skip step two.

slag runs shell commands and edits files in the directory you start it in. Point it at a fresh directory or a repo you can revert.

The published build is macOS on Apple Silicon. Elsewhere, clone the repo and run cargo install --path slag-rs.

What the Forge Ships

Twin-Cast Duels

High-grade ingots get cast twice in separate git worktrees. A judge model assays both casts and merges the winner; a split verdict discards both and re-casts with the critique. Fires when cast B (SLAG_MODEL_ALT) differs from the worker model, or per ingot via :duel t.

Ratatui Dashboard + Steering

--tui opens a full-screen dashboard: crucible state, live event feed, token totals. Type a message and press Enter to steer the smith mid-forge without stopping the run.

Plain-English Narrator

A lightweight interpreter turns raw tool calls into one-line narration on the feed, so you read "wiring the auth routes" instead of a wall of diffs and greps.

📖Recipes

Drop recipes/<name>/RECIPE.md files (frontmatter + markdown) in your repo or ~/.config/slag/recipes/. slag indexes them into every ingot prompt and the smith loads them by name.

$Spend Caps

Dollar ceilings per ingot session (SLAG_MAX_COST_INGOT) and per run (SLAG_MAX_COST_RUN), or max_cost_per_ingot / max_cost_per_run in the config file. Default is uncapped.

Proof-Gated Ingots

Every ingot carries a :proof shell command. Exit 0 forges the ingot and commits; anything else feeds the error back and retries. No commit lands without its proof passing.

openrouter/auto by Default

All four model roles (work, plan, duel, judge) route through openrouter/auto until you pin one. A fresh key forges with zero model configuration.

Pipeline

  PRD.md                                          PROGRESS.md
  (ore)                                             (ledger)
    |                                                 ^
    v                                                 |
 +-----------+    +--------------+    +--------+    +-------+
 | SURVEYOR  |--->| FOUNDER      |--->| FORGE  |--->| ASSAY |
 | analyze   |    | cast ingots  |    | strike |    | report|
 +-----------+    +--------------+    +--------+    +-------+
    |                    |                    |
    v                    v                    v
 BLUEPRINT.md        PLAN.md             git commits
 (analysis)        (s-expr ingots)      (per ingot)

Forge Loop

 PICK ORE                       PARALLEL ANVILS
    |                           +---------+---------+
    v                           |         |         |
 :solo t? ----yes-----> ANVIL 1   ANVIL 2   ANVIL 3
    |                      |         |         |
    no                     v         v         v
    |                   (each anvil runs its own smith session)
    v
 SELECT SMITH by :grade
    |
    |  grade >= 3   --> plan model
    |  default      --> work model
    |  both         --> openrouter/auto
    v
 STRIKE (agent session over OpenRouter)
    |
    v
 TOOLS (read, write, edit, grep, bash)
    |
    v
 PROOF (run :proof shell command)
    |
    +----- pass ----> :forged  + git commit
    |
    +----- fail ----> :heat++ retry with slag feedback
    |
    +----- max -----> :cracked + on to the next ingot
                        (the run keeps going; ASSAY reports the cracks
                         and the run exits 1 once nothing is pending)

Four Phases

1 SURVEYOR

Deep analysis on the plan model. Reads PRD.md (ore), produces BLUEPRINT.md with architecture, dependency graph, risk assessment, and forging sequence. Self-iterates to resolve any ambiguity.

2 FOUNDER

Casts S-expression ingots from the blueprint. Each ingot has an ID, complexity grade, skill tag, proof command, and work description. Outputs PLAN.md as the crucible.

3 FORGE

Strikes each ingot with an agent session over OpenRouter. Solo ingots run on parallel anvils (up to 3). Grade picks the model. Retries with slag feedback on failure. Commits on success.

4 ASSAY

Final quality report. Shows forged/cracked counts, temperature bar, and identifies any cracked ingots. It prints on failed runs too, not only clean ones. Exits 0 on full forge, 1 if any ingot cracked.

Design Decisions

Why One Key?

slag speaks to OpenRouter and nothing else. That is one credential to paste, one bill to read, and every model on the router reachable by id. The four roles (work, plan, duel, judge) all default to openrouter/auto, so a fresh key forges without you choosing a model. Override any role when you have an opinion: a flag, an environment variable, or a line in ~/.config/slag/config.toml. The file wants the lowercase key; the uppercase name is the environment variable and is ignored inside the file.

Role Env var config.toml key Flag
work SLAG_MODEL_BASE model_base --model
plan SLAG_MODEL_PLAN model_plan --plan-model
duel SLAG_MODEL_ALT model_alt
judge SLAG_MODEL_JUDGE model_judge --judge-model

The key itself, the duel knobs, and the spend caps follow the same rule: openrouter_api_key, duel, duel_rounds, screenshot_cmd, max_cost_per_ingot, max_cost_per_run in the file; OPENROUTER_API_KEY, SLAG_DUEL, SLAG_DUEL_ROUNDS, SLAG_SCREENSHOT_CMD, SLAG_MAX_COST_INGOT, SLAG_MAX_COST_RUN in the environment.

Why S-Expressions?

S-expressions are single-line and grep-parseable, so PLAN.md stays readable by you and by a one-line shell command. Every ingot is one line. Fields are keyword-prefixed (:id, :status), which makes them unambiguous to extract with pattern matching and cheap for a model to emit correctly.

Why Parallel Anvils?

Independent ingots (:solo t) run concurrently, up to MAX_ANVILS=3. This gives 3x throughput for foundation tasks that have no dependencies. Each anvil gets its own smith session. Sequential ingots (:solo nil) run one at a time after parallel work completes.

Why Proof-Based Verification?

Every ingot carries a :proof field containing a shell command. Exit code 0 means pass, anything else means fail. No human review needed. Proofs are concrete: "test -f file", "npm test", "grep -q pattern file". This enables fully autonomous forging with machine-verifiable quality gates.

Why Self-Iteration?

When a surveyor or founder output contains questions, slag detects them and feeds the output back with instructions to resolve autonomously. Up to 3 rounds. This prevents the forge from stalling on ambiguity. The AI is instructed to make expert decisions rather than ask for clarification.

Why Metallurgical Metaphor?

Unambiguous vocabulary that maps naturally to the pipeline. Ore (raw input) is surveyed, cast into ingots, heated in a forge, and either becomes forged steel or cracked waste. Every term has exactly one meaning. The temperature gradient (cold → hot → pure) maps to progress from unstarted to complete.

Ingot Examples

Field Reference

Field Values Meaning
:id "i1", "i2", ... Unique ingot identifier
:status ore | molten | forged | cracked Lifecycle state
:solo t | nil Can run in parallel (t) or must be sequential (nil)
:grade 1-5 Complexity level; grade ≥ 3 uses the plan model
:skill web | api | cli | default Work-type tag. Today only web changes anything: Playwright note in the prompt, duel screenshots
:heat 0-N Current retry attempt
:max 5-8+ Max retries before cracking
:smelt 0 | 1 Re-smelt count. A cracked ingot gets one rewrite; at 1 it cracks for good
:proof shell command Acceptance test (exit 0 = pass)
:work string Task description for the smith
:duel t | nil Twin-cast override: t forces a duel, nil blocks one, absent follows SLAG_DUEL

Those eleven are every field the parser reads. Any other :key value pair survives a rewrite untouched.

CLI Reference

Command Role
slag "commission"Write PRD.md from the commission and run the full pipeline
slagForge the PRD.md already in this directory
slag key [KEY]Show setup, or verify and store an OpenRouter key
slag statusShow crucible state
slag resumeResume an existing forge
slag updateSelf-update to the latest release
Flag Effect
--tuiFull-screen dashboard: crucible, live feed, steering input
--anvils NMax parallel anvil workers (default 3)
--autoForce openrouter/auto on all four roles, ignoring pinned models
--model MODELWorker model, any OpenRouter id
--plan-model MODELPlanner model for grade ≥ 3 ingots
--judge-model MODELDuel judge model
--worktreeBranch-per-ingot isolation. Not implemented yet: warns and runs in the shared checkout
Environment variable Effect
OPENROUTER_API_KEYThe key. Overrides the stored one
SLAG_MODEL_BASE / _PLAN / _ALT / _JUDGEPer-role model ids
SLAG_DUELauto (default) / on / off
SLAG_DUEL_ROUNDSOverride the duel round cap
SLAG_MAX_COST_INGOTDollar ceiling for a single ingot session
SLAG_MAX_COST_RUNDollar ceiling for the whole run
SLAG_REASONING_EFFORTlow / medium / high for models that take it
SLAG_SCREENSHOT_CMDShell command producing a screenshot for visual assay of web ingots
SLAG_CHAR_BUDGETTranscript char budget before an agent session compacts
SLAG_CONFIG_DIRMove the config directory off ~/.config/slag
SLAG_OPENROUTER_BASEPoint slag at a proxy instead of OpenRouter
NO_COLOR / COLORTERMDrop color entirely / enable truecolor