Writing Modules¶
A module is a self-contained directory: a thin declarative module.yml plus a
couple of executables that do the real work. This page shows how to author one.
For where modules fit, see Concepts → Modules.
Anatomy¶
modules/<category>/<name>/
module.yml # metadata + the prompts to collect
install # executable: install packages, write files, export env vars
uninstall # executable: undo what install did
resolve # optional executable: derive container input from host state
<hook> # optional helper scripts (e.g. list-accounts)
- The category is the parent directory name (
cloud,infra,tools,language, or a new one you create). It is purely organisational — the module is identified by its globally uniquename. - To add a module, drop its directory under a category in one of your configured
moduleDirs. The whole tree is bind-mounted read-only into every workspace at/opt/opencode-manager/modulesmirroring thecategory/namelayout.
module.yml¶
module.yml declares only metadata and the values to ask the user for:
name: aws
version: 1
description: Install the AWS CLI and write an isolated profile + credentials.
restartServer: false # see "Server restart" below
key: profile # optional — makes the module multi-instance
prompts:
- name: profile
label: AWS profile name
type: string
required: true
default: default
optionsCommand: list-accounts # host hook to populate choices
- name: region
label: Default region
type: string
default: eu-west-3
- name: secret_key
label: Secret access key
type: secret
Fields¶
| Field | Meaning |
|---|---|
name |
Globally unique module identifier. |
version |
Integer; bump when the module's behaviour changes. |
description |
One line shown in the editor and / filter. |
restartServer |
true (default) if the module touches ~/.env; false if it only writes its own config files. |
key |
Name of a prompt that makes the module multi-instance (one install per distinct value). |
prompts |
The values to collect from the user. |
Prompt types¶
type |
Behaviour |
|---|---|
string |
Free-text input. |
secret |
Masked input; not echoed. |
select |
Single choice from options. |
multiselect |
Multiple choices from options. |
Each prompt supports name, label, type, required, and default. A
select/multiselect prompt may list static options, or populate them
dynamically from the host via optionsCommand (see below).
The install and uninstall scripts¶
These run inside the workspace container as the workspace user (sandboxed),
with passwordless sudo available. They receive each prompt value as an OCM_*
environment variable — uppercased prompt name (e.g. OCM_PROFILE,
OCM_SECRET_KEY).
install should:
- install any packages it needs (
sudo apt-get install ...,npx,uvx, …); - write config files into the home directory;
- export environment variables by appending
export VAR=valueto~/.env(a supervisor process sources it so the variable reaches the OpenCode server).
uninstall must undo exactly what install did.
Make multi-instance scripts instance-scoped by the key. For example the
sshmodule writes~/.ssh/config.d/$OCM_HOST.conf, so multiple entries coexist and eachuninstallremoves only its own.
Server restart¶
If your install writes to ~/.env, leave restartServer at its default
(true): the manager bounces the OpenCode server so the variables take effect,
and the editor blocks edits while a task is running. If your module only writes
its own config files that tools read live (like ~/.aws or ~/.kube/config),
set restartServer: false — it is never bounced and can be edited mid-task.
Host hooks (optional)¶
Two optional hooks run on the host (with full host access), as part of an explicit user action — they let a module read host state it must not store.
optionsCommand on a prompt¶
Names an executable in the module directory that prints one choice per line on
stdout. It populates a select/multiselect prompt's options from host state —
e.g. the kubernetes module's list-contexts lists host kube contexts.
A multi-instance module's key prompt may also carry an optionsCommand
(the only non-select prompt allowed to): it drives the import picker that lists
host accounts to import as new instances (e.g. aws's list-accounts,
ssh's list-hosts).
The resolve script¶
A module-level resolve executable (present == enabled) runs before the
container install, with the collected values as OCM_* env vars. It prints extra
key=value lines that are merged into the install environment but not
persisted to the manifest.
Use resolve to derive container input from host-only state you must not store —
for example extracting the selected account's secret key from the host CLI config
so it never lands in workspace.yaml. resolve is re-run on every add and
reconcile. It must emit nothing for an account it does not find on the host,
leaving any manually-typed values in place.
Checklist¶
- [ ]
module.ymlwith a uniquename, accuratedescription, and correctrestartServer. - [ ]
installis idempotent and instance-scoped (ifkeyis set). - [ ]
uninstallfully reversesinstallfor that instance. - [ ] Secrets resolved on the host via
resolverather than stored in the manifest, where applicable. - [ ] Tested by adding/removing the module on a running workspace from the editor.