Skip to content

feat(workspace): one-line attach toast, and a /workspace Status view for the detail - #1312

Draft
ralphstodomingo wants to merge 28 commits into
feat/workspace-sidebar-statusfrom
feat/workspace-status-dialog
Draft

ralphstodomingo wants to merge 28 commits into
feat/workspace-sidebar-statusfrom
feat/workspace-status-dialog

Conversation

@ralphstodomingo

@ralphstodomingo ralphstodomingo commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Issue for this PR

Closes #1311

Type of change

  • New feature

Stacking

Base is feat/workspace-sidebar-status (#1279, the sidebar's memory and skill-sync lines), which now sits on main with #1278 (the /workspace menu) merged. The sidebar tile here carries both #1279's lines and this branch's attach line, in that order under the name: integrations, memories, skills, pinned hint, URL. The branch also carries #1308 and #1310 (the engine's unfulfilled report and the attach report), because the view reads that report; their commits show in this diff until they merge to main, after which this rebases to its own commits.

What does this PR do?

The attach toast carried the whole engine report — every undelivered key grouped by reason, with the engine's detail — and on a workspace with a few gaps it read as noise. Numbers belong in the toast; the keys and reasons belong somewhere they can be read again.

  • The toast is one line: 2 of 9 integration tools available · 7 need attention. Details: /workspace, with · N more via VS Code when a live bridge serves extension tools. describeMissing / describeExtensionServed are gone; reasonPhrase keeps the wording for the view.
  • An attach snapshot per directory — workspace, engine version, the allowlist, what the engine served, its report — kept in memory and in altimate-attach-snapshots.json under the state directory, because the TUI plugin runs in a different process from the overlay (the same reason the binding cache is a file). Bounded to 64 directories; written best-effort; a test seam keeps the suite out of the real state directory.
  • status-view.ts, transport-agnostic like manage.ts: the snapshot joined to the workspace's selection and the catalog gives one row per integration — served / partial / missing with reasons / idle for an extension without a window — attention first, keys beyond the allowlist as extras, and a headline the toast, the menu row and the sidebar share. If the API cannot be reached the view still renders from the snapshot alone, rows named by id.
  • /workspace → Status: the menu's first row, whose description is the headline read from the snapshot (no network before the menu opens). It opens the view: an integration row with counts and the reason, muted sub-rows for its keys (gaps with reasons first, then what is available, capped), and Open on the web / Re-read / Done as action rows. A snapshot from a workspace this project was since re-linked away from is ignored.
  • Sidebar: the Workspace tile shows the headline under the name once a session has attached, same staleness guard, refreshed on the tile's existing poll.
  • Boot box, workspace mode only: under "What is Altimate Code", three lines through a new welcome_extra slot — the mode and the linked workspace, the slash commands the mode adds (/workspace, /skills), and the integrations line: "attach on your first message" before a session, the toast's numbers with a pointer at /workspace after. Unlinked projects get the link command instead. The panel asks for the plugin runtime without throwing, so provider-less renders (its unit tests) omit the slot.

Claims

  • C1 — The toast never names a key or a reason: only counts and the pointer; the reasons are in the view (engine-overlay.test.ts, every announce case).
  • C2 — The view's numbers are the toast's numbers: statusHeadline and attachSummary derive served / declared / gaps / extServed the same way from the same snapshot (status-view.test.ts "counts match the toast").
  • C3 — The snapshot crosses the process boundary: the overlay persists it on every settled attach and the plugin reads the file when its own memory has none (attach-snapshot.test.ts; verified live: the menu row shows the counts in the TUI process).
  • C4 — A stale snapshot is never shown: the menu row, the view and the sidebar all compare the snapshot's workspace id with the current binding.
  • C5 — No network before the menu opens: the Status row's description is computed from the snapshot; the API is read only when the view itself is opened.
  • C6 — Outside workspace mode the boot box is byte-identical: the plugin that fills welcome_extra is registered only under the workspace flag, and an empty slot renders nothing.

Residuals

  • R1 — Custom integrations (numeric ids) are named Integration N: the catalog read is the built-in list; the custom list is a second call not made here.
  • R2 — Headless run prints nothing on a settled attach, as before; the one-line summary is the TUI's.
  • R3 — The sidebar picks the line up on its existing 30 s poll rather than the instant the attach settles.

How did you verify your code works?

  • bun run typecheck clean in packages/opencode, packages/tui and packages/plugin; test/altimate/workspace + test/mcp/engine-unfulfilled.e2e.test.ts: 486 pass (new: attach-snapshot.test.ts, status-view.test.ts, welcome-lines.test.ts; updated: the overlay announce cases, engine-types, the e2e report check); packages/tui welcome-panel.test.tsx still passes without a plugin runtime.
  • Live on a local stack (backend on this machine, workspace with Jira, GitHub, Altimate, Power User and a custom MCP declared): first prompt → toast 2 of 7 integration tools available · 5 need attention. Details: /workspace; snapshot file written; /workspaceStatus 2 of 7 integration tools available · 5 need attention; the view lists GitHub and Jira (no usable connection), the custom and retired integrations (no longer in the catalog), Altimate (available keys), Power User (via VS Code); the sidebar tile shows the same line under the workspace name.

Screenshots / recordings

Terminal captures from the local run (200-column window).

The toast on the first prompt:

Workspace "e2e-demo-live"
2 of 7 integration tools available · 5 need attention. Details: /workspace

/workspace, with the Status row first:

                             Workspace — e2e-demo-live · 0 memories           esc

                             Search

· 3.3s                     ● Status 2 of 7 integration tools available · 5 need a
                             Refresh Pull the workspace's skills and memory into
                             Sync Re-send local memory the workspace never receiv
                             Unlink Detach this project from the workspace.
                             Done Close this menu.

Status:

                             e2e-demo-live · 2 of 7 integration tools         esc
                             available · 5 need attention

                             Integrations
· 3.3s                     ● ○ GitHub 0 of 1 · no usable connection
                                 create_branch no usable connection
                             ○ Integration 1 0 of 1 · no longer in the catalog
                                 demo_tool no longer in the catalog
                             ○ Integration retired-integration 0 of 1 · no longer
                                 retired_tool no longer in the catalog
                             ○ Jira 0 of 2 · no usable connection
                                 jira_get_issue no usable connection
                                 jira_create_issue no usable connection
                             ● Altimate 2 of 2
                                 altimate_analyze_snowflake_query available
                                 altimate_analyze_snowflake_table available
                             ◌ Power User for dbt 0 of 2 · needs a VS Code window
                                 get_projects via VS Code
                                 get_children_models via VS Code

                             Actions
                             Re-read Read the selection and the last attach again

The boot box in workspace mode, before and after the first message (right column):

What is Altimate Code
Altimate Code is a specialized data engineering harness …

Workspace mode · linked to e2e-demo-live
/workspace — status, refresh, sync, unlink · /skills — the workspace's skills
Integrations: attach on your first message
Workspace mode · linked to e2e-demo-live
/workspace — status, refresh, sync, unlink · /skills — the workspace's skills
Integrations: 2 of 7 integration tools available · 5 need attention — /workspace for the reasons

The sidebar's Workspace tile after the attach:

Workspace
e2e-demo-live
2 of 7 integration tools available
· 5 need attention · /workspace

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Generated with Claude Code

https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b


Summary by cubic

Replaces the attach toast’s full engine report with a one-line summary and adds a /workspace Status view for integration details. Attach gaps now come from the engine’s ai.altimate/unfulfilled report, requiring engine version 0.7.2; older engines receive the upgrade offer instead of attaching without gap data. Closes #1307, #1309, and #1311.

Details

  • Commits each MCP listing with its report through MCP.snapshot, counts distinct sanitized tools once, and accepts numeric integration IDs.
  • Persists a bounded attach snapshot per directory so the menu, sidebar, and boot box can share status across processes while ignoring stale workspace bindings.
  • Shows served, partial, missing, and idle integrations with reasons and keys, including snapshot-only rendering when the API is unavailable.
  • Posts one sanitized attach report per distinct outcome without exposing raw engine details.
  • Adds workspace-mode boot box status lines and calls out tools served through a live VS Code bridge.

Written for commit dc155e2. Summary will update on new commits.

Review in cubic

ralphstodomingo and others added 5 commits September 12, 2026 08:17
…clared vs delivered

The MCP catalog now keeps the `_meta` of a server's last tools/list page per client, exposed as
`MCP.listMeta(name)`. On attach, the gaps come from the engine's `ai.altimate/unfulfilled` report,
grouped by reason in the toast and headless line with the engine's detail (e.g. `spawn docker ENOENT`);
`no-bridge` entries stay out of the missing set as before. The attached outcome carries the full
report. `MIN_ENGINE_VERSION` moves to 0.7.2, the first engine that emits it; an engine that sends
none claims no gaps rather than inventing them.

Closes #1307

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
Env-guarded (`ALTIMATE_ENGINE_E2E_ROOT`), skipped otherwise: spawns a built engine over stdio the way
the overlay does, against a fake Altimate API and a real second MCP server, and reads the
`ai.altimate/unfulfilled` report through `MCP.listMeta` into the attach toast text. The engine is a
node shebang script, so the test spawns node rather than the bun test runner.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
Marker Guard flagged the changed lines in the upstream-shared catalog; the single-line marker
comments did not count as a wrapped block.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
Custom (tenant-created) integrations carry numeric ids; the parser treated the whole report as
malformed over that one field and the attach announced no gaps at all. Take the id as a string.
Found by the engine-to-CLI run against a local backend with a custom MCP integration.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…ome settles

When an attach settles — attached, engine missing, engine too old, or the engine failed to
start — the CLI posts what the session received to the backend: binding identity (the same
remote or path the server row holds), CLI and engine versions, bridge state, declared and
delivered keys, and the engine's unfulfilled report. Once per distinct report, fire-and-forget,
never on the turn's path. Engine detail strings never leave the machine: each is reduced to a
code plus, for spawn failures, the command's basename.

Closes #1309

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
@ralphstodomingo ralphstodomingo self-assigned this Sep 14, 2026
@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ralphstodomingo
ralphstodomingo changed the base branch from feat/workspace-followups to feat/workspace-sidebar-status September 15, 2026 07:58
@sahrizvi
sahrizvi force-pushed the feat/workspace-sidebar-status branch from 313a808 to c6f2d15 Compare September 15, 2026 09:53
Ralph Sto. Domingo and others added 4 commits September 15, 2026 17:57
…at/workspace-status-dialog

Rebuilt on 1279's rebased head (main + the 1278 squash): 1310, which carries 1308, merged first; this branch's own commits follow.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…for the detail

The attach toast carried the whole engine report — every undelivered key
grouped by reason, with the engine's detail — and on a workspace with a few
gaps it read as noise (review of the first cut, #1311). Numbers belong in the
toast; the keys and reasons belong somewhere they can be read again.

- The toast says `2 of 9 integration tools available · 7 need attention.
  Details: /workspace` and nothing more; extension tools a live bridge serves
  add `· N more via VS Code`. `describeMissing` / `describeExtensionServed`
  go; `reasonPhrase` keeps the wording for the view.
- The overlay keeps an attach snapshot per directory — workspace, engine
  version, the allowlist, what the engine served, its report — in memory and
  in `altimate-attach-snapshots.json` under the state directory, because the
  TUI plugin runs in another process than the overlay (the same reason the
  binding cache is a file). Bounded to 64 directories; a test seam keeps the
  suite out of the real state directory.
- `status-view.ts`, transport-agnostic like `manage.ts`: the snapshot joined
  to the workspace's selection and the catalog, one row per integration —
  served / partial / missing with reasons / idle for an extension without a
  window — attention first, keys beyond the allowlist as extras, and the
  headline the toast, the menu row and the sidebar share.
- `/workspace` gains a Status row (its description is the headline, read from
  the snapshot so the menu opens without a network call) that opens the
  view: one row per integration with counts and the reason, the keys and
  reasons as the row's footer, and "Open on the web" / "Re-read" / "Done"
  as action rows. A snapshot from a workspace this project was since
  re-linked away from is ignored.
- The sidebar's Workspace tile shows the headline under the name once a
  session has attached, with the same staleness guard.

Tests: the snapshot file round-trip, cap and corrupt-file recovery; the
status view (rows, ordering, name fallback, counts matching the toast,
partial and bridged states, reports for integrations no longer selected,
no allowlist); the overlay's toast wording, snapshot and persistence; the
e2e engine report checked through `reasonPhrase`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
The plugin's DialogSelect renders an option's footer inline with its title,
which left three characters of "Altimate", and it filters `disabled` rows
out entirely, so the keys under each integration never appeared. The keys
are now ordinary indented rows — choosing one keeps the view open — and the
engine version moves off the title (which wrapped) onto the Re-read row.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…e mode

Under "What is Altimate Code", three lines that only exist in workspace
mode: the mode and the workspace this project is linked to, the slash
commands the mode adds (/workspace, /skills), and what the last session
got from the workspace — "attach on your first message" before one, the
toast's numbers with a pointer at /workspace after.

- A `welcome_extra` slot inside the boot box (medium and full variants);
  the panel asks for the plugin runtime without throwing, so its unit tests
  and any provider-less render simply omit the slot.
- `welcome-lines.ts`: the three lines as a pure function of the binding and
  the attach snapshot (unlinked, linked-before-a-session, after a session,
  and a snapshot from another workspace ignored), tested.
- `workspace-welcome.tsx`: the plugin that fills the slot, registered only
  under the workspace flag like the sidebar tile, reading the two cache files
  on a short poll so the integrations line follows the attach.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
@ralphstodomingo
ralphstodomingo force-pushed the feat/workspace-status-dialog branch from 191c091 to a34daca Compare September 15, 2026 10:00
Ralph Sto. Domingo and others added 14 commits September 15, 2026 18:06
…nto feat/workspace-status-dialog

Picks up 1279's review fixes: no notification on a failed cache write, poll ticks dropped mid-refresh, status reuses the resolved binding.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…hat a gap is with its own detail

Answers the multi-model review of the unfulfilled report, client half.

- the tools of a listing and its _meta are committed in one statement (State.meta beside State.defs) and read through one accessor, MCP.snapshot(name): a refresh that is pending or that failed leaves the last good pair standing, and the overlay can no longer pair one listing's tools with another's report
- the catalog commits _meta when a listing completes — the last page that carries one wins, a listing with none clears it — instead of clearing at the start
- served counts compare the declared keys in the catalog's sanitised key space, so the headline cannot undercount a served tool whose raw key the MCP layer renamed
- the missing line groups by reason AND integration, so one integration's error is never printed as another's
- spawn-failed reads 'server could not be started or reached', which is what the engine records under it

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
… feat/attach-report-post

Picks up the multi-model review fixes on the unfulfilled report: tools and _meta committed together (MCP.snapshot), sanitised served counts, per-integration gap details, the spawn-failed phrase.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…at/workspace-status-dialog

Carries 1308's review fixes through 1310. This branch keeps its own presentation (reasonPhrase and the Status view; no describeMissing), so the conflicts resolve to this side; the spawn-failed phrase and the sanitised served counts are taken up here too, in the welcome lines, the status view, the sidebar and the attach report.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…er counts a reported key

Answers the Codex round on the report fixes:
- McpCatalog.defsWithMeta returns the listing and its _meta as one value, and every commit of a listing stores that pair — not a per-client value another refresh may have overwritten while this one was awaiting
- served counts exclude keys the engine reports unfulfilled, so two raw keys that sanitise to one catalog name cannot both count as served
- parseUnfulfilled rejects an entry whose detail is present but not a string, failing closed like the other fields

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
… feat/attach-report-post

Picks up the Codex round on the report fixes: a listing carries its own _meta, the headline never counts a reported key, and a malformed detail fails the report closed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…at/workspace-status-dialog

Carries 1308's Codex round through 1310, and applies its rule here too: a served count never includes a key the engine reports unfulfilled — in the welcome lines, the status view, the sidebar and the attach report. The merged headline test is restated for this branch's one-line toast, whose 'needs attention' now agrees in number.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
Two raw keys that sanitise to one catalog name are one callable tool however many the engine lists; served and extension counts are the number of distinct sanitised entries that are present and unreported.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
… feat/attach-report-post

Picks up the per-entry served count from 1308's final Codex round.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…at/workspace-status-dialog

Carries 1308's final Codex round: served counts are per catalog entry, here too in the welcome lines, the status view and the sidebar. The merged collision test is restated for this branch's one-line toast.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…nd extension groups

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
… feat/attach-report-post

Picks up the cross-group collision count from 1308's last Codex round.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…at/workspace-status-dialog

Carries the cross-group collision count from 1308's last Codex round; the merged test is restated for this branch's one-line toast.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
Ralph Sto. Domingo and others added 5 commits September 15, 2026 21:40
… feat/attach-report-post

Marker wrap only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…at/workspace-status-dialog

Marker wrap only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…w as bare

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
… feat/attach-report-post

Marker wrap only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
…at/workspace-status-dialog

Marker wrap only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHBUvb843k1R7UAGi8Ya9b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant