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