185 lines
7.3 KiB
Markdown
185 lines
7.3 KiB
Markdown
# Thread Bookkeeping with Pin & Archive
|
|
|
|
> **Box is the main surface.** All operator work goes through Box (box.muse-dev.online). The web UI, `box` CLI, and agents share the same API endpoints. No UI-only powers.
|
|
|
|
**Status:** runbook (2026-10-04)
|
|
**Applies to:** muse.ai side-chat threads used by the fleet DM system
|
|
|
|
## Why bookkeeping matters
|
|
|
|
Side-chat threads are addressed by UUID. UUIDs go stale (deletion,
|
|
account-side cleanup, platform reissue — observed 2026-10-04 when
|
|
`heartbeat-opm` changed UUIDs in a single day and when the hardcoded
|
|
`1e75a740` "646 tasks" UUID died ~90 minutes after being committed).
|
|
Stale UUIDs cause silent misdelivery: the SPA redirects to an arbitrary
|
|
valid thread instead of 404ing, and the old placement-blind verify
|
|
claimed success.
|
|
|
|
Duplicates compound the problem. On 2026-10-04 the user observed two
|
|
`BRAIN-INIT` messages, indicating two brain threads where one was
|
|
expected. Fuzzy sidebar name search then matches the wrong thread.
|
|
|
|
Pin and archive are the native muse.ai mechanisms for managing this.
|
|
They are gateway API methods (`/api/session/pin`,
|
|
`/api/session/unpin`, `/api/session/archive`,
|
|
`/api/session/unarchive`, `/api/session/delete`,
|
|
`/api/session/rename`), **not** CDP browser actions. Our
|
|
`muse-chat-api.py` (CDP-based) does not implement them.
|
|
|
|
## Tooling: muse-cli
|
|
|
|
The supported path is the third-party `muse-cli` tool
|
|
(`nikships/muse-cli`), which speaks the gateway protocol (Noise XX +
|
|
protobuf) directly. It is **not** installed on bl, the VM, or the
|
|
operator container as of 2026-10-04.
|
|
|
|
### Install (on bl)
|
|
|
|
```bash
|
|
# Node.js required
|
|
npm install -g muse-cli # or per-repo install per muse-cli README
|
|
```
|
|
|
|
### Auth
|
|
|
|
muse-cli needs a `hatch_sess` cookie from a logged-in browser session.
|
|
Obtain it from the operator's own browser profile — never from another
|
|
agent's session. Treat the cookie as a credential: transient use, never
|
|
logged, never in chat.
|
|
|
|
### Commands (per muse-cli PROTOCOL.md)
|
|
|
|
```bash
|
|
muse-cli pin <session_id> # pin a thread
|
|
muse-cli unpin <session_id> # unpin a thread
|
|
muse-cli session-archive <session_id> # archive a thread
|
|
muse-cli session-unarchive <session_id> # restore an archived thread
|
|
muse-cli session-rename <session_id> <title> # rename a thread
|
|
muse-cli session-delete <session_id> # delete a thread (destructive)
|
|
```
|
|
|
|
`<session_id>` is the thread UUID (the hex string in
|
|
`https://muse.ai/thread/<uuid>`).
|
|
|
|
## When to pin a thread
|
|
|
|
Pin threads that are **critical infrastructure** or **frequently
|
|
accessed during triage**:
|
|
|
|
| Thread | Alias / reuse_key | Why pinned |
|
|
|---|---|---|
|
|
| main-loop brain | `main-loop brain` | Fleet coordination point |
|
|
| 646 tasks | `646 tasks` | 646's primary work thread |
|
|
| heartbeat | `heartbeat-opm` | Pipeline health signal |
|
|
| 646-pip-coord | `646-pip-coord` | Cross-operator coordination |
|
|
| muse tasks | `muse tasks` | muse's primary work thread |
|
|
|
|
Pinning keeps these at the top of the sidebar, which:
|
|
|
|
- Prevents fuzzy-name-search confusion (searching "646" is less likely
|
|
to match the wrong thread when the right one is pinned and visible).
|
|
- Makes important threads easy to find during incident triage.
|
|
- Does **not** change the UUID — pin is purely a display/ordering
|
|
operation. `job-sidechats.json` mappings are unaffected.
|
|
|
|
## When to archive a thread
|
|
|
|
Archive threads that are **stale, duplicate, test, or dead**:
|
|
|
|
- **Duplicates:** the double `BRAIN-INIT` incident — archive the
|
|
surplus thread, keep the registered one.
|
|
- **Stale UUIDs:** threads whose UUID no longer resolves (e.g. the dead
|
|
`1e75a740` if it still exists on 646's account).
|
|
- **Test threads:** `test-auto-prov` (`b96dd020`), `pipe-7d2896`,
|
|
`pipe-1b4579`, and other autoprovision experiments.
|
|
- **Superseded threads:** old threads replaced by a renamed or
|
|
re-provisioned canonical thread.
|
|
|
|
Prefer **archive** over **delete**: archiving is reversible
|
|
(`session-unarchive`), deleting is not. Delete only when certain the
|
|
thread holds nothing worth recovering.
|
|
|
|
## Listing pinned vs archived threads
|
|
|
|
muse-cli's session listing distinguishes state. Our CDP-based
|
|
`sidechat list` scrapes visible sidebar text only and **cannot**
|
|
distinguish pinned/archived/deleted threads — another reason to use
|
|
muse-cli for bookkeeping operations.
|
|
|
|
After any pin/archive operation, verify with the list command and
|
|
confirm the expected state before updating mappings.
|
|
|
|
## Integration with job-sidechats.json
|
|
|
|
`job-sidechats.json` (on bl) is the dynamic UUID registry:
|
|
`{ "<alias>": { "thread_uuid": ..., "agent": ..., ... } }`.
|
|
|
|
Rules:
|
|
|
|
1. **Pin changes nothing** in `job-sidechats.json`. The UUID is the
|
|
same; only sidebar ordering changes.
|
|
2. **Archive the registered thread → update the mapping.** Either
|
|
remove the entry (so the next send autoprovision a fresh thread) or
|
|
point it at the surviving canonical thread's UUID.
|
|
3. **Archive a non-registered duplicate → no mapping change needed**,
|
|
but note it in the commit message for traceability.
|
|
4. **Never hardcode UUIDs** in `SIDCHAT_ALIASES` or elsewhere (lesson
|
|
from 2026-10-04). Use name-based autoprovision with the dynamic
|
|
registry. A hardcoded UUID is a ticking time bomb: it *will* go
|
|
stale, and there is no alert when it does.
|
|
|
|
## Case study: duplicate brain INIT (2026-10-04)
|
|
|
|
**What happened.** The user observed two `BRAIN-INIT` messages in the
|
|
UI, indicating two brain threads where the design calls for one. The
|
|
brain thread (`5f18476d-8994-49e7-a9e0-4838732363fe`, created 19:40 UTC
|
|
on opm's account with placement confirmed) was never registered in
|
|
`job-sidechats.json`, so 646 reported it as "still pending" and
|
|
"unwired" while a second INIT appeared.
|
|
|
|
**Contributing factors.**
|
|
|
|
- The brain thread was created but the registration step was skipped.
|
|
- Without registration, later code paths could not find the canonical
|
|
thread and created (or appeared to create) another.
|
|
- No pin/archive pass had ever been run, so there was no canonical
|
|
"this is the one true brain" signal in the sidebar.
|
|
|
|
**How archive fixes it.**
|
|
|
|
1. Identify both thread UUIDs (from dm-log `alias_resolved` /
|
|
`nav_ok` records or muse-cli session list).
|
|
2. Confirm which UUID is registered in `job-sidechats.json` under
|
|
`"main-loop brain"` — that one is canonical.
|
|
3. `muse-cli session-archive <duplicate_uuid>` on the surplus thread.
|
|
4. Pin the canonical brain thread so it stays visible.
|
|
5. Commit the `job-sidechats.json` state with a note referencing the
|
|
archived duplicate.
|
|
|
|
**Prevention.** After creating any canonical thread: register it in
|
|
`job-sidechats.json` immediately, pin it, and note the UUID in the
|
|
commit message. Run a periodic (monthly) archive pass over test and
|
|
stale threads.
|
|
|
|
## Quick reference
|
|
|
|
```bash
|
|
# one-time: install + auth (hatch_sess cookie, transient)
|
|
# pin the critical set (opm account, adjust per agent)
|
|
muse-cli pin 5f18476d-8994-49e7-a9e0-4838732363fe # main-loop brain
|
|
|
|
# archive a duplicate / stale thread
|
|
muse-cli session-archive <duplicate_uuid>
|
|
|
|
# verify, then update job-sidechats.json on bl if the archived
|
|
# thread was the registered one (re-point or remove the entry)
|
|
```
|
|
|
|
## Open items (2026-10-04)
|
|
|
|
- muse-cli is not yet installed anywhere in the fleet.
|
|
- `hatch_sess` cookie handling needs a defined transient-use procedure.
|
|
- No scheduled archive pass exists yet; propose monthly.
|
|
- CDP-based `sidechat list` cannot see archived state — bookkeeping
|
|
must go through muse-cli, not dm.py.
|