tickmarkr 2.6.4 → 2.6.5
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/dist/adapters/catalog-remote.d.ts +23 -0
- package/dist/adapters/catalog-remote.js +38 -0
- package/dist/adapters/claude-code.d.ts +1 -1
- package/dist/adapters/claude-code.js +4 -1
- package/dist/adapters/codex-commit-check.d.ts +25 -0
- package/dist/adapters/codex-commit-check.js +108 -0
- package/dist/adapters/model-discovery-check.d.ts +33 -0
- package/dist/adapters/model-discovery-check.js +123 -0
- package/dist/adapters/model-lints.d.ts +1 -1
- package/dist/adapters/model-lints.js +4 -0
- package/dist/adapters/prompt.js +3 -2
- package/dist/adapters/types.d.ts +7 -0
- package/dist/cli/commands/approve.js +10 -4
- package/dist/cli/commands/doctor.d.ts +2 -0
- package/dist/cli/commands/doctor.js +14 -2
- package/dist/cli/commands/fleet.d.ts +10 -1
- package/dist/cli/commands/fleet.js +55 -38
- package/dist/cli/commands/init.js +5 -1
- package/dist/cli/commands/plan.js +65 -4
- package/dist/cli/commands/verify.d.ts +1 -1
- package/dist/cli/commands/verify.js +28 -6
- package/dist/config/fleet-overlay.d.ts +2 -1
- package/dist/config/fleet-overlay.js +77 -4
- package/dist/drivers/orca.d.ts +19 -1
- package/dist/drivers/orca.js +161 -31
- package/dist/gates/cache.d.ts +4 -0
- package/dist/gates/cache.js +10 -2
- package/dist/gates/llm.d.ts +4 -1
- package/dist/gates/llm.js +6 -1
- package/dist/gates/review.js +8 -3
- package/dist/gates/run-gates.d.ts +3 -2
- package/dist/gates/run-gates.js +91 -50
- package/dist/run/daemon.js +150 -19
- package/dist/run/git.js +9 -0
- package/dist/run/journal.d.ts +6 -2
- package/dist/run/journal.js +22 -7
- package/dist/run/launchservices-check.d.ts +56 -0
- package/dist/run/launchservices-check.js +117 -0
- package/dist/run/operator-state.d.ts +22 -2
- package/dist/run/operator-state.js +20 -3
- package/dist/run/title-environment.d.ts +45 -0
- package/dist/run/title-environment.js +127 -0
- package/dist/run/title-preload.cjs +38 -0
- package/dist/run/title-preload.d.cts +1 -0
- package/dist/tui/cockpit/board.js +12 -6
- package/dist/tui/cockpit/keys.d.ts +8 -0
- package/dist/tui/cockpit/keys.js +4 -1
- package/dist/tui/cockpit/layout.d.ts +2 -2
- package/dist/tui/cockpit/layout.js +2 -2
- package/dist/tui/cockpit/live-runtime.js +46 -20
- package/dist/tui/cockpit/live-store.d.ts +24 -1
- package/dist/tui/cockpit/live-store.js +99 -8
- package/dist/tui/cockpit/log-view.d.ts +28 -0
- package/dist/tui/cockpit/log-view.js +60 -0
- package/dist/tui/cockpit/run-view.js +4 -0
- package/dist/tui/cockpit/shell.d.ts +2 -1
- package/dist/tui/cockpit/shell.js +6 -4
- package/dist/tui/ink/fleet-app.d.ts +12 -6
- package/dist/tui/ink/fleet-app.js +17 -11
- package/package.json +1 -1
- package/skills/tickmarkr-auto/SKILL.md +32 -2
- package/skills/tickmarkr-loop/SKILL.md +46 -2
- package/skills/tickmarkr-overseer/SKILL.md +83 -8
|
@@ -88,10 +88,40 @@ When spawning consultants (agents gathering synthesis input for decisions like S
|
|
|
88
88
|
1. **Prepare** — start from the requested spec. Run the [binary preflight](#binary-preflight-before-compile-or-run). Check `git status`, confirm no tickmarkr run is active, and work from a non-main branch.
|
|
89
89
|
2. **Compile** — run `tickmarkr compile <spec>`. Correct compilation errors in the spec, never in the generated graph.
|
|
90
90
|
3. **Plan** — run `tickmarkr plan`. Review the routing table, capability-floor warnings, and every human gate, including work that each gate blocks.
|
|
91
|
-
4. **Run** —
|
|
91
|
+
4. **Run** — launch `tickmarkr run` using the [host-owned split form](#host-owned-daemon-and-detached-beats), and start detached beats with their run-end stop items. A watch ending the seat's turn is no watch: keep a **blocking journal consumer** alive for the run's terminal events — the shipped watcher below, or a foreground `until grep` on the run's terminal events — and ensure it is re-armed at most every twenty minutes. Never rely on a `Monitor`-only wake. Watch the run journal rather than polling agents, using the shipped watcher — `.claude/skills/tickmarkr-overseer/scripts/watch-journal.sh <state-dir>/runs 20 28800` — which takes a line baseline at arm time, then wakes ONCE on `run-end`, `task-human`, `task-failed` or `consult-verdict` and grades the run-end summary against every execution clause for you; the debt clause is yours — read CURRENT `tickmarkr status <runId>` (step 5). Re-arm after every wake. ⛔ Never `tail -F | grep -m1` (run-end is the journal's last line, so tail never notices the broken pipe and the watcher hangs forever) and never a pane-level done wait (it fires on every agent turn end, not mission end). ⚠ A bare whole-file `grep -q '"event":"run-end"'` is the trap the watcher exists to avoid: on a resume it matches the PREVIOUS run's run-end and returns instantly, so a re-armed watcher reads as coverage that does not exist. Resolve blocked interactions in the agent session; do not turn them into proxy questions.
|
|
92
92
|
5. **Verify and consolidate** — accept only a green run. A run is green when the run-end event exists in the journal, the tip verify is not "failed", the summary's `failed`, `human`, `blocked` and `pending` buckets are all empty, and CURRENT `tickmarkr status <runId>` reads its owed checks outstanding empty AND known (`outstanding 0`) — a run with a parked task is partial, not green. Empty execution buckets alone are not green either (D-660): every bucket empty and the tip passed, but an operator waived one review, leaves one accepted-risk review check owed — status reads `outstanding 1 (T7 review)` and `run`/`resume` still exit 0 on execution alone, so the run is execution complete, not green. It turns green only when a `tickmarkr verify --record <runId>` discharge moves CURRENT status to `outstanding 0`, including a discharge landing after run-end — the historical run-end record keeps the old count, so never read debt from it; `outstanding unknown` is never green. Tickmarkr consolidates accepted task work on `tickmarkr/<runId>`; it never signs off to the main branch. A human may later merge that integration branch through the repository's normal release process.
|
|
93
93
|
6. **Record** — `tickmarkr report <runId> --md` prints Markdown to stdout. Redirect it explicitly beside the source spec (for example `tickmarkr report <runId> --md > feature.record.md`) and commit the execution record when the repository tracks those records. Then [stand down](#stand-down-mission-end-and-retirement).
|
|
94
94
|
|
|
95
|
+
## Host-owned daemon and detached beats
|
|
96
|
+
|
|
97
|
+
Launch the daemon as a SPLIT of the orchestrator's own pane in the ORCH tab, owned by the
|
|
98
|
+
host PTY. Never launch it as an agent harness background task or in a separate tab. The daemon
|
|
99
|
+
self-places its board from that split, keeping both daemon and board in the ORCH tab.
|
|
100
|
+
|
|
101
|
+
- **On Orca (`TERM_PROGRAM=Orca` and non-empty `ORCA_TERMINAL_HANDLE`)**:
|
|
102
|
+
`orca terminal split --terminal "$ORCA_TERMINAL_HANDLE" --direction vertical --command "tickmarkr run"`.
|
|
103
|
+
- **On herdr (`HERDR_ENV=1`)**: use `herdr pane split` on the orchestrator's own pane, then
|
|
104
|
+
`herdr pane run <new> "tickmarkr run"` in the returned split.
|
|
105
|
+
|
|
106
|
+
For `resume`, use the same host-owned split form with `tickmarkr resume <runId>` in place of
|
|
107
|
+
`tickmarkr run`. After either launch, read this repository's lock pid and walk its ppid chain
|
|
108
|
+
in the process table to the host PTY; verify no agent session is an ancestor. If an agent is
|
|
109
|
+
an ancestor, stop that launch and relaunch through the host split before continuing.
|
|
110
|
+
|
|
111
|
+
Start `tickmarkr beat <tier> --seat <seat> --loop` as a DETACHED background process, one per
|
|
112
|
+
(tier, seat), from the repository root. Use setsid plus nohup (or the host's equivalent detached
|
|
113
|
+
session facility), redirect output to a file, and record a pidfile under the repository's state
|
|
114
|
+
dir. Verify ppid 1 and no agent-session ancestor. Never put beats in a harness background task
|
|
115
|
+
or a visible tab. The lifecycle must be idempotent: start checks the pidfile against the live
|
|
116
|
+
process payload and returns an "already running" no-op for the same (repo, tier, seat); status
|
|
117
|
+
checks that payload and beat freshness; stop sends `--stand-down` for the same tier and seat,
|
|
118
|
+
verifies the loop exits within one interval, then removes its pidfile. A stale or reused pid
|
|
119
|
+
must never be killed without matching its live payload. Include a run-end stop item for every
|
|
120
|
+
beat started, also on failure, park or handoff; verify DISARMED and remove retired beat files.
|
|
121
|
+
|
|
122
|
+
Keep only watchers that must WAKE the seat in the harness. Re-arm them on each wake and at
|
|
123
|
+
their harness cap; daemon and beat lifetimes must not depend on that cap.
|
|
124
|
+
|
|
95
125
|
## Cockpit, parked decisions and printed twins
|
|
96
126
|
|
|
97
127
|
The shipped cockpit is **1 Home, 4 Run, 5 Evidence**: `tickmarkr ui [runId]` defaults to
|
|
@@ -107,7 +137,7 @@ run/task, original park `#L`, actor/reason, exact argv, consequence and enactor.
|
|
|
107
137
|
confirms; `n`/Esc cancel; Enter never confirms. Read the receipt's appended `task-approved`
|
|
108
138
|
line and actor/reason back from the journal. Approval records permission, never dispatch,
|
|
109
139
|
a passed gate or task completion. With no live owner it says **approved; resume required**:
|
|
110
|
-
exit the observer and
|
|
140
|
+
exit the observer and launch `tickmarkr resume <runId>` explicitly with the same host-owned split form above. A matching live daemon
|
|
111
141
|
enacts at its next task boundary; if a different live run owns the repository lock, wait
|
|
112
142
|
for that run to end before resuming this one.
|
|
113
143
|
|
|
@@ -177,6 +207,20 @@ repair and catalog refresh; default doctor and `--fix` still probe. `scope <inte
|
|
|
177
207
|
--preview` performs no probes, model calls or writes; authoring requires confirmation or
|
|
178
208
|
`--yes`. These actions remain CLI entries until their follow-on views ship.
|
|
179
209
|
|
|
210
|
+
**macOS host failure: a launchservicesd restart (D-787/D-789).** If GUI apps suddenly read "The
|
|
211
|
+
application … is not open anymore" during a local suite, launchservicesd crashed and respawned with an
|
|
212
|
+
empty app registry. That was measured on 2026-09-30: `0x1000600b` Mach port exhaustion under node
|
|
213
|
+
`process.title` check-ins, crash at 17:15:00Z and respawn at 17:15:09Z. `tickmarkr doctor` and standalone
|
|
214
|
+
`tickmarkr verify` record the daemon's pid/start through the separate `src/run/launchservices-check.ts`
|
|
215
|
+
module: one bounded `/bin/ps` read with a 5000 ms kill ceiling. doctor's wiring is five lines in
|
|
216
|
+
`src/cli/commands/doctor.ts`. The identity lives on the first `doctor.json` record, and one advisory
|
|
217
|
+
prints and persists when it changed. Unknown evidence keeps the prior identity, and verdicts and retries
|
|
218
|
+
never change. Confirm the identity with `/bin/ps -o pid=,lstart= -p "$(pgrep -x launchservicesd)"`: it
|
|
219
|
+
is young beside Dock and Finder. Confirm the log with `/usr/bin/log show --start '<that lstart minus two
|
|
220
|
+
minutes>'`, looking for `0x1000600b` then `Successfully spawned launchservicesd`. Type the full path: a bare
|
|
221
|
+
`log` is a zsh builtin that prints nothing. Then quit and relaunch the affected apps, or log out /
|
|
222
|
+
restart once the run is stood down; a restart ends agent sessions and wipes `/private/tmp`.
|
|
223
|
+
|
|
180
224
|
Keep this skill's canonical identity `tickmarkr-loop`; sibling skills link to this
|
|
181
225
|
walkthrough. In this repository `skills/` is canonical and installed `.claude/skills/`
|
|
182
226
|
files resolve to it; change the canonical source, never create a second help skill.
|
|
@@ -121,13 +121,13 @@ through brief lineage. **An executor choice nobody made is still an executor cho
|
|
|
121
121
|
tab OVERSEER; create ONE tab ORCHESTRATOR.
|
|
122
122
|
**FIVE-TAB CANON (standing operator layout — corrected three times on 2026-07-27, layout approved
|
|
123
123
|
2026-07-29, re-earned 2026-08-17):**
|
|
124
|
-
- `OVERSEER` — you. Do not add a
|
|
125
|
-
|
|
126
|
-
- `ORCH` — the orchestrator
|
|
124
|
+
- `OVERSEER` — you. Do not add a live run surface here: launch the daemon from the ORCH tab
|
|
125
|
+
using the host-owned split form below; it self-places the shipped board there.
|
|
126
|
+
- `ORCH` — the orchestrator, its host-owned daemon split, and the daemon-placed, run-id-pinned shipped board BESIDE it: the board
|
|
127
127
|
takes the RIGHT half of the tab and the orchestrator's own narration keeps the LEFT half. (It was a
|
|
128
128
|
full-width board above a narration rail until 2026-08-25; the operator changed it, because a task
|
|
129
129
|
table is a few rows and it was spending height it did not need while squeezing the narration.) **Look for that `role: "watch"` pane; never hand-place or hand-roll a live
|
|
130
|
-
run surface.
|
|
130
|
+
run surface. Only the orchestrator, daemon and board belong here: a work seat NEVER splits into the ORCH tab.** Operator verbatim:
|
|
131
131
|
*"in orch tab should be the orch and the watcher only."* Re-earned 2026-08-17: a planning seat split
|
|
132
132
|
beside the orchestrator, and the operator caught it, again. The daemon owns this vertical stack and
|
|
133
133
|
places it the same way at every terminal width; neither the worker-pane halving floor, nor a
|
|
@@ -147,12 +147,13 @@ through brief lineage. **An executor choice nobody made is still an executor cho
|
|
|
147
147
|
fraction (`ORCH · v1.19 4/5`, updated on every task-done); tickmarkr opens ONE TAB PER TASK, labelled
|
|
148
148
|
with the task id and holding that task's worker plus its judge/review/consult panes (tickmarkr
|
|
149
149
|
updates it). Never long context strings or ✓-chains.
|
|
150
|
-
- **On Orca (`TERM_PROGRAM=Orca` and non-empty `ORCA_TERMINAL_HANDLE`)**: Do not load the `herdr` skill and do not map a Herdr workspace. Work from the current Orca terminal context. Keep the overseer in the launching terminal, name it in the same act — `orca terminal rename --terminal "$ORCA_TERMINAL_HANDLE" --title "OVERSEER · <version>"` (tab title; see the seat-name law under Seat-spawn recipes) — and inspect terminals with `orca terminal list --json`.
|
|
150
|
+
- **On Orca (`TERM_PROGRAM=Orca` and non-empty `ORCA_TERMINAL_HANDLE`)**: Do not load the `herdr` skill and do not map a Herdr workspace. Work from the current Orca terminal context. Keep the overseer in the launching terminal, name it in the same act — `orca terminal rename --terminal "$ORCA_TERMINAL_HANDLE" --title "OVERSEER · <version>"` (tab title; see the seat-name law under Seat-spawn recipes) — and inspect terminals with `orca terminal list --json`. Launch the daemon in a host-owned split of the orchestrator terminal using the form below; its self-placed watch board stays in the ORCH tab.
|
|
151
151
|
2. **Orchestrator**: First consume a successful `tickmarkr fleet --pick consult` in the seat repository, per the Fleet selection contract below; then launch the returned adapter/model with your agent host.
|
|
152
152
|
- **On herdr (`HERDR_ENV=1`)**: Spawning on current herdr is two-step — the one-shot `agent start --cwd` form was removed in the herdr CLI redesign and now fails with `unknown option` (OBS-138): first create the pane with `herdr tab create --workspace <ws> --cwd <repo> --label "ORCH · <version>"` and parse `result.root_pane.pane_id` from its JSON, then start the agent in it. For Claude Code, use `herdr agent start orchestrator --kind claude --pane <root-pane-id> -- --permission-mode bypassPermissions` (append `--model <picked-model>` after the `--` from the Fleet receipt). For Codex, use `herdr agent start orchestrator --kind codex --pane <root-pane-id> -- --dangerously-bypass-approvals-and-sandbox` (add `--model <picked-model>` from the Fleet receipt). The unsandboxed flag is REQUIRED: codex's `workspace-write` sandbox keeps `.git` refs read-only, so a sandboxed orchestrator's `tickmarkr run` dies at integration-branch creation — do not downgrade it. Workers you never spawn — tickmarkr spawns its own visible worker panes. Auxiliary agents you do spawn (consultants, reviewers, scouts) follow the same forms: never launch a claude session in plan mode or default permission mode for autonomous work — both stall on per-command approval prompts nobody is watching; claude is always `--permission-mode bypassPermissions --settings '{"promptSuggestionEnabled":false}'`. **For a codex consultant, use `-a never --sandbox workspace-write` — NOT `--sandbox read-only`.** ⚠ **`--sandbox read-only` CONTRADICTS this skill's own completion protocol and will hang the seat.** Every seat you spawn is told to deliver an ARTIFACT ending in a terminal MARKER, because that is the only completion signal the artifact watcher can key on (`done` is turn end). A read-only sandbox cannot write that artifact, so codex blocks on `Would you like to make the following edits?` for its OWN report — and the report exists ONLY in the pending edit, so abandoning the prompt destroys the work rather than merely delaying it. Measured 2026-08-28: a consultant spawned `--sandbox read-only` finished a 14,604-byte verdict, sat blocked on the write, and the operator saw the prompt before the supervising tier did. `read-only` is correct ONLY for a seat that writes nothing at all — which, under the artifact+marker rule, is no seat this skill tells you to spawn. When the prompt does appear, answer **"Yes, and don't ask again for these files"** rather than plain yes: plain yes re-blocks on the next write of the same file. **That `--settings` pair is not cosmetic and it is not optional:** claude-code's AUTOSUGGEST renders context-plausible ghost text into an idle seat's prompt line that is BYTE-IDENTICAL to a typed draft in text-format reads (OBS-482), so a supervising tier cannot tell a seat's own unsent work from a rendering artifact without `agent read --format ansi`. Turning the suggester off at spawn removes the ambiguity at its source instead of paying for the discrimination at every read. Verified against the shipped binary: `claude --settings '{"promptSuggestionEnabled":false}' -p …` exits 0 with a real response, and the key appears in the binary's own settings schema. **For kimi, pass `-y`** (`herdr agent start <name> --kind kimi --pane <id> -- -y`) — the adapter already launches its own workers that way (`src/adapters/kimi.ts:204`), and a kimi seat spawned without it sits on an approval prompt having done nothing. **Herdr cannot see that state**: it reports a kimi pane as `agent_status: working` with `screen_detection_skipped: true` while the prompt is up, so the BLOCKED-STATE watcher below is blind on this vendor and the spawn flag is the ONLY control. Every vendor you spawn needs its auto-approve form named here; a vendor absent from this list is a seat that will hang.
|
|
153
153
|
- **On Orca (`TERM_PROGRAM=Orca` and non-empty `ORCA_TERMINAL_HANDLE`)**: Seats spawn with `orca terminal create` on a path worktree selector with a command:
|
|
154
154
|
`orca terminal create --worktree path:<repo> --title "ORCH · <version>" --command "<agent-cmd>" --json`
|
|
155
155
|
For Claude Code: `orca terminal create --worktree path:<repo> --title "ORCH · <version>" --command "claude --model <picked-model> --permission-mode bypassPermissions --settings '{\"promptSuggestionEnabled\":false}'" --json`. For Codex: `orca terminal create --worktree path:<repo> --title "ORCH · <version>" --command "codex --model <picked-model> --dangerously-bypass-approvals-and-sandbox" --json`. Parse `result.terminal.handle` from the create receipt.
|
|
156
|
+
Require the orchestrator to use the host-owned daemon and detached-beat lifecycle below for both run and resume, and to report the lock pid ancestry check.
|
|
156
157
|
3. **Standing instructions travel as a brief FILE, never as pane text** — PTY input truncates at ~1024B and a
|
|
157
158
|
truncated brief silently drops policy. Write the full brief to `<repo>/.tickmarkr/overseer/ORCH-BRIEF.md`
|
|
158
159
|
(inside the tickmarkr state dir — already self-gitignored, no exclude step needed), then announce the brief file:
|
|
@@ -196,9 +197,23 @@ through brief lineage. **An executor choice nobody made is still an executor cho
|
|
|
196
197
|
The orchestrator's run log, handoff, and plan live inside its sandbox root and are artifacts of that orchestrator.
|
|
197
198
|
The overseer reads them from there, using the path the orchestrator reports; do not substitute the
|
|
198
199
|
overseer's repository or a machine-global planning directory. The orchestrator brief must say: if the seat's
|
|
199
|
-
sandbox denies writes under `.git`, report the denial to the overseer and stop; the overseer launches the daemon itself;
|
|
200
|
+
sandbox denies writes under `.git`, report the denial to the overseer and stop; the overseer launches the daemon itself; use the host-owned split of the ORCH pane, never the overseer tab;
|
|
200
201
|
and the daemon host is never sandboxed.
|
|
201
202
|
|
|
203
|
+
**Sandbox-denial daemon launch (OVERSEER):** use the ORCH address recorded at seat creation,
|
|
204
|
+
re-resolved by title if stale; the launching overseer's own terminal is not the target.
|
|
205
|
+
|
|
206
|
+
- **On Orca (`TERM_PROGRAM=Orca` and non-empty `ORCA_TERMINAL_HANDLE`)**: record the ORCH's
|
|
207
|
+
`result.terminal.handle` from its seat-create receipt. For the fallback, run
|
|
208
|
+
`orca terminal split --terminal <ORCH handle> --direction vertical --command "tickmarkr run"`.
|
|
209
|
+
Here `$ORCA_TERMINAL_HANDLE` names the OVERSEER's own terminal; use it only when the ORCH
|
|
210
|
+
launches its own daemon, never when the OVERSEER launches on the ORCH's behalf.
|
|
211
|
+
- **On herdr (`HERDR_ENV=1`)**: record the ORCH's `result.root_pane.pane_id` from its tab-create
|
|
212
|
+
receipt. For the fallback, use `herdr pane split` targeting that recorded ORCH pane id, then
|
|
213
|
+
`herdr pane run <new> "tickmarkr run"`; never target the OVERSEER's pane.
|
|
214
|
+
|
|
215
|
+
The same recorded ORCH address is required for a fallback `tickmarkr resume <runId>`.
|
|
216
|
+
|
|
202
217
|
**On herdr (`HERDR_ENV=1`)**, after every `agent start`, wait for and read the model banner. Only then
|
|
203
218
|
deliver the brief with `pane run`, then read the transcript back and verify that the brief's first words are
|
|
204
219
|
present before any deadline is armed. **On Orca (`TERM_PROGRAM=Orca` and non-empty
|
|
@@ -291,6 +306,40 @@ Kimi `-y`, artifact plus terminal marker, and verified file-brief delivery. Flee
|
|
|
291
306
|
nothing the tab did not already hold. Brief delivery travels as a file announced by `orca terminal send --terminal <handle> --text "<announcement>" --enter --wait-submit 15 --json`. Read `result.send.prompt.stages` and treat the brief as delivered only when a `turn_started` stage is present; `accepted: true` proves input acceptance, not a started turn; never resend on `accepted` alone.
|
|
292
307
|
For Leg-2 (both hosts), a Codex reviewer under `workspace-write` must be briefed with an in-worktree verdict path such as
|
|
293
308
|
`<repo>/.tickmarkr/overseer/verdicts/<task>.md`, and its verdict must be written there before it is read.
|
|
309
|
+
## Host-owned daemon and detached beats
|
|
310
|
+
|
|
311
|
+
Launch the daemon as a SPLIT of the orchestrator's own pane in the ORCH tab, owned by the
|
|
312
|
+
host PTY. Never launch it as an agent harness background task or in a separate tab. The daemon
|
|
313
|
+
self-places its board from that split, keeping both daemon and board in the ORCH tab.
|
|
314
|
+
|
|
315
|
+
- **On Orca (`TERM_PROGRAM=Orca` and non-empty `ORCA_TERMINAL_HANDLE`)**: only when the ORCH
|
|
316
|
+
launches its own daemon, use
|
|
317
|
+
`orca terminal split --terminal "$ORCA_TERMINAL_HANDLE" --direction vertical --command "tickmarkr run"`.
|
|
318
|
+
When the OVERSEER launches the sandbox-denial fallback, substitute the ORCH handle recorded
|
|
319
|
+
at seat creation: `orca terminal split --terminal <ORCH handle> --direction vertical --command "tickmarkr run"`.
|
|
320
|
+
- **On herdr (`HERDR_ENV=1`)**: use `herdr pane split` on the orchestrator's own pane, then
|
|
321
|
+
`herdr pane run <new> "tickmarkr run"` in the returned split. When the OVERSEER launches the
|
|
322
|
+
fallback, target the ORCH pane id recorded at seat creation, never the OVERSEER's pane.
|
|
323
|
+
|
|
324
|
+
For `resume`, use the same host-owned split form with `tickmarkr resume <runId>` in place of
|
|
325
|
+
`tickmarkr run`. After either launch, read this repository's lock pid and walk its ppid chain
|
|
326
|
+
in the process table to the host PTY; verify no agent session is an ancestor. If an agent is
|
|
327
|
+
an ancestor, stop that launch and relaunch through the host split before continuing.
|
|
328
|
+
|
|
329
|
+
Start `tickmarkr beat <tier> --seat <seat> --loop` as a DETACHED background process, one per
|
|
330
|
+
(tier, seat), from the repository root. Use setsid plus nohup (or the host's equivalent detached
|
|
331
|
+
session facility), redirect output to a file, and record a pidfile under the repository's state
|
|
332
|
+
dir. Verify ppid 1 and no agent-session ancestor. Never put beats in a harness background task
|
|
333
|
+
or a visible tab. The lifecycle must be idempotent: start checks the pidfile against the live
|
|
334
|
+
process payload and returns an "already running" no-op for the same (repo, tier, seat); status
|
|
335
|
+
checks that payload and beat freshness; stop sends `--stand-down` for the same tier and seat,
|
|
336
|
+
verifies the loop exits within one interval, then removes its pidfile. A stale or reused pid
|
|
337
|
+
must never be killed without matching its live payload. Include a run-end stop item for every
|
|
338
|
+
beat started, also on failure, park or handoff; verify DISARMED and remove retired beat files.
|
|
339
|
+
|
|
340
|
+
Keep only watchers that must WAKE the seat in the harness. Re-arm them on each wake and at
|
|
341
|
+
their harness cap; daemon and beat lifetimes must not depend on that cap.
|
|
342
|
+
|
|
294
343
|
## Supervising tickmarkr as the executor — WHO DOES WHAT
|
|
295
344
|
|
|
296
345
|
When the mission runs `/tickmarkr-auto` (tickmarkr dispatches the workers), supervision changes shape —
|
|
@@ -411,6 +460,29 @@ journal tail to decide what happens next, or sweeping orphans — you have taken
|
|
|
411
460
|
its death. Liveness comes from the lock's OWN pid (`kill -0`), never a command-name grep. Recovery is
|
|
412
461
|
`tickmarkr resume <runId>` — **the orchestrator's command, not yours** — and note that resume REPLAYS the
|
|
413
462
|
journal's `baseRef`, so a fix landed on the base branch is unreachable by the running run.
|
|
463
|
+
- **macOS host: a launchservicesd restart is a host failure, not a kill spree (D-787/D-789).** Measured
|
|
464
|
+
2026-09-30: during a local full suite launchservicesd crashed at 17:15:00Z (Mach IPC name space
|
|
465
|
+
exhausted, `0x1000600b`, under node `process.title` check-ins) and launchd respawned it at 17:15:09Z
|
|
466
|
+
with an empty app registry. Every GUI app launched before then read "The application … is not open
|
|
467
|
+
anymore", though none had been killed. Replay it from evidence, in this order:
|
|
468
|
+
1. **Daemon identity.** `/bin/ps -o pid=,lstart= -p "$(pgrep -x launchservicesd)"` beside Dock and
|
|
469
|
+
Finder: a lone young launchservicesd is the tell. Record its pid/lstart before a run and at every lap.
|
|
470
|
+
2. **Recorded log.** `/usr/bin/log show --start '<that lstart minus two minutes>' --predicate 'process ==
|
|
471
|
+
"launchservicesd" OR process == "launchd"'`, looking for `0x1000600b`, then `service inactive` and
|
|
472
|
+
`Successfully spawned launchservicesd`. Always type the full `/usr/bin/log`: in zsh a bare `log` is a
|
|
473
|
+
builtin that prints nothing, and that silence was once misread as a rotated log (D-787 add.1).
|
|
474
|
+
3. **Crash report.** `~/Library/Logs/DiagnosticReports/ExcUserFault_node-*.ips` at the same second
|
|
475
|
+
(`uv_set_process_title → _LSApplicationCheckIn`).
|
|
476
|
+
`tickmarkr doctor` and standalone `tickmarkr verify` read step 1 themselves. The check lives in its own
|
|
477
|
+
module, `src/run/launchservices-check.ts`: one bounded `/bin/ps` read with a 5000 ms kill ceiling.
|
|
478
|
+
doctor's wiring is five lines in `src/cli/commands/doctor.ts` around `writeDoctor`. A changed pid or
|
|
479
|
+
start persists one advisory in the `launchServices` object on the FIRST `doctor.json` record. An
|
|
480
|
+
unreadable read is unknown and keeps the prior identity. The advisory never changes a verdict or a
|
|
481
|
+
retry, and the check never reads `/usr/bin/log`, so steps 2–3 stay yours. **The remedy is the
|
|
482
|
+
operator's call, made actionable by that evidence:** quit and relaunch each affected app, or log out /
|
|
483
|
+
restart the Mac. A restart ends every agent session and wipes `/private/tmp`, so stand the run down at
|
|
484
|
+
a clean boundary first and write the handoff; after the reboot, re-resolve seat handles and re-arm
|
|
485
|
+
watchers. Never kill or restart launchservicesd yourself.
|
|
414
486
|
- **SWEEPING A WORKER ORPHANS ITS CLEANUP, NOT JUST ITS WORK — kill the process GROUP.** Measured
|
|
415
487
|
2026-08-06: a worker running a legitimate load experiment had spawned CPU burners and held a trailing
|
|
416
488
|
`kill` line. It was SIGTERM'd as an orphan; **the cleanup never ran**, and **59 surviving burner shells
|
|
@@ -1095,9 +1167,11 @@ watching it. Two thirds of that line were constants, not measurements.
|
|
|
1095
1167
|
The beat is one shipped command and it arms through two explicit verbs, `--new-arm` and `--loop` —
|
|
1096
1168
|
never a bare invocation. `--loop` already implies `--new-arm`: it creates a durable arm and beats in
|
|
1097
1169
|
this process every 10 seconds, exiting on its own within one interval after a stand-down. Run it from
|
|
1098
|
-
the repo root as
|
|
1170
|
+
the repo root as a detached setsid+nohup process with a pidfile, following the idempotent
|
|
1171
|
+
start/stop/status lifecycle in Host-owned daemon and detached beats; never as a harness task or visible tab:
|
|
1099
1172
|
|
|
1100
1173
|
```bash
|
|
1174
|
+
# Payload for the detached start above; do not execute as a foreground or harness task.
|
|
1101
1175
|
cd <repo> && tickmarkr beat overseer --seat <overseer-agent-or-pane> --loop
|
|
1102
1176
|
cd <repo> && tickmarkr beat overseer --seat <overseer-agent-or-pane> --stand-down # deliberately hand off; --loop exits
|
|
1103
1177
|
```
|
|
@@ -1156,6 +1230,7 @@ but its process ownership still needs a live check. So:
|
|
|
1156
1230
|
legacy bare shell wrapper: unlike `--loop`, it cannot observe the marker and was the form that
|
|
1157
1231
|
re-armed a stand-down.
|
|
1158
1232
|
|
|
1233
|
+
Keep only watchers that must WAKE this seat in the harness, re-armed at their cap.
|
|
1159
1234
|
Arm the bundled watcher as its OWN Bash call with `run_in_background` — chaining it after other commands
|
|
1160
1235
|
with `&` orphans it from the wake chain. It prints one wake reason and exits; re-arm after every wake.
|
|
1161
1236
|
|
|
@@ -1478,7 +1553,7 @@ Create specialist seats using `orca terminal create --worktree path:<repo> --com
|
|
|
1478
1553
|
states an act and lets the successor read a fact, and it survived into a handoff exactly once before
|
|
1479
1554
|
costing two unwatched consult verdicts (OBS-622). The admissible form names the lifetime and the
|
|
1480
1555
|
work it leaves the successor — *"watchers armed by this session (journal, artifact, dialog, beat);
|
|
1481
|
-
|
|
1556
|
+
harness watchers die with it — re-arm on adopt; detached beats require explicit stop"* — and, per rule 11, says which tier's watchers were NOT armed.
|
|
1482
1557
|
A detached watcher is the one exception and must be labelled as such, with its heartbeat file, since
|
|
1483
1558
|
it outlives the seat instead.
|
|
1484
1559
|
- **SWEEP THE PANES THE RUN LEFT.** A daemon killed by a signal flushes its journal and releases its
|