Skip to content

Remote agents: support long-lived hosts alongside ephemeral substrates (and let the model picker see them) #5282

Description

@j-goodz

Duplicate search: nothing found covering persistent-host remote agents. Closest related work I could find is #4289 (Kubernetes backend plugin, merged), #3748 (remote agent spec), and open PRs #5088 (harden Kubernetes persistence) and #5084 (discover remote channel agents). Happy to be pointed elsewhere if this belongs on one of those.

Summary

VISION_REMOTE_AGENTS.md frames the agent body as disposable:

workspace files, checkouts, and session-local state are part of the body, not the agent, and they go when it goes unless the substrate supplies persistence

That is the right default, and the Kubernetes path fits it well. This issue is about the case it does not serve: a project whose working directory is not incidental to the agent, but is the thing the agent works on.

The case

I run several projects across a small fleet — a VPS, a home server, a workstation. Some of those projects live on exactly one machine and cannot meaningfully move:

  • the repository and its supporting files are there,
  • the machine has network reachability the project depends on (private services, other daemons, credentials scoped to that host),
  • the tree is large enough that cloning it per-session is not a sane per-invocation cost.

For those, "fresh compute, same agent" is not equivalent. If the brain of the project is on one host, the session belongs there too. Cloning a large tree onto a disposable pod that cannot reach what it needs is not a substitute for running where the project already is.

This is not an argument against ephemerality — it is an argument that which machine should be a per-agent choice rather than a property of the deployment mechanism.

What works today, and what does not

I run remote agents by defining a custom harness whose command is ssh <host> … opencode acp, with a small wrapper on the remote host that reads env vars forwarded over ssh. That works: the agent runs on the right machine, in the right directory, with the right tools.

Two rough edges:

1. Model discovery is local-only. discover_agent_models resolves the agent binary against the local filesystem and PATH (resolve_commandpath.exists() / local PATH scan) and spawns it locally to enumerate models. For a harness whose command is ssh, there is no local binary to interrogate, so the model picker comes up empty and no model can be selected in the UI.

Execution is already transport-agnostic here — only discovery assumes locality. Running discovery through the same command the harness uses would close the gap.

Workaround: opencode reads opencode.json from its working directory, so the model, MCP servers and plugins can be supplied by the project directory instead of the picker. Verified: an MCP server defined in a directory's opencode.json is listed when opencode runs from that directory and not otherwise. It works, but it means the UI shows nothing where a user would reasonably expect to choose.

2. Working directory is not first-class. Nothing in the agent model expresses "run in this directory on this host", so I pass it as an env var (ACP_FORCE_CWD) forwarded over ssh and interpreted by my wrapper. Each new variable needs both a SendEnv in the harness and an AcceptEnv on the target host, so the mechanism does not generalise well.

Note that kind:30179's PrivateConfig already carries env_vars and agent_args as first-class fields, so much of this may fall out naturally — this issue is partly asking whether that is the intended path.

What I am asking

  1. Is a persistent-host substrate in scope for the remote-agent design — an agent pinned to a machine, in a directory, rather than deployed to disposable compute? If so I would like to help build it.
  2. Should model discovery run through the harness command rather than resolving locally? That looks like a contained fix and would make any remote harness usable from the UI.
  3. Is working directory intended to become first-class via kind:30179's env_vars, or is something else planned?

Prior art I can contribute

I built a session manager (Nexus OCS) that composes what I think of as an agent's makeup: which harness variant, which model or model roster, which MCP servers, which plugins, and which directory on which host. It writes a project directory containing an opencode.json plus a manifest, then launches into it — so the makeup travels with the directory rather than living in a command line, which is what makes the same session reproducible from Buzz.

Three things fell out of building it that may be useful input regardless of what you decide here:

  • The makeup is a directory, not a command line. The launch command is nearly empty (opencode --model X); everything meaningful is the project config it runs against. That composes well with anything that can set a working directory.
  • Multi-model rosters are a real shape. Different harness variants support different numbers of concurrently-configured models (one, a main plus a small/cheap tier, or a larger roster). "One agent, one model" is a limiting assumption for the roster case.
  • Sessions outlive clients. A registry of what a session was is useful independently of which app launched it.

It is a personal tool and not currently public. If any of it is interesting I am happy to open it up, extract the parts that are useful, or just describe the design in more detail — whichever is most helpful.

Environment

Windows 11 desktop; remote hosts are Linux (a VPS and a home server) reached over ssh with a self-hosted relay.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions