Agents
Last updated
An agent is a standing worker. You write what it does in AGENT.md, list the tools it may use, and say when it wakes — on a schedule, on a webhook, when a page changes. It runs on Terminus for everyone who installs it, each with their own connected accounts.
On this page⌄
How an agent works#
An agent is a folder: AGENT.md, terminus.json, and any files it should have at hand. AGENT.md is its instructions, and everything beside it is there for it to read, though not to change — a style guide, examples, a glossary.
Tools are declared by name — service:@terminus/web, gmail.read, skill:@publisher/slug — and they are everything the agent may use. No token or account is ever in the package: when someone installs the agent, gmail.read means their Gmail.
Create an agent#
Create it on the desktop — Create, then Agent. It gets an address, and two ways to work on it: the editor in the browser, or your own machine.
terminus clone @you/release-notes && cd release-notes # an empty draft arrives started
# or connect a folder you already have
terminus remote add @you/release-notesA new agent holds AGENT.md and a terminus.json that offers every model, starting on GPT-5.6 Luna. It runs straight away; the link only matters once you push.
Write AGENT.md#
Write it as the brief you would give a capable new colleague: the job, the voice, what to do when something is missing, and what never to do. Every conversation and every wake starts from it.
AGENT.md
# Release notes
Every Friday, read the pull requests merged into acme/app this week
and draft release notes for customers, not engineers.
- Group changes under New, Improved and Fixed.
- Leave out refactors, dependency bumps and anything internal.
- Follow the tone in style.md, beside this file.
- If nothing shipped, reply with nothing.Mention the files beside it that it should read. A few top-level folder names are reserved for the agent's own use; terminus validate says so if the package ships one.
terminus.json#
terminus.json
{
"kind": "agent",
"id": "@you/release-notes",
"version": "0.0.1",
"models": { "default": "openai:gpt-5.6-luna", "mode": "all" },
"tools": [
"service:@terminus/web",
{ "id": "github.read", "when": "Read this week's merged pull requests." }
],
"triggers": {
"weekly": {
"schedule": { "every": "friday", "at": "16:00", "timezone": "user" }
}
}
}- kind, id, version
- What it is, the address it belongs to, and the release version.
- type
"observed"shares its conversations with the people who maintain it, who can read them; a visitor accepts a notice saying so first. Left out, every conversation stays private.- models
- Which model it runs on. See Models.
- tools
- What it may use. See Tools.
- triggers
- When it wakes, each by name. See Triggers.
It holds no other keys — in order, kind, type, id, version, models, tools, triggers — and the CLI refuses any other. Name, description, icon, price and listing are set on the agent's page and change without a release.
Tools#
Each entry is an id, or { "id": …, "when": … } — when tells the model when the tool is the right one to reach for.
- service:@terminus/web
- Search the web and read public pages.
- service:@terminus/bash
- Run shell scripts over its workspace: bash syntax and about 80 commands, with
python3andnodeinside a script. - service:@terminus/python
- Run Python programs over its workspace, with the standard library.
- service:@terminus/javascript
- Run JavaScript programs over its workspace, with Node-style
fs,path,processandBuffer. - model:@terminus/gpt-image-2
- A picture, music, speech, transcription or video model, as a tool:
generate_image,compose_music,generate_speech,transcribe_audioorgenerate_video. A chat or embedding model is no tool. See Models. - service:@publisher/slug
- Any published service, every operation of it: each one that answers JSON is a tool of its own.
service:@publisher/slug#operationgrants just that one. A connector — a service that works in each person's own account — is granted the same way, and works in the account of whoever the agent is talking to. - schedules.manage, watches.manage
- Manage its own schedules and page watches in conversation.
- skill:@publisher/slug
- A published skill, loaded when it is relevant.
skill:@publisher/slug@1.2.0pins a release. - agent:@publisher/slug
- Another agent it may hand work to.
Its own workspace needs no entry: every agent can read and write its working directory. List a service once — whole, or by the operations it may call. An id terminus validate does not know is refused with the list of what is.
Models#
"models": {
"default": "openai:gpt-5.6-luna",
"mode": "all"
}default is the model it starts on. "all" lets the person talking to it pick any model; "selective" offers the default and the ones in available; "default" keeps it to the default alone. An agent that says nothing gets exactly the section above — every model, starting on GPT-5.6 Luna — which is what terminus init agent writes. Ids are provider:model.
Triggers#
A trigger wakes the agent. triggers holds them by name — lowercase letters, digits, - and _, up to 48 characters. Each holds exactly one of schedule, webhook or watch, and may add a prompt and enabled.
"triggers": {
"weekly-plan": {
"schedule": { "every": "monday", "at": "09:00", "timezone": "user" },
"prompt": "Plan my week."
},
"deploys": {
"webhook": { "coalesce_seconds": 60 },
"prompt": "A deploy finished. Summarise it."
},
"pricing": {
"watch": { "url": "https://example.com/pricing", "pattern": "\\$([0-9.]+)", "condition": { "below": 20 } }
}
}- schedule
every:"day", a weekday ("monday"…),"month"withon_day(1–31),"hour", or an interval like"30m"or"2h"— withat("HH:MM", 24-hour) for a day, a weekday or a month. Or a five-fieldcroninstead, each field*,*/Nor one number.timezoneis an IANA name, or"user"for each installer's own.- webhook
{}, or{ "coalesce_seconds": 60 }(0 to 3600) to gather a burst into one wake. Each install gets its own endpoint: whoever installed the agent makes its URL in the agent's Info → Automations, which shows it once, and making a new one stops the old. A POST to it wakes the agent with the payload.- watch
url, a public https page, and optionally apattern— a regular expression; the part it matches is what is compared — andinterval_minutes: 60 by default, at least 15, at most 10080. Only a real change wakes the agent, with the difference.- prompt
- What the wake says.
AGENT.mdalready says what to do; without a prompt, the agent is told why it woke. - enabled
falsestarts the trigger switched off; whoever installs the agent can switch it on.
- A watch's
condition— exactly one ofchanged_by_pct,beloworabove— is checked against the number thepatterncaptures, without spending a model call. - Every run that has something to say sends a notification: the agent, the first line of its reply, and a link back. An empty reply sends nothing.
- Webhook payloads reach the agent as data to read, never as instructions to follow.
- A trigger that fails ten times in a row pauses itself and tells the owner.
- Whoever installs the agent can switch any of its triggers off, and see its recent runs, from the agent's Info → Automations. A trigger switched off stays off when the agent is updated.
Run it locally#
terminus dev runs the agent on your machine, set up exactly as a release would be, with a local workspace in .terminus/dev/agent/. It opens a chat page to talk to it, watch its tool calls, pick a model, add tools, and add, edit and run its schedules and watches. What you change there is written to terminus.json, and editing AGENT.md or terminus.json reloads the agent.
terminus dev # talk to it in the chat page
terminus dev --prompt "Draft this week's notes" --json # one turn, for scripts
terminus dev --trigger deploys --payload deploy.json # fire a trigger now
terminus dev --remote # the same conversation, on Terminus- It needs you signed in, and works right after
terminus init agent, before the folder is linked. Its model calls, web tools, skills and services run under your own account and spend your credits. - It keeps one conversation across runs: the chat page and each
--promptcarry on where the last turn stopped, so earlier turns are in context.--resume <id>continues a given one; deleting.terminus/dev/agent/starts over from nothing. - With
--json,--promptand--triggerprint every event as one line of JSON, and a turn that failed exits with status 1. --trigger <name>fires the trigger with that name the way Terminus would, and a name that is not declared lists those that are. For a webhook,--payloadis the delivery; a watch fetches its page now, and its first firing records what it saw.--remotepushes the folder to its draft and holds the same conversation on Terminus itself — the check to run before publishing an agent that runs code, whichterminus pushreminds you of. It needs the folder linked;--promptand--triggerrun only on your machine.- To try a connector for real, connect your own account to it on Terminus first —
service:@acme/gmailthen reads your Gmail.
Publish#
terminus validate
terminus push # update the draft; then publish it on the webPublish it from its page in Creations on the web — terminus push prints that page — with a note on what changed. Once published, the agent has a page at /agents/{publisher}/{slug} and a web address of its own under agents.terminus.build, where anyone can talk to it. Installing it binds each declared tool to the installer's own accounts, and its triggers start running for them.
For your coding agent
https://www.terminus.build/