Extending your agent
Giving your agent a new capability usually mixes the same ingredients: a credential to authenticate with, sometimes a skill for the know-how, sometimes a variable for non-secret configuration — and a routine that puts them to work. A whole capability can also arrive pre-assembled as a plugin.
Skills
Skills follow the open Agent Skills standard, so any skill written for Claude Code, Cursor, opencode, or the rest of the ecosystem works in your agent’s skills/ directory unchanged. A routine only gets the skills its frontmatter declares.
openroutines skills new my-skill # scaffold a blank skill
openroutines skills new owner/repo --path sub/dir # vendor one from a git repository
openroutines skills list # skills and which routines use them
Treat a skill like the dependency it is: instructions — sometimes code — that your agent will follow unattended. Review what you vendor in.
Credentials
Secrets are encrypted into the repo, Rails-style: one master key outside the repo, per-routine grants in frontmatter, log scrubbing for every secret value. The repo stays self-contained without ever containing a usable secret.
openroutines credentials set steady_token # add or replace one value (prompted, hidden)
openroutines credentials list # credential names and which routines declare them
A routine declares the credentials it needs in frontmatter, and each one arrives in that run’s environment — steady_token becomes $STEADY_TOKEN. Routines receive only the credentials their frontmatter declares.
Typed credentials
Some secrets are too powerful to hand to a run. Give a credential a type and the stored secret stays with the supervisor, which trades it for short-lived material when the run starts and injects only that. The routine is unchanged: it grants the credential by name, and never sees the root secret. A credential with no type is injected verbatim, as always.
Two types ship today, both declared in openroutines.yml:
github_app trades a stored App private key for a one-hour installation token, minted for each attempt and revoked when it ends.
credentials:
product_bot:
type: github_app
app_id: "1234567"
Store the key with openroutines credentials set product_bot < app-key.pem. A run that grants it can use git and gh as the App.
oauth2_client covers the client-credentials flow most SaaS APIs use for server-to-server access.
credentials:
support_desk:
type: oauth2_client
token_url: https://api.helpscout.net/v2/oauth2/token
client_id: "abc123"
inject_as: support_desk_token
The supervisor exchanges the stored client secret at token_url and injects only the bearer that comes back, as $SUPPORT_DESK_TOKEN.
Variables
Non-secret configuration — a repo name, a docs URL — goes in a variables: map in openroutines.yml, and every run receives each one as an environment variable (product_repo becomes $PRODUCT_REPO). Secrets go in encrypted credentials instead; inside a routine the interface is the same either way, so the only question a value raises is whether it’s secret.
Models
Models are named provider/model, from the models.dev catalog that opencode reads. Any routine can pick a different model than the agent’s default in its frontmatter (see Creating routines).
To use your own endpoint (a gateway, a proxy, a server you host), add a provider block to opencode.json in opencode’s provider schema, keyed by the prefix your model strings use:
{
"provider": {
"my_gateway": {
"npm": "@ai-sdk/openai-compatible",
"options": {
"baseURL": "https://gateway.example.com/v1/compat",
"apiKey": "{env:MY_GATEWAY_API_KEY}"
}
}
}
}
A routine then asks for model: my_gateway/some-model, and the credential my_gateway_api_key goes in as the provider key.
Plugins
A plugin is one or more routines, the skills they use, and the names of the credentials they need, bundled together so you can install the whole capability at once.
openroutines plugin add steadyspacecorp/openroutines-plugins --path steady
openroutines plugin list
openroutines plugin update steady
plugin add first shows you what the bundle can do: every routine with its schedule, model, credentials, and skills. Confirm, and it vendors the files under .openroutines/plugins/<name>/. The routines arrive inactive, and you’re told which credentials to credentials set afterward, since a plugin never carries secrets of its own. Read the routine bodies and skill files before you activate anything: like a vendored skill, this is code your agent will follow unattended.
plugin update merges a new version against your copy, keeping local edits to schedules, prompts, and activation. Where both sides changed the same lines you get ordinary conflict markers to resolve.
A plugin that needs an MCP server declares it in its manifest, and plugin add offers to write that entry into your opencode.json, showing you the exact JSON first. It never writes one on its own, so a plugin can propose an endpoint but only you can make it live.
To write your own, copy a reference plugin from openroutines-plugins: PLUGIN.md names the bundle and the credentials, variables, and MCP servers it needs, and routines/ and skills/ are the payload.