opencode-gitlab-dap
v1.0.0
Published
OpenCode plugin for GitLab Duo Agent Platform (DAP) workflow model discovery and selection
Maintainers
Readme
opencode-gitlab-dap
OpenCode plugin for GitLab Duo Agent Platform (DAP) workflow model discovery and selection.
Overview
This plugin connects OpenCode to the GitLab Duo Agent Platform so users can discover and select workflow models configured for their GitLab namespace. It detects the current GitLab project, queries the DAP API for available models, caches the user's choice per project, and surfaces a TUI selection prompt when multiple models are available.
Architecture
sequenceDiagram
participant TUI as OpenCode TUI
participant Server as OpenCode Server
participant Plugin as gitlab-dap Plugin
participant Cache as GitLabModelCache
participant API as GitLab DAP API
TUI->>Server: POST /plugin/gitlab/discover
Server->>Plugin: route handler
Plugin->>Cache: check cached selection
alt cache hit
Plugin-->>Server: { status: "cached", model }
else no cache
Plugin->>API: detect project + discover models
API-->>Plugin: DiscoveredModels
alt pinned model
Plugin-->>Server: { status: "pinned", model }
else multiple models
Plugin->>Server: askUser via plugin-select bus
Server->>TUI: render selection prompt
TUI-->>Server: user picks model
Server-->>Plugin: selected ref
Plugin->>Cache: save selection
Plugin-->>Server: { status: "selected", model }
else default only
Plugin-->>Server: { status: "default", model }
end
end
Server-->>TUI: JSON responseInstall
This plugin is bundled internally with OpenCode. It is not installed as a standalone package. The plugin entry is registered automatically and exposes routes under the /plugin/gitlab/ prefix.
Configure
Authentication is resolved in this order:
- Request headers (
x-plugin-auth-token,x-plugin-auth-instance) - OpenCode auth store via
input.getAuth("gitlab")(OAuth or API key) - Environment variables as fallback
| Variable | Description | Default |
| ------------------------ | ------------------------------------------------------- | -------------------- |
| GITLAB_INSTANCE_URL | Base URL of your GitLab instance | https://gitlab.com |
| GITLAB_TOKEN | Personal or project access token (when not using OAuth) | -- |
| GITLAB_OAUTH_CLIENT_ID | OAuth application ID for the OAuth flow | -- |
The plugin also reads x-plugin-directory from request headers to scope cache and project detection to a specific working directory.
Routes
All routes are prefixed with /plugin/gitlab.
POST /discover
Detect the GitLab project, query DAP for available models, and return the resolved model or prompt the user to pick one.
Request:
{ "fresh": true }Set fresh: true to clear the cache and re-discover. The body is optional.
Response (pinned):
{
"status": "pinned",
"model": { "name": "Claude 4", "ref": "claude_4" }
}Response (asked then selected):
{
"status": "selected",
"model": { "name": "GPT-5", "ref": "gpt_5" }
}Response (no auth):
{
"status": "no_provider",
"error": "No auth token found"
}Possible status values: pinned, cached, default, selected, dismissed, no_provider, no_models, error.
POST /reply
Save a model selection directly, bypassing the interactive prompt.
Request:
{ "ref": "claude_4" }Response:
{ "ref": "claude_4", "name": "Claude 4" }POST /clear
Clear the cached discovery and selection for the current project.
Response:
trueGET /models
Return the current discovery state without triggering a new discovery.
Response:
{
"models": [
{ "name": "Claude 4", "ref": "claude_4" },
{ "name": "GPT-5", "ref": "gpt_5" }
],
"pinned": null,
"default": { "name": "Claude 4", "ref": "claude_4" },
"switching": true
}Discovery flow
The discover function resolves models through a priority chain:
- No token -- returns
no_providerimmediately. - Project detection -- uses
GitLabProjectDetectorto find the namespace from the working directory. Fails withno_providerif no project is found. - DAP query -- calls
GitLabModelDiscovery.discover()with the namespace GID. Returnsno_modelsif the API returns nothing. - Pinned -- if the namespace has a pinned model, it is saved to cache and returned.
- Cached -- if a previous selection exists in
GitLabModelCache, it is returned. - Asked -- if selectable models exist and nothing is cached, the list is returned with
status: "asked"so the route handler can prompt the user. - Default -- if only a default model exists (no selectable list), it is saved and returned.
- No models -- fallthrough when none of the above match.
Selection flow
When discovery returns status: "asked", the route handler triggers an interactive prompt:
- The
/discoverroute callsaskUser()with the list of models. askUsersends aPOSTto the internalplugin-select/askendpoint on the OpenCode server.- The server forwards the selection prompt to the TUI.
- When the user picks a model, the response flows back through the same path.
- The selected
refis saved viasaveSelection()intoGitLabModelCache. - Subsequent
/discovercalls returnstatus: "cached"without prompting again.
If the user dismisses the prompt, the response is { "status": "dismissed" }.
Develop
Build
npm run buildUses tsup to produce CJS, ESM, and .d.ts outputs in dist/.
Test
npm testRuns Vitest against test/. Watch mode is available with npm run test:watch.
Lint and type-check
npm run lint
npm run type-checkClean
npm run clean