| name | agent-admin |
| description | Query and manage Shipwright agents via the admin API — cron jobs, env vars, tool permissions, API tokens, and plugins. Use to configure the running agent, manage its schedules, inspect another agent's config, or provision a new agent.
|
Shipwright Agent Admin — Skill
Use this skill to configure and manage Shipwright agents via the admin API. Covers cron jobs,
env vars, tool permissions, API tokens, and plugins for any agent — including yourself.
Scope boundary: For delivery pipeline work (planning, code tasks, reviews, deploys) use the
task-store, dev-task, review, or deploy skills. This skill is for agent lifecycle management only.
Authentication
All calls require a Bearer token:
Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY
Your key and base URL are in the agent env:
echo $SHIPWRIGHT_API_URL
echo $SHIPWRIGHT_AGENT_API_KEY
echo $SHIPWRIGHT_AGENT_ID
Verify the service is reachable before doing anything:
curl -sf "$SHIPWRIGHT_API_URL/health"
Creating new agents is an admin-only operation — it requires an admin-level key
(SHIPWRIGHT_ADMIN_API_KEYS on the server side). All other operations work with the
per-agent API key.
Your Agent Identity
curl -sf -H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/config" | jq .
Finding Other Agents
To manage another agent (e.g. resolve a name like "warchild" to an ID), list all agents:
curl -sf -H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents" | jq .
Admin-scoped keys only — this 403s unless your SHIPWRIGHT_AGENT_API_KEY is registered
in SHIPWRIGHT_ADMIN_API_KEYS with scope: "*". Most per-agent keys don't have this; check
with whoever manages the admin service if you get a 403.
Cron Jobs
Crons drive autonomous operation. The agent syncs from the API every 60 seconds — changes
take effect without a restart.
System crons vs. custom crons
System crons ("system": true in the list output) are seeded from the agent type manifest's
crons array (agent-types/{typeName}/manifest.yaml, resolved via the AgentTypeRegistry).
Important rules:
- Cannot be deleted via the API — the server returns 403. They are recreated on the
next
reconcile call.
- Can be enabled/disabled via
PATCH {"enabled": bool} — the enabled-only toggle works
for both custom and system crons. The enabled state persists across reconcile calls.
- Content updates go through code — submit a PR to change the manifest's
crons array
(agent-types/{typeName}/manifest.yaml), then call POST .../crons/reconcile to apply the
new definition.
Custom crons (user-created, "system": false) can be freely created, updated, and deleted.
curl -sf -H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons" | jq .
curl -sf -X POST \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons" \
-d '{
"schedule": "0 9 * * 1-5",
"prompt": "Run the morning brief...",
"channel": "C123456",
"enabled": true
}' | jq .
curl -sf -X POST \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons" \
-d '{
"schedule": "0 20 * * 1-5",
"prompt": "Evening check-in...",
"user": "U0AALR8M69X",
"enabled": true
}' | jq .
curl -sf -X POST \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons" \
-d '{
"schedule": "*/30 * * * *",
"prompt": "/shipwright:dev-task",
"silent": true,
"preCheck": "shipwright:check-test-readiness.ts",
"enabled": true
}' | jq .
curl -sf -X PATCH \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons/{cronId}" \
-d '{
"schedule": "0 8 * * 1-5",
"prompt": "Updated prompt text here",
"channel": "C123456",
"preCheck": "shipwright:check-docs-freshness.ts"
}' | jq .
curl -sf -X PATCH \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons/{cronId}" \
-d '{"enabled": false}' | jq .
curl -sf -X PATCH \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons/{cronId}" \
-d '{"preCheck": "shipwright:check-docs-freshness.ts"}' | jq .
curl -sf -X PATCH \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons/{cronId}" \
-d '{"preCheck": null}' | jq .
curl -sf -X PATCH \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons/{cronId}" \
-d '{
"schedule": "0 8 * * 1-5",
"prompt": "Updated prompt text here",
"enabled": true
}' | jq .
curl -sf -X DELETE \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons/{cronId}"
curl -sf -X POST \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/crons/reconcile" | jq .
Cron field reference:
| Field | Required | Description |
|---|
schedule | Yes | 5-field cron expression (* * * * *) |
prompt | Yes | Prompt sent to Claude (fallback when preCheck is set) |
channel | One of† | Slack channel ID for output |
user | One of† | Slack user ID (posts as DM) |
silent | No | true = run Claude but post nothing to Slack |
enabled | No | Default true. Patchable via enabled-only or full-content PATCH |
preCheck | No | Script — stdout becomes the live prompt; non-0 exit skips the tick |
name | No | Human-readable label (required for system crons) |
† channel and user are mutually exclusive. At least one is required unless silent: true.
Env Vars
Env vars are encrypted at rest. The agent's config-sync loop picks up changes every 60 seconds
— no restart needed.
curl -sf -H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/envs" | jq .
curl -sf -X POST \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/envs" \
-d '{"SLACK_BOT_TOKEN": "xoxb-...", "GH_TOKEN": "ghp_..."}' | jq .
curl -sf -X PATCH \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/envs" \
-d '{"env": {"GH_TOKEN": "ghp_new_token"}}' | jq .
curl -sf -X PATCH \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/envs" \
-d '{"env": {"GH_TOKEN": "ghp_new_token"}, "secretKeys": ["GH_TOKEN"]}' | jq .
curl -sf -X DELETE \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/envs/GH_TOKEN"
Tool Permissions
Tool patterns control which Claude Code tools the agent can invoke.
curl -sf -H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/tools" | jq .
curl -sf -X POST \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/tools" \
-d '{"pattern": "Bash(git *)"}' | jq .
curl -sf -X PATCH \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/tools/{toolId}" \
-d '{"enabled": false}' | jq .
curl -sf -X DELETE \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/tools/{toolId}"
API Tokens
Per-agent tokens for service-to-service or CI calls. The raw token value is returned only
once at creation time — store it immediately.
curl -sf -H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/tokens" | jq .
curl -sf -X POST \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/tokens" \
-d '{"label": "ci-runner"}' | jq .
curl -sf -X DELETE \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/tokens/{tokenId}"
Plugins
Plugins installed on the agent determine which skills and commands are available.
name is the canonical Claude install spec — exactly the string you'd pass to
claude plugin install:
"<plugin>@<marketplace>" for a marketplace-scoped plugin (e.g. "shipwright@shipwright",
"my-plugin@my-marketplace"). The config bundle splits on the first @, and the harness
reassembles <plugin>@<marketplace> to install it.
- A bare
"<plugin>" defaults to the bundled shipwright marketplace.
Do not use an npm-scoped form like @my-marketplace/my-plugin — claude plugin install
does not accept scoped plugin identifiers, and the agent would fail to install it.
curl -sf -H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/plugins" | jq .
curl -sf -X POST \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/plugins" \
-d '{"name": "shipwright", "version": "4.27.2"}' | jq .
curl -sf -X POST \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/plugins" \
-d '{"name": "my-plugin@my-marketplace"}' | jq .
curl -sf -X PATCH \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/plugins?name=shipwright" \
-d '{"version": "4.27.2"}' | jq .
curl -sf -X DELETE \
-H "Authorization: Bearer $SHIPWRIGHT_AGENT_API_KEY" \
"$SHIPWRIGHT_API_URL/agents/$SHIPWRIGHT_AGENT_ID/plugins?name=shipwright"
Creating a New Agent (Admin Only)
Two paths, depending on whether the agent is self-hosted.
Non-self-hosted (preferred): use the inline provisioning wizard at /admin/provision.
Select the "Create new agent" toggle (instead of "Use existing agent") to walk through
Slack app creation, GitHub auth, and AI credentials in one flow.
Self-hosted: the wizard doesn't apply — register the agent directly via the admin API.
Requires an admin-level API key configured in SHIPWRIGHT_ADMIN_API_KEYS on the server.
curl -sf -X POST \
-H "Authorization: Bearer $SHIPWRIGHT_ADMIN_API_KEY" \
-H "Content-Type: application/json" \
"$SHIPWRIGHT_API_URL/agents" \
-d '{"name": "my-agent", "slackId": "U0AALR8M69X"}' | jq .
After creating a self-hosted agent via the raw API, set env vars, add tool patterns, install
plugins, and seed crons using the endpoints documented elsewhere in this skill.
Metrics API
The metrics service exposes task-store-backed pipeline data. Endpoints require Bearer auth.
| Endpoint | What it returns |
|---|
GET /metrics/summary | Cycle time, task counts, FTQ rate |
GET /metrics/trends | Metrics over time, groupable by day/week/month |
GET /metrics/features | Per-feature task and CI data |
GET /metrics/queue | Queue funnel and cycle breakdown |
GET /metrics/tokens | Token usage by agent and session type |
For structured analysis, use /shipwright:metrics instead — it reads local JSONL files
from planning/*/metrics.jsonl, computes fix cascade rates, FTQ rate, CI gate, and other
quality metrics, and produces a formatted report with actionable recommendations.
API Reference
The full admin API schema is committed to the repository at admin/openapi.json. For
interactive schema exploration (endpoints, request/response shapes, validation rules), access
the live /doc endpoint on a running admin service:
open "$SHIPWRIGHT_API_URL/doc"
Note: The /doc endpoint is not yet wired in the production admin service — it is a
planned follow-up. Use admin/openapi.json as the schema reference in the meantime.
Safety Rules
- Confirm before any DELETE — token revocations and plugin removals are not easily reversed.
- Never attempt to delete system crons — the API returns 403. Use
PATCH {"enabled": false} to disable them instead.
- Content PATCH requires
schedule + prompt together — you must resend both even when changing only one. For toggling only enabled, use {"enabled": bool} with no schedule/prompt.
- POST to
/envs replaces everything — use PATCH to update specific keys without wiping others.
- Token raw values are shown once — save
rawToken from the create response before closing the session.
- If the API isn't responding, stop and tell the user — don't guess or retry blindly.