A terminal UI for running multiple autonomous coding agents in parallel. Give it a prompt, it spins up a git worktree and a opencode agent to work on it, while you keep dispatching more tasks.
For an overview of the workflow -- how to think about using faber from idea to finished code -- see WORKFLOW.md.
Each task gets its own git worktree at .worktrees/<task-slug>. An opencode agent runs inside that worktree, so tasks are fully isolated from each other and from your working directory. State is persisted to .faber/state.json, so you can close and reopen faber without losing track of what's running.
- Bun
- opencode on your
PATH, connected to Claude via a Pro/Max subscription or an Anthropic API key - A git repository to work in
curl -fsSL https://raw.githubusercontent.com/blaknite/faber/main/install.sh | bashThis downloads the latest release binary for your OS and architecture, installs it to ~/.faber/bin, and adds it to your PATH.
Building from source
bun install
bun run build:bin # produces a ./faber binaryOr run directly from source:
bun run devfaber updateChecks for a newer release on GitHub and replaces the running binary in-place if one is available. Supports macOS (arm64/x64) and Linux (arm64/x64).
Faber automatically injects the working-in-faber skill into every agent prompt. The skill tells the agent about its environment (git worktrees, branch isolation, sibling agents) and sets expectations around committing in logical units, writing meaningful commit messages, and not pushing.
For this to work, the skill needs to be available in your agent's environment.
faber # open the TUI in the current directory
faber start # same as above, explicit subcommand
faber --dir /path/to/repo # open the TUI in a specific directoryInitialise a repo for use with faber (creates .faber/, .worktrees/, and updates .gitignore):
faber setup
faber setup --dir /path/to/repoFire off a task without opening the TUI:
faber run "fix the login bug"
faber run "fix the login bug" --dir /path/to/repo
faber run "add tests for UserService" --model fast
faber run "add rate limiting" --base my-feature-branch--base sets which branch the new worktree is created from and what the agent diffs against. Defaults to the current branch of the main checkout.
Print a table of all tasks with their ID, status, elapsed time, and a truncated prompt:
faber list
faber list --dir /path/to/repo
faber list --status running # filter by status (running, done, failed, etc.)Print a task's prompt and the agent's text output, with tool calls summarised as one-liners:
faber read <taskId>
faber read <taskId> --full # include full tool block content
faber read <taskId> --json # raw LogEntry[] as JSON
faber read <taskId> --dir /path/to/repoAgents can pull context from other tasks by referencing them with @taskId in a prompt. Selecting a task from the autocomplete inserts the task ID (e.g. @a3f2-fix-login-bug) into the prompt as plain text. Faber doesn't do anything special with it beyond that -- the working-in-faber skill, which is injected into every agent prompt, teaches the agent to recognise the @taskId pattern and run faber read <taskId> to pull the output and extract whatever context it needs.
This is useful when one task builds on the work of another -- for example, pointing a "write tests" task at a completed "refactor UserService" task so the agent can see exactly what changed before writing assertions.
Task list
| Key | Action |
|---|---|
n |
New task |
j / k or arrows |
Navigate list |
Tab |
Toggle filter between active and all tasks |
Enter / o |
Open task |
c |
Continue a stopped or failed task |
s |
Kill running task (confirms with y/n) |
x |
Mark task as done |
d |
Delete task and remove its worktree (confirms with y/n) |
b |
Switch branch |
p |
Push branch to origin (confirms with y/n) |
q / Ctrl-C |
Quit |
Log pane (after pressing Enter on a task with no commits)
| Key | Action |
|---|---|
j / k or arrows |
Scroll |
PgUp / PgDn |
Scroll by page |
c |
Continue task |
s |
Kill running task |
x |
Mark task as done |
d |
Delete task and worktree |
f |
Open diff view |
, / . |
Cycle to next / previous active task |
q / Escape |
Back to task list |
Diff view (after pressing Enter on a task with commits, or f from the log)
| Key | Action |
|---|---|
j / k or arrows |
Scroll |
PgUp / PgDn |
Scroll by page |
g / G |
Jump to top / bottom |
Tab |
Toggle between side-by-side and inline layout |
c |
Continue task |
l |
Switch to log view |
m |
Rebase branch onto HEAD and fast-forward merge (confirms with y/n) |
x |
Mark task as done |
d |
Delete task and worktree |
, / . |
Cycle to next / previous active task |
q / Escape |
Back |
New task / continue input
| Key | Action |
|---|---|
Enter |
Submit |
Shift-Enter / Ctrl-Enter / Ctrl-J |
Insert newline |
Tab |
Cycle through models (or select file suggestion if autocomplete is open) |
Escape |
Cancel (or clear text if the field is non-empty) |
When typing @ in a prompt, faber opens an autocomplete showing both files and tasks. Each suggestion is labelled with its type. Selecting a file inserts its path; selecting a task inserts the task ID (e.g. @a3f2-fix-login-bug). Use Up / Down to navigate and Tab or Enter to select. Escape dismisses the list.
| Label | Model |
|---|---|
| smart (default) | anthropic/claude-sonnet-4-6 |
| fast | anthropic/claude-haiku-4-5 |
| deep | anthropic/claude-opus-4-6 |
When an agent finishes with commits on its branch, the task is marked "ready to merge" and the pending count appears in the top bar. The typical flow from there:
- Select the task and press
enter. If the branch has commits, you go straight to the diff view. Otherwise you land on the log, whereftakes you to the diff. - The diff view runs
git diff HEAD...{branch}(three-dot syntax), so you see exactly what the agent changed relative to the point where work began, regardless of anything that landed onHEADin the meantime. - The diff renders with character-level highlighting and two layout modes: side-by-side (default) and inline. Press
Tabto switch between them. - When you're happy with the changes, press
m. You'll get a[y/n]confirmation prompt, then faber rebases the task branch onto the currentHEADand fast-forward merges it in. The result is a linear history with no merge commits. If the rebase hits a conflict, faber automatically aborts and leaves your repo clean. - After merging, the task moves to "done". The worktree and branch are still there so you can review the log or diff again. When you're done with them, press
dto delete the worktree and branch in one go.
Faber works just as well when your repo is on a feature branch. Switch to it using b and agents will branch off that tip, so all their worktrees and merges stay scoped to it.
The typical flow:
- Launch faber in your repo as usual.
- Switch to your feature branch by pressing
bfrom the task list and typing the branch name. - Create tasks as normal. Each agent branches off the feature branch tip, isolated from both
mainand each other. - Review and merge each task into the feature branch the same as any other task: open the task to reach the diff view, then press
m.
When you're happy with the feature branch as a whole, merge it into main yourself outside of faber.
Press b from the task list to open the branch switcher. A modal appears with a list of your repo's branches sorted by most recently committed, task branches excluded.
Start typing to filter the list. The filter is a case-insensitive substring match, so feat matches feature/auth, my-feat, etc. Use Up / Down to move through the results, then Enter to switch.
If you type a name that doesn't match anything, the list shows "no matches -- press enter to create". Pressing Enter at that point creates a new branch off the current HEAD and switches to it.
Each task records its base branch -- the branch that was checked out when it was dispatched, or the value passed to --base when using faber run. The task list is always filtered to only show tasks belonging to the current branch, so switching branches gives you a clean slate for that context.
Tasks created before branch scoping was introduced show up on every branch.
The active/all toggle (Tab) applies on top of that filter, so "active" means "active tasks on this branch".
Faber isn't just for one-off fixes. You can give an agent the role of orchestrator -- something with full context on a goal that breaks it down, dispatches sub-tasks in parallel, reviews the results, and keeps going until the whole thing is done.
This pattern works particularly well for implementing a product spec: the orchestrator reads the spec, identifies the independent pieces of work, dispatches them all at once, then routes each result as it finishes.
Say you have a spec for a new metrics export feature. Rather than tackling it yourself, you could dispatch a single orchestrating task:
faber run "Implement the metrics export feature described below.
Break the work into independent sub-tasks and dispatch each one using faber run. Run parallel tasks in parallel -- don't wait for one to finish before starting another. Watch each task with faber watch, review the diff, then merge, continue, or discard based on what the agent produced. Repeat until everything from the spec is merged and nothing is outstanding.
Spec:
- Users can export their usage metrics from the settings page
- Supported formats: CSV and JSON
- Export is scoped to a date range (last 7 days, last 30 days, or custom)
- Exports are generated server-side and streamed as a file download
- The endpoint requires authentication; unauthenticated requests return 401"The orchestrating agent takes it from there: it decomposes the spec, runs agents for the data model, the export endpoint, the frontend UI, and the tests -- each in its own isolated worktree -- then drives each one through review and merge.
An orchestrator is just an agent with a well-scoped prompt that instructs it to use faber's CLI to coordinate other agents. It uses the same faber run / faber watch / faber diff / faber merge commands you'd use manually, but it handles the loop automatically.
The key thing to include in an orchestrating prompt is the full goal or spec, with enough detail that sub-task agents can work independently.
Orchestrators use --base $(git branch --show-current) when dispatching sub-tasks, so each child worktree branches from the orchestrator's own branch. This means all sub-task diffs are relative to a common point, and the sub-tasks show up together in the TUI when you switch to the orchestrator's branch.
The orchestration pattern works because of three agent skills faber injects into prompts:
working-in-faber-- covers git worktree isolation, branch conventions, and commit expectations. This is what makes each sub-task agent aware of its environment.orchestrating-faber-tasks-- teaches an agent how to decompose a goal, dispatch sub-tasks in parallel, and drive the whole thing through to completion.reviewing-faber-tasks-- teaches an agent how to inspect a diff and decide whether to merge, continue, or discard. The orchestrator uses this when assessing each sub-task's output.
These skills need to be available in your agent's environment before faber can inject them. See Getting the best results.
bun run dev # run from source
bun run build # compile to dist/
bun run build:bin # compile to a standalone binary