Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Quick start

This walkthrough takes about ten minutes. It runs one small task on an existing repository, from vibe init to a merged branch. It assumes vibe is installed (Installation) and uses a small Rust command-line project as the example; any language works the same way.

1. Choose a model

With an Anthropic key:

export ANTHROPIC_API_KEY=sk-ant-…

Or, with no key at all, a local model through Ollama:

ollama pull qwen2.5-coder

You will point the project at Ollama in step 2. To try the pipeline without any model, jump to Try it with no API key.

2. Initialise the project

cd ~/src/export-tool
git status                  # a clean git repository is the easiest start
vibe init

vibe init writes .vibe/config.toml with every key at its default value and a commented [[plugins]] example, and adds worktrees/ and tool-output/ to .vibe/.gitignore (tasks/ stays committed on purpose). Inspect the effective configuration:

vibe config show
default_provider = "anthropic"
default_model = "anthropic/claude-sonnet-5"
plugins = []

[phases]

[providers.anthropic]
kind = "anthropic"
api_key_env = "ANTHROPIC_API_KEY"

[providers.ollama]
kind = "openai"
base_url = "http://localhost:11434/v1"
default_model = "qwen2.5-coder"

[providers.openai]
kind = "openai"
api_key_env = "OPENAI_API_KEY"

[pipeline]
max_qa_rounds = 3
max_subtask_attempts = 3
max_parallel_subtasks = 3
max_phase_retries = 2
workspace = "git_worktree"
auto_merge = false
merge_strategy = "manual"

[security]
blocked_commands = []
allowed_commands = []
command_timeout_secs = 120
allow_network = false
extra_read_paths = []

Every phase uses default_model; [phases] is empty until you give a phase its own model.

With Ollama, switch the default model:

vibe config set default_model ollama/qwen2.5-coder

Then check everything is in place:

vibe doctor

Every key is explained in Configuration.

3. Add a task

vibe task add "Add a --json flag to the export command" \
  -d "When --json is given, print the exported records as a JSON array on stdout instead of the table. Keep the table as the default. Add a test."
✓ created task #1 Add a --json flag to the export command
  id   6f1c3e0a-9b2d-4c47-8a51-0e3b8f2d7c19
  dir  /home/me/src/export-tool/.vibe/tasks/001-add-a-json-flag-to-the-export-command

Run it with: vibe run 1

The task is stored in .vibe/tasks/001-add-a-json-flag-to-the-export-command/task.json, in the backlog status. vibe task list shows it.

4. Plan without building

A dry run stops after planning, so you can read what the agents intend before they touch any code:

vibe run 1 --dry-run

It runs three phases:

PhaseAgent(s)Produces
assesscomplexity_assessor (unless the heuristic already knows)the complexity and profile, in task.json and run.json
specspec_gatherer, then spec_writer for a standard taskspec.json and spec.md: summary, requirements with acceptance criteria, relevant files
planplannerplan.json and plan.md: phases of subtasks with files, dependencies and verification

The files are in the task directory:

cd .vibe/tasks/001-add-a-json-flag-to-the-export-command
cat spec.md plan.md progress.md
cd -

progress.md has one timestamped note per step: the assessment and its source, the spec summary, the plan. The dry run leaves the run paused and the task back in backlog, ready to continue; the exit code is 0 because it stopped where you asked. If the spec or plan misses the point, edit spec.json and run vibe run 1 --from plan --dry-run, or discard the task and add it again with a better description.

5. Run it

vibe run 1 --resume

--resume continues the paused run at the build phase, reusing the spec and plan you just read. (vibe run 1 would start over from the assessment.) The output looks like this:

Resuming #1 Add a --json flag to the export command (model anthropic/claude-sonnet-5, workspace git_worktree)
▶ run 3b1f09c2

── build ──────────
  ▸ subtask 1/3 Add the --json option to the CLI definition: in_progress
  ● coder · subtask 1/3 Add the --json option to the CLI definition
  ⟶ read_file(path: "src/cli.rs")
  ⟵ ok (2 ms)
  ⟶ edit_file(new_string: "    /// Print records as JSON.\n    #[arg(long)]\n    pub json: bool,\n…
  ⟵ ok (4 ms)
  ⟶ bash(command: "cargo build")
  ⟵ ok (8412 ms)
  ● coder finished: 7 step(s), 31.4k in / 1.9k out tokens, completed
  ▸ subtask 1/3 Add the --json option to the CLI definition: done
  ▸ subtask 2/3 Serialise records as JSON in export: in_progress
  ● coder · subtask 2/3 Serialise records as JSON in export
  ⟶ grep(path: "src", pattern: "fn export")
  ⟵ ok (12 ms)
  ⟶ edit_file(new_string: "    if args.json {\n        serde_json::to_writer_pretty(std::io::st…
  ⟵ ok (3 ms)
  ⟶ bash(command: "cargo test export")
  ⟵ error (6120 ms): exit status 101 --- stdout --- running 4 tests test export::tests::json_out…
  ⟶ edit_file(new_string: "#[derive(Serialize)]\npub struct Record {", old_string: "pub stru…
  ⟵ ok (2 ms)
  ⟶ bash(command: "cargo test export")
  ⟵ ok (5810 ms)
  ● coder finished: 12 step(s), 58.0k in / 3.4k out tokens, completed
  ▸ subtask 2/3 Serialise records as JSON in export: done
  ▸ subtask 3/3 Test the --json output: in_progress
  …
  ▸ subtask 3/3 Test the --json output: done
✓ build: 3 done, 0 failed, 0 skipped (4 min 12 s)

── qa ──────────
  ● qa_reviewer
  ⟶ bash(command: "cargo test")
  ⟵ ok (9204 ms)
  ● qa_reviewer finished: 15 step(s), 39.8k in / 1.9k out tokens, completed
✓ qa: round 1: Approved (0 issue(s)) (1 min 03 s)

── merge ──────────
✓ merge: ready for human review and merge (auto_merge is off) (3 ms)
■ run finished: ready

phase  result  time          tokens in  tokens out  summary
build  ✓       4 min 12 s    176.3k     7.9k        3 done, 0 failed, 0 skipped
qa     ✓       1 min 03 s    39.8k      1.9k        round 1: Approved (0 issue(s))
merge  ✓       3 ms          0          0           ready for human review and merge (auto_mer…
status     ready
duration   5 min 16 s
tokens     216.1k in / 9.8k out
branch     vibe/add-a-json-flag-to-the-export-command-6f1c3e0a
worktree   /home/me/src/export-tool/.vibe/worktrees/add-a-json-flag-to-the-export-command-6f1c3e0a
task dir   /home/me/src/export-tool/.vibe/tasks/001-add-a-json-flag-to-the-export-command

Review the work, then merge it: git merge vibe/add-a-json-flag-to-the-export-command-6f1c3e0a

A ── header opens each phase and a ✓ (or ✗) line closes it with its summary and duration. ● lines mark agent sessions, ▸ lines subtask status changes. Each ⟶ line is a tool call with its arguments (cut at 80 characters) and each ⟵ line its result with the time it took. A failed tool call (error) is normal: the agent reads the error and tries again. With -v, the agents’ own text and informational logs are shown too. The final table sums up the phases of this invocation. Ctrl-C cancels; vibe run 1 --resume continues later.

Exit code 0 means the task is ready (or done with auto-merge).

6. Inspect the result

vibe task show 1

This prints the spec summary, the plan with each subtask’s status, the QA verdict, the state of the run and the workspace. The code is on the task branch, in its own worktree:

git log --oneline main..vibe/add-a-json-flag-to-the-export-command-6f1c3e0a
git diff main...vibe/add-a-json-flag-to-the-export-command-6f1c3e0a
cd .vibe/worktrees/add-a-json-flag-to-the-export-command-6f1c3e0a && cargo test && cd -

Each completed subtask was committed as vibe: complete subtask <n> - <title>.

7. Merge

The task is ready: nothing reached your branch yet. Merge it as any branch:

git switch main
git merge vibe/add-a-json-flag-to-the-export-command-6f1c3e0a

The worktree and the branch stay until you discard the task. vibe task discard 1 --yes removes them, together with the task directory and its traced tool outputs, so the task no longer appears in its history: run it once you no longer need to look back at the task (step 8).

To let Vibe Factory merge by itself as soon as QA approves, run with --auto-merge, or set it for the project:

vibe run 2 --auto-merge
vibe config set pipeline.auto_merge true

Auto-merge fast-forwards when it can, otherwise creates a merge commit. It refuses to run while tracked files of your checkout have uncommitted changes, and it leaves the task ready with the list of conflicting files when the branches conflict. Details in Workspaces and merging.

8. See what was done

Everything a run did stays readable after it ended, rebuilt from the task’s events and git:

vibe history                 # every finished task: runs, commits, files, tokens, time, cost
vibe history 1               # one task: its runs, commits, changed files, validations, QA
vibe trace 1                 # every tool call of the last run, with its result
vibe trace 1 --full          # … and the complete output of each call
vibe events --since 1d       # what happened on every task today, in time order
vibe events --follow         # the activity of every task from now on (Ctrl-C to stop)

vibe history shows a cost only once you give model prices in [pricing]. The complete tool outputs vibe trace --full reads are kept under .vibe/tool-output/, ignored by git; see Tool call trace for their disk usage and History for where each figure comes from.

The same views exist outside the command line:

  • vibe tui opens a terminal UI: the task board (T), the activity of every task (A), the history (H), and a Trace tab in the task detail;
  • vibe serve serves a web UI on http://127.0.0.1:7777 (open the link it prints, which carries the access token) with the Tasks, Activity, History and Evaluations views and a Trace tab per task, and the HTTP API they use;
  • the macOS app in apps/macos/VibeFactory opens a project folder and starts vibe serve for it, or connects to one already running.

Try it with no API key

The built-in mock provider answers every agent with canned, valid documents without calling any model. It edits no file, so it is only good for seeing the pipeline move:

vibe task add "Add a --json flag to the export command"
vibe run 1 --provider mock --dry-run
vibe task show 1

This is the CLI’s built-in mock, used whenever no [providers.mock] table is declared. A provider you declare yourself with kind = "mock" only answers plain text, so its structured phases fail. The mock assessor classifies the task as simple, so the spec is written by the gatherer alone, and the planner returns a one-subtask plan. Drop --dry-run to go through build, QA and merge as well.

To control what the “model” says, give a script with --script. A script is a JSON array of answers replayed in order, or an object with answers per agent role:

{
  "routes": {
    "planner": [
      {"json": {"approach": "Two steps.", "phases": [{"name": "Work", "parallel": false,
        "subtasks": [{"title": "Add flag", "description": "Add --json."},
                     {"title": "Test it", "description": "Add a test.", "depends_on": ["Add flag"]}]}]}}
    ],
    "qa_reviewer": [
      {"json": {"verdict": "changes_requested", "summary": "Missing test.",
                "issues": [{"severity": "high", "title": "No test for --json"}]}}
    ]
  },
  "fallback": true
}
vibe run 1 --script demo.json      # implies the mock provider on every phase

Each request takes the next answer routed to its role, else the next entry of steps, else, with fallback true (the default), the canned answer. An answer is a string (plain text), {"text": "…"}, {"json": …} (sent as a fenced JSON document, as structured agents answer), or {"tool": "read_file", "input": {"path": "src/main.rs"}} (a tool call, which really runs). With "fallback": false, an exhausted script fails the request. Roles are recognised from the first line of the agent’s system prompt, so routes work for the built-in prompts; an agent whose prompt you replaced is only served by steps and the fallback. The example above makes QA request changes once, so you can watch the fix loop: the fixer runs, QA reviews again with the canned approval, and the task ends ready.

Next steps