@basein/runner 0.2.12 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +540 -369
  2. package/dist/auth/client.d.ts +65 -3
  3. package/dist/auth/client.js +305 -53
  4. package/dist/bin/bir-hooks.d.ts +72 -31
  5. package/dist/bin/bir-hooks.js +176 -284
  6. package/dist/bin/bir-proxy.d.ts +17 -2
  7. package/dist/bin/bir-proxy.js +222 -28
  8. package/dist/bin/bir-scenario.d.ts +61 -21
  9. package/dist/bin/bir-scenario.js +593 -122
  10. package/dist/bin/bir.d.ts +12 -6
  11. package/dist/bin/bir.js +2935 -489
  12. package/dist/bin/investigate.js +40 -15
  13. package/dist/bin/scenario-edit.d.ts +7 -1
  14. package/dist/bin/scenario-edit.js +43 -21
  15. package/dist/bin/scenario-liveness.d.ts +194 -0
  16. package/dist/bin/scenario-liveness.js +459 -0
  17. package/dist/bin/scenario-stderr.d.ts +43 -0
  18. package/dist/bin/scenario-stderr.js +76 -0
  19. package/dist/bin/service-read.d.ts +88 -0
  20. package/dist/bin/service-read.js +128 -0
  21. package/dist/bin/setup.d.ts +19 -0
  22. package/dist/bin/setup.js +146 -20
  23. package/dist/config/adapters/claude-code.d.ts +92 -14
  24. package/dist/config/adapters/claude-code.js +291 -101
  25. package/dist/config/adapters/generic.d.ts +4 -1
  26. package/dist/config/adapters/generic.js +13 -14
  27. package/dist/config/generate.d.ts +392 -14
  28. package/dist/config/generate.js +666 -19
  29. package/dist/config/mcp-approval.d.ts +76 -0
  30. package/dist/config/mcp-approval.js +210 -0
  31. package/dist/config/node-path.d.ts +42 -0
  32. package/dist/config/node-path.js +102 -0
  33. package/dist/config/overrides.d.ts +62 -0
  34. package/dist/config/overrides.js +136 -0
  35. package/dist/config/resolve.d.ts +70 -8
  36. package/dist/config/resolve.js +186 -15
  37. package/dist/control/client.d.ts +22 -0
  38. package/dist/control/client.js +26 -7
  39. package/dist/control/correlation.d.ts +23 -5
  40. package/dist/control/correlation.js +0 -0
  41. package/dist/control/daemon.d.ts +400 -18
  42. package/dist/control/daemon.js +1105 -102
  43. package/dist/control/discovery.d.ts +77 -5
  44. package/dist/control/discovery.js +186 -11
  45. package/dist/control/ensure-hook.d.ts +61 -0
  46. package/dist/control/ensure-hook.js +160 -8
  47. package/dist/control/paths.d.ts +26 -0
  48. package/dist/control/paths.js +34 -0
  49. package/dist/control/pin-guard.d.ts +83 -0
  50. package/dist/control/pin-guard.js +534 -0
  51. package/dist/control/recorder-keeper.d.ts +229 -0
  52. package/dist/control/recorder-keeper.js +721 -0
  53. package/dist/control/recorder-main.d.ts +73 -0
  54. package/dist/control/recorder-main.js +778 -0
  55. package/dist/control/server.d.ts +707 -31
  56. package/dist/control/server.js +2787 -302
  57. package/dist/control/transcript.d.ts +21 -1
  58. package/dist/control/transcript.js +378 -112
  59. package/dist/index.d.ts +5 -1
  60. package/dist/index.js +5 -1
  61. package/dist/jsonrpc/framing.d.ts +76 -12
  62. package/dist/jsonrpc/framing.js +216 -59
  63. package/dist/proxy/intercept.d.ts +49 -5
  64. package/dist/proxy/intercept.js +188 -59
  65. package/dist/proxy/relay.d.ts +16 -0
  66. package/dist/proxy/relay.js +77 -5
  67. package/dist/proxy/revive.d.ts +122 -0
  68. package/dist/proxy/revive.js +251 -0
  69. package/dist/proxy/session.d.ts +222 -14
  70. package/dist/proxy/session.js +708 -99
  71. package/dist/record/recorder.d.ts +51 -3
  72. package/dist/record/recorder.js +3 -0
  73. package/dist/record/redact.d.ts +103 -9
  74. package/dist/record/redact.js +659 -30
  75. package/dist/record/remote-recorder.d.ts +327 -32
  76. package/dist/record/remote-recorder.js +1517 -187
  77. package/dist/record/switchable-recorder.d.ts +126 -0
  78. package/dist/record/switchable-recorder.js +351 -0
  79. package/dist/record/truncate.d.ts +40 -1
  80. package/dist/record/truncate.js +111 -4
  81. package/dist/replay/bash-channel.d.ts +35 -0
  82. package/dist/replay/bash-channel.js +133 -0
  83. package/dist/replay/bundle.d.ts +10 -0
  84. package/dist/replay/bundle.js +10 -0
  85. package/dist/replay/controller.d.ts +369 -20
  86. package/dist/replay/controller.js +1176 -107
  87. package/dist/replay/derive.d.ts +1 -0
  88. package/dist/replay/derive.js +81 -24
  89. package/dist/replay/executor.d.ts +51 -16
  90. package/dist/replay/executor.js +114 -41
  91. package/dist/replay/handover.d.ts +54 -1
  92. package/dist/replay/handover.js +55 -5
  93. package/dist/replay/logic.d.ts +62 -10
  94. package/dist/replay/logic.js +140 -22
  95. package/dist/replay/plan.d.ts +201 -27
  96. package/dist/replay/plan.js +581 -141
  97. package/dist/replay/safety.d.ts +72 -0
  98. package/dist/replay/safety.js +303 -0
  99. package/dist/replay/source-run.d.ts +10 -0
  100. package/dist/replay/source-run.js +80 -35
  101. package/dist/replay/targets.d.ts +15 -1
  102. package/dist/replay/targets.js +62 -4
  103. package/dist/replay/tool-error.d.ts +15 -1
  104. package/dist/replay/tool-error.js +33 -1
  105. package/dist/replay/types.d.ts +7 -4
  106. package/dist/upstream/client.d.ts +56 -3
  107. package/dist/upstream/client.js +61 -4
  108. package/dist/upstream/headers.d.ts +43 -0
  109. package/dist/upstream/headers.js +90 -0
  110. package/dist/upstream/http-client.d.ts +213 -22
  111. package/dist/upstream/http-client.js +1034 -168
  112. package/dist/upstream/http-transport.d.ts +143 -0
  113. package/dist/upstream/http-transport.js +391 -0
  114. package/dist/upstream/lazy-client.d.ts +8 -0
  115. package/dist/upstream/lazy-client.js +29 -1
  116. package/dist/upstream/sse.d.ts +78 -0
  117. package/dist/upstream/sse.js +189 -0
  118. package/dist/upstream/stdio-client.d.ts +61 -1
  119. package/dist/upstream/stdio-client.js +356 -33
  120. package/dist/util/atomic-write.d.ts +29 -0
  121. package/dist/util/atomic-write.js +96 -0
  122. package/dist/util/journal.d.ts +15 -0
  123. package/dist/util/journal.js +48 -3
  124. package/dist/util/log.d.ts +10 -0
  125. package/dist/util/log.js +28 -1
  126. package/dist/util/off-switch.d.ts +46 -0
  127. package/dist/util/off-switch.js +91 -0
  128. package/dist/util/service-health.d.ts +133 -0
  129. package/dist/util/service-health.js +217 -0
  130. package/docs/BaseInstRunner.md +694 -621
  131. package/docs/calculatedReplay.md +1625 -1304
  132. package/docs/calculatedReplayGuide.md +1212 -1087
  133. package/docs/installRun.md +1013 -772
  134. package/docs/loginWeb.md +627 -607
  135. package/docs/mcpmark.md +49 -16
  136. package/docs/my-first-sample.md +569 -545
  137. package/docs/quickstart.md +384 -311
  138. package/docs/t-bench.md +406 -394
  139. package/package.json +58 -57
  140. package/production.md +1371 -0
  141. package/scripts/install.ps1 +97 -6
  142. package/scripts/install.sh +104 -7
@@ -1,311 +1,384 @@
1
- # Setting up a runner machine
2
-
3
- One person, one computer: from nothing to a project whose every Claude Code
4
- session is recorded and whose calculated scenarios run. It takes a few minutes,
5
- most of them downloads. Nothing has to stay open afterwards.
6
-
7
- **What you are setting up.** BaseInstRunner sits between Claude Code and the
8
- tools it uses, records each session to the BaseIn service, and — when a new
9
- prompt means the same thing as one it has seen — runs the calculated scenario
10
- instead of letting the model rediscover the plan. Otherwise it does not change
11
- what the model does.
12
-
13
- ---
14
-
15
- ## Before you start
16
-
17
- A BaseIn account. That is all: Node and Claude Code are installed for you if the
18
- machine has neither. On Windows use PowerShell or cmd, whichever your terminal
19
- is; the console shows a line for each.
20
-
21
- ---
22
-
23
- ## Step 1 — paste the line
24
-
25
- Sign in to the console and open **Set up the runner**. The first thing on the
26
- page is one line with a one-time setup token filled in (valid for ten minutes,
27
- usable once). Open a terminal **in the project folder you start Claude Code in**
28
- and paste it:
29
-
30
- ```powershell
31
- $env:BIR_SETUP_TOKEN="<token>"; irm https://api.bi2202.com/install.ps1 | iex
32
- ```
33
-
34
- ```cmd
35
- powershell -NoProfile -Command "$env:BIR_SETUP_TOKEN='<token>'; irm https://api.bi2202.com/install.ps1 | iex"
36
- ```
37
-
38
- ```bash
39
- curl -fsSL https://api.bi2202.com/install.sh | BIR_SETUP_TOKEN="<token>" sh
40
- ```
41
-
42
- Without a token — it expired, or you are not at the console — the same line
43
- without the `BIR_SETUP_TOKEN` part works: `bir setup` uses the sign-in already
44
- cached on this computer if there is one, and otherwise opens your browser to
45
- approve the sign-in and waits. Over SSH it prints the link and a short code
46
- instead; they work from any device, a phone included.
47
-
48
- The script prints a `==>` line per stage and never asks a question. Before it
49
- downloads anything it checks that this is not your home folder or a drive root;
50
- if it is, it stops and asks you to `cd` to the project and paste again. Then:
51
-
52
- 1. **Node.** A Node 20+ on PATH is used when npm sits beside it and nothing
53
- can move it: a Node from nvm, fnm, Volta, asdf, mise or nodenv changes path
54
- per shell or per version, and so does one from Homebrew or snap (macOS and
55
- Linux) or Scoop (Windows) — a `brew upgrade` moves the path the hook pins.
56
- Any of those, or no Node at all, and a private copy goes under
57
- `~/.baseinstrunner/node/v<version>/`. It is never put on your PATH.
58
- 2. **The runner.** `@basein/runner` is installed under `~/.baseinstrunner/npm/`,
59
- with `bir` and `bir-hooks` launchers in `~/.baseinstrunner/bin/`, which goes
60
- first on your user PATH. No execution-policy change on Windows.
61
- 3. **Claude Code.** Installed with its official installer if `claude` is not on
62
- PATH. This can take a minute.
63
- 4. **`bir setup`**, which prints:
64
-
65
- ```
66
- ==> Setting up the runner (0.2.9)
67
- service https://api.bi2202.com
68
- account you@example.com
69
- ==> Wiring the project
70
- + chrome-devtools → bir-proxy (project scope, upstream: npx)
71
- + bir → bir-scenario (calculated replay; project scope)
72
- + hooks → C:\work\repo\.claude\settings.local.json (control server on http://127.0.0.1:53411; the recorder starts itself with each session)
73
- + .claude/settings.local.json is listed in C:\work\repo\.git\info\exclude
74
-
75
- Wrapped 1 server.
76
- …
77
- ==> Starting the recorder in the background
78
-
79
- Done. Recording and replay are on for C:\work\repo
80
- account you@example.com (https://api.bi2202.com)
81
- wrapped chrome-devtools
82
- replay on — direct execution allowed for: all wrapped (narrow it with `bir replay allow chrome-devtools`)
83
- recorder started in the background (pid 1234) — it starts itself with every Claude Code session
84
- log C:\Users\you\.baseinstrunner\logs\3f9c1a2b7d4e5f60.log
85
-
86
- Now: claude
87
- first time in this folder: say Yes to "trust this folder"
88
- just installed Claude Code? it asks you to sign in to Claude (it needs a Claude subscription)
89
- give it a task that takes 4+ tool calls — it appears at https://bi2202.com/recordings within a minute of finishing
90
- Any time: bir doctor bir investigate bir down (stop) bir uninstall (undo)
91
- ```
92
-
93
- Line by line: *service* is the API address, now stored so no terminal needs
94
- `BIR_AUTH_URL`; *account* is who the recordings belong to; *wrapped* is the
95
- project's MCP servers, each now routed through `bir-proxy` under its old name;
96
- *replay* says which of them a calculated scenario may call unattended — narrow
97
- it with `bir replay allow <names>`, turn it off with `bir replay off`, and read
98
- [calculatedReplayGuide.md §5.1](calculatedReplayGuide.md) before leaving it wide
99
- anywhere that matters; *recorder* is the background process, and *log* is where
100
- its audit lines go.
101
-
102
- A project with no MCP servers in any scope — none in `.mcp.json`, and none for
103
- this project or your user in `~/.claude.json` — shows `wrapped (no MCP servers
104
- here)` and `replay steer mode only`: built-in tools and prompts are still
105
- recorded, and a scenario still steers the session, but there is nothing to
106
- execute directly.
107
-
108
- Pasted in the home folder anyway? The script stops before it downloads anything
109
- — `This is your home folder. Open a terminal in the project you start Claude
110
- Code in (cd there) and paste the line again.` Nothing was installed, nobody was
111
- signed in and the token is unused, so `cd` to the project and paste the same
112
- line. It is `bir setup` run by hand in the home folder, with the runner already
113
- installed, that keeps the sign-in and prints the two commands left:
114
- `cd <your project>` and `bir setup`. No token is needed then; the sign-in is
115
- kept on this computer.
116
-
117
- On macOS and Linux the script cannot change the terminal it was pasted into, so
118
- it ends with a line to paste — `export PATH="$HOME/.baseinstrunner/bin:$PATH"` —
119
- or open a new terminal. On Windows it ends with `bir works in every new terminal
120
- (and in this window when it is PowerShell)`: the PowerShell line puts `bir` on
121
- that window's PATH in place, but the cmd line runs the script in a child
122
- `powershell.exe`, so a cmd window has to be a new one.
123
-
124
- ---
125
-
126
- ## Step 2 — start Claude Code
127
-
128
- In the same folder:
129
-
130
- ```
131
- claude
132
- ```
133
-
134
- The first time in a folder Claude Code asks whether to trust it: say Yes, or the
135
- hooks do not run. If the script just installed Claude Code, it asks you to sign
136
- in to Claude; that is Claude's own subscription, separate from BaseIn.
137
-
138
- Then give it a task that takes four or more tool calls. It appears on the
139
- console's Recordings page within a minute of finishing.
140
-
141
- Nothing else to start. The SessionStart hook (`bir-hooks ensure`) starts the
142
- recorder in the background whenever this folder has none, so a session started
143
- tomorrow, or after a reboot, records the same way.
144
-
145
- ---
146
-
147
- ## Step 3 — check it
148
-
149
- ```
150
- bir doctor # is it working right now? exits non-zero if not
151
- bir status # what is installed for this folder; needs nothing running
152
- ```
153
-
154
- `bir doctor` asks the running recorder rather than reading a settings file: it
155
- says which service it records to, that the recorder runs in the background
156
- (with its pid and log file), and what replay is set to and where that setting
157
- came from. `bir status` prints the service address, the wrapped servers and the
158
- control server's address and log.
159
-
160
- Then open https://bi2202.com/recordings. The run from Step 2 is there, with
161
- its prompt, its tool calls and its final answer.
162
-
163
- ---
164
-
165
- ## What it changed on your machine
166
-
167
- | Path | What it holds |
168
- |---|---|
169
- | `~/.baseinstrunner/config.json` | the service address; `BIR_AUTH_URL` in the environment overrides it, and `bir setup` warns when the two differ |
170
- | `~/.baseinstrunner/credentials.json` | the cached session, bound to the service that issued it |
171
- | `~/.baseinstrunner/installed.json` | the original text of every file it rewrote, and each project's port, token and replay switches, and whether Claude's `bir` tools may change scenarios there (`bir scenario editing on`) |
172
- | `~/.baseinstrunner/logs/<key>.log` | the recorder's audit log, one file per project |
173
- | `~/.baseinstrunner/node/` | a private Node, only if the machine had no usable one; not on PATH |
174
- | `~/.baseinstrunner/npm/` | the runner package |
175
- | `~/.baseinstrunner/bin/` | the `bir` and `bir-hooks` launchers, first on your user PATH |
176
- | `<project>/.claude/settings.local.json` | Claude Code's hooks for this project and the pre-approved `bir` scenario server. Yours, not the team's: it carries this project's token and an absolute Node path |
177
- | `<project>/.mcp.json` (or `~/.claude.json`, whichever scope an entry lives in) | each MCP entry rewritten to run through `bir-proxy`, same keys; plus the `bir` scenario entry, which always goes in `.mcp.json` (project scope), never in `~/.claude.json` |
178
- | `<project>/.git/info/exclude` | one line, `.claude/settings.local.json`, so it never shows in `git status` |
179
-
180
- Each project gets its own control port (from 53411 up) and its own token, so one
181
- project's settings file cannot reach another project's recorder.
182
-
183
- ---
184
-
185
- ## Another project
186
-
187
- ```
188
- cd the-other-project
189
- bir setup
190
- ```
191
-
192
- No token: the sign-in is kept. The project gets its own port, token and log.
193
-
194
- ---
195
-
196
- ## Updating
197
-
198
- Paste the line from the console again — the very same line is fine, used token
199
- and all: `bir setup` says `the setup token was already used; keeping the sign-in
200
- from before (you@example.com)` and goes on. It installs the newest version and
201
- runs `bir setup`, which re-wraps any entry whose runner moved. If you installed
202
- by hand with `npm i -g @basein/runner`, upgrade the same way and then run
203
- `bir setup` in each project.
204
-
205
- A recorder of the older version is replaced only at the moments that look for
206
- one — the SessionStart hook, `bir up`, `bir setup` — and only when no session
207
- is mid-run right then; nothing watches for a session to end. `bir setup` says
208
- so when one is open (`recorder 0.2.8 is still serving an open Claude Code
209
- session; it restarts to 0.2.9 with the next session`). `bir up --restart` does
210
- it now.
211
-
212
- ---
213
-
214
- ## Undoing
215
-
216
- ```
217
- bir down # stop this project's recorder
218
- bir uninstall # put every file back byte-for-byte; remove hooks and the bir entry
219
- ```
220
-
221
- `bir uninstall` also forgets the project's port and token and takes the
222
- `.claude/settings.local.json` line back out of `.git/info/exclude`.
223
- Byte-for-byte holds for a file nothing else edited since the install; one you
224
- edited is repaired entry by entry instead, and it says so. A file the install
225
- created — usually `.claude/settings.local.json` — stays behind, empty of our
226
- entries.
227
-
228
- To remove the software: `bir logout` first, so the session is revoked on the
229
- service rather than only forgotten here. Then `npm rm -g @basein/runner` if
230
- you installed by hand, or delete `~/.baseinstrunner` (the runner, its private
231
- Node, the launchers, the session and the logs) and remove
232
- `~/.baseinstrunner/bin` from your PATH.
233
-
234
- ---
235
-
236
- ## When something is wrong
237
-
238
- `bir doctor` first. It names the broken link in the chain, which is most of the
239
- answer. Then:
240
-
241
- | You see | Why | Do |
242
- |---|---|---|
243
- | `This is your home folder…` from the script | a terminal opened from the Start menu begins in the home folder; the script stopped before downloading anything, so nothing is installed, nobody is signed in and the token is unused | `cd` to the project and paste the same line again |
244
- | `Signed in as … This is your home folder, so nothing was wired here` from `bir setup` | the same folder, but `bir setup` run by hand with the runner already installed; the sign-in is kept | `cd` to the project and run `bir setup` — no token needed |
245
- | `… is not a BaseIn service` | the address is the website (docs or app), not the API; or a stale `BIR_AUTH_URL` in a shell profile — `bir setup` warns when the two disagree | `bir setup --auth-url https://api.bi2202.com`; remove the variable from the profile |
246
- | `control.port_busy` in the log (`port N is held by another program or excluded by the system`); the recorder did not start | another program holds this project's port, or the system reserves the range it falls in — on Windows, Hyper-V and WSL exclude blocks that 53411 sits inside | `bir setup --port <n>` (by hand: `bir install --replay --port <n>` — a flag-less install keeps the way the project was installed — then `bir up --restart`) |
247
- | `recorder.disabled … no BaseIn session` in the log; `bir doctor` says the recorder has nowhere to send steps; or `bir setup` ends with ``not signed in — run `bir setup` again (or `bir login`)`` | not signed in, or signed in to another service | `bir setup`, then `bir up --restart` |
248
- | `that is not a valid setup token`, or `this setup token has expired or was already used` from `bir setup` | the token was cut short in the paste; or it is older than ten minutes or already redeemed, with no cached sign-in to fall back on | make a new one on the console's *Set up the runner* page and paste the whole line within ten minutes |
249
- | the tools were recorded but not the prompt | no recorder was running for this folder, so the proxies recorded on their own (Tier 2) | `bir doctor` says whether a recorder runs for this folder; `bir up` starts one now — the next session starts it anyway |
250
- | the run is not in Recordings | fewer than four tool calls; or the runner is signed in as a different account than the console | give a bigger task; compare the *account* line of `bir setup` with the console |
251
- | `bir doctor`: `the SessionStart hook … points at a Node that is gone` | the Node the hook names was removed or moved by a version manager | `bir setup` — it rewires the hook to the current Node |
252
- | Claude Code asks you to sign in | Claude Code was just installed; it needs a Claude subscription | sign in; nothing to do on the runner side |
253
- | `bir` is not recognised in the terminal the line was pasted into | on macOS and Linux the script cannot change that terminal's PATH; on Windows the cmd line runs the script in a child `powershell.exe`, whose PATH dies with it (the PowerShell line changes its own window) | macOS / Linux: `export PATH="$HOME/.baseinstrunner/bin:$PATH"`, or open a new terminal; Windows cmd: open a new window |
254
- | `invalid JSON at …/.mcp.json` | something edited the file into a shape that no longer parses | open it and fix the comma or bracket |
255
-
256
- For a turn that did not do what you expected — a scenario that did not run, a
257
- saving that was not made — `bir investigate` reads the journal and the service
258
- and says why. When it names a step whose code is wrong, you can fix that step
259
- yourself: see the next section.
260
-
261
- ---
262
-
263
- ## Fixing a step (not yet released)
264
-
265
- Built 2026-09-25. It needs the next `@basein/runner` version and a service
266
- deploy, so it does not work yet. The full guide, with real output, is
267
- [calculatedReplayGuide.md](calculatedReplayGuide.md) §9.2.
268
-
269
- A calculated step is code. When `bir investigate` says a step's code is wrong,
270
- you can change that step. The service checks your change against the
271
- recording. It saves it only if it gives the same call the recording made, and
272
- is not a pasted copy of that call. Only the owner of a scenario can change it.
273
-
274
- 1. **Read the step.** `bir scenario show scn_… --step 4` (the `scn_` id and the
275
- step number are the ones `bir investigate` printed).
276
- 2. **Write the new code to a file,** for example `step4.js`. Never on the
277
- command line: the shell breaks JavaScript.
278
- 3. **Check it.** `bir scenario check scn_… --step 4 --input-logic step4.js`.
279
- Nothing is saved. You should see `input reproduces the recorded call`.
280
- 4. **Save it.** `bir scenario edit scn_… --step 4 --input-logic step4.js --note "why"`.
281
- You should see a line that starts `Saved as sedit_…`.
282
- 5. **Changed your mind?** `bir scenario undo scn_…` takes back the newest
283
- change. Run it again to go one further back. With `--step 4` it takes
284
- back only step 4's changes, newest first. An undo that would break a later
285
- step or the final answer is refused (`undo_refused`).
286
-
287
- If the check refuses your change, it says why. For example, the `input` line
288
- says where your call differs from the recorded one. Fix the code and check
289
- again. `--force --note "why"` saves it anyway, but use it only when the
290
- recording itself was wrong.
291
-
292
- The saved code runs on your machine without asking you, like the code the
293
- calculation wrote. The check only tests what it sends for the recording's
294
- values. So read the code before it is saved, yours or Claude's.
295
-
296
- Claude can do this for you. Ask it in the session; it runs the same commands,
297
- and Claude Code asks you before each one, unless you allowed it. Or run
298
- `bir scenario editing on` in the project folder and restart Claude Code: the
299
- `bir` server then also offers tools that change a scenario. These `bir` calls
300
- are never recorded as part of your task.
301
-
302
- ---
303
-
304
- ## Where to go next
305
-
306
- - [installRun.md](installRun.md) — the fleet version: packaging, releases,
307
- offline installs, updates.
308
- - [calculatedReplayGuide.md](calculatedReplayGuide.md) — record, calculate,
309
- check, enable, and read the audit lines.
310
- - [../README.md](../README.md) — what is recorded, what cannot be, and every
311
- configuration switch.
1
+ # Setting up a runner machine
2
+
3
+ One person, one computer: from nothing to a project whose every Claude Code
4
+ session is recorded and whose calculated scenarios run. It takes a few minutes,
5
+ most of them downloads. Nothing has to stay open afterwards.
6
+
7
+ **What you are setting up.** BaseInstRunner sits between Claude Code and the
8
+ tools it uses, records each session to the BaseIn service, and — when a new
9
+ prompt means the same thing as one it has seen — runs the calculated scenario
10
+ instead of letting the model rediscover the plan. Otherwise it does not change
11
+ what the model does.
12
+
13
+ ---
14
+
15
+ ## Before you start
16
+
17
+ A BaseIn account. That is all: Node and Claude Code are installed for you if the
18
+ machine has neither. On Windows use PowerShell or cmd, whichever your terminal
19
+ is; the console shows a line for each.
20
+
21
+ ---
22
+
23
+ ## Step 1 — paste the line
24
+
25
+ Sign in to the console and open **Set up the runner**. The first thing on the
26
+ page is one line with a one-time setup token filled in (valid for ten minutes,
27
+ usable once). Open a terminal **in the project folder you start Claude Code in**
28
+ and paste it:
29
+
30
+ ```powershell
31
+ $env:BIR_SETUP_TOKEN="<token>"; irm https://api.bi2202.com/install.ps1 | iex
32
+ ```
33
+
34
+ ```cmd
35
+ powershell -NoProfile -Command "$env:BIR_SETUP_TOKEN='<token>'; irm https://api.bi2202.com/install.ps1 | iex"
36
+ ```
37
+
38
+ ```bash
39
+ curl -fsSL https://api.bi2202.com/install.sh | BIR_SETUP_TOKEN="<token>" sh
40
+ ```
41
+
42
+ Without a token — it expired, or you are not at the console — the same line
43
+ without the `BIR_SETUP_TOKEN` part works: `bir setup` uses the sign-in already
44
+ cached on this computer if there is one, and otherwise opens your browser to
45
+ approve the sign-in and waits. Over SSH it prints the link and a short code
46
+ instead; they work from any device, a phone included.
47
+
48
+ Behind a corporate proxy, set `NO_PROXY=127.0.0.1,localhost,::1` (plus your own
49
+ entries) as well as `HTTPS_PROXY` before you paste. The runner uses the proxy
50
+ only when `NO_PROXY` exempts `127.0.0.1` — otherwise the proxy would swallow its
51
+ own local calls — and the script prints a note when it does not
52
+ ([installRun.md §5.1](installRun.md)).
53
+
54
+ The script prints a `==>` line per stage and never asks a question. Before it
55
+ downloads anything it checks that this is not your home folder or a drive root;
56
+ if it is, it stops and asks you to `cd` to the project and paste again. Then:
57
+
58
+ 1. **Node.** A Node 20+ on PATH is used when npm sits beside it and nothing
59
+ can move it: a Node from nvm, fnm, Volta, asdf, mise or nodenv changes path
60
+ per shell or per version, and so does one from Homebrew or snap (macOS and
61
+ Linux) or Scoop (Windows) — a `brew upgrade` moves the path the hook pins.
62
+ Any of those, or no Node at all, and a private copy goes under
63
+ `~/.baseinstrunner/node/v<version>/`. It is never put on your PATH.
64
+ 2. **The runner.** `@basein/runner` is installed under `~/.baseinstrunner/npm/`,
65
+ with `bir` and `bir-hooks` launchers in `~/.baseinstrunner/bin/`, which goes
66
+ first on your user PATH. No execution-policy change on Windows.
67
+ 3. **Claude Code.** Installed with its official installer if `claude` is not on
68
+ PATH. This can take a minute.
69
+ 4. **`bir setup`**, which prints:
70
+
71
+ ```
72
+ ==> Setting up the runner (0.2.9)
73
+ service https://api.bi2202.com
74
+ account you@example.com
75
+ ==> Wiring the project
76
+ + chrome-devtools → bir-proxy (local scope, over the .mcp.json entry; upstream: npx)
77
+ + bir → bir-scenario (calculated replay; local scope)
78
+ + hooks → C:\work\repo\.claude\settings.local.json (control server on http://127.0.0.1:53411; the recorder starts itself with each session)
79
+ + .claude/settings.local.json is listed in C:\work\repo\.git\info\exclude
80
+
81
+ Wrapped 1 server.
82
+ …
83
+ ==> Starting the recorder in the background
84
+
85
+ Done. Recording and replay are on for C:\work\repo
86
+ account you@example.com (https://api.bi2202.com)
87
+ wrapped chrome-devtools
88
+ replay on — direct execution allowed for: all wrapped (narrow it with `bir replay allow chrome-devtools`)
89
+ recorder started in the background (pid 1234) — it starts itself with every Claude Code session
90
+ log C:\Users\you\.baseinstrunner\logs\3f9c1a2b7d4e5f60.log
91
+
92
+ Now: claude
93
+ first time in this folder: say Yes to "trust this folder"
94
+ just installed Claude Code? it asks you to sign in to Claude (it needs a Claude subscription)
95
+ give it a task that takes 4+ tool calls — it appears at https://bi2202.com/recordings within a minute of finishing
96
+ Any time: bir doctor bir investigate bir off (out of the way, at once) bir uninstall (undo)
97
+ ```
98
+
99
+ Line by line: *service* is the API address, now stored so no terminal needs
100
+ `BIR_AUTH_URL`; *account* is who the recordings belong to; *wrapped* is the
101
+ project's MCP servers now routed through `bir-proxy` under their old names — as
102
+ copies in this project's local scope in `~/.claude.json`, so `.mcp.json` itself
103
+ is not changed;
104
+ *replay* says which of them a calculated scenario may call unattended — narrow
105
+ it with `bir replay allow <names>`, turn it off with `bir replay off`, and read
106
+ [calculatedReplayGuide.md §5.1](calculatedReplayGuide.md) before leaving it wide
107
+ anywhere that matters; *recorder* is the background process, and *log* is where
108
+ its audit lines go.
109
+
110
+ A project with no MCP servers in any scope — none in `.mcp.json`, and none for
111
+ this project or your user in `~/.claude.json` — shows `wrapped (no MCP servers
112
+ here)` and `replay steer mode only`: built-in tools and prompts are still
113
+ recorded, and a scenario still steers the session, but there is nothing to
114
+ execute directly.
115
+
116
+ Only servers Claude Code already runs here are wrapped. A `.mcp.json` server
117
+ Claude Code has not asked you about yet — a fresh clone, say — is left as it is
118
+ (`- <name> — left unwrapped: Claude Code has not been told to use it yet (it
119
+ asks first); …`); when nothing could be wrapped, *wrapped* reads `(none —
120
+ <name> left as they are, see above)`. Start `claude`, approve the server when it
121
+ asks, and run `bir setup` again to wrap it; until then the hooks record its
122
+ calls. A remote server that Claude Code signs in itself (OAuth) is left
123
+ unwrapped the same way.
124
+
125
+ Pasted in the home folder anyway? The script stops before it downloads anything
126
+ — `This is your home folder. Open a terminal in the project you start Claude
127
+ Code in (cd there) and paste the line again.` Nothing was installed, nobody was
128
+ signed in and the token is unused, so `cd` to the project and paste the same
129
+ line. It is `bir setup` run by hand in the home folder, with the runner already
130
+ installed, that keeps the sign-in and prints the two commands left:
131
+ `cd <your project>` and `bir setup`. No token is needed then; the sign-in is
132
+ kept on this computer.
133
+
134
+ On macOS and Linux the script cannot change the terminal it was pasted into, so
135
+ it ends with a line to paste — `export PATH="$HOME/.baseinstrunner/bin:$PATH"` —
136
+ or open a new terminal. On Windows it ends with `bir works in every new terminal
137
+ (and in this window when it is PowerShell)`: the PowerShell line puts `bir` on
138
+ that window's PATH in place, but the cmd line runs the script in a child
139
+ `powershell.exe`, so a cmd window has to be a new one.
140
+
141
+ ---
142
+
143
+ ## Step 2 — start Claude Code
144
+
145
+ In the same folder:
146
+
147
+ ```
148
+ claude
149
+ ```
150
+
151
+ The first time in a folder Claude Code asks whether to trust it: say Yes, or the
152
+ hooks do not run. If the script just installed Claude Code, it asks you to sign
153
+ in to Claude; that is Claude's own subscription, separate from BaseIn. If it
154
+ asks whether to use a server from the project's `.mcp.json` that `bir setup`
155
+ left unwrapped, say Yes and run `bir setup` again afterwards.
156
+
157
+ Then give it a task that takes four or more tool calls. It appears on the
158
+ console's Recordings page within a minute of finishing.
159
+
160
+ Nothing else to start. The SessionStart hook (`bir-hooks ensure`) starts the
161
+ recorder in the background whenever this folder has none, so a session started
162
+ tomorrow, or after a reboot, records the same way.
163
+
164
+ ---
165
+
166
+ ## Step 3 — check it
167
+
168
+ ```
169
+ bir doctor # is it working right now? exits 1 only for what breaks a session
170
+ bir status # what is installed for this folder; needs nothing running
171
+ ```
172
+
173
+ `bir doctor` asks the running recorder rather than reading a settings file: it
174
+ says which service it records to, that the recorder runs in the background
175
+ (with its pid and log file), what replay is set to and where that setting
176
+ came from, and who approves wrapped MCP calls. It sorts the rest into problems
177
+ (these break a Claude Code session, and only these exit 1), warnings (the
178
+ runner is not doing all it should — not recording, say; `--strict` fails on
179
+ these too) and notes. `bir status` prints the service address, the wrapped
180
+ servers, the control server's address and log, and whether the runner is off.
181
+
182
+ Then open https://bi2202.com/recordings. The run from Step 2 is there, with
183
+ its prompt, its tool calls and its final answer.
184
+
185
+ ---
186
+
187
+ ## What it changed on your machine
188
+
189
+ | Path | What it holds |
190
+ |---|---|
191
+ | `~/.baseinstrunner/config.json` | the service address; `BIR_AUTH_URL` in the environment overrides it, and `bir setup` warns when the two differ |
192
+ | `~/.baseinstrunner/credentials.json` | the cached session, bound to the service that issued it |
193
+ | `~/.baseinstrunner/installed.json` | what `bir uninstall` needs to undo each change — the original text of the project files it rewrote, with their credential values left out — and each project's port, token and replay switches, and whether Claude's `bir` tools may change scenarios there (`bir scenario editing on`) |
194
+ | `~/.baseinstrunner/logs/<key>.log` | the recorder's audit log, one file per project |
195
+ | `~/.baseinstrunner/node/` | a private Node, only if the machine had no usable one; not on PATH |
196
+ | `~/.baseinstrunner/npm/` | the runner package |
197
+ | `~/.baseinstrunner/bin/` | the `bir` and `bir-hooks` launchers, first on your user PATH |
198
+ | `<project>/.claude/settings.local.json` | Claude Code's hooks for this project. Yours, not the team's: it carries this project's token and an absolute Node path |
199
+ | `~/.claude.json` (`$CLAUDE_CONFIG_DIR/.claude.json` when that is set), this project's local scope | a copy of each MCP server it wraps, under the same name, running through `bir-proxy`; plus the `bir` scenario server. The copy takes precedence in this project only; `.mcp.json` and your user-scope servers are not changed |
200
+ | `<project>/.git/info/exclude` | one line, `.claude/settings.local.json`, so it never shows in `git status` |
201
+
202
+ Each project gets its own control port (from 53411 up) and its own token, so one
203
+ project's settings file cannot reach another project's recorder.
204
+
205
+ ---
206
+
207
+ ## Another project
208
+
209
+ ```
210
+ cd the-other-project
211
+ bir setup
212
+ ```
213
+
214
+ No token: the sign-in is kept. The project gets its own port, token and log.
215
+
216
+ ---
217
+
218
+ ## Updating
219
+
220
+ Paste the line from the console again — the very same line is fine, used token
221
+ and all: `bir setup` says `the setup token was already used; keeping the sign-in
222
+ from before (you@example.com)` and goes on. It installs the newest version and
223
+ runs `bir setup`, which re-wraps any entry whose runner moved. If you installed
224
+ by hand with `npm i -g @basein/runner`, upgrade the same way and then run
225
+ `bir setup` in each project.
226
+
227
+ A recorder of an older version is replaced only at the moments that look for
228
+ one — the SessionStart hook, `bir up`, `bir setup` — and only when no session
229
+ is mid-turn right then; nothing watches for a session to end. `bir setup` says
230
+ so when one is (``it is still <old>, serving a Claude Code session that is
231
+ mid-turn; it keeps running as <old> until `bir up --restart` (run it once that
232
+ session ends) replaces it with <new>``). Run `bir up --restart` once that
233
+ session ends.
234
+
235
+ **From 0.2.12.** The runner no longer approves wrapped MCP tool calls itself
236
+ (0.2.12 answered every one "allow"): Claude Code asks about them as it would
237
+ without the runner, and `bir setup` says so once. For headless `claude -p` runs,
238
+ allow them in `permissions.allow` or with `--allowedTools`, or set
239
+ `BIR_CORRELATION_DECISION=allow` where the recorder starts (then
240
+ `bir up --restart` from there). Wrapped entries move
241
+ out of `.mcp.json` into the local scope, and `.mcp.json` is put back as it was.
242
+ A 0.2.12 recorder still running keeps approving those calls, and ignores
243
+ `bir off`, until `bir up --restart` replaces it.
244
+
245
+ Going back to an older version: run `bir uninstall --all` with this one first
246
+ (an older runner cannot undo everything this one wrote), then install the older
247
+ one and run `bir setup`.
248
+
249
+ ---
250
+
251
+ ## Undoing
252
+
253
+ ```
254
+ bir off --here # out of the way at once, open sessions included; nothing is uninstalled
255
+ bir down # stop this project's recorder
256
+ bir uninstall # undo the install here, and stop this project's recorder
257
+ ```
258
+
259
+ `bir off --here` (this project) or `bir off` (every project) is the first thing
260
+ to try when a session misbehaves, or when support wants to rule the runner out:
261
+ hooks answer with nothing within about a second, in sessions already open too;
262
+ wrapped MCP servers run as plain pipes to the real ones from their next start
263
+ (a new session, or `/mcp` → reconnect), and the `bir` server offers no tools
264
+ from its next start.
265
+ `bir on --here` / `bir on` turns it back on. `BIR_OFF=1` in the environment
266
+ Claude Code starts in switches off just that window's session.
267
+
268
+ `bir down` only stops the recorder. The hooks stay installed, so a Claude Code
269
+ session open here shows a "hook error" on each prompt and tool call (the session
270
+ keeps working) until it ends, and the next session starts the recorder again.
271
+
272
+ `bir uninstall` covers this project only. It puts back what the install changed
273
+ — a file nothing else edited since, byte-for-byte; `~/.claude.json`, and a file
274
+ you edited, entry by entry — removes the hooks and the `bir` entry, forgets the
275
+ project's port and token, and takes the `.claude/settings.local.json` line back
276
+ out of `.git/info/exclude` (unless it was there before). It also stops the
277
+ project's recorder — unless a session here still uses it: then the recorder
278
+ stays up, switched off for this project, and it tells you to restart that
279
+ session and run `bir down`. A file the install created — usually
280
+ `.claude/settings.local.json` — stays behind, empty of our entries. If anything
281
+ here still runs through the runner it ends with `Not everything could be
282
+ undone`, names it, and exits 1.
283
+
284
+ To remove the software, take the runner out of every project first — otherwise
285
+ their wrapped servers and hooks keep naming files you are about to delete:
286
+
287
+ ```
288
+ bir uninstall --all
289
+ ```
290
+
291
+ or paste the install line with `BIR_UNINSTALL=1`, which runs just that:
292
+ `curl -fsSL https://api.bi2202.com/install.sh | BIR_UNINSTALL=1 sh`, or
293
+ `$env:BIR_UNINSTALL="1"; irm https://api.bi2202.com/install.ps1 | iex` in
294
+ PowerShell. Once it ends cleanly: `bir logout`, so the session is revoked on the
295
+ service rather than only forgotten here. Then `npm rm -g @basein/runner` if
296
+ you installed by hand, or delete `~/.baseinstrunner` (the runner, its private
297
+ Node, the launchers, the session and the logs) and remove
298
+ `~/.baseinstrunner/bin` from your PATH.
299
+
300
+ ---
301
+
302
+ ## When something is wrong
303
+
304
+ `bir doctor` first. It names the broken link in the chain, which is most of the
305
+ answer. Then:
306
+
307
+ | You see | Why | Do |
308
+ |---|---|---|
309
+ | `This is your home folder…` from the script | a terminal opened from the Start menu begins in the home folder; the script stopped before downloading anything, so nothing is installed, nobody is signed in and the token is unused | `cd` to the project and paste the same line again |
310
+ | `Signed in as … This is your home folder, so nothing was wired here` from `bir setup` | the same folder, but `bir setup` run by hand with the runner already installed; the sign-in is kept | `cd` to the project and run `bir setup` — no token needed |
311
+ | `… is not a BaseIn service` | the address is the website (docs or app), not the API; or a stale `BIR_AUTH_URL` in a shell profile — `bir setup` warns when the two disagree | `bir setup --auth-url https://api.bi2202.com`; remove the variable from the profile |
312
+ | `control.port_busy` in the log; `bir doctor`: `the recorder could not take port N: …`; the recorder did not start | another program holds this project's port, or the system reserves the range it falls in — on Windows, Hyper-V, WSL and Docker reserve blocks that 53411 sits inside, and they move at boot | `bir setup` — it moves the project to a free port when its own cannot be bound; or `bir setup --port <n>` (below 49152 avoids the reserved ranges; by hand: `bir install --replay --port <n>` — a flag-less install keeps the way the project was installed — then `bir up --restart`) |
313
+ | `recorder.disabled` or `recorder.signed_out` in the log (`not signed in`, `no service address`); `bir doctor` warns the recorder has nowhere to send steps; or `bir setup` ends with ``not signed in — run `bir setup` again (or `bir login`)`` | not signed in, or signed in to another service | `bir setup` — the running recorder starts recording by itself once the sign-in is there, no restart needed |
314
+ | `- <name> — left unwrapped: Claude Code has not been told to use it yet` from `bir setup` | a `.mcp.json` server Claude Code has not approved (a fresh clone); a copy would start it without asking | start `claude`, approve it, then `bir setup` again; `bir install --server <name>` wraps it anyway |
315
+ | a `claude -p` run is denied a wrapped MCP tool (since upgrading from 0.2.12) | the runner no longer approves wrapped MCP calls; Claude Code's own permissions decide | allow the tools in `permissions.allow` or with `--allowedTools`, or set `BIR_CORRELATION_DECISION=allow` where the recorder starts, then `bir up --restart` from there |
316
+ | a "hook error" on each prompt and tool call | the recorder was stopped (`bir down`) under an open session | `bir up`; `bir off --here` afterwards if you want the runner out of the way; a new session also starts it |
317
+ | `that is not a valid setup token`, or `this setup token has expired or was already used` from `bir setup` | the token was cut short in the paste; or it is older than ten minutes or already redeemed, with no cached sign-in to fall back on | make a new one on the console's *Set up the runner* page and paste the whole line within ten minutes |
318
+ | the tools were recorded but not the prompt | no recorder was running for this folder, so the proxies recorded on their own (Tier 2) | `bir doctor` says whether a recorder runs for this folder; `bir up` starts one now — the next session starts it anyway |
319
+ | the run is not in Recordings | fewer than four tool calls; or the runner is signed in as a different account than the console | give a bigger task; compare the *account* line of `bir setup` with the console |
320
+ | `bir doctor`: `the SessionStart hook … points at a Node that is gone` | the Node the hook names was removed or moved by a version manager | `bir setup` — it rewires the hook to the current Node |
321
+ | Claude Code asks you to sign in | Claude Code was just installed; it needs a Claude subscription | sign in; nothing to do on the runner side |
322
+ | `bir` is not recognised in the terminal the line was pasted into | on macOS and Linux the script cannot change that terminal's PATH; on Windows the cmd line runs the script in a child `powershell.exe`, whose PATH dies with it (the PowerShell line changes its own window) | macOS / Linux: `export PATH="$HOME/.baseinstrunner/bin:$PATH"`, or open a new terminal; Windows cmd: open a new window |
323
+ | `invalid JSON at …/.mcp.json` | something edited the file into a shape that no longer parses (comments count); `bir setup` changes nothing until it does | open it and fix the comma or bracket |
324
+ | `… is set but NO_PROXY does not name 127.0.0.1 …` from the script or `bir setup` | the runner leaves the proxy out rather than send its own local calls through it | set `NO_PROXY=127.0.0.1,localhost,::1` plus your own entries, and paste the line again |
325
+
326
+ For a turn that did not do what you expected — a scenario that did not run, a
327
+ saving that was not made — `bir investigate` reads the journal and the service
328
+ and says why. When it names a step whose code is wrong, you can fix that step
329
+ yourself: see the next section.
330
+
331
+ ---
332
+
333
+ ## Fixing a step (not yet released)
334
+
335
+ Built 2026-09-25. It needs the next `@basein/runner` version and a service
336
+ deploy, so it does not work yet. The full guide, with real output, is
337
+ [calculatedReplayGuide.md](calculatedReplayGuide.md) §9.2.
338
+
339
+ A calculated step is code. When `bir investigate` says a step's code is wrong,
340
+ you can change that step. The service checks your change against the
341
+ recording. It saves it only if it gives the same call the recording made, and
342
+ is not a pasted copy of that call. Only the owner of a scenario can change it.
343
+
344
+ 1. **Read the step.** `bir scenario show scn_… --step 4` (the `scn_` id and the
345
+ step number are the ones `bir investigate` printed).
346
+ 2. **Write the new code to a file,** for example `step4.js`. Never on the
347
+ command line: the shell breaks JavaScript.
348
+ 3. **Check it.** `bir scenario check scn_… --step 4 --input-logic step4.js`.
349
+ Nothing is saved. You should see `input reproduces the recorded call`.
350
+ 4. **Save it.** `bir scenario edit scn_… --step 4 --input-logic step4.js --note "why"`.
351
+ You should see a line that starts `Saved as sedit_…`.
352
+ 5. **Changed your mind?** `bir scenario undo scn_…` takes back the newest
353
+ change. Run it again to go one further back. With `--step 4` it takes
354
+ back only step 4's changes, newest first. An undo that would break a later
355
+ step or the final answer is refused (`undo_refused`).
356
+
357
+ If the check refuses your change, it says why. For example, the `input` line
358
+ says where your call differs from the recorded one. Fix the code and check
359
+ again. `--force --note "why"` saves it anyway, but use it only when the
360
+ recording itself was wrong.
361
+
362
+ The saved code runs on your machine without asking you, like the code the
363
+ calculation wrote. The check only tests what it sends for the recording's
364
+ values. So read the code before it is saved, yours or Claude's.
365
+
366
+ Claude can do this for you. Ask it in the session; it runs the same commands,
367
+ and Claude Code asks you before each one, unless you allowed it. Or run
368
+ `bir scenario editing on` in the project folder and restart Claude Code: the
369
+ `bir` server then also offers the tools that read and change a scenario (by
370
+ default it offers only `run_scenario`). These `bir` calls
371
+ are never recorded as part of your task.
372
+
373
+ ---
374
+
375
+ ## Where to go next
376
+
377
+ - [installRun.md](installRun.md) — the fleet version: packaging, releases,
378
+ offline installs, proxies, updates, removal.
379
+ - [../production.md](../production.md) — the production contract: timeouts,
380
+ environment variables, what happens when the service is down.
381
+ - [calculatedReplayGuide.md](calculatedReplayGuide.md) — record, calculate,
382
+ check, enable, and read the audit lines.
383
+ - [../README.md](../README.md) — what is recorded, what cannot be, and every
384
+ configuration switch.