Skip to content

feat(studio): align memory settings and fact detail with the prototype - #2222

Merged
peppescg merged 5 commits into
mainfrom
feat/studio-memory-1854
Oct 9, 2026
Merged

peppescg merged 5 commits into
mainfrom
feat/studio-memory-1854

Conversation

@peppescg

@peppescg peppescg commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Closes #1854. Part of #2210 (the prototype is the UI source of truth).

Summary

Studio's memory surfaces now match the design prototype (stacklok/mecatl-prototypes, stack/08-tooling). Everything memory-related lives in apps/web/src/features/memory/.

Settings → Memory is now three cards, as in the prototype:

  • Memory: a read-only On/Off report of the Project memory and Facts about you stores, read from the runtime capabilities. It replaces the old header and its Source/Owner line.
  • Facts about you:
    • States: store off, nothing remembered, loading, load error.
    • "N facts remembered" (no byte size).
    • A sortable Name/Remembers table whose rows open the fact.
  • Consolidate memory: the prototype's card, always shown when the agent reports a target.
    • The store picker uses the shadcn Select (feat(studio): add shadcn primitives from the prototype and upstream shadcn #2211); a target that can't generate is shown as "(unavailable)".
    • Confirms: "Consolidate memory?" and "Apply these changes?".
    • The plan preview ("Keeps … and merges in …" with current values), the outcome notices (still working / try again, no longer valid, view only) and the receipt.

The fact detail page (/workspace/memory?item=<key>, URL unchanged) is a port of the prototype's memory-fact-detail:

  • the back pill, key title, value, and fact rows (Key, Status, Version, Writer, Origin, Source session, Updated);
  • history, newest first;
  • the states "History unavailable from this store/driver", "Memory not found" and "agent can't be reached".

BFF and contract

Consolidation now supports both targets the daemon offers, not only user_model:

  • memoryConsolidationTargetSchema is user_model | project_memory. The generate request takes an optional { target } that defaults to user_model, so existing clients are unaffected.
  • Consolidation capabilities are per target. Generate is gated on the chosen target. Decide is allowed when either target can decide; the daemon still enforces per-plan authority.
  • Plans and receipts carry either target. Unknown targets are rejected (400).

Contracts were regenerated with task studio:generate. The new tests cover project_memory plans, the default target, per-target gating, and receipts for both targets (route, adapter and integration against mecated --mock).

Deviations from the prototype (intentional)

  • Proposal row omitted on the fact detail. Studio's memoryRevisionSchema has no sourceProposalId, and this PR doesn't change the daemon contract.
  • Studio URLs kept: the detail page stays at /workspace/memory?item=…, Source session links to /workspace/chat?sessionId=…, and the back links go to /workspace/settings/memory.
  • Not-found handling: a 404 on the fact shows "Memory not found". A failed index read shows the unreachable message, not "not found".
  • .text-page-title is now an @utility, so a page's own size override (the prototype's 44px key title) wins. Pages without an override are unchanged; the configured-skill detail title benefits too.

Other

  • Test fix: consolidate-memory-card.test.tsx now fakes the BFF via apiClient.setConfig({ fetch }), as src/test-setup.ts prescribes, instead of vi.mock on the query module. The non-isolated vitest setup bypasses vi.mock.
  • No user-docs change: no user-docs/ page describes Studio's memory UI.

Screenshots (before | after | prototype)

"Before" is origin/main. The BFF reads were stubbed in Playwright with fixtures shaped from apps/contracts, because the mock daemon has no memory facts. "Not on origin/main" marks states that only exist after this change.

Settings → Memory
settings memory

Store picker open
store picker

Consolidate confirm
consolidate confirm

Plan preview
plan preview

Apply confirm
apply confirm

Receipt
receipt

Facts about you off
facts off

Fact detail with history
detail history

History unavailable
history unavailable

Not found
not found

Mobile
mobile settings mobile detail

Every state in light and dark (including the empty plan and empty facts) is here.

Verification

Node 26.10.0, pnpm 12.4.2, on the branch rebased onto current main:

  • task studio:lint, task studio:typecheck, task studio:generated-check and task studio:audit pass.
  • task studio:test: web 724 tests, server 187.
  • task studio:test:integration: 8 tests against mecated --mock.
  • STUDIO_REQUIRE_MECATED=1 task studio:browser: 54 journeys.

No Go code changed.

🤖 Generated with Claude Code

peppescg and others added 5 commits October 9, 2026 10:09
The Memory settings section now shows which memory stores the running
agent has, Project memory and Facts about you, as a read-only On/Off
report read from the runtime capabilities. It replaces the section's
icon header, the Source/Owner implementation line, and the consolidation
sentence with the prototype's card and note.

Refs #1854

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 8e493476cd2765aa05966c028e4eb47badfa2b91)
Facts about you is now one settings card with the prototype's states
(store off, nothing remembered, loading, load error), a fact count
without byte sizes, and a sortable Name/Remembers table whose rows open
the fact detail. Consolidation moves below the facts and no longer
disappears when there are none.

Refs #1854

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 6c8e72d824c375fa6d52e491dc687782349018de)
Replace the old "Generate plan" consolidation panel with the prototype's
Consolidate memory settings card: a "Memory to consolidate" picker that
lists unavailable stores disabled, confirm dialogs before generating and
applying, per-change details with current values, open-decision retry
locking, stale-plan notices, and the plain receipt line.

The BFF now consolidates either memory store. The generate route accepts
an optional { target } body (user_model by default, so existing clients
keep working) and gates on that target's own capability; the decide route
admits a plan when any target can decide, leaving per-plan authority to
the daemon. Plans and receipts carry either target.

Refs #1854

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 0854e3b8d4b03e89f21df52ed6c17225be4288b8)
The consolidation card's store picker uses the Select primitive from
#2211 instead of a native select, matching the prototype, and its
buttons drop the 44px minimum height so they line up with the trigger
as in the prototype.

Refs #1854

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Replace the settings-owned "Memory fact" page with the prototype's fact
detail in features/memory: back pill, serif key title, value block,
Details rows, newest-first bounded history (or "History unavailable from
this store/driver."), read-only footer, and the loading, memory-off, not
found (index miss or 404) and unreachable-agent states. The URL stays
/workspace/memory?item=<key>.

Move the Settings → Memory composition into features/memory as
MemorySettingsPage. Register text-page-title with @Utility so a page's
own size override (text-[44px]) wins, as in the prototype. Fake the BFF
over fetch in the consolidation card test instead of vi.mock, which the
no-isolation runner bypassed.

Refs #1854

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@peppescg peppescg self-assigned this Oct 9, 2026
@peppescg
peppescg merged commit aa1979c into main Oct 9, 2026
31 checks passed
@peppescg
peppescg deleted the feat/studio-memory-1854 branch October 9, 2026 08:33
peppescg added a commit that referenced this pull request Oct 9, 2026
Rebasing onto #2222 brought the new features/memory pages, which still
imported errorMessage from knowledge/format and kept an identical local
copy in memory-fact-detail. Both now use lib/error-message. facts-about-you
keeps its own reader because its fallback sentence differs.

Also restore the two describeCron expectations that did not move into
lib/formatters.test.ts, and word the clipboard-unavailable toast for any
copied text rather than only an ID.

Refs #2204

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
peppescg added a commit that referenced this pull request Oct 9, 2026
#2222 added the memory Facts about you table on the retired
ui/sortable-head. It now uses useTableSort and SortableHead from
components/sortable-head, like the skills table.

A new test pins the existing behaviour, and it passes on both the old
and the new head: name ascending by default, a new column starts
ascending, the active column flips, the name tie-break stays ascending,
and aria-sort on each header.

Refs #2204

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@toolhive-release-app toolhive-release-app Bot mentioned this pull request Oct 13, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Studio memory: stores, facts, detail, and consolidation

2 participants