Skip to content

OpenCode Agent ​

OpenCode is ALIDA's operational agent. It exposes APIs and SSE streaming, and can be specialized for a domain through a discovery dataset.

OpenCode workflow with MCP services

Inputs: datasets and MCP servers ​

TIP

You can connect OpenCode to both datasets, which specialize the agent with instructions, skills, and tools, and remote MCP servers, which provide additional capabilities. Both are configured as input ports of dataset type, and the agent accepts multiple ports.

Dataset ​

During startup, OpenCode downloads the dataset and merges its files into /opencode, keeping their relative paths. To specialize the runtime, provide a dataset for the target domain.

The port is passed as --input-dataset (or --input-dataset-N for additional ports) with the S3 prefix, together with .s3_bucket, .s3_URL, .s3_ACCESS_KEY, .s3_SECRET_KEY and the optional .s3_REGION (default garage) and .use_ssl suffixes. Startup fails if a prefix contains no files.

A typical dataset structure is:

text
AGENTS.md
opencode.json
agents/
  domain-expert.md
skills/
  domain-workflow/
    SKILL.md
tools/
  domain-tool.ts
plugins/
  domain-plugin.ts
init.d/
  ...
reference-documentation.md

The structure is entirely optional: you do not need to create or fill every folder. Include only the files you need; because each file is written to /opencode at its own path, a file with the same path is overwritten.

Dataset contents have distinct roles:

  • AGENTS.md contains shared, global instructions that guide the main agent and subagents.
  • opencode.json is the OpenCode configuration: model and providers, local MCP servers, permissions, and instruction files. At startup it is extended with the MLflow plugin and the remote MCP servers connected as input ports. For more details, see Config | OpenCode.
  • agents/ contains Markdown files, one for each specialized subagent. Each file defines its role, expertise, and operating instructions, for example for a domain expert. For further examples of defining a subagent, see Agents | OpenCode.
  • skills/ contains reusable procedures. Each skill has its own folder and a SKILL.md file describing when to apply it and which steps to perform. For more details, see Agent skills | OpenCode.
  • tools/ contains custom tools the agent can invoke during a conversation. Tools are defined in JavaScript or TypeScript files and can run domain integrations or scripts. For more details, see Custom tools | OpenCode.
  • plugins/ contains JavaScript or TypeScript plugins that extend OpenCode through event hooks, for example to integrate external services, change agent behavior, or add tools. For more details, see Plugins | OpenCode.
  • init.d/ contains the scaffold copied into the working repository at startup; files already present in the repository are not overwritten. See the Service Writer scaffold for an example.
  • Domain reference documentation remains outside agents/ and is referenced by instructions or prompts as needed.

Prompts, skills, tools, auxiliary agents, and documentation in the dataset determine the agent's actual specialization. The same runtime can therefore be reused in different domains by changing the dataset.

MCP server ​

A port becomes a remote MCP server when --input-dataset-N.metadata holds JSON metadata whose datasetFileType.type is endpoint and whose datasetFileType.details.url is the server address:

text
--input-dataset-2.metadata='{"name":"my-mcp","datasetFileType":{"type":"endpoint","details":{"url":"http://host:8000"}}}'

The server name is the slugified name field, and the URL is normalized to end with /mcp and checked for reachability before being added to the OpenCode configuration. A port with .metadata is never downloaded from S3.

OpenCode can use capabilities provided by an MCP server, including an ADK Agent. However, it cannot be used as an MCP server by ADK.


Example: ALIDA Service Writer ​

For the Service Writer, OpenCode works on a repository associated with the BDA and uses an ALIDA-focused dataset. The workflow generally includes:

  1. defining or updating .alida/spec.md;
  2. reading the relevant documentation;
  3. implementing the Service code;
  4. generating and validating src/arguments.py and meta-model.json;
  5. producing documentation and CI configuration;
  6. testing, committing, pushing, and opening a merge request after the pipeline succeeds.

At startup, OpenCode creates or clones a repository in the BDA namespace and, when MLflow is configured, creates or retrieves the corresponding MLflow experiment. The BDAID maintains the connection between the chat, artifacts, and operating context.

Startup behavior in detail:

  • OpenCode runs in /workspace; the service repository is cloned into /workspace/service, so every service path the agent writes starts with service/.
  • If GIT_URL is set, the repository is cloned and any missing mandatory files are copied into it. No GitLab project is created.
  • If GIT_URL is empty, a GitLab project named after the slugified BDA_ID is created (or reused) in the group identified by GITLAB_GROUP, with default branch GIT_BRANCH or develop. The project is then cloned and, if newly created, seeded with the initial service scaffold.
  • Git authentication uses GITLAB_TOKEN only, over HTTP or HTTPS.
  • If MLFLOW_TRACKING_URI is not set, the MLflow experiment is skipped and the agent runs without the @mlflow/opencode plugin.

Service scaffold ​

The mandatory files come from /opencode/init.d (overridable with INIT_DIR). Each file is copied into the repository only if it does not already exist, so existing files are never overwritten. Because input datasets are merged into /opencode before the repository is prepared, a dataset can provide its own init.d/ to replace the scaffold.

text
.alida/
  spec.md
  iterations.md
src/
  main.py
  arguments.py
  utils.py
tests/
  .gitlab-ci-test.yml
  seed.py
  run_scenarios.py
.gitlab-ci.yml
Dockerfile
docker-compose.yml
documentation.md
meta-model.json
requirements.txt

The scaffold is a placeholder and is neither valid nor runnable as is: meta-model.json has an empty name and url, src/main.py contains no logic, docker-compose.yml has an empty command, and the test files contain FILL markers. An empty name tells the metamodel-writer subagent that the service is new (version 1.0.0). The agent rewrites these files during the operating cycle, and validate-metamodel passes only after that.

ALIDA dataset ​

The dataset determines what the coding agent knows and how it behaves. For the Service Writer, the ALIDA dataset provides ALIDA-specific prompts, skills, and the alida-documentation.md file.

Agent tools and operating cycle ​

The main agent instructed to develop ALIDA services has the following tools:

  • validate-metamodel: validates meta-model.json and its src/arguments.py file against the ALIDA services contract.
  • generate-gitlab-ci: generates the standard ALIDA CI configuration, including the service-registration phase.
  • commit-and-push-service: the only way the agent delivers a service. It embeds documentation.md into meta-model.json:markDown.value (from which the platform obtains the manual displayed in the user interface), sets the version, validates the meta-model and refuses to commit if it is invalid, prepends the changelog entry to .alida/iterations.md, then commits and pushes to feat/<service-name> after confirming the repository matches GIT_URL. There is no standalone documentation-embedding tool.
  • get_useful_info: returns deterministic information about the execution environment, including the current date, the active user and the GitLab project_id.
  • take-a-coffee: waits 10–300 seconds (default 30) between two pipeline checks, so the agent does not exhaust its polling budget while a job is still running.
  • gitlab-mcp: MCP server that lets the agent interact with GitLab. Only these tools are enabled: list_pipelines, get_pipeline, list_pipeline_jobs, get_pipeline_job_output, list_merge_requests, create_merge_request, get_merge_request_conflicts, search_repositories, create_repository.

The ALIDA dataset also ships these skills:

  • write-service-tests: writes the CI end-to-end tests, with a seed and a scenario matrix (one baseline run plus one run per parameter, plus edge cases).
  • brainstorming: turns a vague request into a settled, written specification before development starts.
  • caveman: compressed response mode (lite, full, ultra) that reduces output tokens and persists for the session until turned off.

GitLab permissions

To commit, push, and create branches, the configured GitLab identity needs access to the group where the repository is written, with at least the Maintainer role: the Developer role is not sufficient to create branches.

The operating cycle starts with creating or reviewing .alida/spec.md, then reads ALIDA documentation related to the required integrations. The agent implements the service, delegates the generation of src/arguments.py and meta-model.json to the metamodel-writer subagent, validates the result, and delegates user-facing documentation to the documentation-writer subagent. It then generates CI configuration and writes end-to-end tests. Finally, commit-and-push-service embeds the documentation in the meta-model, records the iteration and publishes the feat/<service-name> branch; the agent waits for the pipeline, polling with take-a-coffee up to 20 times, and, if necessary, fixes pipeline errors. After successful validation, it opens a merge request. Merging into develop or dev starts service build and registration using the provided meta-model.json.

Reference documentation and validation ​

The agent reads ALIDA documentation from a read-only local copy in /opencode/docs, starting from /opencode/docs/index.md. It covers the service layout (core.md), the meta-model (meta-model.md), Spark (spark.md) and the port types in ports/ (dataset, model, stream, generic-io, rest, multiple, monitoring).

The validate-metamodel tool, also run by commit-and-push-service before committing, enforces these rules:

  • meta-model.json must contain name, version, description, accessLevel, mode, url, properties and markDown with its value.
  • name uses lowercase letters, digits and hyphens, cannot start or end with a hyphen, and is at most 30 characters.
  • Property valueType is one of STRING, BOOLEAN, DOUBLE, JSON (there is no INT).
  • At most one property has inputData: true and at most one has outputData: true.
  • Every property except assets must have a matching argument in src/arguments.py.
  • BOOLEAN arguments use type=str2bool (not type=bool nor store_true/store_false), and arguments.py must define str2bool; DOUBLE arguments use type=float or type=int.

Runtime configuration ​

  • The model is set with the OPENCODE_MODEL environment variable (default opencode/musa-spark-1.3-free). A local Ollama provider at http://localhost:11434/v1 is also configured; the openai, gemini and gitlab providers are disabled.
  • At startup, the configuration is extended through OPENCODE_CONFIG_CONTENT with only the @mlflow/opencode plugin (when MLflow is enabled) and the remote MCP servers discovered from the input ports.
  • Permissions: the agent can run shell commands and read any directory, cannot ask interactive questions, and cannot edit /opencode/docs or /opencode/skills. AGENTS.md is always loaded as instructions.
  • OpenCode is served with opencode serve on port 10000 (overridable with OPENCODE_PORT), exposing its APIs and SSE stream. For browser clients that need CORS, the repository includes an optional sse_proxy.js that listens on port 3001 and forwards /sse-proxy?target=<url> as an event stream and /http-proxy?target=<url> as plain HTTP.