The BaseInst Handbook
BaseInst Record · Calculate · Replay Handbook, revision 11

Stop paying twice
for the same run.

Your agent worked this out yesterday. Today it paid full price to work it out again. BaseInst records the run, derives the plan, runs the plan next time — and then measures what that actually saved, rather than claiming it.

The distinction the whole product is built on — example figures
Verified $412.80
Projected $190.15

Verified is money we watched move: costs measured on both sides and reported by the process that spent them. Projected is booked from costs nobody measured end to end — real rows, honest arithmetic, partial inputs. The console leads with the first number and never adds the second into it.

One

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.

Step one Record

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 run
Step two Calculate

The 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 scenario
Step three Replay

A 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 saving

Record

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.

Claude Code answering: check the eu-west-1 fleet and tell me which device is most at risk
A run, as the agent saw it. Claude Code is given a task, calls the fleet tool, and answers. Nothing about the agent changed; the runner recorded it from the side, and a run like this is what a recording is made of.

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.

Press Calculate yourself, or let the service choose: whenever a prompt comes back it takes the recording with the most to save — among those whose prompt has come back at least three times and that passed end to end, the run finishing without an error and no tool call in it failing — and calculates it. It never replaces a scenario you already have. Would rather it were a different recording? Prefer that one: it is calculated at once, taking the place of an automatic scenario (or, after you confirm, one you calculated by hand), and nothing evicts it in turn until you withdraw the preference.

The distinction

The transcript says what the agent did. The scenario says what the agent was doing, which is the only half worth running again.

The scenario panel on a recording's page: the intent, the parameters, and the last execution
A scenario, as the console shows it. The intent names the task, not the fleet. The parameters — fleet and id — are what may change next time. The last execution says what one reuse cost and what it saved.
One step of the scenario: its description, the recorded input, the input logic and the output logic
One step's logic. return { fleet: parameters.fleet } sends whatever fleet the new prompt names; the output logic sorts what comes back by risk and hands the worst device to the next step. Nothing is remembered — everything is recomputed. A plan that had memorised dev_88f1 would look identical today and be wrong the day the data changed.

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.

Verified

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.

Projected

Booked from costs nobody measured end to end. Real rows, honest arithmetic, partial inputs. Shown beside the headline and never added into it.

The three headline tiles: Verified saved, Calculated scenarios, Calculated runs
The headline, as the console shows it. The verified figure leads, with the runs it is measured over underneath. Beside it: how many calculated scenarios the account holds, and how many times a scenario has done the work. This picture was taken before the fee and the allowance were removed, so the first tile still shows a fee beneath it and the second still shows a limit.

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.

Scenario caching, not semantic caching

AI gateways such as TrueFoundry's and Gravitee's offer semantic caching. The gateway keeps the model's reply to each prompt, keyed by an embedding of that prompt. When a new prompt is close enough to one it has seen, above a similarity threshold you set, it returns the stored reply and the model is never called. For what it is built for it is a good tool: the same question asked many times in slightly different words, where the same answer is still right. A help desk answering the password-reset question is the textbook case.

BaseInst starts the same way and then does something different. It also embeds the request and looks for a close match among your earlier ones, with a stricter threshold and more checks before anything runs. But what it keeps and reuses is not the answer. It is the scenario: the plan the agent worked out, with the values that vary taken out of it, and a rule per step for recomputing that step's arguments from the new request and from what the previous step returned. On a match the tools are really called, against today's data, and the model reads the results and writes today's answer. What is skipped is the working-out, not the work. The honest name for it is scenario caching: it caches the plan.

Semantic cacheBaseInst: scenario caching
What is storedThe model's reply, keyed by the prompt's embeddingThe plan: an intent, the parameters, one rule per step
What a hit returnsThe stored reply, without calling the modelA fresh run of the plan: live tool calls, a new answer
Right whenThe same question deserves the same answerThe same task comes back with different values: another fleet, another customer, another week
Wrong whenThe world moved since the reply was stored, or the near-match was a different questionThe task is exploratory, so there is no plan to reuse
Where it sitsIn front of the model, in the gatewayBeside the agent, on the path to its tools
What it savesThe whole model call, on questions that repeat word for word or nearlyThe planning turns, on tasks that repeat in shape
What it reportsA hit rateA saving: what the agent costs on the task, minus what the replay measurably cost, with verified kept apart from projected
The failure to watch forA hit that should have been a miss returns the wrong answer, confidently. Both vendors' own documentation warns of itA step that remembers a value instead of computing it. The free dry run exists to catch that

The two are not rivals for the same request. A question with a fixed answer belongs in a semantic cache, and BaseInst would save nothing on it: there are no tool calls to plan. A task that calls tools, whose answer depends on what those tools return today, cannot be cached at all. Only its plan can, and that is what BaseInst caches.

What BaseInst is not

Not thisBecause
A caching layer, or a semantic cache 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. The side-by-side is under Scenario caching, not semantic caching, above.
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 replay A run is recorded automatically, and a scenario is calculated automatically once its prompt keeps coming back — or because you asked, or preferred it. Replay happens only once you have turned it on and said which servers may be called unattended.
Two

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.

  1. Will I run this again?

    Not "could someone"; will you. A task run once is a task whose plan is worth nothing to derive.

  2. 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.

  3. 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. Something you run twice a year, where the environment has moved on by the time it comes round again, so the plan the scenario holds is no longer the plan.

Who, in job terms

You areWhat you get out of it
Platform / SREScheduled sweeps and runbook openings. The highest-yield case: fixed spine, changing scope, run constantly
Data / analytics engineeringReport pipelines where the shape is stable and the window moves
Support & success engineeringPer-customer investigations that always start the same way
Agent and tooling teamsA measured answer to "is this agent worth what it costs", from the ledger, before you touch replay at all
Engineering leadershipThe verified-savings figure — deliberately conservative, and therefore quotable
Note the fourth row

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. Recording, calculating and replaying are all free, there is no limit on how many scenarios you hold, and none of them expires. Take the task you repeat most, record it, calculate it (or repeat it three times and let the service calculate it for you), 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.

If it is convincing, the question that follows is usually not about price but about where the recordings live. That is what running it in-house is for.

The honest limits

None of these is a bug to be fixed later.

  • A saving is only counted when it is measured. The verified figure needs the runner to report what a run cost. A session that ends without reporting loses you the measurement, and the saving lands under projected instead — the ledger stays conservative either way.
  • Calculation can be paused. Working a scenario out costs us several model calls, so the free service calculates one scenario at a time per account and stops for the day if the whole service has spent its budget. An ordinary account never meets the second one.
  • 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.
Three

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

  1. Register

    With an email and password, or sign in with Google.

  2. 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.

  3. 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.

The sign-in page at bi2202.com: the headline, and the sign-in card
The front door. bi2202.com, signed out. The card is where you sign in; Create account is top right and under the card. The grey note at the top of the card only appears when a long-idle session was signed out.

A new account sees Getting started on the dashboard where the tiles would be. The next step is to install the runner — about ten minutes — and the first recording lands there.

Getting around

The menu is on the left and stays there. It is grouped, because the destinations are about different things.

The dashboard: three headline numbers, then the Getting started and Recent recordings cards, with the menu on the left. Taken before the Credit card was removed
The dashboard. Three numbers, three cards, and the menu that stays on the left of every page. Each opens one sentence saying exactly what its number counts; when in doubt, click the ⓘ.
SectionScreens
Dashboard, Recordings — and, while you are inside Recordings, its saved views
AccountAccount, Sign-in history
AdminUsers, Invoices — admin accounts only

Pinned to the bottom of the rail:

  • Documentation — this handbook, where the deployment has been given a docs URL.
  • 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 thirteen columns. Everything about it lives in the URL — sort, page, search, filters — so a view worth building can be bookmarked or sent to somebody.

The Recordings page: the three tiles, then a table with one row per recorded task
Recordings. One row per task the agent did; rows with a green left edge have a calculated scenario. The sentence above the table says that the service also calculates recordings by itself once a prompt has come back three times.
The table header and two rows of the recordings list, up close
The header and two rows, up close. On the second row: the agent's run cost $0.1406, a replay costs $0.093, so each reuse is 33.7% cheaper; the prompt has come back five times, the scenario has done the work twice, and $0.0947 was saved.
ColumnReading
RunThe generated title, ≤40 characters. Falls back to the first line of the prompt before a title exists. Calculated rows carry a green edge
StartedWhen the agent ran
StepsActions the agent took. Not every stored row — a tool's response and the recorder's own bookkeeping are not steps the agent took
Statusdone, failed, or running
LLM $/runThe baseline: what this task costs when the agent does it. Its says how many runs the baseline is drawn from
Scenario $/runWhat a replay costs. Marked est. when it is a pre-flight estimate rather than an observed mean — "we measured this" and "we guessed this" must not look alike
Saved %/runHow much cheaper one calculated run is than one agent run: (LLM $/run − Scenario $/run) ÷ LLM $/run, from the two columns beside it. The bar under the figure fills to the same percentage, in a green that deepens as the saving grows; red only when a replay costs more than the agent. Marked est. while the scenario cost is still an estimate; without a ready scenario or a baseline
Original timeWall-clock for the agent's run
Calculated?yes, no, calculating… or failed. A scenario whose recent replays cost more than the agent is flagged not paying off here too. auto beside the badge means the service calculated it by itself. The ★ Preferred and ⊘ Switched off badges under a title are the two things you can tell the service about a recording
Calculated runsReplays of this scenario that did work — the same count as the tile above. Its breaks out unmeasured, dry and not-steered runs
Similar hitsPrompts matched against this recording
Saved $Verified savings for this row, signed. until a measured replay has actually happened. Projected savings, when there are any, sit beneath it and are never added in

Every column with a figure in it sorts, Saved %/run included. 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.

Recordings — the detail page

Everything stored for one run: the prompt, each step with its arguments and output, the final answer, and the scenario if there is one. This is where you press Calculate, read what calculation produced, and run the dry replay that is worth doing before you trust anything. There is no Recalculate button: a calculation that failed is run again by preferring the recording, which resets it and starts a fresh job. From the command line it is still bir scenario calc --force.

A recording's page: the prompt, the agent's answer, the steps, and the scenario on the right
A recording, opened. Top to bottom: the name and when it ran; the exact prompt; the agent's answer; each tool call with what it sent and what came back. On the right, the scenario calculated from it, pictured up close in section One.

It is also where you overrule the service's pick, in either direction. ☆ Prefer this recording calculates this one straight away, and takes nothing from anybody: you may hold as many scenarios as you like, so nothing has to be replaced to make room. A preferred recording is also first in line whenever the service looks for something to calculate on its own, whatever its hit count, and is kept however short it is. The opposite switch is Disable calculation, which tells the service to leave a recording alone: it is never picked automatically, and while the switch is set a matching prompt is not replayed from its scenario either. A recording is preferred, switched off, or neither.

Switch off calculation and replay is the opposite instruction: the service never picks that recording on its own, however often its prompt comes back and however much it has at stake — and while it is off, a matching prompt is not replayed from its scenario either: the agent runs again and nothing is saved. The scenario is kept, and comes back when you switch calculation and replay on again. The two are one switch, so each button is offered only while the other flag is not set: a recording is preferred, switched off, or neither. Two badges beside them are about the server rather than the recording — server cannot calculate when the deployment has no Anthropic key and nothing can be calculated on it at all, no automatic calculation when the key is there and only the picking is switched off, which leaves Prefer working.

What it costs

The service here is free. Recording, calculating, replaying, as many scenarios as you like, and none of them expires. There is no card, no balance and no fee. Your recordings are stored on our server in Germany, and the page on security and privacy says exactly what that means.

That last sentence is what we sell. A recording holds the request you typed, every tool call, and everything those tools returned — file contents, query rows, whatever a browser fetched. Plenty of companies cannot keep that on somebody else’s server, whatever the terms say. For them there is BaseInst In-house: the same service as a container you run inside your own network, at $5 per person per month. A person is someone with an account on your instance, however many machines they record from. There is no minimum, and a 30-day trial key needs no card. If you would rather not run it yourself, we will host a separate instance for you under your own address, at the same price.

One thing to be exact about, because it is the part people assume away: an in-house instance still sends data to Anthropic, on your own key and under your own account. The whole recording when it calculates a scenario; a short excerpt when it writes a recording’s title; the new request and the scenario’s parameters when a replay works out what to pass. By default nothing else leaves the network. Everything that could — your mail relay, sign-in with Google, licence renewal, certificates — is something you switch on.

To talk about running it in-house, write to support@bi2202.com.

Reading the numbers honestly

  1. 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.

  2. 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.

  3. Believe a negative

    A scenario flagged as not paying off is costing you money on its recent runs. The two useful responses are to retire it (delete the recording) or to replace it by preferring a different recording; both beat looking away.

Four

How to record

Everything starts with a recorded run. The recorder is BaseInstRunnerbir — which lives in its own repository, BaseInstRunnerMCP. Getting started installs it in about ten minutes.

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.

Getting started — install the runner

The beginner's path: one computer, Claude Code, and the runner installed from npm. Allow about ten minutes, most of it waiting for downloads. Nothing here needs a copy of the runner's source code. Signed in to the console, the same six steps are on its Set up the runner page, with your account filled in and a line that turns green when your first recording arrives.

The steps below, done once on a Windows machine. A small project to record, the task run by hand, then the install, the wrap, the sign-in, the recorder, and the first verified saving. 7 min 54 s, silent; the step being done is named in the corner. The desktop is wide, so watch it full screen.
  1. 0:00The handbook
  2. 0:06Step 2 · A small project to record
  3. 0:38The task, before the runner
  4. 1:34Step 1 · Install the runner
  5. 1:48Step 3 · Wrap the project
  6. 2:03Step 4 · Sign in
  7. 3:24Step 5 · Record
  8. 4:10The run in Recordings
  9. 5:31Calculated
  10. 6:52Replay
  11. 7:33Verified saving
Before you start

Five things must be true. The steps below do none of them for you.

  • You have a BaseInst account. Register at bi2202.com, open the link in the verification email, and sign in once. Stay signed in — step 4 approves the runner from that same browser session, and that is how the runner learns which account it belongs to. There is no account name or identifier to type anywhere.
  • Claude Code is installed and starts when you type claude. The runner wires itself into Claude Code's settings; it does not install Claude Code.
  • Something to record. The runner records MCP tool calls, so it needs a project with at least one MCP server — a .mcp.json in the project folder, or servers listed in ~/.claude.json. If you do not have one, that is fine: step 2 builds you a small, real one in about a minute. You do not need to go and find a project first.
  • Node 20 or newer. Type node -v in a terminal. v20. or higher is fine. Anything lower, or an error, means: install the LTS build from nodejs.org, close the terminal, open a new one, and check again.
  • On Windows, use PowerShell — not cmd.exe. Every Windows command on this page is PowerShell. In cmd, # does not start a comment (it is passed to the program, so npm install … # note fails with EINVALIDTAGNAME) and $env:VAR = "…" is not valid at all. Open Windows PowerShell or Terminal from the Start menu.
  1. Install the runner

    Two lines. The first installs the runner. The second gives it the address of BaseInst, once, for every terminal you open from now on.

    npm install -g @basein/runner
    setx BIR_AUTH_URL https://api.bi2202.com
    npm install -g @basein/runner
    echo 'export BIR_AUTH_URL=https://api.bi2202.com' >> ~/.zprofile
    npm install -g @basein/runner, answered with: added 1 package in 1s
    You should see one line from the first command, added 1 package. The second prints SUCCESS on Windows and nothing on macOS. That is the whole install.

    Then close the terminal and open a new one before going on. The address only reaches a terminal opened after it was set.

    This puts four commands on your PATH: bir, bir-hooks, bir-proxy and bir-scenario. You only ever type the first two.

    Windows: if this says "running scripts is disabled on this system", PowerShell is blocking npm's own launcher. Allow scripts for your account with Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, answer Y, and run the install again.

  2. Make something to record

    The runner records MCP tool calls, so it needs a project with at least one MCP server in it. If you already have one — a .mcp.json in the folder, or servers listed in ~/.claude.json — use that project and go on to the next step.

    If you do not have one, build a small one now. It takes a minute, needs nothing but Node, and gives you a task worth recording rather than a toy that records nothing.

    mkdir fleet-demo
    cd fleet-demo

    Save this into it as fleet-server.js:

    #!/usr/bin/env node
    /**
     * A tiny, real MCP server over stdio — the thing `bir-proxy` will wrap.
     *
     * Two tools, chosen so a scenario built from them has to thread state:
     *   list_devices(fleet)  -> the fleet's devices, with risk scores
     *   device_detail(id)    -> one device's detail
     *
     * Step 2 of a scenario can only compute its `id` argument from step 1's output,
     * which is exactly what `respParams` threading is for.
     */
    
    const FLEETS = {
      "eu-west-1": [
        { id: "dev_88f1", name: "edge-01", risk: 0.94, firmware: "3.1.2" },
        { id: "dev_2c30", name: "edge-02", risk: 0.31, firmware: "3.2.0" },
        { id: "dev_9a05", name: "edge-03", risk: 0.62, firmware: "3.1.9" },
      ],
      "us-east-2": [
        { id: "dev_4411", name: "core-01", risk: 0.77, firmware: "2.9.4" },
        { id: "dev_7b22", name: "core-02", risk: 0.12, firmware: "3.2.0" },
      ],
    };
    
    const TOOLS = [
      {
        name: "list_devices",
        description: "List the devices in a fleet, with their risk scores.",
        inputSchema: {
          type: "object",
          properties: { fleet: { type: "string", description: "Fleet id, e.g. eu-west-1" } },
          required: ["fleet"],
        },
      },
      {
        name: "device_detail",
        description: "Full detail for one device.",
        inputSchema: {
          type: "object",
          properties: { id: { type: "string", description: "Device id, e.g. dev_88f1" } },
          required: ["id"],
        },
      },
    ];
    
    function callTool(name, args) {
      if (name === "list_devices") {
        const devices = FLEETS[args.fleet] ?? [];
        const worst = [...devices].sort((a, b) => b.risk - a.risk)[0];
        return {
          fleet: args.fleet,
          count: devices.length,
          devices,
          worstDeviceId: worst ? worst.id : null,
        };
      }
      if (name === "device_detail") {
        for (const devices of Object.values(FLEETS)) {
          const found = devices.find((d) => d.id === args.id);
          if (found) return { ...found, lastSeen: "2026-08-31T09:12:00Z", status: "online" };
        }
        return { error: `unknown device: ${args.id}` };
      }
      throw new Error(`unknown tool: ${name}`);
    }
    
    // ── minimal MCP stdio plumbing (newline-delimited JSON-RPC) ─────────────────
    let buf = "";
    process.stdin.on("data", (chunk) => {
      buf += chunk.toString("utf8");
      let nl;
      while ((nl = buf.indexOf("\n")) >= 0) {
        const line = buf.slice(0, nl).trim();
        buf = buf.slice(nl + 1);
        if (line) handle(JSON.parse(line));
      }
    });
    
    const send = (msg) => process.stdout.write(JSON.stringify(msg) + "\n");
    const reply = (id, result) => send({ jsonrpc: "2.0", id, result });
    
    function handle(msg) {
      const { id, method, params } = msg;
      if (id === undefined || id === null) return; // notification
      switch (method) {
        case "initialize":
          return reply(id, {
            protocolVersion: params?.protocolVersion ?? "2025-06-18",
            capabilities: { tools: {} },
            serverInfo: { name: "fleet", version: "1.0.0" },
          });
        case "tools/list":
          return reply(id, { tools: TOOLS });
        case "ping":
          return reply(id, {});
        case "tools/call": {
          try {
            const out = callTool(params.name, params.arguments ?? {});
            // A normal MCP result: a text block holding JSON.
            return reply(id, { content: [{ type: "text", text: JSON.stringify(out) }], isError: false });
          } catch (err) {
            return reply(id, { content: [{ type: "text", text: String(err.message) }], isError: true });
          }
        }
        default:
          return send({ jsonrpc: "2.0", id, error: { code: -32601, message: `no method ${method}` } });
      }
    }
    
    // Diagnostics go to stderr. A stray byte on stdout corrupts the JSON-RPC stream.
    process.stderr.write("fleet-server: ready\n");

    That is a real MCP server, not a mock: 111 lines, no dependencies, speaking newline-delimited JSON-RPC over stdio exactly as any other MCP server does. It holds two fleets of pretend devices and offers two tools:

    list_devices(fleet) → the fleet's devices, with risk scores
    device_detail(id)   → one device's detail

    Two tools chosen for one reason: step 2 of a scenario can only work out its id argument from step 1's output. That makes it the smallest honest test of whether scenario calculation really works, rather than the smallest test that passes.

    Now tell Claude Code the server is there. Save this as .mcp.json in the same folder:

    {
      "mcpServers": {
        "fleet": {
          "command": "node",
          "args": ["fleet-server.js"]
        }
      }
    }

    You should end up with those two files and nothing else. Do not start the server yourself — Claude Code launches it when it needs it, and after the next step bir sits in between.

  3. Wrap the project

    In a terminal opened after step 1, go to the project folder and run one command:

    cd path\to\your\project
    bir install --global
    cd ~/path/to/your/project
    bir install --global

    A healthy run ends like this:

      + chrome-devtools -> bir-proxy (project scope, upstream: npx)
      + hooks -> .../.claude/settings.json
    
    Wrapped 1 server.

    bir install rewrites the project's MCP entries in place — every server keeps its name, so nothing the model sees changes — and wires Claude Code's hooks. It keeps a copy of every file it touches, and bir uninstall puts them back byte for byte. If it prints No MCP servers found for this directory. Nothing to wrap., you are in a folder with no MCP servers configured — go back to step 2 and build the demo one, or cd to a project that already has them.

    bir install --global: fleet already wrapped, hooks written to .claude/settings.json, and what to do next
    The same command on a project wrapped once before, so fleet reads = already wrapped and the count is 0; on a first run that line starts with + and the count is 1. The two lines after Next: are the point — run bir-hooks, or only tool calls are recorded.
  4. Sign in

    bir login

    This opens your browser at bi2202.com/activate and shows a short code in the terminal, like FQSB-JCNQ. Check that the code on the page matches the one in your terminal, approve it, and the terminal finishes by itself. You never type a password into the terminal. The code is good for ten minutes; if it expires, run bir login again.

    This is the moment the runner is tied to your account. There is no account name or identifier to type anywhere: whichever account is signed in in the browser that presses Approve is the account this terminal signs in as. The page says so, under Will sign in as, and the terminal confirms it with Signed in to … as you@example.com. From then on every recording from this computer goes to that account, until you run bir logout. If the page names the wrong account, press Deny, sign out of the site, sign in as the right one, and run bir login again.

    Prefer no browser step? Signed in to the console, its Set up the runner page makes a one-time setup token that is already tied to your account. Paste it within ten minutes, in the project folder:

    bir login --token <the token from the page>

    It needs runner 0.2.1 or newer, and it is used once.

    On a machine with no browser — a server over SSH, a container — use bir login --no-browser. It prints the address and the code instead of opening anything, so you can approve it from your laptop.

    You are not asked again; the session is cached under ~/.baseinstrunner, and bir logout revokes it.

    bir login in the terminal, and the browser page it opens: Approve a sign-in, showing the same code
    The code in the terminal and the code on the page are the same — that is the check. Press Approve and the terminal finishes by itself. The blurred line is the machine's public address, shown so you can tell your own request from someone else's; if you did not just run bir login, press Deny.
  5. Record

    Two terminals, both in the project folder. That is how the two halves of the recorder find each other; a different folder in one of them means your prompts are not recorded.

    What the recorder sends, and what it strips out first, is under Security and privacy, section Five.

    Terminal A — leave this running the whole time:

    bir-hooks
    bir-hooks running: auth.ok, replay.enabled, control.listening
    Three lines, then it waits: signed in, replay armed for this folder, listening for the session. Leave the window open. The session itself looks like the run pictured under Record, in section One.

    Terminal B — your normal work, now recorded:

    claude

    If you built the demo in step 2, ask for "check the eu-west-1 fleet and tell me which device is most at risk". In the sample data the answer is dev_88f1edge-01, risk 0.94, on firmware 3.1.2: two tool calls, plus the model's turns around them.

    Otherwise, give the agent a real task — one that takes at least four tool calls. A run with three or fewer is kept but not listed, because there is no plan worth reusing in a couple of calls. When the run finishes, terminal A prints a line like:

    [bir] …  run.finish  run=run_… steps=14 durationMs=48210 lossy=false recorded=true

    Now open Recordings at bi2202.com. The run is there, with its title, its step count and what it cost. The demo task is a small one and sits near the four-step minimum — if it does not appear, that is why: ask a second thing in the same session ("and check us-east-2 as well") and it will clear the threshold comfortably. When you are done for the day, Ctrl+C in terminal A. It does not start itself after a reboot — start it again next time, in the project folder.

  6. Check it

    With bir-hooks still running, in a third terminal in the project folder:

    bir doctor

    This is the one command worth remembering. It does not read a settings file and tell you what should happen; it asks the running system what is happening, and says so loudly when something is broken. bir status shows the configuration without needing anything running.

    bir doctor with bir-hooks running: recording tier bound (Tier 1), recording yes, one problem listed
    Healthy: bound (Tier 1) and Recording: yes. The one problem listed only says that no agent session was open at that moment; start claude and it goes away.
    bir doctor without bir-hooks: control server not running, standalone (Tier 2)
    Not healthy: not running and standalone (Tier 2) mean bir-hooks is not running in this folder. Tool calls would be recorded, your prompt would not, and nothing could ever match.

If something is wrong

What you seeWhat it means
bir is not recognised / bir: command not foundThe terminal predates the install. Close it and open a new one.
running scripts is disabled on this system (Windows)PowerShell is blocking npm's launcher. Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, then try again.
BIR_AUTH_URL not set — nothing is recorded in bir statusThe address from step 1 has not reached this terminal. Close it and open a new one. If a terminal inside an editor still says this on macOS, add the same export line to ~/.zshrc as well; on Linux, or in bash, use ~/.bashrc instead of ~/.zprofile.
not signed in — run bir loginStep 4 was skipped, or the session expired. Run bir login again.
The run was recorded, but it is not in your RecordingsThe runner is signed in as a different account: whichever one pressed Approve in step 4. Run bir logout, sign in to the site as the right account, and run bir login again.
No MCP servers found for this directoryThis folder has no .mcp.json and no servers in ~/.claude.json. Build the demo server in step 2, or cd to a project that already has one.
Tools are recorded, but not what you typedbir-hooks is not running, or is running in a different folder. Stop it, cd to the project folder, start it again.
The run finished but is not in RecordingsThree tool calls or fewer. Give the agent a bigger task.
Anything elseRun bir doctor and keep the output. It names the broken link in the chain.
Typing bir before the install: 'bir' is not recognized as an internal or external command
The first row, as it looks. A terminal opened before the install does not know the word yet.

Undoing it. In the project folder, bir uninstall puts every file it touched back exactly as it was; npm rm -g @basein/runner removes the software as well.

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.

The guarantee

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.

The limit

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

TierWhenWhat ends up in the recording
1 — Boundbir-hooks is discoverable for this working directoryBuilt-ins and MCP, in one ordered step stream, with the prompt and the final answer
2 — StandaloneNo control server found within five secondsMCP 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

The beginner's path is Getting started above: npm install -g @basein/runner, set BIR_AUTH_URL, bir install --global, bir login. Working on the runner itself? From a checkout of BaseInstRunnerMCP, build it and point the install at the checkout instead of the published package:

npm install; npm run build
$env:BIR_AUTH_URL = "https://api.bi2202.com"
node dist/bin/bir.js install --local    # this checkout's proxy, not npx
node dist/bin/bir.js login
npm install && npm run build
export BIR_AUTH_URL=https://api.bi2202.com
node dist/bin/bir.js install --local    # this checkout's proxy, not npx
node dist/bin/bir.js login

For a fleet of machines, the runner repository ships one-command installers in scripts/ that do the whole of Getting started in one go; see its docs/quickstart.md and docs/installRun.md.

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.

Terminal A — leave running:

bir-hooks

Terminal B — your session, now recorded:

claude

And in a third terminal, whenever you want to know where you stand:

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.

Rule one

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.

Rule two

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:

cmd /c "bir-hooks 2>&1" | Tee-Object -Append -FilePath $HOME\.baseinstrunner\audit.log
bir-hooks 2>&1 | tee -a ~/.baseinstrunner/audit.log

Do not simplify the Windows one to bir-hooks 2>&1 | …. Windows PowerShell wraps every stderr line from a native program in a NativeCommandError record, so the log fills with At line:1 char:1 blocks instead of bir's key=value lines. Letting cmd merge the two streams first means PowerShell only ever sees stdout, and both the console and the file stay clean.

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 what it points at 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 — with one exception: the console has no Recalculate button, so a failed calculation is run again there by preferring the recording.

Or do nothing. Once a prompt has come back three times (SCENARIO_AUTO_MIN_HITS) and the run it keeps matching passed end to end — it finished without an error and no tool call in it failed — the service calculates the recording with the most to save by itself, and the console marks it auto. A run has to have been quiet for ten minutes first (SCENARIO_AUTO_SETTLE_MS): a session that has just finished is often still sending steps. It never deletes anything and never retries a failed calculation, and it works through one calculation at a time per account. Or say which ones to leave alone: press Disable calculation on a recording's page and the picker never chooses it, however often its prompt comes back — though you can still calculate it yourself. Or say which one you want: press ☆ Prefer this recording on its page. It is calculated straight away and takes nothing from anything else you hold. SCENARIO_AUTO_CALCULATE=false leaves calculation entirely to the button.

Do this every time

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
$env:BIR_REPLAY = "1"; bir-hooks   # and this is the actual switch
bir install --replay      # adds the `bir` MCP server
BIR_REPLAY=1 bir-hooks    # and this is the actual switch
Read this before enabling it anywhere that matters

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

VariableEffect
BIR_AUTH_URLThe BaseInst service. Unset means nothing is recorded — everything else still works
BIR_CONTROL_PORTPreferred control-server port (default 53411)
BIR_CORRELATION_DECISIONallow (default) or ask. Correlation auto-approves wrapped MCP calls; ask keeps the prompt, at the cost of lossier matching
BIR_HOMEWhere state lives (default ~/.baseinstrunner)
BIR_VERBOSE=1Per-message detail on stderr
BIR_REPLAY=1Enable replay. Nothing else about replay matters until this is set
BIR_REPLAY_ALLOW_SERVERSServer keys eligible for direct execution. Set this
BIR_MIN_STEER_SIMILARITYMinimum match similarity to replay (default 0.92)
ANTHROPIC_API_KEYEnables 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.

SymptomCauseFix
Nothing appears in the consoleBIR_AUTH_URL unset, or not signed inbir login; check bir doctor
tier: standalonebir-hooks not running, or not for this cwdStart it in the project directory
Recorded, but not in the listThree actions or fewerNothing to fix — below the threshold on purpose
recorded=falseThe service matched it to an existing runWorking as intended
No prompt ever matchesSimilarity detection off, or the prompts really are differentCheck SIMILARITY_DETECTION_ENABLED; re-read the prompt you wrote
Calculate returns 503No Anthropic key on the serverServer-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 uses the fleet-demo folder you built in step 2 of Getting started: 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
Why these two tools

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.

  1. Set up the project

    This is the fleet-demo folder from step 2. If you have not built it yet, go back and do that first — two files and a minute. BIR_AUTH_URL is already set permanently, from step 1, so there is nothing to export here.

    cd fleet-demo
    bir install --global --replay
    bir login

    --replay adds the scenario server now, so step 7 needs no second install. --global invokes the installed package by absolute path instead of going through npx — no registry round trip each time a server starts, and one less thing to go wrong. bir install rewrites .mcp.json so the fleet server runs through bir-proxy, and writes .claude/settings.json for the hooks; both are generated for your machine, absolute paths and control-server port included. It keeps a copy of everything it touches, and bir uninstall puts it all back byte for byte.

  2. Start the control server

    In its own terminal, from the same directory: bir-hooks. Watch for tier=bound. If it says standalone, the control server and the session disagree about either the working directory or the port — the only two things discovery matches on.

  3. Record the run

    In a second terminal, in the same folder, start Claude Code and ask it the task:

    claude

    Ask for "check the eu-west-1 fleet and tell me which device is most at risk". The two tool calls go past in the control-server terminal, then a run.finish line.

  4. 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.

  5. Calculate the scenario — and read it

    bir scenario list                 # find the run id
    bir scenario calc run_…
    bir scenario show run_…

    Read what comes back before going further. You are looking for three things:

    • an intent that describes the task, not the specific fleet;
    • fleet as a parameter with eu-west-1 as 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_88f1 looks identical on a green run and is wrong the moment the data moves.
  6. Dry-replay against a different fleet

    bir scenario replay scn_… --prompt "check the us-east-2 fleet" --dry

    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 marked Result (recorded):. What you are checking is the parameter derivation and the step logic, not the answer.

  7. Replay it for real

    Stop bir-hooks with Ctrl+C and start it again with replay turned on:

    $env:BIR_REPLAY = "1"; $env:BIR_REPLAY_ALLOW_SERVERS = "fleet"
    bir-hooks
    BIR_REPLAY=1 BIR_REPLAY_ALLOW_SERVERS=fleet bir-hooks

    Then in the other terminal start claude again and ask for "check the us-east-2 fleet and tell me which device is most at risk".

    Now the tools are really called. us-east-2's highest-risk device is dev_4411core-01, risk 0.77. That is the proof the scenario computed the answer rather than remembering it.

  8. 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. Saved %/run is the same verdict per run at a glance — a green bar is a cut, a red one is a loss. 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. There is another demo of the same shape with a longer chain — list_services, service_metrics, error_logs, recent_deploys, dependency_graph. It lives in the runner repository, which is not public, so it is not something you can fetch today; the point of it survives without it. Extend the fleet server above until it has five tools, at least one of them needing an argument computed from an earlier step's output. That is 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

Status

One of the four is recorded. Video 2, the install, was filmed on 2026-09-12 and is embedded at the top of Getting started — 7 min 54 s, silent, captioned. The other three are still shot lists and narration, 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.
1 · What is BaseInst? 90 seconds
TimeShotNarration
0:00Terminal: the same task run twice, cost visible both times"Your agent solved this yesterday. Today it paid full price to solve it again."
0:15The record → calculate → replay diagram"BaseInst records the run, derives the plan, and runs the plan next time."
0:35Console: the recording, then its scenario — intent and parameters"A transcript says what the agent did. A scenario says what it was doing."
0:55Dashboard, verified tile, ⓘ open"And it measures what that saved. The number it leads with is the one it watched move."
1:15Recordings list, the savings column"It is free to use. What we sell is running the whole thing inside your own network, when the recordings cannot leave it."
2 · Install and record your first run 4 minutes

The guide, executed. One terminal, one browser window.

Recordedthe film in Getting started. It follows this list loosely: the demo project and one run of the task by hand come first, then the install, and it runs on past the first recording to the scenario being calculated and the saving being verified. It is silent, with the step being done named in the corner, so it was cut without narration; the shot list below is kept as written, for a retake.

  1. npm install -g @basein/runner, bir install --global, bir login — say what install rewrites, and that uninstall reverses it byte for byte.
  2. bir-hooks in a second terminal. Point at tier=bound and say what Tier 2 would mean.
  3. bir doctor. Explain why this is the command to trust, not status.
  4. Run the fleet task. Watch run.start and run.finish go past.
  5. Console → Recordings → the row. Name the columns: Steps, LLM $/run, and the baseline's sample count.
  6. Close on the threshold: "fewer than four actions and it is not kept — there is no plan in a single call."
3 · Calculate a scenario, and check it before you trust it 5 minutes

The video that earns its place, because this is where people get burned.

  1. scenario calc, then scenario show. Read the intent aloud.
  2. Stop on the parameters. fleet: eu-west-1 — a sample value, not a constant.
  3. Stop on step 2's logic. Show it reading step 1's output. Then show, by hand, what a hard-coded dev_88f1 would look like: identical on this run, wrong on the next.
  4. Dry replay against us-east-2. Explain Result (recorded): and why a dry run still shows eu-west-1 devices.
  5. Real replay. dev_4411. "It computed that. It did not remember it."
  6. Close on the ledger row and the not-paying-off flag: "a scenario can cost you money, and this is where it says so."
4 · Reading the console 3 minutes
  1. The sidebar: the sections, and what each one is for.
  2. ⌘K, including the recordings-search row. Say plainly that it does not search everything.
  3. Recordings: verified versus projected, with the ⓘ open. The segment worth over-explaining.
  4. The Saved %/run bars: read one row's two $/run figures against its percentage, then show a red one.
  5. auto in the origin column, and the ★ Preferred and ⊘ Switched off badges under two titles: a row the service calculated by itself, one the user preferred over it, and one they switched off.
  6. The delete confirmation, naming the savings that will leave the headline.

They live in videos/ beside this page, deployed with it, and are embedded beside the section each one covers; the console embeds them from this address, VITE_DOCS_URL. The install film is there. Until the others exist, their written sections stand on their own — which is why they were written to.

Five

Security and privacy

What BaseInst sees, where it goes, how long it stays, and what it does without asking you. This section describes what the software does today, in plain words.

The formal version is the Privacy Policy on the website; where the two differ, the policy is the one that counts. Terms of service will be published separately.

In one paragraph

The runner records what your agent did: the request you typed, every tool call with its arguments and results, the model's reasoning before each call, the final answer, and what it all cost. It strips the secrets it recognises, then sends the rest over HTTPS to your BaseInst account, where only you can see it. Working out a plan from a recording sends that recording to Anthropic. Nothing is sold, nothing is used for advertising, and no analytics run anywhere. You can delete a recording at any time, and everything derived from it goes with it.

What is recorded

One recording is one run of your agent: from the request you typed to the answer it gave. For each run the runner keeps:

  • The request you typed, word for word.
  • Every tool call: the tool's name, the arguments the agent sent, and what came back, or the error if it failed. Calls to the project's MCP servers pass through the runner itself. The agent's built-in tools, such as reading a file or running a shell command, are seen through Claude Code's hooks, which is why bir-hooks has to be running.
  • The model's reasoning written just before each tool call. The runner reads it from the session's transcript file on your own machine and attaches it to the step.
  • The final answer, the model used, token counts, timings and the cost.
  • Run details: which recorder made it, whether the trace is complete or MCP-only, the host application, the names of the wrapped servers, whether any steps were dropped, the session id, and the path of the project folder, which can include your username. An MCP-only run also carries your computer's name.

A recording can therefore contain anything a tool read or returned: the contents of a file the agent opened, the rows a query returned, a page a browser tool fetched. Record only what you are comfortable storing.

What is not recorded. Your password: you never type it into the terminal, because bir login opens the browser, where you approve a code, or takes a one-time setup token made in the console. Anything the agent did not do: the runner does not scan your disk or watch other programs, and sees only what passed through a wrapped server or a hook, in the folder where bir-hooks runs. Sessions in other folders: each project is recorded only while its own bir-hooks is running there.

What is stripped before sending. Redaction runs on your machine, on the copy that is about to be sent, before it is even queued:

  • By name. A value stored under a name that looks secret is replaced with [redacted], whatever it is: token, secret, password, api_key, authorization, cookie, session_id, credential, private_key, access_key, client_secret and their variants.
  • Every value under an env block, because MCP server configurations put credentials there under any name at all.
  • By shape, wherever it appears, including inside free text: bearer tokens, JWTs, sk- keys of the OpenAI and Anthropic kind, GitHub, Slack and Google API keys, and AWS access key ids.
  • Size. A single string is cut at 8 KB and a step at 64 KB. A file a tool returned in full arrives as its first 8 KB.

This is pattern matching, not understanding. A secret stored under an unusual name, or shaped like ordinary text, goes through. Treat a recording the way you would treat a log file from your own machine, and do not wrap a tool that handles data you are not allowed to keep.

Where it goes

WhoWhat they receiveWhen
BaseInst's serverThe recording, as described above, over HTTPSEvery recorded run
AnthropicThe whole recording: reasoning, every tool input and output, and the final answerWhen a scenario is calculated, by you or automatically
AnthropicThe first 1,200 characters of the request, the names of the tools used, and a short excerpt of the first reasoning. Tool outputs and the final answer are deliberately left outWhen a run finishes, to write its title
Anthropic, from your own machineThe new request, the scenario's intent and its parameter samplesOn a replay, only if you set ANTHROPIC_API_KEY on the runner. It uses your key, not ours
PayPalThe invoice reference, the amount and the service's name. You pay on PayPal's own pages; BaseInst never sees a card numberOnly if you buy an in-house licence. Nothing is charged for using the service here
GoogleThat you signed in here; BaseInst receives your Google id, email address and nameOnly if you sign in with Google
ResendYour email address and the one-time linkVerification and password-reset emails
Google FontsThe IP address and browser of whoever opens the pageThis handbook site only. The console loads nothing from anyone else
  • In transit. The runner talks to api.bi2202.com over HTTPS only, and refuses to follow a redirect to a different site while carrying your token.
  • At rest. Recordings are stored in a database on one server, rented from Hetzner in Germany. The application does not encrypt them itself; they are protected by the server and its disk.
  • Who can read them. You, signed in to your own account. There is no administrator screen that shows another account's recordings. The person who operates the server can read the database and the logs directly.
  • Recognising a repeated request is done with a small open-source model that runs on BaseInst's own server. Nothing leaves for that.
  • No analytics, no tracking pixels, no advertising scripts, in the console, the runner or this handbook.

How long it stays, and how to delete it

  • A recording stays until you delete it, from its own page in the console. Deleting it also deletes its steps, its fingerprint, its scenario and its replay history, and the savings it booked leave your totals with it.
  • Very short runs, a couple of tool calls, that were never calculated and never matched are pruned automatically.
  • A scenario does not expire. It stays with its recording, and steers a matching prompt, until the recording is deleted or its owner switches calculation and replay off.
  • Sign-in records keep the time, the method, the IP address and the browser or runner for every sign-in attempt, successful or not. They are kept for as long as the service runs, and your own are shown on your Sign-in history page. A bir login approval shows the runner's address on the approval page and is pruned a day later; a setup token made in the console is the same kind of record.
  • Sessions last thirty days from their last use. An access token lasts a day, a verification link a day, a password-reset link an hour, and a sign-in code ten minutes.
  • Closing your account, from Account settings, removes your profile, your password, your Google link and your sessions. It does not yet remove your recordings, scenarios, replay history or sign-in records. Delete your recordings first, and write to us for the rest.
  • On your own machine the runner keeps your session in ~/.baseinstrunner/credentials.json, readable by your user only, and a copy of every configuration file it changed, so that bir uninstall can put them back. bir logout revokes the session.
  • Server logs hold, for every request, the method, path, status, duration, IP address and, when signed in, your user id. Secrets are masked before they are written. Backups, when they are taken, can hold deleted data until they expire.

What runs without asking you

Three things happen without a prompt, and each is a switch you own.

  1. Wrapped tool calls are approved automatically while recording

    To attach a call id to a tool call, the runner answers Claude Code's permission hook with allow. So a call to a wrapped MCP server that you would otherwise have been asked about is not asked about. Start the recorder with BIR_CORRELATION_DECISION=ask to keep the prompts, at the cost of less exact matching.

  2. Replay is off until you turn it on

    Nothing is replayed unless bir-hooks runs with BIR_REPLAY=1. When it is on, a steered step is approved for the agent, and a step the runner executes directly never reaches the permission system at all. Name the servers you are content to have called that way in BIR_REPLAY_ALLOW_SERVERS, and keep anything destructive, or anything that must not run unattended, off that list.

  3. Calculation can start by itself

    Once the same request has come back three times, the service works out the plan for the best candidate without anyone pressing the button, which sends that recording to Anthropic as described above. Every recording's page has a switch that turns calculation and replay off for that recording.

How the service is protected

  • Passwords are stored as argon2id hashes. Session, verification and reset tokens are random, stored only as hashes, and rotated when used.
  • An email address must be verified before it can sign in. Sign-in and account routes are rate-limited per address.
  • Everything is served over TLS, with strict transport security. The console loads scripts from its own origin only, and the API accepts browser requests from the console's origin only.
  • The API runs as an unprivileged user in a hardened system service that can write to one directory.
  • The runner package has no third-party dependencies at run time, so nothing else is loaded into your agent's process tree.

Your side of it

  • You choose what is recorded: which project, which servers, and when bir-hooks runs. Do not wrap a tool that returns secrets or personal data you are not allowed to store.
  • Delete what you no longer need. A recording is as sensitive as the tools it called.
  • Keep replay off destructive tools. A replayed scenario is a list of tool calls you recorded, run again with computed arguments. What those calls do is yours.
  • On a shared machine, run bir logout when you finish.

Reporting a security problem

Write to support@bi2202.com, the address on the Privacy Policy. Describe what you found and how to reproduce it, and please do not post it publicly before we have replied.

This section describes the runner at version 0.2.0 and the service as deployed on 2026-09-11. It is a statement of practice, not a contract; the Privacy Policy governs, and terms of service will be published separately. When the software changes in a way that matters here, this section changes with it.