Managed vs. manual agents: An agent synced from a repo is engine-owned — it is read-only in the Cotool UI. You change a managed agent by editing its YAML and letting the next sync apply it. Agents created in the UI are unaffected; the two can coexist in the same organization.
How It Works
You keep agent YAML in a Git repo
Each agent is one YAML file in a folder you choose (default
cotool/agents). The file describes the whole agent: prompt, model, tools, skills, inputs, triggers, and more.Cotool polls and reconciles
Roughly every 5 minutes, Cotool fetches the configured branch and makes your agents match the files — creating new agents, updating changed ones, and removing agents whose file disappeared. A commit-SHA check skips the fetch entirely when the branch hasn’t moved.
Every change is versioned
Each synced create or update appends an entry to the agent’s version history, tagged with the source commit. An unchanged re-sync adds nothing.
Setup
Response Agents as Code syncs from the GitHub integration. Connect GitHub first, then configure the sync.Connect GitHub
Go to Settings > Integrations and connect GitHub. Install the GitHub App on the organization and repositories you want to sync from.
Open the Response Agents as Code card
On the GitHub tool page, find the Response Agents as Code card. (You need the
tool.manage permission to configure it.)Choose repo, branch, and path
Pick the repository, branch, and the folder that contains your agent YAML files. The dropdowns are populated from the repos the GitHub App can access. The path defaults to
cotool/agents.Enable and save
Turn on Enable sync and click Save config. While enabled, the periodic sync includes your organization; while off, it skips it.
File Format
Each file defines one response agent. The format is intentionally distinct from the UI’s bulk export/import format — here it’s one agent per file, with the system prompt either inline or in a separate.md file.
Top-level fields
| Field | Required | Notes |
|---|---|---|
apiVersion | optional | Schema version, e.g. cotool.ai/v1. |
kind | optional | Must be ResponseAgent when present. |
metadata | required | Identity and human-readable info (see below). |
spec | required | The agent definition (see below). |
metadata
| Field | Required | Notes |
|---|---|---|
sync_key | optional | Stable, org-unique identity for the agent (see Identity). |
name | required | Human-readable name. Can change freely — it is not the identity. |
description | optional | What the agent does. |
tags | optional | Free-text tags for categorizing the agent. |
spec
| Field | Required | Notes |
|---|---|---|
modelAlias | required | Model alias, e.g. anthropic:chat:sonnet-4.6. |
systemPrompt | required | Either { inline: "..." } or { file: "prompt.md" } (path relative to the YAML file). |
planningMode | optional | auto (default), never, or always. See Planning Modes. |
agentFilesystem | optional | Mount a persistent Agent Filesystem across runs (default false). |
toolNames | optional | Non-agent tool ids the agent may use. |
agentTools | optional | Other managed agents this agent may call, by sync_key (see Agent-to-agent). |
cliNames | optional | CLI integration ids the agent may use. |
skills | optional | Attached skills by name (org-scoped, tracks the latest version). |
inputs | optional | Declared agent inputs. |
acceptanceCriteria | optional | Acceptance criteria evaluated for each run. |
triggers | optional | Inline triggers (see Triggers). |
structuredOutputSchema | optional | JSON schema for structured output. |
contextDocs | optional | Context documents attached to the agent. |
The YAML is strict — unknown or misspelled keys (for example
syncKey instead of sync_key) are rejected with a validation error for that file rather than being silently ignored.Identity
Each file maps to exactly one agent. Cotool decides which agent a file represents by:metadata.sync_key— an author-chosen identity, unique within your organization. Recommended. Because identity is independent of file content and location, you can rename the agent or move/rename the file without churning the agent or losing its triggers and history.- File path — used when no
sync_keyis set. Renaming or moving the file then changes its identity (Cotool treats it as a new agent).
Set a
sync_key for any agent you expect to rename or reorganize. It’s the only way to keep a webhook trigger’s minted secret and URL stable across a rename.Triggers
Declare triggers inline underspec.triggers. The sync engine materializes them as engine-owned, read-only triggers on the agent. Supported sources: cron, webhook, jira, jira-automation, slack, linear, and email.
sync_key is its stable identity within the agent (it defaults to a slug of name). Set it explicitly to rename a trigger without recreating its row — which, for webhook-family triggers, is what preserves the minted secret and URL.
For the full set of fields per source, see Triggering Agents.
Agent-to-Agent References
A YAML agent can call another managed agent as a tool by referencing itssync_key:
agentTools and sync_key, not via toolNames.
Reconcile Behavior
Each sync makes your agents match the files:- New file → a new managed agent is created.
- Changed file → the managed agent is updated, and the change is recorded as a version.
- Removed file → the agent is gently soft-deleted. This keeps its triggers and tags and is reversible: if the file returns, the same agent is resurrected (not a fresh copy).
- Invalid file → the last good version of that agent is kept. The error is recorded against that file and never blocks the others, so one bad file can’t take down the rest of your agents.
ok, integration not connected, or a parse/validation error for each file, with a link to the file at the synced commit.
Validate Before Syncing
POST /api/agent-sync/validate runs the exact same parse, schema, and cross-file graph validation as the sync engine, statelessly, over files you post — so it cannot drift from real sync behavior. It’s the engine behind the CI Action below, and you can call it directly:
errors (would block sync) and warnings, plus an overall valid flag. Warnings are checks that depend on live org state the request can’t see (an unprovided systemPrompt.file, or an agentTools sync_key not in the posted set) and never fail the check. See the API Reference for the full schema.
Validate in CI
Thecotool/validate-agents GitHub Action validates your agent YAML on every pull request and annotates problems inline.
The Action authenticates only via GitHub OIDC — there is no API-key input, and it is the recommended way to validate in CI. The job mints a short-lived, repo-scoped OIDC token; Cotool verifies it and maps the repository to your org via your GitOps sync configuration. Nothing to store or rotate, and the token grants validate-only access — never your broader API-key permissions.
OIDC requires that this repository is configured as your org’s agents source under Settings → Agents → GitOps sync — that registration is what authorizes the repo. To validate before configuring sync, or outside GitHub CI, call the endpoint directly with an API key (the
curl example above) rather than the Action — subject to the API-key trade-offs noted above.Inputs
| Input | Default | Description |
|---|---|---|
dir | cotool/agents | Directory to scan for agent YAML (and referenced prompt .md). |
file | — | Comma-separated explicit file list; overrides directory discovery. |
recursive | true | Recurse into subdirectories of dir. |
audience | cotool-validate | OIDC audience requested from GitHub and verified by the Cotool API. |
api_url | https://app.cotool.ai | Base URL of the Cotool API. |
fail_on_warnings | false | Fail the check on warnings (errors always fail). |
How validation gates a merge — and how syncing stays safe
The Action (and the/validate endpoint behind it) is advisory by default: it reports problems on the pull request, but on its own it does not stop anything from syncing. Cotool’s sync engine polls whatever is on your configured branch and reconciles it — it does not know or care whether a CI check ran or passed. Two separate mechanisms turn that into a safe GitOps workflow:
- Branch protection makes validation a merge gate (recommended). In your repository settings, mark the validation check as a required status check on the branch you sync from. GitHub then blocks any pull request from merging until validation passes, so only validated YAML ever reaches the branch Cotool polls. This is the piece that actually gates syncing, and it lives in your GitHub settings — not in Cotool.
- The sync engine re-validates as a backstop. Independently of CI, every sync runs the exact same parse, schema, and cross-file graph checks before applying a file. An invalid file is skipped per-file — its last good version is kept and the error is recorded against that file — so a bad file that slips past CI never corrupts your live agents (see Reconcile Behavior).
Open a pull request
An author edits agent YAML under your synced path and opens a PR. The
validate-agents Action runs against the PR’s files and annotates any errors or warnings inline.The required check gates the merge
With branch protection enabled on your sync branch, the PR cannot merge until the validation check is green. Reviewers only ever merge validated YAML; broken YAML is blocked at the door.
Merge to the sync branch
Once approved and green, the PR merges into the branch you configured under Settings → Agents → GitOps sync (commonly your default branch).
Cotool never reads your CI status — branch protection is what ensures only validated YAML lands on the sync branch. If you sync from an unprotected branch (or commit directly to it), the Action becomes a non-blocking signal and the server-side backstop is your only guard against invalid files.
Exporting an Existing Agent
To move a UI-built agent into Git, open the agent, use the version dropdown, and choose Export as YAML. The export emits the canonical sync shape — inline prompt as a literal block, stablesync_keys for agent-tool references, and triggers without any server-owned secrets — ready to commit to your repo.
Recovery
If the backing GitHub integration is disconnected, synced agents keep running — only syncing pauses. The card surfaces a Reconnect GitHub prompt. If you need to edit a managed agent while GitHub is disconnected, use convert to manual: Cotool makes an editable copy, moves the triggers to it, and parks the managed original (recoverable). The copy is an ordinary UI-owned agent from then on.Related
Agent Versioning — how synced and manual changes share one timeline
Triggering Agents — all trigger types and their fields
GitHub Integration — connect GitHub and configure repository sync
Creating Agents — building agents in the UI
Skills — reusable instructions referenced by name