lobstah 0.6.9 → 0.7.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.
@@ -16,6 +16,7 @@ keys of that section.
16
16
  | `notifyVerbs` | `["needs-decision", "blocked", "done", "failed"]` | Which verbs fire `notifyCommand`. |
17
17
  | `attentionKinds` | `["question", "decision", "pr:ready", "pr:review", "pr:conflict", "pr:checks"]` | Which kinds `man tend`, the glass, and the desktop pet show. `decision` is a question the helm put to the human with `lobstah man ask`; the glass shows it as a card to answer, and it hides the raw `question` it frames. Without `decision`, framed decisions do not show and raw questions do. `pr:draft`, `landed`, and `report` are valid opt-in kinds. An explicit list is used unchanged. Unknown kinds are errors. See the [attention contract](vocabulary.md#attention-contract). |
18
18
  | `remindSecs` | `900` | An unanswered `needs-decision`/`blocked` re-fires to `man wait`/`man haul` on this interval until answered. `0` = report once only. |
19
+ | `readySettleSecs` | `600` | `pr:ready` stands after continuously meeting the ready conditions on the same head for this many seconds. Any not-ready observation or new head resets the timer. Each attention read re-evaluates expiry from the persisted start, even without a new forge event. `0` restores immediate ready attention; other `pr:*` kinds are unchanged. |
19
20
 
20
21
  ## `[repos.<key>]` — workspace definitions
21
22
 
@@ -109,6 +110,7 @@ send a continuation.
109
110
  | `ttlSecs` | `1800` | Heartbeat age past which a registration is a ghost trap: the sweep removes it and requeues an unfinished catch, finalizes done/failed in `done/`, or finalizes a cancelled catch as failed. A fresh `lobstah report` or beat counts as liveness. If the daemon's own tick gap exceeds this TTL, it grants a full TTL after resume before sweeping any traps. |
110
111
  | `beat` | `true` | The post-tool hook (`lobstah soak beat`) refreshes a soaking session's liveness and writes its catch's activity, at most once per 30 seconds per trap. With `false` the hook does nothing, and a trap's liveness comes from its reports and its park only. |
111
112
  | `signOffGraceSecs` | `600` | After a trap signs off, its address is held this long: messages to it wait for a re-soak of the same worktree instead of bouncing, `send` to it queues with a warning, and work addressed to it raises no `bait-orphaned` notice. After the grace the daemon bounces the held messages. `0` bounces at sign-off. |
113
+ | `terminal` | unset | The terminal app a thrown trap opens in: `terminal` (Terminal.app) or `iterm` (iTerm2). A trap's roster profile (`man roster set <trap> --terminal`) overrides it. Unset, `man throw` uses the app the trap last signed on from, else Terminal.app. `man throw` opens the trap's session there through AppleScript (macOS only); the app needs Automation permission for the terminal that runs `man throw`. |
112
114
  | `pausedTtlSecs` | `86400` (24 hours) | A trap whose catch last reported `paused` is kept out of the ghost sweep this long after the report. `report paused --until <iso|duration>` sets the expiry instead. After it, the sweep removes the trap as usual, and the notice says the pause expired. |
113
115
 
114
116
  ## `[helm]` — the orchestrator seat (`lobstah man helm`)
@@ -221,5 +223,5 @@ See [pickup.md](pickup.md) for the loop semantics these keys drive.
221
223
  |---|---|
222
224
  | `LOBSTAH_HOME` | The instance root (default `~/.lobstah`). Multiple instances = multiple homes; one daemon per home, enforced. |
223
225
  | `LOBSTAH_MAN` | `=1` designates a session as the lobstah man for the `man haul` Stop hook. |
224
- | `LOBSTAH_TRAP_TICKET` | A `trap reserve` ticket. `lobstah soak` redeems it and signs the session on as the reserved trap. `--ticket` takes precedence. |
226
+ | `LOBSTAH_TRAP_TICKET` | A ticket `man throw` reserved. `lobstah soak` redeems it and signs the session on as the reserved trap. `--ticket` takes precedence. |
225
227
  | `LOBSTAH_TERMINAL_TITLE` | `=0` stops soak from naming the terminal tab after the trap, and stow from clearing it. |
package/docs/man.md CHANGED
@@ -473,7 +473,9 @@ dispatch with its full brief, status log, inbox, and evidence, each trap
473
473
  with its lifecycle notices, message history, and catches, the notices
474
474
  tail, the merge view, and watches — with filters, a table/cards toggle,
475
475
  and the helm identified by name. Its tabs are On deck, Dispatches, Traps,
476
- PRs, Reports, and Notices. The Reports tab lists every report, unacked first,
476
+ PRs, Reports, Notices, and Stats. The Stats tab shows catches per day as a
477
+ 53-week heatmap, with today, this week, the total, and the top traps; it
478
+ reads `stats.json` from `GET /data/stats` and sends nothing. The Reports tab lists every report, unacked first,
477
479
  then newest first, and the repo filter and the search box (title, author,
478
480
  dispatch id, repo) apply to it. Reading the glass consumes no cursor. Each
479
481
  live trap has a **↗ open** button at the end of its foot line. It asks the local server to focus
@@ -919,8 +921,8 @@ lobstah focus <trap> # focus a live trap from the CLI
919
921
  lobstah stow # sign off; an open catch requeues, unread
920
922
  # messages wait [soak].signOffGraceSecs for a
921
923
  # re-soak, then bounce back to the helm;
922
- # removes the worktree when soak created it
923
- lobstah stow --keep # sign off and keep the worktree
924
+ # keeps the worktree
925
+ lobstah stow --remove # sign off and remove the worktree soak created
924
926
  lobstah soak --name amber-gull # choose or change this trap's two-word name
925
927
  ```
926
928
 
@@ -967,15 +969,20 @@ trap by session id (`--session <id>`, or `$CLAUDE_CODE_SESSION_ID`), and
967
969
  `send session:<id>` addresses it. With `--session`, or from inside the worktree, `report done` records the
968
970
  worktree's HEAD commit and branch in evidence.
969
971
 
970
- `stow` removes a worktree only when soak created it and nothing in it exists
971
- elsewhere. It keeps the worktree and prints `worktree: kept` and a `reason:`
972
- when soak did not create the worktree, or when the worktree has uncommitted
973
- changes, untracked files that are not ignored, commits its upstream lacks,
974
- or no upstream. Ignored files do not block removal. `stow --force` explicitly
975
- allows removal of unsaved checkout files; `--keep` still keeps the checkout.
972
+ `stow` keeps the worktree by default: it prints `worktree: kept` and
973
+ `reason: stow keeps the worktree; --remove removes it`, and a later
974
+ `man throw` brings the trap back in it. `stow --remove` removes a worktree
975
+ only when soak created it and nothing in it exists elsewhere. It keeps the
976
+ worktree and prints `worktree: kept` and a `reason:` when soak did not create
977
+ the worktree, or when the worktree has uncommitted changes, untracked files
978
+ that are not ignored, commits its upstream lacks, or no upstream. Ignored
979
+ files do not block removal. `stow --remove --force` explicitly allows removal
980
+ of unsaved checkout files; `--force` alone refuses. `--keep` is accepted and
981
+ changes nothing.
976
982
  Stow runs the removal from the primary checkout, so it works from inside
977
983
  the worktree. On removal it prints `worktree: removed`, `path:`, and
978
- `returnTo: <primary checkout>`, with a help line `cd <primary>`. It
984
+ `returnTo: <primary checkout>`, with a help line `cd <primary>`. Before
985
+ removal, the checkout's HEAD goes to the trap's protected ref. It
979
986
  deletes the branch only when every commit on it is on its upstream (with no
980
987
  upstream: on some remote branch);
981
988
  otherwise it prints `branchKept: <branch> (<reason>)`. A deleted branch
@@ -1080,43 +1087,46 @@ enlistment** — noticed with its diagnosis (usually a missing Stop hook →
1080
1087
  Nobody is conscripted: only a worktree whose session ran `soak` ever
1081
1088
  receives work.
1082
1089
 
1083
- ### Reserving a trap before its session starts
1090
+ ### Starting a new trap
1084
1091
 
1085
1092
  ```bash
1086
- lobstah trap reserve --repo <key> # reserve a trap; prints its name, id, and a one-time ticket
1087
- [--harness claude|codex] # print only that harness's start command
1088
- [--name amber-gull] # choose the name
1089
- [--deadline 180] # seconds the session has to sign on (default 180)
1090
- lobstah soak --ticket <ticket> # in the new session: sign on as the reserved trap
1093
+ lobstah man throw --new --repo <key> [--count N] [--harness claude|codex]
1094
+ # start N fresh traps; wait until each listens
1095
+ lobstah man throw --new --repo <key> --count 3 --dry-run
1096
+ # what would start; launches nothing
1097
+ lobstah soak --ticket <ticket> # what the new session runs: sign on as the reserved trap
1091
1098
  lobstah stow --wt amber-gull # withdraw a reservation no session has redeemed
1092
1099
  ```
1093
1100
 
1094
- `trap reserve` picks the two-word name and the `wt:` id before any session
1095
- exists and writes a **starting** reservation (`soaking/<id>.starting`) with a
1096
- deadline. `dispatch --for <name>` works on it at once: the work waits, as it
1097
- does for any addressed trap. `man tend` and the glass show the trap as
1098
- `starting`.
1101
+ `man throw --new` (the helm's) picks a two-word name and a `wt:` id for each
1102
+ fresh trap before any session exists and writes a **starting** reservation
1103
+ (`soaking/<id>.starting`) with a deadline (`--timeout`, default 180 seconds).
1104
+ `dispatch --for <name>` works on it at once: the work waits, as it does for
1105
+ any addressed trap. `man tend` and the glass show the trap as `starting`.
1099
1106
 
1100
- The output holds a one-time ticket and the command that starts the session in
1101
- the repo's primary checkout:
1107
+ The harness comes from `--harness`, else `[repos.<key>.harness].default`,
1108
+ else `[harness].default`; the model and effort from the same tables. The
1109
+ terminal is `[soak].terminal`, else Terminal.app. Throw opens the start
1110
+ command in a new tab in the repo's primary checkout:
1102
1111
 
1103
1112
  ```bash
1104
- cd <repo> && CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1 claude "/lobstah:trap soak --ticket <ticket>"
1113
+ cd <repo> && CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1 claude '/lobstah:trap soak --ticket <ticket>'
1105
1114
  cd <repo> && codex '$lobstah:trap soak --ticket <ticket>'
1106
1115
  ```
1107
1116
 
1108
- Nothing starts the session for you: a person runs the command. The session's
1109
- soak redeems the ticket, from `--ticket` or from the `LOBSTAH_TRAP_TICKET`
1110
- environment variable. It creates a worktree named after the reserved id,
1111
- signs on under the reserved name and id, and deletes the reservation. The
1112
- ticket then redeems nothing. A spent ticket left in `LOBSTAH_TRAP_TICKET` is
1113
- ignored; a spent `--ticket` is refused, except in the session that redeemed
1114
- it. A session that already mans a trap cannot redeem a ticket.
1115
-
1116
- A reservation still unredeemed at its deadline **fails**: the daemon posts one
1117
- `trap-start-failed` notice, and the glass shows the trap as `start failed`
1118
- with the reason. Work addressed to it stays queued. The ticket still redeems
1119
- after the deadline. `lobstah stow --wt <name>` withdraws the reservation; its
1117
+ The session's soak redeems the ticket, from `--ticket` or from the
1118
+ `LOBSTAH_TRAP_TICKET` environment variable. It creates a worktree named after
1119
+ the reserved id, signs on under the reserved name and id, and deletes the
1120
+ reservation. The ticket then redeems nothing. A spent ticket left in
1121
+ `LOBSTAH_TRAP_TICKET` is ignored; a spent `--ticket` is refused, except in
1122
+ the session that redeemed it. A session that already mans a trap cannot
1123
+ redeem a ticket.
1124
+
1125
+ A throw that sees no sign-on by its deadline withdraws the reservation and
1126
+ posts `trap-start-failed`. A reservation found unredeemed at its deadline by
1127
+ the daemon (one throw did not wait for) **fails** the same way: the glass
1128
+ shows the trap as `start failed` with the reason, and work addressed to it
1129
+ stays queued. `lobstah stow --wt <name>` withdraws a reservation; its
1120
1130
  addressed work is then orphaned bait and the helm gets a `bait-orphaned`
1121
1131
  notice.
1122
1132
 
@@ -1140,20 +1150,125 @@ greyed card: `requested · <repo> · <harness> · waiting for the helm`, or
1140
1150
  `waiting for a helm` when no helm is signed on.
1141
1151
 
1142
1152
  ```bash
1143
- lobstah trap requests # open trap requests
1144
- lobstah trap reserve --request <id> # reserve what the request asks for, and close it
1153
+ lobstah man throw --new --request <id> # start what the request asks for, and close it
1145
1154
  ```
1146
1155
 
1147
- `trap reserve --request <id>` takes the repo and harness from the request,
1148
- records the request on the reservation, and closes the request. The card
1149
- becomes the starting card, then the live trap when the session signs on.
1156
+ `man throw --new --request <id>` takes the repo and harness from the request
1157
+ (flags may repeat them, never contradict them), records the request on the
1158
+ reservation, and closes the request with the result. The card becomes the
1159
+ starting card, then the live trap when the session signs on.
1160
+
1161
+ Every starting card shows a start command with a copy button: paste it into a
1162
+ terminal to start the session by hand if the throw's terminal could not open.
1163
+ The ticket in it is kept in `soaking/<id>.ticket` (mode 0600) until the
1164
+ reservation is redeemed or withdrawn. The glass sends it only to a page on
1165
+ this machine's own glass address, only on the starting card, and no notice or
1166
+ log carries it.
1167
+
1168
+ ### The roster, and what a throw would do
1169
+
1170
+ Every trap that signs on gets a **roster** record
1171
+ (`~/.lobstah/roster/<trapId>.json`). A registration lasts while a session
1172
+ mans the trap, and the signed-off hold lasts for the mail grace. The roster
1173
+ record stays through stow, the end of the grace, a ghost sweep, and `cull`.
1174
+ It keeps the trap's name, repo, worktree, branch and HEAD, harness, session,
1175
+ the registration's model and config, and why the trap left. Its name is the
1176
+ trap's name: a trap that signs on again in its worktree keeps it, from any
1177
+ session.
1178
+
1179
+ Before stow, a ghost sweep, or `cull` removes a trap's checkout, lobstah
1180
+ writes the checkout's HEAD to the **protected ref**
1181
+ `refs/lobstah/traps/<trapId>` in the repository. It is not a branch:
1182
+ removing the worktree or deleting its branch leaves the ref and its commit in
1183
+ place.
1150
1184
 
1151
- Every starting card shows the start command `trap reserve` prints, with a copy
1152
- button: paste it into a terminal to start the session by hand. The ticket in
1153
- it is kept in `soaking/<id>.ticket` (mode 0600) until the reservation is
1154
- redeemed or withdrawn. The glass sends it only to a page on this machine's
1155
- own glass address, only on the starting card, and no notice or log carries
1156
- it.
1185
+ ```bash
1186
+ lobstah man roster # every trap the roster keeps
1187
+ lobstah man roster set <trap> --harness codex --model <m> --terminal iterm --config effort=high
1188
+ # save how a throw starts it; `default` or `key=` clears
1189
+ lobstah man throw <trap> [--timeout <secs>] # bring one trap back; wait until it listens
1190
+ lobstah man throw --all # every eligible trap in your grounds, at once
1191
+ lobstah man throw --repo <key> # every eligible trap of one repo
1192
+ lobstah man throw --new --repo <key> --count N # N fresh traps (see "Starting a new trap")
1193
+ lobstah man throw --dry-run <trap>... | --all | --repo <key> | --new ...
1194
+ # what a throw would do; launches nothing (--plan too)
1195
+ lobstah man roster forget <trap> [--force] # remove a stowed trap's record, worktree, and ref
1196
+ ```
1197
+
1198
+ `man throw --dry-run` (or `--plan`) launches nothing and writes nothing. Each
1199
+ row says what a throw would do and why:
1200
+
1201
+ - `resume`: the harness reopens the saved session (`claude --resume`, `codex
1202
+ resume`) in the trap's checkout.
1203
+ - `cold`: a new session under the same name, id, and checkout. The reason is
1204
+ one of: no saved history for the session, a session that ran in an app (the
1205
+ Claude desktop app's Code tab, the VS Code extension, the Codex app), or a
1206
+ saved profile whose harness is not the one that wrote the session.
1207
+ - `skip`: the trap is live or starting (reserved).
1208
+ - `unresolved`: a throw would refuse. The repo is no longer configured or now
1209
+ points at another repository, the record is incomplete, the checkout is
1210
+ gone and no protected ref keeps its revision, or the path now anchors
1211
+ another trap. A trap stowed before the roster existed is listed here until
1212
+ a session soaks in its worktree once.
1213
+
1214
+ `checkout` is `kept` (the checkout is adopted as it is) or `recreate` (it is
1215
+ added back at the protected revision). The harness, model, config, and
1216
+ terminal come from the saved profile, else from the trap's last sign-on. The
1217
+ terminal is the profile's, else `[soak].terminal`, else the app the trap last
1218
+ signed on from, else Terminal.app. `--all` and `--repo` stay inside the
1219
+ grounds: `--grounds`, else the caller's helm grounds, else every repo.
1220
+
1221
+ `man throw <trap>` does what its plan row says, for one trap (the helm's
1222
+ verb). A `skip` refuses: a trap that is live, or already starting, is never
1223
+ launched twice. Otherwise:
1224
+
1225
+ 1. It reserves the trap under its **own** id and name, in its own worktree.
1226
+ The reservation is created exclusively, so a second throw refuses until
1227
+ the first returns or times out. `--for <name>` keeps working throughout.
1228
+ 2. A `recreate` checkout is added back at `refs/lobstah/traps/<id>` on the
1229
+ trap's recorded branch, with the repo's `setup`. An existing branch is
1230
+ used only when it still contains that revision; a throw never resets a
1231
+ branch. A kept checkout is used as it is, dirty or not.
1232
+ 3. It opens the start command in the terminal (Terminal.app or iTerm2,
1233
+ through AppleScript, macOS only). `resume` reopens the saved session from
1234
+ the directory its history is keyed by (Claude keys transcripts by the
1235
+ directory the session started in); `cold` starts a new session in the
1236
+ worktree. The profile's model and config become harness flags (`--model`,
1237
+ `--effort`, `--permission-mode` for Claude; `-m`, `model_reasoning_effort`
1238
+ for Codex); a setting with no flag is named as not applied. The first
1239
+ prompt redeems the ticket, so the session signs on as the same trap.
1240
+ 4. It returns when the trap has signed on and parked, and prints whether it
1241
+ resumed or started cold, and why. Past `--timeout` (default 180 seconds)
1242
+ it withdraws the reservation, so a late session cannot take the trap,
1243
+ posts `trap-start-failed`, and leaves the roster unchanged.
1244
+
1245
+ **Batches.** `man throw --all` throws every eligible trap in the grounds
1246
+ (`--grounds`, else the caller's helm grounds, else every repo); `--repo`
1247
+ narrows to one repo; `--new --count N` starts N fresh ones. Every launch runs
1248
+ at once, with no limit, and the batch waits for all of them. It prints one
1249
+ row per trap: `resumed`, `cold`, or `new` (with why), `skipped` (live,
1250
+ starting, or unresolved, with why), or `failed` (with why). One trap failing
1251
+ does not stop the others, and the command exits 1 when any failed.
1252
+
1253
+ **Notices.** A trap's start wakes the helm once: `trap-available`, when the
1254
+ trap is listening. Its reservation (`trap-starting`), sign-on
1255
+ (`trap-signed-on`), and sign-off (`trap-stowed`) are quiet: tend, the
1256
+ digest's `traps` table, and the glass show them. A ghost sweep of an idle
1257
+ trap is quiet the same way; a ghost sweep of a trap that held a catch wakes.
1258
+ A batch posts no `trap-available` per trap: when every throw has settled it
1259
+ posts one `trap-batch` notice with the counts and the names that failed. A
1260
+ trap that failed to start (`trap-start-failed`) and work addressed to a trap
1261
+ that is gone (`bait-orphaned`) still wake.
1262
+
1263
+ **Forget.** `man roster forget <trap>` (the helm's) takes a stowed trap off
1264
+ the roster for good. It refuses a live or starting trap. It also refuses, and
1265
+ names the work, when the trap holds anything that exists nowhere else:
1266
+ modified or untracked files in its checkout, or commits (in the protected
1267
+ ref, the checkout, or its branch) that are on no remote branch and not merged
1268
+ to trunk. `--force` forgets anyway. Otherwise it removes the worktree soak
1269
+ created (one it did not create stays, minus its anchor), deletes
1270
+ `refs/lobstah/traps/<id>`, bounces held messages, and frees the name. A
1271
+ branch that still holds commits on no remote is kept even with `--force`.
1157
1272
 
1158
1273
  ### The sign-on title
1159
1274
 
@@ -1188,7 +1303,7 @@ Other terminals are left alone. `lobstah stow` clears the name.
1188
1303
  Claude Code writes its own title to the tab, and in Terminal.app that title
1189
1304
  replaces the custom title. `CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1` on the
1190
1305
  command that starts Claude Code stops that for that one process; the start
1191
- command `trap reserve` prints sets it. Codex also sets the terminal title.
1306
+ command `man throw` opens sets it. Codex also sets the terminal title.
1192
1307
 
1193
1308
  ### Culling and disk space
1194
1309
 
@@ -396,7 +396,7 @@ evidence).
396
396
  | descriptor `pr` | `{ url, headRefName?, headSha? }`: the existing PR a dispatch works on. A PR repair and a pickup rebase chore carry it. The runner pushes no branch and opens no PR for such a dispatch; its worker pushes to the PR's head branch. |
397
397
  | push rule | What a repair or rebase brief tells its worker: push only to the PR's head branch; on a non-fast-forward rejection, fetch, rebase the commits onto the moved head again, and push with `--force-with-lease` on the head just fetched, at most three times; a hook failure from a real test or type error is not retried; when it cannot push, report `failed "push rejected: <rejection text>; moved head <sha>"` and leave the PR as it was. That report marks the PR's repair `blocked` at the moved head and posts a `push-failed` notice. |
398
398
  | checks unknown | Without `Checks: read`, the check re-reads the PR without `statusCheckRollup`: the PR state is recorded, `checks.unknown` is `no permission`, and the check's output carries the permission `error`. `pr:ready` never stands on unknown checks. |
399
- | PR record | `~/.lobstah/prs/<owner>__<repo>__<n>.json` — the PR's latest observation keyed by the PR, not by a dispatch: the evidence `pr` object (with `title`, read on every check; a title change is not a state change) plus `key`, `repo` (`<owner>/<repo>`), `dispatches` (the ids whose watch observed it; empty for a human's or a culled PR), and `firstSeenAt` (the time of the first observation; written once, never rewritten). `firstSeenAt`, then the PR number, is the order of every PR list. A record from before `firstSeenAt` existed sorts by number at the earliest `firstSeenAt` in the set, and its next observation writes that time as its `firstSeenAt`. **Owner:** `packages/core/src/prs.ts` (`upsertPr`, `readPrs`); the one writer is the preset's observation path (`observePr`), on every observation, man-owned or dispatch-owned — a dispatch-owned one also stamps that dispatch's evidence, which stays the per-dispatch view. Tend's `pr:*` kinds and `pr:ready` stack suppression, the glass PRs tab and stacks, the merged/closed notice, and PR acks read records first and fall back to dispatch evidence only for a PR with no record yet. `cull` removes records merged or closed longer than its window, never open ones. |
399
+ | PR record | `~/.lobstah/prs/<owner>__<repo>__<n>.json` — the PR's latest observation keyed by the PR, not by a dispatch: the evidence `pr` object (with `title`, read on every check; a title change is not a state change) plus `key`, `repo` (`<owner>/<repo>`), `dispatches` (the ids whose watch observed it; empty for a human's or a culled PR), and `firstSeenAt` (the time of the first observation; written once, never rewritten). `firstSeenAt`, then the PR number, is the order of every PR list. A record from before `firstSeenAt` existed sorts by number at the earliest `firstSeenAt` in the set, and its next observation writes that time as its `firstSeenAt`. **Owner:** `packages/core/src/prs.ts` (`upsertPr`, `readPrs`); the one writer is the preset's observation path (`observePr`), on every observation, man-owned or dispatch-owned — a dispatch-owned one also stamps that dispatch's evidence, which stays the per-dispatch view. Tend's `pr:*` kinds and `stack-ready` aggregation and quiet stacked `pr:ready` items, the glass PRs tab and stacks, the merged/closed notice, and PR acks read records first and fall back to dispatch evidence only for a PR with no record yet. `cull` removes records merged or closed longer than its window, never open ones. |
400
400
 
401
401
  Every event carries `headSha`. A dispatch-owned PR watch records work events,
402
402
  then the repair planner decides whether to follow up. One repair runs per PR
@@ -467,18 +467,21 @@ worktree is refused (the session lock); a stale one is adopted.
467
467
  | ---- | ------- |
468
468
  | `soak` | Sign the worktree's trap on and take matching work. From a primary checkout, or with `--repo <key>` from outside any configured repo, it first creates a linked worktree like a dispatch does (fetch trunk, new branch from `origin/<trunk>`, `setup` commands), prints `worktree:`, `created: true`, `branch:`, and, when the session is elsewhere, `instruction: cd <path> ...`; the session works in that directory. If creation fails, nothing is signed on and the partial worktree and branch are removed. `--repo` in a linked worktree must match its repo. A session that already mans a trap re-uses it (resolved from the session id) and never gets a second worktree. `--session` is needed only on first sign-on. `--one` stows after the first catch. `--wait` registers a watcher and waits for work; a quiet timeout exits 3. Workers never run `man` verbs. |
469
469
  | `soak title-set` (alias `trap title-set`) | Confirm this session applied the title sign-on printed (`step: Apply this title: <title>`). The registration records `titleSet` and `titleSetAt` and drops `titlePending`; sign-on is complete. Until then, SessionStart and Stop remind the session once per turn, at most three times. A trap runs `soak title-set`: Claude Code's worktree isolation refuses a command line containing `trap`. |
470
- | `stow` | Sign the trap off (in the worktree, or elsewhere by session id: `--session <id>` or `$CLAUDE_CODE_SESSION_ID`); an unfinished catch requeues, done/failed finalizes in `done/`, and a cancelled catch finalizes as failed. Unread messages are held for `[soak].signOffGraceSecs` (default 600): they deliver if the same worktree re-soaks in time, else the daemon bounces them to the helm (at once when stow removed the worktree or the grace is `0`). A trap always stows itself freely; stowing someone else's (`--wt`) is steering — the claimed helm's alone. Stow closes the seat, never the session: an opted-in session can only be asked to stop, and a still-looping worker re-enlists visibly (`trap-signed-on`). By default stow removes the worktree when soak created it (`createdWorktree: true`) and prints `worktree: removed`, `path:`, and `returnTo:`; `--keep` leaves it. It keeps the worktree (`worktree: kept`, `reason:`) when soak did not create it, or when it holds uncommitted changes, untracked files that are not ignored, commits absent from its upstream, or no upstream. `--force` explicitly allows discarding unsaved checkout files; `--keep` still keeps it. The branch is deleted (`branchDeleted:`) only when all its commits are on its upstream (with no upstream: on some remote branch); otherwise `branchKept: <branch> (<reason>)`. `--wt` follows the same rules. The SessionEnd hook (`stow --quiet`) signs off only when the ending session is the trap's registered session (another session in the worktree ending is a no-op) and keeps the worktree; SessionEnd cannot tell a restart or compaction from an exit (Claude Code's `reason` is `clear`, `resume`, `logout`, `prompt_input_exit`, or `other`; Codex's is always `other`), so the grace covers a session that signs on again. |
470
+ | `stow` | Sign the trap off (in the worktree, or elsewhere by session id: `--session <id>` or `$CLAUDE_CODE_SESSION_ID`); an unfinished catch requeues, done/failed finalizes in `done/`, and a cancelled catch finalizes as failed. Unread messages are held for `[soak].signOffGraceSecs` (default 600): they deliver if the same worktree re-soaks in time, else the daemon bounces them to the helm (at once when stow removed the worktree or the grace is `0`). A trap always stows itself freely; stowing someone else's (`--wt`) is steering — the claimed helm's alone. Stow closes the seat, never the session: an opted-in session can only be asked to stop, and a still-looping worker re-enlists visibly (`trap-signed-on`). By default stow keeps the worktree (`worktree: kept`, `reason: stow keeps the worktree; --remove removes it`), so `man throw` can bring the trap back in it; `--keep` is accepted and changes nothing. `--remove` removes the worktree when soak created it (`createdWorktree: true`) and prints `worktree: removed`, `path:`, and `returnTo:`; it still keeps it (`worktree: kept`, `reason:`) when soak did not create it, or when it holds uncommitted changes, untracked files that are not ignored, commits absent from its upstream, or no upstream. `--remove --force` explicitly allows discarding unsaved checkout files; `--force` alone refuses. The branch is deleted (`branchDeleted:`) only when all its commits are on its upstream (with no upstream: on some remote branch); otherwise `branchKept: <branch> (<reason>)`. `--wt` follows the same rules. The SessionEnd hook (`stow --quiet`) signs off only when the ending session is the trap's registered session (another session in the worktree ending is a no-op) and keeps the worktree; SessionEnd cannot tell a restart or compaction from an exit (Claude Code's `reason` is `clear`, `resume`, `logout`, `prompt_input_exit`, or `other`; Codex's is always `other`), so the grace covers a session that signs on again. |
471
471
  | sign-off grace | For `[soak].signOffGraceSecs` after a trap signs off (`~/.lobstah/signed-off/<trap>.json`), its address is held: `send wt:<trap>` queues and warns instead of refusing, held messages wait, and work addressed to it raises no `bait-orphaned` notice. A re-soak of the same worktree releases the hold; after the grace, the daemon bounces the held messages (`message-bounced`). |
472
472
  | address | `--for wt:<trap>` targets one trap; `session:<id>` is an alias resolved to the trap at dispatch time. **Sticky:** addressed work is never the daemon's — it waits for its trap; an orphan (trap gone) surfaces as a `bait-orphaned` notice for the helm to re-address, release, or cancel. Delivery stamps a receipt (`deliveredTo`/`deliveredAt`) into evidence. Unaddressed work defers to a parked matching trap for `[soak].deferSecs`, then the daemon spawns headless. |
473
473
  | message | `send wt:<trap> "<text>"` — a conversational continuation, not work: no branch, no catch, no report obligation. Delivered before bait at the trap's next park, stamped with its sender (`helm` / `session:<id>` / `terminal`); undeliverable messages bounce to the helm as notices. |
474
474
  | catch | The active dispatch a trap claimed (`claim.json`, `by: wt:<id>`). One catch per trap; one active item per worktree. The daemon never spawns or restarts it — the session's reports are its liveness. |
475
475
  | hook command | `lobstah hook session-start\|stop\|post-tool-use\|session-end`: the command each plugin hook runs. Each detects the session's role (helm, trap, or neither) and runs what `man brief`, `man haul`, `soak beat`, and `stow --quiet` run; those stay as aliases. Stop, PostToolUse, and SessionEnd are inert for a session with neither role; SessionStart announces the session id to every session. |
476
476
  | beat | `lobstah soak beat` (`lobstah hook post-tool-use`), run by the plugin's post-tool hook after every tool call. It resolves the trap from the working directory, else from the session id (files only: no git, no network), refreshes the trap's beat (`soaking/<trap>.beat`, separate from the registration), and writes the claimed catch's [activity](#activity). Throttled to one per 30 seconds per trap. Inert in a session that is not soaking, or with `[soak].beat = false`. Always exits 0; errors go to `logs/beat.log`. |
477
- | ghost trap | A registration whose heartbeat **and** beat lapsed past `[soak].ttlSecs` **after having parked at least once**. The sweep removes the registration, requeues only unfinished catches, finalizes done/failed in `done/`, and posts a `trap-ghosted` notice. It removes a soak-created checkout only when clean and pushed to its upstream; dirty, unpushed, no-upstream, or unreadable checkouts stay, protected from later culls too. The notice includes path, branch, modified-file and unpushed-commit counts, or `unknown` when unavailable. A kept anchor preserves the address on re-soaking. A fresh report or beat keeps a working session out of the sweep; a fresh beat also holds the session lock. A catch whose last report is `paused` keeps its trap until the pause expires ([Waiting on](#waiting-on)). A daemon tick gap longer than the soak TTL starts one full TTL of resume grace before any ghost sweep. |
477
+ | ghost trap | A registration whose heartbeat **and** beat lapsed past `[soak].ttlSecs` **after having parked at least once**. The sweep removes the registration, requeues only unfinished catches, finalizes done/failed in `done/`, and posts a `trap-ghosted` notice: quiet (digest and glass only) for an idle trap, a wake for one that held a catch. It removes a soak-created checkout only when clean and pushed to its upstream; dirty, unpushed, no-upstream, or unreadable checkouts stay, protected from later culls too. The notice includes path, branch, modified-file and unpushed-commit counts, or `unknown` when unavailable. A kept anchor preserves the address on re-soaking. A fresh report or beat keeps a working session out of the sweep; a fresh beat also holds the session lock. A catch whose last report is `paused` keeps its trap until the pause expires ([Waiting on](#waiting-on)). A daemon tick gap longer than the soak TTL starts one full TTL of resume grace before any ghost sweep. |
478
478
  | defective enlistment | A stale registration that **never parked** — signed on but never listened (usually no Stop hook). Not swept: the helm gets a `trap-defective` notice with the remedy (`soak --wait`), and the registration stays so the address keeps protecting its work. |
479
- | reserved trap | A trap `lobstah trap reserve` created before any session signs on as it: a name, a `wt:` id, and a one-time ticket, shown as `starting`. Work addressed to it waits. A session redeems the ticket with `soak --ticket` (or `LOBSTAH_TRAP_TICKET`) and signs on as that trap. Unredeemed past its deadline, it fails with a `trap-start-failed` notice and its work stays queued. `stow --wt <name>` withdraws it. |
480
- | trap request | A trap the human asked for from the glass's **+ New trap** button: a `trap-request` request in `requests/<id>.json` with a repo and a harness. It wakes the helm as a `trap-request` event; the helm reserves it with `trap reserve --request <id>`, which closes it. |
481
- | notice | The helm's attention channel for non-status events (`~/.lobstah/notices/`): reservations (`trap-starting`), reservations that did not start (`trap-start-failed`), trap requests from the glass (`trap-request`), sign-ons, first parks, sign-offs, ghosts, defective enlistments, orphaned work, bounced messages, PRs merged or closed, watches held over the fork cap (`watch-held`), failing (`watch-failing`), and recovered (`watch-recovered`), free-space holds (`disk-held`, `disk-cleared`), worktrees released after their PR merged (`worktree-released`, one per cull pass), a repair or rebase that could not push to its PR's branch (`push-failed`), repairs stopped on a PR that made no progress (`repair-stopped`), and a human's answer to a decision (`decision-answer`; its ref is the request id in `~/.lobstah/requests/`). A trap leaves the registry only through a `trap-stowed` or `trap-ghosted` notice — the end-state is always explicit. Consumed by `man wait`/the park; a first park (`trap-listening`) is consumed without waking anyone. tend always shows the recent tail. |
479
+ | reserved trap | A trap `man throw` reserved before its session signs on: a name, a `wt:` id, and a one-time ticket, shown as `starting`. `man throw --new` reserves a fresh id and name; `man throw <name>` reserves an existing roster trap under its own id and name, in its own worktree (the reservation records the worktree). A trap has at most one reservation, so a second throw refuses. Work addressed to it waits. A session redeems the ticket with `soak --ticket` (or `LOBSTAH_TRAP_TICKET`) and signs on as that trap. A throw that sees no sign-on by its timeout withdraws the reservation; one found unredeemed past its deadline fails with a `trap-start-failed` notice and its work stays queued. `stow --wt <name>` withdraws it. A reservation made by a batch throw records the batch, and so does the registration its sign-on makes. |
480
+ | trap roster | One durable record per trap that ever signed on (`~/.lobstah/roster/<trapId>.json`): canonical name, repo and its git common directory, worktree, soak branch, last branch and HEAD, harness, session, the registration's model and config, window and link (navigation hints only), state (`live`, `stowed`, `ghosted`), when and why it left, its last catch, and a saved profile (harness, model, config, terminal) set with `man roster set`. Sign-on writes it; stow and the ghost sweep update it before the registration goes. Stow, the end of the sign-off grace, a ghost sweep, and `cull` never remove it. The roster's name is the trap's name: a trap that signs on again keeps it. A roster record never makes a trap live or claimable. `man roster` lists it; `man throw` reads it; `man roster forget` removes it. |
481
+ | protected ref | `refs/lobstah/traps/<trapId>` in the trap's repository: the trap's last HEAD, written at sign-on and before stow, a ghost sweep, or `cull` removes the checkout. It is not a branch, so worktree removal and branch cleanup leave it and its commit in place. A missing checkout is recreated from it. A trap checkout whose revision cannot be written there is not removed by a ghost sweep or cull. |
482
+ | trap request | A trap the human asked for from the glass's **+ New trap** button: a `trap-request` request in `requests/<id>.json` with a repo and a harness. It wakes the helm as a `trap-request` event; the helm starts it with `man throw --new --request <id>`, which takes the request's repo and harness and closes it. |
483
+ | notice | The helm's attention channel for non-status events (`~/.lobstah/notices/`): reservations (`trap-starting`), reservations that did not start (`trap-start-failed`), trap requests from the glass (`trap-request`), sign-ons, a trap free to take work (`trap-available`), a batch throw settled (`trap-batch`), sign-offs, ghosts, defective enlistments, orphaned work, bounced messages, PRs merged or closed, watches held over the fork cap (`watch-held`), failing (`watch-failing`), and recovered (`watch-recovered`), free-space holds (`disk-held`, `disk-cleared`), worktrees released after their PR merged (`worktree-released`, one per cull pass), a repair or rebase that could not push to its PR's branch (`push-failed`), repairs stopped on a PR that made no progress (`repair-stopped`), and a human's answer to a decision (`decision-answer`; its ref is the request id in `~/.lobstah/requests/`). A trap leaves the registry only through a `trap-stowed` or `trap-ghosted` notice — the end-state is always explicit. Consumed by `man wait`/the park. A trap's start wakes once, with `trap-available` when it is listening; `trap-starting`, `trap-signed-on`, `trap-stowed`, `trap-listening` (older homes), a ghost of an idle trap, and a batch member's `trap-available` are quiet: consumed without waking anyone, shown in tend, the glass, and (sign-offs and idle ghosts) the digest's `traps` table. A batch throw wakes once, with `trap-batch` when every throw settled: counts, and the names that failed. tend always shows the recent tail. |
484
+ | stack-ready notice | One wake for an all-ready PR stack, with the PRs in bottom-first merge order. Stacked per-PR ready items remain quiet; unchanged heads do not re-notify as the bottom PRs merge. |
482
485
 
483
486
  Delivery routes by ownership, same as watches: a continuation for a chain
484
487
  claimed by a live trap is addressed back to that trap and stays sticky.
@@ -496,14 +499,20 @@ hold two; a live foreign holder refuses sign-on without `--take`. The rule
496
499
  is strict: once a helm is claimed, the orchestrator verbs that consume helm
497
500
  state (`man wait`, `man report`, the lobstah man park) are reserved for the
498
501
  helm session — any other caller is refused with guidance (or, for the hook,
499
- silently ignored). Read verbs (`man tend`, `man brief`) and the enlistment
500
- verbs stay open. A stale helm reserves nothing.
502
+ silently ignored). Read verbs (`man tend`, `man brief`, `man throw --dry-run`,
503
+ `man roster`) and the enlistment verbs stay open; `man roster set`,
504
+ `man roster forget`, and `man throw` are the helm's. A stale helm reserves nothing.
501
505
 
502
506
  | Word | Meaning |
503
507
  | ---- | ------- |
504
508
  | lobstah man | One interactive session that takes the helm for a grounds, triages the fleet, dispatches work, and answers traps; `lobstah man` also names its CLI command group. |
505
509
  | `helm` | Sign a session on as the orchestrator for one grounds. Prints the charter and enables the Stop hook without a marker file. Re-running from the same session is an idempotent re-sign. |
506
510
  | watcher registration | `~/.lobstah/watchers/<session-id>.json` stores a `man wait` or `soak --wait` process's PID and heartbeat. The waiter refreshes it while running and removes it on exit; a heartbeat older than five seconds is stale, and a second waiter for the same session refuses. |
511
+ | `man throw --dry-run` | What a throw would do for each selected trap (`--plan` is the same), read from the [trap roster](#soaking-contract): `resume` the saved session, `cold` (a new session under the same name, id, and checkout; the row says why: no saved history, an app session, a profile that changes harness), `skip` (live or starting), or `unresolved` (repo no longer configured or now another repository, record incomplete, checkout gone with no protected ref, or the path anchors another trap). Names select traps; `--all` selects every eligible trap in the grounds; `--repo` narrows. Each row shows harness, model, config, terminal (and where each came from), checkout (`kept` or `recreate`), revision, and held messages. Read-only: it launches and writes nothing. |
512
+ | `man throw --all \| --repo <key> \| --new [--count N]` | A batch throw (the helm's): every eligible trap in the grounds, one repo's, or N fresh traps from the harness defaults (`--harness`, `--request <id>` for a glass trap request). Every launch runs at once, with no limit. One row per trap: `resumed`, `cold`, `new`, `skipped`, or `failed`, each with why; one failure does not stop the others, and the command exits 1 when any failed. The batch posts one `trap-batch` notice when it settles and no per-trap `trap-available`. `--dry-run` (or `--plan`) shows the plan and launches nothing. |
513
+ | `man roster forget <name>` | Remove a stowed trap for good (the helm's): its worktree (one soak did not create stays, minus its anchor), its protected ref, its roster record, its held messages (bounced), and its name. Refuses a live or starting trap, and refuses, naming the work, when its checkout has unsaved files or its commits are on no remote branch and not merged to trunk; `--force` forgets anyway, keeping a branch that still holds such commits. |
514
+ | `man throw <name>` | Bring one roster trap back and wait until it listens. The helm's. It follows the plan for that trap: a `skip` (live or starting) refuses, which fences a double launch; an `unresolved` refuses with its reason. Otherwise it reserves the trap under its own id and name, recreates a missing checkout from the protected ref on its recorded branch (an existing branch only when it still contains that revision; a kept checkout, dirty or not, is used as is), and opens the start command in the profile's terminal (Terminal.app or iTerm2, macOS): `resume` reopens the saved session from the directory its history is keyed by, `cold` starts a new one in the worktree; the first prompt redeems the ticket. It returns when the trap has signed on under its id and parked, printing which start happened and why. Past `--timeout` (default 180 s) it withdraws the reservation, posts `trap-start-failed`, and leaves the roster unchanged. Batches: see `man throw --all`. |
515
+ | `man roster` | List the trap roster. `man roster set <trap> --harness\|--model\|--terminal <value>\|--config <key>=<value>` saves how a throw starts the trap; `default` (or `key=`) clears a field. |
507
516
  | `man haul --park` | Make the Stop hook wait for attention while work is in flight. `[helm].park = "block"` selects the same mode. In arm mode, the hook allows a stop with a live watcher or blocks with the arm command. |
508
517
  | `relieve` | Step down. `--take` on another session's `helm` is the only force path: it displaces a live holder deliberately and leaves them a stand-down notice, delivered once at their next park. A holder whose heartbeat lapsed past `[helm].ttlSecs` is stale and claimable without `--take`. |
509
518
  | grounds | A named territory: the subset of configured repos one helm oversees, from `[grounds.*]`. A repo belongs to at most one grounds (config error otherwise). No grounds configured means one implicit `fleet` grounds covering every repo. |
@@ -534,7 +543,8 @@ never until someone acknowledges it.
534
543
  | `pr:review` | An open PR has unresolved review questions, or requested changes that lobstah cannot repair, has exhausted, or is configured not to repair. | Every thread resolved and no changes requested, or merged / closed. |
535
544
  | `pr:checks` | An open PR has a failed latest check, and lobstah cannot repair it, has exhausted attempts, or is configured not to repair. | Green on the head, or merged / closed. |
536
545
  | `pr:conflict` | An open PR conflicts with its base, and lobstah cannot repair it, has exhausted attempts, or is configured not to repair. | The merge state leaves `DIRTY`, or merged / closed. |
537
- | `pr:ready` | An open, non-draft PR has no review condition, a mergeable state (`CLEAN`, `HAS_HOOKS`, or `UNSTABLE`), and no failed, pending, or unknown latest checks. It is approved or has at least one check. | Merged or closed, or the ready conditions stop holding. |
546
+ | `pr:ready` | An open, non-draft PR has no review condition, a mergeable state (`CLEAN`, `HAS_HOOKS`, or `UNSTABLE`), and no failed, pending, or unknown latest checks. It is approved or has at least one check, continuously on the same head for `readySettleSecs` (default 600; `0` is immediate). Attention reads re-evaluate expiry without requiring a new forge event. In a trunk-rooted same-repo stack of two or more non-fork PRs, each ready item stays visible but quiet; the stack wakes once. | Merged or closed, or the ready conditions stop holding; any not-ready observation or new head resets settling. |
547
+ | `stack-ready` | Every open member of a trunk-rooted same-repo base/head chain meets the identical `pr:ready` rule, including settling. Enabled with `pr:ready` (or explicitly with `stack-ready`). One notice and walking item per ready epoch, naming PRs bottom to top in merge order. Tend, digest, and the existing glass group also show partial readiness. Existing `pr:` watches discover missing links at their normal cadence; `lobstah watch add pr:<owner>/<repo>#<n>` follows a stack from any member. | Any member becomes unready or gets a new head; all ready again wakes once. Bottom-first merges and retargeting do not wake again for unchanged surviving heads. |
538
548
  | `report` | A filed report (`report --report`, `man file`) has no ack for this filing. Opt-in. Key `report:<lane>:<uuid>` or `report:helm:<grounds>:<rid>`. | Not cleared: it stays listed until culled. `lobstah attention ack <key>` acks it, and a newer report in the same chain acks the older; an acked report no longer walks. |
539
549
 
540
550
  `pr:*` kinds read only the `pr:` watch's evidence — never a forge call —
@@ -563,7 +573,7 @@ reminder loop apply the same predicate.
563
573
 
564
574
  | Word | Meaning |
565
575
  | ---- | ------- |
566
- | ack | `~/.lobstah/acks/<item-key>.json` — `{ key, kind, stateHash, at, by }`, written only by `lobstah attention ack` (removed by `unack`, by the CLI's `man tend` / `attention` when its `stateHash` goes stale, and by `cull` when the item is gone). **Display-only**: it hides the item from the desktop pet and the glass lobs while the item's `stateHash` is unchanged; `man tend --json` keeps the item with `acked: { at, by }`, and `man wait`, the park, reminders, and `notifyCommand` never read acks. Item keys: `<lane>:<uuid>` (question, landed), `decision:<rid>`, `pr:<owner>/<repo>#<n>` (all of a PR's `pr:*` kinds — one ack covers them), `watch:<key>`. `stateHash` covers the status entry (question, landed) or the PR's head sha plus every evidence field a `pr:*` kind stands on (not `observedAt`); for a ready PR, only when `pr:ready` began standing (its `standingSince`), so repeat observations of the same ready state keep the ack and ready → not ready → ready re-stands it once. |
576
+ | ack | `~/.lobstah/acks/<item-key>.json` — `{ key, kind, stateHash, at, by }`, written only by `lobstah attention ack` (removed by `unack`, by the CLI's `man tend` / `attention` when its `stateHash` goes stale, and by `cull` when the item is gone). **Display-only**: it hides the item from the desktop pet and the glass lobs while the item's `stateHash` is unchanged; `man tend --json` keeps the item with `acked: { at, by }`, and `man wait`, the park, reminders, and `notifyCommand` never read acks. Item keys: `<lane>:<uuid>` (question, landed), `decision:<rid>`, `pr:<owner>/<repo>#<n>` (all of a PR's `pr:*` kinds — one ack covers them), `watch:<key>`. `stateHash` covers the status entry (question, landed) or the PR's head sha plus every evidence field a `pr:*` kind stands on (not `observedAt`); for a ready PR, only the head sha. A ready ack is kept across same-head CI flaps and draft toggles, without hiding checks, conflicts, or review attention during the flap. A new head re-stands ready once after settling. |
567
577
  | pet state | `~/.lobstah/pet/state.json` — `{ pid, at, ok, command, reason, consecutiveFailures, items, lastOkAt }`. The desktop pet's one write: it rewrites the file after each attention read (about every six seconds). `command` is the command that worked (`attention --json`, or `man tend --json` from an older CLI). `reason` says why the last read failed (timed out, non-zero exit, output that does not decode). Only `lobstah doctor` reads it, for its `pet` row: running means `pid` is alive and `at` is less than two minutes old. |
568
578
  | budget stop | A headless runner's `failed` verb with a `budget:` note means its progress-extended active-work window reached the hard ceiling. This is out of time, not a code failure: the runner checkpoints eligible changes, pushes when enabled, names the saved branch/commit/draft PR, and invites `lobstah send <id> "continue"`. Paused `--waiting-on` time is excluded. |
569
579
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lobstah",
3
- "version": "0.6.9",
3
+ "version": "0.7.0",
4
4
  "description": "Harness-agnostic, token-efficient supervision framework for coding agents",
5
5
  "license": "MIT",
6
6
  "author": "aequitas labs LLC",