Reproducible Setup and Named Schedules
The additive REST setup surface uses stored configuration and the existing scheduler. API_CONFIGURATION_ENABLED defaults false for new writes. Authorized reads and retained matching retries remain available when that gate is disabled. Enabling the gate does not validate your workers or providers.
When general API_ADMISSION_ENABLED is enabled, setup/schedule requests and matching replays consume shared HTTP quota; these configuration operations reserve no queued-input capacity. Named-schedule DELETE retains the existing control-action exemption; disable remains an ordinary configuration write. 503 admission_unavailable carries a retry hint for coordination failure. 503 configuration_unavailable requires enabling new configuration admission and has no retry interval. Retained setup outcomes preserve their original JSON types and ETags while quota headers describe the current request.
Paths below are relative to /api/v1. Use an authorized member-issued agents:manage key for setup writes. Organization keys retain current issuer agent-management authority; a service's agents:manage scope does not confer Organization administration.
Prepare, inspect, then activate
GET /setup/workspaces/lists current authorized placement options (page defaults 1; page_size defaults 20, maximum 100). Organization inventory returns Teams plus the issuer's Organization-private workspace. Personal keys see their personal workspace. This does not create or administer Teams.POST /agents/withis_active:falsecreates an inactive agent. Addteam_idfor direct placement in an accessible active Team of the key's Organization; that field requiresIdempotency-Keyand the configuration admission gate. The normal seat/name/plan/tenancy policy still applies. The owner remains the key issuer. No first-check-in timer or initial agent processing is published for inactive creation. Description/tag/avatar metadata-generation jobs can still be scheduled. An active create requests initial processing and a default check-in even withschedule:nullorproactive_opt_in:false.GET /agents/{id}/configuration/returns the current configuration slice, allowed tier/settings options, workspace, named-schedule limits and aconfiguration_revisionequal to itsETag.PATCHthe same route with that token inIf-Matchand a retry key. Allowed fields arename,charter(maximum 65,536 characters),schedule,preferred_llm_tier,whitelist_policy,contact_approval_mode, andproactive_opt_in. Unknown fields are rejected. This route requires the agent to remain inactive, retains domain validation, and never activates it or queues a settings-change processing wake. Use the dedicated routes below for named schedules and bindings.- Discover/configure schedules and integrations. Follow any
action_requiredbrowser handoff as the key issuer in the indicated workspace; return to the API to inspect fresh state. Creating credentials, OAuth consent, certificate material and recent-authenticated administration retain their guarded browser flows. A returned handoff is not completed authentication. - Inspect
GET /agents/{id}/readiness/(optionalkindandintegration_idtogether, plusoperation_idfor OpenAPI or nativecapability). It returns stored checks, unresolved human steps andexecution_tested:false. A paused lifecycle remains blocked; configured credentials, tools and network settings are not provider acceptance, DNS/TLS reachability or worker health. - Intentionally
POST /agents/{id}/activate/through the existing lifecycle API. Activation restores expired lifecycle/saved primary cadence when applicable, synchronizes schedules and may resume eligible deferred broadcasts. It does not recreate the skipped creation check-in. Observe actual work separately. Credentials, licenses, emergency controls, approval policy and workers still govern execution.
{
"name": "Renewal observer",
"charter": "Inspect renewal records and report concerns for review.",
"is_active": false,
"schedule": null,
"proactive_opt_in": false,
"team_id": "<authorized-team-uuid>"
}
PATCH /agents/{id}/workspace/ accepts workspace_type (team, organization_private, personal) and team_id exactly for Team destinations, with a configuration ETag and retry key. Destination and source must stay within the current key boundary. This setup route permits only inactive unused agents: no messages, retained requests/completions, steps, snapshots, custom tools/skills/secrets, boards, browser work, nonempty/shared filespaces or OpenAPI bindings. An empty exclusively owned default filespace is permitted. Existing domain restrictions apply, including the disabled Team-to-private move. Create directly in the intended Team when historical work exists; this route does not transfer historical visibility. A move fences old named occurrences and removes inaccessible MCP assignments through the existing workspace service.
Deterministic named schedules
| Method/path | Effect |
|---|---|
GET /agents/{id}/schedules/ | Bounded complete named-schedule collection; primary cadence is separate |
POST /agents/{id}/schedules/ | Create a stable UUID with a unique immutable agent-local schedule_key |
GET /agents/{id}/schedules/{schedule_id}/ | Current fields, claim revision and ETag |
PATCH /agents/{id}/schedules/{schedule_id}/ | Update supplied mutable fields |
DELETE /agents/{id}/schedules/{schedule_id}/ | Remove future desired occurrences |
POST …/{schedule_id}/enable/, POST …/{schedule_id}/disable/ | Change desired enabled state; empty JSON body |
Schedule writes require Idempotency-Key; all existing-schedule changes also require the exact detail ETag in If-Match. Schedule reads require agents:read; writes require agents:manage. Service credentials support only these schedule operations with current explicit agent/Team grants and installation/Organization enablement. Creation, setup discovery, workspace moves, configuration and binding writes remain unavailable to services. No grant expansion or fallback human occurs.
{
"schedule_key": "weekday_renewals",
"name": "Weekday renewal check",
"instruction": "Inspect renewal records and report concerns.",
"kind": "recurring",
"expression": "0 9 * * 1-5",
"timezone": "America/New_York",
"enabled": true
}
Supported fields: schedule_key at most 64 lowercase letters/digits/underscores/hyphens, beginning with a letter/digit; name at most 120 characters; instruction at most 500; kind recurring or once; expression at most 128; IANA timezone at most 64, default UTC; offset-aware run_at; JSON boolean enabled, default true. primary is reserved. id, schedule_key, revision and observed timestamps are not mutable. Unknown fields, natural-language timing, @reboot, floating local datetimes and intervals exceeding eight years are rejected.
The named REST interval maximum is exactly 2,928 elapsed days (366 * 8), separate from the primary cadence's representability limit. Shared interval validation rejects overflowing numeric components/combined durations and next dates outside the scheduler's supported date range, including when calculating from an explicit future anchor. Invalid expressions return field validation errors even for disabled named schedules; they do not change existing desired state or revisions. No new admission gate or migration is required for this validation repair.
Recurring expressions accept five-field Celery cron (minute/hour/day-of-month/month/day-of-week), parser shorthand such as @daily, or @every 2h 30m. Cron day-of-month and day-of-week intersect (AND). Local nonexistent times during a DST jump are skipped; repeated local times use the first fold only. Intervals are elapsed durations anchored on creation/change or the latest claim, independent of timezone, with targets normalized to RedBeat second precision. The next cron occurrence is bounded to eight years. A late recurring claim advances strictly beyond the later of its target and claim time, skipping missed periods.
For a one-time timer use kind:"once", expression:null, and an ISO-8601 run_at with an explicit offset. Targets normalize to UTC seconds. Enabled new/re-enabled timers must satisfy the deployment's minimum future lead; a completed/past timer requires a fresh future run_at to re-enable. One-time claim disables the schedule, preserves last_fired_at and clears next_run_at. Editing an unclaimed timer's label/instructions preserves its exact target even if it became overdue while editing. Restart/synchronization retains an unclaimed timer's original target; a late eligible timer can claim once. Ownership moves and emergency reset fence all named revisions, skip overdue recurring targets, and disable overdue one-time timers instead of renewing them as fresh work. Future targets remain with a new revision. This behavior requires upgraded scheduler/reset writers even when the REST gate is off.
Primary cadence, onboarding check-in and siblings are preserved by single-schedule mutations. Total/active/recurring-day bounds include the primary cadence; owner/plan minimum recurrence still applies. Inspect configuration discovery for deployment limits. next_run_at is a desired occurrence, not evidence of execution. A claim changes revision, so a client with a pre-claim ETag must reload. Disabling/deleting rejects unclaimed deliveries; it does not cancel already admitted trigger events or running work. Emergency halt retains its separate authority.
Integration discovery and permitted bindings
GET /agents/{id}/integrations/?kind=native|openapi lists non-secret metadata (bounded page/page_size). GET /agents/{id}/integrations/{integration_id}/?kind=… shows effective connection, selected tools/capabilities or published/draft OpenAPI metadata and the current binding. Native IDs are discovered provider keys; OpenAPI IDs are Organization UUIDs. The detail ETag covers the agent configuration slice plus that integration's stored metadata. Use identical query parameters when writing.
PATCH that detail route accepts enabled and, for OpenAPI, an existing credential_id and unique active approver_ids (at most 100). Supply its ETag and retry key. The existing domain service checks integration Organization, credential type/current grant, eligible approvers and selected tools. Member-owned credentials require an explicit grant to this agent; knowing a UUID or having agent-management authority cannot borrow another member's credentials. Native connections are inherited from the agent's authorized workspace; credential IDs cannot override them. Native skill disablement does not revoke credentials or remove tools shared by another skill. Agent mailboxes and managed connections return human/workspace handoffs rather than a fabricated local toggle.
GET …/{integration_id}/setup/?kind=… returns either stored-credential readiness or an action_required object containing action.type, guarded action.url, workspace/agent context and instructions. It never returns secret values. Browser OAuth, manual secret entry, new OpenAPI specifications/publication, default workspace credentials, certificate imports and recent-auth approval remain outside this REST slice. Complete them through existing authenticated flows, then inspect again with a new logical retry key when a prior request returned a historical handoff.
Retry, rollout and recovery
This uses the existing encrypted safe-retry receipt ledger: member-key namespaces and stable service-identity namespaces, with the configured 24-hour default retention. Fingerprints include method, path, body, query parameters and the exact If-Match value. Changed input with the same key returns 409. Every retry rechecks live authority and referenced resources before disclosing an outcome. A matching replay returns the original acceptance/body/ETag even after its conditional revision changed; retrieve current state separately. New-key stale conditions return 412; missing conditions return 428. After expiry, a key can admit new work.
Schedule publication uses existing after-commit RedBeat synchronization; the API response proves PostgreSQL desired state, not Redis/worker execution. Run the existing sync_schedules repair command in the owning environment after scheduler loss. It is not a second scheduler. Preserve original claims and emergency generations. Deploy/drain web, workspace/reset/schedule writers, workers and Beat together; no new migration is required. Keep the configuration gate off until you have validated HTTP, worker, Beat, provider and restart/disable/halt behavior in your environment. Admission and file workflows are separate workstreams, not availability guarantees from this feature.
Disable the admission gate for rollback while preserving authorized reads, encrypted outcomes, desired schedules, accepted trigger events and recovery. Retain compatible scheduler/reset/replay readers throughout receipt retention. Do not erase accepted work, refresh stale generations or restore older workers that ignore the fences.
Conditional ordinary agent updates
GET /api/v1/agents/{id}/ returns an agent-specific strong ETag. Select X-API-Contract: 2026-10-14 for ordinary PUT/PATCH and supply that exact ETag in If-Match, plus Idempotency-Key. New conditional writes require the existing API_CONFIGURATION_ENABLED deployment gate. Named schedules and /configuration/ keep their separate configuration ETags; those tokens cannot substitute for the ordinary agent token.
curl "$BASE/api/v1/agents/$AGENT_ID/" -H "X-Api-Key: $API_KEY"
# Copy its exact quoted ETag into AGENT_ETAG, then:
curl -X PATCH "$BASE/api/v1/agents/$AGENT_ID/" \
-H "X-Api-Key: $API_KEY" -H 'Content-Type: application/json' \
-H 'X-API-Contract: 2026-10-14' -H "If-Match: $AGENT_ETAG" \
-H 'Idempotency-Key: configure-charter-1' --data '{"charter":"Prepare the weekly report."}'
Missing If-Match returns 428 configuration_revision_required; a wildcard, weak token, list or malformed value returns 400 configuration_revision_invalid; a well-formed stale token returns 412 configuration_revision_conflict. Missing replay key returns 400 idempotency_key_required. If-Match on an ordinary agent write without the selected version returns 400 api_contract_required, so a condition is never silently ignored. Identical accepted retries return the original response/ETag without another mutation, even after later configuration changes or gate shutdown. Current issuer/scope/grant/ownership authority is checked first. Body, query, exact If-Match and selected version are hashed together; changed semantics under the same key return 409.
The monotonic revision covers persisted name, charter, primary schedule string, active/lifecycle/deletion state, proactive opt-in, model tier, whitelist/contact/email policy, SMS disable state, preferred contact endpoint and owner/workspace IDs. Unchanged writes keep it; changes away and back still advance it. Console, REST, MCP, runtime tools, SQLite reconciliation, workspace/lifecycle services and normal ORM/bulk updates advance this same authority. Deferred and legacy writes remain unconditional last-write-wins; they invalidate previously read tokens but are not themselves protected. Runtime counters, timestamps, planning and heartbeat do not advance it. Named schedules/claims and integration/skill/tool relationships retain their separate configuration contracts. Personal MCP server-list replacement is unsupported in this versioned update.
Raw SQL, historical migration writers and direct base-manager/superclass bypasses are outside coverage. Drain old writers before conditional admission. Rollback disables new configuration admission while retaining the revision column, upgraded writers and encrypted safe-retry readers/receipts for their lifetime; never reset counters or erase acceptance. Validate behavior in your own deployment.