# opencode-inside: a coding agent (opencode) running inside a capsule. # # What this example adds to openrouter-secrets: # - a Dockerfile instead of a ready-made image, for an image with opencode in it # (every FROM, npm and pip version pinned, or `m64 check` blocks it); # - the agent.session kind: a small session API (agent_gateway.py) that m64's # front lets through, for agents and scripts; # - [runtime.app]: opencode's own web UI and API, exposed on a second port, for # people (and `opencode attach`). # The model still runs on OpenRouter, and the key still stays in m64's gate. schema = "m64/capsule@1" description = "opencode inside a capsule: the opencode coding agent in a sandbox, on DeepSeek V4.1 Flash through OpenRouter. Each session gets an empty directory where the agent can write and run code. Shows a Dockerfile, the agent.session kind and [runtime.app]. No GPU." kinds = ["agent.session"] authors = ["motif42"] license = "mit" [hardware] # CPU only. The Dockerfile builds the same on ARM: use "linux-aarch64" there. platform = "linux-x86_64" [runtime] sandbox = "container" # No `image`: m64 builds the Dockerfile in this folder (cached by the capsule's id). gpu = false # The session API (agent_gateway.py) listens here. internal_port = 9500 health = "/health" # The first serve builds the image, which takes minutes; later serves start in ~20 s. expected_load_seconds = 60 # The node user from the base image, not root. user = "1000:1000" # A second, raw port: m64 exposes opencode's own server (web UI, API, SSE, the # terminal's WebSocket) as `app_url`. Unlike the kind routes it is not filtered, # so it has no per-session isolation. [runtime.app] internal_port = 4096 [network] needs = ["openrouter.ai:443"] why = "the model runs on OpenRouter: your prompts and its replies go through openrouter.ai" [secrets] required = ["OPENROUTER_API_KEY"] # opencode.json points opencode at http://openrouter.ai (plain http) with # apiKey "{env:OPENROUTER_API_KEY}". Inside the container that variable is only a # placeholder; m64's gate replaces the header with the real key on the way out. [[secrets.inject]] name = "OPENROUTER_API_KEY" host = "openrouter.ai" header = "Authorization" value = "Bearer {secret}"