Bug
The ServerStatus component in apps/web/src/app/server-status.tsx renders an OpencodeSSRPlugin with directory: "":
<OpencodeSSRPlugin
config={{
baseUrl: "/api/opencode",
directory: "", // No specific directory for global operations
}}
/>
This sets window.__OPENCODE = { baseUrl: "/api/opencode", directory: "" }. When the user navigates to a session page, if the URL doesn't include ?dir= or the session page's own OpencodeSSRPlugin doesn't render (guarded by {directory && ...}), the config retains directory: "".
Impact
All hooks that look up store data by cfg.directory (like useMessages, useMessagesWithParts) query state.directories[""], but SSE events store data under the real directory path (e.g., "/Users/user/project"). This causes:
- Initial messages don't hydrate —
hydrateMessages stores under the real directory, hooks look under ""
- New messages never appear — SSE updates go to one store key, UI reads from another
- No
x-opencode-directory header sent — empty string is falsy, so createOpencodeClient skips setting the header
Additional: directory is required in OpencodeConfig
OpencodeConfig requires directory: string (non-optional), making it impossible to render the plugin without a directory. It should be optional so the session page can override the ServerStatus default even when the directory isn't available from the URL.
Fix
- Make
directory optional in OpencodeConfig
- Always render
OpencodeSSRPlugin in the session layout to override ServerStatus
- Pass
directory: directory ?? "" to maintain a consistent lookup key
Logs
[useSendMessage] config: {baseUrl: '/api/opencode', directory: ''}
[useSSEEvents] Received event for /Users/drewsepeczi/opencode-vibe : session.status
// Two different keys — data never matches
Bug
The
ServerStatuscomponent inapps/web/src/app/server-status.tsxrenders anOpencodeSSRPluginwithdirectory: "":This sets
window.__OPENCODE = { baseUrl: "/api/opencode", directory: "" }. When the user navigates to a session page, if the URL doesn't include?dir=or the session page's ownOpencodeSSRPlugindoesn't render (guarded by{directory && ...}), the config retainsdirectory: "".Impact
All hooks that look up store data by
cfg.directory(likeuseMessages,useMessagesWithParts) querystate.directories[""], but SSE events store data under the real directory path (e.g.,"/Users/user/project"). This causes:hydrateMessagesstores under the real directory, hooks look under""x-opencode-directoryheader sent — empty string is falsy, socreateOpencodeClientskips setting the headerAdditional: directory is required in OpencodeConfig
OpencodeConfigrequiresdirectory: string(non-optional), making it impossible to render the plugin without a directory. It should be optional so the session page can override the ServerStatus default even when the directory isn't available from the URL.Fix
directoryoptional inOpencodeConfigOpencodeSSRPluginin the session layout to override ServerStatusdirectory: directory ?? ""to maintain a consistent lookup keyLogs