Skip to content

Home Registry + dashboard home picker #130

@ThomasK33

Description

@ThomasK33

Problem Statement

I run agent-tty across many Homes — the default ~/.agent-tty, throwaway mktemp -d directories for isolated runs, and per-project AGENT_TTY_HOME overrides. But agent-tty can't see across them. list and the Session Dashboard only ever show the single Home resolved for that invocation, and there's no way to enumerate Homes at all (the only cross-Home artifact is a one-way sha256(home) hash under /tmp). So I can't discover which Homes exist, I have to remember and re-type every --home path, and a Home I've used effectively disappears from view the moment I move on — even though its Event Logs are still inspectable.

Solution

agent-tty remembers every Home that has hosted a Session in a per-machine Home Registry, and the Session Dashboard gains a Home picker so I can switch Homes and inspect each one's Sessions without leaving the dashboard. A new home list gives the same view on the CLI, comparable to list for Sessions. The registry stays tidy on its own: dead Homes (deleted temp dirs, emptied Homes) are hidden from listings immediately and pruned by garbage collection, which now sweeps across all known Homes by default. Everything is read-only observation; browsing never changes a Session.

User Stories

  1. As a developer, I want agent-tty to remember each Home I've created a Session in, so that I don't have to track --home paths myself.
  2. As a developer, I want home list to show the Homes that currently have Active Sessions, so that I can see where my live work is.
  3. As a developer, I want home list --all to also show Homes whose Sessions are all Terminal, so that I can find a finished project's Home to replay its Sessions.
  4. As a developer, I want home list --json, so that I can script over the set of Homes.
  5. As a developer, I want each home list row to show the Home path, a count of Active/total Sessions, and when it was last used, so that I can tell Homes apart at a glance.
  6. As a developer, I want home list sorted by most-recently-used first, so that the Home I care about is at the top.
  7. As a developer, I want to open the Session Dashboard and press a key to bring up a Home picker, so that I can switch which Home's Sessions I observe without restarting the dashboard.
  8. As a developer, I want the dashboard to open on the Home I launched it with (or the default), so that the picker is additive and nothing about today's behavior changes.
  9. As a developer, I want the picker to default to Active Homes and let me widen to all registered Homes, mirroring the dashboard's existing active/all scope for Sessions.
  10. As a developer, when I select a Home in the picker, I want the dashboard to list that Home's Sessions and let me open a Live View, so that inspecting another Home works exactly like inspecting the current one.
  11. As a developer, I want browsing Homes in the picker to never change any Session's state, so that merely looking around can't reconcile or kill anything.
  12. As a developer, I want a Home added to the registry automatically the first time it hosts a Session, so that I never register Homes by hand.
  13. As a developer who uses throwaway mktemp -d Homes, I don't want the registry to balloon with dead entries, so that the picker and home list stay useful.
  14. As a developer, I want listings to immediately hide a Home whose directory or Sessions are gone, so that I never see a stale Home even before garbage collection runs.
  15. As a developer, I want gc to sweep all registered Homes by default and prune dead ones, so that one periodic command keeps the registry from growing without bound.
  16. As a developer, I want gc --home <path> to scope collection to a single Home, so that I can still target one Home when I need to.
  17. As a developer, I want garbage collection to deregister a Home once it has no Sessions left, so that emptied Homes drop out of the picker.
  18. As a developer, I want garbage collection to never delete a Home directory, so that agent-tty can't remove a directory I own and might still want.
  19. As a developer, I want a deregistered Home to reappear automatically if I create a Session in it again, so that deregistration is never destructive or sticky.
  20. As a developer, I want home forget <path> to remove a Home from the registry without touching disk, so that I can clear a Home from the picker immediately.
  21. As an AI coding agent, I want home list --json, so that I can discover which Homes are available and choose one to inspect.
  22. As a developer, I want the registry to be per-machine, so that another machine's Homes never appear in or interfere with mine.
  23. As a developer using Coder workspaces, I want each workspace to keep its own registry, so that Homes don't leak between workspaces.
  24. As a developer, I want the registry stored at ${XDG_STATE_HOME:-~/.local/state}/agent-tty/homes.json, so that it sits in the conventional machine-local state location and is easy to find or clear.
  25. As a developer, if I delete the registry file, I want Homes to re-register on next use, so that losing the file is harmless.
  26. As a developer, I want the dashboard picker and home list to show the same Homes under the same scope, so that the two surfaces never disagree.
  27. As a developer, I want home commands and the picker to use the term "Home" consistently and never conflate it with my OS $HOME, so that the vocabulary is unambiguous.
  28. As a developer, when I enter a selected Home, I want its Sessions reconciled (accurate statuses) exactly as list/the dashboard do today for a single Home, so that entry reflects the truth.
  29. As a developer running parallel agent workflows, I want concurrent creates to update the registry safely without corrupting it, so that the file survives heavy use.
  30. As a developer, I want home list to never mutate Session state across Homes just to display counts, so that listing stays cheap and safe.

Implementation Decisions

  • New HomeRegistry store module under src/storage/ (sibling to sessionPaths.ts/home.ts): a per-machine, advisory JSON index. The Home directories remain the source of truth; the registry is reconciled against them, never the reverse. (See docs/adr/0008-home-registry-advisory-per-machine.md.)
  • Location: ${XDG_STATE_HOME:-~/.local/state}/agent-tty/homes.json, derived from the OS user and independent of AGENT_TTY_HOME — the registry spans Homes, so it cannot live inside one. Resolved by a pure function, mirroring resolveHome.
  • Entry shape: { path, lastSeenAt } only. No cached Session counts or statuses; those are derived live by scanning the Home at read time.
  • Store interface with injected fs + clock (mirroring GcDependencies): upsert(path) (register / refresh lastSeenAt), list() (applies prune-on-read), forget(path), and a prune/sweep operation. Writes are atomic (temp file + rename) to tolerate concurrent creates.
  • Auto-registration: the create path upserts the resolved Home after a Session is created.
  • Prune-on-read: list() stats each entry and omits Homes whose directory or sessions/ tree is gone; it does not rewrite the file on every read (durable compaction is gc's job).
  • Scope: an Active Home is a Home with ≥1 Active Session. Default scope of both home list and the picker is Active Homes; --all (and the picker's existing all toggle) include Terminal-only Homes. Active-ness is determined by a read-only manifest scan with no reconciliation, so listing/browsing never mutates state.
  • New home command group (mirroring skills): home list [--all] [--json] and home forget <path>. home list reuses the existing emitSuccess/list-result envelope; rows show path, derived active/total counts, and last-seen; sorted newest-first.
  • gc becomes cross-Home by default: with no explicit Home selection it sweeps every registered Home (collect Collectable Session directories in each existing Home, reconcile within the local boundary, deregister gone/emptied Homes). With --home or an explicit AGENT_TTY_HOME it scopes to that single Home as today. This requires the command context to expose whether a Home was explicitly selected vs defaulted. gc never deletes a Home directory.
  • Local-only reconciliation: reconcile/kill use local PIDs and manifests carry no machine identity, so a Home shared across machines is unsupported (ADR 0008). No machine-id guard in this PRD.
  • Session Dashboard becomes Home-aware: home lifts into dashboard state; the Focus state machine gains a home pane; selecting a Home re-runs the already-Home-parameterized session-listing. The dashboard opens on the launched/resolved Home (additive picker); full reconcile happens only on Home entry, never while browsing. --home/AGENT_TTY_HOME sets only the initial Home and does not restrict navigation. Picker logic lives in pure functions; the Ink component stays thin.

Testing Decisions

  • Good tests assert external behavior, not implementation: given a registry file + Home directories on disk (or an injected store), assert what home list/gc/the scope functions produce and persist, not how.
  • HomeRegistry storetest/unit/storage/homeRegistry.test.ts (prior art: sessionPaths.test.ts, artifactStorage.test.ts): register+dedupe (same path refreshes lastSeenAt), prune-on-read omits gone Homes, atomic write survives concurrent upserts, newest-first ordering, XDG_STATE_HOME honored with ~/.local/state fallback, location independent of AGENT_TTY_HOME.
  • Scope/picker pure functionstest/unit/dashboard/ (prior art: sessionScope.test.ts, sessionListLayout.test.ts): Active Home = ≥1 Active Session; default vs all membership; ordering; and a guard test injecting a reconcile spy to prove the scope scan performs zero reconciliation.
  • home list / home forget commandstest/unit/commands/ (prior art: dashboard.test.ts, skills-list.test.ts, gc.test.ts): --json envelope shape + human lines; forget removes an entry without touching disk; empty-registry behavior.
  • Cross-Home gc — extend test/unit/commands/gc.test.ts: default sweep prunes dead/emptied Homes; --home scopes to one; deregister-on-empty; gc never rms a Home directory (assert the Home dir still exists, only session dirs + registry entry removed); --dry-run/--stale-only/--older-than still honored per-Home within the sweep.
  • Auto-registration on create — extend test/unit/commands/create.test.ts: creating a Session upserts the resolved Home (injected store / temp state dir).
  • Result-schema sweepgc's result shape changes and a new home list result is added, so grep the suite for stale .result assertions (typecheck + sandbox unit runs miss these; CI integration/e2e catch them) and cover new/changed envelopes in golden-envelopes.test.ts.
  • The Ink app.tsx gets no new dedicated unit test (consistent with today); its behavior is exercised through the pure scope/layout functions.

Out of Scope

  • Cross-machine / remote Home aggregation — the registry is per-machine and local-only; remote Event Log Follow transport and shared/NFS Homes are out of scope (ADR 0008).
  • Machine-identity guard on reconcile — deferred follow-up; this PRD relies on the per-machine boundary instead.
  • Deleting Home directories — gc deregisters and collects Sessions but never removes a Home directory.
  • User-assigned Home names/labels — entries are {path, lastSeenAt} only.
  • Cached Session counts in the registry — always derived live.
  • Making the dashboard agent-aware (grouping/filtering by client identity) — unchanged; still gated on a separate domain extension per CONTEXT.md.
  • A gc daemon / automatic periodic sweep — gc stays user/automation-invoked; "periodic" means the user or their harness schedules it.

Further Notes

  • Domain terms and relationships are already captured in CONTEXT.md (Home, Home Registry, Active Home; the Session Dashboard redefined as Home-aware) and the rationale in docs/adr/0008-home-registry-advisory-per-machine.md — both on branch feat/home-registry.
  • Backward-incompatible CLI change: plain gc changes from "collect the default Home" to "sweep all registered Homes." Call this out in the changelog; automation relying on the old behavior must pass --home.
  • ADR numbering: 0008 currently collides with the unpushed feat/workflow-hero-demo branch's 0008-carry-two-parallel-hero-demos; whichever merges second must renumber.
  • The registry is advisory: losing homes.json is non-fatal (Homes re-register on next create; only Terminal-only Homes vanish from the picker until reused).

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentFully specified, ready for an AFK agent

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions