Skip to content

CLI reference

The executable is factory. From a source checkout, prefix every command with uv run.

factory [OPTIONS] COMMAND [ARGS]...

  Local-first autonomous software engineering factory.

Options:
  --version, -V   Show the factory version and exit.

Commands:
  run         Run one work item synchronously through the factory workflow.
  project     Derive and execute a bounded project work breakdown.
  start       Poll a GitHub Issues backlog and dispatch eligible work.
  runs        List persisted runs, most recently created last.
  show        Show the persisted details of one run as JSON.
  doctor      Check this machine's prerequisites for the configured feature set.
  status      Report derived run metrics and operational health, read-only.
  skill       Inspect, validate and refresh repository guidance.
  dashboard   Serve the read-only local dashboard until interrupted.
  service     Manage the opt-in per-user macOS launchd service.

Common options

Most commands accept these.

Option Default Effect
--config <path> packaged config Factory config YAML to load.
--data-dir <path> factory.data_dir Override the configured data directory.
--model-profile <name> default Select the top-level models routing or a complete named entry from model_profiles. Available on agent-invoking commands, doctor, and service install.

--data-dir is how you keep an experiment out of ~/.software-factory. The test suite uses it for exactly that.

Exit codes

Code Meaning
0 Success.
1 The command failed, or a run ended in NEEDS_HUMAN or FAILED.
2 Configuration error or missing prerequisite. Nothing was started.

factory run

Run one work item synchronously through the whole workflow.

factory run \
  --repo ~/projects/example \
  --title "Reject empty customer names" \
  --description "Return HTTP 400 for empty or whitespace-only names." \
  --acceptance-criterion "Empty or whitespace-only names return HTTP 400."
Option Required Default Effect
--repo <path> yes none Path to the target Git repository.
--title <str> yes none Short title for the work item.
--description <str> yes none Description of the work to perform.
--acceptance-criterion <str> no none Required outcome. Repeat as needed.
--constraint <str> no none Work item constraint. Repeat as needed.
--work-item-id <str> no random Stable work item id. Use the scheduler's tracker-owner/repo#12 form so a manual run and the daemon cannot duplicate the same work.
--runtime <fake\|copilot> no fake fake makes no model calls. copilot is paid.
--model-profile <name> no default Select a configured model profile, such as the packaged economy profile.
--performance-mode <standard\|fast> no configured Override the workflow performance mode. Fast mode applies only to eligible low-risk work.
--config <path> no packaged Config YAML.
--data-dir <path> no configured Data directory override.

Prints the run id, final state, workspace path and the controller-derived changed files. Creates an isolated Git worktree under the data directory.

Refuses with exit code 2 if a prerequisite for the enabled feature set is missing.


factory project

Turn a high-level project description into the smallest sufficient set of work items, then execute them through the existing workflow.

factory project \
  --repo ~/projects/example \
  --title "Build customer onboarding" \
  --description "Add signup, email verification, and the first-login flow." \
  --acceptance-criterion "A new customer can complete onboarding." \
  --runtime copilot
Option Required Default Effect
--repo <path> yes none Path to the target Git repository.
--title <str> unless resuming none Short project title.
--description <str> unless resuming none High-level product or feature description.
--acceptance-criterion <str> no none Required outcome. Repeat as needed.
--constraint <str> no none Project constraint. Repeat as needed.
--project-id <str> no random Stable project identifier.
--resume no false Reconcile the stored project. Requires --project-id and reuses its brief and plan.
--github-repo <OWNER/NAME> no none Create one GitHub issue per validated task and close it after integration or confirmed merge.
--runtime <fake\|copilot> no fake fake creates one deterministic task. copilot derives the real plan.
--model-profile <name> no default Select a configured model profile, such as economy.
--performance-mode <standard\|fast> no configured Override the workflow performance mode for child runs.
--config <path> no packaged Config YAML.
--data-dir <path> no configured Data directory override.

The planner is read-only and returns a typed ProjectPlan. Task ids are contiguous. Dependencies can point only to earlier tasks. At most 12 tasks are accepted. One task is preferred whenever one coherent change is sufficient.

Dependency-ready tasks run in waves using scheduler.max_concurrent_tasks (1 or 2). Each task still uses the full triage, refine, plan, implement, verify, test, and review pipeline. Successful task commits are cherry-picked onto one persistent project integration branch, so downstream tasks see predecessor changes. The configured repository commands run once more against the complete integration branch before the project is DONE. A conflict, failed child run, final verification failure, or human-approval gate stops the project instead of guessing.

With PR/CI/merge disabled, project execution produces a local integration branch. With all three enabled, tasks run serially through PR creation. Then they pass through bounded CI repair and guarded automatic merge. Each task starts from the refreshed target including its merged predecessors. Final verification and confirmed child merges determine project completion. GitHub issue publication is optional. It does not apply the scheduler's agent-ready label. Thus, the project command remains the single execution owner.

--resume uses the stored brief and immutable plan, reconciles persisted child delivery checkpoints, and never resets attempt budgets. It refuses policy/repository drift and does not replay ambiguous interrupted agent work. See Autonomous project delivery.

Artifacts are stored under:

<data_dir>/projects/<project-id>/
├── project-brief.json
├── project-plan.json
├── execution.json       # includes planner invocation usage when reported
└── logs/

factory start

Poll a GitHub Issues backlog and dispatch eligible work.

factory start --repo ~/projects/example --github-repo acme/example --config ~/my-factory.yaml
Option Required Default Effect
--repo <path> yes none Path to the target Git repository.
--github-repo <str> yes none Backlog repository as OWNER/NAME.
--runtime <fake\|copilot> no fake Agent runtime.
--model-profile <name> no default Select a configured model profile for every dispatched run.
--performance-mode <standard\|fast> no configured Override the workflow performance mode for dispatched runs.
--once no off Run one bounded tick instead of polling forever.
--config <path> no packaged Config YAML.
--data-dir <path> no configured Data directory override.

Refuses to run, and never touches GitHub, unless scheduler.enabled is true in the configuration. It blocks in the foreground. Press Ctrl-C to stop it after the current tick.

See GitHub backlog, PRs and CI.


factory runs

List persisted runs, most recently created last.

factory runs

Tab-separated: run id, state, work item id, creation timestamp.

Options: --config, --data-dir.


factory show

Show the persisted details of one run as JSON.

factory show run-9bb36bbbdf114f53bd9599a103122976
Argument Required Effect
run_id yes The run id to display.

Options: --config, --data-dir.

Prints the work item text, so redact before sharing.


factory doctor

Check this machine's prerequisites for the configured feature set.

factory doctor
factory doctor --json --config ~/my-factory.yaml
Option Default Effect
--runtime <fake\|copilot> fake Check prerequisites for this runtime. copilot additionally requires the copilot executable.
--model-profile <name> default Validate this configured model profile.
--json off Emit the report as JSON.
--config <path> packaged Config YAML.
--data-dir <path> configured Data directory override.

Checks the platform and the build type. Also checks launchctl, git, configuration validity, and data directory writability. Checks the executables behind configured repository commands. Checks gh only when the configuration enables pull requests, CI observation, or the scheduler.

Never makes a paid model call. The only copilot interaction is a bounded copilot --version probe.

Exits nonzero if any check errored. Warnings alone do not fail it.


factory status

Report derived run metrics and operational health. Read-only.

factory status
factory status --json --limit 50 --offset 50
Option Default Effect
--limit <int> 20 How many runs to list. Minimum 1.
--offset <int> 0 Where to start the listing.
--stale-after-seconds <int> scheduler.stall_timeout_seconds Idle time before a non-terminal run counts as stale.
--max-scanned-runs <int> 1000 Hard cap on run files parsed per call.
--json off Emit snapshot and health as JSON.
--config <path> packaged Config YAML.
--data-dir <path> configured Data directory override.

Everything is recomputed from persisted artifacts on each call. This command never creates, mutates or repairs a run, a workspace, a lock or the data directory itself. A truncated or partially unreadable scan reports DEGRADED. For normal workflow runs, the human and JSON views include totals derived from persisted invocation records. Missing runtime-reported fields remain unknown, and premium-request cost and nano-AIU are raw Copilot units, not USD.


factory skill

Inspect, validate and refresh the repository guidance for the optional post-green polish attempt. Guidance lives under the configured data directory. Repository-scoped storage uses the repository and its dependency fingerprint as its key. Guidance never exists inside the target repository. See Repository skills and overlays.

factory skill path

Print the generated-skill and overlay locations discovered for a repository.

factory skill path --repo ~/projects/example
Option Required Default Effect
--repo <path> yes none Path to the target Git repository.
--config <path> no packaged Config YAML.
--data-dir <path> no configured Data directory override.

Read-only. It creates nothing. It does not create the overlay file.

The repository key comes from the canonical local Git common directory. Linked worktrees of one checkout report the same directory. Moving or re-cloning a repository reports a different directory. If you want to move or copy guidance, run this command before moving the repository.

factory skill validate

Validate the current generated skill and overlay for a repository.

factory skill validate --repo ~/projects/example
Option Required Default Effect
--repo <path> yes none Path to the target Git repository.
--config <path> no packaged Config YAML.
--data-dir <path> no configured Data directory override.

Reports whether stored guidance matches the current dependency fingerprint. Also checks whether every cited source is inside the configured allowlists, and why an overlay is ignored. Read-only: it never repairs, reformats, rewrites or creates a file, and an invalid overlay is left exactly as written.

factory skill refresh

Refresh generated guidance for a repository, explicitly.

factory skill refresh --repo ~/projects/example --runtime copilot
Option Required Default Effect
--repo <path> yes none Path to the target Git repository.
--runtime <fake\|copilot> no fake fake makes no model calls. copilot is paid.
--model-profile <name> no default Select the Researcher configuration used for generation.
--config <path> no packaged Config YAML.
--data-dir <path> no configured Data directory override.

Touches generated guidance only. It never creates, rewrites or deletes your repository-skill-overlay.yaml, and it changes no run, workspace or configuration.

This command is the only command that can replace an existing generated file. Warnings from runs point here when stored guidance no longer revalidates. The standalone generation invocation is persisted as last-invocation.json in the neutral generation directory. Each refresh replaces that command-specific record. Normal run telemetry remains in the run artifact.


factory dashboard

Serve the read-only local dashboard until interrupted.

factory dashboard
factory dashboard --port 0 --open-browser
Option Default Effect
--port <int> 8765 Loopback port. 0 asks the OS for a free port.
--open-browser off Open the tokenized URL in the default browser.
--max-scanned-runs <int> 1000 Hard cap on run files parsed per request.
--config <path> packaged Config YAML.
--data-dir <path> configured Data directory override.

The dashboard shows active and completed projects, task progress, and models used by invocations. It also displays workflow runs, attempts, active invocations, usage totals, and operational health. The factory persists an active invocation before Copilot starts. The run lease labels it running, stale, crashed, or abandoned. The previous completed attempt does not determine this label. When Copilot reports nano-AIU, the dashboard converts it to an AI usage value in USD. The conversion uses GitHub's published rate of 1 AI credit to $0.01. This value is the price of the reported model usage. It is not necessarily the amount added to the bill. Included or pooled credits can cover it. Input and output token counts remain separate metrics. Legacy premium-request units also remain separate and are never multiplied.

Blocks in the foreground. Binds 127.0.0.1 and nothing else, answers GET only, and requires a token generated for that process. The tokenized URL is printed to stdout once and never written to the log. Ctrl-C stops it and closes the socket.

This is the only command that opens a socket.


factory service

Manage the opt-in per-user macOS launchd service. macOS only.

factory service install

factory service install \
  --repo ~/projects/example \
  --github-repo acme/example \
  --config ~/my-factory.yaml
Option Required Default Effect
--repo <path> yes none Absolute path to the target Git repository.
--github-repo <str> yes none Backlog repository as OWNER/NAME.
--config <path> no packaged Config the service loads. Must enable scheduler.enabled.
--data-dir <path> no configured Data directory for the service.
--runtime <fake\|copilot> no fake Runtime the service runs with.
--model-profile <name> no default Profile retained in the installed factory start arguments.
--executable <path> no this build Explicit factory executable to run.
--label <str> no com.github.software-agent-factory LaunchAgent label.
--allow-source-dev no off Permit an executable in an otherwise-refused location, such as a source checkout.
--json no off Emit the resulting status as JSON.

Writes one plist under ~/Library/LaunchAgents. Refuses unless the target configuration enables the scheduler, and refuses if factory doctor reports any error. Defaults to --runtime fake so an installed-but-forgotten agent cannot spend money.

Nothing installs a service when you extract an archive, run the factory, or upgrade the build.

factory service status

factory service status --json
Option Default Effect
--label <str> com.github.software-agent-factory LaunchAgent label to inspect.
--json off Emit as JSON.

Read-only.

factory service uninstall

factory service uninstall
Option Default Effect
--label <str> com.github.software-agent-factory LaunchAgent label to remove.
--json off Emit the result as JSON.

Unloads the agent and removes the plist. Leaves every run, artifact and workspace on disk.