@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.
- package/package.json +1 -1
- package/payload/lanes/README.md +1 -1
- package/payload/lanes/VERSION +1 -1
- package/payload/lanes/bin/lanes +111 -25
- package/payload/lanes/client/ghostty/common.conf +4 -0
- package/payload/lanes/client/ghostty/lanes-themed-window +73 -0
- package/payload/lanes/client/ghostty/omarchy.conf +4 -2
- package/payload/lanes/container/hooks/muse-hooks.json +13 -0
- package/payload/lanes/container/hooks/zcode-hooks.json +9 -0
- package/payload/lanes/container/lane +7 -4
- package/payload/lanes/container/lane-mcp +13 -5
- package/payload/lanes/container/lane-signal +88 -21
- package/payload/lanes/container/lane_core.py +143 -19
- package/payload/lanes/container/throttle-pulse +9 -6
- package/payload/lanes/docs/ARCHITECTURE.md +58 -11
- package/payload/lanes/docs/INSTALL.md +10 -6
- package/payload/lanes/docs/RUNBOOK.md +125 -16
- package/payload/lanes/docs/USERGUIDE.md +77 -28
- package/payload/lanes/install.sh +2 -1
- package/payload/lanes/libexec/agent_state.py +90 -14
- package/payload/lanes/libexec/attach.py +181 -0
- package/payload/lanes/libexec/harness_muse.py +531 -0
- package/payload/lanes/libexec/lanes_lib.py +3 -2
- package/payload/lanes/libexec/sidebar.py +9 -6
- package/payload/lanes/libexec/statusd.py +16 -6
- package/payload/manifest.json +4 -3
|
@@ -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
|
|
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
|
|
127
|
-
(`hooks-kimi`, `hooks-grok`, `hooks-grok-cli`), each only when its home
|
|
128
|
-
is in the container, else `skipped
|
|
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.
|
|
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
|
|
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
|
|
1001
|
-
|
|
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
|
|
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)
|
|
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
|
|
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`, `
|
|
1056
|
-
whose `comm` is `claude`, `codex`, `kimi`/`kimi-code
|
|
1057
|
-
|
|
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 >
|
|
1074
|
-
observer (its session file, else its title) > the Grok Build title on a pane observed as `grok` > the
|
|
1075
|
-
where Codex can be) > the observed harness itself; the
|
|
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
|
|
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 **
|
|
1727
|
-
pane
|
|
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
|
|
1753
|
-
`unknown`; a pane that runs only shells is `shell` to the walk and shows no agent
|
|
1754
|
-
there, with the status shell). A pane title that looks like Codex's is read as
|
|
1755
|
-
title of two or more words read as an idle Codex, so a Kimi lane showed
|
|
1756
|
-
`
|
|
1757
|
-
|
|
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
|
|
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.
|
|
1839
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2088
|
-
rows (1.
|
|
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
|
|
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–
|
|
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 |
|
package/payload/lanes/install.sh
CHANGED
|
@@ -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
|