Atlassian Rovo Dev authentication plugin for OpenCode, plus an optional local
runtime proxy that exposes an OpenAI-compatible /v1/* API on top of Rovo Dev
serve mode.
This project is for people who want to use Rovo Dev credits/models through an OpenCode-compatible workflow without building a separate provider integration from scratch.
- An OpenCode plugin exported from
dist/index.js - A local Bun entrypoint (
rovodev-proxy.ts) - A runtime layer under
src/runtime/that:- accepts OpenAI-compatible requests
- normalizes request bodies from OpenCode
- forwards them to
acli rovodev serve - translates streamed output back into OpenAI-compatible response shapes
Supported local endpoints:
GET /healthGET /healthcheckGET /v1/modelsPOST /v1/chat/completionsPOST /v1/responses
Use this project if you want to:
- run Rovo Dev locally and route OpenCode traffic into it
- expose a local OpenAI-compatible endpoint for OpenCode
- experiment with a runtime compatibility layer instead of a direct provider API
This project is not a hosted service. It is a local development utility.
OpenCode
-> plugin (src/plugin.ts)
-> local runtime server (rovodev-proxy.ts + src/runtime/server.ts)
-> backend driver (src/runtime/backend/rovo-serve-driver.ts)
-> Atlassian Rovo Dev serve mode (acli rovodev serve /v3/*)
Read this before using the plugin.
- The backend is still
acli rovodev serve, not a native OpenCode runtime. - The runtime is text-first. Non-text multimodal parts are not forwarded.
- Unsupported tool-calling fields are stripped conservatively.
- Usage/token accounting is synthetic where Rovo serve mode does not expose reliable values.
- The backend behaves like a single active session, so requests are serialized.
- The plugin strips
Authorizationbefore proxying because authentication comes from your local Atlassian CLI session, not from an OpenAI API key. - When OpenCode asks for an API key, any placeholder string is acceptable
(for example
rovodev).
src/runtime/server.ts- HTTP routing
- JSON parsing
- CORS handling
- health endpoints
src/runtime/backend/rovo-serve-driver.ts- request queue
/v3/*transport- busy-session retry flow
- health probe
src/runtime/openai/chat.ts/v1/chat/completions- streaming and non-streaming response shaping
src/runtime/openai/responses.ts/v1/responses- streaming and non-streaming Responses API shaping
src/runtime/openai/models.ts/v1/models
src/runtime/session/message-compiler.ts- message normalization
- prompt compilation
src/runtime/session/response-builder.ts- shared usage and finish-reason policy
src/runtime/session/output-guard.ts- suppresses clearly internal narration preambles before returning text
src/runtime/stream/*.ts- SSE parsing and mapping
src/runtime/policy/*.ts- model list and backend capability policy
You need all of the following:
- Node.js
>= 20 - npm
- Bun
- Atlassian CLI (
acli) - a working Rovo Dev login/session in the Atlassian CLI
Clone the repository and install dependencies:
npm ciBuild the plugin/runtime output:
npm run buildThe helper script does two important Windows-specific things:
- starts
acli rovodev servefrom this repo directory so Rovo Dev does not default toC:\Users\...as the workspace - forwards a detected
git.exeinto the child process PATH to reducegit-aiwarnings when Git is installed outside standard locations
Optional verification:
npm run typecheckThe build output goes to dist/.
Default Rovo Dev port used by this repo: 8123
acli rovodev serve 8123 --disable-session-tokenIf this command is not healthy, the proxy will not work.
Default proxy port used by this repo: 4100
bun rovodev-proxy.tsOr choose explicit ports:
bun rovodev-proxy.ts --rovodev-port 8123 --proxy-port 4100On Windows, you can use:
start-rovodev.batThe helper script starts Rovo Dev serve mode from the repository directory,
forwards Git into the launched shell, and then starts the local proxy. This is
useful because running acli rovodev serve from the wrong working directory can
produce Git/workspace warnings in Rovo Dev.
Check that the proxy is up:
curl http://localhost:4100/health
curl http://localhost:4100/v1/modelsExpected outcomes:
/healthresponds successfully/v1/modelsreturns the availablerovodev-*model ids
This package exports the OpenCode plugin from dist/index.js.
Exact plugin-loading details can vary by OpenCode version, but these values are the important constants exposed by this project:
- Provider id:
atlassian-rovodev - Auth label:
Rovo Dev (Local Proxy) - Proxy base:
http://localhost:4100 - OpenAI-compatible API base:
http://localhost:4100/v1
- The provider should target
http://localhost:4100/v1 - Compatibility mode should be OpenAI-compatible / compatible
- Model ids must match the values returned by
GET /v1/models - If OpenCode asks for an API key, enter any placeholder value
Use a provider entry equivalent to the following shape in your OpenCode config:
{
"atlassian-rovodev": {
"npm": "@ai-sdk/openai",
"options": {
"baseURL": "http://localhost:4100/v1",
"compatibility": "compatible"
},
"models": {
"rovodev-auto": {
"name": "Rovo Dev (Auto)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text"], "output": ["text"] }
},
"rovodev-claude-sonnet-4-5": {
"name": "Claude Sonnet 4.5 (Rovo Dev)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
},
"rovodev-claude-haiku-4-5": {
"name": "Claude Haiku 4.5 (Rovo Dev)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text", "image"], "output": ["text"] }
},
"rovodev-claude-sonnet-4": {
"name": "Claude Sonnet 4 (Rovo Dev)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
},
"rovodev-claude-sonnet-4-6": {
"name": "Claude Sonnet 4.6 (Rovo Dev)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text"], "output": ["text"] }
},
"rovodev-gemini-3-flash-preview": {
"name": "Gemini 3 Flash (preview) (Rovo Dev)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text"], "output": ["text"] }
},
"rovodev-gpt-5": {
"name": "GPT-5 (Rovo Dev)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text"], "output": ["text"] }
},
"rovodev-gpt-5-1": {
"name": "GPT-5.1 (Rovo Dev)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text"], "output": ["text"] }
},
"rovodev-gpt-5-2": {
"name": "GPT-5.2 (Rovo Dev)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text"], "output": ["text"] }
},
"rovodev-gpt-5-2-codex": {
"name": "GPT-5.2-Codex (Rovo Dev)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text"], "output": ["text"] }
},
"rovodev-gpt-5-4": {
"name": "GPT-5.4 (Rovo Dev)",
"limit": { "context": 200000, "output": 64000 },
"modalities": { "input": ["text"], "output": ["text"] }
}
}
}
}Current /v1/models output includes:
rovodev-autorovodev-claude-haiku-4-5rovodev-claude-sonnet-4rovodev-claude-sonnet-4-5rovodev-claude-sonnet-4-6rovodev-gemini-3-flash-previewrovodev-gpt-5rovodev-gpt-5-1rovodev-gpt-5-2rovodev-gpt-5-2-codexrovodev-gpt-5-4
These names correspond to the current Rovo Dev model list shown in the UI:
- Claude Haiku 4.5
- Claude Sonnet 4
- Claude Sonnet 4.5
- Claude Sonnet 4.6
- Gemini 3 Flash (preview)
- GPT-5
- GPT-5.1
- GPT-5.2
- GPT-5.2-Codex
- GPT-5.4
rovodev-auto is kept as a local convenience alias for OpenCode-side selection.
Use this order every time:
npm run buildacli rovodev serve 8123 --disable-session-tokenbun rovodev-proxy.tscurl http://localhost:4100/health- open OpenCode and use the
atlassian-rovodevprovider - select one of the
rovodev-*models - enter a placeholder API key if prompted
The runtime applies a small output guard to assistant text before returning it to OpenAI-compatible clients.
- Leading internal narration such as
let me review/let me inspectstyle preambles is suppressed when it appears before the real answer. - Ordinary answers pass through unchanged.
- If a reply consists only of suppressed narration, the returned text is an empty string.
This is meant to reduce obvious backend work-log narration leaking into the final user-visible response.
Install dependencies:
npm ciTypecheck:
npm run typecheckBuild:
npm run buildImportant notes:
dist/is generated output, never hand-edit it- the project uses ESM (
"type": "module") - relative TypeScript imports use
.jsextensions intentionally rovodev-proxy.tsis run by Bun and is not included intsconfig.json
- confirm
acli rovodev serve 8123 --disable-session-tokenis running - check
curl http://localhost:8123/healthcheck - restart the proxy after restarting serve mode
- start Rovo Dev from the repository directory, not from your home directory
- on Windows, prefer
start-rovodev.bat - if an old process is still running on port
8123, stop it and restart with the helper so the correct working directory and Git path are used
- change proxy ports with
--proxy-port - change backend serve port with
--rovodev-port - if you change the proxy port, also update
PROXY_BASEinsrc/plugin.tsand rebuild
This is expected sometimes. The runtime serializes requests because Rovo Dev serve mode behaves like a single active agent session.
This runtime currently forwards text-oriented content only. Images and PDFs may be represented only by whatever text survives request normalization.
That is an architectural limitation of the current backend path. This repo makes OpenCode talk to Rovo Dev through a compatibility runtime, but the upstream runtime is still Rovo Dev serve mode.
- The proxy is intended for local development
- It allows cross-origin requests
- It does not implement its own authentication layer
- Do not expose it to untrusted networks
MIT (see package.json#license)