bus-dev
bus-dev — developer workflows for BusDK module repositories
Synopsis
bus dev [-h] [-V] [--check] [-v] [-q] [-C <dir>] [-o <file>] [--color <auto|always|never>] [--no-color] [--agent <cursor|codex|codex:local|gemini|claude>] <operation> [operation ...]
Operations: init, commit, plan, spec, stage, work, e2e, triage, each, retry, set, context, list, pipeline, action, and script.
Each operation token can be a base operation name, a pipeline name (built-in, repository-local, or preference), or a user-defined action name (repository-local prompt or script).
Only one invocation that operates on a given directory (init, commit, stage, plan, work, spec, e2e, triage, retry) runs at a time for that directory. A second invocation for the same directory waits until the first exits.
The set, context, list, pipeline, action, and script subcommands are management operations. They do not participate in workflow chaining.
Repository-writing management commands (pipeline set repo, pipeline unset repo, action set, action unset, action generate, script set, script unset, script generate) take the same per-directory lock as workflow operations.
The workflow operations plan, spec, work, e2e, triage, stage, and commit can be run in any order and combination in one invocation (for example bus dev plan spec work or bus dev plan work stage commit). All tokens are resolved and expanded before execution. Repeated step names are merged so each step appears once in first-appearance order.
retry is an executable workflow control command with its own flag contract (--on-fail, --attempts) and is intended to run as a standalone operation. It is not mixed with other workflow tokens in the same top-level invocation.
With global --check, bus-dev validates token expansion and script runnability without executing steps.
init accepts an optional directory, then zero or more workflow tokens that expand only to plan, spec, work, and e2e.
bus dev init [DIR] [--lang go] [plan|spec|work|e2e ...] — initialize module files in the current directory by default, or in DIR when provided; does not run plan/spec/work/e2e unless explicitly listed.
bus dev commit — commit staged changes with high-quality messages (no remote, no history rewrite).
bus dev stage — prepare the working tree for commit by having the agent ensure only intended files are staged: identify temporary files, e2e leftovers, and other files that should not be tracked, add them to .gitignore or remove them, then stage the rest; if there are no unstaged or untracked changes, stage exits 0 without invoking the agent or running git add; combinable with plan, spec, work, e2e, and commit so you can run full cycles in one invocation.
bus dev plan — review SDD and docs against repository state, then refresh PLAN.md with prioritized unchecked undone work items only.
bus dev spec — ensure the repository has a compact but detailed local spec in AGENTS.md that reflects the latest BusDK specifications and describes how to implement this tool; creates AGENTS.md from online SDD and user documentation when missing.
bus dev work — run the “do the work in this repo” agent workflow (code, tests, README).
bus dev e2e — guided workflow to detect and scaffold missing end-to-end tests.
bus dev triage — keep development-state documentation accurate and evidence-based by reconciling test-proven capabilities with planned work and dependencies; updates only documentation (development-status page and module docs), never code or tests.
bus dev each [--check] [--skip MODULE[,MODULE...]]... TOKEN... — superproject-only helper that runs bus dev TOKEN... in every discovered child module from the deterministic union of .gitmodules paths and top-level directories that contain .bus/dev (deduplicated): bus first when present, then remaining discovered paths sorted lexicographically. A discovered child is selected when it contains a Makefile or .bus/dev. Before execution, it preflights all selected modules and fails fast if any module cannot resolve the requested tokens or has a non-runnable script action (for Unix script actions, missing +x fails preflight). --check performs the same preflight without executing any module command. --skip excludes one or more modules by directory name; it may be repeated and supports comma-separated names.
bus dev retry --on-fail|-f <TOKEN>[,<TOKEN>...] [--attempts N] <workflow-token>... — run the workflow token sequence, and if it fails, run the fallback token list and retry the workflow up to N additional times with exponential backoff (1s, 2s, 4s, …). Workflow and fallback token lists are each resolved and normalized before execution. Omit --attempts to default to one additional retry. --attempts 0 is valid, runs the workflow once, and skips fallback execution. Built-in-only fallback tokens can be forced with @ (for example @commit).
bus dev set agent <cursor|codex|codex:local|gemini|claude> — set the bus-dev persistent default agent (bus-dev.agent) via the bus-preferences Go library.
bus dev set model <value> — set the bus-dev persistent default model (bus-dev.model).
bus dev set model-reasoning-effort <minimal|low|medium|high|xhigh> — set default model reasoning effort (bus-dev.model_reasoning_effort).
bus dev set model-verbosity <low|medium|high> — set default model verbosity (bus-dev.model_verbosity).
bus dev set output-format <ndjson|text> — set the bus-dev persistent default output format (bus-dev.output_format).
bus dev set timeout <duration> — set the bus-dev persistent default timeout (bus-dev.timeout).
bus dev set agent-for <token|@token> <cursor|codex|codex:local|gemini|claude> — set the bus-dev per-step runtime default (bus-dev.agent_for.*).
bus dev set model-for <token|@token> <value> — set the bus-dev per-step model default (bus-dev.model_for.*).
bus dev set model-reasoning-effort-for <token|@token> <minimal|low|medium|high|xhigh> — set per-step reasoning effort (bus-dev.model_reasoning_effort_for.*).
bus dev set model-verbosity-for <token|@token> <low|medium|high> — set per-step verbosity (bus-dev.model_verbosity_for.*).
bus dev set model-reasoning-effort-for-model <model> <minimal|low|medium|high|xhigh> — set per-model reasoning effort (bus-dev.model_reasoning_effort_for_model.*).
bus dev set model-verbosity-for-model <model> <low|medium|high> — set per-model verbosity (bus-dev.model_verbosity_for_model.*).
bus dev set env-for <token|@token> <ENV_NAME> <value> — set per-step environment override (bus-dev.env_for.*).
bus dev set allow-dirs-for <token|@token> <dir...> — set per-step allowed directories for agent runtimes that support directory allow-lists (bus-dev.allowed_dirs_for.*).
bus dev set allow-dirs-for-module <module> <token|@token> <dir...> — set per-module per-step allowed directories (bus-dev.allowed_dirs_for_module.*).
bus dev context — print the full prompt-variable catalog and current resolved values (one KEY=VALUE line per variable, sorted by key) for use by prompt and script authors; requires a Git repository and exits 2 when not in one.
bus dev list — print every runnable token (operations, pipelines, prompt actions, script actions) and what they execute, without running any agent, script, or Git operation; outside a repo shows only built-in operations and pipelines with descriptions and expanded steps; inside a repo adds repository-local and preference pipelines, prompt actions, and script actions with source and expansion.
bus dev pipeline set repo NAME TOKEN... — write or overwrite .bus/dev/NAME.yml with a YAML sequence of tokens.
bus dev pipeline unset repo NAME — remove .bus/dev/NAME.yml if present; exit 0 if absent.
bus dev pipeline set prefs NAME TOKEN... — write preference bus-dev.pipeline.NAME as a JSON array of strings (via bus-preferences library, no shell-out).
bus dev pipeline unset prefs NAME — remove the preference key if present; exit 0 if absent.
bus dev pipeline list [all|repo|prefs|builtin] — print a deterministic listing of pipelines and their source; output to stdout, lexicographic by name then source.
bus dev pipeline preview TOKEN... — resolve and expand tokens, apply the same normalization used by runnable invocations (merge only repeated direct base-operation steps; no merge across pipeline invocations), print one step name per line to stdout, and exit without running any step.
bus dev action set NAME — read content from stdin and write .bus/dev/NAME.txt; stdin must be non-empty (empty stdin → exit 2).
bus dev action unset NAME — remove .bus/dev/NAME.txt if present; exit 0 if absent.
bus dev action list — print available repository actions to stdout.
bus dev action generate NAME INSTRUCTION... — agent-assisted: produce a prompt template and write it to .bus/dev/NAME.txt.
bus dev script set NAME [--platform=unix|windows|windows-ps1|both] — write .bus/dev/NAME.sh (unix), .bus/dev/NAME.bat (windows), and/or .bus/dev/NAME.ps1 (windows-ps1) from stdin; set executable bit on .sh (chmod failure → exit 1).
bus dev script unset NAME [--platform=unix|windows|windows-ps1|both] — remove the selected script variant(s); exit 0 if absent.
bus dev script list — print available repository scripts and variant/enabled status to stdout.
bus dev script generate NAME --platform=unix|windows|windows-ps1|both INSTRUCTION... — agent-assisted: produce script content and write to the correct file(s).
bus dev [plan|spec|work|e2e|triage|stage|commit] ... — run one or more base operations, pipeline names, or user-defined action names in the order you list them (e.g. bus dev plan spec work, bus dev round, or bus dev round refresh); tokens are resolved and expanded first, then normalization is applied (repeated direct base-operation tokens are merged to one run each; steps from pipeline expansion are not merged across pipeline invocations), then the normalized sequence runs and stops on first failure.
Description
Command names follow CLI command naming. bus dev is a developer-only companion that centralizes workflow logic that module repositories would otherwise duplicate in scripts/.
It provides one entry point for module scaffolding, commit workflows, planning, AGENTS.md maintenance, e2e scaffolding, and development-state documentation triage.
Agent runtime execution (Cursor CLI, Codex, Gemini CLI, Claude CLI) is provided by the bus-agent library so runtime detection and diagnostics stay consistent across modules. The codex:local runtime token is also supported and runs Codex in local mode (--oss).
bus dev accepts one operation (bus dev work) or multiple operations in one invocation (bus dev plan work stage commit). It also supports built-in and user-defined pipelines, plus repository-local actions/scripts under .bus/dev/.
Use bus dev list to see every runnable token in the current context, and bus dev pipeline preview TOKEN... to inspect the normalized execution order before running steps.
Most subcommands operate on the current Git repository. bus dev init is the exception: it can initialize files in place or in an explicit target directory without creating or modifying a Git repository.
The tool does not operate on workspace accounting datasets. End-user accounting workflows should use module CLIs such as bus accounts, bus journal, and bus validate.
For a practical .bus file that runs dev, agent, and run commands together in one sequence, see .bus getting started — multiple commands together.
From BusDK v0.0.26 onward, bus dev can select Codex through the shared bus-agent runtime layer (--agent codex, --agent codex:local, BUS_DEV_AGENT=codex, or preferences). Codex CLI sign-in works with a ChatGPT Plus subscription (and other eligible ChatGPT plans), so contributors can use Codex-backed workflows without API-key-only setup. Gemini and Claude runtime paths exist but remain in-progress and not fully verified by end-to-end tests.
For ChatGPT Pro users, a practical research-preview setup is to pin Codex as the default runtime for both bus dev and bus run, then use a faster Codex model only for stage and commit steps.
$ bus dev set agent codex
$ bus run set agent codex
$ bus dev set model-for @stage gpt-5.3-codex-spark
$ bus dev set model-for @commit gpt-5.3-codex-spark
$ bus preferences list
bus-agent.runtime=codex
bus-dev.agent=codex
bus-dev.model_for.builtin.commit=gpt-5.3-codex-spark
bus-dev.model_for.builtin.stage=gpt-5.3-codex-spark
bus-run.agent=codex
All paths and the working directory are resolved relative to the current directory unless you set -C / --chdir. The tool discovers the repository root from the effective working directory and does not require a config file for repository-scoped commands. Subcommands that need a module name in repository scope (for example for e2e script naming) derive it deterministically from the repository: the module name is the base name of the repository root directory (the last path component of the absolute path to the repo root). For init, which can run outside a Git repository, the module name is derived from the base name of the init target directory.
Only one bus dev run that operates on a given directory (init, commit, stage, plan, work, spec, e2e, triage, retry) executes at a time for that directory. A second invocation for the same directory waits until the first exits.
This avoids concurrent edits to PLAN.md, AGENTS.md, and the staging area.
set, list, and context do not take the lock. Management subcommands pipeline, action, and script take the lock only for repository-writing operations.
If the lock cannot be acquired (for example the directory is not writable), the command exits with code 1 and a clear message.
Safety. bus dev never runs remote Git operations (push, pull, fetch, clone) and never rewrites history (--amend, rebase, squash).
It may run the agent for workflow steps, run local git add after stage cleanup, and run local git commit on already staged content. commit does not stage files by itself.
Bus-dev does not edit user-global configuration. Repository-local instruction/config updates are additive, except for the legacy Cursor rule file .cursor/rules/<module-name>.mdc, which may be migrated into AGENTS.md during bus dev spec.
Diagnostics and progress go to stderr. Deterministic command results are written to stdout.
Commands
init [DIR] [--lang go] [plan|spec|work|e2e|pipeline ...] — Initialize module root files without performing any Git operations. If DIR is omitted, initialization happens in the effective current working directory. If DIR is provided, initialization happens there (the directory is created if missing). When you run init, it ensures a single AGENTS.md exists at the project root (the target directory) and ensures a root Makefile exists by writing a built-in sample Makefile when missing. Init is not required to create AGENTS.md: in an existing repository you can run bus dev spec and the tool creates AGENTS.md from the online SDD and module end-user documentation when the file is missing. The --lang flag defaults to go and controls which default AGENTS.md content init installs when you use init. By default this command only initializes files; it does not run plan, spec, work, or e2e. To run workflow operations as part of init, append them explicitly in any order (base operations or pipelines that expand only to plan, spec, work, and e2e). They run in the exact order you provide after expansion, for example bus dev init plan spec work or bus dev init bus-accounts work plan e2e (target directory). If you use a pipeline that expands to stage, commit, or triage after init (e.g. bus dev init round), the command fails with invalid usage (exit 2) before running any step. If any requested step fails, the command exits non-zero with a clear diagnostic. Use this when you want deterministic in-place initialization first, then optional AI workflow steps under explicit control.
commit — Create one or more commits from the currently staged changes only. The command requires git to be installed and available in PATH; if Git is missing, it exits non-zero with a clear diagnostic. If there is nothing staged (and no submodules with staged changes to commit), the command does nothing and exits 0. The tool does not modify files, does not stage anything, and does not amend or rebase. If the repository has submodules, it commits inside submodules first (depth-first), then the superproject only if it has staged changes. If a submodule commit leaves an unstaged gitlink in the superproject, the tool reports that clearly and stops without staging it; you must stage the gitlink manually if desired. For each commit, the message must have a concise, imperative subject line; a body may follow, with traceability (issue IDs or URLs) when helpful. By default the tool commits exactly what is currently staged and does not alter the staging area. If a hook (e.g. pre-commit, commit-msg) fails, the tool reports the failure and exits non-zero; it does not retry.
stage — Prepare the working tree for commit by ensuring only intended files are staged. If there are no unstaged tracked changes and no untracked files to stage, the command exits 0 immediately and does not invoke the agent or run git add. Otherwise, the tool invokes the configured agent with an embedded prompt that instructs it to review the working tree, identify files that should not be tracked (for example temporary files, e2e test leftovers, or build artifacts), and either add them (or matching patterns) to .gitignore or remove them from the project. After the agent has finished, the tool stages all remaining changes at the repository root so that a subsequent commit has only the intended content. May be combined with plan, spec, work, e2e, triage, and commit in any order (e.g. bus dev plan work stage commit). Does not commit, amend, or rebase, and does not perform any remote Git operations. If the repository has submodules, only the current repository’s working tree is in scope; see the module SDD for the normative rule.
plan — Build or refresh PLAN.md at repository root as a compact prioritized checklist of undone work. May be combined with spec, work, e2e, and triage in any order; operations run in the order you list them and stop on first failure. The command reviews the current repository, the main SDD, the current module SDD, the current module end-user docs, and other project SDD pages relevant to requirement coverage. It detects unimplemented features and other undone work and writes only PLAN.md. When PLAN.md already exists, the command re-validates existing items, removes items that are already done (including checked items), keeps items that are still undone, and adds newly detected missing work. This command is the one that prunes completed checked items from the plan. The file written by bus dev plan is a compact unchecked task list ordered by priority, with one unchecked item per undone work item and no implementation-level detail that should instead come from the SDD and related docs.
work — Run the canonical “do the work in this repo now” workflow. May be combined with plan, spec, e2e, and triage in any order (e.g. bus dev plan work or bus dev work plan spec e2e); operations run in the order you list them and stop on first failure. At the start of each agent step (plan, work, spec, e2e, triage, stage), the tool prints to stderr which internal agent runtime and which model are in use for that step. The tool invokes the configured external agent runtime with an embedded prompt that tells it to operate only inside the current module repository: make concrete code changes, add or update tests, run the Makefile checks, and update README before finishing. The agent is allowed to read the repository’s AGENTS.md and design docs as the authoritative specs. When PLAN.md exists at repository root, the workflow reads it first and prioritizes unchecked items before proposing additional work. As work items are completed, bus dev work checks them off in PLAN.md. It does not remove already checked items; checked-item pruning is handled by bus dev plan. When the selected runtime is Gemini CLI, the agent may also use repository-local Gemini context (e.g. repo-root GEMINI.md, .gemini/settings.json, .geminiignore); Bus Dev never modifies user-global Gemini configuration or memory. Which agent runtime is used is determined by the agent selection configuration (see below). This subcommand does not perform any Git remote operations.
spec — Ensure the repository has a compact but detailed local spec in AGENTS.md that reflects the latest BusDK specifications and describes how to implement this tool. May be combined with plan, work, e2e, and triage in any order; operations run in the order you list them and stop on first failure. The file is always AGENTS.md at the repository root. When AGENTS.md does not exist, the command creates it from the online SDD and module end-user documentation in the same run. If a Cursor rule file exists at .cursor/rules/<module-name>.mdc (where the module name is the base name of the repo, e.g. bus-accounts), its content is refactored into AGENTS.md and that file is then removed. No source code, tests, or README are changed. The refinement is driven by an embedded prompt inside the binary; the agent may read BusDK docs and the AGENTS.md format to align the file. When Gemini CLI is selected, repository-local Gemini context is used in parallel; Bus Dev does not write to user-global Gemini config or memory.
e2e — Guided workflow to detect missing end-to-end tests for the current module and scaffold them in a hermetic way, consistent with BusDK testing conventions and the module’s SDD and end-user documentation. May be combined with plan, spec, work, and triage in any order; operations run in the order you list them and stop on first failure. E2E tests are Bash scripts under tests/ named e2e_bus_<name>.sh, where <name> is the module name with the bus- prefix stripped (for example bus-accounts → tests/e2e.sh). The tool uses the module’s SDD and end-user docs to determine which tests are needed and produces scaffolds that cover the behavior described there. When PLAN.md exists at repository root, the workflow reads it first, treats checked items as completed-feature coverage obligations, verifies each checked item is fully covered by e2e tests, and prioritizes unchecked test-related items. It also continues to search SDD and end-user docs for other untested behavior exactly as it does without PLAN.md. This subcommand does not remove already checked plan items; checked-item pruning is handled by bus dev plan. The command does not perform remote Git operations or modify workspace accounting datasets.
triage — Keep development-state documentation accurate, compact, and evidence-based by reconciling what users can actually do (as proven by tests) with what is planned next (PLAN.md) and what depends on what. Updates only documentation: the overall development-status page and each module’s end-user docs page (the “Development state” section). Never modifies source code or test files. The command detects the project context automatically: run from the docs repo to update the development-status page and all module pages; run from the BusDK super-project to update the docs submodule’s same targets; run from a single module repo to update only that module’s page and the overall development-status page in the sibling docs repo. If the context is ambiguous, the command exits with code 2 and guidance on where to run it. May be combined with plan, spec, work, e2e, stage, and commit in any order (e.g. bus dev triage plan work); operations run in the order you list them and stop on first failure. At the start of the triage step, the tool prints to stderr which agent runtime and model are in use. See the module SDD for the normative behavior, project-context detection rules, and the structure of the “Development state” sections triage writes.
each [--check] [--skip MODULE[,MODULE...]]... TOKEN... — Superproject-only helper that dispatches the remaining command as bus dev TOKEN... in each child module. Child discovery is deterministic and sourced from a deduplicated union of .gitmodules paths and top-level directories containing .bus/dev; if bus is present it runs first, then remaining discovered child paths are sorted lexicographically. A discovered child is selected when its directory contains a Makefile or .bus/dev. Before any module command runs, each preflights every selected module with the same tokens and fails immediately if any module cannot resolve the token sequence or has a non-runnable script action (Unix script actions require .sh with +x). The command stops on first failure and returns that exit code. With --check, only preflight is run and no module command is executed. Use --skip to exclude modules by directory name (--skip can be repeated and accepts comma-separated names). each itself is not a workflow step and is not expanded by pipelines. Example: bus dev each --skip bus-docs,bus-legacy stage commit runs bus dev stage commit in each non-skipped child module; bus dev each --check --skip bus-docs stage commit validates readiness only for selected modules; bus dev each --check retry -f fix-tests test preflights retry fallback/target resolution in each selected module.
When you run each, the remaining tokens are exactly the command that each child module receives. For example, bus dev each --check --skip bus-docs pipeline preview round validates that every selected child can resolve pipeline preview round without executing a workflow step.
retry --on-fail|-f <TOKEN>[,<TOKEN>...] [--attempts N] <workflow-token>... — Run one workflow sequence, and if it fails, run the fallback token list before retrying. --on-fail (or -f) is required and each token list is expanded and normalized using standard token rules before execution. Workflow tokens may include multiple entries (for example test test_2) so both run together on each attempt. --attempts defaults to one additional retry and accepts zero or greater. --attempts 0 means the workflow runs once and exits with its original failure code without fallback. Fallback execution only occurs after a workflow failure. If fallback has no runnable steps (including after normalization), or if any token is invalid, execution fails with usage error. Built-in-only fallback tokens can be forced with @ (for example @commit).
The retry loop uses exponential backoff (1s, 2s, 4s, …) between workflow attempts and stops as soon as the workflow succeeds. If fallback returns non-zero, that code is returned immediately. Examples: bus dev retry --on-fail fix-tests,fix-tests-2 --attempts 2 test test_2, bus dev retry -f fix-tests,fix-tests-2 --attempts 1 test.
set — Set a persistent preference via the bus-preferences Go library (no shell-out to bus preferences). Bus-dev provides a dedicated subcommand for each key that affects agent use:
set agent <runtime> — Set the bus-dev persistent default agent (bus-dev.agent) via the bus-preferences Go library. Only the bus-dev namespace is written; no other namespace is modified. <runtime> must be one of cursor, codex, codex:local, gemini, or claude. Invalid runtime yields exit 2.
set model <value> — Set the bus-dev persistent default model (bus-dev.model) via the bus-preferences Go library. Only the bus-dev namespace is written. Invalid value yields exit 2.
set model-reasoning-effort <minimal|low|medium|high|xhigh> — Set bus-dev default model reasoning effort (bus-dev.model_reasoning_effort). This is used by runtimes that support it (Codex). Invalid value yields exit 2.
set model-verbosity <low|medium|high> — Set bus-dev default model verbosity (bus-dev.model_verbosity). This is used by runtimes that support it (Codex). Invalid value yields exit 2.
set output-format <ndjson|text> — Set the bus-dev persistent default output format (bus-dev.output_format) via the bus-preferences Go library. Valid values: ndjson (raw structured output), text (human-readable). Only the bus-dev namespace is written. Invalid value yields exit 2.
set timeout <duration> — Set the bus-dev persistent default timeout (bus-dev.timeout) via the bus-preferences Go library (e.g. 60m). Only the bus-dev namespace is written. Invalid value yields exit 2.
set agent-for <token|@token> <runtime> — Set a per-step runtime preference via bus-dev.agent_for.*. Use token for the generic selector (applies to both built-in and user-defined steps with that name) and @token for built-in-only selector matching. Runtime values are cursor, codex, codex:local, gemini, or claude. Invalid selector or runtime yields exit 2.
set model-for <token|@token> <value> — Set a per-step model preference via bus-dev.model_for.*. Use token for generic matching and @token for built-in-only matching. Invalid selector yields exit 2.
set model-reasoning-effort-for <token|@token> <minimal|low|medium|high|xhigh> — Set a per-step reasoning effort preference via bus-dev.model_reasoning_effort_for.* with the same selector semantics as model-for. Invalid selector or value yields exit 2.
set model-verbosity-for <token|@token> <low|medium|high> — Set a per-step verbosity preference via bus-dev.model_verbosity_for.* with the same selector semantics as model-for. Invalid selector or value yields exit 2.
set model-reasoning-effort-for-model <model> <minimal|low|medium|high|xhigh> — Set a per-model reasoning effort preference via bus-dev.model_reasoning_effort_for_model.*. This is applied when resolved model equals <model>. Invalid model or value yields exit 2.
set model-verbosity-for-model <model> <low|medium|high> — Set a per-model verbosity preference via bus-dev.model_verbosity_for_model.*. This is applied when resolved model equals <model>. Invalid model or value yields exit 2.
set env-for <token|@token> <ENV_NAME> <value> — Set a per-step environment override via bus-dev.env_for.*. Use token for generic matching and @token for built-in-only matching. ENV_NAME must match [A-Z_][A-Z0-9_]*. Invalid selector or env name yields exit 2.
set allow-dirs-for <token|@token> <dir...> — Set per-step allowed directories via bus-dev.allowed_dirs_for.*. Use token for generic matching and @token for built-in-only matching. Values are stored as a deterministic list (trimmed, deduplicated, order-preserving) and are passed to runtimes that support directory allow-lists. Invalid selector or empty/invalid dir list yields exit 2.
set allow-dirs-for-module <module> <token|@token> <dir...> — Set per-module per-step allowed directories via bus-dev.allowed_dirs_for_module.<module>.*. Module-specific entries are layered after global allowed_dirs_for entries for the same step and selector. Use this when one submodule needs extra writable roots (for example ../docs only for optimize in bus). Invalid module, selector, or empty/invalid dir list yields exit 2.
context — Print the full prompt-variable catalog and the current resolved values in deterministic, script-friendly form. Output is one KEY=VALUE line per variable, sorted by key ascending, with values exactly as used for prompt rendering and for environment injection into repository-local script actions. Use this when authoring or debugging prompt templates (.bus/dev/<name>.txt) or script actions (.bus/dev/<name>.sh, .bus/dev/<name>.bat, or .bus/dev/<name>.ps1) so you can see the same variables the tool uses. The command requires a Git repository; when the effective working directory is not inside a repository, it exits with code 2 and a clear message. Does not acquire the per-directory lock. Output goes to stdout.
list — Print every runnable token available in the current context and what each executes, without running any agent, script, or Git operation. Outside a Git repository, output includes only built-in operations and built-in pipelines, each with a one-line description and (for pipelines) the normalized expanded step sequence. Inside a Git repository, output additionally includes repository-local pipelines (source path and expanded steps), repository-local prompt actions (.bus/dev/<name>.txt), repository-local script actions (source and platform variants), and preference pipelines (source key and expanded steps). Each entry includes token name, type (operation, pipeline, action prompt, or action script), a short description or source, and for pipelines the normalized expanded step sequence. Output format is stable and parseable. Does not acquire the per-directory lock. Use this to see the full catalog of operations, pipelines, and user-defined actions before running them.
pipeline — Management operations for user-defined pipelines. Does not participate in workflow chaining. pipeline set repo NAME TOKEN… writes or overwrites .bus/dev/NAME.yml with a strict YAML sequence of scalar strings (one token per line/item). Requires a Git repository and takes the per-directory lock. pipeline unset repo NAME removes .bus/dev/NAME.yml if present; exits 0 if the file is already absent. pipeline set prefs NAME TOKEN… writes the preference key bus-dev.pipeline.NAME as a JSON array of strings via the bus-preferences Go library (no shell-out to bus preferences). pipeline unset prefs NAME removes that preference key if present; exits 0 if absent. **pipeline list [all |
repo | prefs | builtin]** prints a deterministic, line-oriented listing of available pipelines and their source (e.g. one line per pipeline with source tag and expanded token list); output is lexicographic by pipeline name then by source. pipeline preview TOKEN… resolves tokens with the same rules as runnable invocations, expands pipelines, merges repeated step names so each appears once in first-appearance order, prints one normalized step name per line to stdout, and exits without running any step. List and preview output go to stdout. The name NAME must start with a letter and contain only lowercase letters (a–z), digits, hyphens, and underscores; it must not match a reserved built-in operation (plan, spec, work, e2e, triage, stage, commit). Invalid name or a conflicting definition for the same name (e.g. an existing action or script with that name) yields exit 2 with a diagnostic that identifies the conflicting path(s) or key(s). |
action — Management operations for repository-local prompt actions (.bus/dev/<name>.txt). action set NAME reads the full content from stdin until EOF and writes it to .bus/dev/NAME.txt; creates .bus/dev if missing. Stdin must be non-empty; empty stdin yields exit 2. action unset NAME removes .bus/dev/NAME.txt if present; exits 0 if absent. action list prints available repository actions deterministically by name to stdout. action generate NAME INSTRUCTION… invokes the configured agent with an embedded generator prompt to produce a complete prompt template, then writes the result to .bus/dev/NAME.txt; the agent does not write files directly — bus dev performs the write. Defining an action (set or generate) fails with exit 2 if a pipeline or script with the same name already exists (ambiguity rule). Repository-writing commands take the per-directory lock.
script — Management operations for repository-local script actions (.bus/dev/<name>.sh, .bus/dev/<name>.bat, and .bus/dev/<name>.ps1). **script set NAME [–platform=unix |
windows | windows-ps1 | both]** reads content from stdin and writes .bus/dev/NAME.sh (unix), .bus/dev/NAME.bat (windows), and/or .bus/dev/NAME.ps1 (windows-ps1); default is the current platform. When writing the Unix variant, the tool sets the executable bit on .bus/dev/NAME.sh; if setting the bit fails, the command exits with code 1. **script unset NAME [–platform=unix |
windows | windows-ps1 | both]** removes the selected variant(s); exits 0 if already absent. script list prints available repository scripts by name with variant (.sh, .bat, .ps1) and enabled/disabled status to stdout; a Unix script without the execute bit is reported as disabled but still reserves the name for conflict detection. **script generate NAME –platform=unix | windows | windows-ps1 | both INSTRUCTION…** uses the agent to produce script content, then writes to the correct file(s) and sets the executable bit on .sh. On Windows, when both .bat and .ps1 exist for the same name, the tool uses .ps1. Defining a script (set or generate) fails with exit 2 if a pipeline or action with the same name exists. Repository-writing commands take the per-directory lock. |
Pipelines and repository-local extensions
A pipeline is a named sequence of operations (and optionally other pipelines or user-defined actions). You can use a pipeline name instead of listing each operation so that common workflows stay short and consistent. Operation tokens can also be user-defined actions: repository-local prompt actions (agent runs driven by a template file) or repository-local script actions (shell or batch scripts). All tokens are resolved and expanded into a flat list of runnable steps before any step runs. Bus-dev then normalizes: repeated base-operation tokens (e.g. commit commit commit) are merged to one run of that step; steps that come from pipeline expansion are not merged across pipeline invocations (so iterate iterate iterate runs three times), but within each pipeline expansion repeated steps (e.g. commit commit) are reduced to a single step for that run. Execution uses that normalized final sequence with stop-on-first-failure, exactly as if you had typed the normalized steps yourself. Use bus dev pipeline preview TOKEN... to print the normalized final sequence without executing it.
Built-in pipelines are defined in the bus-dev binary and versioned with it. You can use them without any configuration.
| Pipeline | Expands to |
|---|---|
| snapshot | stage commit |
| refresh | spec plan stage commit |
| round | work e2e stage commit |
| cycle | spec plan work e2e stage commit |
| iterate | cycle then refresh → spec plan work e2e stage commit, then spec plan stage commit |
Example: bus dev round runs work, then e2e, then stage, then commit in one invocation. bus dev iterate expands to cycle then refresh; within that expansion repeated steps (e.g. commit appearing twice) are merged so the runnable sequence is spec, plan, work, e2e, stage, commit. bus dev commit commit commit normalizes to one commit step. bus dev iterate iterate iterate runs that normalized iterate sequence three times (no merge across the three pipeline invocations); within each of the three runs, repeated steps such as commit commit are still reduced to a single commit.
Token resolution and @. A token that starts with @ (e.g. @round, @plan) always means “built-in only”: it resolves to the built-in operation or built-in pipeline of that name and never to a repository-local or preference-defined item. If you define a user-defined pipeline with the same name as a built-in (e.g. you override round), the unqualified name uses your definition. To run the built-in pipeline in that case, prefix the name with @: for example bus dev @round always runs the built-in round (work e2e stage commit). For a token without @, resolution order is: repository-local prompt (.txt), then repository-local script (.sh, .bat, or .ps1; on Windows .ps1 is used if present, else .bat), then repository-local pipeline (.yml), then preference pipeline, then built-in operation, then built-in pipeline. The same name in more than one of those (e.g. both .txt and .yml) yields exit 2; having .sh, .bat, and/or .ps1 for the same name is allowed (one script action, platform-specific variants). Per-step runtime/model selectors use the same naming model: token matches both built-in and user-defined steps named token, while @token matches built-in steps only.
Repository-local extensions live under .bus/dev/ at the repository root. You can define and remove them with bus dev pipeline, bus dev action, and bus dev script (see those commands above). Discovery is limited to that directory and to the repository; paths must stay inside the repo (symlinks that point outside the repo are refused). Three kinds of definitions are supported. (1) Prompt action: a file .bus/dev/<name>.txt is a UTF-8 prompt template using the same `` placeholders as built-in prompts. When you invoke the token <name>, the tool loads that file, substitutes the prompt-variable catalog (same variables as for built-in prompts; see the module SDD for the full list), and invokes the agent with the rendered text. Missing or unresolved placeholders cause the command to fail (exit 2) before any agent run. (2) Pipeline: a file .bus/dev/<name>.yml must be a YAML sequence of strings only (a list of scalar strings). Each string is a token resolved with the same rules as command-line tokens; pipelines can reference other pipelines and actions. Invalid YAML (e.g. mappings or non-string scalars) causes exit 2. Cycles and expansion limits are detected and reported with a clear diagnostic. (3) Script action: .bus/dev/<name>.sh (non-Windows) or .bus/dev/<name>.bat or .bus/dev/<name>.ps1 (Windows) runs as a script when you invoke the token <name>. On non-Windows the .sh file must have at least one execute bit set; on Windows, .bat must be tracked by Git with executable mode 100755, and .ps1 is enabled when the file exists and is readable. When both .bat and .ps1 exist for the same name, the tool uses .ps1. The tool runs .sh via exec (shebang respected) or a fixed shell; .bat via cmd.exe /C; .ps1 via PowerShell (e.g. powershell.exe -NoProfile -ExecutionPolicy Bypass -File <path>). Scripts run with the repository root as the working directory and receive the full prompt-variable catalog as environment variables (e.g. DOCS_BASE_URL, MAIN_SDD_URL, MODULE_NAME, MODULE_SDD_URL, MODULE_DOCS_URL, E2E_SCRIPT, E2E_SCRIPT_PATH, PLAN_FILE, PLAN_FILE_PATH); these override any existing environment variables of the same name. Use bus dev context to print the exact KEY=VALUE set your scripts will see. .sh, .bat, and .ps1 can exist for the same name (platform variants); the tool uses the platform-appropriate one and that is not considered an ambiguity.
Quick start for .bus/dev/. In your repository root, keep reusable items in .bus/dev/:
.bus/dev/
review-pr.txt
check-local.sh
release-ready.yml
Create and use them:
cat <<'EOF' | bus dev action set review-pr
Review local changes and list commit risks.
EOF
cat <<'EOF' | bus dev script set check-local --platform=unix
#!/usr/bin/env sh
set -eu
make check
EOF
bus dev pipeline set repo release-ready plan work e2e check-local stage commit
bus dev list
bus dev pipeline preview release-ready
bus dev release-ready
If you add a full busfile at .bus/dev/<name>.bus, you can run it as bus dev <name> without the extension.
Use bus dev context to inspect the prompt/script variables that .txt and script actions receive.
After init. When you use init, only operations from the set plan, spec, work, and e2e may follow. Pipeline and action tokens are allowed after init only if their expansion contains just those four base operations. If you use a pipeline or action that expands to stage, commit, triage, or any user-defined action after init (for example bus dev init round), the command fails with invalid usage (exit 2) before running any step.
Preference-based user-defined pipelines are stored in bus-preferences under keys bus-dev.pipeline.<name>. The value is a JSON array of strings; each string is either a base operation name, another pipeline name, or an @-prefixed built-in (e.g. "@plan", "@round"). The name <name> must start with a letter and contain only lowercase ASCII letters (a–z), digits, hyphens, and underscores (e.g. my-workflow, quick_refresh). You cannot use a name that matches a base operation (plan, spec, work, e2e, triage, stage, commit); those are reserved. Define or remove pipelines with bus dev pipeline set prefs NAME TOKEN... and bus dev pipeline unset prefs NAME (bus-dev uses the bus-preferences library directly; no shell-out to bus preferences). You can also set a preference pipeline with bus preferences set bus-dev.pipeline.<name> '<json array>' (e.g. bus preferences set bus-dev.pipeline.quick-refresh '["spec","plan","stage","commit"]'). List all pipelines (repo, prefs, and built-in) with bus dev pipeline list [all|repo|prefs|builtin]. When defining a pipeline (repo or prefs), the tool refuses the write with exit 2 if another definition already exists for that name (e.g. an action .txt, a script .sh/.bat/.ps1, or the other pipeline scope); the diagnostic identifies the conflicting path(s) or key(s). Bus-dev reads pipeline definitions via the bus-preferences library when resolving tokens. Invalid JSON, a non-array value, an invalid name, or an invalid token in the array causes the command to fail with exit 2 before any agent or git step. If a pipeline references another pipeline (including itself indirectly), cycles are detected and reported with exit 2 and a diagnostic that includes the cycle path; expansion depth and token limits also apply to avoid pathological configs. See the module SDD for the full token-resolution rules, @ semantics, and validation requirements.
Global flags
These flags apply to all subcommands. The common subset matches the standard global flags; bus dev adds --agent for runtime selection. They can appear in any order before the subcommand. A lone -- ends flag parsing; any following tokens are passed to the subcommand.
-h and --help print help to stdout and exit 0. Help describes built-in operations and pipelines and points to bus dev list, bus dev pipeline list, bus dev action list, and bus dev script list for repository-local discovery. -V and --version print tool name and version and exit 0.
--check validates workflow-token expansion and script-runnability without executing steps. This works with normal workflow-token runs and with each.
-v and --verbose increase diagnostics on stderr and can be repeated, for example -vv. -q and --quiet suppress normal output and keep only errors. Quiet and verbose cannot be combined; that is usage error exit 2.
-C <dir> and --chdir <dir> set the effective working directory used for repository resolution and path handling. -o <file> and --output <file> redirect normal output to a file; diagnostics still go to stderr. If output and quiet are both set, quiet wins and nothing is written.
--color <auto|always|never> controls colored stderr output. --no-color is the same as --color=never. --agent <runtime> selects runtime for this invocation only; valid values are cursor, codex, codex:local, gemini, and claude, and invalid values return usage error exit 2.
Command results are written to stdout when a subcommand produces them. Diagnostics, progress, and human-readable agent output are written to stderr.
Agent runtime selection
Subcommands that invoke an external agent (plan, work, spec, e2e, and triage, including when plan/spec/work/e2e are requested after init) use the bus-agent library and one of its supported runtimes: Cursor CLI, Codex, Gemini CLI, and Claude CLI. The runtime token codex:local selects Codex in local mode (--oss). At the start of each such step, the tool prints to stderr which internal agent and which model are in use so that logs and scripts can see the active runtime and model.
The active runtime is chosen in this order: (1) --agent <runtime> for that invocation; (2) BUS_DEV_AGENT (bus-dev-only session default; when set, used for every bus dev command in that session until unset or overridden); (3) BUS_AGENT (shared session default, used when BUS_DEV_AGENT is not set); (4) bus-dev persistent preference (e.g. bus-dev.agent via bus-preferences, affects only bus-dev); (5) bus-agent persistent preference (bus-agent.runtime); (6) first available runtime in the effective order (alphabetic by runtime ID by default). Set bus-dev’s default with bus preferences set bus-dev.agent <runtime> and the shared default with bus preferences set bus-agent.runtime <runtime>. At any step, if the configured runtime is disabled by user configuration, the tool prints a warning to stderr and continues with the next source. You can configure agent order and enable/disable; see the bus-agent SDD and bus-agent module docs.
Invalid runtime names (e.g. --agent unknown or an invalid value in BUS_DEV_AGENT or BUS_AGENT) produce a clear usage error and exit 2. If the user has selected an agent (via flag or BUS_DEV_AGENT) and that agent’s CLI is not installed or not in PATH, the tool reports that on stderr, directs you to the canonical installation URL for that runtime, and exits with code 1. When no runtime is selected and no agent is available (none in PATH or all disabled/restricted), the tool exits with a clear diagnostic and directs you to install or enable at least one supported agent, with pointers to the canonical installation URLs for each runtime. Model, output format, and timeout follow the same resolution logic as agent (see Preference settings below): bus-dev session env (BUS_DEV_MODEL, BUS_DEV_TIMEOUT, BUS_DEV_OUTPUT_FORMAT), then bus-dev persistent preferences (bus-dev.model, bus-dev.timeout, bus-dev.output_format), then bus-agent preferences as fallback, then bus-agent defaults (e.g. model auto, output format text).
Preference settings (bus-preferences)
Preferences that affect bus dev are stored via the bus-preferences Go library. Bus-dev only ever writes to the bus-dev namespace. When you run bus dev set agent, bus dev set model, bus dev set model-reasoning-effort, bus dev set model-verbosity, bus dev set output-format, bus dev set timeout, bus dev set agent-for, bus dev set model-for, bus dev set model-reasoning-effort-for, bus dev set model-verbosity-for, bus dev set model-reasoning-effort-for-model, bus dev set model-verbosity-for-model, bus dev set env-for, bus dev set allow-dirs-for, or bus dev set allow-dirs-for-module, the tool writes only the corresponding bus-dev.* key and never modifies bus-agent.* or any other namespace. When bus-dev invokes the agent (plan, work, spec, e2e, triage), it resolves each option in the same order: per-command override (e.g. --agent) if present, then bus-dev session environment (BUS_DEV_AGENT, BUS_DEV_MODEL, BUS_DEV_TIMEOUT, BUS_DEV_OUTPUT_FORMAT, BUS_DEV_MODEL_REASONING_EFFORT, BUS_DEV_MODEL_VERBOSITY), then per-step selectors (@token then token for built-in steps, token only for user-defined steps), then per-model selectors (bus-dev.model_reasoning_effort_for_model.<model>, bus-dev.model_verbosity_for_model.<model> using the resolved model), then bus-dev persistent defaults (bus-dev.agent, bus-dev.model, bus-dev.model_reasoning_effort, bus-dev.model_verbosity, bus-dev.timeout, bus-dev.output_format), then bus-agent persistent preferences as fallback (bus-agent.runtime, bus-agent.model, bus-agent.model_reasoning_effort, bus-agent.model_verbosity, bus-agent.output_format, bus-agent.timeout), then bus-agent defaults. Environment overrides use bus-dev.env_for.* and apply to every runtime. Directory allow-list overrides use bus-dev.allowed_dirs_for.* (global per-step) plus bus-dev.allowed_dirs_for_module.<module>.* (module-scoped); for built-in steps selector precedence is @token then token, and for user-defined steps selector precedence is token only. At runtime, bus-dev resolves these directories relative to the repository root and passes them through only for runtimes that support explicit allowed directories (currently Codex via --add-dir); unsupported runtimes continue with a warning and ignore directory overrides. Set any bus-dev default with bus dev set <key> <value> (e.g. bus dev set agent gemini, bus dev set model auto, bus dev set model-reasoning-effort medium, bus dev set model-verbosity low, bus dev set output-format text, bus dev set timeout 60m, bus dev set agent-for commit codex, bus dev set model-for @commit gpt-5-codex, bus dev set model-reasoning-effort-for-model gpt-5-codex high, bus dev set allow-dirs-for-module bus optimize ../docs) or with bus preferences set bus-dev.<key> <value>. Inspect with bus preferences get <key>. The bus-dev CLI uses the bus-preferences library directly and does not shell out to bus preferences.
| Key | Description |
|---|---|
bus-dev.agent |
Bus-dev default agent runtime. Valid values: cursor, codex, gemini, claude. Resolution order: --agent → BUS_DEV_AGENT → BUS_AGENT → bus-dev.agent → bus-agent.runtime → first available. Set with bus dev set agent <runtime>. For the shared default when not using bus-dev, set bus-agent.runtime via bus agent set runtime <runtime>. |
bus-dev.model |
Bus-dev default model (e.g. for Cursor). Resolution order: per-command override (if any) → BUS_DEV_MODEL → bus-dev.model → bus-agent.model → bus-agent default (auto). Set with bus dev set model <value>. |
bus-dev.model_reasoning_effort |
Bus-dev default model reasoning effort (Codex values: minimal, low, medium, high, xhigh). Resolution order: BUS_DEV_MODEL_REASONING_EFFORT → bus-dev.model_reasoning_effort → BUS_AGENT_MODEL_REASONING_EFFORT → bus-agent.model_reasoning_effort. Set with bus dev set model-reasoning-effort <value>. |
bus-dev.model_verbosity |
Bus-dev default model verbosity (Codex values: low, medium, high). Resolution order: BUS_DEV_MODEL_VERBOSITY → bus-dev.model_verbosity → BUS_AGENT_MODEL_VERBOSITY → bus-agent.model_verbosity. Set with bus dev set model-verbosity <value>. |
bus-dev.output_format |
Bus-dev default output format. Valid values: ndjson (raw structured output), text (human-readable). Resolution order: per-command override (if any) → BUS_DEV_OUTPUT_FORMAT → bus-dev.output_format → bus-agent.output_format → bus-agent default (text). Set with bus dev set output-format <ndjson|text>. |
bus-dev.timeout |
Bus-dev default run timeout as a duration string (e.g. 60m). Resolution order: per-command override (if any) → BUS_DEV_TIMEOUT → bus-dev.timeout → bus-agent.timeout → bus-agent default. Set with bus dev set timeout <duration>. |
bus-dev.agent_for.<selector> |
Bus-dev per-step runtime default. <selector> is encoded from token or @token (@token means built-in-only selector). Selector resolution: built-in step uses @token first, then token; user-defined step uses token only. Runtime values are cursor, codex, codex:local, gemini, claude. Set with bus dev set agent-for <token|@token> <runtime>. |
bus-dev.model_for.<selector> |
Bus-dev per-step model default. Same selector semantics as agent_for: built-in step uses @token first, then token; user-defined step uses token only. Set with bus dev set model-for <token|@token> <value>. |
bus-dev.model_reasoning_effort_for.<selector> |
Bus-dev per-step model reasoning effort. Same selector semantics as agent_for. Set with bus dev set model-reasoning-effort-for <token|@token> <value>. |
bus-dev.model_verbosity_for.<selector> |
Bus-dev per-step model verbosity. Same selector semantics as agent_for. Set with bus dev set model-verbosity-for <token|@token> <value>. |
bus-dev.model_reasoning_effort_for_model.<model> |
Bus-dev per-model reasoning effort override. Applied when resolved model equals <model>. Set with bus dev set model-reasoning-effort-for-model <model> <value>. |
bus-dev.model_verbosity_for_model.<model> |
Bus-dev per-model verbosity override. Applied when resolved model equals <model>. Set with bus dev set model-verbosity-for-model <model> <value>. |
bus-dev.env_for.<selector>.<env_name> |
Bus-dev per-step environment override. Selector semantics match agent_for (@token first then token for built-in steps, token only for user-defined). Set with bus dev set env-for <token|@token> <ENV_NAME> <value>. |
bus-dev.allowed_dirs_for.<selector> |
Bus-dev per-step allowed directories. Selector semantics match agent_for (@token first then token for built-in steps, token only for user-defined). Values are JSON arrays of directory strings. Set with bus dev set allow-dirs-for <token|@token> <dir...>. |
bus-dev.allowed_dirs_for_module.<module>.<selector> |
Bus-dev per-module per-step allowed directories. Applied only when repository module name equals <module> and layered after bus-dev.allowed_dirs_for.* for matching selector. Set with bus dev set allow-dirs-for-module <module> <token|@token> <dir...>. |
bus-dev.pipeline.<name> |
User-defined pipeline: a JSON array of tokens (base operation names, pipeline names, or @-prefixed built-ins). <name> must start with a letter and use only lowercase ASCII letters, digits, hyphens, and underscores; it must not match a base operation name. Set with bus dev pipeline set prefs <name> TOKEN... or bus preferences set bus-dev.pipeline.<name> '<json array>'. Unset with bus dev pipeline unset prefs <name>. See Pipelines and repository-local extensions above. |
Example: building a module from scratch with AI
BusDK specifications are openly readable. You can have an AI-assisted workflow build a bus module from scratch, then optionally initialize Git and commit. Prerequisites: install one of the supported agent runtimes (Cursor CLI, Codex, Gemini CLI, or Claude CLI), BusDK (at least v0.0.15), and Go.
Option: initialize only, then run workflows explicitly. From the module root you want to initialize, run bus dev init [--lang go]. Or from a parent directory, run bus dev init bus-accounts [--lang go]. The tool initializes a root AGENTS.md and a root Makefile (from a built-in sample when missing). It does not run any Git commands and does not run spec, work, or e2e unless you ask for them. After initialization, run bus dev plan to refresh PLAN.md, then run bus dev spec work e2e in that module directory when you want the AI workflow sequence.
Option: initialize and run ordered workflows in one command. If you want initialization plus workflow operations in one invocation, append the operations after init. bus dev init spec work e2e initializes the current directory and runs the three operations in that exact order. bus dev init bus-accounts spec work e2e does the same in bus-accounts. If one operation fails, later operations are not run.
Option: manual steps. If you prefer to create everything yourself, create the module directory and a root Makefile (and optionally a root AGENTS.md if you want a starting point), then run bus dev spec work e2e (or the three operations in separate invocations), then initialize Git and commit as desired. You do not need to create AGENTS.md first: bus dev spec creates it from the online SDD and module end-user documentation when it is missing. The --lang flag on init (default go) controls which default AGENTS.md content is installed when you use init instead of creating files manually.
Option: full cycle in one invocation. To run a complete sequence without leaving the tool, combine operations: bus dev plan work stage commit or use built-in pipelines such as round (bus dev round) and cycle (bus dev cycle). Repeated base-operation tokens (for example bus dev commit commit commit) are normalized to one run of that step; repeated pipeline tokens (for example bus dev iterate iterate iterate) run that pipeline’s full sequence once per token, with no merge across invocations. Each stage invocation first checks whether anything is stageable; if not, it exits 0 without agent execution; otherwise it invokes the agent to clean the working tree (update .gitignore or remove unintended files), then stages the remaining changes so the following commit has only intended content.
Option: refresh development-state docs. To keep the development-status page and each module’s “Development state” section accurate and evidence-based, run bus dev triage from the docs repo, the BusDK super-project, or a single module repo (the tool detects the context). You can chain it with other workflows, for example bus dev triage plan work to update docs then plan and work in a module.
Because the specs are public and machine-readable, this flow lets you regenerate or rewrite any bus module from scratch with AI, without depending on pre-packaged source. If you prefer not to build from specs yourself, we offer tested and verified bus module source code for a fee. We also offer compiled binaries for free.
Examples
bus dev list
bus dev --check plan work stage commit
bus dev -C ./bus-books --agent codex plan work stage commit
bus dev -C ./bus-books stage commit
bus dev -C ./bus-books set model gpt-5-codex
bus dev -C ./bus-books set timeout 45m
bus dev pipeline set repo release-ready plan work e2e stage commit
bus dev action set release-note < .bus/dev/release-note.txt
bus dev script set verify-local --platform=unix < .bus/dev/verify-local.sh
bus dev pipeline preview release-ready
bus dev release-ready
bus dev each context
bus dev each --check retry -f fix-tests,fix-tests-2 --attempts 1 test test_2
bus dev retry -f fix-tests,fix-tests-2 --attempts 1 test test_2
bus dev retry --on-fail @commit test_2
bus dev each --check stage commit
bus dev each --check --skip bus-docs pipeline preview cycle
bus dev each --check --skip bus-docs,bus-legacy plan work stage commit
bus dev each --skip bus-docs context
bus dev -C .. each --skip bus-docs,bus-legacy stage commit
bus dev each --check --skip bus-docs stage commit
bus dev each --skip bus-docs,bus-legacy stage commit
bus dev each --skip bus-docs --skip bus-legacy stage commit
Files
bus dev does not read or write workspace accounting datasets (CSV, schemas, datapackage.json). It operates on the Git repository (metadata and index) and, when running the agent, on the repository working tree (source files, repository-root AGENTS.md as the canonical project instruction source). To ensure only one run per directory at a time, the tool uses a lock file (e.g. .bus-dev.lock) in the effective operation directory; the lock is released when the command exits. The documentation base URL used in prompts and diagnostics is configurable via BUS_DEV_DOCS_BASE_URL (default https://docs.busdk.com). bus dev spec creates or updates repository-root AGENTS.md, creating it from the online SDD and module end-user documentation when missing so the result is a compact local implementation spec; if a Cursor rule file exists at .cursor/rules/<module-name>.mdc (module name = base name of the repo), its content is merged into AGENTS.md and that file is then removed — this is the only case where bus-dev may remove or replace existing repo content for instruction standardization. The tool also uses repository-root PLAN.md for planning continuity: bus dev work checks off completed plan items, bus dev e2e validates that checked items are fully covered by e2e tests and still searches docs for other missing tests, and neither work nor e2e removes checked items. bus dev plan is the command that re-validates the plan and prunes completed checked items while adding newly detected missing work. When Gemini CLI is selected, the tool uses only repository-local Gemini files (e.g. repo-root GEMINI.md, .gemini/settings.json, .geminiignore) and never modifies user-global Gemini configuration or memory. How each runtime (Codex, Cursor, Gemini CLI, Claude Code) loads AGENTS.md is defined by the shared instruction contract in the bus-agent SDD. No bus-dev-specific config file is required; configuration is via flags and environment only. User-defined pipelines are read from bus-preferences (keys bus-dev.pipeline.<name>) when resolving operation tokens; see Pipelines and repository-local extensions. Repository-local extensions (prompt actions, script actions, and pipelines) live under .bus/dev/ at the repository root; see that section for the three supported file types (.txt, .yml, .sh / .bat) and for bus dev context, which prints the prompt-variable catalog for authors.
Exit status and errors
Exit code 0 means success. For bus dev commit, “nothing to commit” is still success.
Exit code 1 means execution failed. Common causes are Git or hook failure, agent failure or timeout, missing or non-executable selected runtime, no available enabled runtime for automatic selection, lock-acquisition failure, non-runnable script detected by each preflight, failure to set execute bit for generated .sh, or failure to create/write repository-local files under .bus/dev/.
Exit code 2 means invalid usage. Common causes are unknown subcommands or tokens, unknown @ names, invalid flags or runtime names, missing required repo context, invalid init target, invalid or recursive pipelines, expansion-limit failures, invalid post-init token expansion, repository-local name ambiguity across .txt/.yml/preference/script definitions, disabled or invalid script action invocation, path or YAML validation failures, invalid each usage, invalid or reserved names, conflicting definitions, or empty stdin for action set.
Deterministic results (e.g. list, pipeline list, action list, script list, context) are written to stdout. Diagnostics and errors are written to stderr.
Error messages are always on stderr. If you are not in a Git repository when a subcommand requires one, the tool exits with code 2 and a clear message. If the selected agent runtime is missing or cannot be executed, or if no agent is enabled when the automatic default would apply, the tool exits with code 1 and directs you to the canonical installation URLs for the supported runtimes. If the working-directory lock cannot be acquired (e.g. the directory is not writable or the lock file cannot be created), the tool exits with code 1 and reports that the lock could not be acquired; check directory permissions or whether another bus dev process is running in that directory.
Using from .bus files
Inside a .bus file, write this module target without the bus prefix.
# same as: bus dev --help
dev --help
# same as: bus dev -V
dev -V
# run staged commit flow in one module
dev -C ./bus-books stage commit
# validate then run a full cycle in one command
dev -C ./bus-books --check plan work stage commit
dev -C ./bus-books plan work stage commit
dev -C ./bus-books retry --on-fail fix-tests,fix-tests-2 --attempts 1 test test_2
# use repo-local definitions under .bus/dev/
dev -C ./bus-books list
dev -C ./bus-books context
dev -C ./bus-books pipeline set repo nightly plan e2e triage stage commit
dev -C ./bus-books pipeline preview nightly
dev -C ./bus-books nightly
# run stage+commit in each module except selected ones (superproject)
dev each --skip bus-docs,bus-legacy stage commit
# validate each child module can resolve and run a full cycle without executing it
dev each --check --skip bus-docs,bus-legacy plan work stage commit
# run from a different directory by setting the superproject root explicitly
dev -C .. each --skip bus-docs context
Development state
Value promise: Single entry point for scaffolding and running standardized developer workflows (init, plan, spec, work, e2e, triage, stage, commit, set, context, pipeline list/preview) in BusDK module repos so contributors get a consistent Makefile, AGENTS.md, and prompts.
Use cases: Developer module workflow with Cursor CLI, Developer module workflow with Gemini CLI, Developer module workflow with Claude CLI, Developer module workflow with Codex CLI.
Completeness: 60% — Init, set, flags, lock, context, pipeline list/preview, and post-init restrictions verified by e2e; plan/work/spec/e2e/stage/commit and pipeline expansion verified by unit tests with stub agent; only Cursor path e2e-covered, other runtimes unverified.
Use case readiness: Developer module workflow with Cursor CLI: 60% — user can init module root, set agent/run-config, use flags and context, list builtin pipelines, preview normalized steps; plan/work/spec/e2e/stage/commit unit-tested with stub and repo-local pipeline override. Developer module workflow with Gemini CLI: 30% — same CLI; run/work/spec/e2e with Gemini not test-covered. Developer module workflow with Claude CLI: 30% — same CLI; run/work/spec/e2e with Claude not test-covered. Developer module workflow with Codex CLI: 30% — same CLI; run/work/spec/e2e with Codex not test-covered.
Current: tests/e2e.sh verifies help, version, subcommand help, -- terminator, invalid quiet+verbose and --color/--agent, -C missing/non-repo, per-directory lock (init into read-only dir → exit 1), init creating AGENTS.md, Makefile, .cursor/rules, e2e script name in Makefile, post-init-only plan/spec/work/e2e (triage/stage/commit/round → exit 2), context KEY=VALUE and --output, quiet wins over --output, set invalid key/agent/output-format, action/script generate invalid usage, pipeline list builtin, pipeline preview (commit×3→one; iterate→six steps), pipeline set repo YAML and unset, script list unix(disabled). run/run_test.go verifies plan, work, spec, e2e, stage, commit with stub agent; commit depth-first submodule and unstaged gitlink; pipeline round/iterate and duplicate-step merge; repo-local override; triage context; set persist; pipeline preview. internal/extensions/extensions_test.go, internal/init/scaffold_test.go, internal/set/set_test.go, internal/cli/flags_test.go, internal/repo/resolve_test.go, internal/lock/lock_test.go, internal/prompts/prompts_test.go add coverage.
Planned next: Top-level bus dev list (every runnable token with expansion) per PLAN.md; advances discoverability for all four developer workflow use cases. Action/script generate to write agent output to .bus/dev/ once bus-agent exposes stdout API.
Blockers: None known.
Depends on: None.
Used by: Developers in module repositories; no other Bus module invokes it.
See Development status.