@vibelord/lanes 1.5.0 → 1.6.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.
@@ -118,14 +118,15 @@ account with UID 1000. With `--write` it then applies these steps in order:
118
118
  or to the title the board already has. A board that already disagrees stops the run before the container is
119
119
  touched.
120
120
  2. **Contract.** Runs `lanes install-container`: the `lane` contract, and the Lanes MCP server (`lane-mcp`) in
121
- Claude Code's `~/.claude.json` and Codex's `~/.codex/config.toml`, and in Kimi Code's, Grok Build's and grok-cli's
122
- files where those harnesses are installed (only where it is missing; the old file is kept
121
+ Claude Code's `~/.claude.json` and Codex's `~/.codex/config.toml`, and in Kimi Code's, Grok Build's, grok-cli's,
122
+ Muse Code's and ZCode's files where those harnesses are installed (only where it is missing; the old file is kept
123
123
  as `<file>.bak-<UTC time>`). The `lane-mcp` row of the table then says whether that changed either file.
124
124
  3. **Agent hooks.** Runs `lanes hooks install --write`, first for Claude and then for Codex. Your own hooks and
125
125
  keys are kept, with a backup of each changed file. A Lanes hook group that is already installed stays where
126
- it is, even when Throttle's setup has added its own group around it. Then for Kimi Code, Grok Build and grok-cli
127
- (`hooks-kimi`, `hooks-grok`, `hooks-grok-cli`), each only when its home (`~/.kimi-code`, `~/.grok-build`, `~/.grok`)
128
- is in the container, else `skipped`. Two steps run only when you name them: `--step kimi-notify` (Kimi Code's
126
+ it is, even when Throttle's setup has added its own group around it. Then for Kimi Code, Grok Build, grok-cli, Muse Code
127
+ and ZCode (`hooks-kimi`, `hooks-grok`, `hooks-grok-cli`, `hooks-muse`, `hooks-zcode`), each only when its home
128
+ (`~/.kimi-code`, `~/.grok-build`, `~/.grok`, `~/.config/muse`, `~/.zcode`) is in the container, else `skipped`
129
+ (Lanes installs neither Muse Code nor ZCode). Two steps run only when you name them: `--step kimi-notify` (Kimi Code's
129
130
  `tui.toml` `notification_condition = "always"`) and `--step grok-build` (Grok Build installed into
130
131
  `~/.grok-build` from its stable channel, before step 2, so its MCP entry and hooks land in the same run; the
131
132
  channel publishes no checksum, so the receipt's `warn` row records the download's size and sha256 as
@@ -263,7 +264,10 @@ cd bw-tools/lanes
263
264
  ```
264
265
 
265
266
  OpenSSH is required. Install Ghostty for a dedicated window, or run `lanes-launch` in your existing terminal.
266
- Linux also supports Foot, plus optional Omarchy/Hyprland shortcuts. Tailscale is required when your profile uses
267
+ Linux also supports Foot, plus optional Omarchy/Hyprland shortcuts. The dedicated Ghostty window defaults to
268
+ Catppuccin Latte in light mode and Dracula in dark mode. On Omarchy, its launcher preserves everyday fonts, padding
269
+ and shortcuts while excluding inherited theme colors so this pair takes effect; the everyday Ghostty config is left
270
+ untouched. Tailscale is required when your profile uses
267
271
  a tailnet address. When the profile's `LANES_SERVER_NAME` ends in `.ts.net`, the installer checks Tailscale before
268
272
  the server: without it, it prints `tailscale: not installed — macOS: brew install --cask tailscale · Linux:
269
273
  https://tailscale.com/download` and exits 4 (the client is installed); on a logged-out machine it prints
@@ -378,7 +378,16 @@ lanes studio-host re-key --yes after the owner revoked the Host: a new mac
378
378
  stderr. Writes are atomic and only on a change; the file stays 0600 and `~/.ssh` 0700. A non-default sshd
379
379
  `AuthorizedKeysFile` does not read this block.
380
380
 
381
- - **A view looks wrong / stuck:** `lanes rebuild mac`. Views are disposable; agents are untouched; the client reconnects.
381
+ - **A desktop stops accepting keys while SSH stays connected:** reconnect that window's display first (close and
382
+ reopen the Lanes window, or terminate only its verified SSH display child so `lanes-launch` retries). Do not
383
+ restart holders or containers. `lanes attach` now supervises its Zellij client with `libexec/attach.py`: output
384
+ waiting to reach the terminal is limited to 1 MiB and an oldest pending chunk age of 5 s. Either bound ends only
385
+ that client (TERM, then KILL after 1 s if needed), exits 1, and lets `lanes-launch` reconnect to the existing view.
386
+ Idle terminals have no deadline; input, resizing and normal exit codes pass through. A client that cannot drain
387
+ its terminal cannot be rescued by SSH keepalives alone (DEF-1965). This guard covers desktop SSH attachments;
388
+ Zellij's browser transport does not use it. Already attached desktops pick it up on their next attachment.
389
+ - **A view's layout looks wrong:** `lanes rebuild mac`. Views are disposable; agents are untouched; the client
390
+ reconnects. Rebuilding also ends that view's Host tab shell, so prefer a display reconnect for a frozen client.
382
391
  - **A lane was added/renamed/removed in a repo's `.vscode/terminals.json`:** nothing to do. `lanes-sync.timer`
383
392
  re-reads registries every 2 minutes and the sidebar follows. The zellij layout is never edited live. A sync that
384
393
  finds nothing new leaves `registry.json` (and its `generated_at`) untouched and only records the time in
@@ -997,8 +1006,9 @@ whose agent is alive but silent keeps the last word for up to an hour.
997
1006
  ## Harnesses
998
1007
 
999
1008
  Since 1.5.0 (W12, spec `docs/superpowers/specs/2026-10-15-lanes-harness-observers-design.md`) Lanes reads Kimi Code,
1000
- Grok Build and grok-cli lanes as well as Claude Code and Codex ones; what each status means for the person at the
1001
- board is the user guide's [Harnesses](USERGUIDE.md#harnesses). This section is the operator's: what to install per
1009
+ Grok Build and grok-cli lanes as well as Claude Code and Codex ones, and since 1.6.0 (W13, spec
1010
+ `docs/superpowers/specs/2026-10-16-lanes-harness-observers-muse-zcode-design.md`) Muse Code and ZCode lanes; what each
1011
+ status means for the person at the board is the user guide's [Harnesses](USERGUIDE.md#harnesses). This section is the operator's: what to install per
1002
1012
  container, how statusd decides, and how to check each harness. Claude Code's and Codex's hooks are in "Installing
1003
1013
  agent hooks" above.
1004
1014
 
@@ -1010,19 +1020,22 @@ changes, a symbolic link below the container home refuses the file, and in a TOM
1010
1020
 
1011
1021
  1. `lanes install-container <name>` — ships 1.5.0's contract: `lane-signal` (its harness, when no `--harness` or
1012
1022
  `LANE_HARNESS` names one, read from the parent processes, never assumed `codex`), `lane-mcp` and its editors, and
1013
- the hook definitions in `~/.lz/hooks/` (`kimi-hooks.toml`, `grok-hooks.json`, `grok-cli-hooks.json`). Unless
1023
+ the hook definitions in `~/.lz/hooks/` (`kimi-hooks.toml`, `grok-hooks.json`, `grok-cli-hooks.json`, and since 1.6.0
1024
+ `muse-hooks.json`, `zcode-hooks.json`). Unless
1014
1025
  `--no-mcp`, it also runs `~/.lz/bin/lane mcp install`, which adds the Lanes MCP server for each harness installed
1015
1026
  there, beside Claude's and Codex's entries (each subsection below names its file).
1016
1027
  2. The hooks of each harness the container has, each with its dry run first: `lanes hooks install --agent kimi
1017
1028
  --container <name>` ([Kimi Code](#kimi-code)), `--agent grok` ([Grok Build](#grok-build), after Grok Build is
1018
- installed) and `--agent grok-cli` ([grok-cli](#grok-cli)).
1029
+ installed), `--agent grok-cli` ([grok-cli](#grok-cli)), `--agent muse` ([Muse Code](#muse-code)) and `--agent
1030
+ zcode` ([ZCode](#zcode)).
1019
1031
  3. Optional, the operator's call per container: `lanes onboard <login> --container <name> --step kimi-notify --write`
1020
1032
  (Kimi Code's bell) and `--step grok-build --write` (installs Grok Build).
1021
1033
  4. New agent sessions read the hooks and the MCP entry; a running session keeps what it started with (inferred from
1022
1034
  how the harnesses read their configuration at start, not measured).
1023
1035
 
1024
1036
  `lanes onboard` runs step 2 by itself for each harness whose home is in the container (`hooks-kimi`, `hooks-grok`,
1025
- `hooks-grok-cli`; `skipped` otherwise); `kimi-notify` and `grok-build` run only when named with `--step`
1037
+ `hooks-grok-cli`, `hooks-muse` for `~/.config/muse`, `hooks-zcode` for `~/.zcode`; `skipped` otherwise — Lanes installs
1038
+ neither Muse Code nor ZCode); `kimi-notify` and `grok-build` run only when named with `--step`
1026
1039
  (`grok-build` right after the board, before the contract, so the same run writes Grok Build's MCP entry and hooks).
1027
1040
 
1028
1041
  What each event writes (`agent{}` vocabulary):
@@ -1039,22 +1052,35 @@ What each event writes (`agent{}` vocabulary):
1039
1052
  | Grok Build | `StopFailure` / `SessionStart` / `SessionEnd` | `errored` / `idle` / `shell` |
1040
1053
  | grok-cli | `UserPromptSubmit`, `PreToolUse`, `PostToolUse` | `working` |
1041
1054
  | grok-cli | `Stop` / `StopFailure` / `SessionEnd` | `needs_input` / `errored` / `shell` |
1055
+ | Muse Code | `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `PostToolUseFailure` | `working` |
1056
+ | Muse Code | `PermissionRequest`, `Notification` | `needs_approval` |
1057
+ | Muse Code | `Stop`, `Interrupt` (async) | `needs_input` |
1058
+ | Muse Code | `StopFailure` / `SessionStart` / `SessionEnd` | `errored` / `idle` / `shell` |
1059
+ | ZCode | `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `PostToolUseFailure` | `working` (`needs_input` when the hook says `is_interrupt`) |
1060
+ | ZCode | `PermissionRequest` | `needs_approval` |
1061
+ | ZCode | `Stop` / `SessionStart` | `needs_input` / `idle` |
1042
1062
 
1043
1063
  Verified event names (2026-10-15, this host): Kimi Code 2.1.1's `HOOK_EVENT_TYPES` and its strict `[[hooks]]` schema
1044
1064
  (`event`, `matcher?`, `command`, `timeout?` 1–600) in its binary; grok-cli 1.1.7's hook events, its exact-string
1045
1065
  matcher, `sh -c` with its own environment, and its MCP server entry (`{id, label, enabled, transport, command, args,
1046
1066
  env}`, client name `grok-cli-<id>`) in the source its binary carries; Grok Build 1.0.52's events from its source and
1047
1067
  user guide (`docs/superpowers/specs/evidence/2026-10-15-grok-build-measurement.md` §3). Not yet proven on a live,
1048
- logged-in session: that each harness fires these hooks in a lane as the source says.
1068
+ logged-in session: that each harness fires these hooks in a lane as the source says. Muse Code 1.4.10 (2026-10-16, a
1069
+ scratch HOME with the offline `--provider echo`, never a credential): its hook shape, `schema_version` 1, the
1070
+ `async` Interrupt and the cleared hook environment MEASURED; SessionStart fires right before the first prompt, not at
1071
+ launch (MEASURED); `PermissionRequest`, `Notification`, `StopFailure` and `Interrupt` firing NOT measured (the echo
1072
+ provider asks for no permission and cannot fail or be interrupted in time). ZCode's events are its README's; ZCode was
1073
+ not run (needs_operator_capture, DEF-2060).
1049
1074
 
1050
1075
  ### The observed harness
1051
1076
 
1052
1077
  Which harness runs in a lane needs nothing installed: statusd OBSERVES it instead of guessing it from the pane title.
1053
1078
  It walks the pane's process tree in the container's `/proc` (`/proc/<pid>/task/*/children` and the `comm` of each
1054
1079
  process, breadth first from the pane's root, at most four levels and 64 processes, no spawn) and publishes
1055
- `agent.harness` as `claude`, `codex`, `kimi`, `grok` (Grok Build), `grok-cli`, `shell` or `unknown`. The first process
1056
- whose `comm` is `claude`, `codex`, `kimi`/`kimi-code` or `grok`, or whose executable holds `/claude/versions/`, names
1057
- it: native Claude Code before 2.1.299 runs with its version as `comm` (`2.1.295`), so its executable names it
1080
+ `agent.harness` as `claude`, `codex`, `kimi`, `grok` (Grok Build), `grok-cli`, `muse` (Muse Code), `zcode` (ZCode),
1081
+ `shell` or `unknown`. The first process whose `comm` is `claude`, `codex`, `kimi`/`kimi-code`, `grok`, `muse` (Muse's
1082
+ launcher script) or `zcode-cli` (ZCode's process title), or starts with `muse-bin-` (MEASURED: `muse-bin-1.4.10`), or
1083
+ whose executable holds `/claude/versions/` or is a file named `muse-bin-…`, names it: native Claude Code before 2.1.299 runs with its version as `comm` (`2.1.295`), so its executable names it
1058
1084
  (DEF-1993; the same rule as `lane-signal`'s and `lane_core`'s). A `grok` is Grok Build when its executable is
1059
1085
  `…/downloads/grok-linux-<arch>` (`readlink /proc/<pid>/exe`), any other is grok-cli; one whose executable cannot be read
1060
1086
  is `unknown`. Only shells is `shell`; anything else, a cut tree or an unreadable read is `unknown`. The answer is kept
@@ -1068,15 +1094,18 @@ found exited or now runs under another `comm`; `shell` and `unknown` are never k
1068
1094
  | Kimi Code | `kimi-code` (or `kimi`) | `~/.kimi-code/sessions/…/state.json` + `agents/main/wire.jsonl` | `kimi-session-file` |
1069
1095
  | Grok Build | `grok`, exe `$GROK_HOME/downloads/grok-linux-<arch>` | `$GROK_HOME/active_sessions.json` + the session's `events.jsonl` and `summary.json`, else its pane title | `grok-session-file`, `grok-title` |
1070
1096
  | grok-cli | `grok`, any other exe | nothing: no title, no bell, no pid in its database | — (hooks only) |
1097
+ | Muse Code | `muse-bin-<version>` (exe `~/.local/bin/muse-bin-<version>`) | the session log whose `.session.lock` it holds open (else the runtime registry), else its pane title | `muse-session-file`, `muse-title` |
1098
+ | ZCode | `zcode-cli` (a Node process titled so) | nothing: sessions in SQLite, no title, no bell | — (hooks, else `process`) |
1071
1099
  | any of them, nothing else claiming | — | the process itself: `idle`, `done` with the bell | `process` |
1072
1100
 
1073
- The order statusd takes them in: a hook sidecar > a Claude session file > a Kimi session file > the Grok Build
1074
- observer (its session file, else its title) > the Grok Build title on a pane observed as `grok` > the Codex title (only
1075
- where Codex can be) > the observed harness itself; the window bell turns an idle or finished turn into `done`. When
1101
+ The order statusd takes them in: a hook sidecar > a Claude session file > a Kimi session file > a Muse session file >
1102
+ the Grok Build observer (its session file, else its title) > the Grok Build title on a pane observed as `grok` > the
1103
+ Muse title on a pane observed as `muse` > the Codex title (only where Codex can be) > the observed harness itself; the
1104
+ window bell turns an idle or finished turn into `done`, except for Muse Code and ZCode, which ring none. When
1076
1105
  the walk names a harness, that is the published `harness` whatever signal decided the status. Check it:
1077
1106
 
1078
1107
  ```sh
1079
- lanes doctor | grep ' lanes: ' # lanes: claude 50 · codex 20 · kimi 3 · grok 0 · grok-cli 0 · shell 0
1108
+ lanes doctor | grep ' lanes: ' # lanes: claude 50 · codex 20 · kimi 3 · grok 0 · grok-cli 0 · muse 1 · zcode 0 · shell 0
1080
1109
  jq '[.lanes[].agent.harness // empty] | group_by(.) | map({(.[0]): length}) | add' ~/.local/state/lanes/status.json
1081
1110
  ```
1082
1111
 
@@ -1092,7 +1121,8 @@ python3 -c 'import json,sys; a=json.load(open(sys.argv[1]))["lanes"][sys.argv[2]
1092
1121
  process), `cat $P/<pid>/task/*/children` lists its children, `cat $P/<child>/comm` names each and `readlink
1093
1122
  $P/<child>/exe` its file. A harness more than four levels below the pane is `unknown`; so is a pane whose tree holds
1094
1123
  anything but shells and no harness. Before 1.5.0 a Kimi lane read `codex / idle`: the title rule took any title of two
1095
- or more words for Codex's (DEF-1970).
1124
+ or more words for Codex's (DEF-1970); before 1.6.0 a busy Muse Code lane read `codex / working`: the walk did not know
1125
+ Muse, and the Codex rule reads a braille spinner on an `unknown` pane (DEF-2030).
1096
1126
 
1097
1127
  ### Kimi Code
1098
1128
 
@@ -1202,6 +1232,76 @@ TERM and USER, so `lane-mcp` reads `LANE_ID`, `LANE_WS`, `TMUX` and `TMUX_PANE`
1202
1232
  `/proc/<pid>/environ`, and only when that parent process is a harness (DEF-1992). grok-cli sends no custom headers: its
1203
1233
  requests carry no trace.
1204
1234
 
1235
+ ### Muse Code
1236
+
1237
+ **Observed** (`libexec/harness_muse.py`, ARCHITECTURE "Muse Code and ZCode"). Muse Code 1.4.10 (Meta) runs as one
1238
+ process, `~/.local/bin/muse-bin-<version>`, exec'd by the launcher script `~/.local/bin/muse`. statusd joins the pane's
1239
+ Muse pid to its session through `/proc/<pid>/fd`: the live process holds `…/muse/sessions/YYYY/MM/DD/<id>/.session.lock`
1240
+ open, and the lock file says `pid=<pid>` (both MEASURED); else Muse's runtime registry,
1241
+ `~/.local/share/muse/runtime/muse/sessions/<id>.json`, whose `process_generation_hint` is `pid=<pid>` (deleted when Muse
1242
+ exits). It reads the last 64 KiB of that session's `session.jsonl` (whole lines only): an accepted prompt or a running
1243
+ turn is `working`; the turn's `terminal` completed or cancelled is `needs_input`, failed `errored`; `session.end`, or no
1244
+ write for an hour, makes no claim. The session's name (`session.name.changed`, near the log's start: read from its first 32 KiB when the tail holds none) is the task line. The `run started`
1245
+ record and the accepted-prompt record carry the person's prompt: the observer reads only their kinds and times, never
1246
+ their text. Without a usable log the title decides: `⠙ <workspace folder>` working, `<workspace folder>` idle. Muse
1247
+ rings no bell: a Muse lane is never `done` by the bell.
1248
+
1249
+ To confirm a Muse lane is joined, in its container: `ls -l /proc/<muse pid>/fd | grep session.lock` names the session
1250
+ directory; `tail -c 2000 <that directory>/session.jsonl` ends with the turn's last record. Do not paste that file
1251
+ anywhere: its `run started` and `runtime.user_intent.accepted` records hold the prompt (customer content).
1252
+
1253
+ **Hooks** (installed when the container has `~/.config/muse/`): `lanes hooks install --agent muse --container <name>`,
1254
+ then `--write`, merges the lane-signal groups into the `hooks` of `~/.config/muse/settings.json` (Claude Code's shape:
1255
+ `{Event: [{hooks: [{type: "command", command, timeout}]}]}`, timeout in seconds). A new file is created with
1256
+ `"schema_version": 1`; an existing file without it is refused (Muse refuses it too). Never registered:
1257
+ `PreLLMCall`/`PostLLMCall`, `SubagentStart`/`SubagentStop`, `PostToolBatch` (they carry model content and fire per
1258
+ call). `Interrupt` runs with `"async": true`, which Muse requires. **Muse clears a hook's environment** to HOME, PATH,
1259
+ TERM, LANG, LC_ALL, USER, LOGNAME, SHELL, TMPDIR, MUSE_SESSION_ID and MUSE_THREAD_ID (MEASURED): LANE_ID, LANE_WS, TMUX
1260
+ and TMUX_PANE do not arrive, so `lane-signal` reads them from the Muse process's own `/proc/<pid>/environ` (bounded,
1261
+ never through a link, and only when that pid is a known harness; DEF-2031). Muse does not run Claude Code's hooks or
1262
+ MCP servers.
1263
+
1264
+ **MCP and trace.** `lane mcp install` writes `mcp_servers.lanes` into `~/.config/muse/settings.json`: `{"transport":
1265
+ "stdio", "command": "/home/coder/.lz/bin/lane-mcp", "args": [], "env": {"LANE_ID": "${LANE_ID:-}", "LANE_WS":
1266
+ "${LANE_WS:-}", "TMUX": "${TMUX:-}", "TMUX_PANE": "${TMUX_PANE:-}"}, "mode": "optional"}`. Muse starts a stdio server
1267
+ with a cleared environment plus the entry's `env`, and fills `${NAME:-}` from its own environment (MEASURED: the lane id
1268
+ arrived; an unset name arrived empty); `mode` `optional` keeps a failing `lane-mcp` from stopping the session (the
1269
+ default `required` would). Its MCP client name is `tbh` (MEASURED), which lane-mcp reads as `muse`. Every canonical
1270
+ recipe sets `MUSE_CUSTOM_HEADERS='x-throttle-trace: lanes/<ws>/<id>'`: MEASURED on 1.4.10 (the header arrived on Muse's
1271
+ `GET …/models`), but Meta does not document the variable, so a later Muse may drop it silently (DEF-2059): after a Muse
1272
+ update, check that the Throttle `muse-code` pool still sees `x-throttle-trace` from a lane.
1273
+
1274
+ **Measurement hazard.** Muse 1.4.10 writes `~/.local/share/muse/session-name-authority/` under the account's home from
1275
+ the password database even when `HOME` points elsewhere (MEASURED 2026-10-16 in a scratch-HOME run: it created
1276
+ `authority.json` and `session-names.db` in the real home). Anyone measuring Muse in a scratch HOME must remove that
1277
+ directory afterwards.
1278
+
1279
+ **Not captured yet (needs_operator_capture, DEF-2057):** the session-log records of a turn that waits for an approval
1280
+ and of a failed turn. The observer reads a failed `terminal` as `errored` and an approval only from a record kind that
1281
+ names one; until a logged-in capture exists, the hooks are the approval signal.
1282
+
1283
+ ### ZCode
1284
+
1285
+ ZCode CLI (Z.ai, `zai-org/ZCode` apps/zcode-cli 0.16.9; read in its source and README, not run here) is a Node program
1286
+ that sets its process title to `zcode-cli` (its `comm`). It keeps its sessions in SQLite (`~/.zcode/cli/db/db.sqlite`)
1287
+ and draws no title and no bell, so Lanes observes only its process: a ZCode lane without hooks is `zcode` / `idle`
1288
+ (`source: process`).
1289
+
1290
+ **Hooks** (installed when the container has `~/.zcode/`): `lanes hooks install --agent zcode --container <name>`, then
1291
+ `--write`. ZCode's hooks are off by default; the install sets `hooks.enabled` to true in `~/.zcode/cli/config.json` and
1292
+ merges `process` hooks into `hooks.events` (`{type: "process", command: "/home/coder/.lz/bin/lane-signal", args:
1293
+ ["working", "--event", "PreToolUse", "--harness", "zcode"], timeoutMs: 2000}`; ZCode runs argv without a shell, so the
1294
+ path is absolute). A file whose `hooks.enabled` is explicitly false refuses: someone turned hooks off, and Lanes does not
1295
+ turn them on behind them. ZCode runs no `Stop` after an interrupt: an interrupted tool's `PostToolUseFailure` carries
1296
+ `is_interrupt: true`, which lane-signal records as `needs_input`; an interrupt while the model streams is not seen
1297
+ (DEF-2091). Hooks inherit ZCode's environment plus `ZCODE_SESSION_ID`, so the lane identity arrives directly.
1298
+
1299
+ **MCP, no trace.** `lane mcp install` writes `mcp.servers.lanes` = `{"type": "stdio", "command":
1300
+ "/home/coder/.lz/bin/lane-mcp"}`; ZCode's stdio servers inherit its environment. A file with `features.mcp` false is
1301
+ left alone. ZCode's client name is read as `zcode` when it starts with `zcode` (INFERRED from its source, DEF-2060).
1302
+ ZCode sends only the fixed `api.headers` of its configuration: there is no per-process header, so its requests carry
1303
+ no lanes trace.
1304
+
1205
1305
  ### Throttle-side notes
1206
1306
 
1207
1307
  A trace only matters for a harness attached to a Throttle pool; a running lane gets the recipe's trace variables when
@@ -1211,7 +1311,10 @@ it is next created.
1211
1311
  and `/pools/kimi/status` when tokened), but an update only ships the new `throttle-pulse` file: `lanes
1212
1312
  install-container` starts nothing while the `pulse` session runs, so the 1.4.0 loop keeps running and the sidebar's
1213
1313
  `◆ moonshot` row says `no data` (`lanes doctor`: `kimi ?`) until it is restarted (DEF-2003): `docker exec -u 1000
1214
- <container> tmux -L lanes-pulse kill-session -t pulse`, then `lanes install-container <container>`.
1314
+ <container> tmux -L lanes-pulse kill-session -t pulse`, then `lanes install-container <container>`. The same holds for
1315
+ 1.6.0's `muse-code` and `zai` pools (the `◆ meta` and `◆ z.ai` rows; `lanes doctor`: `muse-code ? · zai ?`). A daemon
1316
+ from before Throttle's native `muse-code` and `zai` pools answers 404 on their routes: those rows then say `no data`
1317
+ too, which is no fault of Lanes.
1215
1318
 
1216
1319
  **Throttle-side items (the Throttle provider lane's; filed, not built in Lanes):**
1217
1320
 
@@ -1229,6 +1332,12 @@ install-container` starts nothing while the `pulse` session runs, so the 1.4.0 l
1229
1332
  Attaching it is a Throttle step (`throttle accounts add <name> --provider kimi --pool kimi`, then `throttle setup
1230
1333
  --install-clients`; the [`throttle-kimi-provider`](../../skills/throttle-kimi-provider/SKILL.md) skill), outside
1231
1334
  Lanes.
1335
+ - **Muse Code and ZCode attachment (Throttle side, not Lanes):** Throttle has no managed Muse CLI attachment, so a Muse
1336
+ lane's requests reach Throttle's `muse-code` pool only if the operator points Muse at it; Claude Code reaches either
1337
+ pool through `throttle sessions start --claude --pool muse-code|zai`. ZCode is attached by `throttle setup
1338
+ --install-clients` after the first Z.ai account (the managed `throttle-zai` rule in `~/.zcode/v2/provider_config.json`).
1339
+ See the [`throttle-muse-code-provider`](../../skills/throttle-muse-code-provider/SKILL.md) and
1340
+ [`throttle-zai-provider`](../../skills/throttle-zai-provider/SKILL.md) skills.
1232
1341
 
1233
1342
  ## The agents' MCP entries (`lane-mcp`, on by default)
1234
1343
 
@@ -1656,8 +1656,8 @@ Names must be non-empty and free of control characters. The id, resolve file and
1656
1656
  each container running, the statusd heartbeat, all registry lanes observed and present (stale lanes counted as
1657
1657
  "shown with their last known state"), the process table, no host-side tmux servers, coexistence mode, Zellij
1658
1658
  reachable, phone picker panes current, and the host not under critical memory pressure.
1659
- - Information: the harness mix (1.5.0, [Harnesses](#harnesses)): `lanes: claude 50 · codex 20 · kimi 3 · grok 0 ·
1660
- grok-cli 0 · shell 0`, from each lane's `agent.harness` (`unknown` only when a lane has it; a lane with no agent is
1659
+ - Information: the harness mix (1.5.0; muse and zcode 1.6.0, [Harnesses](#harnesses)): `lanes: claude 50 · codex 20 · kimi
1660
+ 3 · grok 0 · grok-cli 0 · muse 1 · zcode 0 · shell 0`, from each lane's `agent.harness` (`unknown` only when a lane has it; a lane with no agent is
1661
1661
  not counted; `shell` stays 0 in practice: a lane whose harness ended into its shell is published under that
1662
1662
  harness's name with the status `shell`); lanes per create-recipe class (`idempotent`, `attach-only`, `null`, `external`, `retired-path`), how many
1663
1663
  create with their identity, where the `lane` contract is installed, zmx-held lanes, the preview renderer, the live
@@ -1723,12 +1723,14 @@ anything, picks the first signal that applies:
1723
1723
  turn keep it, unless the report was `working`.
1724
1724
  2. A **Claude Code session file** `~/.claude/sessions/<pid>.json` naming the pane, for a live pid (recycled pids are
1725
1725
  rejected).
1726
- 3. **Kimi Code's session files**, then **Grok Build's** (which session the pane's `grok` runs, its event log, else its
1727
- pane title), for a pane whose process is that harness ([Harnesses](#harnesses)).
1726
+ 3. **Kimi Code's session files**, then **Muse Code's** (the session log of the Muse process the pane runs), then
1727
+ **Grok Build's** (which session the pane's `grok` runs, its event log, else its pane title), then **Muse Code's
1728
+ pane title**, for a pane whose process is that harness ([Harnesses](#harnesses)).
1728
1729
  4. The **Codex pane title**, only where Codex can run: `[ ! ] Action Required` is needs approval, a braille spinner is
1729
1730
  working, a task title is idle.
1730
1731
  5. The **harness process itself**: nothing above claimed the pane, so it is the harness the pane runs, idle.
1731
- 6. The **window bell**, throughout: an idle lane or a finished turn plus a bell is done.
1732
+ 6. The **window bell**, throughout: an idle lane or a finished turn plus a bell is done. Muse Code and ZCode ring no
1733
+ bell, so a bell never makes their lane done.
1732
1734
 
1733
1735
  A Codex title left on a bare shell with no child process, or a Grok Build title over a pane that runs only shells, is
1734
1736
  `shell` (the harness ended). Since 1.5.0 the harness itself is observed, not guessed: see [Harnesses](#harnesses).
@@ -1747,14 +1749,17 @@ A Codex approval read from its pane title (a lane without hooks) keeps the same
1747
1749
  ### Harnesses
1748
1750
 
1749
1751
  Lanes 1.5.0 (W12, [spec](../../docs/superpowers/specs/2026-10-15-lanes-harness-observers-design.md)) reads five agent
1750
- harnesses: Claude Code, Codex, Kimi Code, Grok Build (xAI's official `grok`) and grok-cli (the community `grok`).
1752
+ harnesses: Claude Code, Codex, Kimi Code, Grok Build (xAI's official `grok`) and grok-cli (the community `grok`);
1753
+ Lanes 1.6.0 (W13, [spec](../../docs/superpowers/specs/2026-10-16-lanes-harness-observers-muse-zcode-design.md)) adds
1754
+ Muse Code (Meta's `muse`) and ZCode (Z.ai's `zcode`).
1751
1755
  Which one runs in a lane is an **observed fact**: statusd walks the pane's process tree (plain `/proc` reads, no new
1752
- process) and publishes `agent.harness` as `claude`, `codex`, `kimi` (Kimi Code), `grok` (Grok Build), `grok-cli` or
1753
- `unknown`; a pane that runs only shells is `shell` to the walk and shows no agent of its own (or the harness that ended
1754
- there, with the status shell). A pane title that looks like Codex's is read as Codex only where Codex runs: before 1.5.0 any
1755
- title of two or more words read as an idle Codex, so a Kimi lane showed `codex / idle`. `lanes doctor` prints the mix:
1756
- `lanes: claude 50 · codex 20 · kimi 3 · grok 0 · grok-cli 0 · shell 0`. Each harness gets the lane-signal hooks, the
1757
- Lanes MCP server and the Throttle trace its own files allow:
1756
+ process) and publishes `agent.harness` as `claude`, `codex`, `kimi` (Kimi Code), `grok` (Grok Build), `grok-cli`,
1757
+ `muse` (Muse Code), `zcode` (ZCode) or `unknown`; a pane that runs only shells is `shell` to the walk and shows no agent
1758
+ of its own (or the harness that ended there, with the status shell). A pane title that looks like Codex's is read as
1759
+ Codex only where Codex runs: before 1.5.0 any title of two or more words read as an idle Codex, so a Kimi lane showed
1760
+ `codex / idle`, and before 1.6.0 a busy Muse Code lane (its spinner title `⠙ <folder>`) showed `codex / working`.
1761
+ `lanes doctor` prints the mix: `lanes: claude 50 · codex 20 · kimi 3 · grok 0 · grok-cli 0 · muse 1 · zcode 0 · shell
1762
+ 0`. Each harness gets the lane-signal hooks, the Lanes MCP server and the Throttle trace its own files allow:
1758
1763
 
1759
1764
  | Harness | What Lanes reads with no hooks (observed) | Hooks (`lanes hooks install --agent …`, a dry run until `--write`) | MCP server |
1760
1765
  | --- | --- | --- | --- |
@@ -1763,6 +1768,8 @@ Lanes MCP server and the Throttle trace its own files allow:
1763
1768
  | Kimi Code 2.1.1 | its session files: `~/.kimi-code/sessions/wd_*/session_<uuid>/state.json` and the last 64 KiB of `agents/main/wire.jsonl` | `--agent kimi`: a `# >>> lanes hooks >>>` block of `[[hooks]]` in `~/.kimi-code/config.toml` | `~/.kimi-code/mcp.json` |
1764
1769
  | Grok Build 1.0.52 | `$GROK_HOME/active_sessions.json` (which pid runs which session), the session's `events.jsonl` and `summary.json` (its title), the pane title | `--agent grok`: `~/.grok-build/hooks/lanes.json` plus blocks in `~/.grok-build/config.toml` | a `# >>> lanes mcp >>>` block in `~/.grok-build/config.toml` |
1765
1770
  | grok-cli 1.1.7 | nothing: it sets no title and rings no bell | `--agent grok-cli`: `hooks` in `~/.grok/user-settings.json` | the `mcp.servers` item `lanes` in `~/.grok/user-settings.json` |
1771
+ | Muse Code 1.4.10 | its session log `~/.local/share/muse/sessions/YYYY/MM/DD/<id>/session.jsonl` (the last 64 KiB; the session is the one whose `.session.lock` the lane's Muse process holds open), the pane title | `--agent muse`: `hooks` in `~/.config/muse/settings.json` | `mcp_servers.lanes` in `~/.config/muse/settings.json` |
1772
+ | ZCode (zcode-cli 0.16.9) | only its process: it keeps its sessions in a database and sets no title or bell | `--agent zcode`: `hooks.events` (and `hooks.enabled`) in `~/.zcode/cli/config.json` | `mcp.servers.lanes` in `~/.zcode/cli/config.json` |
1766
1773
 
1767
1774
  Per container, on the server (each a dry run that prints its diff until `--write`):
1768
1775
 
@@ -1770,9 +1777,11 @@ Per container, on the server (each a dry run that prints its diff until `--write
1770
1777
  lanes hooks install --agent kimi --container <name> --write # Kimi Code: ~/.kimi-code/config.toml
1771
1778
  lanes hooks install --agent grok --container <name> --write # Grok Build: ~/.grok-build/hooks/lanes.json, config.toml
1772
1779
  lanes hooks install --agent grok-cli --container <name> --write # grok-cli: ~/.grok/user-settings.json
1780
+ lanes hooks install --agent muse --container <name> --write # Muse Code: ~/.config/muse/settings.json
1781
+ lanes hooks install --agent zcode --container <name> --write # ZCode: ~/.zcode/cli/config.json
1773
1782
  ```
1774
1783
 
1775
- What the hooks of the three newer harnesses give the boards (Claude Code's and Codex's: "Hooks" below):
1784
+ What the hooks of the five newer harnesses give the boards (Claude Code's and Codex's: "Hooks" below):
1776
1785
 
1777
1786
  | Harness | Event | Status |
1778
1787
  | --- | --- | --- |
@@ -1788,6 +1797,15 @@ What the hooks of the three newer harnesses give the boards (Claude Code's and C
1788
1797
  | Grok Build | `SessionStart` / `SessionEnd` | idle / shell |
1789
1798
  | grok-cli | `UserPromptSubmit`, `PreToolUse`, `PostToolUse` | working |
1790
1799
  | grok-cli | `Stop` / `StopFailure` / `SessionEnd` | needs_input / errored / shell |
1800
+ | Muse Code | `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `PostToolUseFailure` | working |
1801
+ | Muse Code | `PermissionRequest`, `Notification` | needs_approval |
1802
+ | Muse Code | `Stop`, `Interrupt` | needs_input |
1803
+ | Muse Code | `StopFailure` | errored |
1804
+ | Muse Code | `SessionStart` / `SessionEnd` | idle / shell |
1805
+ | ZCode | `UserPromptSubmit`, `PreToolUse`, `PostToolUse` | working |
1806
+ | ZCode | `PostToolUseFailure` | working; needs_input when the person interrupted the tool |
1807
+ | ZCode | `PermissionRequest` | needs_approval |
1808
+ | ZCode | `Stop` / `SessionStart` | needs_input / idle |
1791
1809
 
1792
1810
  **Kimi Code** comes from its own installer (`~/.kimi-code`). Without hooks, a Kimi session is joined to its lane by
1793
1811
  working folder: the lane's Kimi process whose folder is the session's `cwd`, newest `updatedAt` first. Two Kimi lanes
@@ -1824,22 +1842,51 @@ there.
1824
1842
  **grok-cli** comes from its own installer (`~/.grok`) and has hooks only, with exact-string matchers. It has no
1825
1843
  approval signal and no title or bell: its lane shows working, needs input, errored or shell, never needs approval.
1826
1844
 
1845
+ **Muse Code** comes from Meta's installer (`~/.local/bin/muse`, which runs `muse-bin-<version>`; its settings in
1846
+ `~/.config/muse`). Without hooks, statusd joins the lane's Muse process to its session through the session's
1847
+ `.session.lock`, which the live process holds open (else Muse's runtime registry), and reads the end of
1848
+ `session.jsonl`: an accepted prompt or a running turn is working; a completed or cancelled turn is needs input; a
1849
+ failed turn is errored; a session that ended (`session.end`) or that wrote nothing for an hour says nothing. The
1850
+ session's name (two words such as `velvet-pollux`, or the one you gave it) is the lane's task line; Lanes never reads
1851
+ or publishes your prompt. Without a readable log, the title decides: `⠙ <folder>` is working, `<folder>` idle. Muse
1852
+ rings no bell. Muse runs its hooks with a cleared environment (no `LANE_ID`, no `TMUX`), so `lane-signal` finds the lane
1853
+ in the environment of the Muse process itself. The hooks install requires (and creates in a new file)
1854
+ `"schema_version": 1`; it never registers the per-model-call, subagent or tool-batch events, and `Interrupt` runs
1855
+ `async` as Muse requires. An approval in Muse's own log was not captured yet: until it is, the hooks
1856
+ (`PermissionRequest`, `Notification`) are what shows needs approval.
1857
+
1858
+ **ZCode** comes from Z.ai's installer (`~/.zcode`). Lanes reads nothing of its own files: it keeps sessions in a
1859
+ database and draws no title or bell, so a ZCode lane without hooks shows `zcode / idle`. Its hooks are off by default:
1860
+ `lanes hooks install --agent zcode` sets `hooks.enabled` to true and adds `process` hooks (the absolute path of
1861
+ `lane-signal` and its arguments, a 2 s timeout); a file where someone set `hooks.enabled` to false is left alone. ZCode
1862
+ runs no `Stop` hook after you interrupt a turn: an interrupted tool reports needs input through `PostToolUseFailure`,
1863
+ and an interrupt while the model streams is not seen.
1864
+
1827
1865
  **Agent tools (MCP).** `~/.lz/bin/lane mcp install` (which `lanes install-container` runs, or `lane mcp install
1828
- --agent kimi|grok|grok-cli`) writes the Lanes server into each harness's file in the table above: Kimi Code's
1866
+ --agent kimi|grok|grok-cli|muse|zcode`) writes the Lanes server into each harness's file in the table above: Kimi Code's
1829
1867
  `~/.kimi-code/mcp.json` (the Claude `mcpServers` shape), Grok Build's `[mcp_servers.lanes]` as a marked block (its
1830
1868
  `[compat.claude] mcps = false` keeps `lane-mcp` from starting twice; Grok Build passes its session id to the server),
1831
1869
  and grok-cli's `mcp.servers`. grok-cli starts MCP servers with a stripped environment, so `lanes_whoami` reads the
1832
- lane's identity from the environment of the grok-cli process that started it.
1870
+ lane's identity from the environment of the grok-cli process that started it. Muse Code also clears a server's
1871
+ environment, so its entry passes `LANE_ID`, `LANE_WS`, `TMUX` and `TMUX_PANE` as `${NAME:-}` (Muse fills them from its
1872
+ own environment) and is `"mode": "optional"` (Muse's default `required` would stop the session if `lane-mcp` could not
1873
+ start); its file must already say `"schema_version": 1`. ZCode's servers inherit its environment; a file with
1874
+ `features.mcp` false is left alone.
1833
1875
 
1834
1876
  **The Throttle trace.** Kimi Code blanks `ANTHROPIC_CUSTOM_HEADERS`, so every recipe that sets it also sets
1835
1877
  `KIMI_CODE_CUSTOM_HEADERS='x-throttle-trace: lanes/<ws>/<id>'`. Grok Build's global extra headers would trace every
1836
1878
  lane alike, so recipes export `LANES_TRACE` and its hooks install writes `env_http_headers = {"x-throttle-trace" =
1837
1879
  "LANES_TRACE"}` for its built-in models `grok-4.6` and `grok-4.5`. grok-cli sends no custom headers: its requests carry
1838
- no trace. A trace only matters for a harness attached to a Throttle pool: Kimi Code when `throttle setup
1839
- --install-clients` attached it, Grok not at all (Throttle has no xAI pool).
1880
+ no trace. Muse Code sends the headers of `MUSE_CUSTOM_HEADERS` (measured on 1.4.10, not documented by Meta), so every
1881
+ recipe also sets `MUSE_CUSTOM_HEADERS='x-throttle-trace: lanes/<ws>/<id>'`. ZCode has only fixed headers in its
1882
+ configuration: its requests carry no trace. A trace only matters for a harness attached to a Throttle pool: Kimi Code
1883
+ when `throttle setup --install-clients` attached it, Muse Code and ZCode once attached to Throttle's `muse-code` and
1884
+ `zai` pools, Grok not at all (Throttle has no xAI pool).
1840
1885
 
1841
1886
  **Files Lanes changes.** Each is kept as `<file>.bak-<UTC>` first. In a TOML file Lanes changes only its marked block,
1842
- so to undo, delete the block. The diff a dry run prints shows a credential's value (grok-cli's `apiKey`) as `…`.
1887
+ so to undo, delete the block; in Muse Code's and ZCode's JSON files it changes only the one member it names (`hooks`,
1888
+ `mcp_servers.lanes`, `hooks.events`, `mcp.servers.lanes`), every other byte kept. The diff a dry run prints shows a
1889
+ credential's value (grok-cli's `apiKey`) as `…`.
1843
1890
  `lane-signal` without `--harness` takes the harness from `LANE_HARNESS`, else from the agent process above it, else
1844
1891
  records `unknown`.
1845
1892
 
@@ -1860,7 +1907,7 @@ lanes onboard anna --container ws-anna --workspace anna-tools --repo /home/coder
1860
1907
  | Board | A workspace tab for the repository (`lanes workspaces add`, section 6) on every device's view |
1861
1908
  | Contract | `lane`, `lane-run`, `lane-signal`, `lane-edit`, the quick-edit `vimrc`, `lane-mcp` and the hook definitions in the container's `~/.lz` (`lanes install-container`) |
1862
1909
  | Agent tools | The Lanes MCP server in Claude Code's and Codex's configuration, so an agent can see the lanes around it ("Agent tools (MCP)" below) |
1863
- | Hooks | The lane-signal hooks for Claude Code and Codex ("Hooks" below), and for Kimi Code, Grok Build and grok-cli where they are installed ([Harnesses](#harnesses)), so the sidebar's agent glyphs are event-driven |
1910
+ | Hooks | The lane-signal hooks for Claude Code and Codex ("Hooks" below), and for Kimi Code, Grok Build, grok-cli, Muse Code and ZCode where they are installed ([Harnesses](#harnesses)), so the sidebar's agent glyphs are event-driven |
1864
1911
  | Throttle | `throttle setup --install-clients` inside the container when Throttle is installed and configured there, so the agents' requests go through the pool; otherwise the one-time setup to run on a terminal is printed (a first setup signs in, which needs a person; Lanes runs without Throttle) |
1865
1912
  | Recipes | `lanes cursor-sync <id> --canonicalize --write` when the repository has a `.vscode/terminals.json`: each lane's create recipe gives it its identity and trace ("Lane identity" below) |
1866
1913
  | Sync and doctor | The registry knows the new lanes; `lanes doctor`'s result is reported, never fatal |
@@ -1888,8 +1935,8 @@ lanes hooks install --agent claude --container <name> --write # applies it (b
1888
1935
  lanes hooks install --agent codex --container <name> --write # ~/.codex/hooks.json (+ notify in config.toml)
1889
1936
  ```
1890
1937
 
1891
- `lanes hooks install --agent claude|codex|kimi|grok|grok-cli (--container <name> | --home <dir>) [--dry-run | --write]`
1892
- is a dry run unless `--write` (Kimi Code, Grok Build and grok-cli: [Harnesses](#harnesses)); your own hooks and
1938
+ `lanes hooks install --agent claude|codex|kimi|grok|grok-cli|muse|zcode (--container <name> | --home <dir>) [--dry-run | --write]`
1939
+ is a dry run unless `--write` (Kimi Code, Grok Build, grok-cli, Muse Code and ZCode: [Harnesses](#harnesses)); your own hooks and
1893
1940
  keys stay, and an earlier lane-signal install is replaced, not duplicated. An install that is already current is
1894
1941
  left where it is, even when another tool (Throttle's `setup --install-clients`) has put its own group before or
1895
1942
  after it or re-sorted the file's keys, so running it again writes nothing. For
@@ -1931,7 +1978,7 @@ verbs, so the holder stays swappable.
1931
1978
  | `lane kill <id> --yes [--force]` | End the lane (the only verb that ends an agent); refuses while the hook sidecar says `working` unless `--force` |
1932
1979
  | `lane new <id> [--ws W] [--title T] [--cwd DIR] [--icon I] [--color C] -- <command…>` | Create a zmx-held lane |
1933
1980
  | `lane gc --sockets` | Unlink this container's tmux socket files that tmux is refused on (no server listens); a live, empty or silent server keeps its file |
1934
- | `lane mcp install [--agent claude\|codex\|kimi\|grok\|grok-cli\|all] [--write]` | Add the Lanes MCP server to `~/.claude.json` and `~/.codex/config.toml`, and to Kimi Code's, Grok Build's and grok-cli's files where they are installed ("Agent tools (MCP)" below); a dry run until `--write` |
1981
+ | `lane mcp install [--agent claude\|codex\|kimi\|grok\|grok-cli\|muse\|zcode\|all] [--write]` | Add the Lanes MCP server to `~/.claude.json` and `~/.codex/config.toml`, and to Kimi Code's, Grok Build's, grok-cli's, Muse Code's and ZCode's files where they are installed ("Agent tools (MCP)" below); a dry run until `--write` |
1935
1982
  | `lane publish <file> [--title T] [--for <login>] [--kind md\|html\|svg\|file]` | Put a file of this container on the docs page from the lane it runs in ("Publish to the docs page" below); prints the request as JSON |
1936
1983
 
1937
1984
  Every tmux client these verbs start runs with `-N`, so none of them can start a tmux server: an attach to a lane
@@ -1974,7 +2021,7 @@ only read:
1974
2021
  | Tool | Answers |
1975
2022
  | --- | --- |
1976
2023
  | `lanes_whoami` | Which lane the agent runs in: id, board, name, kind (declared, registered or unregistered), tmux socket and session. It comes from `LANE_ID`, else from the agent's own tmux pane. Outside a lane the answer is `lane: null` with the reason |
1977
- | `lanes_list` | Every lane in this container with its state and its agent (harness, status, task). Filters: `workspace`, `needs_you: true` (needs approval, errored or needs input, the sidebar's "Needs you" section) and `agent` (`any`, `none`, `claude`, `codex`, `kimi`, `grok` for Grok Build, `grok-cli`). `status.fresh` is false once the host's observation is more than 60 s old |
2024
+ | `lanes_list` | Every lane in this container with its state and its agent (harness, status, task). Filters: `workspace`, `needs_you: true` (needs approval, errored or needs input, the sidebar's "Needs you" section) and `agent` (`any`, `none`, `claude`, `codex`, `kimi`, `grok` for Grok Build, `grok-cli`, `muse` for Muse Code, `zcode` for ZCode). `status.fresh` is false once the host's observation is more than 60 s old |
1978
2025
  | `lanes_status` | One lane in full: what the registry says, the observed state and agent, whether its tmux session is alive now (`null` when tmux does not answer in 5 s) and its hook sidecar |
1979
2026
  | `lanes_capture` | The last `lines` (1 to 500, default 100) non-blank lines of a lane's screen and scrollback, as plain text. Any lane of the container can be read |
1980
2027
 
@@ -2084,8 +2131,8 @@ zmx lane's agent state yet (DEF-1573). Gate results: [ZMX-RING0.md](ZMX-RING0.md
2084
2131
 
2085
2132
  The sidebar's free rows hold a pinned health block (Lanes 1.4.0, W11): on panes of 18 rows or more, once the server's
2086
2133
  statusd publishes the fleet facts, it sits above the upload strip and the lane list scrolls in the rows left. It is
2087
- live (statusd rewrites it at most every 10 s), local, and needs no collector. At 25 rows or more it is a rule and six
2088
- rows (1.5.0 added the Kimi pool's row; 1.4.0 drew five from 24 rows):
2134
+ live (statusd rewrites it at most every 10 s), local, and needs no collector. At 27 rows or more it is a rule and eight
2135
+ rows (1.6.0 added Throttle's Muse Code and Z.ai pools' rows; 1.5.0 the Kimi pool's; 1.4.0 drew five from 24 rows):
2089
2136
 
2090
2137
  ```
2091
2138
  ── fleet ──────────────────────────
@@ -2093,6 +2140,8 @@ rows (1.5.0 added the Kimi pool's row; 1.4.0 drew five from 24 rows):
2093
2140
  ◆ anthropic ▰▰▰▰▰▰▱▱▱▱ 12/19 · wk 61% · reset 2h
2094
2141
  ◆ openai ▰▰▰▱▱▱▱▱▱▱ 3/5 · 5h 28%
2095
2142
  ◆ moonshot ▰▰▰▰▰▰▱▪▪· 5/8 · wk 44% · 5h 12%
2143
+ ◆ meta ▰▰▰▰▰▰▰▱▪· 6/9 · wk 52% · 5h 31%
2144
+ ◆ z.ai ▰▰▰▰▰▰▰▪▪· 4/6 · wk 47% · 5h 22%
2096
2145
  ▣ productbox cpu 42% · mem 61% · load 37 · psi 3%
2097
2146
  ▣ bw-tools 15G · worlds 9G · sakio 4G
2098
2147
  ```
@@ -2100,11 +2149,11 @@ rows (1.5.0 added the Kimi pool's row; 1.4.0 drew five from 24 rows):
2100
2149
  | Row | What it shows |
2101
2150
  | --- | --- |
2102
2151
  | `⚙ throttle` | One line for the Throttle pool: with the opt-in token, overflow spend today against the daily cap, new 429s and the spill fraction — one pool's figure, never a sum: the Anthropic and OpenAI overflow budgets are separate money, so the row shows the pool nearest its cap, one at its alert level first (Kimi has no paid overflow, so its pool never gives the money); without the token ` ⚙ throttle up · spill 76% · 429 +4`, and ` down` in red when the daemon does not answer |
2103
- | `◆ anthropic`, `◆ openai`, `◆ moonshot` | One availability bar per provider pool — Claude, Codex and (1.5.0) Kimi Code's, whose vendor is Moonshot AI: ten cells of usable `▰`, cooling `▱`, benched `▪` and dead `·` accounts (ASCII `=` `~` `:` `.`), then the usable count of the configured ones (` ◆ anthropic ▰▰▰▰▰▰▱▪·· 12/19`), then — with the token — the worst weekly or 5-hour burn and the soonest reset. A daemon with no Kimi account shows ` ◆ moonshot ·········· 0/0`, which is no alarm; `no data` means the pulse did not report the pool (a pulse from before 1.5.0 still running: [RUNBOOK](RUNBOOK.md#harnesses)). There is no Grok row: Throttle has no xAI pool |
2152
+ | `◆ anthropic`, `◆ openai`, `◆ moonshot`, `◆ meta`, `◆ z.ai` | One availability bar per provider pool — Claude, Codex, (1.5.0) Kimi Code's, whose vendor is Moonshot AI, and (1.6.0) Throttle's `muse-code` (Meta's Muse Code) and `zai` (Z.ai) pools: ten cells of usable `▰`, cooling `▱`, benched `▪` and dead `·` accounts (ASCII `=` `~` `:` `.`), then the usable count of the configured ones (` ◆ anthropic ▰▰▰▰▰▰▱▪·· 12/19`), then — with the token — the worst weekly or 5-hour burn and the soonest reset. A daemon with no Kimi account shows ` ◆ moonshot ·········· 0/0`, which is no alarm (the same for no Muse Code or Z.ai account); `no data` means the pulse did not report the pool (a pulse from before 1.5.0, or 1.6.0 for `meta` and `z.ai`, still running, or a daemon without that pool: [RUNBOOK](RUNBOOK.md#harnesses)). Kimi, Muse Code and Z.ai have no paid overflow, so their pools never give the Throttle row's money. There is no Grok row: Throttle has no xAI pool |
2104
2153
  | `▣ productbox` | The host: CPU and memory utilization, the 1-minute load, the highest pressure (PSI) figure |
2105
2154
  | `▣ <container> …` | The three workspace containers using the most memory |
2106
2155
 
2107
- At 18–24 rows the block is three rows — Throttle, the provider with the smallest usable share (a pool with nothing
2156
+ At 18–26 rows the block is three rows — Throttle, the provider with the smallest usable share (a pool with nothing
2108
2157
  configured is never that one), the host — and smaller panes show none. Parts that do not fit are dropped from the end. A row turns amber when overflow spend reaches its alert
2109
2158
  level, a provider has no usable account, memory is fully stalled, memory use reaches 90 % or the CPU 95 % (its lead
2110
2159
  mark turns amber even when that part was dropped); red when the daemon does not answer. The whole block is dim, with a
@@ -2387,7 +2436,7 @@ Clients also get `lanes-helper.service` and `lanes-upload.path`/`.service` (Linu
2387
2436
  | Editor | `lanes cursor-commit [ws…] [--push]` | Section 6 |
2388
2437
  | Containers | `lanes install-container <name> [--no-mcp]` | Install the `lane` contract (section 2) and the agents' MCP entries for `lane-mcp` (section 7, "Agent tools (MCP)"); `--no-mcp` leaves both out |
2389
2438
  | Containers | `lanes onboard <login> --container <name> [--workspace <id> --repo <path> [--title T]] [--write] [--no-mcp]` | One user's container in one command: board, contract, Claude and Codex hooks, Throttle attachment, canonical recipes, sync, doctor, and a receipt (a dry run until `--write`; section 2) |
2390
- | Containers | `lanes hooks install --agent claude\|codex\|kimi\|grok\|grok-cli (--container <name> \| --home <dir>) [--dry-run \| --write]` | Section 7 ([Harnesses](#harnesses)) |
2439
+ | Containers | `lanes hooks install --agent claude\|codex\|kimi\|grok\|grok-cli\|muse\|zcode (--container <name> \| --home <dir>) [--dry-run \| --write]` | Section 7 ([Harnesses](#harnesses)) |
2391
2440
  | Uploads | `lanes upload <ws> \| --active <device> [--paste]` | Read a tar stream into that workspace's `uploads/` |
2392
2441
  | Uploads | `lanes docs push <id>` | Print one docs-store document's receipt (any login's: you are the operator) and exit 2 `not configured`: the hook for the data service's publication surface, not built yet ([Docs](#docs)) |
2393
2442
  | Client | `lanes hello [device] [--client-version V]` | Prove path, key and server version; ` update=<version>` when V is older |
@@ -354,6 +354,7 @@ install_client() {
354
354
  fi
355
355
  chmod +x "$target/lanes-launch" "$target/lanes-window" "$target/lanes-upload"
356
356
  for name in lanes-launch lanes-window lanes-upload; do ln -sfn "$target/$name" "$bin/$name"; done
357
+ ln -sfn "$target/ghostty/lanes-themed-window" "$bin/lanes-themed-window"
357
358
  say "commands: lanes-launch, lanes-window, lanes-upload in $(tilde "$bin") ($([ "$link" = 1 ] && echo "linked to this checkout" || echo "copied to $(tilde "$target")"))"
358
359
  printf '%s\n' "$device" > "$config/device"
359
360
  say "device (view session) name: $device"
@@ -514,7 +515,7 @@ install_desktop() {
514
515
  return 0
515
516
  fi
516
517
  mkdir -p "$HOME/.local/share/applications"
517
- sed "s|^Exec=.*|Exec=$bin/lanes-window|" "$target/omarchy/lanes.desktop" > "$HOME/.local/share/applications/lanes.desktop"
518
+ sed "s|^Exec=.*|Exec=$bin/lanes-themed-window|" "$target/omarchy/lanes.desktop" > "$HOME/.local/share/applications/lanes.desktop"
518
519
  # Hyprland (Omarchy): follow the LIVE config generation — Omarchy 4 = Lua, Omarchy 3 = hyprlang. One added
519
520
  # line, validated with `hyprctl configerrors`, and reverted automatically if Hyprland reports any error.
520
521
  hypr=$HOME/.config/hypr