Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions docs/ai/design/2026-10-10-feature-muse-adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
phase: design
title: System Design & Architecture
description: Design the system architecture and technical approach
---

# System Design & Architecture

## Architecture

New `muse/` harness mirroring the `claude/` and `codex/` layout. Detection joins two sources:
the small live set (`runtime/muse/sessions/*.json`) and the dated archive
(`sessions/yyyy/mm/dd/<uuid>/session.jsonl`).

```mermaid
flowchart LR
PS[process snapshot] --> LOC[MuseSessionLocator]
RT[runtime/muse/sessions/*.json] --> LOC
AR[sessions/yyyy/mm/dd/*/session.jsonl] --> LOC
LOC -->|direct + legacy matches| MAP[MuseAgentMapper]
LOC --> ADP[MuseAdapter]
PAR[MuseSessionParser] --> ADP
ADP --> AM[AgentManager]
RD[muse/readiness.ts] --> AR2[AgentReadiness]
CR[muse/credentials.ts] --> RD
```

## Components

- `MuseSessionLocator`: three-stage match like Claude's — runtime-file PID match (authoritative,
with a start-time staleness guard), then archive fallback by session id, then legacy
cwd+birthtime heuristic. Enumerates the archive with a flatten walk + UUID regex, mtime
cache, excluding `subagent/`, `approval-review/`, logs, and sqlite files.
- `MuseSessionParser`: two-stage framed parse (outer line, then inner `record_json`) dispatched
on `payload_type`; extracts user/assistant messages, first-user-message filtering, µs→ms
timestamps, `workspace_root`/`model_id` from metadata payloads. Spike alternative: `muse export`
JSON document (decided in planning; see open item).
- `MuseAgentMapper`: name from `workspace_label`/`session_name`, summary from last user prompt,
status from tail heuristic (no published live status exists).
- `MuseAdapter`: registers `muse` in `AGENT_TYPES`, `processNames` covering the
`muse-bin-<version>-<build>` shape, `canHandle`, `detectAgents`, tail-efficient
`getConversation`, `listSessions`, `findSessionsById` (runtime-first).
- Type-forced registration checklist (all three are `Record` over every `AGENT_TYPES`
member, so the compiler enforces them): `HARNESS_RUNTIME_PROFILES.muse` in
`runtimeProfiles.ts` using a `matchArgv0Name("muse")`-style matcher (argv0 basenames look
like `muse-bin-1.4.4-R5419.1`, so exact-name matching fails); `READINESS_PROFILES.muse`
in `AgentReadiness.ts` pointing at `muse/readiness.ts`; adapter instance in
`createBuiltinAdapters()`. The readiness `executableCheck` resolves the profile's
`command`, so the profile command must be `muse` (on PATH).
- `muse/readiness.ts` + `muse/credentials.ts`: executable on PATH, `~/.config/muse/` dir,
`auth.json` state, built-in skills presence — reusing the shared readiness checks.

## Data Models

- Runtime entry: `{ schema_version, session_id, session_name|null, endpoint_hint?,
workspace_label?, target_eligibility?, process_generation_hint: "pid=<n>" }`.
- Transcript frame: `{ retained_frame, record_json: string, ... }` with inner
`{ stream:{kind,id}, sequence, recorded_at(µs), record_type, payload_type, payload }`.
- Outputs reuse `AgentInfo`, `SessionSummary`, `ConversationMessage` unchanged.

## Design Decisions

- Runtime-first lookup everywhere: the live set is tiny, the archive walk is cached.
- Exclude, never parse, non-transcript files; require `session.jsonl` presence per session dir.
- Verbatim session-id round-trip for `muse resume` compatibility.
- Read-only: no writes under Muse directories; temp files only if the export path wins the spike.

## Security / Performance

- Tolerate `0600` files; skip unreadable entries instead of failing enumeration.
- Never log transcript content or the export document (bundles encrypted reasoning).
- Tail reads scale with the tail; full-file reads only where the caller asks for full history.
- One cached archive walk per refresh; keyed invalidation by directory mtime.

## Open Items

- Parser vs `export` spike outcome (cost/latency/freshness comparison on a large transcript).
- Status heuristic definition (which tail payloads map to running/waiting/idle).
89 changes: 89 additions & 0 deletions docs/ai/implementation/2026-10-10-feature-muse-adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
phase: implementation
title: Implementation Guide
description: Guide the implementation with detailed technical specifications
---

# Implementation Notes

What shipped for `feature-muse-adapter` (v1 vertical slice, `agent-manager` only).

## Changed files

- `packages/agent-manager/src/harnesses/muse/MuseSessionParser.ts` (new): framed-transcript
parsing (direct / `record_json` / `retained_frame` children), `payload_type` dispatch,
µs→ms timestamps, incremental cache + tail reader reuse.
- `packages/agent-manager/src/harnesses/muse/MuseSessionLocator.ts` (new): runtime-file PID
matching with birthtime staleness guard, dated-archive walk with UUID filter, legacy
cwd+birthtime fallback via bounded metadata head-reads.
- `packages/agent-manager/src/harnesses/muse/MuseAgentMapper.ts` (new): project-named
agents, last-prompt summaries, parser-derived status.
- `packages/agent-manager/src/harnesses/muse/MuseAdapter.ts` (new): `type "muse"`,
`processNames ["muse"]` + `processNamePrefixes ["muse"]`, precise `canHandle`.
- `packages/agent-manager/src/harnesses/muse/readiness.ts` (new): config dir
`.config/muse`, auth probe on `auth.json` presence.
- Shared discovery extension: `AgentAdapter.processNamePrefixes`, prefix matching in
`utils/process.ts` (capture, filter), threaded through `AgentManager`,
`harnesses/shared.ts`, `fixtures/capture.ts`. Existing adapters pass no prefixes, so
their capture call shapes are byte-identical (verified by untouched mock assertions).
- Registration: `AGENT_TYPES` + `createBuiltinAdapters` + `READINESS_PROFILES.muse` +
`HARNESS_RUNTIME_PROFILES.muse` (`matchArgv0Name("muse")`, command `muse`).
- Tests: 4 new muse suites (20 tests) + prefix tests + runtime-profile case + muse
readiness cases; updated readiness keys, fixture bundles
(`fixtures/harness/muse/matched|fallback.json`), readiness fixtures
(healthy/degraded muse entries).
- Deliberately NOT created: `muse/credentials.ts` (no token consumer; auth probe reads
`auth.json` directly like the pi pattern).

## Decisions and deviations

- T1 spike picked the hand-written framed parser over `muse export`: 0.37s in-process vs
0.51s + subprocess + 13MB temp file + sensitive reasoning bundle.
- Staleness guard compares process start against transcript birthtime (runtime files carry
no start timestamp).
- First-user-message may come from any pre-skip line (Claude semantics); session start
from the first line only.
- Fixture timestamps: matched bundle uses `$NOW` starts (birthtime-coupled) with `$TODAY`
day dirs; fallback uses a frozen clock.

## Edge cases handled

0600 files skipped, malformed runtime entries ignored, non-UUID dirs excluded, `subagent/`
and logs never match (require `session.jsonl`), verbatim id round-trip, empty transcripts
return null.

## Minor deviation from design

Design mentioned an mtime cache for the archive walk; not implemented — walks are
readdir-only and bounded like Claude's `discoverHistoricalSessionFiles`. Add caching only
if profiling shows refresh cost.

## Cross-package fallout (found via CLI build)

Adding `muse` to `AGENT_TYPES` broke the CLI build: `AGENT_TYPE_LABELS` and
`AGENT_TYPE_LABELS_COMPACT` in `packages/cli/src/util/agent.ts` are exhaustive
`Record<AgentType, string>`. Added `muse: "Muse Code"` / `muse: "muse"`. This also
made muse startable in the console start pane and listable in `--type` filters and
status reports (all automatic via the runtime profile); updated those list-membership
tests. Spawning `muse` from the console works through the profile command, so no
exclusion mechanism was added.

## Rust `devkitd` detection parity (added scope)

- `rust/crates/devkit-harness/src/muse/{mod,locator,parser}.rs`: framed-transcript fold
(envelope/children unwrap, µs timestamps, intent/assistant/approval/input signals),
runtime-file PID matching with birthtime staleness guard, dated-archive walk, legacy
cwd+birthtime join; status mirrors TS exactly (no idle override).
- `shared.rs`: `matches_executable_prefix`; `devkit-core/discover.rs`: daemon pool gate
admits `muse`/`muse-*` basenames (precision stays in `can_handle`).
- Wiring: `lib.rs` module + `default_registry` + parity test.
- Golden fixtures `fixtures/harness/muse/*` replay byte-identical through the Rust port;
`cargo test` 70 + 16 green, clippy clean. `cargo fmt` drift is repo-wide pre-existing
(newer local rustfmt); new code matches surrounding style, no reformatting.
- Deliberately NOT ported: conversation reads, incremental cache, display names, model
ids, history listing, readiness checks (daemon surface is detect-only).

## v2 handoff

Send transport (endpoint socket vs `session-message` CLI), runtime-file exit cleanup,
status-heuristic refinement, Rust `devkitd` mirror, CLI status surfacing.
91 changes: 91 additions & 0 deletions docs/ai/planning/2026-10-10-feature-muse-adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
phase: planning
title: Project Planning & Task Breakdown
description: Break down the implementation into actionable tasks
---

# Project Planning & Task Breakdown

Scope: v1 vertical slice (user-approved). Every task traces to requirements (R),
design (D), or testing scenarios (T).

## Milestone 0 — Worktree bootstrap

- [x] T0 Bootstrap worktree dependencies.
Outcome: worktree `npm ci` (or documented offline fallback) so vitest/tsc run.
Deps: none. Validation: `vitest --version` runs in worktree agent-manager.
Risk: sandbox network/npm-cache limits; record fallback if install fails.

## Milestone 1 — Parser spike (time-boxed)

- [x] T1 Decide framed parser vs `muse export` for `getConversation`.
Outcome: recorded decision with cost/latency/freshness numbers on a large transcript.
Deps: T0. Validation: spike notes in implementation doc. Traces to D-open-item, R-open-item.
Scenarios: T tail-cost, T message ordering.

## Milestone 2 — Discovery (locator + fixtures)

- [x] T2 `muse/MuseSessionLocator.ts`: runtime-dir PID match with start-time staleness guard,
dated-archive flatten walk with UUID regex, live/archive merge, noise exclusions
(`subagent/`, `approval-review/`, logs, sqlite), mtime cache.
Outcome: staged strategies mirror Claude's locator. Deps: T0. Validation: locator unit tests
on fake home trees. Traces to R-goals 1–3, D-locator. Scenarios: live detect, stale pid,
archive filter, runtime-first resolve, unreadable files.
- [x] T3 `fixtures/harness/muse/matched.json` + `fallback.json`: live runtime entry, stale
variant, framed transcript lines (test in worktree, never real `~/.local`).
Deps: T2. Validation: fixtures load in tests. Traces to R-goal 6.

## Milestone 3 — Parsing + mapping

- [x] T4 `muse/MuseSessionParser.ts`: two-stage framed parse, `payload_type` dispatch,
user/assistant extraction, first-message filtering, µs→ms timestamps.
(If T1 picks export: thin wrapper + redaction handling instead.)
Deps: T1. Validation: parser tests incl. tail slicing. Traces to R-goal 4, D-parser.
Scenarios: ordering, tail cost, filtering, timestamp normalization.
- [x] T5 `muse/MuseAgentMapper.ts`: name from `workspace_label`/`session_name`, summary from
last user prompt, tail-heuristic status, idle threshold via shared helper.
Deps: T4. Validation: mapper tests. Traces to R-goal 1, D-mapper.

## Milestone 4 — Adapter + registration

- [x] T6 `muse/MuseAdapter.ts` + type-forced registration: `AGENT_TYPES`, `processNames`
for the `muse-bin-*` shape, `canHandle`, `detectAgents`, `getConversation`,
`listSessions` (strict cwd), `findSessionsById` (runtime-first); register in
`createBuiltinAdapters()`; add `HARNESS_RUNTIME_PROFILES.muse` (`matchArgv0Name`-style,
command `muse`).
Deps: T2, T5. Validation: adapter tests + `tsc` (Record types enforce the checklist).
Traces to R-goals 1–4, D-checklist. Scenarios: detect, cwd filter, verbatim id round-trip.

## Milestone 5 — Readiness

- [x] T7 `muse/readiness.ts` + `muse/credentials.ts` (`~/.config/muse/auth.json` state) +
`READINESS_PROFILES.muse` (configDir `.config/muse`).
Deps: T0. Validation: readiness matrix tests. Traces to R-goal 5, D-readiness.
Scenarios: readiness matrix.

## Milestone 6 — Verification + docs

- [x] T8 Blast-radius sweep: run full agent-manager suite; fix count/snapshot tests that
enumerate `AGENT_TYPES` or readiness types; run `lint --feature muse-adapter`.
Deps: T6, T7. Validation: green suite, lint 12+ checks pass.
- [ ] T9 Update implementation doc with what shipped, deviations, and v2 handoff notes
(send transport, exit-cleanup, status heuristic).
Deps: T8. Validation: Phase 7 check (code matches design).
- [x] T10 Rust `devkitd` detection parity (added scope): `muse/` port (locator, parser,
adapter), `matches_executable_prefix` in harness `shared.rs`, daemon pool-gate prefix
in `devkit-core` `discover.rs`, registry + parity-test wiring, golden fixtures replay.
Validation: `cargo test -p devkit-harness -p devkit-core` green, clippy clean.

## Risks / sequencing

- Order: T0 → T1 → T2/T3 → T4/T5 → T6 → T7 (T7 parallelizable after T0) → T8 → T9.
- Biggest risk: framed-schema drift; mitigated by validating against `muse schema` output.
- `AGENT_TYPES` append affects every consumer of the union; T8 exists for that reason.
- Rust mirror, send, durable runs stay out; any code reaching toward them gets cut.

## Status (Phase 6 reconciliation)

All implementation tasks T0–T8 done; T9 (this implementation doc update) in progress.
No scope changes. One intermittent ManagedAgentRuntime spaced-path failure observed once
in full-suite parallelism (passes in isolation and on reruns); treated as pre-existing
flake, needs a watch item, not a code change. No new tasks discovered.
91 changes: 91 additions & 0 deletions docs/ai/requirements/2026-10-10-feature-muse-adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
phase: requirements
title: Requirements & Problem Understanding
description: Clarify the problem space, gather requirements, and define success criteria
---

# Requirements & Problem Understanding

## Problem Statement

**What problem are we solving?**

Muse Code sessions are invisible to AI DevKit. `agent list`, the console, `listSessions`,
and readiness reporting cover Claude Code, Codex, Gemini, and the other harnesses, but a
developer running `muse` gets no supervision, no history, and no conversation access through
the shared control plane. The current workaround is inspecting `~/.local/share/muse` by hand.

- Who is affected: developers whose agent mix includes Muse Code (e.g. this repo's own users).
- Current situation: manual `ls`/`cat` of runtime and transcript files; no programmatic access.

## Goals & Objectives

- Primary goals (v1, vertical slice in `agent-manager`):
1. Detect live Muse sessions (process + runtime-file match) with correct pid, session id,
project path, and display name.
2. Enumerate historical sessions from the dated archive with cwd filtering.
3. Resolve a session id without a full archive walk (`findSessionsById`, runtime-first).
4. Read conversations including tail-efficient reads for large transcripts.
5. Report Muse readiness (executable, config dir, auth, built-in skills) through the
existing readiness pipeline.
6. Ship fixtures and tests matching the harness conventions (adapter, locator, parser,
readiness, summary equivalence, tail parity).
- Secondary goals: document the Muse storage layout and open questions for the v2
(send/steer, durable runs) feature.
- Non-goals (explicitly out of scope for v1):
- Steering a live session (`agent send`; socket vs `session-message` transport undecided).
- Durable/headless runner on `muse exec` and resume wiring.
- CLI start-pane wiring and MCP setup writer for Muse.
- Rust `devkitd` mirror (moved INTO scope per user instruction; detection parity only —
`canHandle` + `detect`, no history/conversation/status-config surfaces).
- CLI `status`-command surfacing for Muse (skill-root map entry and readiness display;
tracked separately even though harness-level readiness checks are in scope).

## User Stories & Use Cases

- As a developer running `muse`, I want `agent list` to show my live session so that I can
supervise it alongside Claude/Codex sessions.
- As a developer, I want session history for Muse so that I can find and resume prior work
with `muse resume <id>` round-tripping verbatim.
- As a developer, I want the last user prompt and conversation tail for a Muse session so
that detail views and handoffs work like other harnesses.
- Edge cases: stale runtime file after process exit; PID reuse; `0600` runtime files;
`subagent/` child sessions that must not double-count; huge transcripts (tail-only reads);
sessions whose transcript dir has noise (`cli-*.log`, `cron.db`, `*.sqlite3`).

## Success Criteria

- `detectAgents` finds the live Muse session with exact pid, session id, and workspace root.
- `listSessions` enumerates archive sessions with strict cwd filtering; `findSessionsById`
hits the runtime dir first and avoids full walks.
- `getConversation` returns user/assistant messages with `tail` reading proportional to the
tail, not the file; first-user-message noise filtering matches harness conventions.
- Readiness reports pass/warn/fail for executable, config, auth, and built-in skills.
- New fixtures (`fixtures/harness/muse/`) and tests pass; `lint --feature muse-adapter` passes.
- No writes to Muse-owned directories except an explicit temp file if the `export` path is chosen.

## Constraints & Assumptions

- Technical constraints: read-only against Muse storage; tolerate `0700`/`0600` permissions;
follow the `AgentAdapter` contract (`AGENT_TYPES`, `processNames`, `canHandle`,
`detectAgents`, `getConversation`, `listSessions`, `findSessionsById`).
- Assumptions: session ids are UUID-shaped; `process_generation_hint` format is `pid=<n>`;
transcript timestamps are microseconds (normalize to ms); framed log schema is stable and
`muse schema` is its contract; `subagent/`, `approval-review/`, logs, and sqlite files are
excluded from enumeration.
- Validation: repo's own vitest suites for the touched harness surface must pass in-session.

## Rollout

Additive only: a new optional harness. No existing adapter behavior changes except appending
`muse` to the shared `AGENT_TYPES` list. No migration, no config changes, no rollout risk
beyond the standard CI gate.

## Questions & Open Items

- Deferred to design spike: hand-written framed parser vs `muse export` JSON for
`getConversation` (cost, latency, temp-file writes, sensitive reasoning payload).
- Deferred to v2: send transport (endpoint socket vs `session-message` CLI), exit-cleanup
semantics of runtime files, and the source for running/waiting/idle status.
- Memory/task tracing CLIs are unusable in this environment (DB open failures); lifecycle
continues without task logging.
Loading
Loading