Skip to content

Attach to the shared OpenCode service instead of spawning one server per vault #76

Open

Description

@romor001

Proposal: attach to the shared OpenCode service instead of spawning one server per vault

Context

With the OpenCode 2.x fix in #74/#75 the plugin works again, but it still does
what it did in 1.x: it spawns a private opencode serve --port … per vault and
embeds that server's web app.

OpenCode 2 changed that model. serve --service starts one long-lived background
daemon that owns the database, the MCP servers and the per-directory sessions;
the web app is a client of it, and opencode pair / opencode service … exist
to manage and connect to that daemon. Everything the CLI, the TUI and the desktop
app use is served from that one process.

That makes the plugin's private server redundant:

  • Same database anyway. A private serve opened with cwd=<vault> writes to
    the same opencode.db as the service (SQLite in WAL mode). It is not an
    isolated instance, just a second process on the same data.
  • Duplicated runtime. Each private server starts its own copy of every
    configured MCP server and its own watchers, for as long as Obsidian is open.
  • Port and password churn. The plugin invents a port (14096 by default) and,
    since 2.x, its own OPENCODE_SERVER_PASSWORD; those collide with nothing only
    as long as the user does not run their own server on that port.
  • CORS flag dependency. In own-server mode the plugin has to pass
    --cors app://obsidian.md so the renderer may call the API. A service started
    by the CLI does not have that origin configured, which is why plugin-side API
    calls in service mode have to go through node:http instead of fetch.

Proposal

Add a server mode to the plugin settings, default service:

service (proposed default) - attach to the daemon:

  • URL from opencode service status, password from ~/.config/opencode/service.json
    (fallback: opencode service get password).
  • opencode service start if nothing is running (the command is idempotent and
    prints the URL).
  • "Stop" in the panel only detaches; it must never stop the daemon, because
    the user's terminal sessions live in it.
  • Sessions are created with location.directory = <vault root>, so file tree,
    @-mentions, terminal and git stay scoped to the vault.

own - keep today's behaviour (private opencode serve, port/hostname/custom
command settings as they are) for users who deliberately want a separate client,
e.g. with their own OPENCODE_DB.

Vault scoping in the embedded UI

Worth stating explicitly, because it surprised me: the web app is a global
client. Its home screen lists every project known to the server, and there is no
API-level way to scope it to one directory. I checked:

  • the router only knows /, /settings, /connect, /components,
    /new-session, /server/<serverKey>/session/<id> - no project-scoped route;
  • the app's own store (opencode.global.dat:server) has a hidden map, but
    populating it does nothing to the project list.

So the plugin's approach would be: always open a session URL (never the home
screen), and optionally hide the project switcher in the session header via a
single CSS rule on a data-slot hook ("vault focus"). That is cosmetic, not a
sandbox - if you would rather not ship a CSS hack, the alternative is to leave
the switcher visible and live with it.

Open questions

  1. Should service be the default, or opt-in with a one-time notice?
  2. Is "Stop = detach" acceptable semantics, or should the button disappear in
    service mode?
  3. Vault focus as a CSS rule: acceptable, or out of scope?
  4. Anything the plugin must not do while the daemon is shared (e.g. triggering a
    restart, writing config)?

Implementation status

A working implementation exists locally (service discovery via
opencode service status/start, password resolution from service.json with CLI
fallback, detach-only stop, serverMode + vaultFocus settings, tests using a
fake service CLI). It is intentionally not opened as a PR yet - it changes the
default behaviour, so I would like a direction first. Happy to open it as a draft
or to drop parts of it.

Activity

  1. romor001 commented on Nov 4, 2026

    @romor001
    Author

    Fixed in a fork, installable via BRAT: romor001/opencode-obsidian (release v0.3.0, OpenCode 2.x only). PR upstream: #. Root cause was the removed / route plus the new mandatory auth.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions