Fir
Fir is Frazer’s version control. It keeps the words every engineer and every model already knows (repository, branch, main, commit, pull request, merge, merge queue) and changes what is underneath: every session works in its own workspace on the server, a pull request keeps one number through every rebase, merges happen on the server, and every step can be undone.
fir is the command line. The commands are shaped like the git and pull request commands you know, every command takes --dry-run where it changes something, and none of them prompts. The full list is in the Fir CLI reference.
Product overview: Fir.
The words Fir uses
Section titled “The words Fir uses”| Word | What it is in Fir |
|---|---|
| Repository | A repository, such as acme/storefront |
| Branch | A named line of commits that pull requests target. Every new repository’s default branch is main. Release branches are release/*. A personal branch looks like lena/retry-errors |
| Commit | A snapshot with a content hash. A commit merged into a protected branch also gets a sequence number: main@48213 |
main@verified |
The newest commit on main that passed verification after merge. Deploys and new work read it |
| Pull request | The unit of review, numbered per repository: #482. It keeps its number through every rebase and update |
| Version | Each push to a pull request makes a new version: v1, v2, v3. Reviews and approvals name the version they were made on |
| Workspace | The working copy of one session, kept on the server, such as ws/s-81f2. A workspace is not a branch: it is a git worktree on the server. fir worktree is another name for fir ws |
| Stack | Pull requests stacked on each other: each targets the one below, and the stack merges as one entry in the merge queue |
| Merge queue | One per protected branch. It tests pull requests on top of the branch and moves the branch once per batch |
| Activity log | Everything that happened in a workspace, a pull request or a branch, in order. Each entry is an operation you can undo |
| Fork | A copy of a repository in your own namespace, made when you open a pull request without write access |
| Merge request, MR | Other names for a pull request |
How work moves
Section titled “How work moves”workspace ws/s-81f2 ──fir pr create──► pull request #482 v1 ──fir pr push──► v2, v3 │ checks, reviews, rules ▼ fir pr merge 482 --auto ──► merge queue on main ──► main@48217 │ verification ▼ main@verified, what deploys read- Work in a workspace. A Frazer session (an agent, a devbox, the Frazer app) starts in its own workspace on the server. Every write is snapshotted, so a sandbox that stops loses at most seconds of work.
- Open a pull request.
fir pr createpublishes the workspace as a pull request. The session gets a head branch of its own, such asagent/s-81f2. - Push new versions.
fir pr pushadds a version to the same pull request. Compare any two versions withfir pr diff 482 --from 2 --to 3; edits that only rebased are hidden. - Merge on the server.
fir pr merge 482 --autowaits for the rules and the checks, then joins the merge queue. Nothing merges on your machine. - Deploy what is verified. After a merge, verification runs on
main;main@verifiedmoves when it passes.
Pull requests at 10,000 to 50,000 a day
Section titled “Pull requests at 10,000 to 50,000 a day”One person can direct 10,000 to 50,000 pull requests a day on Fir, because almost every pull request merges on its own receipt (Auto-merge and the merge queue). The pull request list stops being a review queue and becomes three things: what needs you (short at any volume), what is happening now (stages and rates), and the controls. Top to bottom, a person sees the count line, the Now strip, Needs you with its budget line, the control strip when anything is paused, frozen or throttled, and then the groups by plan level. Each view is a tab and a view in the API, and your last view and density are remembered per list:
| View | What it shows | Density by default |
|---|---|---|
| Now | The pipeline by stage: with agents, checks and the second opinion, the merge queue, merged in the last hour, watched; each stage’s count and its rate an hour against the same hour last week, the groups that hold most of it, and a mark on a stage growing faster than its rate, with the cause (a partition stalled, a provider down, a freeze) | Standard |
| Needs you | The decisions you owe, one row each; exceptions with one cause as one row that says “covers N”; what each blocks; the one action and its key; your budget line; folded below it, Since you last looked as counts | Comfortable |
By node (by-plan stays an alias) |
Program › plan › phase › stack at any depth, at the level that fits the screen; campaign › wave › shard; dependency updates by update group; each line its counts by state and what needs you | Standard |
| Outcomes | Where pull requests ended (merged on their receipt, merged with a person, reverted, closed) by class, agent and policy, with what came after: reverts within 14 days, follow-up fixes within 14 and 90 days, incidents linked | Standard |
| All | One line a pull request: state · repository#number · title · plan and stack · Next · actor · age; more columns from a picker; sorted on the server; virtualized to 100,000 rows; Space peeks |
Compact |
| Needs others | Open exceptions by holder (a person or an OWNERS group): the count, the oldest, what they block, and a holder over budget marked | Standard |
| Flow | The last 24 hours’ arrivals by hour, each split by its pull requests’ state now, so the bars add up to the count line | — |
| Comfortable inbox | The sections a small team works in: Needs you, Your agents, Low risk, Waiting on others, Merging | Comfortable |
A scope with more than 50 open pull requests, or more than 25 new a day for you, opens on Needs you; a smaller one opens on the Comfortable inbox, and your own choice always wins. Rows come in three densities: Comfortable (two lines, 48 px), Standard (one line, 36 px) and Compact (one line, 28 px); ⇧D cycles them.
The count line counts pull requests over the last 24 hours, because agents work around the clock, and it adds up to the total: needs you · needs others · with agents · merged (and how many needed a person) · closed. The Now strip splits what is not merged yet by stage, and it adds up to its count line too. Demo, Tue Nov 17 at 15:00 (product UI, demo data):
| Scope | Count line | Now strip |
|---|---|---|
| lena at Acme, all of lena’s campaigns | 224 need you · 10 need others · 4,766 with agents · 44,000 merged (350 with a person) · 1,000 closed · 50,000 in the last 24 h | being written 3,134 · checks and the second opinion 1,170 · waiting for a person 234 · being repaired 251 · waiting for a lower layer 186 · in the merge queue 25 (17 testing, 8 waiting) · merged in the last hour 2,350 · watched 822 |
| priya at Pellwyn, priya’s plans and campaigns | 45 need you · 8 need others · 1,947 with agents · 17,600 merged (100 with a person) · 400 closed · 20,000 in the last 24 h | being written 1,272 · checks and the second opinion 475 · waiting for a person 53 · being repaired 102 · waiting for a lower layer 76 · in the merge queue 22 · merged in the last hour 2,340 · watched 820 |
| All of Pellwyn, eleven people, as priya sees it | 45 need you · 141 need others · 3,814 with agents · 35,200 merged (400 with a person) · 800 closed · 40,000 in the last 24 h | being written 2,459 · checks and the second opinion 955 · waiting for a person 186 · being repaired 205 · waiting for a lower layer 150 · in the merge queue 45 (31 testing, 14 waiting) · merged in the last hour 4,400 · watched 1,640 |
The count line counts pull requests; Needs you counts rows. lena’s 224 pull requests that need lena sit in 26 rows, most of them failing campaign shards that one daily campaign review covers. “Watched” counts merged layers whose watch (verification and the canary) is still running. Every level adds up to the one above at the same snapshot: Pellwyn’s 4,000 not merged at 15:00 are about 2,600 plan layers in about 720 stacks under about 240 phases of about 200 plans, about 600 campaign shards in their waves, and about 800 dependency updates, exempt classes and repairs; a program’s line (“#120 · 70 not merged · 19 stacks · 6 phases · 1 needs you”) opens to its plans, phases and stacks with nothing lost on the way.
The control strip. When any control is in force over the scope, one line under the count line says which (“Auto-merge on · 2 scopes paused (#640 P3, agent deps) · freeze release/2026.11 until 18:00 · ledger throttled to 600 an hour · error budget: payments 41 % left”); each part opens its control. The receipt in the peek: Space on a merged row shows its merge receipt in seven glyphs with words, and W opens it whole; on an open row it says which condition is still missing and what will satisfy it (“A4: second opinion running, 3 of 4 lanes · A3: 9 of 11 checks”).
An exception is something a person must decide before work can go on; everything else merges on its receipt, waits for an agent, or is closed by policy. Most never reach a person: agents resolve them (the author’s loop, regenerating a conflicted layer on the new base, a fresh start by another family), the intent declared them (the plan’s approval reviewed its predictable protected patches and settled its overlaps), a standing rule covers them (a decided cause never asks again), or a higher approval covers them (a program’s terms). What is left goes to the person or group that owns its decision, and rows with one cause join one row while its decision waits:
| Exception | Decided by default | The one action |
|---|---|---|
| A layer outside its plan’s terms | The plan’s approver | Approve the layer, or amend the terms, which covers every layer with the same path pattern |
| A never-automated path | The path’s OWNERS group | Review |
| A conflict at the resolver ladder’s last step | The people both agents act for, and the paths’ OWNERS | Accept the recommended resolution, or choose a side |
| Checks still failing after the repair rounds | The plan’s owner | Retry with the fix, quarantine the test, or drop the layer |
| A decision row | The plan’s decider | Accept the recommendation, or choose |
| A Frazer Reviewer escalation | The plan’s approver | Accept, dismiss with a reason, or ask for a fix |
| A campaign’s daily review | The campaign’s accountable person | One row covers its failing shards and holds |
| A release-time approval | The release’s approver | Approve the stage, or hold it |
| A contract break held in the queue | Both squads’ accountable people | Stay compatible, version, or coordinate |
| A batch of an exempt class not automated yet | The OWNERS | Approve the batch: R0 and R1 only, at most 20 a row |
| A person’s own pull request | The OWNERS | Review |
Rows are ranked by what they block, then due time, then risk class, then age. What one person is asked is budgeted: at most 40 pending, 25 a day and 90 minutes a day by default, and at most 10 new rows in any 10 minutes. A person whose job is supervising agents may choose a supervisor budget instead: on average at most one decision every ten minutes while on duty, at most 48 a day and four hours, with the same flood line and guards; the header then reads “13 of 48 decided · 47 of 240 min (supervisor budget)”. Past the budget, new rows go to other eligible approvers and the header says how many went to whom; rows no one else may decide wait and say so; and the causes that would remove the most rows tomorrow are listed, each with its fix as a plan. Nothing is approved by silence and no row is dropped. Because one campaign’s approval sets thousands of shards going, attention follows campaigns and plans, not pull requests: in the scale-day demo, lena’s 50,000 pull requests come to 53 rows and about 2 hours 50 minutes of decisions, and priya’s 20,000 of plan work to 61 rows and about 3 hours 20 minutes.
Accountable, as facts. Every agent pull request holds five facts as data: its scope inside the plan’s terms, the plan or record it implements, the item’s proofs, the session that answers for it, and the person the agent acts for. The peek lists them, and a pull request missing one is grouped under Needs evidence, never mixed with ready ones.
One query language for the URL (?q=), fir pr list --query, MCP list_pull_requests and saved views: is:open needs:@me kind:outside_terms plan:pellwyn/plans#416 repo:pellwyn/ledger risk:R2..R3 author:agent for:@me cause:<cause> age:>2h group:stack.
Keys and bulk actions. J and K move · X selects · Space peeks · W opens the receipt · ↵ opens · E marks an informational row done · H snoozes · A does what the row allows · ⇧A opens a batch to look at each one first · M merges when ready · R requests changes · G N Now · G O Outcomes · P pauses the selected scope with a reason (⇧P resumes) · T throttles · / filters · ? lists every key. A bulk action does, for each row, only what that row already allows you; layers outside a plan’s terms are decided by amending the terms, never by a bulk approval.
My work follows the same rule across every source: your Needs you count in decisions and your budget line, your scope’s count line, Needs you grouped by kind, your agents and campaigns as counts by state with only their exceptions as rows, your plans as one rollup line each, and Since you last looked as counts. An item exists once: answering it anywhere clears it everywhere.
fir pr list --view now --jsonfir pr list --view needs-you --jsonfir pr list --view by-node --query "plan:pellwyn/plans#405"fir pr why ledger#147233fir work --jsonFor agents, list_pull_requests {query, view, group_by} returns the counts, the exception groups, the groups and the rows at one as_of; {view: "now"} returns the stages with their counts, rates and top groups, and {view: "by_node"} the plan levels with their counts and what needs the person. get_merge_receipt returns a receipt, and the event inbox.changed updates live screens at most once a second. An agent working for a person may prepare a row (draft the amendment, rerun the check it names) and say so on it; it never answers one. The count line, the Now strip and the rollups are designed to read within 5 ms at p99 on the server for a scope of 50,000 pull requests a day, a receipt within 10 ms, and the All view to paint within 200 ms at 100,000 rows.
Every pull request carries an intent
Section titled “Every pull request carries an intent”A pull request carries what it is for: the task (an issue or a prompt summary), the plan and the acceptance criteria. Agents write it from their task; people write a sentence. Link an issue it fixes with fir pr create --fixes 479. The Frazer Reviewer checks the diff against the intent and flags files the intent does not explain. Text copied from an issue or a web page is labeled untrusted and is never followed as an instruction.
Plans, specs and decisions
Section titled “Plans, specs and decisions”The documents a change is written against live in Fir too, as records: plans, specs, decisions, milestones, runbooks and the rest, stored in the code repository’s own tree or in the project’s plan repository, and read through one index either way. They are numbered, versioned when they merge, typed, and linked to the commits, pull requests and checks that implement them without anyone typing a link. fir why on any line shows the change that wrote it, the plan version it was written against, the requirement that covers it and the decisions in force then and now. People approve plans after Fir has checked them and models of other families have reviewed them cold; layers inside an approved plan’s terms merge on their proofs. See Plan repositories, Record types, Programs, Decisions and The planning flow.
Merging
Section titled “Merging”Each path of a repository has one of three merge policies. A path with a fixed policy always uses it.
| Policy | What happens | Right for |
|---|---|---|
| direct | The pull request merges once its own checks pass; the branch is verified after, a failure is bisected and the culprit reverted | Leaf code, tests, docs, most agent pull requests |
| queue | The pull request is checked on top of the current tip first; pull requests with separate paths and build targets never wait | Schemas, migrations, auth, release branches |
| hybrid, the default | A risk score picks direct or queue for each pull request from its class, paths, author and evidence | Most repositories |
Find out exactly what still blocks a merge with fir pr blockers 482: each blocker names its rule, what it needs and what it has. fir rules explain 482 says which rules apply and why.
Inside an approved plan’s terms, a layer auto-merges with no person’s act when seven conditions hold at its exact version (intent, worked through, checks, an independent second opinion, its risk class’s rule, paths and window), and its merge record carries a signed receipt: fir pr why 482 prints it. Every protected branch has one merge queue, split into partitions by affected targets, that tests entries in test batches. See Auto-merge and the merge queue.
Every snapshot, rebase, merge, branch change and policy change is an operation in the activity log. fir activity lists them; fir undo <operation> undoes one in your workspace or on an unmerged pull request, and shows a plan of what it changes first. fir restore <operation> brings back the state an operation left. An undo is itself an operation, so it can be undone. A merged pull request is never erased: fir pr revert 482 opens a pull request that reverts it, and it merges through the same rules.
Stacks
Section titled “Stacks”Every pull request is in a stack, and a single pull request is a stack of one layer. fir stack create --plan 469 makes a stack with a planned layer per plan item; fir stack submit creates or extends a stack from your workspace. The server restacks every layer above one that changes, in one transaction that never fails: a conflict becomes data on the layer, and approvals follow each layer’s own patch. fir stack merge --up-to 483 merges the stack up to #483 as one entry in the merge queue, and a stack’s approver sees only what needs them. Overlaps with other open work are warned on every snapshot and resolved by a ladder of resolvers before a person is asked. See Stacks and conflicts.
Ask the codebase
Section titled “Ask the codebase”The same calls an agent makes through MCP are fir commands. Each answer names where it is true (a commit such as main@48213, a pull request version, or your workspace with its unsaved edits) and how precise it is.
| Question | Command |
|---|---|
| Where is this text or symbol? | fir search |
| Show a file or a range of lines | fir show main@48213:services/payments/capture.go:40-80 |
| What is defined in this file or directory? | fir symbols services/payments |
| Where is it defined, and who uses it? | fir def, fir refs, fir calls |
| A map of the repository in a token budget | fir map --budget 2000 |
| Why does this line exist? | fir why services/payments/capture.go:57 |
| Which tests cover it, and what failed here? | fir tests, fir failures --since 7d |
| Who owns this path? | fir owners services/checkout-api/payments |
Fir for agents
Section titled “Fir for agents”Frazer’s own agents and the harnesses Frazer supports call Fir through MCP, and every tool is also a fir command and an API method. Tool names follow the names agents already use for pull requests:
| MCP tool | fir command |
What it does |
|---|---|---|
search_code |
fir search |
Literal, regex, path and symbol search, up to 16 queries a call |
get_file_contents |
fir show |
Line-numbered ranges with a token budget, or an outline |
create_pull_request |
fir pr create |
Open a pull request from a workspace |
get_merge_blockers |
fir pr blockers |
What still blocks a merge, as data |
merge_pull_request |
fir pr merge |
Merge, naming the expected version; returns an operation to follow |
get_merge_queue |
fir queue status |
The merge queue of a branch |
submit_stack |
fir stack submit |
Create or extend a stack from a workspace |
get_stack |
fir stack view |
A stack’s layers, states and blockers |
get_overlaps |
fir overlaps |
Open overlaps with other work, with the hunks and a suggested action |
get_activity |
fir activity |
The activity log |
undo_operation |
fir undo |
Undo an operation |
why |
fir why |
Why a line, symbol or change exists |
open_session |
fir session open |
Open the Fir session an agent’s commits need |
get_merge_receipt |
fir pr why |
Why a layer merged, or what it still waits for |
Run a local MCP server with only the tools you need: fir mcp --toolsets pull_requests,search --read-only. Connect an agent of any vendor in one step with fir agent setup <harness>; every fir command follows the CLI contract for agents.
Build tools that ask git for a version get it from the environment in every Fir workspace shell and in CI: FIR_COMMIT (the commit ID), FIR_BRANCH, FIR_SEQ (the sequence number once merged), FIR_PR (number and version) and FIR_CHANGE_ID. fir describe prints a string in the shape git describe prints.
Move a repository to Fir, and back
Section titled “Move a repository to Fir, and back”-
Plan the import. Nothing changes until you accept the plan; it lists the history, the owners and branch rules it converts, and every place in the repository, its CI and its scripts that calls git, with the replacement for each.
Terminal window frazer source repositories import --from <git-url> --dry-run -
Run it without
--dry-run. The full history comes in, original commit IDs kept..gitignorebecomes.fir/ignore, and code owners becomeOWNERSfiles. -
Rehearse. Agents, CI and devboxes read the Fir copy while people keep writing on git, for at least a week. Then cut over in one window: git becomes read-only, a last sync runs, and open pull requests move to Fir.
Leaving is one command too. frazer source repositories export --to git writes a plain git repository with the full history at any time; fir export does the same from the command line.
Pricing
Section titled “Pricing”| Fir | On your servers | On the Frazer fleet |
|---|---|---|
| Price | Included: caches, search and daemons on your servers · stored data as on the fleet | Stored data $0.012 / GiB-month, counted once after deduplication · workspaces, merges and search free within fair use · no seats for people or agents |
Every line, with the estimator: pricing.
Reference
Section titled “Reference”- Fir CLI reference: every
fircommand - Tasks, step by step: open a pull request on Fir, as an agent
CLI
| Command | What it does |
|---|---|
frazer source repositories import | Import a git repository into Fir with its full history, as a plan you read before anything changes. |
frazer source repositories export | Write a Fir repository out as a plain git repository, history included, at any time. |
All of them: CLI reference.
Related
Section titled “Related”- Plan repositories, Record types, Programs, Decisions and The planning flow
- Stacks and conflicts: stacked pull requests, the merge queue and conflicts
- Agents and plans: what an agent session receives from its plan
- Frazer for agents: how agents read these docs and use Frazer
- Frazer CI: checks for Fir repositories
- CLI: the
frazercommand line