@basein/runner 0.3.20 → 0.3.22

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 (51) hide show
  1. package/README.md +6 -5
  2. package/dist/bin/bir-hooks.d.ts +17 -19
  3. package/dist/bin/bir-hooks.js +17 -19
  4. package/dist/bin/bir-scenario.js +1 -1
  5. package/dist/bin/bir.js +1 -21
  6. package/dist/bin/investigate.d.ts +0 -9
  7. package/dist/bin/investigate.js +15 -43
  8. package/dist/bin/scenario-edit.js +13 -44
  9. package/dist/control/recorder-main.d.ts +0 -15
  10. package/dist/control/recorder-main.js +22 -42
  11. package/dist/control/server.d.ts +24 -137
  12. package/dist/control/server.js +107 -1001
  13. package/dist/record/recorder.d.ts +11 -142
  14. package/dist/record/recorder.js +0 -3
  15. package/dist/record/remote-recorder.d.ts +1 -9
  16. package/dist/record/remote-recorder.js +3 -49
  17. package/dist/record/switchable-recorder.js +0 -2
  18. package/dist/replay/builtins.d.ts +45 -9
  19. package/dist/replay/builtins.js +131 -59
  20. package/dist/replay/bundle.d.ts +2 -2
  21. package/dist/replay/bundle.js +3 -3
  22. package/dist/replay/controller.d.ts +34 -125
  23. package/dist/replay/controller.js +171 -528
  24. package/dist/replay/derive.d.ts +0 -10
  25. package/dist/replay/derive.js +0 -3
  26. package/dist/replay/handover.d.ts +2 -37
  27. package/dist/replay/handover.js +38 -106
  28. package/dist/replay/logic.d.ts +0 -11
  29. package/dist/replay/logic.js +0 -24
  30. package/dist/replay/plan.d.ts +43 -163
  31. package/dist/replay/plan.js +144 -556
  32. package/dist/replay/safety.d.ts +4 -5
  33. package/dist/replay/safety.js +7 -7
  34. package/dist/replay/source-run.d.ts +15 -24
  35. package/dist/replay/source-run.js +25 -58
  36. package/dist/replay/targets.d.ts +11 -21
  37. package/dist/replay/targets.js +30 -69
  38. package/dist/replay/types.d.ts +9 -96
  39. package/dist/replay/types.js +3 -16
  40. package/dist/util/service-headers.d.ts +1 -2
  41. package/dist/util/service-headers.js +1 -2
  42. package/docs/calculatedReplay.md +30 -81
  43. package/docs/calculatedReplayGuide.md +17 -34
  44. package/package.json +1 -1
  45. package/production.md +7 -36
  46. package/dist/replay/condition-words.d.ts +0 -28
  47. package/dist/replay/condition-words.js +0 -59
  48. package/dist/replay/flatten.d.ts +0 -161
  49. package/dist/replay/flatten.js +0 -222
  50. package/dist/replay/reads-only.d.ts +0 -29
  51. package/dist/replay/reads-only.js +0 -261
@@ -50,13 +50,9 @@ export function isReadyScenario(value) {
50
50
  s.steps.every(readyStep));
51
51
  }
52
52
  /**
53
- * One step of a ready chain (segmented.md 10.6 step 1).
54
- *
55
- * A call row carries no tool of its own, so the old test — a string `toolName`
56
- * and a string `toolInputLogic` — would decline every chain that contains one.
57
- * A call is ready when it says it cannot run (the plan stops in front of it and
58
- * the agent takes over there) or when it carries a segment whose own steps pass
59
- * this same test. A call row with neither is a payload we cannot run.
53
+ * One step of a ready chain: a tool and the logic that computes its input.
54
+ * Anything else — a row with no tool, as an older service could send — is a
55
+ * payload this runner cannot run, and the plan is not armed.
60
56
  */
61
57
  function readyStep(step) {
62
58
  if (!step)
@@ -65,15 +61,6 @@ function readyStep(step) {
65
61
  // not armed rather than run with the step always in, or always out.
66
62
  if (step.when !== undefined && step.when !== null && !isStepTest(step.when))
67
63
  return false;
68
- if (step.kind === "segment") {
69
- if (step.unusable)
70
- return true;
71
- const segment = step.segment;
72
- return (!!segment &&
73
- Array.isArray(segment.steps) &&
74
- segment.steps.length > 0 &&
75
- segment.steps.every(readyStep));
76
- }
77
64
  return typeof step.toolName === "string" && typeof step.toolInputLogic === "string";
78
65
  }
79
66
  //# sourceMappingURL=types.js.map
@@ -5,8 +5,7 @@
5
5
  *
6
6
  * - **1** — stops in front of a step that carries `stop`, and reads
7
7
  * `withheld: "runner_update_required"` on a match.
8
- * - **2** — runs a step (or a sub-task's call row) only when its test, `when`,
9
- * says so: leaves it out (`not_taken`) or stops in front of it
8
+ * - **2** — runs a step only when its test, `when`, says so: leaves it out (`not_taken`) or stops in front of it
10
9
  * (`other_branch`) when the test says no, and stops when the test cannot
11
10
  * answer (stage `when_logic`). The service's autocorrect.md AC5: a plan
12
11
  * holding a test is handed only to a runner that names contract 2 or newer,
@@ -22,8 +22,7 @@ import { packageVersion } from "./version.js";
22
22
  *
23
23
  * - **1** — stops in front of a step that carries `stop`, and reads
24
24
  * `withheld: "runner_update_required"` on a match.
25
- * - **2** — runs a step (or a sub-task's call row) only when its test, `when`,
26
- * says so: leaves it out (`not_taken`) or stops in front of it
25
+ * - **2** — runs a step only when its test, `when`, says so: leaves it out (`not_taken`) or stops in front of it
27
26
  * (`other_branch`) when the test says no, and stops when the test cannot
28
27
  * answer (stage `when_logic`). The service's autocorrect.md AC5: a plan
29
28
  * holding a test is handed only to a runner that names contract 2 or newer,
@@ -45,7 +45,7 @@ this design has a ladder whose cheapest rung is free — and the more of a stack
45
45
  |---|---|---|
46
46
  | Runs MCP tools itself | No (`replay.md` §12: *"rrepeat never executes tools — not even MCP"*) | **Yes**, on the connection it already owns |
47
47
  | Divergence fallback | A second Agent SDK session — the dominant cost | Direct `tools/call` through the proxies — **$0** |
48
- | Reaches built-ins (`Bash`, `Read`) | Only by steering the live session | `Read`, `Glob`, `Grep`, `Edit`, `Write` and `Bash` run on the runner itself, jailed to the project (`BIR_BUILTIN_TOOLS`, `BIR_BASH_ALLOW`); any other built-in is steered. In a host that is not Claude Code a tool with one of these names is the application's own, and the runner runs none of them (§7.4) |
48
+ | Reaches built-ins (`Bash`, `Read`) | Only by steering the live session | `Read`, `Glob`, `Grep`, `Edit`, `Write` and `Bash` run on the runner itself, on any path the agent could reach unless `BIR_PATH_ALLOW` names folders (`BIR_BUILTIN_TOOLS`, `BIR_BASH_ALLOW`, `BIR_PATH_ALLOW`); any other built-in is steered. In a host that is not Claude Code a tool with one of these names is the application's own, and the runner runs none of them (§7.4) |
49
49
  | Needs `@anthropic-ai/*` at runtime | Yes | No (§16.3) |
50
50
 
51
51
  ---
@@ -231,8 +231,8 @@ more than one score — a same-request question under its threshold, and a secon
231
231
  prompt's task line. Re-scoring that on this side declined matches the server had made (a checked
232
232
  0.85, a task line at 0.91). **A match is the decision to use the scenario**, so every hand-out
233
233
  steers; what a plan cannot do — a parked first step, a tool nothing reaches, a target the prompt
234
- never named — the gates after it still stop. `BIR_MIN_STEER_SIMILARITY` and
235
- `BIR_MIN_SEGMENT_STEER_SIMILARITY` are ignored.
234
+ never named — the gates after it still stop. `BIR_MIN_STEER_SIMILARITY` is
235
+ ignored.
236
236
 
237
237
  `not_steered` as the floor is not a failure code. It is the **control group**: the prompt matched,
238
238
  the agent ran the task the ordinary way, and the cost of doing so is a fresh measurement of what this
@@ -265,7 +265,7 @@ export function modeFor(steps: SerializedScenarioStep[], wrapped: ReadonlySet<st
265
265
 
266
266
  | Every step | Mode | Where the tools run | Model spend |
267
267
  |---|---|---|---|
268
- | a wrapped MCP tool, or a built-in on `BIR_BUILTIN_TOOLS` | **`direct`** (§6) | The proxies, on connections already open; allow-listed built-ins on the runner itself, jailed to the session's project directory (replay/builtins.ts) | one Haiku derivation + one turn that reads the results |
268
+ | a wrapped MCP tool, or a built-in on `BIR_BUILTIN_TOOLS` | **`direct`** (§6) | The proxies, on connections already open; allow-listed built-ins on the runner itself, from the session's project directory (replay/builtins.ts) | one Haiku derivation + one turn that reads the results |
269
269
  | anything else, or mixed | **`steer`** (§7) | The live session, inputs pinned | one Haiku derivation + the live turn |
270
270
  | — | `none` | nowhere | declines at gate 5 |
271
271
 
@@ -275,11 +275,17 @@ so `Task`, `WebFetch`; up to 0.3.7 also `Bash`, `Edit`, `Write`), an MCP server
275
275
  `claude-in-chrome` — which is `scope: "dynamic"`, appears in no config file, and therefore can never
276
276
  be wrapped (v1 design §1). None of them can be reached except through the session.
277
277
 
278
- A built-in **on** the allow-list runs on the runner, in the session's own project directory and
279
- confined to it — a path that resolves outside the project, symlinks included, is refused and the
280
- step is `not_run`, the clean hand-over. `Bash` has a second switch on top (`BIR_BASH_ALLOW`,
281
- command prefixes; unset means any command, `none` keeps `Bash` in the session), because a
282
- runner-side step never reaches the host's permission prompts. The
278
+ A built-in **on** the allow-list runs on the runner, from the session's own project directory: a
279
+ relative path resolves against it, as the host's tools resolve it, and an absolute path is taken
280
+ as it is, inside the project or not — the agent's own tools reach any folder its session allows,
281
+ and the recorded call was one of them (up to 0.3.20 every path was confined to the project, and a
282
+ plan that read the agent's memory file under `~/.claude` handed the whole task back). The file
283
+ tools have a switch of their own (`BIR_PATH_ALLOW`, folders; unset means any, `project` brings
284
+ back the confinement, `project,~/.claude` adds a folder, `none` keeps them in the session); under
285
+ a list, a path outside it, symlinks included, is refused and the step is `not_run`, the clean
286
+ hand-over. `Bash` has its switch too (`BIR_BASH_ALLOW`, command prefixes; unset means any command,
287
+ `none` keeps `Bash` in the session), because a runner-side step never reaches the host's
288
+ permission prompts. The
283
289
  results mimic the hook's view of each tool, which is what the recorder stored for built-in steps
284
290
  and what their `toolOutputLogic` was authored against; they pass through the same
285
291
  `serializeCapped(redact(…))` as every recorded payload. Bash keeps the host's own semantics a
@@ -748,30 +754,6 @@ about it:
748
754
  It ends with the remaining planned steps and the parameters derived for this request, within 4 000
749
755
  characters.
750
756
 
751
- **A plan's decision (0.3.19)** has a note of its own. The service serves a step with
752
- `stop: {kind: "decision"}` where the task has an "if … otherwise" (its segmentsbreakdown.md). The
753
- plan runs only the steps before it, in steer and direct mode and when a divergence's bundle runs up
754
- to it, and hands the task back. The note opens *"[BaseInstRunner calculated replay] The calculated
755
- scenario for this request ran the steps before a decision, and stopped there."*, says which steps
756
- ran as above, and ends *"This request asks for a decision: “…”. Decide from the results above
757
- which way applies, then continue the task, calling tools as needed."* (*below* in a direct run's
758
- answer, *above and below* after a divergence; *"This task has a decision to make here."* when the
759
- request has no such sentence). The quote is the live request's own sentences with a word for a
760
- condition, found with the service's word list (`if`, `otherwise`, `else`, `unless`, `only when`,
761
- `only if`, `in case`, `whether`, and the Hebrew ones), at most 600 characters
762
- ([`condition-words.ts`](../src/replay/condition-words.ts)). The note has no intent line, no
763
- remaining planned steps and no parameters, and never the condition the service keeps (`stop.why`):
764
- each names, or hints at, the half the recording took. The directive at the prompt leaves the intent
765
- out for the same reason, and says the task comes back *"at a decision"*. The report is `fell_back`
766
- (`failed` when no step ran) with `fallbackKind: "decision"`; the decision step has no verdict, so
767
- nothing counts against it. A runner up to 0.3.18 reads the unknown kind as `known_bad_step`.
768
-
769
- A plan whose chain has a decision keeps these protections when it stops *earlier* for another
770
- reason — a parked or failed step, a judgement, the budget. Its note is the ordinary one above, but
771
- with no intent line and no parameters, and its remaining planned steps end before the decision. Its
772
- directive leaves the intent out too. An agent sent on to the recorded half's steps would start that
773
- half's segment, and the plan would have decided after all.
774
-
775
757
  With `BIR_REPLAY_RECORDED_OUTPUTS=1`, a step that could not be *sent* (a built-in, no proxy, off the
776
758
  allowlist) is served its **recorded output** instead (§8.1), marked `(recorded)` in the bundle so the
777
759
  model is never told a stale result is fresh. A timeout or an upstream error never is.
@@ -910,8 +892,7 @@ requests* — which is what §7.3's ordering rule protects.
910
892
  Built 2026-10-23 for the service's autocorrect.md AC5; not yet released. A task can have two
911
893
  halves: "if engaged users went over the threshold, book a meeting; otherwise send a note". A
912
894
  recording shows one half, so its plan knows one half. The service's correction adds the other half
913
- and a test on each step that belongs to only one of them. A served step, and a sub-task's call
914
- row, may carry:
895
+ and a test on each step that belongs to only one of them. A served step may carry:
915
896
 
916
897
  ```ts
917
898
  when?: { logic: string; otherwise: "skip" | "hand_over"; text?: string | null } | null
@@ -920,16 +901,12 @@ when?: { logic: string; otherwise: "skip" | "hand_over"; text?: string | null }
920
901
 
921
902
  The test runs in the same sandbox as the other logic (`evalWhenLogic`, `src/replay/logic.ts`). It is
922
903
  decided when its step comes due, with what is known then: the request's values and the results of
923
- the steps before it. A call row's test is decided once, in the caller's scope, before the sub-task
924
- starts — where its first step *or its callee's* is: a sub-task whose chain begins with a call
925
- begins with that call's steps, so nothing of it runs before its test says it is needed. A sub-task
926
- is entered there too, before its callee, whose mapping reads its parameters, and left after the
927
- last step of it or its callee (`frameEdges`, `src/replay/flatten.ts`).
904
+ the steps before it.
928
905
 
929
906
  | The test says | What happens |
930
907
  |---|---|
931
908
  | `true` | The step runs. |
932
- | `false`, `otherwise: "skip"` | Nothing is sent. The step is reported `not_taken` and the plan goes on. A skipped call row leaves out its whole sub-task and is reported `not_taken` under its own index. |
909
+ | `false`, `otherwise: "skip"` | Nothing is sent. The step is reported `not_taken` and the plan goes on. |
933
910
  | `false`, `otherwise: "hand_over"` | The plan stops in front of the step and hands the rest of the task to the model, saying the steps from here are only for when `text` (`fallbackKind: other_branch`). |
934
911
  | throws, or not exactly `true` or `false` | The plan stops: the step is `failed` at stage `when_logic` (`fallbackKind: step_failed`). The model is told the plan could not tell whether this request needs the step, and decides itself. Nothing is guessed. |
935
912
 
@@ -937,24 +914,18 @@ A plan whose tests left out every step it came to, and ran none, hands the whole
937
914
  (`other_branch`, step 0). Its report is `failed` with `fallbackKind: other_branch`, and it is sent
938
915
  although it cost nothing: it tells the service the request took the half the plan does not know.
939
916
 
940
- A step left out that is the last of a sub-task still hands the sub-task's results back to its
941
- caller. When the body that maps them throws, the plan stops there: the call row is `failed` at stage
942
- `tool_output_logic`, and the note says the sub-task could not hand back its results — never that
943
- the step left out ran.
944
-
945
917
  - **Direct mode** decides the tests in its loop. The bundle gives a left-out step its own heading,
946
918
  `--- Step 5: tool (not needed) ---`, and says it is only for when `text`, so the model does not run
947
919
  it itself.
948
920
  - **Steer mode** settles the tests after each call. The `PostToolUse` answer names the next step
949
- this request does not need, and the step to call instead. A call to a left-out tool — every tool
950
- of a sub-task left out whole — is answered in its place with the same words, at most twice, and
921
+ this request does not need, and the step to call instead. A call to a left-out tool is answered in its place with the same words, at most twice, and
951
922
  does not end the plan. When the left-out step and the next one share a tool and the note has not
952
923
  reached the model yet, a call the pin guard (§7) finds is not the next step gets the note in its
953
924
  place too, so the step left out never runs because the note was late. A note naming a step to call
954
925
  next is dropped when the plan retires — a divergence, a hand-over — since the plan no longer has
955
926
  that step; only "the sequence is complete" outlives a plan that finished.
956
- - **The divergence bundle** (§8) decides the tests the same way, going on from the sub-task the
957
- cursor is inside, with what that sub-task made so far. A `hand_over` stop ends the bundle there,
927
+ - **The divergence bundle** (§8) decides the tests the same way, going on from where the
928
+ cursor is, with what the plan made so far. A `hand_over` stop ends the bundle there,
958
929
  and the turn is booked `fell_back` when a step did its work (`failed` when none did) — a hand-over,
959
930
  as in the other modes, never `diverged`, so the service takes the agent's work after it as that
960
931
  half's evidence.
@@ -1034,16 +1005,10 @@ note replaces the call, in direct mode `run_scenario` answers with it). The deri
1034
1005
  itself times out after max(`BIR_SERVICE_TIMEOUT_MS`, `BIR_DERIVE_BUDGET_MS`). None of these waits
1035
1006
  happens while the service is cooling down after a failure: the turn simply runs normally.
1036
1007
 
1037
- **Intent arming mid-turn is on by default from 0.3.19.** An intent probe is sent from `PreToolUse`
1038
- for hit counting. While arming is on — `BIR_SEGMENT_ARM` unset or `1`, the recorder's default from
1039
- 0.3.19, or `BIR_INTENT_ARM=1` — the probe may arm a plan in that call's place, and the hook waits at
1040
- most `BIR_INTENT_ARM_BUDGET_MS` (**500**) for it and 1.5 s more for arming. With `BIR_SEGMENT_ARM=0`
1041
- (and no `BIR_INTENT_ARM=1`), or `BIR_INTENT_ARM=0`, it is never waited on. Up to 0.3.18 arming was
1042
- opt-in: a segment runs only mid-task, and a plan that stops at its decision hands the rest of the
1043
- task to segments of its halves, so 0.3.19 turns it on. A probe asks the service to hand segments out
1044
- (`acceptSegments`) only where one can arm: segment and intent arming on, in Claude Code. Any other
1045
- probe — `BIR_INTENT_ARM=0`, or a session of another host — gets what would have armed instead, and
1046
- it is logged (`replay.segment_would_arm`).
1008
+ **Intent arming mid-turn is opt-in.** With `BIR_INTENT_ARM=1`, a `PreToolUse` whose call the agent
1009
+ explained sends an intent probe, and a whole plan it matches may arm in that call's place; the hook
1010
+ waits at most `BIR_INTENT_ARM_BUDGET_MS` (**500**) for the probe and 1.5 s for arming. Unset (or
1011
+ `0`), no probe is sent and nothing arms mid-turn.
1047
1012
 
1048
1013
  `UserPromptSubmit` must stay non-`async`: an async hook is fire-and-forget and cannot return
1049
1014
  `additionalContext` at all.
@@ -1075,8 +1040,7 @@ stopped at a step that broke (a logic failure, a tool error, a call sent and nev
1075
1040
  recorded stand-in (`BIR_REPLAY_RECORDED_OUTPUTS=1`) is never work done: it counts toward neither
1076
1041
  `stepsPinned` nor the upgrade, and a direct run that used one is `diverged` at best. A call that ran
1077
1042
  beside a pinned one hands over as `fell_back` or `failed` (§7), and so does a divergence whose
1078
- bundle stops in front of the other half of an "if … otherwise" (§9.2), or in front of the plan's
1079
- decision (§8). A direct run cancelled by its caller
1043
+ bundle stops in front of the other half of an "if … otherwise" (§9.2). A direct run cancelled by its caller
1080
1044
  (Esc, or `bir-scenario`'s own timeout) books `fell_back` or `failed` with `measured: false`, never
1081
1045
  `diverged`: that turn's cost says nothing about what the task costs.
1082
1046
 
@@ -1185,10 +1149,6 @@ a replay that sent 3600.
1185
1149
  has no output, and neither has a call the host says failed without a result. The exception is a
1186
1150
  step its host stopped itself (§7.4): its verdict keeps what the host handed back, and after a
1187
1151
  changed call it has no input, because only the host knows the arguments that call ran with.
1188
- - **Only for the reported scenario's own steps.** A step inside a called segment is reported with
1189
- its verdict and its `scenarioId`, without payloads: the console still files verdicts by step
1190
- number alone (the service's plan-services.md, W1.9), and a called segment numbers its steps from
1191
- zero too.
1192
1152
 
1193
1153
  `ok` and `recorded` are passes (`recorded` with an asterisk: the values came from the source run,
1194
1154
  which happens only with `BIR_REPLAY_RECORDED_OUTPUTS=1` and in `bir replay`). `skipped` produced no
@@ -1216,8 +1176,7 @@ nothing knows which step the stack trace belonged to. In steer mode there is no
1216
1176
  the controller records the verdict at both hooks: `PreToolUse` for an input-logic throw, `PostToolUse`
1217
1177
  for the pass or the output-logic throw — and keeps the pinned arguments on the pin, so the verdict
1218
1178
  `PostToolUse` writes can say what the call ran with. `ReplayState.stepResults` is keyed by the
1219
- scenario that owns the step and its index, so the second word on a step replaces the first and a
1220
- called segment's step 0 never replaces the caller's.
1179
+ step's index, so the second word on a step replaces the first.
1221
1180
 
1222
1181
  One consequence for the rule that a costless decline is not worth sending (`buildReport`, and the
1223
1182
  service's matching `202 { recorded: false }`): it now *is* worth sending when a step broke. No cost
@@ -1287,15 +1246,6 @@ tokens and every model in the list has a price; with no usage at all, the line s
1287
1246
  `why="the host sent no usage"`. Such a host hands over one number for the whole run, so with more
1288
1247
  than one plan in one run none of them is measured.
1289
1248
 
1290
- **A plan stopped at its decision is billed up to the stop (0.3.19).** When a step of it ran, its
1291
- hand-over takes a usage mark, and its report's window ends there: the agent's decision and the half
1292
- it took are the agent's own, not the plan's (the service's segmentsbreakdown.md SB-26). This holds
1293
- for a plan the prompt started, which gets a way to take a mark only when its stop is a decision, and
1294
- for one an intent match started, whose window already ended at its own retire. Every other plan
1295
- keeps its window — a plan of the prompt is billed for the whole turn up to the next plan, so the
1296
- answer it was asked for stays on its bill — and every other hand-over still takes no mark. A
1297
- decision reached before any step ran takes no mark either: its report is a sample of the whole turn.
1298
-
1299
1249
  ---
1300
1250
 
1301
1251
  ## 12. What the replayed turn records
@@ -1780,12 +1730,12 @@ bir replay status|on|off|allow <a,b>|allow all
1780
1730
 
1781
1731
  bir scenario list GET /recordings/runs runs, iterations, scenario state
1782
1732
  bir scenario show <runId> GET /recordings/runs/:id/scenario intent, params, steps, logic
1783
- bir scenario show <scnId> GET /scenarios/:id the same, by scenario id (segments too)
1733
+ bir scenario show <scnId> GET /scenarios/:id the same, by scenario id
1784
1734
  [--step <n>: one step, with scenarioId and chainRevision first]
1785
1735
  bir scenario calc <runId> POST /recordings/runs/:id/calculate [--force to re-derive in place]
1786
1736
  [--force --discard-edits: re-derive a plan with hand edits]
1787
1737
  bir scenario calc <scnId> --force
1788
- POST /scenarios/:id/recalculate recalculate in place (segments too)
1738
+ POST /scenarios/:id/recalculate recalculate in place
1789
1739
  [--discard-edits: sends {discardEdits: true}]
1790
1740
  bir scenario replay <scnId> --prompt "…" [--dry]
1791
1741
 
@@ -1811,8 +1761,7 @@ are where `bir` changes a scenario by hand, so the rules are strict:
1811
1761
  `--force --note "<why>"`. `check` and `edit` run the same check; `check` never writes. When the
1812
1762
  check had any problem, a forced save is recorded as forced, and `bir investigate` keeps saying so.
1813
1763
  - `<id>` is a `run_` id, resolved to its whole-run scenario with `GET /recordings/runs/:id/scenario`,
1814
- or a `scn_` id, used as it is. A sub-task scenario has only its `scn_` id; for a run with only
1815
- sub-task scenarios, `bir` lists their `scn_` ids. Logic goes in with `--input-logic` /
1764
+ or a `scn_` id, used as it is. Logic goes in with `--input-logic` /
1816
1765
  `--output-logic` from a file, or `-` for stdin — never inline, because shell quoting mangles
1817
1766
  JavaScript. `edit` also takes `--freeze`, `--unfreeze`, `--note` and `--revision <n>` (the
1818
1767
  `expectedRevision` of the body).
@@ -158,8 +158,7 @@ Calculation is a background job. Poll `show` until `state` leaves `calculating`:
158
158
  `409 scenario_exists` means this run already has one. Re-derive it in place — keeping the id and its
159
159
  replay history — with `bir scenario calc run_… --force`. A `run_` id reaches only the run's
160
160
  whole-run scenario. From the next version (not yet released), `bir scenario calc scn_… --force`
161
- does the same by the scenario's own id, a sub-task scenario included; it is the only way to
162
- recalculate a sub-task scenario from `bir`.
161
+ does the same by the scenario's own id.
163
162
 
164
163
  To change one step instead, without recalculating, see §9.2. A plan with steps edited by hand is
165
164
  not rebuilt unless you add `--discard-edits`, which replaces those edits. They stay in
@@ -241,8 +240,10 @@ When replay arms:
241
240
  §7) — and never in plan mode.
242
241
  - **Direct steps are not visible to the permission system at all.** They are dispatched straight to a
243
242
  `bir-proxy`, which calls the upstream on a connection it already holds — or, for Claude Code's own
244
- `Read`, `Glob`, `Grep`, `Edit`, `Write` and `Bash`, run by the recorder itself in the project
245
- folder, any `Bash` command included (`BIR_BUILTIN_TOOLS`, `BIR_BASH_ALLOW`; up to 0.3.7 only the
243
+ `Read`, `Glob`, `Grep`, `Edit`, `Write` and `Bash`, run by the recorder itself from the project
244
+ folder, on any file the agent could reach (from 0.3.21; up to 0.3.20 only files inside the
245
+ project) and any `Bash` command included (`BIR_BUILTIN_TOOLS`, `BIR_PATH_ALLOW`,
246
+ `BIR_BASH_ALLOW`; up to 0.3.7 only the
246
247
  first three). Claude Code never sees them.
247
248
  The `run_scenario` call that starts them is answered `allow` too, while the runner has announced a
248
249
  direct plan; your own deny or ask rules for it still apply.
@@ -253,7 +254,8 @@ That is what makes replay fast, and it is the whole risk. Two things follow:
253
254
  2. Run `bir replay allow <servers>` (§5.3). An allowlist of the servers you are comfortable having
254
255
  called unattended is cheap insurance, and it is the difference between "replay reads a dashboard"
255
256
  and "replay can do anything any wrapped server can do". The same goes for built-ins:
256
- `BIR_BUILTIN_TOOLS=Read,Glob,Grep` keeps writes and commands with the model, and
257
+ `BIR_BUILTIN_TOOLS=Read,Glob,Grep` keeps writes and commands with the model,
258
+ `BIR_PATH_ALLOW=project` keeps the file tools inside the project folder, and
257
259
  `BIR_BASH_ALLOW=git,npm test` (for example) limits the commands the recorder runs itself.
258
260
 
259
261
  Nothing else is approved on your behalf. Outside a matched scenario's own steps, a wrapped MCP call
@@ -327,7 +329,6 @@ Recording : yes
327
329
  · the recorder runs in the background (pid 41820); its audit log is ~/.baseinstrunner/logs/<key>.log
328
330
  · the BaseIn service last answered the recorder 12 s ago
329
331
  · wrapped MCP calls are not approved by the runner: Claude Code asks as it would without it. For headless runs (`claude -p`) allow them in permissions.allow or --allowedTools, or set BIR_CORRELATION_DECISION=allow where the recorder starts
330
- · segments run mid-task — recurring sub-tasks, and the halves after a plan's decision — and so may whole plans (the default; BIR_SEGMENT_ARM=0 turns this off)
331
332
 
332
333
  No problems found.
333
334
  ```
@@ -368,10 +369,10 @@ so there is exactly one switch and it cannot get out of step with itself.
368
369
  | `BIR_STEP_TIMEOUT_MS` | `60000` | Per-step ceiling for one direct `tools/call`, clipped to what the plan has left |
369
370
  | `BIR_LOGIC_TIMEOUT_MS` | `1000` | How long one scenario logic body may run before it is stopped. At most 10 000 |
370
371
  | `BIR_REPLAY_RECORDED_OUTPUTS` | *(unset)* | `1` lets a step that could not be sent (a built-in off `BIR_BUILTIN_TOOLS`, no proxy, a server off the allowlist) stand on its recorded output instead of stopping the plan. Never for a timeout or an upstream error |
371
- | `BIR_BUILTIN_TOOLS` | `Read,Glob,Grep,Edit,Write,Bash` | Built-ins the runner executes itself during a replay, in the session's own project directory and confined to it. A chain whose only non-MCP steps are on this list arms `direct`. A runner-side step never reaches the host's permission prompts, so leave off any tool you want the model to call itself; `Read,Glob,Grep` is the read-only set (the default up to 0.3.7). `none`: every built-in step is steered in the session. Claude Code sessions only: in a LangChain application a tool with one of these names is the application's own, and the runner runs none (§6.5) |
372
+ | `BIR_BUILTIN_TOOLS` | `Read,Glob,Grep,Edit,Write,Bash` | Built-ins the runner executes itself during a replay, from the session's own project directory (which folders the file tools may touch: `BIR_PATH_ALLOW`). A chain whose only non-MCP steps are on this list arms `direct`. A runner-side step never reaches the host's permission prompts, so leave off any tool you want the model to call itself; `Read,Glob,Grep` is the read-only set (the default up to 0.3.7). `none`: every built-in step is steered in the session. Claude Code sessions only: in a LangChain application a tool with one of these names is the application's own, and the runner runs none (§6.5) |
372
373
  | `BIR_BASH_ALLOW` | *(unset: any command)* | Command prefixes a runner-side `Bash` step may run (`*` for all). Unset means any command; `none` means no command, and `Bash` steps are steered in the session. A plan's Bash steps share a working directory, exactly as the host's own Bash tool does — variables and functions do not persist, also as the host's. A call with `run_in_background`, or with its own `timeout` longer than the step's clock (`BIR_STEP_TIMEOUT_MS`), is never started on the runner: the plan hands over in front of it |
373
- | `BIR_SEGMENT_ARM` | *(unset: on, from 0.3.19)* | A segment the service hands out runs mid-task: a recurring sub-task, or a half of a task after a plan's decision. `0` is observe-only: what would have armed is logged (`replay.segment_would_arm`) and nothing is replaced. Up to 0.3.18 observe-only was the default. A recorder started before an update keeps its old default until `bir up --restart` |
374
- | `BIR_INTENT_ARM` | *(unset)* | `1` lets a match found mid-turn arm a plan in the calling tool's place, which means waiting for it (`BIR_INTENT_ARM_BUDGET_MS`, 500); `0` never waits, and then nothing starts mid-task, segments included: what would have armed is logged; unset follows `BIR_SEGMENT_ARM`, so from 0.3.19 it is on unless `BIR_SEGMENT_ARM=0` |
374
+ | `BIR_PATH_ALLOW` | *(unset: any folder, from 0.3.21)* | Folders a runner-side `Read`, `Glob`, `Grep`, `Edit` or `Write` may touch (`*` for all). Unset means any path, as the agent's own tools reach it — a plan that reads the agent's memory file under `~/.claude` runs. `project` is the session's project folder alone (the rule up to 0.3.20); add folders after a comma, `~` for the home folder: `project,~/.claude`. Under a list, a path outside it, symlinks included, is refused and the plan hands over in front of it. `none` means no folder, and the file steps are steered in the session. `Bash` is `BIR_BASH_ALLOW`'s |
375
+ | `BIR_INTENT_ARM` | *(unset: off)* | `1` lets a whole plan whose intent matches the agent's reasoning mid-turn arm in the calling tool's place, which means waiting for it (`BIR_INTENT_ARM_BUDGET_MS`, 500). Unset or `0`: off — no probe is sent and nothing arms mid-turn, as up to 0.3.18 |
375
376
  | `BIR_VERBOSE` | *(unset)* | `1` adds per-step `replay.*` detail lines |
376
377
 
377
378
  The `bir` server reads its own, from the environment Claude Code starts it with:
@@ -494,11 +495,7 @@ Everything replay decides is one line. `grep` for these:
494
495
  | `replay.step` | One direct step executed |
495
496
  | `replay.step_not_taken` | A step's test said this request does not need it, and nothing was sent for it ([calculatedReplay.md](calculatedReplay.md) §9.2). `plan.armed … tests=` lists the tested steps by their place in the plan: `4:hand_over,11:skip` |
496
497
  | `replay.diverge` / `replay.compose` | Off-script, and the recovery |
497
- | `replay.handover` | The plan stopped and handed the rest of the task to the model; `kind=` and `step=` say where. `kind=decision` (0.3.19) is a plan that ran the steps before its decision and stopped there, as planned (`via=divergence` when a divergence's bundle ran up to it) |
498
- | `run.fragment … decision=true` / `run.fragment_dropped` | After a plan's decision: the agent's own work from its next call is recorded as a fragment, from which the service makes a calculated scenario of that way / a plan the intent check armed, or a next scenario, took that call instead, so nothing is recorded as the agent's own |
499
- | `replay.next_ready` / `replay.next_hit` / `replay.next_miss` | 0.3.20: the calculated scenarios that can follow a plan's decision, armed while the agent decided / the agent's call was one's first step, value for value, so it runs in the call's place / none was used: `reason=other_values` (the same first tool with other values), `own_way` (a call that may change something and starts none of them), `not_ready` (the one that starts with that tool was not armed in time), `calls_limit` (5 calls started none), `turn_ended`. A call that only reads ends nothing |
500
- | `run.fragment_closed` | 0.3.20: a scenario that follows the decision took over after the agent's own looks had opened the fragment; the fragment ends there, with what the agent did itself |
501
- | `replay.decision … code=would_repeat` | 0.3.20: a plan an intent match armed after the agent's call would have made that call again (the same tool that may change something, or for a shell the same command), so it was not started (never twice) |
498
+ | `replay.handover` | The plan stopped and handed the rest of the task to the model; `kind=` and `step=` say where |
502
499
  | `replay.vetoed` | A direct plan retired without running anything: `run_scenario` was not the first call, or never arrived |
503
500
  | `replay.run_ambiguous` | Two sessions had `run_scenario` pending and the request named neither; nothing ran |
504
501
  | `replay.cancelled` / `replay.note_kept` | A direct run's caller went away (Esc); no further step started, and the note is kept for the model's next call |
@@ -583,11 +580,6 @@ A recorded output that stood in for a step (`BIR_REPLAY_RECORDED_OUTPUTS=1`) is
583
580
  work done. A direct run you cancel (Esc) is booked `fell_back` or `failed` with `measured: false`:
584
581
  a turn cut short says nothing about what the task costs.
585
582
 
586
- A plan that stops at its decision (runner 0.3.19 or newer) is booked `fell_back` with
587
- `fallbackKind: decision`, or `failed` when no step ran. Nothing is counted against its steps, and
588
- when a step ran its cost ends at the stop: the agent's decision and the half it took are not on the
589
- plan's bill.
590
-
591
583
  A turn's cost is **measured** only when its tokens were found and every model of the turn has a
592
584
  price in the runner's table. A model with no price used to count as $0, and that zero was called
593
585
  measured. Now such a turn is not measured, in Claude Code as in any host, and a `run.unmeasured`
@@ -666,14 +658,12 @@ Code's pool, as before.
666
658
  | `run_scenario` answers "The prepared results are not available for this request. Do the task normally with your tools." | The plan could not be delivered — a recorder that does not answer, a timeout, an HTTP error — and the model does the task itself | The `scenario.answered` line on the `bir` server's stderr has the real reason. `BIR_SCENARIO_DEBUG=1` in that server's environment hands the raw reason to the model as an error, for debugging |
667
659
  | A hand-over note says a step "was sent but did not answer … may or may not have completed" | The step timed out, or its upstream went away mid-call; nothing after it ran | Check whether its work happened before running it again — the model is told the same. Repeats: look at that upstream, or raise `BIR_STEP_TIMEOUT_MS` |
668
660
  | A hand-over note says "a step never runs on another session's upstream" | Two Claude Code sessions are open in the project, and this one has not yet made a call of its own to that server, so bir cannot tell its proxy from the other session's. A direct plan is told apart by the process that started both the `bir` server and the session's proxies, so for one this means an older proxy or `bir` server (restart the session after an update), or a server started through a wrapper such as a shell or `npx` | Expected: the model calls the tool itself. Once the session's own call to the server has gone through, later replays use its proxy |
669
- | A hand-over note says the plan "ran the steps before a decision, and stopped there" | The service split the plan at its "if … otherwise" (runner 0.3.19 or newer): the plan runs the steps both ways need, then the agent decides which way applies. The note quotes the request's own sentences with the condition | Expected. The agent's next step may start a segment of the way it chose (`replay.intent_armed … kind=segment`); with `BIR_SEGMENT_ARM=0` it does that part itself. `bir investigate` shows the run as `fell_back · decision` |
670
- | A hand-over note says a step "did not run: it has failed before", and the step never failed | A runner up to 0.3.18 met a plan's decision, a stop it does not know. It stops there too, but its note names a failure and lists the remaining steps | Update the runner (`bir update`, then `bir up --restart`) |
671
661
  | A hand-over note says a step "was not run by the host", or "ran with arguments a person chose, not the scenario's" | A LangChain application (§6.5). A person said no to the step, or answered in the tool's place, or a call limit blocked the call (`host_rejected`); or a person changed the call before it ran (`host_edited`) | Expected, and no fault of the plan: the step is booked `skipped`, the plan stops there and the model takes over. It is told not to run the step again — after a refusal, unless the user asks. §7 has what the report says |
672
662
  | `recorder.send_failed … error="HTTP 409 … invalid_ticket"` | The execution report's ticket was already redeemed, or belongs to another scenario. Or the report came more than an hour after its plan was handed out | Harmless if the body says `duplicate: true`. Otherwise a rollover raced `SessionEnd`; the server books once. A report that came too late is not booked; the service as built (not deployed yet) takes a report for 24 hours |
673
663
  | `recorder.send_failed … error="HTTP 429 …"` | The account is over one of the service's limits, and the answer is `429` with `Retry-After`. The limits are built on the service and not deployed yet; each is a setting there. By default: 120 runs a minute · 3,000 steps a minute (a tool call is two steps) · 10 title requests a minute · 20 requests in any one hour for Calculate, Prefer and Recalculate together (`bir scenario calc` then prints a line that begins `Could not start calculation (HTTP 429`) | What it costs: a create, a step or a report is sent once more, at most 2 s later, then dropped. A dropped step is a hole in its recording. A run whose create got the 429 runs without its plan. A 429 that the second try did not cure counts as the service being unwell: for 5 to 60 seconds no prompt of that recorder waits for a match. An intent probe over its own limit (1,500 a minute) is answered with no match, never with `429` |
674
664
  | `savedUsd` looks impossible | Pricing drift between the runner's table and the server's | Compare `PRICING_VERSION` on both sides. Design §11.3 documents a known live drift between two existing copies |
675
665
  | The hand-over note says a step "did not run: its input needs a judgement" | The service marked the step non-deterministic when it calculated the plan: the generated logic could not compute its input from the prompt or from earlier outputs, so the recorded value was a copy (the service's plan-services design, D8 kind 3 — it lives in the BaseIn repository, not this one). `nondeterministicWhy: by_hand` means someone marked it with `bir scenario edit --freeze` | If the code only has a slip, fix the step yourself: `bir scenario show scn_… --step <n>`, write the input logic to a file, then `bir scenario edit scn_… --step <n> --input-logic <file>` — the service checks it against the recording before it saves it (§9.2, not yet released). Of the edits, only `--unfreeze` lifts a mark made by hand (`by_hand`); a code edit, even a forced one, leaves it in place. A real judgement — a choice with no fixed rule — cannot be written as code: the agent makes that choice and finishes the task; a model step for it is planned (W3.1). The journal's `plan.armed` line lists the step under `stops=` |
676
- | A parked step ran again after an hour, or a plan was recalculated by itself | The service's grace period (D8): a parked step is served with `stop: null` once an hour for a day and a success clears its count; if it keeps failing, or its tool is gone, the next repeat of the prompt is recorded in full and the plan is calculated again from it | Nothing: that is the repair. `bir investigate` says which it is — a step still being retried, a parked step whose repair is due, or a plan being calculated again. To repair now by hand: `bir scenario calc <runId> --force` for a whole-run plan; from the next version, `bir scenario calc <scnId> --force` works for any plan, a sub-task one included. A plan with steps edited by hand is not repaired by itself: the parked step stays parked, and `bir investigate` says the repair was skipped. Then fix the step (§9.2); or take the edits back with `bir scenario undo`, once per edit, and it is repaired as usual; or recalculate now and drop the edits: `bir scenario calc <scnId> --force --discard-edits` |
666
+ | A parked step ran again after an hour, or a plan was recalculated by itself | The service's grace period (D8): a parked step is served with `stop: null` once an hour for a day and a success clears its count; if it keeps failing, or its tool is gone, the next repeat of the prompt is recorded in full and the plan is calculated again from it | Nothing: that is the repair. `bir investigate` says which it is — a step still being retried, a parked step whose repair is due, or a plan being calculated again. To repair now by hand: `bir scenario calc <runId> --force` for a whole-run plan; from the next version, `bir scenario calc <scnId> --force` works by the plan's own id. A plan with steps edited by hand is not repaired by itself: the parked step stays parked, and `bir investigate` says the repair was skipped. Then fix the step (§9.2); or take the edits back with `bir scenario undo`, once per edit, and it is repaired as usual; or recalculate now and drop the edits: `bir scenario calc <scnId> --force --discard-edits` |
677
667
  | `sessionCostUsd` grows every prompt in a session | The per-run usage watermark is missing or not taken | Design §11.4. Reports without a mark must carry `measured: false` |
678
668
  | `run.unmeasured` in the log, and `bir investigate` shows the report as `UNMEASURED` | The turn's cost is not measured. The run opened before any hook carried a transcript path, or the runner has no price for a model of the turn (`models=` names it). In a LangChain application: the adapter sent no usage, the run made no model call, or a model has no price | Update the runner when it has no price for the model. The report is booked as not measured. A model with no price used to count as $0 and measured (§7) |
679
669
  | Everything works, nothing is saved | A replayed turn is deliberately not recorded (design §12) | Correct. The matched run stays canonical and its `iterations` is bumped |
@@ -799,8 +789,7 @@ bir scenario editing on|off|status
799
789
  ```
800
790
 
801
791
  A `run_` id finds the run's whole-run scenario. A `scn_` id (what `bir investigate` prints) is used
802
- as it is. A sub-task scenario has only a `scn_` id. When a run has only sub-task scenarios, `bir`
803
- lists their `scn_` ids instead of guessing. `--step` is the `stepIndex` that `show` prints; it
792
+ as it is. `--step` is the `stepIndex` that `show` prints; it
804
793
  starts at 0. `--revision <n>` saves only if the plan is still at revision `n`: the `chainRevision`
805
794
  at the top of `show --step`. `--json` on `check`, `edit`, `edits` or `undo` prints the service's
806
795
  answer unchanged. Exit codes: `0` checked OK, saved or undone · `1` refused, not found, or a
@@ -829,8 +818,7 @@ code in its own process, with the global scope and only a time limit, where `fet
829
818
  do exist. So read every change before it is saved — yours and Claude's.
830
819
 
831
820
  **Only a step's code and its mark can be changed — and a parameter's kind (below, *A value no prompt names*).**
832
- Not the parameters' sample values, not the logic that builds the final answer. Only tool steps: a
833
- sub-task call row belongs to the service.
821
+ Not the parameters' sample values, not the logic that builds the final answer.
834
822
 
835
823
  #### The fix, step by step
836
824
 
@@ -1027,8 +1015,6 @@ call with a mistake you do not want repeated. Then no correct code can reproduce
1027
1015
  as a `warn`.
1028
1016
  - A forced save removes a mark **the calculation** set, unless you also pass `--freeze`. A mark
1029
1017
  made **by hand** (`--freeze`) stays. A save lifts it only with `--unfreeze`.
1030
- - A step after a sub-task call row can only be saved with `--force`: the check cannot rebuild the
1031
- outputs that step reads.
1032
1018
 
1033
1019
  #### Mark or unmark a step by hand
1034
1020
 
@@ -1166,13 +1152,11 @@ Not recalculated: steps 3, 4 were edited by hand, and a recalculation rebuilds e
1166
1152
  ```
1167
1153
 
1168
1154
  A `run_` id reaches only the run's whole-run scenario. `bir scenario calc <scnId> --force`
1169
- recalculates any scenario in place, by its own id, a sub-task scenario included. Add
1155
+ recalculates any scenario in place, by its own id. Add
1170
1156
  `--discard-edits` when it has hand edits. A `scn_` id without `--force` is refused before anything
1171
1157
  is sent: a scenario that exists can only be recalculated.
1172
1158
 
1173
- The console's *Recalculate* button (on a sub-task's scenario) is refused too while a plan has hand
1174
- edits; the console does not discard them. The service's own rebuilds — the repair of a parked step
1175
- (§9) and the adoption of a sub-task — skip a plan with hand edits. `bir investigate` says that the
1159
+ The service's own rebuild — the repair of a parked step (§9) — skips a plan with hand edits. `bir investigate` says that the
1176
1160
  service does not rebuild the plan on its own, and warns when it skipped a repair
1177
1161
  (`repair_skipped_edits`). After `--discard-edits` the old edits stay readable, but they cannot be
1178
1162
  undone (`edit_replaced`).
@@ -1344,12 +1328,11 @@ Parameter database: target → setting (revision 4). Undo: bir scenario undo scn
1344
1328
  | A `later` step no longer reproduces | The change broke a step after it — usually output logic that stopped keeping a value a later step reads | Keep every key the later steps read |
1345
1329
  | `too costly to check` | The check used up its 5 seconds of sandbox time (`EDIT_CHECK_BUDGET_MS`). Usually code that reads or keeps a great many values, so the check has to run it very many times | Make the code cheaper to run, then check again |
1346
1330
  | `Nothing to change: the step already has this code and this mark.` | The code and the mark you gave are what the step already has (`nothing_to_change`) | Nothing to do. `check` says `Nothing would change` for the same case |
1347
- | `not_a_tool_step` | The index is a sub-task call row, not a tool step | Call rows cannot be edited; the service writes them |
1348
1331
  | `note_required` | `--force` without `--note` | Add `--note "why"` |
1349
1332
  | `revision_changed` | The plan changed since you read it: another edit, or a recalculation | `show` it again, check again, save again |
1350
1333
  | `not_ready` or `scenario_calculating` | The scenario is not `ready`, or a recalculation is running | Wait for it to finish |
1351
1334
  | `undo_refused` | The undo would stop a later step from giving its recorded call, or leave the final answer without its values | Fix that later step first. Or undo it on purpose: `--force --note "why"` |
1352
- | `not_latest_edit` | The step has changed since the edit you named: a newer entry changed it. For a correction: the plan has changed since it. When the newer entry is an `ssplit_…` id, the plan was split at its decision after the correction, and a correction cannot be taken back while the split is in use | `bir` prints two commands: undo the newer one first, then yours. For a split, `bir` says to press Undo on the Split card of the plan's recording page first, and prints the command for yours |
1335
+ | `not_latest_edit` | The step has changed since the edit you named: a newer entry changed it. For a correction: the plan has changed since it | `bir` prints two commands: undo the newer one first, then yours |
1353
1336
  | `already_undone` | That edit was undone already | To redo it, undo the undo. `bir` prints the command |
1354
1337
  | `edit_replaced` | A recalculation replaced the plan after that edit | Nothing to undo; the edit is history now |
1355
1338
  | `logic_sandbox_unavailable` | The service could not run step code just now (HTTP 503). Nothing was checked, saved or undone | Try again in a minute |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basein/runner",
3
- "version": "0.3.20",
3
+ "version": "0.3.22",
4
4
  "description": "A recording MCP proxy: sits between any MCP client and its MCP servers, executes each call on the client's behalf, and records the run as a reusable BaseIn scenario.",
5
5
  "type": "module",
6
6
  "license": "MIT",