What is BaseInst?
An agent given a task works out a plan, calls tools, reads what comes back, and answers. Give it the same task tomorrow with one value changed — a different region, a different customer, a different week — and it works the same plan out again from nothing.
The tokens, the latency and the tool calls are all spent a second time to arrive at a conclusion the first run already reached. BaseInst records those runs, derives the plan from one of them, and runs the plan directly the next time the same question comes round.
The loop
Three steps. Each is a thing you can see in the console, and each can be inspected before you trust the next.
The agent works normally. Every tool call, its arguments, what came back, how long it took and what it cost is stored — along with the prompt that started it and the answer it reached.
Produces · a runThe transcript becomes logic: an intent, a parameter schema naming what was incidental to that particular run, and one body per step that recomputes that step's arguments.
Produces · a scenarioA prompt that means the same thing as a recorded one runs the logic instead of being solved again. The tools are really called; only the rediscovery is skipped.
Produces · a savingRecord
The runner sits in the agent's execution path and stores each run. Nothing about the model's behaviour changes — the recorder executes the calls the model was going to make anyway and returns the results unaltered.
A run with three tool actions or fewer is not kept in the searchable pool and is eventually pruned. Below that threshold there is no plan to derive, only a single call and its answer. Each finished run gets a title of at most 40 characters, written by a model from its transcript, so the list reads as a list of tasks rather than a list of ids.
Calculate
A recorded run is a transcript: what happened, once, with those exact values. A calculated scenario is what BaseInst derives from it — an intent, a parameter schema, and one logic body per step.
The transcript says what the agent did. The scenario says what the agent was doing, which is the only half worth running again.
Replay
Matching is on the prompt text, embedded and compared by
similarity — not the transcript and not the answer. Above the detection
threshold (default 0.9) the service recognises a match; above
the steering threshold (default 0.92) the runner acts on it.
- Fully wrapped — every step is a tool the proxy already holds a connection to. The sequence runs through those connections with zero model tokens; the model's only job is to read the results.
- Mixed — some steps are built-in tools the proxy cannot execute. The live session is steered instead: each step runs as normal, with its arguments pinned to what the scenario computed.
The savings ledger, and why it is careful
The headline is verified saved. It is deliberately smaller than the number BaseInst could report, and the gap is the point.
Money we watched move. Costs measured on both sides — what the agent's run cost, what the replay cost — reported by the process that spent them. This is the number the dashboard leads with.
Booked from costs nobody measured end to end. Real rows, honest arithmetic, partial inputs. Shown beside the headline and never added into it.
The distinction matters because of how the arithmetic fails when a cost is
missing. An unmeasured replay usually has only its parameter-derivation call
priced, so baseline − cost books nearly the whole baseline as
profit. A ledger that summed those would report a large, confident, wrong
number.
Two more rules in the same spirit:
- A baseline drawn from one run is labelled as one run. Every saving on a row is measured against what the agent costs on that task. If that figure comes from a single sample it is a guess, and the console says so rather than presenting a statistic.
- A scenario can lose money, and it will say so. If recent replays cost more than the agent does, the row is flagged as not paying off. Savings are not clamped at zero — a scenario quietly costing you money is exactly the thing you need to be told.
Two run types are counted but save nothing, and are reported separately. A dry replay evaluates stored logic against recorded outputs — a check, not work. A not-steered hit is a matched prompt the runner declined to replay, which becomes another baseline sample instead.
What BaseInst is not
| Not this | Because |
|---|---|
| A caching layer | A cache returns a stored answer. A scenario re-runs the work with new arguments — the tools are really called, against live data, and the answer is about today. |
| A prompt library | Nothing here changes what the model is told. Tool descriptions are never edited to steer the model's choices. |
| An observability product | It records runs and you can read them, but the recording exists to become a scenario. If you only want traces there are cheaper things to run. |
| Automatic | A run is recorded automatically. A scenario is calculated because you asked. Replay happens only once you have turned it on and said which servers may be called unattended. |
Who should use it?
BaseInst pays off on a narrow, common shape of work: a task you give an agent more than once, where what changes between runs is the values and not the plan.
If that describes something you do weekly, read on. If it does not, the honest answer is that BaseInst will record your work faithfully and save you nothing — and you should know that now rather than in three weeks.
The three-question test
All three have to be yes.
-
Will I run this again?
Not "could someone"; will you, within the month a calculated scenario stays live. A task run once is a task whose plan is worth nothing to derive.
-
Does the plan stay the same when the values change?
"Check the eu-west-1 fleet and tell me which device is most at risk" and "check us-east-2" are one plan with a parameter moved. "Figure out why the build broke" is a different investigation every time, even when the words are identical.
-
Is it more than three tool calls?
Below four actions there is no plan to capture, and the service will not keep the run in its searchable pool. A one-call task is already as cheap as it gets.
The shapes that work — and the ones that don't
Worth recording
- Scheduled sweeps and reports. Fleet health, cost reports, open-PR triage, error-budget checks. Same steps, new window, run on a cadence.
- Per-entity investigations on a fixed path. The customer changes; the four tools and their order do not.
- Fan-out over a list. Record once against one repository, region or account; the other thirty-nine are the same scenario with a different parameter. This is where the arithmetic gets loud.
- Runbooks with a stable spine. Nobody should be paying a model to rediscover the opening moves at 3am.
Not worth it
- Genuinely exploratory work. Debugging, code review, research — anywhere the second tool call depends on what the first said in a way you could not have predicted. The plan is the work.
- Non-MCP tools without hooks. You get a partial recording, correctly labelled as one.
- Anything that must not run unattended. If that sentence makes you uneasy about a particular tool, do not put it on the allow-list — that instinct is correct.
- High-variance, low-frequency work. The scenario will have expired by the time it comes round again.
Who, in job terms
| You are | What you get out of it |
|---|---|
| Platform / SRE | Scheduled sweeps and runbook openings. The highest-yield case: fixed spine, changing scope, run constantly |
| Data / analytics engineering | Report pipelines where the shape is stable and the window moves |
| Support & success engineering | Per-customer investigations that always start the same way |
| Agent and tooling teams | A measured answer to "is this agent worth what it costs", from the ledger, before you touch replay at all |
| Engineering leadership | The verified-savings figure — deliberately conservative, and therefore quotable |
Recording is useful on its own, and it is the whole of what runs out of the box. A team that never calculates a single scenario still ends up with a priced, searchable record of what its agents did and what each run cost. For some teams that is the entire value, with replay as a later question.
What it costs you to find out
An afternoon, and no money. The free program allows one calculated scenario, live for 30 days — enough to answer the only question that matters. Take the task you repeat most, record it, calculate it, dry-replay it, and read the ledger after a week. If the number is unconvincing on your best candidate, it will not improve on your second-best.
| Program | Price | Scenarios at once | Each live for |
|---|---|---|---|
| Free | — | 1 | 30 days |
| Starter | $5 / month | 3 | 30 days |
| Pro | $10 / month | 15 | 30 days |
| Pro quarterly | $15 / 3 months | 15 | 90 days |
The limit is on scenarios held at once, not on runs recorded or replays performed. Recording is unlimited on every program.
The honest limits
None of these is a bug to be fixed later.
- A scenario expires. It stops steering runs when its window is up but keeps its place against your allowance until you delete its recording. On the free program, one expired scenario blocks the next.
- A match is a match on the prompt. Phrase the first prompt of a reusable task as though someone else will have to phrase it again next month — because that is exactly what has to happen.
- Standalone recording is partial. Without the hook binary there is no prompt, no final answer and no built-in steps, so there is nothing for a match to compare against and replay cannot arm.
- Calculation needs a model. Deriving a scenario, and deriving parameters at replay time, both call Anthropic. A service without a key configured will refuse to calculate.
Using the console
The console is where recordings, scenarios and money are visible. What follows is a tour of the screens and, more usefully, of what each number is actually claiming.
Getting an account
Register
With an email and password, or sign in with Google.
Verify the address
Registration does not create a session; the link in the email does. That link is the proof of the inbox, and it may be opened on a different device from the one you registered on.
Sign in
You land on the dashboard. If a verification link has gone stale, ask for another from the sign-in screen — a new link supersedes the old one.
Getting around
The menu is on the left and stays there. It is grouped, because the destinations are about different things.
| Section | Screens |
|---|---|
| — | Dashboard, Recordings — and, while you are inside Recordings, its saved views |
| Billing | Programs, Billing |
| Account | Account, Sign-in history |
| Admin | Users, Invoices — admin accounts only |
Pinned to the bottom of the rail:
- Documentation — this handbook, where the deployment has been given a docs URL.
- The program chip — your program and how much of the calculating allowance is in use. It turns amber when the allowance is spent, which is the state where Calculate will be refused. Knowing that before you click is the entire reason the chip is there.
- The account chip — name and role, with account settings, the light/dark toggle and sign out.
⌘K opens search from anywhere. It searches the menu, and offers one row that hands your query to the recordings search. It does not search across everything — there is no index behind that, and a palette pretending otherwise would be worse than one that is clear about its scope.
At the foot of every page: API status, Help and support, Feedback. The status light is a single call on load — it does not poll, because a status indicator that hammers a service during an incident is a second outage stacked on the first.
Recordings — the columns
The list, and the only screen with twelve columns. Everything about it lives in the URL — sort, page, search, filters — so a view worth building can be bookmarked or sent to somebody.
| Column | Reading |
|---|---|
| Run | The generated title, ≤40 characters. Falls back to the first line of the prompt before a title exists |
| Steps | Actions the agent took. Not every stored row — a tool's response and the recorder's own bookkeeping are not steps the agent took |
| LLM $/run | The baseline: what this task costs when the agent does it. Its ⓘ says how many runs the baseline is drawn from |
| Scenario $/run | What a replay costs. Marked when it is a pre-flight estimate rather than an observed mean — "we measured this" and "we guessed this" must not look alike |
| Scenario runs | Replays of this scenario |
| Similar hits | Prompts matched against this recording |
| Saved $ | Verified savings for this row, signed. — until a measured replay has actually happened |
| Calculated | yes, no, calculating…, failed, or expired |
Calculated recordings sort to the top of every column by default; the note above the table says so and lets you turn it off. Runs with three actions or fewer are hidden, with a link saying how many — hidden rather than deleted, because they are also below the threshold for being kept at all.
Programs and billing
Two things the programs screen deliberately does:
- It does not charge on a single click. Choosing a program expands the card into what the choice costs and when; the second press is the one that spends money.
- It does not hide the downgrade. Free is a card like any other. A program you cannot see how to leave is a trap.
Upgrades are not prorated and downgrades keep the period already paid for. Both are said before the click, not after. An overdue renewal keeps working through a grace window, and the billing screen says when that window closes.
Reading the numbers honestly
Lead with verified
It is the smaller number and the defensible one. If you need the larger one for a slide, say which half is projected.
Check the baseline's sample count
Before quoting a saving. One run is a guess, and every saving on that row is measured against it.
Believe a negative
A scenario flagged as not paying off is costing you money on its recent runs. The two useful responses are recalculate or retire; both beat looking away.
Read
expiredas its own stateIt is not failed and not missing. It still occupies your allowance — on the free program, that means it is blocking the next scenario until its recording is deleted.
How to record
Everything starts with a recorded run. The recorder is
BaseInstRunner — bir — which lives in its own
repository, BaseInstRunnerMCP.
Three files there are the source of truth for everything below:
README.md (the operator's half),
docs/BaseInstRunner.md (the design), and
docs/calculatedReplayGuide.md (the replay runbook in more
detail than this page goes into). Where they disagree with this page, they
are right — they sit next to the code.
Guide
What the recorder is
bir is an MCP proxy. It registers under your
existing MCP server keys, so the model still emits
mcp__chrome-devtools__navigate_page and still gets exactly what
chrome-devtools-mcp would have returned. The difference is that
bir executed the call on the client's behalf, and wrote down
what happened.
Interception is a configuration fact, not a prompting one. The model is never asked to cooperate, and tool descriptions are never edited to steer its choices.
An MCP server sees only MCP traffic addressed to it. Bash, Read, Edit, Grep are not MCP. Neither is your prompt, the model's reasoning, or the final answer.
Which is why there are two halves. bir-proxy records MCP calls;
bir-hooks is a hook receiver that records everything else and
owns the run.
The two tiers
| Tier | When | What ends up in the recording |
|---|---|---|
| 1 — Bound | bir-hooks is discoverable for this working directory | Built-ins and MCP, in one ordered step stream, with the prompt and the final answer |
| 2 — Standalone | No control server found within five seconds | MCP calls only. No prompt, no final answer, no built-in steps |
Tier 2 is not a degraded bug — it is the honest ceiling of what a proxy alone can observe, and a run records which tier produced it so nothing downstream mistakes a partial trace for a complete one. For anything beyond raw recording you want Tier 1: a match is a match on the prompt, and a standalone proxy never sees one.
Install
# in the BaseInstRunnerMCP checkout
npm install && npm run build
# in the project you want to record from
export BIR_AUTH_URL=https://api.bi2202.com
node dist/bin/bir.js install # or `bir install` once linked
bir login
bir install rewrites your MCP entries in place,
keeping every key — so mcp__<server>__<tool> names
never change — and wires Claude Code's hooks. It stashes the original text of
every file first, and bir uninstall puts it back byte for byte.
bir-hooks # its own terminal; leave running
claude # another terminal — now recorded
bir status # what is wrapped, and which config scope won
bir doctor # is it working right now — exits non-zero if not
doctor is the one to trust. status tells you what is
configured; doctor tells you whether a proxy can currently reach
a control server — which is the difference between Tier 1 and Tier 2.
For other MCP clients, nothing in bir knows where Cursor or Codex
keep their settings, and it does not guess:
bir install --config <path>, or
bir wrap --server-name my-server -- node my-server.js to print an
entry to paste. Those clients have no hooks, so they record at Tier 2.
Record a run worth keeping
Work normally. Two server-side facts decide whether the run becomes reusable, and both bite quietly.
A run needs more than three tool actions. Below that it is not embedded, does not enter the similarity pool, does not appear in the list, and is eventually pruned. A two-tool run will never match anything however often you repeat it.
The prompt is what gets embedded — the text you typed, not the transcript and not the answer. Write the first prompt of a reusable task as though someone else will have to phrase it again next month, because that is exactly what has to happen.
Watch it land on the audit stream:
[bir] … run.start run=run_… sess=birsess_… tier=bound
[bir] … run.finish run=run_… steps=14 durationMs=48210 lossy=false recorded=true
recorded=false means the service declined the run — usually
because it matched something you already have, which is similarity detection
working. Every decision is one key=value line on
stderr, never stdout, which belongs to the host's JSON-RPC
stream. There is no log file to configure; persistence is the shell's job:
bir-hooks 2>&1 | tee -a ~/.baseinstrunner/audit.log.
Calculate, then check
bir scenario list # what you have
bir scenario calc run_5f3a… # start the background job
bir scenario show run_5f3a… # poll until state leaves `calculating`
failed carries an error field; fix it and recalculate
with --force. Or do all of this from the console's recording
detail page, which is the same API with the results laid out.
Dry-replay before you trust it. It derives parameters from a new prompt and evaluates the stored logic against the recorded outputs — no real tool is called, nothing is billed, and it is the cheapest way to find out that step 3 computes an argument you did not expect.
bir scenario replay scn_9c1b… --prompt "check the us-east-2 fleet" --dry
Turning replay on
Recording is the default and the whole of what runs out of the box. Replay takes two switches, deliberately:
bir install --replay # adds the `bir` MCP server
BIR_REPLAY=1 bir-hooks # and this is the actual switch
A scenario is a pre-approved list of tool calls with computed
arguments. A steered step is answered
permissionDecision: "allow", so a pinned Bash or
Edit runs without the prompt you would otherwise have seen. A
directly executed step never reaches the permission system at all.
Set BIR_REPLAY_ALLOW_SERVERS to the servers you are content to
have called unattended. Leaving it unset means every wrapped server
is eligible, and that is not the setting you want.
Configuration
| Variable | Effect |
|---|---|
BIR_AUTH_URL | The BaseInst service. Unset means nothing is recorded — everything else still works |
BIR_CONTROL_PORT | Preferred control-server port (default 53411) |
BIR_CORRELATION_DECISION | allow (default) or ask. Correlation auto-approves wrapped MCP calls; ask keeps the prompt, at the cost of lossier matching |
BIR_HOME | Where state lives (default ~/.baseinstrunner) |
BIR_VERBOSE=1 | Per-message detail on stderr |
BIR_REPLAY=1 | Enable replay. Nothing else about replay matters until this is set |
BIR_REPLAY_ALLOW_SERVERS | Server keys eligible for direct execution. Set this |
BIR_MIN_STEER_SIMILARITY | Minimum match similarity to replay (default 0.92) |
ANTHROPIC_API_KEY | Enables parameter derivation at replay time. Without it, replay uses the scenario's recorded sample values — free, and often still correct |
When it goes wrong
The governing rule is that a host session never fails because of BaseInstRunner. Every failure degrades to passthrough or to not-recording.
| Symptom | Cause | Fix |
|---|---|---|
| Nothing appears in the console | BIR_AUTH_URL unset, or not signed in | bir login; check bir doctor |
tier: standalone | bir-hooks not running, or not for this cwd | Start it in the project directory |
| Recorded, but not in the list | Three actions or fewer | Nothing to fix — below the threshold on purpose |
recorded=false | The service matched it to an existing run | Working as intended |
| No prompt ever matches | Similarity detection off, or the prompts really are different | Check SIMILARITY_DETECTION_ENABLED; re-read the prompt you wrote |
| Calculate returns 503 | No Anthropic key on the server | Server-side configuration |
Sample — the fleet demo
A complete run-through against a real MCP server, on your machine, with no
cloud resources and no money spent. About ten minutes. It lives in the runner
repository at examples/fleet-demo/: a tiny but genuine MCP server
over stdio, with two tools.
list_devices(fleet) → the fleet's devices, with risk scores
device_detail(id) → one device's detail
Step 2 can only compute its id argument from step 1's
output. That makes this the smallest honest test of whether scenario
calculation actually works, rather than the smallest test that passes.
The task: "check the eu-west-1 fleet and tell me which device is most at
risk" — which resolves, in the sample data, to dev_88f1:
edge-01, risk 0.94, firmware 3.1.2.
Set up the project
cd BaseInstRunnerMCP/examples/fleet-demo export BIR_AUTH_URL=http://localhost:8080 node ../../dist/bin/bir.js install --local --replay node ../../dist/bin/bir.js login--localinvokes this checkout's proxy rather than fetching one.--replayadds the scenario server now, so step 7 needs no second install. The demo ships with a config from whoever built it; re-runninginstallregenerates it for your machine — paths and port included.Start the control server
In its own terminal, from the same directory:
node ../../dist/bin/bir-hooks.js. Watch fortier=bound. If it saysstandalone, the control server and the session disagree about either the working directory or the port — the only two things discovery matches on.Record the run
session.mjsis a stand-in for a Claude Code session: it does what Claude Code does, in the same order, so this exercises the real code paths rather than a mock of them.node session.mjs "check the eu-west-1 fleet and tell me which device is most at risk"Look at it in the console
Recordings holds the run with its generated title, step count and cost. This is the baseline: what the task costs when the agent does it.
Calculate the scenario — and read it
Run
scenario calc, thenscenario show. You are looking for three things:- an intent that describes the task, not the specific fleet;
fleetas a parameter witheu-west-1as its sample value — if the region is baked into a step's logic, the scenario only ever answers one question;- step 2's logic reading step 1's output to pick the highest-risk id. A scenario that hard-codes
dev_88f1looks identical on a green run and is wrong the moment the data moves.
Dry-replay against a different fleet
The derived parameter should be
us-east-2. Since a dry run evaluates against recorded outputs, step 2 still picks from the eu-west-1 devices — correct behaviour, and the reason those lines are markedResult (recorded):. What you are checking is the parameter derivation and the step logic, not the answer.Replay it for real
BIR_REPLAY=1 BIR_REPLAY_ALLOW_SERVERS=fleet \ node ../../dist/bin/bir-hooks.js node session.mjs "check the us-east-2 fleet and tell me \ which device is most at risk" --replayNow the tools are really called.
us-east-2's highest-risk device isdev_4411—core-01, risk 0.77. That is the proof the scenario computed the answer rather than remembering it.Read the ledger
Back in the console, check three things: Saved $ is populated and the baseline's ⓘ says how many runs it is drawn from (on a first pass, one — and one sample is a guess); the headline moved under verified, not projected; and the scenario is not flagged as not paying off. On a two-step task against a local server the arithmetic is tight — on real work with real latency it is not.
The second sample. examples/incident-demo/ is the
same shape with a longer chain — list_services,
service_metrics, error_logs,
recent_deploys, dependency_graph. Worth doing once
the fleet demo works, because a five-step scenario is where the interesting
failures start: a step whose logic reads the wrong earlier output
looks fine on two steps and falls apart on five.
Videos
None of these are recorded yet. What follows is the shot list and narration for each, written so somebody can sit down and record them without having to invent the structure first.
Common conventions, so the four feel like one set:
- 1280×720, terminal at a size legible on a phone.
- Light theme in the console — it is the default and it screenshots better.
- No music. Voice-over or captions, not both.
- Real data from the fleet sample. Never a mock-up of a screen that does not exist.
- Cut every wait longer than two seconds. Calculation takes about ten; nobody needs to watch it.
| Time | Shot | Narration |
|---|---|---|
| 0:00 | Terminal: the same task run twice, cost visible both times | "Your agent solved this yesterday. Today it paid full price to solve it again." |
| 0:15 | The record → calculate → replay diagram | "BaseInst records the run, derives the plan, and runs the plan next time." |
| 0:35 | Console: the recording, then its scenario — intent and parameters | "A transcript says what the agent did. A scenario says what it was doing." |
| 0:55 | Dashboard, verified tile, ⓘ open | "And it measures what that saved. The number it leads with is the one it watched move." |
| 1:15 | Programs page | "One calculated scenario, free, for thirty days. Enough to find out on your own work." |
The guide, executed. One terminal, one browser window.
npm run build,bir install,bir login— say whatinstallrewrites, and thatuninstallreverses it byte for byte.bir-hooksin a second terminal. Point attier=boundand say what Tier 2 would mean.bir doctor. Explain why this is the command to trust, notstatus.- Run the fleet task. Watch
run.startandrun.finishgo past. - Console → Recordings → the row. Name the columns: Steps, LLM $/run, and the baseline's sample count.
- Close on the threshold: "fewer than four actions and it is not kept — there is no plan in a single call."
The video that earns its place, because this is where people get burned.
scenario calc, thenscenario show. Read the intent aloud.- Stop on the parameters.
fleet: eu-west-1— a sample value, not a constant. - Stop on step 2's logic. Show it reading step 1's output. Then show, by hand, what a hard-coded
dev_88f1would look like: identical on this run, wrong on the next. - Dry replay against
us-east-2. ExplainResult (recorded):and why a dry run still shows eu-west-1 devices. - Real replay.
dev_4411. "It computed that. It did not remember it." - Close on the ledger row and the not-paying-off flag: "a scenario can cost you money, and this is where it says so."
- The sidebar: sections, the program chip, and the amber state.
- ⌘K, including the recordings-search row. Say plainly that it does not search everything.
- Recordings: verified versus projected, with the ⓘ open. The segment worth over-explaining.
expiredas its own state — still holding a slot, no longer steering.- Programs: the two-step confirmation, and Free being a visible card.
- The delete confirmation, naming the savings that will leave the headline.
Host them wherever the deployment's VITE_DOCS_URL points, embedded
beside the section each one covers. Until they exist, the written sections
stand on their own — which is why they were written to.