A ceremony is a scheduled skill invocation — a recurring fleet ritual defined in YAML, fired by a cron expression, and dispatched through the standard skill routing pipeline.
A ceremony is a recurring fleet ritual: a cron schedule, an observable outcome (persisted to knowledge.db and surfaced on /api/ceremonies), and an on-demand trigger. Unlike event-driven routing — where an inbound Discord/GitHub/Linear message is routed to an agent the moment it arrives — a ceremony fires on its own fixed schedule, like a daily standup or a weekly retrospective, and can also be run on demand.
How ceremonies work
CeremonyPluginowns an internal cron timer for each enabled ceremony and firesceremony.<id>.executeat the scheduled timeCeremonyPluginpublishesagent.skill.requestwith the configured skill and targetsSkillDispatcherPluginroutes the request to the matching executor (in-process or A2A)- On terminal response (or 120s timeout)
CeremonyPluginpublishesceremony.<id>.completedand persists the outcome toknowledge.db
Ceremony YAML is hot-reloaded every 5 seconds — drop a file and it's live without a restart.
Ceremony YAML schema
Create a file in workspace/ceremonies/<id>.yaml:
# workspace/ceremonies/daily-standup.yaml
# Must match the file name (without .yaml).
id: daily-standup
# Human-readable name.
name: "Daily Fleet Standup"
# Optional description — shown in /api/ceremonies.
description: "Morning ceremony: board summary, active ceremonies, open PRs"
# Cron expression (UTC). Standard 5-field cron.
schedule: "0 9 * * 1-5"
# Skill name to dispatch. Must be registered by an agent.
skill: board_audit
# Agent names to route this skill to. If multiple, all receive it.
# Leave empty to use default routing (skill-match or default executor).
targets:
- ava
# Discord channel ID for the response. Leave empty to suppress Discord posting.
notifyChannel: "1469195643590541353"
# Set to false to disable without deleting the file.
enabled: true
# Ownership marker — stamped automatically when created via API with a
# per-agent key. Controls who can update/delete through the HTTP API.
# Operator-authored ceremonies omit this (treated as "system"-owned).
createdBy: quinnField reference
| Field | Required | Description |
|---|---|---|
id | Yes | Unique ceremony ID. Must match the filename (without .yaml). |
name | Yes | Human-readable name shown in the API and logs. |
description | No | Explains the purpose of the ceremony. |
schedule | Yes | 5-field cron expression (UTC). Examples below. |
skill | Yes | Skill name dispatched via agent.skill.request. |
targets | Yes | Non-empty array of agent names (e.g. ["quinn"]), or ["all"] for fleet broadcast. |
notifyChannel | No | Discord channel ID for delivery. Empty = no Discord post. |
enabled | No | true (default) or false to suspend without deleting. |
createdBy | No | Owning agent name. Stamped automatically when created via the HTTP API with a per-agent key; operator-written files typically omit it. Enforced by /api/ceremonies/:id/update and /api/ceremonies/:id/delete. |
Cron expression examples
| Schedule | Expression |
|---|---|
| Weekdays at 9:00 UTC | 0 9 * * 1-5 |
| Every 30 minutes | */30 * * * * |
| Every 3 hours | 0 */3 * * * |
| Mondays at 9:00 UTC | 0 9 * * 1 |
| Daily at midnight | 0 0 * * * |
Triggering a ceremony manually
Ceremonies can be triggered outside their schedule via the HTTP API:
curl -X POST http://localhost:3000/api/ceremonies/daily-standup/run \
-H "X-API-Key: $WORKSTACEAN_API_KEY"Or by publishing to the bus:
curl -X POST http://localhost:3000/publish \
-H "X-API-Key: $WORKSTACEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"topic": "ceremony.daily-standup.execute", "payload": {}}'Listing ceremonies
curl -H "X-API-Key: $WORKSTACEAN_API_KEY" http://localhost:3000/api/ceremoniesAdmin keys see every ceremony; per-agent keys (WORKSTACEAN_API_KEY_<AGENT>) return only ceremonies where createdBy matches the caller. Admins can pass ?all=true to see everything regardless of owner.
Response:
{
"success": true,
"data": [
{
"id": "daily-standup",
"name": "Daily Fleet Standup",
"schedule": "0 9 * * 1-5",
"skill": "board_audit",
"targets": ["ava"],
"notifyChannel": "1469195643590541353",
"enabled": true
}
]
}Creating ceremonies at runtime
Drop a file into workspace/ceremonies/ (hot-reloaded in ≤5s) or call the API:
curl -X POST http://localhost:3000/api/ceremonies/create \
-H "X-API-Key: $WORKSTACEAN_API_KEY_QUINN" \
-H "Content-Type: application/json" \
-d '{
"id": "quinn.hourly-sweep",
"name": "Hourly Sweep",
"schedule": "0 * * * *",
"skill": "qa_report",
"targets": ["quinn"]
}'When called with a per-agent key, createdBy is stamped server-side. Agents can then update or delete only ceremonies they own; admins can manage any. See Build an A2A agent → Scheduled work for the agent-side manage_cron tool pattern.
Example: security triage ceremony
This ceremony runs hourly:
# workspace/ceremonies/security-triage.yaml
id: security-triage
name: "Security Incident Triage"
description: "Investigates open security incidents and reports resolution status."
schedule: "0 * * * *"
skill: bug_triage
targets: []
notifyChannel: ""
enabled: trueAny caller can fire this ceremony off-schedule by publishing ceremony.security-triage.execute on the bus (or by POSTing to /api/ceremonies/security-triage/run). The cron path and the on-demand path share the same code, so on-demand runs are observable on /api/ceremonies just like scheduled ones.
Example: weekly retrospective
# workspace/ceremonies/weekly-retro.yaml
id: weekly-retro
name: "Weekly Retrospective"
schedule: "0 9 * * 1"
skill: pattern_analysis
targets:
- quinn
notifyChannel: "1469195643590541355"
enabled: trueQuinn receives the pattern_analysis skill request every Monday at 9:00 UTC and posts its output to the configured Discord channel.
Adding a ceremony
- Create the file
workspace/ceremonies/<id>.yamlwith the schema above (or POST to/api/ceremonies/create) - Wait ≤5s for the hot-reload watcher, or confirm immediately via
GET /api/ceremonies - Optionally trigger it manually with
/api/ceremonies/<id>/runto verify the skill routes correctly
Related
- Add an agent — register the agent that will run the ceremony's skill
- Bus topics reference —
ceremony.<id>.execute,cron.<id> - Workspace files reference