Little documentation
Guides and APIReference

CLI

The minimal command surface that ships with v0.1.0-alpha.

Little Workflow: published on npm as little-workflow@0.2.0-alpha.1 (2026-10-06). Sections labeled UNRELEASED describe source-only changes. Release status

The little binary ships with the @little-stack/workflow package (npx @little-stack/workflow@alpha <command> without installing, once it is published; until then npx little-workflow@alpha <command> runs published 0.2.0-alpha.1). Alpha ships the local commands needed for the SDK loop: scaffold workflow projects, validate compiled LWIR, run compiled LWIR in Local World, run folder-authored workflows, dump events, replay state, and report what a run cost. There is no runs list, runs inspect, timeline, retry-from-step, or fork command yet; a fuller inspection surface is planned (see the Roadmap).

little setup [directory | --here] [--template node|next|existing-next] [--workflow]
little init [name | --here] [--workflow-name <name>] [--with-harness] [--provider <id>] [--model <id>]
little add workflow <name> | little add harness
little validate <workflow.json>
little run <workflow.json> --input <input.json> [--run-id <id>]
little test <workflow-folder-or-name> --input <input.json> [--timeout <ms>]
little events <run-id> [--type <event-type>] [--caller <caller>]
little replay <run-id>
little report <run-id> [--table]

little --help prints this list and exits 0; little with no command prints it and exits 1. little init --help and little add --help print the full option lists. Unknown commands are rejected, and so are unknown options to init and add.

Successful command output is JSON by default (--json is accepted and changes nothing). events emits newline-delimited JSON, one event per line. report accepts --table to render human-readable output instead. Usage and parse errors are plain text on stderr, with exit code 1. Use --data-dir <dir> to point run, test, events, replay, and report at a Local World directory; otherwise the CLI uses .little-workflow.

Setup

This section is the command reference. For a guided walkthrough, including setup versus init and what to change before production, see the shared Setup guide.

# Interactive Next.js or standalone Node agent wizard
# (published as little-workflow until the first @little-stack release;
#  after it, use npx @little-stack/workflow@alpha with the same flags)
npx little-workflow@0.2.0-alpha.1 setup

# Preview additive changes in an existing TypeScript App Router project
npx little-workflow@0.2.0-alpha.1 setup --here --template existing-next --workflow --plan

# Apply, explicitly allow the SQLite native build, and run keyless verification
npx little-workflow@0.2.0-alpha.1 setup --here --template existing-next --workflow --yes --install --allow-native-build --verify

# Recover CLI-owned files after an interrupted transaction
npx little-workflow@0.2.0-alpha.1 setup --here --rollback --yes

UNRELEASED (current source, no npm version yet): --here always means the current directory and no longer selects the existing-app mode, so pass --template existing-next as above to add Little to an existing Next.js app (the published release accepts it too). A new-project template (node, the default, or next) needs an empty target. The default provider is openai, matching little init and little-harness init. The --workflow starter is a fixed-plan starter_echo workflow with no model.

setup includes Harness and optionally a working durable Workflow echo example. It detects app/ or src/app/, places agent definitions beside the app, preserves routes, scripts, configuration and environment files, and rejects conflicts before writing. Rerunning the same choices is a no-op. The default demo uses no keys or model calls. Live production chat requires application authentication; filesystem and SQLite persistence are for local development. Compute is not published. Run setup --help for provider, model, package manager, route, page, installation and verification options.

Setup journals generated files and temporary writes. Rollback restores unchanged CLI-written content and preserves concurrent edits. After process termination, stop the installer before using --rollback, and pass the same project directory (or --here from inside it).

In published 0.2.0-alpha.1, --rollback without a directory or --here recovers the current directory. When no edited files were preserved, it prints one generic success line, including when it found no setup journal; retained edits keep the journal available for manual recovery.

UNRELEASED (current source, no npm version yet): --rollback needs a project directory or --here; the interrupted-setup error prints the exact, shell-quoted recovery command; recovery reports whether it found nothing to recover, rolled back an uncommitted setup, finished cleanup of a committed one, or preserved edited files and left the journal for manual recovery (an error exit). The library API is recoverSetup(). See Setup Recovery.

Validate

little validate workflow.json

Parses compiled LWIR JSON, or a locked WorkflowVersion JSON document with a top-level lwir field, runs it through the static validator (JSON Schema subset, expression syntax, capability resolution, schema compatibility), and prints findings.

The command exits 0 when the document is valid and 1 when findings are present.

Init And Add

little init [project-name] [--here] [--workflow] [--workflow-name <name>] [--with-harness] [--agent <name>] [--provider <provider>] [--model <model>] [--force]
little add workflow <name> [--dir <dir>] [--provider <provider>] [--model <model>] [--force]
little add harness [--agent <name>] [--workflow-name <existing-name> | --new-workflow <name>] [--provider <provider>] [--model <model>] [--force]

init creates a workflow-first TypeScript project in ./<name> (default little-workflow-project; --here uses the current directory, which need not be empty). It writes little-workflow.json, a starter workflows/<name>/workflow.ts (name it with --workflow-name; default candidate-review), instructions.md, tools/echo.ts, tsconfig.json, input.example.json, and a package.json with test:workflow and typecheck scripts. The starter is a defineWorkflow with a fixed one-step plan, so little test runs it without a model call; delete plan to let the planner draft the steps. --workflow is accepted for parity with little setup and changes nothing: init always writes the starter workflow. The default provider is openai, as in little setup and little-harness init; --provider accepts any provider the Little Harness scaffolder knows, and --model overrides its default model. init never prompts or installs packages, so it rejects --yes, --no-install and --install. An existing non-empty target is refused unless you pass --force. For a Harness-first Node or Next.js project, use little setup.

In published 0.2.0-alpha.1, init names the workflow with --workflow <name>, accepts --yes and --no-install without effect, and defaults to the deepseek provider.

The generated package.json pins versions instead of using latest. @little-stack/workflow is pinned to the CLI's own version (^0.2.0-alpha.2 from this source; published 0.2.0-alpha.1 pins little-workflow), ai to ^7.0.0, and the provider package to its AI SDK 7-era range. It also sets "pnpm": { "onlyBuiltDependencies": ["better-sqlite3"] } so pnpm 10 builds the event store's native binding.

--with-harness also creates little-harness.json, an agent folder (agents/<agent>/, default support), a test:agent script, and an agent workflow shim, agents/<agent>/workflows/<name>.ts. The shim default-exports loadWorkflow(...) for the manifest folder, so the agent gets the workflow as a tool. See Compose With Little Harness.

add workflow adds another workflow folder (under workflows/, or --dir) and records it in little-workflow.json. add harness creates or reuses a Harness agent and writes an agent workflow shim for either an existing manifest workflow (--workflow-name; --workflow in published 0.2.0-alpha.1) or a new one (--new-workflow).

Orchestrate

little orchestrate is reserved and exits with an error: planner-backed runs need a harness, which alpha exposes only through the SDK (runWorkflow(), or a Little Harness agent for composition). The CLI does not load harness adapters from JSON.

Run

little run workflow.json --input input.json [--run-id <id>]

Registers compiled LWIR JSON, or accepts a locked WorkflowVersion JSON document, and executes it against the configured world (defaults to localWorld({ dataDir: '.little-workflow' })). Blocks until the run reaches RunCompleted or RunFailed, prints the result summary (runId, workflowVersionId, status, output or error, usage, artifacts, eventCount), and exits 0 on completion or 1 on failure. --run-id sets the durable run id; re-running with the id of a terminal run replays its recorded result instead of executing again. A locked WorkflowVersion whose inputBinding is required is rejected when --input does not hash to its inputHash.

run remains the raw LWIR path. A compiled LWIR that requires an unavailable tool/model will terminate as RunFailed with a JSON summary.

Test

little test <workflow-folder-or-name> --input input.json [--timeout <ms>]

Loads a folder-authored workflow from a direct folder path, file URL, or a workflow name in the nearest little-workflow.json (via loadWorkflow), then runs it with the folder's discovered instructions.md, tools/, and skills/. This runs the planner and model calls for real, so it needs the provider's API key. The JSON summary includes workflowId, runId, status, output, usage, artifacts, and event count. The command exits 0 when the run completes and 1 otherwise.

Events

little events <runId>

Dumps the event log for a run from the alpha event store. JSON output, one event per line, in commit order. The basis for hand-built inspection until the proper inspector lands in beta.

The event log includes both LWIR-level step events and harness-level session events:

  • LWIR step events: StepAttemptStarted, StepCompleted, StepFailed, ParallelGroupStarted/Completed, etc.
  • Harness session events: harness.session.started, harness.session.completed, harness.session.failed, harness.model.called, harness.model.responded, harness.tool_call.started, harness.tool_call.succeeded, harness.tool_call.failed, harness.execute_step.started, harness.execute_step.succeeded.

Filtering by event type

# Show only harness session boundary events:
little events <runId> --type harness.session.*

# Show all harness tool-call events (model- and code-driven):
little events <runId> --type harness.tool_call.*

# Show only events emitted by code.run tool proxy (not the model):
little events <runId> --type harness.tool_call.* --caller code

# Show model invocations:
little events <runId> --type harness.model.called

The --caller filter matches the payload.caller field on harness.tool_call.started events:

--caller valueWhat it selects
modelTool calls the agent's model emitted in its agent loop (including bash, and the deprecated orchestrator's plan_workflow, run_workflow, start_workflow)
codeTool calls a code.run step body made via the tools proxy

harness.session.started inspection

Each harness session's first event contains the full manifest used for that session:

little events <runId> --type harness.session.started

This shows the OrchestratorManifest, PlannerManifest, or WorkerManifest (depending on role) with its manifestHash. Useful for auditing what model, harness, skills, and tools were in effect when the session ran.

Replay

little replay <runId>

Reconstructs run state from the event log without calling models, tools, shell, code, or external APIs. The output is the rebuilt in-memory state at the last persisted event. This is what proves the kill-and-resume invariant.

Replay works at both layers:

  • LWIR step replay: reconstructs which steps completed, their outputs, and artifact refs. Completed steps with committed StepCompleted events are never re-executed on resume.
  • Harness session replay: reconstructs each harness session's conversation state turn-by-turn. Committed harness.model.called, harness.model.responded pairs are fast-forwarded; committed harness.tool_call.started, harness.tool_call.succeeded pairs replay their results. The session resumes from the last uncommitted boundary.

Report

little report <runId> [--table] [--data-dir <dir>]

Materializes the run's event log and prints a per-step ledger of tokens, prompt-cache hit share, and real US dollars. Dollars are computed here, not read off the log: events record token counts and the { provider, modelId } that served each call, and report multiplies those against the bundled model registry's USD-per-1M-token rates.

JSON is the default, matching the rest of the CLI. --table opts into the human-readable fixed-width rendering.

Run run_7f3a (completed)

STEP          IN  CACHED  CACHE%    OUT  CALLS  COST (USD)
---------  -----  ------  ------  -----  -----  ----------
classify     900       0    0.0%    120   0+1?         n/a
extract    20000   16000   80.0%  10000      1    0.007800
summarize  20000       0    0.0%  10000      1    0.009000
---------  -----  ------  ------  -----  -----  ----------
TOTAL      40900   16000   39.1%  20120   2+1?    0.016800

Note: 1 model call(s) had no registry pricing and are excluded from the cost above.

Columns:

ColumnMeaning
IN / OUTPrompt and completion tokens attributed to the step.
CACHEDThe part of IN served from the provider's prompt cache — a subset of IN, not an addition to it.
CACHE%CACHED / IN.
CALLSModel calls on the row: priced alone, or priced+unpriced? when some call had no registry entry.
COST (USD)Summed dollars over the priced calls: n/a when none could be priced, <0.000001 for real money below the display precision, 0.000000 for a genuine zero.

The three renderings are deliberately distinct. n/a is not 0.000000 — an unpriced call is not a free call. And <0.000001 is not 0.000000 either: one gpt-4o-mini call with a single input token costs $0.00000015, so a six-decimal figure would round real spend down to a zero that reads like a step which spent nothing. Only 0.000000 means zero. The JSON form is unaffected — it carries the exact number.

The trailing note appears whenever unpricedCalls > 0, so a receipt can never quietly under-report. Model calls belonging to no step (a planner or orchestrator session) appear as an (unattributed) row so the per-step rows and the total reconcile.

The JSON form carries the same figures plus reasoningTokens, pricedCalls, and unpricedCalls on every row. Below is the same run, with the steps array trimmed to one entry for brevity — every row, including total and the optional unattributed, has the identical shape:

{
  "runId": "run_7f3a",
  "status": "completed",
  "steps": [
    {
      "stepPath": "extract",
      "status": "completed",
      "inputTokens": 20000,
      "cachedInputTokens": 16000,
      "outputTokens": 10000,
      "reasoningTokens": 0,
      "cacheHitShare": 0.8,
      "costUsd": 0.0078,
      "pricedCalls": 1,
      "unpricedCalls": 0
    }
  ],
  "total": {
    "stepPath": "TOTAL",
    "status": "completed",
    "inputTokens": 40900,
    "cachedInputTokens": 16000,
    "outputTokens": 20120,
    "reasoningTokens": 0,
    "cacheHitShare": 0.39119804400978,
    "costUsd": 0.0168,
    "pricedCalls": 2,
    "unpricedCalls": 1
  },
  "hasUnpricedCalls": true
}

costUsd is number | null everywhere it appears. null means unpriced; a genuine 0 is a real zero-dollar total, normally because there were no model calls in scope.

Pre-run cost estimation and budget enforcement are separate, still-unimplemented surfaces — report is strictly a post-run receipt. See the Roadmap.

On this page