a plugin declares its chat directory; email stops being hardcoded here

ChatPanelWrapper had one plugin's screen id compiled into a shared platform
package: `workspace.id === 'email'` → `{ context: 'email' }`. its own comment
said the general fix was a way for a plugin to DECLARE its chat context, and
that a second hardcoded id would be the signal it was needed. that fix exists
(`declared`), the email plugin now passes it, so the branch is gone.

it also could not fire any more, which is the part worth keeping. a plugin's
workspace key is `screens/plugin/<name>`, so email's id became `plugin/email`
the day it was extracted and the test silently stopped matching. a hardcoded id
does not fail loudly when the thing it names moves — it just stops being true,
and nothing said so for eight days.

two things on the backend half:

resolveEmailCwd now installs the email plugin's chat/CLAUDE.md. an email chat
runs in the account's directory, not the plugin's chats directory, so the
`plugin` branch never reaches it — the brief follows the chat rather than the
chat moving to the brief. a second plugin wanting this is the signal that
"which directory does this chat run in" belongs in the manifest.

and it verifies the mailbox exists before joining it. `accountEmail` comes from
the client (the mailbox picker's `?account=`) and this function ends in mkdirSync
— so an unrecognised value did not fail, it CREATED a directory named after
whatever arrived and ran the turn in it. the list's unified view uses the
sentinel `all`, which is the value most likely to show up by accident. the panel
drops it; this is the half that does not depend on the panel remembering to.

docs/claude-md-touchpoints.md updated: the copier now has two callers.

unrelated and NOT from this change: ModelSelector's "an unstarted composer gets
a default" fails on master too — verified by stashing these files and rerunning.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
2026-08-26 18:43:13 +00:00
co-authored by Claude Opus 5
parent d58652bf14
commit be210c3ed4
3 changed files with 77 additions and 51 deletions
@@ -203,24 +203,21 @@ export const ChatPanelWrapper = ({
// `contextId` stays the raw workspace key: it is the same string `agent_panels.dashboard_id` holds, and
// a stored address should not be two different strings depending on which feature wrote it. The bare id
// is for deciding, which is what `kind` and `id` are doing above it.
// `'email'` is a PLUGIN's screen id, hardcoded in a shared platform package, and it is the one piece of
// plugin vocabulary the extraction on 2026-08-18 could not remove.
//
// It is the frontend half of a pair: this sends `context: 'email'`, and the chat socket answers it by
// running the turn in that mailbox's directory (`resolveEmailCwd`). The backend half carries its own
// justification; this line is recorded here so the coupling is visible from both ends rather than only
// one. If the email plugin is not installed, no workspace has this id and the branch is simply never
// taken — it fails to nothing rather than to an error.
// There WAS a third branch here — `workspace.id === 'email'` → `{ context: 'email' }` — one plugin's
// screen id hardcoded in a shared platform package. Its own comment said the general fix was a way for a
// plugin to DECLARE its chat context, and that a second hardcoded id would be the signal it was needed.
// `declared` is that fix, and the email plugin now passes it, so the branch is gone.
//
// The general fix is a way for a plugin to declare a chat context, which does not exist. Until it does,
// adding a SECOND id here is the signal that it needs to.
// It also could not fire any more, which is the part worth keeping: a plugin's workspace key is
// `screens/plugin/<name>`, so email's id became `plugin/email` the day it was extracted and the test
// silently stopped matching. Every email chat since ran with no mailbox anywhere near it. A hardcoded id
// does not fail loudly when the thing it names moves — it just stops being true.
const chatContext = declared
? declared
: workspace?.kind === 'screen' && workspace.id === 'email'
? { context: 'email' as const }
: workspace?.kind === 'dashboard'
? { context: 'dashboard' as const, contextId: workspace.key }
: {};
: workspace?.kind === 'dashboard'
? { context: 'dashboard' as const, contextId: workspace.key }
: {};
const agentPanel = useAgentPanel(panelId);