Author: Mavis (operator panel session 412100071272671)
Date: 2026-07-15
Status: Investigation complete. Awaiting operator decisions before design lock.
avidtech6/oscar-platform, private repo)app/src/modules/oscar-ask-unit/ — 686-line AskUnit.tsx + 570-line AskUnit.css + index.ts. The portable "input bar + answer surface in one component" used across every page. Mantine + IconChevron + Markdown. State machine: idle | working | answer | error.app/src/modules/oscar-credential-surface/ — 6 files. In-memory store keyed by ProviderId (NOT workspaceId — Oscar is single-tenant). Masked after creation. IndexedDB-persisted behind a toggle. Fires 'fvs:credential-removed' CustomEvent for cross-surface sync.app/src/assistant/ResultToast.tsx — reduced to info + error toasts only (5-cap stack, 5s default). The 'result' toast was deleted in v1.3.3; the AI reply lives IN the AskUnit now.app/src/assistant/AssistantDock.tsx — thin coordinator. Owns the AI state machine and exchange bundle. AskUnit is the visual.avidtech6/freshvibestudio, private repo)studio/modules/chat/ — the constitutional chat primitive: ChatFrame (container), MessageStore (per-workspace append-only log + useChat(workspaceId) hook), StreamingClient (Provider → async iterable), InputBar, ModelChip, ModelPicker, Scrollback, TokenCounter, AgentContainer (layer slot). One-directional dependency graph (chat ← agent layers, NEVER chat → layers).studio/modules/credential-surface/ — per-workspace credentials: Record for origin / vibecoder / vibescope / freshcards. In-memory only. Fires 'fvs:credential-removed' so chat can mark in-flight messages orphaned.studio/modules/coder-chat/ — CoderStrip agent layer. Plugs into AgentContainer slot.studio/modules/providers/ — Provider interface (id, label, listModels, createChat). OpenAICompatibleProvider base.studio/modules/chrome/vibe-panel/ — the left chat panel wrapping ChatFrame in FVS.studio/modules/vibecoder/ + studio/modules/vibescope/ — the 2 sovereign workspace modules.avidtech6/freshcards-standalone — Mantine + BlockNote. Has Notifications from @mantine/notifications. No AskUnit, no ChatFrame, no chat/toast story. Mounts FreshCardsProvider → FreshCardsHomeSurface + FreshCardsLeftCurtain.avidtech6/vibecoder-standalone — Mantine + BlockNote + monaco-editor + typescript-language-server. Has Notifications. No AskUnit / ChatFrame. Mounts VibeCoderHomeSurface + 2 curtains.avidtech6/vibescope-standalone — Mantine only. Has Notifications. No AskUnit / ChatFrame. Mounts VibeScopeHomeSurface + 2 curtains.All 3 have @mantine/notifications already in deps. The Notifications provider IS a toast system, but it's a different shape from ResultToast (no input bar, no AI state, no thread bundle).
pact/platform/chat/chat-module.md — Chat Module owns 9 things, doesn't own (a) credentials (b) providers (c) workspace awareness (d) layer-specific tools. One-directional dependency graph.pact/platform/workspace-surfaces/credential.md — credential.surface.workspace-aware.001 enforces Record.pact/platform/ai/providers/providers.md — provider.interface.001 is the only contract.> "I want vibe chat in each standalone, but I don't want it shared across workspaces. And I want standalones to be aware of each other but not share threads."
Reading the code, the actual question is:
What I propose: create a new constitutional module that lives at avidtech6/ai-shell (a NEW repo — a portable AI shell). Both Oscar and the 3 standalones depend on it. FVS Studio optionally depends on it too (drop-in replacement for the existing chat + credential modules).
ai-shell exports:
AskUnit — the visual component (lifted from oscar-ask-unit/AskUnit.tsx)ResultToast — info/error toasts (lifted from assistant/ResultToast.tsx)useThreads(workspaceId) — per-workspace/per-app thread storeuseCredentials(workspaceId) — per-workspace/per-app credential storeuseProviders() — provider registry (lifted from providers/)useChat(workspaceId, options) — send / abort / stream with Provider bindingEventBus for cross-surface events (so the same 'fvs:credential-removed' event works)Shape (per-workspace / per-app):
aiShell.configure({
workspaceId: 'freshcards', // or 'vibecoder' / 'vibescope' / 'oscar' / 'origin'
appId: 'freshcards-standalone', // identifies the standalone
mode: 'standalone' | 'studio', // decides which credential backend to use
crossWorkspaceAwareness: true, // show "other apps exist" hint, don't share threads
providers: [...], // injected from the provider registry
indexedDB: { // optional persistence
name: 'freshcards-ai',
stores: ['threads', 'credentials']
}
})
Cross-app awareness (operator's ask): a small "Workspaces" chip in the top bar of each standalone that shows the OTHER apps (FreshCards, VibeCoder, VibeScope, Oscar, my.freshvibeapps.com, panel) with a one-click link. Threads are never shared. When you click a chip, you navigate to the other app; the chat there is independent. The chip also shows "currently active" if you're in FVS Studio.
The operator said: "when it's no longer stand alone they need to have a shared awareness of each other and a shared workspace I guess."
I read this as: when you put a standalone BACK into FVS Studio, the credential store and thread store should sync from the standalone's local IndexedDB to the FVS PocketBase backend. Not the other way around.
mode: 'studio' → writes go to PB (the existing ai_threads + users collections).mode: 'standalone' → writes go to IndexedDB.mode: 'studio' and PB has threads for this user, the AskUnit shows them; if mode: 'standalone', only local IndexedDB threads are shown.ai-shell module exposes a migrate(fromLocal: boolean) API that flushes local IndexedDB → PB on first launch of the integrated mode.Both Oscar's ResultToast and FVS's notifications serve the same purpose. The ai-shell module should ship:
useToast() hook with push({ kind, title, body }) component that auto-mounts in the standalone's rootEsc to dismiss alldata-testid pattern as Oscar's for parityThe 3 standalones should drop their @mantine/notifications import and use ai-shell's toast. (Keeps the toast UI consistent across all 4 apps.)
ai-shell depFreshCardsApp in mounted in the shell footer (always visible, mobile + desktop) to the rootai-shell depVibeCoderApp in systemPromptBuilder) needs to know which file is open, which cursor position, etc. — plug the CoderStrip from FVS into the AgentContainer slot to the rootai-shell depsystemPromptBuilder needs to know the active layer, the cinema/dev layout, the engine — same AgentContainer slot pattern to the rootoscar-ask-unit → ai-shell (or extract into shared). The Oscar copy is the most mature reference. Lift it verbatim, with the workspaceId/single-tenant adaptations in the same file.oscar-credential-surface with the shared ai-shell/useCredentials. Same single-tenant in-memory store, with the 'fvs:credential-removed' event preserved.assistant/ResultToast with ai-shell/ToastHost. Same shape, same pushToast() API.chrome/vibe-panel/) gets refactored to use the ai-shell AskUnit as the visual, with the panel's chrome around it. The existing ChatFrame is retired.chat/, credential-surface/, providers/, coder-chat/, vibechat-signals/ modules are deprecated in favour of the single ai-shell import.AgentContainer slot in FVS's ChatFrame becomes the AskUnit's built-in extension point (no separate module).ai-shell be a new repo or a module in avidtech6/freshvibestudio?ai-shell code from?ai-shell/ directory@mantine/notifications entirely, use ai-shell/ToastHost only@mantine/notifications for now, add ai-shell/ToastHost alongside@mantine/notifications much today (just Notifications provider mounted) — verify before refactoring1. New repo avidtech6/ai-shell. Oscar moves its oscar-ask-unit + oscar-credential-surface + assistant/ResultToast INTO it. The 3 standalones depend on it via Vite alias (sibling ../ai-shell/src).
2. IndexedDB for both threads and credentials in standalone mode. The IndexedDB schema is the same as PB's ai_threads schema, so the migrate() flush from local → PB on first integrated-mode launch is a straight INSERT loop.
3. The Workspaces chip is static (no unread counts) in v1. Smart in v2.
4. VibeCoder + VibeScope each ship with a single systemPromptBuilder that reads the active file / active layer. No cross-app context — the user types what they need.
5. Toast: drop @mantine/notifications from the 3 standalones entirely, use ai-shell/ToastHost only. The shape is a strict superset of what @mantine/notifications does.
vibecoder + vibescope in FVS mode is already the current behaviour, but in standalone mode each app has its own).