write-forge
Writing, checking or running FORGE `.forge` programs — the authoring loop, the CLI's JSON envelope and exit codes, and the syntax and checker mistakes that break agents. Use when a task asks for a FORGE program or `.forge` file, names FORGE tasks/flows/agents/pools/wardens, or when the project has a forge.project.toml.
- License 许可
- Apache-2.0
- 所属仓库
- ncmlabs/forge
- 最近更新
- 2026-10-16
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- write-forge
- description
- Writing, checking or running FORGE `.forge` programs — the authoring loop, the CLI's JSON envelope and exit codes, and the syntax and checker mistakes that break agents. Use when a task asks for a FORGE program or `.forge` file, names FORGE tasks/flows/agents/pools/wardens, or when the project has a forge.project.toml.
02 资源文件 1
- 参考文档forge-card.md11.5 KB
03 SKILL.md 正文
Writing FORGE
FORGE is a language for oracle-augmented computation: LLM calls are primitives, uncertainty is a
compile-time type, and independent work runs in parallel. Deterministic logic lives in pure,
stochastic logic in task; agents are first-class with memory, lifecycle, events and supervision.
Read forge-card.md before writing code — it ships with this skill: the syntax
that trips agents, one idiom per primitive, and the checker errors you will actually hit.
When to choose FORGE
Choose it when the task is an orchestration of LLM work:
- several LLM steps, where independent ones should run in the same wave (a
flowstage withoutneeds, orpoolworkers); - output whose confidence matters —
uncertain<T>is a type andwhen x.sureis the dispatch; - a long-lived agent: memory, lifecycle states, events, supervision by a
warden; - a visible boundary between deterministic logic (
pure) and oracle calls (task).
Do not choose it for plain data munging with no LLM or effect (write a script), for a single API
call, or when the task needs a library ecosystem FORGE does not have — reach for
command ["argv", "array"] or exec instead of inventing a capability.
The authoring loop
Run these in order. A program is not ready until it has been through all six.
0. Install — once per machine, before step 1
cargo install --git https://github.com/ncmlabs/forge.git # Rust 1.90+; puts `forge` on PATH
forge --version # proves the binary is installed
Without a forge on PATH every later step fails with forge: command not found.
forge-card.md and forge explain <code> are the offline references — they come
with the tool, and docs/forge-reference.md lives in the FORGE repo, not in the project you are
writing for.
1. Scaffold — forge init
forge init my-app --template pipeline # templates: pipeline, agent, webhook-bot
forge init my-app --dry-run # list the files, write nothing
Writes forge.project.toml, forge.config.toml (mock provider by default), main.forge,
main.forge.fixtures.json, expected.txt, .gitignore and AGENTS.md.
2. Check — forge check --json
forge check --json main.forge
Parse + resolve + check, one JSON envelope on stdout. Read data.diagnostics[] and apply each
help — that key carries the fix text (there is no separate fix key) — then re-check. Loop until
data.diagnostics is empty and the exit code is 0. Inside a project, check the manifest instead
of the file: forge check --manifest forge.project.toml registers the declared skill.*
capabilities and checks every source.
3. Explain — forge explain <code>
forge explain E020
forge explain --list
Every diagnostic has a stable code. explain prints what it means with a wrong/right example;
next_steps in the check envelope already hands you forge explain <code> for each distinct error.
4. Replay — forge test
forge run main.forge --record # once: record every provider response as fixtures
forge test main.forge # replay them — no provider, no tokens, $0
test replays <file>.fixtures.json beside the program. With no fixtures it exits 1 and tells
you the --record command to run.
5. Plan — forge run --dry-run
forge run --dry-run main.forge
Prints the static execution plan — the cost table of every LLM operation, then the effect sites
(command, exec, http, file.write, session, spawn) — and the line nothing was executed.
Nothing runs, no provider is built: it is the cost and blast-radius review before step 6.
6. Run — forge run --json
FORGE_MOCK=1 forge run main.forge # whole program on the mock provider, still $0
forge run --json main.forge # the real run
data.output holds the program's say lines (in JSON mode nothing is printed to stdout),
data.result the returned value, and data.summary the run's economics.
Exit codes
Semantic in both modes — --json never changes them.
| Code | Meaning |
|---|---|
0 |
success — clean check, completed run |
1 |
error — diagnostics, a blocked run, or an invalid command line |
2 |
warnings only — check (or run --dry-run) found warnings but no errors, and nothing else |
3 (partial), 10 (needs input) and 11 (async pending) are reserved. In a loop, treat 2 as
"read data.warnings, then keep going".
The JSON envelope
Every in-scope command emits one document — --json, or FORGE_OUTPUT=json for a whole session:
| Field | What an agent reads it for |
|---|---|
status |
success, error, warning or pending |
command |
which subcommand produced it |
data |
the payload; --fields diagnostics keeps only what you need |
context |
one sentence on what happened |
next_steps |
the commands to run next (forge explain <code>) |
warnings |
non-fatal findings; for check they are also in data.diagnostics |
cost |
USD this command spent; 0.0 when it made no LLM call — for run --dry-run and forge cost the estimate is data.estimated_cost_usd |
error |
null, else {type, code, message, suggestion} |
duration_ms |
wall-clock time |
Payloads worth knowing: check → {files, diagnostics[]} where each diagnostic has
code, severity, file, line, col, message, label, help; run/test →
{file, output, result, summary}; run --dry-run → {dry_run, file, operations, effects, total_tokens_in, total_tokens_out, estimated_cost_usd}; explain → {code, title, explain}.
line/col are null when the diagnostic names a file that was not parsed — never a fake 1:1.
The five mistakes that break most FORGE programs
whentakes an arrow, not a block.when x.sure -> give x, withelse -> ...as a sibling at the same indentation. Onlyif,forandmatchtake an indented body.fn mainhas no parentheses and no return type. Writefn main, neverfn main(), and its body sits at i1 with noneeds/gives/do. Keep it thin — put branching in ataskorpure.- Indentation is exact: 2 spaces per level (i1–i4, nesting stops at i4), never a tab, and a blank line inside a body ends the block — the next indented line then fails to parse.
purecannot call LLMs. Noreason,classify,search,recall,exec,command,session,file.read,skill.*,escalate,try ... or, and no call to atask. Move the line into atask;pureis deterministic and always confidence1.0.uncertain<T>is handled by binding, then dispatching.reason,classify,search,recall,exec,command,session,file.read,toml.parse,json.parseand everyskill.*call return an uncertain value, and taint survives assignment and field access.give recall "{q}"fails with E021 (oracle result given without confidence dispatch);prior = recall "{q}"thengive priorfails with E020 (priormay be uncertain and must be dispatched). Bind it, then dispatch withwhen result.sure -> .../.unsure/else, ormatch. Thresholds:sure≥ 0.8,unsure0.5–0.8,unreliable< 0.5; override withwhen result.sure(above: 0.9).
04 同仓库更多 Skills
greeter
Greet a person by name.
git_analysis
Deep agentic analysis of git repository health and trends
slack
Slack operations via the Web API — messages, channels, threads, reactions, and approvals.
ollama
Use Ollama local inference for text generation, classification, and analysis via local GPU models.
github
GitHub operations via the gh CLI — issues, PRs, branches, and CI checks.
codex
Use Codex CLI as a bounded coding agent for repo exploration, implementation, review, and session resume.