The developerz.ai MCP server is live at mcp.developerz.ai. Connect it from
Claude Code, Claude Desktop, or any MCP-capable client
using a personal access token from the dashboard.
Trust model
Every MCP call is bound by the same rules as the rest of the platform:
- The bot always discloses. Every action it takes is labelled as automated, it never impersonates a human.
- Thin orchestrator, BYOK. On the fleet path your AI devs write the code on your own enrolled boxes; an external hand-off (Copilot, or a webhook runner) runs where that agent runs, GitHub for Copilot. Inference uses your own provider key. We never proxy or resell tokens.
- Audit-first. Every tool call is written to the append-only audit log. If it isn't logged, it didn't happen.
Connecting
Claude Code, from a project-root .mcp.json (it expands ${DEVELOPERZ_API_KEY} from
your environment at launch), or with claude mcp add --transport http. Every client's
recipe is in MCP clients.
{
"mcpServers": {
"developerz": {
"type": "http",
"url": "https://mcp.developerz.ai/v1/mcp",
"headers": { "Authorization": "Bearer ${DEVELOPERZ_API_KEY}" }
}
}
}
Or direct HTTP (JSON-RPC 2.0 over POST /v1/mcp):
curl https://api.developerz.ai/v1/mcp \
-H "Authorization: Bearer dev_pat_…" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","id":1,"params":{"name":"whoami","arguments":{}}}'
Scopes are on the wire, not just on this page
Every row tools/list returns carries its own gate, so a client never has to
read this page or pattern match a description:
{
"name": "box",
"annotations": { "readOnlyHint": false, "destructiveHint": true, "idempotentHint": false },
"_meta": {
"developerz.ai/scopes": {
"kind": "action",
"actions": { "list": "read:runners", "revoke": "write:runners" }
}
}
}
A flat tool publishes {"kind": "tool", "scope": "write:tasks"} instead, with
"scope": null when it gates on nothing. Pair it with whoami, which returns
the scopes your token actually holds, and you can tell before you call which
verbs are open to you and which need a wider token. annotations is the MCP
standard triple: readOnlyHint is claimed only when every one of a tool's
actions is a read.
The tables below are the same information, rendered for humans. They are
generated from the catalog the server enforces, so the two cannot drift.
Flat, hot-path tools available to every authenticated account. No action field.
| Tool |
Scope |
Description |
whoami |
(none) |
Return caller account, MCP tier, granted scopes, and the platform-access rungs behind them (approved | Terms accepted | capped). |
next_steps |
(none) |
WHAT DO I DO NEXT: the ordered preconditions between this credential and a first plan_start, each with the fact observed and where it clears (cleared_by, of which only here names a verb you can call). Optional repo narrows the same ladder to one repository. No scope required. |
status |
(none) |
HOW IS IT GOING, AND WHAT NEEDS ME: waiting FIRST, which is one sentence on what is waiting on the human (pull requests parked on an approval, questions owed an answer, pending work held), the classes with something in them, and the classes this credential could not read, so an all-clear is never mistaken for an unread one. Then conversion (what 30 days of work turned into, and the failure mix), then the verdict, then capacity. advice.verdict is access | tokens | vms | nothing | fix_conversion, the last meaning more work is dying than landing so more hardware will not help. Then which boxes are working and on what, the backlog per lane, whether the BYOK pool can sign, every reason holding pending work with its remedy, and this billing month’s tokens + BYOK spend per model with the fraction of runs each total covers. Composes box fleet_status | GET /v1/fleet/utilization | task stalls | session list | task list | pr approvals; the ONE field it derives is advice. With repo (and window_days, 1..90, default 7) it adds repo_health: that repo’s SLOs graded ok | warn | bad | no_data, each quoting its numerator, denominator and window, and the single worst bottleneck named (read:tasks + read:prs; the same body GET /v1/repos/:owner/:repo/health serves). No scope required; a block behind a scope you lack answers readable: false naming it. |
repo_ask |
read:repos |
Grounded repo Q&A with citations, refuses rather than guessing when no citable evidence exists. |
plan_start |
write:tasks |
Start a scout planning session over a repo: hand it a raw ask and a box authors a plan (groups → tasks). Returns {task_id, queue_position, queue_depth_cap}. Poll task outcome {task_id}: while the scout runs its run.run_id is what message steers, and once it is delivered its plan_id goes to plan get, whose tasks carry the pull requests. Name SEVERAL repos to ask for one change across them: with return_context: true one sub-scout surveys each and fanout_id addresses their merged answer (plan context); without it the ask is filed for triage, which authors ONE plan with a slice per repository ordered by its dependencies, and the answer is {raw_task_id}, the same id plan get takes once triage settles. require_approval is refused on that arm, by name: the triage lane mints unconditionally and has no held state to write. Refuses no_scout_capacity when the account has no online box able to hold a live session, no_capacity when it has 0 AI developers, and queue_full when its backlog is at its cap. |
message |
write:tasks |
Send a message to a live run (any lane but review; read at its next turn) and await the agent reply. |
help |
(none) |
Orientation: which verbs THIS credential can call and which it is scope-refused on; points at next_steps and docs. |
docs |
(none) |
How to drive developerz.ai: the 24 goal-indexed guides (plus 5 operator-only ones, listed to platform staff) (docs://recipes/<name>) with the exact calls in order. docs({}) is the map, docs({q}) inlines the best match, docs({uri}) reads one. Call it before the first plan_start / ask file on an account or repo you have not driven before, and whenever a refusal cites a docs:// URI. No scope. |
Config migration
dz_migrate schedules the move of a repository's root config files into
.dz/. It is the one user-tier tool dispatched by an action field, like the
resource tools below, and without confirm: true it is a dry run that opens
nothing.
| Action |
Scope |
Description |
migrate |
write:repos |
Schedule the move of a repository’s root config files into .dz/. DRY-RUN BY DEFAULT: without confirm: true it plans the move and opens nothing; with it, one DRAFT pull request per repository. repos names the repositories, all: true takes every installed one that has a file to move, inventory: true only reports what would move. |
Resource tools, one tool name, dispatched by an action field. That collapse is
what keeps the catalog readable: one tools/list entry per resource instead of
one per action. Each entry is complete, its JSON Schema naming every action and
the arguments that action takes, so any MCP client can call any of them straight
from the catalog. There is no second call to make and no extension to install.
Consumer-or-absent. A tool only appears in tools/list when its backing
service is configured. All tools below are available on platform-managed accounts.
Box
| Action |
Scope |
Description |
list |
read:runners |
List fleet boxes. |
get |
read:runners |
Get one box + live presence. |
fleet_status |
read:runners |
Aggregated fleet status (counts + per-box line). |
versions |
read:runners |
Fleet dz-runner build spread, box count per version. |
releases |
read:runners |
Release-ledger rows per build target, what CI published (NOT the installed-build spread versions reports). A tenant sees the INSTALLABLE view: version/channel/target/published_at, the rows box update may pin. An operator holding admin:releases sees the full ledger, including yanked rows, commit_sha and signing-key provenance; the response names which view it answered. |
logs |
read:runners |
The box's own process log: boot, enrolment, self-update, NATS. Excerpt plus a presigned archive url. Unlike task.run_tail it answers for a box with no run. |
add |
write:runners |
Mint a one-time enrollment token. |
enroll_ssh |
write:runners |
Enroll by SSH-pull: we dial the box; no token leaves the platform. |
drain |
write:runners |
Evacuate box; re-enqueue in-flight tasks. Reversible: the box stays enrolled. |
revoke |
write:runners |
KILL a box: free its seat, halt it over its control channel and cascade its tokens dead. Not reversible. |
decommission |
write:runners |
Take a box out of the fleet in one act: drain, then revoke (halted, presence dropped), then audit runner.decommissioned; run dz-decommission on the machine afterwards. |
reissue_creds |
write:runners |
Operator-initiated credential re-issue for a healthy box. Convenience, not recovery: a locked-out box is systemctl restart dz-runner. |
set_owner |
write:runners |
Retarget a box shared | org | user (the runner-ownership model). |
set_prompt |
write:runners |
Set/clear the box's concise briefing (what this VPS runs, ≤2000 chars). |
update |
write:runners |
Start a staged dz-runner self-update rollout of this account’s fleet (canary → soak → waves; halts + rolls back on failure). |
attest_isolation |
admin:runner:isolation |
Platform-operator attestation that this box runs every coding job in its own container. The ONE thing that widens its claim past a single tenant, so it takes only the box id: no box-reported evidence of its own containment is admissible. |
withdraw_isolation |
admin:runner:isolation |
Retract that attestation. The box is single-tenant again on the assigner's next pass. |
Project
| Action |
Scope |
Description |
list |
read:repos |
List account repositories with enabled state. |
get |
read:repos |
One repo's full row (policy validity, warnings, last activity). |
add |
write:repos |
Enable an installed (but disabled) repo, addressed by repo (owner/name). |
disable |
write:repos |
Turn an enabled repo off and cancel its queued tasks; the row and its history stay, and add re-enables it for new work. Cancelled tasks don't come back. |
set_ai_first |
write:repos |
Declare a repo already AI-first, releasing the coding work the onboarding gate holds. |
set_donations_enabled |
write:repos |
Consent to receive donated boxes/keys for a repo. |
set_canary |
write:repos |
Opt a repo into a daily small, safe, real ask: the end-to-end probe behind its status {repo} health report. |
set_public_stats |
write:repos |
Consent to publish this repo’s agent-authored numbers on the no-auth GET /v1/public/oss/{owner}/{repo}/stats page; the gate still drops a private or disabled repo. |
create |
write:repos |
One-step create+scaffold of a brand-new gold-standard repo. ORG accounts only, since the App holds no administration: write on a personal one (advertised only when backed). |
setup |
write:tasks |
The advertised path for a NEW repo: you create it on GitHub, project add, then a box scaffolds it. Also re-establishes the base on an existing repo (advertised only when backed). |
policy_get |
read:repos |
Effective maintainer.yml policy one enabled repo runs, plus fallback: null, or the failing stage and errors when its snapshot is invalid. |
policy_validate |
write:repos |
Pure maintainer.yml check, nothing stored. |
overview |
read:repos |
Activity rollup for one enabled repo (repo-detail tab). |
settings |
read:repos |
Settings view for one enabled repo (repo-detail tab). |
Ask
The admission gate's door, and the only way new work enters: file the ask for
triage to decide, then read the decision back. Nothing on this surface mints an
executable task around triage.
| Action |
Scope |
Description |
file |
write:tasks |
File an ask the platform DECIDES on, the object triage judges rather than a task it runs. Take the ask itself, the repos it touches and evidence as path:line anchors plus urls; triage reads it against the LIVE fleet and mints executable tasks, drops it, cross-links it to work already in motion, or escalates it to a human. Ground it first with plan_start {return_context: true} (a scout on a box that HAS the code) and steer that scout with message, then file what you composed. It takes NO files_touched, depends_on, parallel_safe, preferred_runner_id or priority: those are triage’s output, decided against boxes and sibling work a conversation cannot see. The one ordering fact it does take is after_tasks: existing tsk_… ids the work builds on, which the platform (not triage) holds every piece of the ask behind until each has merged. Idempotent on your own dedupe_key, so a retried call answers existing rather than filing a second ask. |
get |
read:tasks |
One filed ask and what triage decided: pending (nobody has looked yet), triaged with a schedule verdict naming the task_ids it minted (poll each with task outcome), dropped (noise, or a duplicate naming the task that covers it), or escalated (a human decides, which is an outcome and not a failure). |
redrive |
write:tasks |
Re-drive one ask the triage judge never answered: an ask escalated with reason judge_unavailable goes back to pending and the admission drain is nudged for a fresh pass. Every other escalation was a DECISION and stands; the refusal names its kind (not_redrivable_status / not_redrivable_reason) and ask get shows what the row actually is. nudged: false on a success means the row IS pending but the hand-off was refused, and the stale-pending sweep re-nudges it. |
Task
| Action |
Scope |
Description |
list |
read:tasks |
List fleet task queue (supports filters.status, per_page). |
stalls |
read:tasks |
Why is nothing moving: every reason holding a pending task, with a fix for each. |
reassign |
write:tasks |
Pull in-flight task off its box → pending. A terminal task is REFUSED (task_terminal); run it again with redispatch. |
cancel |
write:tasks |
STOP a task: cancelled, and the box holding it is interrupted. Idempotent on a terminal task (kind: "already_terminal"). A PR-review task is REFUSED, because stopping it would release the merge gate's review hold. |
redispatch |
write:tasks |
Run a failed (or otherwise finished) task again: back to pending, and the tasks that failed BECAUSE it did go with it (released_dependents). attempt and its own failure_kind are kept. A task already pending, or one an operator cancelled, is refused. |
depend |
write:tasks |
Hold a task until other EXISTING tasks (after_task_ids) have merged (or finished with no PR): the edges land on its depends_on. A pending task is held at once; an in-flight one keeps running (in_flight: true), and task reassign puts it back in line behind the edges. Refused for a task whose run is over, and for an unknown, dead, self or cyclic upstream. |
run_status |
read:tasks |
One-row pulse for a task's run. |
run_tail |
read:tasks |
Durable run events after since_seq, capped. Takes EXACTLY ONE address: run_id (from a task list row) or task_id (what plan_start / ask get hand back). Addressed by task it resolves to whichever run a box mints, so it works BEFORE the run exists ({run_id: null, events: [], next_since_seq: null} means re-send the same call, not an error) and picks up a run that starts mid-wait. Add wait_ms (up to 25 000) to WATCH rather than poll: the call is held open until the first new event lands, so one request covers what 25 would. An empty page after a wait is not an error, re-send the same cursor. A run that has already ended settles the wait at once, so an instant empty page means run_status and stop. |
result |
read:tasks |
What a run DELIVERED: the report markdown with its source (report_md, final_turn, none beside report_missing: true, or unknown for a run that predates the field), the raw tasks a devops run filed, the blocker it declared, and the devops summary. The read for a report / devops / ops_action task once run_status says finished; a task that has not run answers run_id: null. |
outcome |
read:tasks |
IS IT DONE? One call for what happened to a request: the phase (queued | running | delivered | awaiting_ci | in_review | awaiting_merge | merged | failed | cancelled | blocked), the run, the pull request with its CI status, review verdict and merge decision, where the change is once merged (deploy.state: deployed | failed | pending | missing | not_tracked, and only pending keeps a merged task non-terminal), the open blocker, and the terminal reason if it failed, plus a one-paragraph summary naming the verb for the next move. Poll this instead of task list + run_status + pr list + status. |
Blocker
| Action |
Scope |
Description |
list |
read:tasks |
Answerable holds a human still owes (open: false for the closed record). |
answer |
write:tasks |
Supply what was missing. Closes the blocker and mints the resumption. Give the LOCATION of a credential, never the credential itself: the answer is stored and copied into the raw task verbatim. |
withdraw |
write:tasks |
Retire an open blocker whose ask went away. |
spec |
read:tasks |
Read an access form: each field by the NAME submit takes, its kind, and whether it has landed, plus remaining and the fix_url. Names only; the form stores no value. |
submit |
write:secrets |
Fill an access form: fields maps each field NAME to its value (an mcp:<name> field takes {url, transport, token}). Partial fills allowed, each field write-once; values are sealed into their stores and never echoed. OAuth fields are refused (not_submittable); they complete through the fix_url. A run waiting on the form wakes on the landing. |
Plan
| Action |
Scope |
Description |
list |
read:tasks |
The account's plans (epics) newest-first, in numbered pages: id, repo, lead-slice title, merged/total, held count. bucket/repo/q filter, page walks; the envelope carries total and per-bucket counts. |
get |
read:tasks |
One plan's full projection, the group → task → PR chain (mirrors GET /v1/plans/:planId). |
rollup |
read:tasks |
Per-conversation_ref rollup: tasks that carried the ref, the plan groups whose task carried it (sibling groups filtered out), open blockers on those task ids, and a deployVerdict field stating unknown when no verdict is recorded (rather than an omitted line). Tenant-isolated: a second account reading the same ref gets null. |
context |
read:tasks |
The MERGED answer of a multi-repo plan_start fan-out, addressed by the fanout_id that call returned. One sub-scout surveyed each repo; this folds their findings into one answer with per-repo attribution, refs repo-qualified (repo:path:line), and a claim two repos both established collapsed once. A fan-out still running answers too, NAMING the repos still surveying: poll again rather than reading a short answer as complete. Tenant-isolated, so an id this account does not own reads as no such fan-out. |
cancel |
write:tasks |
STOP the epic: every non-terminal child cancels and its box is interrupted. Answers three id lists: stopped, already finished, and the PR-review children the merge-gate carve-out refused. |
approve |
write:tasks |
RELEASE a held plan (the one plan_start produced when require_approval: true). Flips every held group back to dispatched and mints its tasks in one transaction. Idempotent on re-approve (the second call reports already_approved). |
regroup |
write:tasks |
REPLACE unfinished group_ids with the tasks that replace them: a SCHEDULED ask_id (file the re-cut with ask file) or task_ids. One new group per task takes the slot; every group and task that waited on the old one waits on ALL the new ones, and a dependent the old one killed is revived. Mints nothing and does not stop the superseded task; the answer names it for task cancel. |
unlink |
write:tasks |
DROP named upstream_group_ids from ONE group_id's edges in an open plan, with a stated reason: the group edge and its task mirror both go, unless an edge that remains still names that task. Only for edges that are ordering, not code dependencies (the group imports nothing the upstream adds). Never adds an edge or touches another group; refuses a settled group. Audited with both edges before and after. |
execute |
write:tasks |
EXECUTE a committed plan directory ({repo, path}, the /planx layout). The platform reads it, cuts one unit per PR with the order and file sets the plan states, and records ONE plan whose units each start when the units they depend on MERGE. Work units never touch the plan directory; only a final unit updates its status.yml. dry_run: true records it held for review. Answers the plan_id to poll with plan get. |
file |
write:tasks |
FILE a plan DIRECTORY inline ({repo, slug, files, scout_task_ids, dry_run}, the /planx layout): documents, the slug, and the completed return_context scouts it was grounded on. Validates everything in one reply (slug, documents, each cited scout and its staleness against GitHub at the default branch), then stores the documents and hands the plan to the SAME plan.execute lane. An identical re-file answers unchanged; a changed re-file revises the same plan as its next revision, refused while the plan is done or cancelled or a read of it is running. Answers the plan_id to poll with plan get. |
file_switch_get |
read:account |
READ the org's plan-file switch: whether scouts may file plan documents into this org's repos. Default on; an owner opts out. |
file_switch_set |
write:account |
FLIP the org's plan-file switch ({enabled}, strict). Answers the state it made: plan_file_enabled, and changed false on a no-op set, which is still audited (who asked, when, with which credential). |
Audit
| Action |
Scope |
Description |
tail |
read:sessions |
Recent maintainer-visible audit events, newest-first. |
Session
What developerz.ai actually did on one repo, and what a different policy
would have done. The live SSE tail stays REST-only because holding a connection
open is not a JSON-RPC shape: events pages the same audit rows behind an opaque
cursor, so an agent polls it until finished is true. replay is walked through, with
its arguments and the diff it returns, in Policy replay.
| Action |
Scope |
Description |
list |
read:sessions |
One enabled repo's agent sessions, newest-first, filterable by trigger / entity_kind / outcome. |
get |
read:sessions |
One session header: repo, triggering entity, model, outcome, start and finish. |
events |
read:sessions |
Page one session's audit rows behind an opaque cursor. Poll it, feeding back next_cursor, until finished is true, the live SSE tail stays REST-only. |
replay |
read:sessions |
Re-decide a stored session against a candidate maintainer.yml and return the decisions DIFF. Executes nothing, stores nothing. |
Template
| Action |
Scope |
Description |
list |
read:runners |
List agent templates. |
get |
read:runners |
Get one agent template by name. |
set |
write:runners |
Create-or-replace (full upsert) an agent template. |
delete |
write:runners |
Delete agent template (idempotent). |
Config
Scoped prompt-var KV, #{{key}} interpolation into agent prompts.
| Action |
Scope |
Description |
get |
read:runners |
Read one prompt var (account | repo | template scope, specific wins). |
set |
write:runners |
Set a prompt var (#{{key}} interpolation). |
delete |
write:runners |
Clear one prompt var (idempotent). |
list |
read:runners |
List prompt vars for a scope. |
onboarding_state |
read:account |
Where this account is in the install funnel + what fires next. |
onboarding_advance |
write:account |
Fire one install-funnel transition you WITNESSED (auth_completed, plan_selected, repos_selected, yml_requested, yml_retried). The four the platform observes about you (key_set, gh_app_installed, yml_validated, yml_invalid) are refused from every state, naming the act that causes each. |
Prompt
The authored prose layers of the system-prompt cascade (platform, then org, repo
and your own). A set replaces that layer; a get on an unauthored one answers
prompt: null. The personal layer belongs to the caller: no action names a user,
and a machine token, which has no human behind it, is refused.
| Action |
Scope |
Description |
org_get |
write:prompts |
Read the org-wide system-prompt layer. |
org_set |
write:prompts |
Set it (replaces the layer). |
org_clear |
write:prompts |
Clear it. |
repo_get |
write:prompts |
Read one repo’s layer (repo uuid). |
repo_set |
write:prompts |
Set it; the repo layer refines the org one. |
repo_clear |
write:prompts |
Clear it. |
self_get |
write:self:prompt |
Read your OWN layer (needs a user-bound credential). |
self_set |
write:self:prompt |
Set it, over your own dispatched work only. |
self_clear |
write:self:prompt |
Clear it. |
User
| Action |
Scope |
Description |
approve |
admin:users |
Approve a waitlisted user for the closed beta (operator PAT only). |
suspend |
admin:users |
Clear approval, return the user to the waitlist (idempotent). |
approve_by_id |
admin:users |
Approve one specific user row by id. The escape hatch when approve refuses a login as ambiguous: users.login is not unique, so a handle can name more than one row and only one of them is the one that signs in. |
suspend_by_id |
admin:users |
Clear approval on one specific user row by id. The suspend half of the ambiguity escape hatch, so a duplicated login can still be revoked. |
invite |
admin:users |
Invite an EMAIL that need not have signed up yet. Mints or re-arms the one live platform invitation for that address, mails it, and returns the accept link ONCE: it is a single-use bearer token, and no later read can show it again. |
provision |
admin:grants |
Onboard a friend in one call: invite if unregistered, approve, and grant free capacity (ai_devs N, unlimited, or the default invite bundle). Answers all three effects plus the id of the provision audit row; an unregistered address is a success whose seats land when they accept. Needs admin:grants AND admin:users. Free seats are friends-only and operator-issued, with no self-serve path. |
Admin
The operator's sign-up funnel, in one verb: the access requests the public waitlist
lands, and the invitations that answer them. Operator PAT only: admin:read:users
reads, admin:users decides, and access_requests_invite also needs admin:grants
because it books the invite bundle. It is the same control the REST admin routes call,
so the dashboard and this verb cannot disagree; every action writes an audit row.
| Action |
Scope |
Description |
access_requests_list |
admin:read:users |
Applications from the waitlist form, newest first, pending by default (status: pending, invited, declined, all). A bounded head: truncated says to raise the limit. |
access_requests_get |
admin:read:users |
One access request by id, with its derived status. |
access_requests_invite |
admin:grants |
Invite ONE applicant: mints the accept link, mails it, and books the default invite bundle (free AI developers for a set number of days; the box budget follows from that count). The request flips to invited. Needs admin:grants AND admin:users. The link is returned ONCE. |
access_requests_decline |
admin:users |
Decline a pending request; the optional reason lands on the audit row and nothing is sent to the applicant. A second decision is refused as already_decided. |
invites_list |
admin:read:users |
Platform invitations with their derived status (pending, accepted, revoked, expired). Never returns an accept link. |
invites_resend |
admin:users |
A fresh accept link and a fresh mail for a pending or expired invitation, on the same row (the old link dies). Refused by name for an accepted or revoked one. |
invites_revoke |
admin:users |
Withdraw one invitation by id. Answers a named reason (unknown, already revoked, already accepted) when it changed nothing. |
Account
| Action |
Scope |
Description |
me |
read:account |
The /v1/me identity view: the scopes this credential holds, user, memberships, active account. |
active_account_switch |
read:account |
Repoint the live user session at a member account. |
keys_list |
write:self:keys |
List YOUR OWN personal BYOK keys, masked (the org pool is billing.keys_list). |
key_add |
write:self:keys |
Add one of YOUR OWN personal BYOK keys, sealed at capture and never echoed. Ranked ahead of the org pool for your own dispatched work. Takes the picked model plus an optional per-model lane tier (fast | general | smart | heavy). |
provider_models |
write:self:keys |
List a provider’s real model ids for a raw key, BEFORE capture, so account key_add picks an id instead of guessing one. Stores nothing: the key is used for one outbound GET and never sealed, echoed or audited. |
key_verify |
write:self:keys |
Verify one of YOUR OWN personal keys against its provider (live probe). An invalid result is data, not an error. |
key_rotate |
write:self:keys |
Swap the material of one of YOUR OWN personal keys. Verify-first, so a refused probe writes nothing and the old key stays live. |
key_delete |
write:self:keys |
Revoke one of YOUR OWN personal keys. |
key_kind_set |
write:self:keys |
Set the billing kind (metered or subscription) of one of YOUR OWN personal keys. The audit trail carries both the previous and the next value. |
key_priority_set |
write:self:keys |
Rank one of YOUR OWN personal keys in your pool: an integer 0..10000, LOWER tried first among keys that fit the lane equally well (unset ranks as 100). Audited with the previous and the next value. |
key_capacity_set |
write:self:keys |
Declare how many concurrent model streams one of YOUR OWN personal keys sustains: an integer 1..256, or null to clear it (the platform default applies: 1 for a z.ai subscription, 2 for Kimi, unbounded for metered). Audited with the previous and the next value. |
llm_pref_get |
write:self:keys |
YOUR model default, or null when unset ("the org key, but this model"). |
llm_pref_set |
write:self:keys |
Set YOUR model default, optionally pinned to one provider. |
llm_pref_clear |
write:self:keys |
Clear YOUR model default. |
accept_tos |
read:account |
Record YOUR consent to the current terms version (needs a user session). |
oss_verify_get |
read:billing |
The account’s OSS fee-waiver application and its verdict, or null. |
oss_verify_apply |
write:billing |
Apply for the OSS-verified fee waiver: one repo plus the evidence a human reviews. |
The platform operator's row: the staff radar, overrides on an account by id, and
the release-ledger repair. Every action rides an admin:* scope that no role
ceiling, session or self-minted token carries, so a tenant's tools/list never
lists it. The reads that disclose a tenant's data need a user-bound credential and
leave a platform-audit row before they answer, exactly as their REST twins do, and
every mutation takes confirm: true.
| Action |
Scope |
Description |
overview |
admin:read:platform |
Platform radar rollup. |
hive |
admin:read:platform |
Every fan-out lane’s self-report, graded (the hive band). |
goals |
admin:read:platform |
The platform’s own milestones and epics, read off GitHub. |
audit |
admin:read:platform |
The PLATFORM-wide audit tail. Trailed: needs a user-bound credential, and the read is recorded first. |
trail |
admin:read:platform |
What platform staff did TO tenants (the operator trail). Not itself trailed. |
health |
admin:read:platform |
Platform-wide aggregate telemetry over window (24h | 7d): session, task, tool, prompt-version, escalation, deploy, janitor, schedule, screen and bug counts. Aggregates only. Trailed. |
orgs_list |
admin:read:orgs |
All org accounts. Trailed. |
account_detail |
admin:read:orgs |
One org in detail, with its member roster. Trailed as a tenant read. |
oss_queue |
admin:read:orgs |
The OSS-verified review queue. Trailed. |
users_list |
admin:read:users |
All users. Trailed. |
set_tier |
admin:accounts |
Operator override: set an account's tier by id. confirm: true. |
set_seats |
admin:accounts |
Operator override: set an account's seat count. confirm: true. |
set_spend_cap |
admin:accounts |
Operator override: set an account's spend cap. confirm: true. |
set_member_role |
admin:accounts |
Staff change of one member's role in an org, by account and user id. Refuses demoting the last owner (last_owner: promote another owner first). confirm: true. |
oss_verify_decide |
admin:accounts |
Rule on a queued OSS-verified application, approve (also re-tiers the account to oss_verified) or reject with a note. confirm: true. |
unyank |
admin:releases |
Restore a halted dz-runner release to its channel’s installable read for EVERY tenant (channel required, never defaulted). Reports the artifact count cleared, 0 when it was not yanked. confirm: true. |
Bug
developerz.ai staff only (admin:bugs, a scope no role ceiling and no self-minted
token can hold), so no customer credential is served this verb. A report is
untrusted text: it is screened before anything lists it, and it becomes work only
when the evidence behind it is reproduced. A verdict takes confirm: true.
| Action |
Scope |
Description |
report |
admin:bugs |
File a platform bug (title, body, optional evidence). Lands as screening; the injection screen decides whether anything ever lists it. |
list |
admin:bugs |
Screened platform bugs, newest first, keyset-paged; never screening or discarded. Title and body arrive quoted as untrusted. |
verdict |
admin:bugs |
Rule on a screened bug; clean.claim says whether the report is true (confirmed, refuted, unverifiable). confirm: true. |
Grant
Audited entitlement overrides, free capacity on top of what an account pays for,
granted to an account (all four kinds) or to a user (unlimited_fleet /
concurrency only, the two the person-level fleet gates read).
Issuing and revoking are operator-only (admin:grants, a scope no role ceiling
and no self-minted token can hold); the listing rides the platform-staff read
scope, so a radar session can see who holds free capacity without being able to
hand any out. Every grant carries a stated reason and an issuing human, and is
revoked rather than edited, the row parks so the decision stays legible.
| Action |
Scope |
Description |
list |
admin:read:orgs |
A subject's grant history, newest-first. Revoked and expired rows included, each with its resolved active (staff read). |
issue |
admin:grants |
Operator only: free capacity, and the SUBJECT decides whose (ai_devs N: N concurrent AI developers on top of paid seats; unlimited_fleet: no cap; unlimited_spend, concurrency, boxes, ci_slots). Subject matrix: account admits unlimited_fleet, unlimited_spend, concurrency, boxes, ci_slots, ai_devs; user admits unlimited_fleet, concurrency, ai_devs. An account subject lifts that account. A user subject lifts only that person’s OWN personal account and never an org they belong to, so it cannot be used to widen org capacity. Required reason, optional expiry. |
revoke |
admin:grants |
Operator only: stop a grant. Parks the row (reason and history stay legible); already-stopped is a benign no-op. |
Review
AI code-review runs for a pull request (the PR rows themselves live on
pr).
| Action |
Scope |
Description |
status |
read:prs |
The PR's AI code-review runs, newest-first. |
rerun |
write:prs |
Re-run the latest review on the same commit. |
CI
| Action |
Scope |
Description |
runs |
read:runners |
List self-hosted CI runs newest-first (repo/status/per_page). |
log_url |
read:runners |
Short-lived presigned URL for one CI run's archived log. |
Artifact
| Action |
Scope |
Description |
put |
write:artifacts |
Register an artifact and get a presigned PUT URL (5-min TTL). |
get |
read:artifacts |
Get a presigned download URL for an artifact (1-hour TTL). |
list |
read:artifacts |
List artifacts for the account; filter by task_id, run_id, or repo_id. |
share |
write:artifacts |
Mint a fresh presigned download URL for an existing artifact. |
delete |
write:artifacts |
Delete an artifact immediately (soft-delete for 24 h, then purged). |
Issue
| Action |
Scope |
Description |
list |
read:issues |
One enabled repo's issues newest-first (state/qualification/q/per_page). |
get |
read:issues |
One issue by id. |
handoff |
write:issues |
Force-fire the issue to the coding-agent webhook (queued delivery; reason + optional webhook_ref). |
escalate |
write:issues |
Force-pull a human in (category + reason → escalation row + notification). |
Pull request
| Action |
Scope |
Description |
list |
read:prs |
One enabled repo's PRs newest-first (state/ci_status/per_page). |
approvals |
read:prs |
Account-wide queue of PRs parked on ask-before-acting. |
get |
read:prs |
One PR by id. |
approve_pending |
write:prs |
Approve the PR's outstanding ask-before-acting. |
skip_pending |
write:prs |
Decline the PR's outstanding ask-before-acting. |
rearm_babysit |
write:prs |
Re-arm the PR's spent babysit CI self-fix budget (pr_id or repo+pr_number, reason) and run a pass now. |
Dashboard
| Action |
Scope |
Description |
list |
read:dashboards |
List account-shared boards. |
get |
read:dashboards |
Get a board with all widget specs. |
upsert |
write:dashboards |
Create a named board, a name already in use is refused unless replace: true, which fully replaces that board. The widget grammar is docs://ref/dashboard-widgets; a widget that does not match is refused by path. A seeded built-in is never replaceable. |
patch |
write:dashboards |
Rename and/or relayout a board WITHOUT touching its widgets (unlike upsert). A layout ref to a widget not on the board is refused. A seeded built-in is read-only. |
widget_page |
read:dashboards |
One page of a widget's data, checked against that widget's declared spec.capabilities. |
delete |
write:dashboards |
Delete a board (idempotent). A seeded built-in is refused. |
Donation
| Action |
Scope |
Description |
create |
write:donations |
Donate money | compute | llm, earmarks the resource oss-only. Optional models on an llm gift = the ceiling the recipient picks within. Refused without an active oss_donor subscription. |
list |
read:donations |
List the account's donations. |
cancel |
write:donations |
Detach a donation (idempotent). |
received |
read:donations |
The MAINTAINER's inbox, gifts pinned to repos this account owns. |
decline |
write:donations |
Refuse a gift you were given, parks the row and releases the donor's box/key. Authorized against the RECIPIENT (the pinned repo's owner); the donor's own detach is cancel. |
set_model |
write:donations |
The maintainer's model pick on a received llm gift, inside the donor's ceiling (null clears it). |
Integration
| Action |
Scope |
Description |
list |
read:integrations |
List the account's connected integrations (status only; credentials never cross the boundary). |
get |
read:integrations |
Get one connector by kind (status only; never echoes the secret). |
disconnect |
write:integrations |
Disconnect a connector: drops the row and its vault secret. Connecting a connector stays dashboard-only, since its credential never crosses this surface. |
source_list |
read:integrations |
The account's connected inbound webhook sources: url, gesture, status. Never a secret. |
source_connect |
write:integrations |
Connect an inbound webhook source (sentry | linear | gitlab | gitee | generic), optionally filing into repo (owner/name): mints the url; the signing secret of a generic source is minted and returned ONCE, a sentry/linear/gitlab/gitee source REQUIRES the vendor-issued one as vendor_secret (never returned; gitlab: the whsec_ signing token; gitee: the WebHook 签名密钥, in signing mode). A gitlab source (on gitlab.com, or jihulab.com named as instance) also takes api_token (a read_api project access token, read once to prove it, never returned) and project_path. A gitee source (gitee.com only, no instance) also takes api_token (a personal access token with projects + pull_requests, read once to prove it, only ever used to read, never returned) and project_path as exactly owner/repo. Neither files work: each records every merge or pull request read-only, so its gesture must be always. The tenant is this row; a delivery never names one. A gesture is required; nothing is claimed implicitly. |
source_rotate |
write:integrations |
Store a new signing secret for a source: minted and returned ONCE on generic, the vendor-rotated one REQUIRED as vendor_secret on sentry/linear/gitlab/gitee (never returned), keeping the old one verifying for the rotation window so no delivery is dropped. A gitlab or gitee API token is replaced by disconnecting and connecting again. |
source_disconnect |
write:integrations |
Disconnect an inbound webhook source: drops the row and both vault secrets. |
Knowledge base
The repo wiki the agents maintain: one row, four actions. index is the whole
catalog with no query, for when you do not know what the wiki calls the thing.
| Action |
Scope |
Description |
search |
read:kb |
Pages ranked by how much of query each covers; a miss reports how many pages exist. |
index |
read:kb |
The whole catalog, most-linked-to first, no query. |
get |
read:kb |
One page verbatim by slug: body, cross-links, provenance. A miss is {found: false}. |
upsert |
write:kb |
Create or replace one page by slug, the post-task write-back so learnings compound. Idempotent by repo + slug. |
Digest
| Action |
Scope |
Description |
list |
read:digests |
Digest header rows newest-first (per_page cap). |
get |
read:digests |
One digest with rendered_html. |
Billing
| Action |
Scope |
Description |
keys_list |
read:billing |
List BYOK keys (masked). |
key_add |
write:billing |
Add a BYOK key, sealed + captured, never echoed. Takes the picked model plus an optional per-model lane tier (fast | general | smart | heavy). |
provider_models |
write:billing |
List a provider’s real model ids for a raw key, BEFORE capture. The org-pool twin of account provider_models; stores nothing. |
key_delete |
write:billing |
Delete a BYOK key. |
key_verify |
write:billing |
Verify a key against its provider (live probe). |
key_rotate |
write:billing |
Swap an org key's material in place (probe first; a refusal writes nothing). |
key_priority_set |
write:billing |
Rank an org key in the pool: an integer 0..10000, LOWER tried first among keys that fit the lane equally well (unset ranks as 100). Answers the key and the previous value; audited. |
key_kind_set |
write:billing |
Set the billing kind (metered or subscription) of an org key. A subscription is held to its concurrency capacity; audited with both values. |
key_capacity_set |
write:billing |
Declare how many concurrent model streams an org key sustains: an integer 1..256, or null to clear it (the platform default applies: 1 for a z.ai subscription, 2 for Kimi, unbounded for metered). Answers the key and the previous value; audited. |
capacity |
read:billing |
Key concurrency: per key its effective capacity (declared, default, learned and which binds), the streams running on it and the tasks waiting for a slot; totals as "N running / M capacity". |
key_purpose_set |
write:billing |
Fence an org key to ONE lane (a job class, review, or gardener; default is refused). An unrecognised value is refused at input naming the admissible set, before any row is touched. |
key_purpose_clear |
write:billing |
Clear the key's lane fence, returning it to a general key. Reads ride billing keys_list. |
usage |
read:billing |
Usage rollup for the current billing window. |
entitlements |
read:billing |
The account's tier entitlements. |
portal |
write:billing |
Mint a Stripe billing-portal URL. |
checkout |
write:billing |
Mint a Stripe Checkout session for N seats of solo | pro. |
set_cap |
write:billing |
Set the monthly spend cap. |
outage_pick |
write:billing |
Apply a named ORG key to the work one open key outage holds. Pairs with billing keys_list and the open-outage block of status. |
log_sink_get |
read:billing |
Read the LLM-log sink config. |
log_sink_set |
write:billing |
Set the LLM-log sink (validate + probe + seal). |
log_sink_clear |
write:billing |
Clear the LLM-log sink. |
LLM route
Which pool key, provider or model serves which work. A pin names a purpose (a job
class, review, gardener, or the default catch-all) plus at least one of
key_label / provider / model; a re-pin replaces the row, so axes you leave
out are cleared. A repo pin beats the org one at claim time, and within a scope an
exact purpose beats the catch-all. Keys themselves live on the billing verb: a
route names a key by label, never key material.
| Action |
Scope |
Description |
list |
read:billing |
Every routing pin the account holds, org and per-repo. |
preview |
read:billing |
What each purpose resolves to right now: the key and model a task would get, or why none. |
org_pin |
write:billing |
Pin the account-wide key / provider / model for one purpose (a job class, review, gardener, or the default catch-all). |
org_clear |
write:billing |
Clear the org pin for one purpose. Idempotent. |
repo_pin |
write:billing |
Pin one repo's route (repo uuid); it beats the org pin at claim time. |
repo_clear |
write:billing |
Clear a repo pin for one purpose. Idempotent. |
Agent mode
Switch each box mode (scout, worker, reviewer, devops) on or off, and
narrow the code tools its model may choose to an allowlist inside that mode's
ceiling. A repo override beats the org one, which beats the default (enabled, full
ceiling). A disabled mode holds its tasks until it is switched back on; nothing
fails. Widening past the ceiling, dropping the floor (a coding mode keeps read,
edit and write) or giving the reviewer tools is refused. A mode's prose is the
prompt verb's role.
| Action |
Scope |
Description |
org_list |
write:prompts |
Every mode's effective state at org scope: enabled, code_tools, ceiling, floor, revision. |
repo_list |
write:prompts |
Every mode's effective state for one repo (repo > org > default). |
org_set |
write:prompts |
Switch a mode on/off org-wide and narrow its code tools within the ceiling. Replaces the row. |
repo_set |
write:prompts |
Set one repo's mode override (repo uuid); it beats the org override. |
org_clear |
write:prompts |
Reset a mode at org scope to its code default. Idempotent. |
repo_clear |
write:prompts |
Reset a repo's mode override so the org one applies. Idempotent. |
Email route
| Action |
Scope |
Description |
list |
read:account |
The resolved notification category → address matrix. |
set |
write:account |
Override one category's route. |
delete |
write:account |
Clear an override (back to the default). |
Notification
Your own inbox and delivery preferences, the same ones the dashboard bell and the
notification settings page drive. Inbox rows are events rather than deliveries: one
escalation fanned out to email and push reads as a single row, and marking it read
clears it everywhere. Every action needs a user-bound credential, because an inbox
belongs to a person; a machine token is refused. Two mandatory cells refuse
prefs_set: the email for a security, license or cla escalation, for an owner or admin
(the disclosure contract) and the blocked-task email for everyone (the operational must-tell).
Web Push device subscriptions stay browser-only and have no verb.
| Action |
Scope |
Description |
inbox |
read:account |
Your notification inbox, newest first (channel deliveries collapsed to one row per event) plus the unread count. |
read |
read:account |
Mark one event read; answers the new unread count. Idempotent. |
read_all |
read:account |
Mark every unread event read (clears the badge). |
prefs_get |
read:account |
Your notification settings: the resolved matrix with each row’s tier, the email cadence, the preset your choices equal and your delivery address. |
estimate |
read:account |
About how many emails a week your current settings mean, from your own last 7 days, plus the total under each preset. |
deliveries |
read:account |
Your email notifications from the last 7 days, newest first, each with why it was or was not sent. |
prefs_set |
write:self:notifications |
Set one cell. A locked cell (escalation email for owners and admins, blocked-task email for everyone) is refused. |
prefs_clear |
write:self:notifications |
Drop one override, back to the default. Idempotent. |
prefs_replace |
write:self:notifications |
Change settings in one atomic write: a preset, the email cadence and any number of cells. A cell that is always on for your role, or cannot be delivered that way, refuses the whole write. |
test_email |
write:self:notifications |
Send one test email to your own address, now. At most 3 an hour; a missing or bouncing address is refused by name. |
Token
| Action |
Scope |
Description |
list |
read:account |
List PATs (masked rows incl. revoked). |
mint |
write:account |
Mint a PAT (subset-of-caller scopes; plaintext returned ONCE). |
rename |
write:account |
Relabel a PAT (the human name only, no change of reach). |
revoke |
write:account |
Revoke a PAT. |
Webhook
Outbound delivery targets. Urls come back masked (origin kept, path redacted, since a
webhook path can itself carry a shared secret) and the HMAC signing secret is returned
exactly once, by create. test does not dial out from the control plane: it queues a
signed test.ping that the worker delivers on the real path, so the result names the
queued delivery and the outcome shows up in deliveries.
| Action |
Scope |
Description |
list |
read:webhooks |
List the account’s outbound webhooks (urls MASKED, never the signing secret). |
get |
read:webhooks |
Get one webhook by id (masked url, health, subscribed events). |
deliveries |
read:webhooks |
The account’s delivery ledger, newest first: status code, attempt, response excerpt. |
create |
write:webhooks |
Create a delivery target. The HMAC signing secret is minted server-side and returned exactly ONCE, since there is no re-reveal door. |
delete |
write:webhooks |
Delete a webhook (its deliveries cascade). |
test |
write:webhooks |
Queue a signed test.ping through the real delivery path (the worker fires it within ~15s); the outcome lands in deliveries. |
Member
The active org's roster. list returns all of it, with no page knob, because the REST
collection does too and a truncation nobody is told about is worse than a long answer;
list_invitations answers the whole invitation history for the same reason.
Every mutation below needs a user-bound credential (invite, set_role, remove and
revoke_invitation alike): the gate asks whether your own role outranks the target, and a
machine token holds no role at all. Neither read does. Nobody may promote past their own
rank, and the last owner can be neither demoted nor removed.
| Action |
Scope |
Description |
list |
read:account |
The active org’s WHOLE roster (no paging, same as REST), each row marking whether it is you. |
invite |
write:members |
Add someone to the org, by exactly one of login (an already-registered user, on the roster at once) or email (anyone: a one-time invitation link, returned once and mailed to them). Needs a user-bound credential: the gate asks whether YOUR role outranks the target. |
set_role |
write:members |
Change a member’s role. Nobody may promote past their own rank, and the last owner cannot be demoted. |
remove |
write:members |
Remove a member. The last owner cannot be removed. |
list_invitations |
read:account |
The org’s invitations, every status, newest first. |
revoke_invitation |
write:members |
Withdraw one PENDING invitation (idempotent). Refuses an already-accepted one; remove the member instead. |
SSO
Your org's own OIDC single sign-on. Owner-only on every action, so a PAT never reaches
it. set carries no client_secret field: a credential the platform mints may ride
back in a result, but one you supply never crosses this boundary, which is the same
rule that leaves integration without a connect. So set updates the non-secret
half and reuses the stored sealed secret, and refuses outright until a connection
exists. Create that one in the dashboard, or with PUT /v1/org-sso.
| Action |
Scope |
Description |
get |
read:account |
The org’s identity provider, MASKED: the stored client secret is a boolean, never a value. Shows the not-entitled state too. |
set |
write:account |
Update the non-secret half of the OIDC connection (issuer, client id, redirect, claim gate, group→role map) and REUSE the stored client secret. A caller-supplied secret never crosses this surface, so creating a connection stays a dashboard/REST act. The issuer is probed live. |
delete |
write:account |
Remove the connection; the org falls back to GitHub login. |
Ops
The devops / debugger run: reproduce a failure against the repository's own secrets,
read the running system, act on infrastructure, and report. It is the one role that
reaches a live system, so the surface here is deliberately one verb wide.
outcome_kind: report is the default and opens no pull request: a devops run's
deliverable is findings. ops_action may act on infrastructure, and on a
production-tagged box it refuses without a fresh signed approval and escalates to a
human; there is no field on this verb that can supply one, by design. A run that needs
access it does not have reports a blocker naming the credential rather than working
around it, and files a raw task for triage when the fix is bigger than the session.
| Action |
Scope |
Description |
dispatch |
write:tasks |
Dispatch a devops / debugger run against a repository: reproduce a failure with the repo’s own secrets, read the running system, and report. outcome_kind: report (the default) delivers findings and opens no pull request; ops_action may act on infrastructure and, on a production-tagged box, REFUSES without a fresh signed approval and escalates to a human (this verb cannot supply one). A run that lacks an access it needs reports a blocker naming the credential rather than working around it, and files a raw task when the fix is bigger than the session. |
Scopes
PATs carry only the scopes you select at creation time. Dashboard session cookies
grant all scopes. Scope names follow read|write:<resource>.
| Scope |
Grants |
read:repos / write:repos |
Repos + project management + KB |
read:tasks / write:tasks |
Fleet task queue |
read:runners / write:runners |
Boxes + templates + config + CI |
read:sessions / write:sessions |
Audit log + interactive runs |
read:issues / write:issues |
Tracked issues + forced handoff/escalate |
read:prs / write:prs |
PR review + pending decisions |
read:artifacts / write:artifacts |
Artifact storage |
read:dashboards / write:dashboards |
Realtime boards |
read:donations / write:donations |
OSS donations |
read:digests |
Weekly-digest archive |
read:billing / write:billing |
BYOK keys, usage, billing controls |
read:account / write:account |
Identity view, account switch, email routes, PATs |
admin:users |
Closed-beta user approval (staff only) |
admin:accounts |
Operator account overrides (staff only) |
admin:read:platform / admin:read:orgs / admin:read:users |
Platform radar reads (staff only) |
Verb tables on this page are generated from the MCP server's scope catalog; headings and prose are hand-curated.