Session lifecycle: make archived_at usable, and decide whether sessions need a status beyond archived/not-archived
- Lenguaje dominante
- Rust
- Estrellas
- 54.2k
- Forks
- 6.2k
- Merge medio
- 3 d 2 h
- PR fusionados (30 d)
- 262
Descripción
**What problem would this solve?**
Session lists grow without bound and there is no way to say what a session *was*. Every session looks alike in the list forever, whether it is live work, an experiment abandoned ten minutes in, or a task whose PR merged three weeks ago. Finding the session you actually want means scanning an ever-growing list of things that are all nominally equal.
`main` already has the beginnings of an answer: an `archived_at` column, `_goose/unstable/session/archive` and `.../unarchive` ACP methods that set and clear it, and `archivedAt` surfaced through to the desktop session types. What is missing is everything that would make it usable, plus the question of whether binary archived/not-archived is the right shape:
- **Nothing consumes it.** Session listings do not filter on `archived_at`, so archiving a session does not actually remove it from the list.
- **No CLI surface.** There is no `goose session archive` / `unarchive`, and no way to see archived sessions.
- **No UI surface.** There is no archive action on a session card and no indication that a session is archived.
- **Archived vs. finished are different things.** "I am done looking at this" and "this work completed successfully" and "this was rejected" all collapse to the same bit. For sessions that drove a PR, the outcome is knowable and useful, and a single boolean cannot express it.
**What would a good outcome look like?**
A user can retire sessions from their working list, and can later tell what happened to the ones they retired — from both the desktop app and the CLI.
Concretely:
- Retired sessions are hidden from the default list and reachable through an explicit opt-in.
- The state is visible on the session itself, not just implied by its absence.
- Retiring and un-retiring are available from the app and from the CLI, and agree with each other.
- Whatever states exist are consistent across the DB, ACP, CLI, and UI, rather than one surface inventing its own vocabulary.
**Possible approaches**
The main design question this issue should settle: **does Goose want a lifecycle status enum, or is `archived_at` plus better plumbing enough?**
*Option A — finish what `archived_at` started.* Add list filtering, CLI commands, and a UI action on top of the existing column. Smallest change, no migration, no new vocabulary. Cannot express outcome; "abandoned" and "merged" stay indistinguishable.
*Option B — a lifecycle status.* Something like `active`, `archived`, `completed`, `superseded`, `pending`, `rejected`, with `archived_at` maintained alongside for compatibility. Expresses outcome and supports things like "show me what is still in flight". Costs a migration, a wider API surface, and a decision about how status and `archived_at` stay consistent — including which one is authoritative when they disagree.
Sub-questions either way:
- Should status ever be inferred rather than set by hand? For sessions containing GitHub PR URLs the PR state is a strong signal (open → in flight, merged → completed, closed → rejected), and scanning the conversation for those URLs is cheap. Attractive, but it makes session state depend on an external tool (`gh`) and on network access, so it is probably an explicit opt-in command rather than anything automatic.
- Which states hide from the default list? Not all of them should — a session waiting on review is still live work and should stay visible.
- Is this per-session only, or does it interact with the existing project grouping?
**Additional context**
I have an implementation of Option B in #10616 — status enum, migration, `_goose/unstable/session/set-status`, CLI `archive`/`unarchive`/`list --archived`/`infer-status`, and desktop badge plus archive action.
That PR predates the `archived_at` work that has since landed on `main`, and now overlaps it: the PR adds its own archive path rather than building on the one that exists. I have deliberately left it un-rebased rather than mechanically merging the two, because which of them survives is a design decision, not a merge conflict. Once this issue settles Option A vs Option B, I will rewrite the PR on top of whatever `main` already provides — or close it if Option A is the answer and the scope shrinks to plumbing.
- [x] I have verified this does not duplicate an existing feature request
Guía de contribución
Evaluación
Este issue todavía no se ha evaluado.