lobstah 0.2.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.
- package/README.md +16 -5
- package/dist/main.js +866 -226
- package/dist/runner.js +5 -0
- package/docs/assets/lob-star.png +0 -0
- package/docs/assets/social-preview.png +0 -0
- package/docs/configuration.md +7 -0
- package/docs/lobsterman.md +38 -8
- package/docs/vocabulary.md +36 -0
- package/package.json +1 -1
package/dist/runner.js
CHANGED
|
@@ -767,6 +767,10 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
|
767
767
|
}
|
|
768
768
|
|
|
769
769
|
// packages/core/dist/config.js
|
|
770
|
+
var DEFAULT_SOAK = {
|
|
771
|
+
deferSecs: 90,
|
|
772
|
+
ttlSecs: 1800
|
|
773
|
+
};
|
|
770
774
|
var DEFAULT_LIMITS = {
|
|
771
775
|
maxConcurrent: 2,
|
|
772
776
|
choreConcurrent: 1,
|
|
@@ -801,6 +805,7 @@ function loadConfig() {
|
|
|
801
805
|
repos,
|
|
802
806
|
harness: raw.harness ?? {},
|
|
803
807
|
limits: { ...DEFAULT_LIMITS, ...raw.limits ?? {} },
|
|
808
|
+
soak: { ...DEFAULT_SOAK, ...raw.soak ?? {} },
|
|
804
809
|
notifyCommand: raw.notifyCommand ? String(raw.notifyCommand) : void 0,
|
|
805
810
|
notifyVerbs: Array.isArray(raw.notifyVerbs) ? raw.notifyVerbs.map(String) : void 0,
|
|
806
811
|
remindSecs: raw.remindSecs !== void 0 ? Number(raw.remindSecs) : void 0
|
|
Binary file
|
|
Binary file
|
package/docs/configuration.md
CHANGED
|
@@ -53,6 +53,13 @@ Same three keys as the per-repo block. Precedence for every harness setting:
|
|
|
53
53
|
| `wallClockSecs` | `3600` | Hard per-dispatch ceiling, enforced by the runner. |
|
|
54
54
|
| `choreRetentionDays` | `7` | Completed chores age out of `chores/done/`. |
|
|
55
55
|
|
|
56
|
+
## `[soak]` — soaking sessions (`lobstah soak`)
|
|
57
|
+
|
|
58
|
+
| Key | Default | Meaning |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `deferSecs` | `90` | A soaking session whose park heartbeat is this fresh holds unaddressed matching bait — the daemon waits instead of spawning. Addressed bait (`--for session:<id>`) waits regardless, until the registration is gone. |
|
|
61
|
+
| `ttlSecs` | `1800` | Heartbeat age past which a registration is a ghost trap: the sweep removes it and requeues its open catch (or finalizes a cancelled one as failed). A fresh `lobstah report` on the catch counts as liveness too. |
|
|
62
|
+
|
|
56
63
|
## `[pickup]` — tracker loops (`lobstah pick`)
|
|
57
64
|
|
|
58
65
|
| Key | Default | Meaning |
|
package/docs/lobsterman.md
CHANGED
|
@@ -141,9 +141,10 @@ trapline; every orchestrator-facing command lives under `lobstah man`).
|
|
|
141
141
|
Install it from the project you'll run the lobsterman in:
|
|
142
142
|
|
|
143
143
|
```bash
|
|
144
|
-
# Easiest: the
|
|
145
|
-
#
|
|
146
|
-
# /plugin install lobstah@lobstah
|
|
144
|
+
# Easiest: the plugin ships the hooks + the lobsterman skill, no settings
|
|
145
|
+
# edits — /plugin marketplace add aequitas-labs/lobstah, then
|
|
146
|
+
# /plugin install lobstah@lobstah (Claude Code and Codex v0.114+; Codex asks
|
|
147
|
+
# for a one-time hook trust review). Or wire the Claude hook by hand:
|
|
147
148
|
lobstah man init # merges the Stop hook into .claude/settings.local.json
|
|
148
149
|
lobstah man init --shared # …or the committed .claude/settings.json
|
|
149
150
|
lobstah man init --global # …or once into ~/.claude/settings.json — any
|
|
@@ -173,11 +174,11 @@ the haul context as the work order for that turn.
|
|
|
173
174
|
The trade-offs, honestly. While parked, the turn never ends, so the terminal
|
|
174
175
|
shows a running hook. Each wake appends a turn to the context, and long
|
|
175
176
|
shifts eventually compact. Without the gate, the hook parks every session in
|
|
176
|
-
the project. And parking
|
|
177
|
-
can block and inject a continuation. Claude Code's Stop hook can
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
for a dedicated, long-lived liaison session.
|
|
177
|
+
the project. And parking needs a turn-end hook that
|
|
178
|
+
can block and inject a continuation. Claude Code's Stop hook can, and so can
|
|
179
|
+
Codex's since its hooks system landed (v0.114+; older Codex only has the
|
|
180
|
+
fire-and-forget notify hook, which cannot). Tier 2 is the right default.
|
|
181
|
+
Tier 3 is for a dedicated, long-lived liaison session.
|
|
181
182
|
|
|
182
183
|
**Delivery guarantee.** Attention wakes are at-least-once with backoff. An
|
|
183
184
|
unanswered question is reported immediately. While it still stands, it
|
|
@@ -201,6 +202,35 @@ Zero tokens between events and works anywhere a shell does; the cost is that
|
|
|
201
202
|
each event gets a fresh context rather than a continuing liaison
|
|
202
203
|
conversation.
|
|
203
204
|
|
|
205
|
+
## Soaking: a live session volunteers as a worker
|
|
206
|
+
|
|
207
|
+
Workers are usually traps lobstah sets itself — fresh headless sessions in
|
|
208
|
+
fresh worktrees. A **soaking** session is the inverse: an interactive thread
|
|
209
|
+
already in the water volunteers to take bait, keeping its warm context, its
|
|
210
|
+
visible terminal, and whatever authenticated tooling a headless spawn can't
|
|
211
|
+
get.
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
lobstah soak --session <id> # from a worktree — the primary checkout is
|
|
215
|
+
# never claimable, so sign on from a linked
|
|
216
|
+
# worktree (git worktree add ../side -b side)
|
|
217
|
+
lobstah stow --session <id> # sign off; an open catch requeues
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The session id comes from the plugin's session-start brief (`lobstah man
|
|
221
|
+
brief` announces it into the conversation). Once soaking, the same Stop hook
|
|
222
|
+
that parks a lobsterman parks the worker: at turn end it waits for bait,
|
|
223
|
+
claims it, and wakes with the brief. While it works a catch, the park wakes
|
|
224
|
+
it for `lobstah send` messages and cancels instead.
|
|
225
|
+
|
|
226
|
+
Routing follows ownership: `dispatch --for session:<id>` targets one trap;
|
|
227
|
+
unaddressed bait for a matching repo prefers a parked trap for
|
|
228
|
+
`[soak].deferSecs` before the daemon spawns headless; a watch continuation
|
|
229
|
+
for a chain a soaking session claimed is addressed back to that session. A
|
|
230
|
+
registration whose heartbeat lapses past `[soak].ttlSecs` is a **ghost
|
|
231
|
+
trap** — swept, its catch requeued. Nobody is conscripted: only a session
|
|
232
|
+
that ran `soak` ever receives work.
|
|
233
|
+
|
|
204
234
|
## What the daemon gives your liaison for free
|
|
205
235
|
|
|
206
236
|
- Parallel work that can't collide — worktree per dispatch.
|
package/docs/vocabulary.md
CHANGED
|
@@ -137,3 +137,39 @@ Delivery is level-triggered and at-least-once, like dispatch attention:
|
|
|
137
137
|
events stand until the owner consumes them. One continuation dispatch in
|
|
138
138
|
flight per watch; later events buffer and fork from the latest session in
|
|
139
139
|
the chain.
|
|
140
|
+
|
|
141
|
+
## Soaking contract
|
|
142
|
+
|
|
143
|
+
A **soaking trap** is a live interactive session that volunteered as a worker
|
|
144
|
+
through `lobstah soak` — the validated write path; nothing else touches
|
|
145
|
+
`soaking/`. Sub-agent workers are the traps lobstah sets itself; a soaking
|
|
146
|
+
session is a trap already in the water, and dispatch drops bait into it
|
|
147
|
+
before building a new one. **Owner:** `packages/core/src/soak.ts`.
|
|
148
|
+
**Enforcement:** sign-on is refused from a repo's primary checkout (never
|
|
149
|
+
claimable) and when another session already soaks the same worktree.
|
|
150
|
+
|
|
151
|
+
| Word | Meaning |
|
|
152
|
+
| ---- | ------- |
|
|
153
|
+
| `soak` | Sign a session on: it parks at turn end (Stop hook) and takes matching bait from the work queue. `--one` stows after the first catch. |
|
|
154
|
+
| `stow` | Sign a session off; an open catch goes back to the queue (a cancelled one finalizes as failed). |
|
|
155
|
+
| bait address | `--for session:<id>` on a dispatch targets one soaking session. Addressed bait waits for its trap until the registration is gone; unaddressed bait defers to a parked matching trap for `[soak].deferSecs`, then the daemon spawns headless. |
|
|
156
|
+
| catch | The active dispatch a soaking session claimed (`claim.json` in the active dir). One catch per trap; one active item per worktree. The daemon never spawns or restarts it — the session's reports are its liveness. |
|
|
157
|
+
| ghost trap | A registration whose heartbeat lapsed past `[soak].ttlSecs` — a lost trap that keeps fishing. The sweep hauls it out and requeues its catch. A fresh report on the catch keeps a mid-turn session out of the sweep. |
|
|
158
|
+
|
|
159
|
+
Delivery routes by ownership, same as watches: a continuation for a chain
|
|
160
|
+
claimed by a live soaking session is addressed back to that session; once it
|
|
161
|
+
ghosts, the same bait forks headless. Sessions are never conscripted — a
|
|
162
|
+
thread works bait only after opting in.
|
|
163
|
+
|
|
164
|
+
## Exit codes
|
|
165
|
+
|
|
166
|
+
The CLI's exit-code contract, aligned with axi.md P6. **Owner:**
|
|
167
|
+
`apps/cli/src/main.ts` (`UsageError`) and `apps/cli/src/usage.ts` (the
|
|
168
|
+
registry that decides what parses).
|
|
169
|
+
|
|
170
|
+
| Code | Meaning |
|
|
171
|
+
| ---- | ------- |
|
|
172
|
+
| `0` | Success — including definitive empty results. |
|
|
173
|
+
| `1` | Error: the command was well-formed but could not do its job. |
|
|
174
|
+
| `2` | Usage mistake: unknown command, flag, or subverb. The error names the offender and prints the command's usage card. Flags in a free-text tail (a `send` message, a `report` note) are never validated — prose may contain anything. |
|
|
175
|
+
| `3` | `man wait --timeout` elapsed with nothing to report. Its own code so `while lobstah man wait` loops still terminate on timeout while `2` stays unambiguous. |
|