@assuredloop/orca-bot-kit 0.1.0 → 0.3.0

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 (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +548 -3
  3. package/SETUP.md +275 -0
  4. package/package.json +32 -13
  5. package/rules/evidence.md +15 -0
  6. package/rules/finishing.md +23 -0
  7. package/rules/limits.md +18 -0
  8. package/rules/mail.md +17 -0
  9. package/rules/profiles.md +9 -0
  10. package/rules/review.md +14 -0
  11. package/rules/scope.md +22 -0
  12. package/rules/simple.md +14 -0
  13. package/rules/talk.md +13 -0
  14. package/rules/tests-first.md +17 -0
  15. package/rules/the-ask.md +19 -0
  16. package/skills/obk-arch/LICENSES.md +52 -0
  17. package/skills/obk-arch/NOTICE.md +242 -0
  18. package/skills/obk-arch/SKILL.md +598 -0
  19. package/skills/obk-bot-building/LICENSES.md +21 -0
  20. package/skills/obk-bot-building/NOTICE.md +113 -0
  21. package/skills/obk-bot-building/SKILL.md +312 -0
  22. package/skills/obk-debugging/LICENSES.md +67 -0
  23. package/skills/obk-debugging/NOTICE.md +115 -0
  24. package/skills/obk-debugging/SKILL.md +434 -0
  25. package/skills/obk-decision-memo/LICENSES.md +49 -0
  26. package/skills/obk-decision-memo/NOTICE.md +181 -0
  27. package/skills/obk-decision-memo/SKILL.md +241 -0
  28. package/skills/obk-finops/LICENSES.md +19 -0
  29. package/skills/obk-finops/NOTICE.md +77 -0
  30. package/skills/obk-finops/SKILL.md +148 -0
  31. package/skills/obk-fleet-review/LICENSES.md +52 -0
  32. package/skills/obk-fleet-review/NOTICE.md +104 -0
  33. package/skills/obk-fleet-review/SKILL.md +256 -0
  34. package/skills/obk-grilling/LICENSES.md +42 -0
  35. package/skills/obk-grilling/NOTICE.md +111 -0
  36. package/skills/obk-grilling/SKILL.md +221 -0
  37. package/skills/obk-grooming/LICENSES.md +52 -0
  38. package/skills/obk-grooming/NOTICE.md +111 -0
  39. package/skills/obk-grooming/SKILL.md +222 -0
  40. package/skills/obk-handoff/LICENSES.md +45 -0
  41. package/skills/obk-handoff/NOTICE.md +51 -0
  42. package/skills/obk-handoff/SKILL.md +119 -0
  43. package/skills/obk-personal-facilitation/LICENSES.md +53 -0
  44. package/skills/obk-personal-facilitation/NOTICE.md +62 -0
  45. package/skills/obk-personal-facilitation/SKILL.md +86 -0
  46. package/skills/obk-recall/LICENSES.md +42 -0
  47. package/skills/obk-recall/NOTICE.md +53 -0
  48. package/skills/obk-recall/SKILL.md +129 -0
  49. package/skills/obk-researching/LICENSES.md +67 -0
  50. package/skills/obk-researching/NOTICE.md +170 -0
  51. package/skills/obk-researching/SKILL.md +269 -0
  52. package/skills/obk-reviewing/LICENSES.md +66 -0
  53. package/skills/obk-reviewing/NOTICE.md +58 -0
  54. package/skills/obk-reviewing/SKILL.md +411 -0
  55. package/skills/obk-tdd/LICENSES.md +68 -0
  56. package/skills/obk-tdd/NOTICE.md +54 -0
  57. package/skills/obk-tdd/SKILL.md +547 -0
  58. package/skills/obk-tdd/mutation-tools.md +80 -0
  59. package/skills/obk-teach/LICENSES.md +42 -0
  60. package/skills/obk-teach/NOTICE.md +65 -0
  61. package/skills/obk-teach/SKILL.md +106 -0
  62. package/skills/obk-why/LICENSES.md +42 -0
  63. package/skills/obk-why/NOTICE.md +74 -0
  64. package/skills/obk-why/SKILL.md +180 -0
  65. package/skills/obk-writing/LICENSES.md +272 -0
  66. package/skills/obk-writing/NOTICE.md +161 -0
  67. package/skills/obk-writing/SKILL.md +254 -0
  68. package/src/book.js +268 -0
  69. package/src/bot.js +451 -0
  70. package/src/cli.js +1169 -0
  71. package/src/conversations.js +150 -0
  72. package/src/groom.js +159 -0
  73. package/src/health.js +309 -0
  74. package/src/hooks.js +257 -0
  75. package/src/init.js +314 -0
  76. package/src/launch.js +299 -0
  77. package/src/message.js +402 -0
  78. package/src/orca.js +362 -0
  79. package/src/pause.js +63 -0
  80. package/src/record.js +209 -0
  81. package/src/restart.js +193 -0
  82. package/src/retire.js +92 -0
  83. package/src/roster.js +71 -0
  84. package/src/rules.js +408 -0
  85. package/src/skills.js +630 -0
  86. package/src/sources.js +371 -0
  87. package/src/up.js +500 -0
  88. package/src/usage.js +401 -0
  89. package/bin/okb.js +0 -4
  90. package/src/index.js +0 -11
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Wenqing Gu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,10 +1,555 @@
1
- # @assuredloop/orca-bot-kit
1
+ # Orca Bot Kit
2
2
 
3
- Orca bot kit.
3
+ A kit for running a small fleet of long-lived role bots on your own computer —
4
+ a manager, developers, reviewers, a personal helper. Each bot keeps its
5
+ identity, its rules, its skills and its sessions across restarts.
6
+
7
+ [Orca](https://github.com/stablyai/orca) is the host: a bot is an Orca project
8
+ and a session is a tab, on Claude Code or Codex. The kit is an npm package with
9
+ an `obk` command and a set of skills. You are meant to manage the fleet by
10
+ talking to Bot Father, the first bot, whose skills call the CLI for you — not by
11
+ editing files.
12
+
13
+ The design is in [`docs/prd.md`](docs/prd.md); the decisions with lasting
14
+ consequences are in [`docs/adr/`](docs/adr/); what we know about Orca and the
15
+ two harnesses is in [`docs/tech-notes.md`](docs/tech-notes.md).
16
+
17
+ ## Start here
18
+
19
+ Paste this into any AI session that can run commands — a Claude Code or Codex
20
+ session in a terminal, or anything else with a shell:
21
+
22
+ > Set up Orca Bot Kit on this machine: get
23
+ > https://github.com/guwenqing/orca-bot-kit, then follow SETUP.md in it to the
24
+ > end.
25
+
26
+ It checks what your machine already has, tells you plainly about anything
27
+ missing rather than installing it, asks you the only two things it cannot work
28
+ out for itself — where your bots folder goes, and which harness Bot Father runs
29
+ on — and leaves you talking to Bot Father, which is where everything after this
30
+ happens.
31
+
32
+ [`SETUP.md`](SETUP.md) is that page. It is written for the assistant rather than
33
+ for you, so you do not have to read it; nothing in it is hidden from you either.
34
+
35
+ The rest of this README is the reference: what each command does, and why the
36
+ kit is built the way it is. Reach for it when you want to know how something
37
+ works, not to get started.
38
+
39
+ ## Reporting a problem
40
+
41
+ When the kit itself goes wrong (an `obk` command fails in a way its own message
42
+ does not explain, or does something other than what it says), open an issue on
43
+ this repository's Issues page (the address `package.json` gives as `bugs`) with
44
+ the form there. It asks for the command and its whole output, what you expected,
45
+ `obk health --json`, and the versions of `obk`, Node, Orca and the harness. Take
46
+ out anything private first: issues are public.
47
+
48
+ Bot Father is told the same thing. Tell it what went wrong and it gathers these
49
+ details and, when you say so, files the issue or gives you the text to paste.
50
+
51
+ ## Status
52
+
53
+ Early. The CLI creates your bots folder, brings Bot Father up in Orca, creates
54
+ bots and their sessions on either harness, and builds each bot's `AGENTS.md`
55
+ from its charter and the rules it carries.
4
56
 
5
57
  ## Install
6
58
 
59
+ Node.js >= 24.21.0, git, and Orca with at least one of Claude Code or Codex
60
+ installed and configured. That line because the kit keeps writers out of each
61
+ other's way in a bot's book with a SQLite write transaction, through Node's own
62
+ `node:sqlite`. That module is older than the 24 line; 24.21.0 is the first
63
+ release measured here that loads it without an experimental warning on stderr,
64
+ which would otherwise land in the output of every command.
65
+
7
66
  ```sh
8
67
  npm install -g @assuredloop/orca-bot-kit
9
- okb --version
68
+ obk --version
69
+ ```
70
+
71
+ The command is `obk`. If `obk --version` does not answer after that, npm has no
72
+ working release yet (an early placeholder has no `obk` in it): run
73
+ `npm uninstall -g @assuredloop/orca-bot-kit`, then install from a clone of this
74
+ repository with `npm install` and `npm link`. To work on the kit itself, run
75
+ your clone's `src/cli.js` by its full path instead of linking it: the `obk` on
76
+ PATH stays the published one, and the kit calls itself back by the path of the
77
+ CLI that started it, so what your clone brings up calls back into your clone.
78
+
79
+ Releases go out from CI: publishing a GitHub Release tagged `v<version>` runs
80
+ `.github/workflows/publish.yml`, which runs the suite and publishes that version
81
+ to npm with a provenance statement. Nothing else publishes.
82
+
83
+ ## Create your bots folder
84
+
85
+ ```sh
86
+ obk init --bots /absolute/path/to/my-bots --harness claude
87
+ ```
88
+
89
+ `--harness claude|codex` says which harness Bot Father itself runs on; there is
90
+ no default. This makes the folder a git repository and seeds it:
91
+
92
+ ```
93
+ my-bots/
94
+ .gitignore # what obk links here, which no clone carries
95
+ defaults.yaml # rules and skills every bot gets
96
+ skills.yaml # online skill sources
97
+ rules/ # your own rule units
98
+ skills/ # your own common skills
99
+ bots/bot-father/bot.yaml # Bot Father: charter, rules, skills, sessions
100
+ ```
101
+
102
+ The folder is yours. It holds your configuration and none of the kit's code —
103
+ kit skills are linked from the installed package, never copied
104
+ ([ADR 0014](docs/adr/0014-skills-are-linked-never-copied.md)). Run `init` again
105
+ whenever you like: it adds what is missing and leaves everything else, including
106
+ your edits, exactly as it is. It does not commit for you.
107
+
108
+ The `.gitignore` keeps out the skill links, and the kit's own record of which
109
+ ones it made (`.obk-skills.yaml` in each bot folder). The links point at
110
+ where the kit and your skill sources are installed on this machine, so they say
111
+ nothing true on another one, and `obk up` makes them again wherever you check
112
+ the repo out. So a clone carries your bots and not this machine's paths, and two
113
+ computers do not take turns rewriting each other's links. Anything of your own
114
+ in a bot's skills directories is still yours: `git add --force` takes it in.
115
+
116
+ ## Add a bot and its sessions
117
+
118
+ ```sh
119
+ obk bot create --bots /path/to/my-bots --name api-bot --harness codex \
120
+ --charter 'Api Bot owns the API clone.'
121
+ obk session add --bots /path/to/my-bots --bot api-bot --name daily \
122
+ --effort high --work-dir work/api \
123
+ --prompt 'Keep the API clone green. Ask before you touch main.'
124
+ obk up --bots /path/to/my-bots
125
+ ```
126
+
127
+ `bot create` writes the bot's folder — `bot.yaml`, the `AGENTS.md` built from
128
+ that file and the rule units, `CLAUDE.md` as a symlink to it, and a `.gitignore`
129
+ for `work/`.
130
+ `session add` writes one session into `bot.yaml`: its harness (the bot's unless
131
+ it says otherwise), model, effort, context window, approval level, start prompt,
132
+ work dir and any extra arguments for the harness. A start prompt is either text
133
+ (`--prompt`) or, when it is long, a file in the bot home the session points at
134
+ (`--prompt-file prompts/reviewer.md`), and it reaches the harness as written,
135
+ apart from two things the kit does on purpose: blank space at either end is
136
+ trimmed, and when the session has a work dir the kit appends its one-sentence
137
+ note about it. Anything you leave out is the
138
+ harness's own default; the kit names no model of its own. The approval level is
139
+ `auto` — the harness's real auto mode — unless you ask for `ask` or, in those
140
+ words, `dangerously-skip`
141
+ ([ADR 0015](docs/adr/0015-three-approval-levels-auto-by-default.md)).
142
+
143
+ Neither command touches Orca. `obk up` is what makes it all real there: an Orca
144
+ project per bot, a tab per session, each started at the bot home with its own
145
+ launch command and its start prompt. It only ever adds — it never closes a tab —
146
+ so run it after a restart, or whenever something is missing. `--bot` and
147
+ `--session` bring up one thing rather than the fleet.
148
+
149
+ ## The rules a bot works by
150
+
151
+ Each bot has one `AGENTS.md`, shared by all its sessions: its charter, then the
152
+ rule units it uses
153
+ ([ADR 0013](docs/adr/0013-agents-md-is-compiled-from-rule-units.md)). A rule
154
+ unit is one short block of always-on working rules. The kit's own units live in
155
+ [`rules/`](rules/) in this package; yours go in `rules/` inside your bots
156
+ folder. What is always on stays short, because every session reads it on every
157
+ turn; the depth belongs in skills.
158
+
159
+ ```sh
160
+ obk rules build --bots /path/to/my-bots [--bot api-bot]
161
+ ```
162
+
163
+ That writes the file, and `obk up` does the same for every bot it brings up,
164
+ before any session starts — a session reads its rules as it comes up, so a
165
+ rebuild landing after the tab is open would reach nobody. The build owns a
166
+ marked block and nothing else in the file:
167
+
168
+ ```
169
+ <!-- obk:rules 6f1cfe05a4d3b2e9 — built by obk from bot.yaml and the rule units; ... -->
170
+ # Api Bot
171
+
172
+ ## Charter
173
+ ...
174
+ <!-- obk:rules end -->
175
+ ```
176
+
177
+ Write what you like above or below that block and it comes back exactly as you
178
+ left it. Edit inside it and the build stops, tells you, and leaves your words
179
+ alone — the checksum on the begin marker is how it knows its own text from
180
+ yours. A bot carries every kit unit marked `applies: all` without asking for
181
+ them; anything else is named in a `rules:` list, in `defaults.yaml` for every
182
+ bot or in one bot's `bot.yaml`, as `kit:<name>` for one of the kit's or a bare
183
+ name for one of yours. Codex reads at most 32 KiB of an instructions file and
184
+ says nothing when it stops, so the build tells you when a bot's file goes over.
185
+
186
+ Nine units suit every bot, whatever it does:
187
+
188
+ | | |
189
+ |---|---|
190
+ | `the-ask` | reading the whole request, which questions are yours to answer |
191
+ | `simple` | the smallest thing that answers it, and reusing what is there |
192
+ | `scope` | changing what the work needs and leaving the rest |
193
+ | `evidence` | what you saw, what you worked out, and not inventing either |
194
+ | `finishing` | the check you can run, run on the real thing, reported as it came |
195
+ | `limits` | the charter, what needs a yes, no quiet substitutes |
196
+ | `talk` | answer first, short, real names |
197
+ | `mail` | asking the kit for the road to another session; mail is queued |
198
+ | `profiles` | the few lines the fleet keeps on each bot, for choosing who to hand work to |
199
+
200
+ Two more are for bots that write code: `tests-first`, a failing test first and
201
+ someone else writing it, and `review`, someone who did not write the work
202
+ reading it.
203
+
204
+ They are the essence, not the depth: how to debug, how to review well, how to
205
+ write a test worth keeping and how to hand work over belong to the skills a bot
206
+ picks. They are also defaults, not fences — a bot uses the ones its owner
207
+ picks, your own units sit beside them, and a bot does what its user asks of it.
208
+ Why the set is this size is in
209
+ [`docs/proposals/41-common-rules.md`](docs/proposals/41-common-rules.md).
210
+
211
+ A unit is a markdown file whose frontmatter carries `name` (the file's own
212
+ name), `title` (the heading it gets in `AGENTS.md`) and `applies` (`all` or
213
+ `code`); the body is the rule text and nothing else.
214
+ [`test/kit-rules.test.js`](test/kit-rules.test.js) holds that shape, and the
215
+ size the always-on set may reach.
216
+
217
+ ## The skills a bot uses
218
+
219
+ The kit ships its own skills in [`skills/`](skills/), one directory per skill,
220
+ named `obk-<technique>`
221
+ ([ADR 0019](docs/adr/0019-skills-by-technique-with-a-prefix.md)). They are
222
+ organised by technique rather than by role: a role is a charter plus a choice
223
+ of skills. Each one gives techniques and defaults, never a process or
224
+ a way of working you have to adopt, and carries what it needs itself rather
225
+ than relying on another skill being loaded.
226
+
227
+ | | |
228
+ |---|---|
229
+ | `obk-tdd` | a failing test first, a separate test author, the mutation check |
230
+ | `obk-reviewing` | giving a review that is worth acting on, and answering one |
231
+ | `obk-debugging` | a check that goes red first, the real cause, proof where it broke |
232
+ | `obk-arch` | what is wanted, the shape, runnable and testable, work in slices |
233
+ | `obk-grilling` | interviewing a plan until it holds, and writing down what was settled |
234
+ | `obk-handoff` | stopping somewhere safe, and the note a cold reader can act on |
235
+ | `obk-recall` | where a piece of work actually stands, before carrying on with it |
236
+ | `obk-why` | why the code is like this, and how sure you are |
237
+ | `obk-teach` | explaining something so it lands, at the other person's pace |
238
+ | `obk-personal-facilitation` | keeping someone's own list true, and stopping before the step that cannot be taken back |
239
+ | `obk-researching` | finding it out from sources, and saying how well you know it |
240
+ | `obk-writing` | writing for a reader, in one kind of piece, with the claims checked |
241
+ | `obk-decision-memo` | the conclusion first, the alternatives, and the argument against it |
242
+ | `obk-bot-building` | what a bot owns, the charter interview, and the skills the job needs |
243
+ | `obk-fleet-review` | one verdict per bot, the cheaper answers first, and where a problem goes |
244
+ | `obk-grooming` | the daily pass: only what changed, one output checked, one short report |
245
+ | `obk-finops` | what a result cost, live prices, and which limits are really enforced |
246
+
247
+ A skill is where the depth lives. The always-on rules say that a change in
248
+ behaviour starts with a failing test someone else wrote and is read by someone
249
+ who did not write it; `obk-tdd` is how to write a test worth keeping and find
250
+ out whether the tests would catch a real mistake, and `obk-reviewing` is how to
251
+ read a change so the findings are worth acting on, and how to answer a reading
252
+ of your own.
253
+
254
+ A bot gets the ones its lists name:
255
+
256
+ ```sh
257
+ obk skills build --bots /path/to/my-bots [--bot api-bot]
258
+ ```
259
+
260
+ `skills:` in `defaults.yaml` gives them to every bot and `skills:` in a bot's
261
+ `bot.yaml` to that one. An entry is `kit:<name>` for one of the kit's, a bare
262
+ name for a directory in `skills/` inside your bots folder, or anything with a
263
+ `/` in it for a skill directory anywhere on disk. `obk up` links them before it
264
+ opens a tab, and `bot create` gives a new bot what the lists already name.
265
+
266
+ What lands in the bot is a symlink, never a copy
267
+ ([ADR 0014](docs/adr/0014-skills-are-linked-never-copied.md)) — into
268
+ `.claude/skills` and `.agents/skills` in the bot home, which is where each
269
+ harness reads a project's skills from. So a kit skill is read where npm
270
+ installed it, editing a skill is what a running session reads without a
271
+ restart, and updating the kit updates every bot at once.
272
+
273
+ The kit takes away only what it can prove it put there. It writes down every
274
+ link it makes, in `.obk-skills.yaml` in the bot folder, and when no list names
275
+ one any more it takes that link away, whichever shelf it came from, as long as
276
+ the link is still the one it wrote. Anything else in those directories is left
277
+ alone and shown as yours: a skill you wrote there, a link of your own, or one of
278
+ the kit's that you have since pointed somewhere else. If you want one of those
279
+ gone, delete it yourself; the skill a link points at is never touched.
280
+
281
+ ## Skills from somebody else's repo
282
+
283
+ `skills.yaml` in your bots folder lists where else skills come from:
284
+
285
+ ```yaml
286
+ sources:
287
+ - name: someones-skills
288
+ repo: https://github.com/someone/skills
289
+ path: skills # subfolder inside the repo, optional
290
+ ref: v1.2.0 # branch, tag or sha
291
+ ```
292
+
293
+ ```sh
294
+ obk skills fetch --bots /path/to/my-bots [--source someones-skills]
295
+ obk skills update --bots /path/to/my-bots [--source someones-skills]
10
296
  ```
297
+
298
+ `fetch` clones each source into `<your-bots-folder>.skill-sources/`, a sibling
299
+ of your repo and never inside it, at the version you pinned, and writes the sha
300
+ it got back beside your `ref`. A source that is already there it leaves exactly
301
+ as it is — no network, no moving — even when the `ref` is a branch that has gone
302
+ on ahead. `update` is the asking, and it is the only thing that moves one. So
303
+ the version your bots run changes when you say so and at no other time; `obk up`
304
+ never fetches.
305
+
306
+ A bot names one of those skills `<source>:<skill>` in its `skills:` list, beside
307
+ the other three forms. Moving a source moves what every session reading it sees,
308
+ with no rebuild, because the link points at the clone.
309
+
310
+ The kit says one line when a source carries scripts or hooks. It does not read
311
+ them and does not stand in your way — a third-party skill is your risk to take
312
+ ([ADR 0014](docs/adr/0014-skills-are-linked-never-copied.md)).
313
+
314
+ A skill is a directory holding `SKILL.md` — frontmatter carrying `name` (the
315
+ directory's own name) and `description`, then the body — plus any reference
316
+ files it links to and a `NOTICE.md` naming the sources it was built from and
317
+ their licences. The notice travels with the skill, which is what the licences
318
+ ask for, and stays out of `SKILL.md`, which a bot reads into its context every
319
+ time the skill is used. Those two keys are the only frontmatter both Claude Code and
320
+ Codex read, so a kit skill carries nothing else, and its links stay inside its
321
+ own directory, because a bot gets the directory alone.
322
+ [`test/kit-skills.test.js`](test/kit-skills.test.js) holds that shape.
323
+
324
+ ## Sessions that come back
325
+
326
+ Each bot keeps a book, `sessions.yaml` in its folder: which Orca tab each session
327
+ lives in, which harness session it is running as, and every id it ran as before,
328
+ with why that one ended and when
329
+ ([ADR 0012](docs/adr/0012-the-book-is-the-authority-for-session-ids.md)).
330
+
331
+ The book stays true to the harness through a hook `obk up` puts in the bot's own
332
+ folder — `.claude/settings.json` or `.codex/hooks.json`, never your user-level
333
+ settings ([ADR 0020](docs/adr/0020-kit-hooks-live-in-the-bot-folder.md)). Your own
334
+ settings in those files are kept. Codex asks you to trust a hooks file the first
335
+ time it sees one; answer its question in the tab.
336
+
337
+ So: kill a tab, or reboot, and `obk up` brings the session back with the
338
+ conversation it was having, rather than starting a new one. Clear a session —
339
+ `/clear` on Claude Code, `/new` on Codex — and the kit writes down the new id,
340
+ keeps the old one, and gives the session its start prompt again, because that
341
+ prompt is what tells one session's duty from another's.
342
+
343
+ One tab holds one session: the harness the kit started in it. Anything that
344
+ session runs inside the tab — a `codex exec`, a helper, a subagent's own process
345
+ — is not the session, and never becomes the conversation the kit brings back.
346
+
347
+ And when the kit cannot say which conversation a session is, it does not pick
348
+ one. The usual reason is a Codex hooks file trusted after the session had already
349
+ begun talking: nothing was recorded for that first conversation, and trusting the
350
+ file does not go back for it.
351
+
352
+ A bot's sessions all live in one folder, and so does every harness they start
353
+ inside themselves, so a conversation sitting in that folder says nothing about
354
+ whose it is — and neither harness writes down anything that ties a conversation
355
+ that has ended to the session that had it. So the kit writes what it found into
356
+ the book as `unclaimed`, tells you the ids, and starts the session on a fresh
357
+ conversation with its duty rather than guessing. To bring one back yourself,
358
+ write it into `sessions.yaml` under that session as `session: <id>` and run
359
+ `obk up` again.
360
+
361
+ ## Restarting a session
362
+
363
+ A restart is rare and never automatic: `obk up` only ever adds, because closing
364
+ a tab takes your screen away and Orca's resume record with it. When you do want
365
+ one, ask for it.
366
+
367
+ ```sh
368
+ obk restart --bots /path/to/my-bots --bot api-bot [--session daily]
369
+ ```
370
+
371
+ It closes the session's tab — one tab, by its own handle — and opens a new one
372
+ with the conversation the book holds, so the session comes back as itself. With
373
+ no `--session` it does that for every session of the bot.
374
+
375
+ What it will not do, in order of how much it would cost you. It closes only a
376
+ tab your book names, so Bot Father's ops tab and anything you opened yourself
377
+ are left alone. It will not close a tab whose conversation the book cannot name:
378
+ that close would be the end of that conversation, so it refuses, tells you which
379
+ session and which file to settle it in, and touches nothing. It will not close
380
+ anything at all until everything that would stop the session starting again has
381
+ been settled — the same refusals `obk up` gives, made before the tab goes rather
382
+ than after. If Orca refuses to close a tab it stops there, rather than start a
383
+ second harness beside the first. And it waits for Orca's own listing to agree
384
+ that the tab has gone before opening the new one, because Orca answers a close
385
+ before it stops reporting the tab.
386
+
387
+ ## Changing, pausing and retiring
388
+
389
+ Bot Father does these for you when you ask; these are the commands it runs.
390
+
391
+ ```sh
392
+ obk bot change --bots /path/to/my-bots --bot api-bot --charter "…"
393
+ obk session change --bots /path/to/my-bots --bot api-bot --session daily --model opus
394
+ obk skills remove --bots /path/to/my-bots --bot api-bot --skill kit:obk-tdd
395
+ obk pause --bots /path/to/my-bots --bot api-bot [--session daily]
396
+ obk unpause --bots /path/to/my-bots --bot api-bot [--session daily]
397
+ obk retire --bots /path/to/my-bots --bot api-bot [--session daily]
398
+ ```
399
+
400
+ A change to a charter or a setting is written at once, and a running session
401
+ takes it when it next starts. A session keeps its harness: to move one, retire
402
+ it and add another. A pause closes the tabs the way a restart does, with the
403
+ same refusals, and `obk up` leaves what is paused closed until `obk unpause`
404
+ brings it back with its conversations. Retiring a session takes it off the bot
405
+ and keeps its conversations in the book under `retired`. Retiring a bot closes
406
+ its tabs, removes its Orca project and moves its folder to `retired/`; it will
407
+ not touch a bot whose Orca project holds a tab your book does not name. Bot
408
+ Father itself, and its management session `daily`, are never paused or
409
+ retired; its other sessions are like any bot's.
410
+
411
+ ## When something is wrong
412
+
413
+ ```sh
414
+ obk health --bots /path/to/my-bots [--bot api-bot]
415
+ ```
416
+
417
+ It reads your setup and says what it found, in plain sentences with `--json`
418
+ beside them for Bot Father to read. It writes nothing at all — not a file, not a
419
+ link, not a tab — so everything it finds is yours to decide about.
420
+
421
+ What it looks for:
422
+
423
+ - **configuration that will not work**: a `bot.yaml` nothing can read, a session
424
+ the kit would refuse to start, a bot with no `AGENTS.md`, a block somebody
425
+ edited by hand, a file bigger than the 32 KiB Codex reads, a `CLAUDE.md` that
426
+ is not this bot's rules, and a hooks file without the kit's own hook in it,
427
+ which is how a book goes stale without anything saying so;
428
+ - **a skill that is not where its list says**: a listed skill missing from one
429
+ of the two harnesses, a skill of your own standing where a listed one would
430
+ go, and a link with nothing at the end of it;
431
+ - **a session the book knows that Orca does not**: its tab was closed, or the
432
+ machine was restarted, and `obk up` brings it back;
433
+ - **leftovers no book owns**: an Orca project inside your bots folder with no
434
+ bot in it, a tab in a bot's project that the book does not name, a start
435
+ prompt written for a session that has gone, a clone of a skills source you no
436
+ longer list, and the conversations the kit found and would not assign;
437
+ - **Orca's own default launch arguments**. Orca adds these to the agents it
438
+ launches, relaunches and resumes, so when they carry a permission bypass every
439
+ session runs in that mode whatever the kit asked for. The kit never sets that
440
+ setting and says so every time it is on — including when Orca has no entry for
441
+ a harness at all, because Orca's own default for a missing entry is the bypass.
442
+
443
+ It exits 1 when it found something, so a script can tell. Nothing it prints is a
444
+ verdict: which of these matter, and in what order, is for you or for Bot Father.
445
+
446
+ ## Sessions and bots that talk
447
+
448
+ Ask the kit how to reach a session, and it answers with the road and the
449
+ address ([ADR 0018](docs/adr/0018-messaging-transport.md)):
450
+
451
+ ```sh
452
+ obk message to --bots /path/to/my-bots --to api-bot/daily
453
+ obk message send --bots /path/to/my-bots --to api-bot/daily \
454
+ --subject 'the schema changed' --text 'orders.total is cents now'
455
+ obk message check --bots /path/to/my-bots --bot api-bot --session daily
456
+ ```
457
+
458
+ Two roads, and a bot never picks. Claude Code to Claude Code in the same
459
+ approval class (`auto` and `ask` are one class, `dangerously-skip` the other)
460
+ is the harness's own messaging: `message to` answers with the
461
+ session's name — `<bot>.<session>`, which `obk up` puts on its launch line —
462
+ and the sending session writes to that name itself, because no command can send
463
+ that message for it. Everything else goes through Orca's mailbox, which the kit
464
+ does carry.
465
+
466
+ A session's mailbox is made the first time `obk up` brings it up, and written in
467
+ the book beside its tab. It is an Orca Run rather than the session's tab,
468
+ because a tab's address dies with the tab and a Run does not — so a message sent
469
+ while a session is down is still there when it comes back.
470
+
471
+ Nothing in a mailbox wakes anybody, so `message send` also types one line into
472
+ the receiver's tab telling it to look. Both harnesses take a typed line as the
473
+ next thing to do rather than cutting into what they are doing, which is the
474
+ whole of "queued, not interrupting". A session that is not up is not typed
475
+ into at all; its message waits.
476
+
477
+ A message longer than 4 KiB is written to a file beside your bots folder and
478
+ named in the message, so a long one arrives whole without landing a document in
479
+ somebody's context.
480
+
481
+ One thing to know about Codex bots: the kit launches them with
482
+ `-c sandbox_workspace_write.network_access=true`. Without it, the Orca CLI run
483
+ from inside a Codex session answers that Orca is not there — `reachable: false`,
484
+ and every mailbox call refused — so a Codex bot can neither read its mail nor
485
+ send any. Why is not established; what is, is that those calls fail without the
486
+ switch and work with it. It widens that session's sandbox to the network generally — there
487
+ is no localhost-only setting — and that is the price of a Codex bot being in the
488
+ fleet at all. Turn it off for a session with your own
489
+ `--extra-arg=-c --extra-arg=sandbox_workspace_write.network_access=false`, and
490
+ the kit will report that session as out of reach of fleet mail rather than
491
+ failing quietly.
492
+
493
+ ## Working on the kit
494
+
495
+ ```sh
496
+ npm test # the whole suite, in a few minutes
497
+ npm run test:system # what the system tests would drive, and nothing else
498
+ npm run test:system -- --yes # drive them, on this machine, for real
499
+ npm run mutate # the mutation audit, on what your branch changed
500
+ ```
501
+
502
+ The tests come in two layers, and every test file belongs to one of them.
503
+
504
+ `npm test` is `test/*.test.js`: unit tests and end-to-end runs of the CLI in a
505
+ throwaway folder, with a fake `orca` on PATH. It needs nothing but Node, so
506
+ [GitHub Actions](.github/workflows/ci.yml) runs it on every pull request and on
507
+ every push to `main`: on Node 25.8.0, the current line, and again on 24.21.0,
508
+ the floor `engines.node` promises users, with only the kit's own dependencies
509
+ installed.
510
+
511
+ `npm run test:system` is `test/system/*.test.js`: the real `obk` against the
512
+ real Orca and the real harnesses on your own machine. No CI runner can do that,
513
+ so these are run by hand before a change that touches Orca or a harness is
514
+ merged. A system test touches only what it creates and removes it afterwards,
515
+ except the mailbox Runs Orca gives no way to delete, which the run names; it
516
+ never closes a tab it did not open.
517
+
518
+ They run on the machine the command is typed on, so the command will not start
519
+ them by itself. On its own it says what it is about to drive — whose machine,
520
+ which Orca, which files, and what they will do to it — and then stops without
521
+ driving any of it, answering non-zero so that a run which did not run them
522
+ cannot be read as one that passed. `-- --yes` is how you say you meant it. When
523
+ Orca is not answering, the command says which Orca it asked and skips, rather
524
+ than report a kit that is not broken.
525
+
526
+ `npm run mutate` runs [StrykerJS](https://stryker-mutator.io) over the
527
+ JavaScript this branch changed against `main` — committed, still in the working
528
+ tree, or not tracked yet — and reports the mutants the tests do not kill. It is
529
+ an audit, not a step of every pull request
530
+ ([PRD 7.3](docs/prd.md#73-decided-rules-inside-the-skills)): the everyday
531
+ check is the implementer's own hand check, and the tool runs over the whole
532
+ suite at a milestone or when the owner asks, or once, narrowed to the changed
533
+ logic, for a change at the core of the kit. A surviving mutant is a change to
534
+ the code that no test objects to. It is worth a test only where it shows a gap
535
+ in behaviour the requirement cares about, and that test is written by the
536
+ separate test author. Name targets yourself to check a whole area instead:
537
+
538
+ ```sh
539
+ npm run mutate -- 'src/**/*.js'
540
+ ```
541
+
542
+ Every mutant means running the tests again, so the check does not run them the
543
+ way `npm test` does. It runs [`scripts/mutation-suite.js`](scripts/mutation-suite.js)
544
+ instead: the same test files, one at a time, stopping at the first file that
545
+ fails, trying the file that killed the last mutant first and then the quickest.
546
+ On a ten-core machine, `src/up.js` as it was when this was measured (128 lines,
547
+ 76 mutants) took about twelve minutes that way. Running the whole suite for every mutant, as it used to, took
548
+ forty, and counted a mutant as killed whenever a run of it ran out of time. A
549
+ change across several files takes proportionally longer, so check one or two at
550
+ a time.
551
+
552
+ The check still takes minutes where the suite takes seconds, which is why it is
553
+ a command of its own. StrykerJS is a development dependency of this repo, pinned
554
+ to an exact version and needing Node 22 or newer; the kit itself neither ships
555
+ it nor needs it.