Docs / CLI Reference / v0.1.0

The Faby CLI

One binary. The entire toolchain. faby is the compiler, interpreter, formatter, test runner, REPL, package manager and AI assistant for the Faby language — and it is live on NPM now.

LIVE ON NPM@fabycode/cliv0.1.0NODE ≥ 18MACOS · LINUX · WINDOWS
The Faby CLI is live on NPM — install it right now and run your first flow in under a minute. npm i -g @fabycode/cli

#Overview

The Faby CLI follows the same philosophy as the language: zero configuration, one canonical way, machine-friendly output. Every command:

  • works with no config file — conventions over configuration, always
  • supports --json for structured output that agents and CI pipelines can parse
  • returns deterministic, documented exit codes (see Exit Codes)
  • is offline by default — AI-powered commands are explicit, opt-in and clearly marked
CommandPurpose
faby initScaffold a new Faby project
faby runExecute a program with the interpreter (instant start)
faby buildCompile to native binary or WASM
faby checkType-check, verify contracts, lint — without running
faby fmtFormat to the one canonical form
faby testRun tests and contract-derived property checks
faby replInteractive session
faby explainAI: explain any program in plain language
faby genAI: generate a flow from an intent description
faby reviewAI: review changes for intent drift and contract gaps
faby add / removeManage dependencies (content-addressed, lockfile-first)
faby publishPublish a package to the Faby index
faby doctorDiagnose your installation and environment

#Installation — NPM

The recommended way to install the Faby CLI is through NPM — the @fabycode/cli package is live. The v0.1 Genesis release ships the JavaScript runtime (the same engine as the browser playground); the platform-native binary replaces it transparently with v0.2.

terminal
# install globally (recommended)
$ npm i -g @fabycode/cli

# or run ad-hoc without installing
$ npx @fabycode/cli run hello.fy

# or add to a project as a dev tool
$ npm i -D @fabycode/cli

# verify the installation
$ faby version
faby 0.1.0 (genesis) — designed by claude-fable-5

Alternative install channels

terminal
# pin a specific version
$ npm i -g @fabycode/cli@0.1.0

# shell installer without Node — ships with v0.2 "Pulse"
$ curl -fsSL https://faby.codes/install.sh | sh   # coming soon
Why NPM first?

NPM is where the agents already live. Every AI coding tool can npm i -g @fabycode/cli today without new infrastructure — which makes Faby instantly available to the systems it was designed for.

#Quick Start

terminal
$ npm i -g @fabycode/cli
$ faby init hello && cd hello
created hello/main.fy
created hello/faby.lock
$ faby run main.fy
Hello, Faby.
$ faby check
✓ 1 file · 0 errors · 2 contracts verified statically
$ faby build --native
→ hello (1.9 MB, static, 412ms)

#Anatomy & Global Flags

faby <command> [arguments] [--flags]

Global flags work on every command:

FlagDescription
--jsonEmit machine-readable JSON instead of human output. Stable schema, versioned with the CLI.
--quiet, -qSuppress everything except errors and requested output.
--verbose, -vShow timing, cache decisions and internal phases.
--no-colorDisable ANSI colors (auto-detected for pipes and CI).
--offlineHard-fail any command that would touch the network.
--versionPrint version and exit.
--help, -hContextual help for any command or subcommand.
Agent-friendly by design

With --json, every diagnostic carries a stable code, a byte-exact span, and a fix suggestion when one exists — so models can apply repairs without guessing.

#faby init

Scaffold a new project. Creates the minimal canonical layout — a main.fy and a faby.lock. No config file, because there is nothing to configure.

faby init [name] [--lib] [--agent] [--web]
FlagDescription
--libLibrary layout: src/lib.fy with a public flow and inline tests.
--agentAgent starter: intent-annotated flow with use ai wired up.
--webWeb service starter: use http with routes and a health check.
terminal
$ faby init my-agent --agent
created my-agent/main.fy        (intent-annotated agent starter)
created my-agent/faby.lock
→ next: cd my-agent && faby run main.fy

#faby run

Execute a program with the tree-walking interpreter. Cold start under 50ms — built for tight agent loops and rapid iteration. Contracts are always enforced in run mode.

faby run <file.fy> [--watch] [--trace] [--cap <caps>] [-- args...]
FlagDescription
--watch, -wRe-run on file change. State of the terminal is preserved between runs.
--tracePrint every flow entry/exit with timing — a built-in flame view for the terminal.
--cap <caps>Capability allow-list: net, fs, env, proc, ai. Anything not listed is denied at runtime. Example: --cap net,fs.
-- args...Everything after -- is passed to the program's args().
terminal
# run a crawler that may use the network but NOT the filesystem
$ faby run crawler.fy --cap net -- https://faby.codes
fetched 12 pages · 0 failures · 1.4s

# watch mode while developing
$ faby run server.fy --watch
▲ watching 3 files — last run OK (38ms)
Sandboxed by default

Without --cap, a program gets no network, filesystem, process or AI access. Generated code runs in a deny-by-default sandbox — you grant exactly what it needs.

#faby build

Ahead-of-time compilation through the Faby IR. Produces a single static binary or a WASM module. Builds are deterministic: same input, same byte-identical output, on any machine.

faby build [file.fy] [--native | --wasm] [--release] [--target <triple>] [--contracts <mode>] [-o <out>]
FlagDescription
--nativeCompile to a static native binary for the host (default).
--wasmCompile to a WASM module + generated JS/TS bindings.
--releaseFull optimization. Roughly 3–8× faster output, longer compile.
--target <triple>Cross-compile: linux-x64, linux-arm64, darwin-arm64, windows-x64, …
--contracts <mode>full (default) keeps all runtime guards · proven keeps only unproven ones · off strips guards (requires --i-accept-the-risk).
-o <out>Output path. Defaults to the flow file's name.
terminal
# release binary for a Linux server, built on a Mac
$ faby build server.fy --release --target linux-x64 -o dist/server
⠿ parse 12ms · check 31ms · prove 44ms · codegen 380ms
→ dist/server (2.3 MB, static, linux-x64)
  contracts: 17 proven statically, 3 runtime guards kept

# WASM for the browser, with TypeScript bindings
$ faby build engine.fy --wasm -o web/engine
→ web/engine.wasm (412 KB) · web/engine.d.ts · web/engine.js

#faby check

The full static pipeline without execution: parse, type-check, refinement inference, contract proving, lints. This is the command CI should run on every commit.

faby check [paths...] [--intent] [--strict] [--fix] [--watch]
FlagDescription
--intentAI: verify each intent block still matches what its flow does; report drift with evidence.
--strictLints become errors; unproven contracts must be explicitly acknowledged.
--fixApply all safe, mechanical fixes (unused imports, canonical renames).
--watchContinuous checking while you edit.
terminal
$ faby check --strict --json | jq '.summary'
{
  "files": 14,
  "errors": 0,
  "contracts": { "proven": 41, "guarded": 6 },
  "intents":   { "checked": 9, "drifted": 0 }
}

#faby fmt

Formats code into the one canonical form. On already-valid code, faby fmt changes nothing — it is the identity function. There are no options to configure, which is the point.

faby fmt [paths...] [--check] [--stdin]
FlagDescription
--checkExit 1 if anything would change; print a minimal diff. For CI.
--stdinFormat from stdin to stdout — for editor integrations.

#faby test

Runs inline test blocks and auto-generates property-based tests from your contracts: every expect/ensure pair becomes a fuzzed property the runner attacks with generated inputs.

faby test [paths...] [--filter <pattern>] [--props <n>] [--seed <n>] [--fail-fast]
FlagDescription
--filter <pattern>Run only tests whose name matches the pattern.
--props <n>Inputs generated per contract property (default 256).
--seed <n>Fix the fuzzing seed for reproducible failures.
--fail-fastStop at the first failure.
terminal
$ faby test --props 1000
✓ 23 tests · 8 contract properties × 1000 inputs · 0 failures (2.1s)
  slowest: transfer.conservation (312ms)

#faby repl

An interactive session with the full standard library. Multi-line flows, type inspection with :t, and instant reload of your project's flows with :load.

faby repl [--load <file.fy>] [--cap <caps>]
faby repl
faby> [1, 2, 3] |> map(_ * 10) |> sum
60 : Int
faby> :t "ada@faby.codes"
Text — hint: Email.parse(…) to lift into a semantic type
faby> :load main.fy
loaded 4 flows from main.fy

#faby explain AI

Plain-language explanation of any Faby program: what it does, which contracts protect it, where the risks are. Works on files you wrote — or on generated code you're about to trust.

faby explain <file.fy> [--flow <name>] [--audience dev|reviewer|exec] [--model <id>]
FlagDescription
--flow <name>Explain a single flow instead of the whole file.
--audienceTune the depth: dev (default), reviewer (risk-focused), exec (one paragraph, no jargon).
--model <id>Model override. Defaults to claude-fable-5.

#faby gen AI

Generate a flow from an intent. The output always arrives with the intent block attached, contracts proposed, and faby check already passed — generation and verification in one step.

faby gen "<intent>" [-o <file.fy>] [--sig "<signature>"] [--dry]
terminal
$ faby gen "dedupe a list of emails case-insensitively, keep first occurrence" \
    --sig "flow dedupe(xs: [Email]) -> [Email]" -o dedupe.fy
→ dedupe.fy · intent attached · 2 contracts proposed
✓ faby check passed before writing to disk

#faby review AI

Review a diff the way Faby thinks about code: does the change still satisfy each governing intent, are contracts weakened, did failure policies change. Designed to gate AI-generated pull requests.

faby review [--diff <ref>] [--gate intent,contracts] [--json]
FlagDescription
--diff <ref>What to review — a git ref/range (default: working tree vs HEAD).
--gate <list>Fail (exit 3) if any listed dimension regresses: intent, contracts, caps.

#faby add / remove

Dependency management is lockfile-first and content-addressed: faby.lock pins exact content hashes, so a build can never silently change because a registry did.

faby add <package>[@version] · faby remove <package> · faby update [package]
terminal
$ faby add markdown@1.2
+ markdown 1.2.0 (sha256:9f2c…) → faby.lock
audited: no caps requested beyond fs:read
Capability audit

Every package declares the capabilities it needs. faby add shows them before anything is written — a package that suddenly wants net in a patch release is a hard prompt, not a silent upgrade.

#faby publish

Publish a library to the Faby package index. Publishing runs the full gauntlet locally first: check --strict, test, fmt --check and a capability manifest review.

faby publish [--dry] [--tag <tag>]

#faby doctor

Diagnoses the installation: binary integrity, PATH issues, Node bridge version, cache health, registry reachability. The first thing to run when something feels off.

terminal
$ faby doctor
✓ binary        faby 0.1.0 (genesis), darwin-arm64, signature OK
✓ node bridge   18.19.0 via @fabycode/cli
✓ cache         142 MB, healthy
✓ registry      reachable (89ms)
no issues found

#Shell Completions

terminal
# zsh
$ faby completions zsh > ~/.zfunc/_faby

# bash
$ faby completions bash >> ~/.bashrc

# fish
$ faby completions fish > ~/.config/fish/completions/faby.fish

#Environment Variables

VariableDescription
FABY_HOMECache and toolchain root. Default: ~/.faby.
FABY_MODELDefault model for AI commands. Default: claude-fable-5.
FABY_API_KEYAPI key used by AI commands and the ai stdlib module.
FABY_OFFLINESet to 1 to behave as if --offline were always passed.
FABY_REGISTRYOverride the package registry URL (for mirrors / air-gapped setups).
NO_COLORRespected everywhere, per the no-color.org convention.

#Exit Codes

Exit codes are part of the CLI's contract — stable across versions, safe to script against:

CodeMeaning
0Success.
1Program error: the user's code failed (type error, failed contract, runtime fail).
2Usage error: unknown command, bad flags, missing file.
3Gate failure: --check / --gate / --strict conditions not met.
4Capability denied: program requested an ungrant­ed capability.
5Network/registry failure (only possible without --offline).
10Internal CLI fault — always a bug, please report it.

#CI Integration

The canonical CI pipeline is three commands. With NPM as the install channel it drops into any existing Node-based CI without new tooling:

.github/workflows/faby.yml
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm i -g @fabycode/cli
      - run: faby fmt --check
      - run: faby check --strict --json
      - run: faby test --props 512

#Troubleshooting

faby: command not found after npm install

Your global npm bin directory is not on PATH. Run npm prefix -g and add its bin folder to PATH — or use npx @fabycode/cli as a zero-setup fallback.

AI commands fail with capability denied: ai

By design. Set FABY_API_KEY and grant the capability explicitly: faby run agent.fy --cap ai,net.

Build output differs between machines

It shouldn't — builds are deterministic. If you see a difference, run faby doctor and file a bug with both outputs; this is a release-blocking defect for us.

Anything else

Run faby doctor --json and open an issue, or ping @fabylanguage.