← Corpus / ai-labs / exploration
In-App Agent Chat — As-Built vs. As-Specced (Internal Audit)
Phase 1 deliverable of the agent-harnesses/conversational-UI study plan. The four 2026-05-18 architecture docs got most of the shape right — but reality diverged from the letter of the spec in one load-bearing way: augment-it never built the shared @lossless/in-app-agent package, it built the WorkspaceAdapter pattern directly inside @augment-it/workspace instead. Memopop-native has zero agent code but a proven, generalizable Rust sidecar-dispatcher substrate. Dididecks is untouched. This changes what a cross-product native shell needs to reuse vs. build fresh.
- Path
- explorations/In-App-Agent-Chat-As-Built-vs-As-Specced.md
- Authors
- Michael Staton
- Augmented with
- Claude Code on Claude Sonnet 5
- Tags
- Exploration · Audit · In-App-Agent-Chat · Augment-It · Memopop-Native · Workspace-Pattern · Tauri
In-App Agent Chat — As-Built vs. As-Specced
Phase 1 of ai-labs/context-v/plans/Study-Agent-Harnesses-and-Conversational-UI-Before-Cross-Product-Shell.md. Cites real paths, not paraphrase.
The headline correction
The four 2026-05-18 docs ([[In-App-Agent-Chat-Walking-Skeleton]], [[Slides_Anatomy-of-the-In-App-Agent-Shell]], [[Slides_Per-App-Workspaces-and-the-Chat-as-Optional-Surface]], [[Slides_Agent-Capabilities_Hooking-the-Chat-Surface-into-Memopop]]) specced a shared @lossless/in-app-agent UI package, consumed by every app through a typed WorkspaceAdapter. ai-labs/packages/in-app-agent/ was never created — confirmed empty search of ai-labs/packages/ (only mermaid-js-ai-agent/ and odysseus/ exist there).
But the pattern the package would have enforced — chat is a thin UI consumer, the workspace singleton is the only mutation surface and owns the actual model call — was built, just inlined into augment-it’s own code instead of extracted into a shared package:
augment-it/apps/chat/src/chat-state.svelte.ts:12importsworkspace, ChatProposal, ChatToolCalldirectly from@augment-it/workspace— not from any shared chat package.chat-state.svelte.ts:52callsworkspace.chatTurn({ message, thread_id, context, thread })— the model call itself lives in the workspace package (augment-it/packages/workspace/src/state.svelte.tsandtransport.ts, bothgrep -l chatTurnhits), not in the chat UI.- The chat UI (
ChatSurface.svelte, 224 lines;chat-state.svelte.ts, 154 lines;CharacterCastRow.svelte, 64 lines;ResponseModeRenderer.svelte, 187 lines;PromptDraftPanel.svelte, 92 lines) only renders transcript, character-cast, and response-mode affordances — it holds zero business data, exactly as the Anatomy doc’s Configuration A prescribes.
Correction to the plan’s Context section: augment-it’s chat is not “fully bespoke, ignoring the pattern” — it faithfully implements the workspace/chat split, just as a monolithic per-app implementation rather than the shared-package + adapter-seam shape the spec called for. The WorkspaceAdapter interface itself (subscribe/getSnapshot/invoke/getCapabilityRegistry) was never extracted as a standalone typed contract; augment-it’s chat imports the workspace’s own types (ChatProposal, ChatToolCall) directly.
What this means for a cross-product shell: there is no existing shared adapter interface to reuse as-is. Any new shell either (a) revives the WorkspaceAdapter seam properly this time — extracting it from augment-it’s working code rather than re-speccing from scratch — or (b) accepts that each backend gets its own bespoke thin client inside the new shell, same as augment-it did internally. Phase 3 (synthesis) should decide this explicitly rather than assume the spec’s abstraction still holds.
memopop-native: zero agent code, but a proven, generalizable substrate
Confirmed via find memopop-ai/apps/memopop-native/src -iname "*agent*" -o -iname "*capabilit*" -o -iname "*chat*" → no results. The “memopop adaptation” walking-skeleton doc ([[Slides_Agent-Capabilities_Hooking-the-Chat-Surface-into-Memopop]]) was written and never executed.
What is real and working, per src-tauri/src/lib.rs (39 lines) and src-tauri/src/api/:
lib.rs:11registers a singleapi::sidecar::SidecarManageras managed Tauri state, and wires exactly one IPC command:api_dispatch(lib.rs:32, defined inapi/router.rs, 216 lines). This is a generic JSON-RPC-shaped dispatcher, not one Tauri command per capability — directly relevant to a shell that needs to add capabilities per-context without touching the Rust binary’s command surface.lib.rs:18-27handles bothCloseRequestedandDestroyedwindow events to callmanager.shutdown()— the fix for a real incident (a stale Python sidecar surviving a closed window, “the bug that wasted hours of runtime” per the inline comment atlib.rs:20).api/sidecar.rs(215 lines):ensure_running()(:49) always probes/healthzfirst (:60) before deciding to spawn — self-healing against a dead-but-still-tracked child — then spawns{repo}/.venv/bin/python -m src.serverand polls/healthzon a deadline (:100-121).forward()(:121) proxies requests to the sidecar.find_venv_python()(:200) locates the orchestrator’s venv from a user-anchored path chosen once during onboarding.api/queries.rs(528 lines) andapi/actions.rs(140 lines) are the read/write split on top of the dispatcher — queries hit the sidecar’s FastAPI routes, actions mutate.
What this means for a cross-product shell: the SidecarManager pattern (lazy-spawn, healthz-probe-before-respawn, forward-by-proxy, clean shutdown on both close events) is transport-agnostic — it doesn’t know or care that the backend is memopop’s orchestrator specifically. Generalizing it to point at a different backend (augment-it’s Node services, dididecks’ SvelteKit API routes) per active context is plausible without a rewrite: the forward() proxy and find_venv_python-style path resolution would need to become per-context config rather than hardcoded to one repo, but the shape holds. This is the strongest argument for extending memopop-native rather than starting a new Tauri app from zero, matching what the user confirmed in-session.
dididecks-ai: fully greenfield
Confirmed via find dididecks-ai -iname "*chat*" -o -iname "*agent*" → only unrelated deck content about “agentic” topics (client-site slide decks), zero implementation. No prior art to reconcile here; a cross-product shell that adds dididecks as a context is building that integration from scratch regardless of which shell-hosting decision Phase 3 makes.
Net effect on Phase 3 (synthesis)
Three concrete inputs the synthesis doc must resolve, now that they’re grounded rather than assumed:
- Adapter seam: extract a real
WorkspaceAdapter-shaped interface from augment-it’s workingchatTurn()contract (proven in production use), rather than re-deriving one from the unbuilt spec. - Host substrate:
memopop-native’sSidecarManager+ single-dispatcher-command pattern is the one piece of native-shell plumbing already de-risked in this tree — generalizing itsforward()/find_venv_pythonconfig to be per-context (augment-it / dididecks / memopop) is the concrete engineering task if Phase 3 picks “extend memopop-native.” - dididecks integration is greenfield either way and shouldn’t anchor the host-substrate decision.
Related
ai-labs/context-v/plans/Study-Agent-Harnesses-and-Conversational-UI-Before-Cross-Product-Shell.md- [[In-App-Agent-Chat-Walking-Skeleton]]
- [[Slides_Anatomy-of-the-In-App-Agent-Shell]]
- [[Slides_Per-App-Workspaces-and-the-Chat-as-Optional-Surface]]
- [[Slides_Agent-Capabilities_Hooking-the-Chat-Surface-into-Memopop]]
augment-it/apps/chat/src/chat-state.svelte.ts,augment-it/packages/workspace/src/memopop-ai/apps/memopop-native/src-tauri/src/lib.rs,src-tauri/src/api/{sidecar,router,queries,actions}.rs