Nerdit
OfficialManages URLs and TLS through an embedded Caddy server, allowing agents to route services by path or subdomain, serve custom domains, and advertise over mDNS.
Deploys and manages applications as Docker containers with health checks, restarts, and versioned images.
Enables deploying applications directly from a Git repository URL.
Enables deploying applications from GitHub repositories.
Runs and manages local AI models through Ollama, exposing them via an OpenAI-compatible API.
Integrates with external AI APIs like OpenAI, allowing apps to use hosted models through a consistent environment.
Provides managed Redis databases, creating credentials and binding them into applications.
Nerdit
A self-hosted PaaS for your own machine, built so an AI agent can run it.
Point Nerdit at a folder or a Git repository: it builds the app, runs it as a
supervised service, gives it a URL, and wires it to a database or a local
model when it needs one. You drive it from the nerdit CLI, the local
dashboard, or an AI agent through its MCP server. The agent gets the same
operations as the CLI, behind scoped tokens and an audit log.
nerdit deploy ./my-app --wait # build, run, wait until healthy
nerdit serve llama3.1:8b --gpus 1 # local model behind an OpenAI-compatible APIYour apps, data and models stay on your hardware. The optional Nerdit Cloud account adds remote access and hosted URLs, but it doesn't run your apps. An unlinked machine keeps working on its own.
Free during the public beta, with up to five linked machines per account.
How it works
One daemon, nerditd, runs on your machine next to Docker:
nerdit CLI ───┐ ┌─ apps (Docker, health-checked, restarted)
dashboard ────┼─ REST ► nerditd ┼─ models (Ollama / vLLM, or an external API)
AI agent (MCP)┘ ├─ databases (Postgres, Redis)
└─ Caddy: URLs + TLSAn app says what it needs in a nerdit.toml next to its code:
[deploy]
name = "my-app"
port = 8000
[ai.default]
provider = "ollama" # or "api" for an external endpoint
model = "llama3.1:8b"The app starts with OPENAI_BASE_URL and OPENAI_API_KEY set. To move from a
local model to a hosted API, you change the config. The app code stays the
same.
Related MCP server: emergent-mcp
Install
curl -fsSL https://get.nerdit.ai | sh
nerdit doctorThis installs one signed archive: the CLI, the daemon and a pinned Caddy. You
don't need Python. It also registers a service and starts the daemon. You need
Docker installed and running. The dashboard is at http://127.0.0.1:9321/.
For your first deployment, see the quickstart. Other install methods are listed below.
Use it with an AI agent
Nerdit ships an MCP server with 59 tools. Your agent can deploy, wire and diagnose apps without a shell.
Claude Code, Cursor and other local clients (stdio)
On the machine where nerdit is installed:
claude mcp add nerdit -- nerdit mcpOther clients take the equivalent entry:
{
"mcpServers": {
"nerdit": { "command": "nerdit", "args": ["mcp"] }
}
}If your client doesn't inherit your shell's PATH, use an absolute path to
nerdit.
The server acts with the credentials of your nerdit CLI. Give an agent a
narrow token rather than your admin one:
nerdit token create --role submitter --scope my-app --expires-in 24hThe readonly role can list and read but not write. A token scoped to a
service can only change that service. See
Security for how the CLI selects a
token.
Claude on the web or desktop (remote, through Nerdit Cloud)
Link the machine with nerdit link. Then open Agents in
app.nerdit.ai and add the connection URL it shows as a
custom connector in Claude. You approve which machines or projects the
agent can reach. No token leaves your machine. See the
guide.
Over HTTP
Set [mcp].http_enabled = true to serve the same tools at
http://127.0.0.1:9321/api/mcp, behind a bearer token. See
MCP setup.
What to ask
Deploy the app in
./todo-api, give it a Postgres database, and tell me the URL once it's healthy.
blogis crash-looping. Find out why and fix it.
Serve
qwen2.5:7band pointmy-chatbotat it instead of the OpenAI API.
A typical run: capabilities → deploy (with dry_run first) →
wait_for_service → diagnose_service and service_logs if something fails.
An agent that has no files on the machine can use write_app_files, then
deploy_app. It can also use deploy_git.
The API is built for agents to retry safely:
Every write is idempotent, so a retry never runs an action twice.
Every write is audited.
Errors carry a stable
codeand a recoveryhint.Reads are bounded, so no single call floods the context window.
Secrets are write-only: an agent can set them but never read them back.
What you get
Deploy from a folder, a Git URL or a template, using a Dockerfile or the Python or Node buildpacks. Images are versioned, and deploys support
--dry-run,--waitand--rollback.Services restart with backoff and have HTTP and TCP health checks and stable ports. A redeploy cuts over with no downtime.
URLs and TLS come from an embedded Caddy. It routes by path or subdomain, serves your own domains, advertises over mDNS on the LAN, and uses an internal CA that you can pin.
Models run through Ollama or vLLM on your GPU, or through an external API. Apps get the same environment variables either way.
Databases: managed Postgres and Redis. Nerdit creates the credentials and binds them into apps through
[db.*].Projects group several services in one
nerdit.toml(nerdit apply). Variables are plain or secret. Secrets are encrypted at rest and can be rotated.Backups cover the control plane, with an offline restore. A managed database also gets a logical dump (
nerdit db dump) that you can restore while it runs.
Other install methods
pip. Needs Python 3.11+ and Docker, on Linux, macOS, or Windows through WSL2:
python3 -m venv ~/.venvs/nerdit && source ~/.venvs/nerdit/bin/activate
python -m pip install nerdit
nerdit init && nerdit doctorThe CLI, the daemon, the dashboard, MCP and mDNS are all included. The pip
package doesn't bundle Caddy or register a startup service. Install Caddy
yourself if you want HTTPS, and run nerdit init again after a reboot. See
installation.
From source.
git clone https://github.com/nerdit-ai/nerdit && cd nerdit
python -m venv venv && venv/bin/pip install -e ".[dev,mcp]"
(cd src/nerdit/daemon/web && npm ci && npm run build) # dashboard, required
venv/bin/nerdit initPlatforms
Linux: Ubuntu 22.04 or 24.04, with systemd.
macOS: Apple Silicon. Models run on the CPU.
Windows: through WSL2 only.
GPUs: NVIDIA needs Linux or WSL2. AMD support is experimental and behind a flag.
No telemetry
The daemon collects no product telemetry. Linking to Nerdit Cloud, public relay
traffic and external AI APIs send only the data their feature needs. The
optional [posthog] dashboard analytics hook is off by default and reports to
your own PostHog project.
Nerdit Cloud
app.nerdit.ai adds:
remote access and assistant connections
deploys from GitHub
hosted URLs
Your machine connects out to the cloud, so you open no inbound port. Hosted shares are private by default: only you and the people you allow in the Nerdit App can open them. Public access needs an explicit publication and follows the Terms.
Questions or feedback: feedback@nerdit.ai.
License
Apache-2.0, see LICENSE. "Nerdit" and the logo are trademarks and are not covered by the code license, see NOTICE.
Contributing
Issues and pull requests are welcome. CONTRIBUTING.md explains how contributions land in releases.
Available Tools
67 toolsadd_domainA
Serve a deployed app at a domain YOU own, from this node's own proxy (P26).
Unlike ``share_service`` (Nerdit's domain, over the cloud tunnel), this
is the node's embedded Caddy answering ``https://<domain>/`` directly —
in either proxy mode, at the ROOT, so a frontend needs no ``/<app>/``
base path. The one thing the daemon cannot do for you: point the
domain's DNS (A/AAAA/CNAME) at this machine. By default the domain is
served with the node's internal CA, so a client must run
``nerdit trust`` once. ``acme=True`` requests a public ACME
certificate; it needs an ADMIN token (403 ``domain.acme_forbidden``,
``reason: acme_admin_only`` — the node has one ACME account whose rate
limits every domain on it shares) and 409 ``domain.acme_disabled``
unless the daemon has ``[proxy.acme].enabled``.
Refusals:
422 ``domain.invalid`` — the name broke exactly one grammar rule and the
message names it (``empty``, ``whitespace``, ``not_bare``,
``has_port``, ``wildcard``, ``ip_literal``, ``idn``, ``single_label``,
``grammar``, ``reserved``); 409 ``domain.taken`` (one domain, one
service — never silently re-pointed); 422 ``domain.kind_unsupported``
(models and databases are not routed).
Returns ``{domain, url, state, cert_state, created}``; ``state`` is
``ready`` | ``withheld`` (``withheld`` = the proxy is off, the app is
not routed yet, or its ``[deploy].edge_auth`` secret does not resolve —
the row is stored either way and answers once it is). ``cert_state`` is
the orthogonal certificate fact: ``internal`` (this node's CA) |
``disabled`` (``acme`` asked for, ``[proxy.acme]`` off) | ``pending``
(issuing, or failing — check ``doctor``) | ``issued`` | ``expired``.
The URL then appears in ``get_service`` / ``list_routes`` under
``public_urls`` (kind ``domain``).
| Name | Required | Description | Default |
|---|---|---|---|
| acme | No | Tri-state certificate policy. ``true`` = request a public ACME certificate; ``false`` = serve with this node's internal CA; omit (the default ``null``) = keep the row's stored value, ``false`` on a new domain — so a re-run never downgrades an issued certificate. | |
| name | Yes | Name (or row id) of an existing deployed app — only kind 'service' can be exposed: ``share_service``/``add_domain`` refuse a model or database with 422 ``*.kind_unsupported``, while the remove tools just find nothing to undo. | |
| domain | Yes | Bare lowercase DNS name of at least two labels: no scheme, path, port, wildcard, IP literal or IDN/punycode. Case and one trailing dot are folded server-side, so ``App.Example.COM.`` and ``app.example.com`` are one resource. A name at or under this node's own hostname, ``base_domain`` or ``extra_hostnames`` is reserved. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so extensively: it explains the internal-CA trust requirement, ACME admin-token gating, disabled ACME errors, refusal codes, idempotency implications, row storage on `withheld`, and the orthogonal `cert_state` values. This is unusually complete for a mutation/deployment tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The main purpose and sibling distinction are front-loaded, and the structure is readable. It is long and enumerates several error codes and return states that could be trimmed, but most of that detail is useful because there are no annotations and no output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete for a complex proxy/certificate operation: it covers prerequisites, auth requirements, refusal modes, return shape, URL visibility in sibling tools, and certificate state transitions. With no output schema and no annotations, this level of detail is appropriate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents `name`, `domain`, `acme`, and `idempotency_key` in detail. The prose reinforces domain grammar, ACME authorization, and service-only exposure, but adds little parameter syntax or meaning beyond what is already present in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: serve a deployed app at a domain owned by the caller, through this node's own proxy. It explicitly distinguishes this from `share_service`, so the agent can tell which sibling to choose before opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly frames the alternative: `share_service` uses Nerdit's domain over the cloud tunnel, whereas this tool serves at the root via the node's embedded Caddy. It also states the key prerequisite the daemon cannot fulfill: DNS A/AAAA/CNAME must already point at this machine.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_hookA
Give a deployed app an inbound webhook address a provider can POST to.
The machine verifies each delivery's signature before the app sees it,
then POSTs the provider's headers and exact body to ``path``. No secret
travels through this tool: the response carries ``url`` (paste it at the
provider) and ``secret_key``; then store the provider's signing secret
with ``set_secret(name, {secret_key: value})``. ``url`` is null until
the machine is linked, and answers only once the app is shared.
Refusals: 422 ``hook.invalid`` (``reason`` ``name`` or ``shape``), 422
``hook.kind_unsupported`` (models and databases), 409 ``hook.exists``
(a different webhook already has that name). A replay of the same
webhook answers ``created: false``.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name (or row id) of an existing deployed app — only kind 'service' can be exposed: ``share_service``/``add_domain`` refuse a model or database with 422 ``*.kind_unsupported``, while the remove tools just find nothing to undo. | |
| path | Yes | App path each delivery is POSTed to, e.g. ``/webhooks/stripe``. | |
| header | No | sender ``hmac`` only (required there): the signature header. | |
| prefix | No | sender ``hmac`` only: text before the hex digest (``sha256=``). | |
| sender | Yes | Who signs the deliveries: ``stripe`` (Stripe-Signature), ``github`` (X-Hub-Signature-256), ``slack`` (X-Slack-Signature), ``hmac`` (HMAC-SHA256 lowercase hex in ``header``, after ``prefix``) or ``none`` (unsigned: the URL is the only guard). | |
| hook_name | Yes | Webhook name: lowercase letters, digits and '-', 1-32 characters, starting with a letter (e.g. ``stripe``); maps to ``NERDIT_HOOK_<NAME>_SECRET`` and ``NERDIT_HOOK_<NAME>_URL``. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so well: it explains that the machine verifies each delivery's signature before the app sees it, forwards the provider's headers and exact body to path, and that no secret travels through this tool. It also discloses prerequisites, null URL behavior, refusal codes, and idempotent replay semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the purpose, then explains the delivery behavior, secret handling, prerequisites, and refusals in a compact sequence. Despite its density, every sentence contributes operational information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no annotations and no output schema, the description is complete enough: it covers the creation workflow, signature verification, returned url and secret_key, sharing and linking prerequisites, refusal modes, and replay behavior. An agent has what it needs to call add_hook correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already explains all parameters, including sender values and header/prefix conditions. The description adds some workflow meaning around path and the returned secret_key, but does not add parameter-specific semantics beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: give a deployed app an inbound webhook address that a provider can POST to. It clearly distinguishes this from siblings like list_hooks, remove_hook, and set_secret by describing the creation workflow and the follow-up secret-storage step.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives strong usage context: only deployed service apps can be exposed, models and databases are refused, the app must be shared, and the machine must be linked before a URL appears. It also routes the follow-up signing-secret storage to set_secret, though it does not explicitly say when to use list_hooks or remove_hook for existing hooks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
apply_configA
Declaratively apply a multi-section daemon config document (all-or-nothing).
A dry run needs neither an ``If-Match`` nor an idempotency key.
| Name | Required | Description | Default |
|---|---|---|---|
| dry_run | No | true = validate and return the plan (what would change) with zero writes; nothing is built, deployed or audited as a change. | |
| if_match | No | ETag of the whole config, sent as ``If-Match`` (the daemon requires it on a real apply; 409 ``config.stale`` when it no longer matches). Omit and the current ETag is read and used for you; ``*`` matches unconditionally. Not needed when ``dry_run`` is true. | |
| sections | Yes | Desired state as ``{section: {key: value}}``. Only the sections named are touched; each is merged and validated like ``set_config``'s ``values`` (an omitted key keeps its value, null deletes a NULLABLE key — a null on a non-nullable one is a 422 — and an unknown key is a 422). One invalid key rejects the whole document. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does disclose two genuinely important traits: the apply is atomic ('all-or-nothing', one invalid key rejects the whole document per schema) and a dry run is side-effect-free and exempt from both If-Match and idempotency keys. It still leaves out permission/auth requirements and what the dry-run plan response looks like.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the atomicity guarantee front-loaded and the dry-run caveat immediately after. Nothing could be removed without losing information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-parameter mutation tool with no annotations and no output schema, the description plus the rich schema documentation covers what an agent needs: atomicity, the dry-run escape hatch, and the stale-ETag/validation failure modes. Nothing essential to invoking it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline would be 3, but the description adds cross-parameter semantics that the individual fields only partially state: that a dry run needs neither an If-Match nor an idempotency key. That relational constraint is useful and slightly exceeds what the schema spells out for idempotency_key.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('declaratively apply a multi-section daemon config document') plus the key semantic of the operation ('all-or-nothing'), which is more than a restatement of the name. It does not, however, contrast itself with the sibling set_config, whose merge semantics it only references indirectly via the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by 'declaratively apply' and 'all-or-nothing' — an agent can infer this is the whole-document path versus set_config's incremental path — but the description never names that alternative or states when to prefer one over the other. The dry-run sentence guides parameter choice rather than tool selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
apply_projectA
Apply a project's declaration: deploy every [services.<name>] of its nerdit.toml.
The loop: ``get_project`` (read) → ``apply_project(dry_run=true)`` →
if ``status`` is ``waiting_for_variables``, do NOT invent or request
the values in chat: ask the human to run ``nerdit vars set <project>
--secret --prompt KEY`` for each name in ``missing``, then dry-run
again → ``apply_project`` → ``wait_for_service`` once per ``label`` in
``services`` → ``diagnose_service`` on any that failed.
The response lists ``services`` in declaration order, each with its
``label`` (the name every other tool takes: ``web`` is the project
name, any other service ``<service>--<project>``), ``action``
(``fresh``/``redeploy``) and, on a dry run, its ``plan`` (env key names
only, values never); ``public_urls`` carries every advertised address.
``waiting_for_variables`` deploys nothing and returns names only.
Asynchronous like every deploy: ``applied`` means accepted, not healthy.
Every refusal lands before the first build, and a dry run creates
nothing and mints no idempotency key. A project another token owns is
409 ``project.owned``. There is NO rollback across services: a failure
on one is ``project.apply_incomplete``, whose ``services`` lists the
ones already applied and ``failed`` the one that was not — fix it and
apply again (done services redeploy, the rest are retried). A
``[deploy]``-only ``nerdit.toml`` is not a declaration: use
``deploy_app`` / ``deploy_git`` for it (they answer 422
``deploy.use_apply`` on a declaration).
SANDBOX: by DEFAULT containers run with all Linux capabilities dropped
(``cap_drop=["ALL"]``) and no-new-privileges — both are operator settings
(``[containers].drop_all_caps`` / ``[containers].no_new_privileges``), so
read the live profile in ``capabilities.sandbox`` rather than assuming: an
operator may have relaxed it. Under that default, an image whose entrypoint
does root work — ``chown``/``chmod`` of its own runtime dirs, dropping
privileges via ``setuid``/``setgid``, writing ``/var/run`` — dies before
your app ever starts. Stock ``nginx`` is the classic trap. Use a non-root
image and a non-root ``USER`` that owns the files it writes: for a static
site, ``nginxinc/nginx-unprivileged`` (listens on **8080**, so set
``port=8080``) or any tiny static server. A crash from this reports
remediation code ``image_needs_privileges`` in ``diagnose_service``. PORT
CONTRACT: the container MUST listen on the declared ``port`` (the tool
argument, else ``nerdit.toml`` ``[deploy].port``, else **8000**) — that is
the only port the daemon publishes and health-checks, so listening anywhere
else fails the health probe with a healthy-looking container. A port below
1024 is NOT the reason a root entrypoint is needed: every container runs on
the docker bridge in its own network namespace (never host networking),
where Docker sets ``net.ipv4.ip_unprivileged_port_start=0``, so binding 80
needs no capability and no root — the chown/setuid work does.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | No | Git branch or tag to clone; only with ``repo_url``. | |
| dry_run | No | true = validate and return the plan (what would change) with zero writes; nothing is built, deployed or audited as a change. | |
| project | Yes | Immutable prj_ ID or name of the project to apply. The resolved name must equal ``[project].name`` in ``nerdit.toml``. An unknown name may be created; an unknown or retired ID is refused. | |
| repo_url | No | https Git URL whose root ``nerdit.toml`` is the declaration. Omit to apply the project's workspace (what ``write_project_files`` wrote). | |
| token_ref | No | Private-repo credential as a REFERENCE, never a token: ``${vars.KEY}``, ``${secrets.shared.KEY}`` or ``${github.installation}``; only with ``repo_url``. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: asynchronous semantics (``applied`` means accepted, not healthy), refusals before first build, dry run creating nothing and minting no idempotency key, 409 ``project.owned``, and no rollback across services via ``project.apply_incomplete``. It also documents sandbox defaults, the remediation code ``image_needs_privileges``, and the port/health-probe contract.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded: purpose first, then the operating loop, then response shape, then failure semantics. It is long, and the SANDBOX/PORT CONTRACT block is verbose, but nearly every sentence encodes a concrete failure mode or default an agent would otherwise get wrong; trimming would risk losing actionable detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description compensates by naming the response fields (``services``, ``label``, ``action``, ``plan``, ``public_urls``, ``missing``, ``failed``) and their semantics. For a complex, multi-stage deploy tool it covers prerequisites, ordering, identity conflicts, partial-failure recovery, and environment defaults.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds meaning the schema does not: ``dry_run`` creates nothing and mints no idempotency key, and the PORT CONTRACT clarifies how the ``port`` argument interacts with ``nerdit.toml`` ``[deploy].port`` and the default 8000. It does not re-explain ``repo_url``/``token_ref``/``ref`` beyond the schema, which is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: deploy every ``[services.<name>]`` of a project's ``nerdit.toml``. It explicitly contrasts itself with ``deploy_app``/``deploy_git`` for ``[deploy]``-only manifests, so an agent can tell it apart from the sibling deploy tools without inspecting schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit ordered loop (get_project → dry_run → vars set → apply → wait_for_service → diagnose_service) and the branch condition ``waiting_for_variables``. It names the alternatives for manifests that are not declarations, and explicitly forbids inventing secret values in chat.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
capabilitiesA
Describe this daemon: version, caller role/quotas, URL grammar, backends.
Role-aware, pure in-memory read — call it first to learn what the
daemon can do (buildpacks, model backends, proxy mode and public-URL
shape, deploy limits, git allowlist, feature flags) instead of probing
endpoints. Admin callers additionally receive ``proxy.admin_addr`` and
the ``paths`` block.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the disclosure burden and does well: it declares 'pure in-memory read' and notes role-aware behavior where admin callers receive additional fields. It does not discuss failure modes, caching, or permission requirements in more detail, but the key safety profile is clear.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence front-loads the core purpose, and the second paragraph adds useful context. There is mild repetition in 'learn what the daemon can do' following 'Describe this daemon,' and the parenthetical list is long, but overall it is efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must explain return contents, and it does: version, role/quotas, URL grammar, backends, buildpacks, proxy details, deploy limits, git allowlist, feature flags, plus admin-only fields. That is complete enough for a zero-parameter introspection call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so parameter semantics are not applicable; baseline 4 applies. The description appropriately adds no parameter information because there is none.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource: 'Describe this daemon,' then enumerates what is returned (version, caller role/quotas, URL grammar, backends). It also positions the tool as a first-stop discovery call rather than endpoint probing, which distinguishes it from config/diagnostic siblings like get_config or doctor.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'call it first to learn what the daemon can do ... instead of probing endpoints' provides an explicit trigger and an alternative behavior. It does not explicitly state when not to use it or name sibling alternatives, so it stops short of the top score.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cluster_statsB
Get aggregate cluster metrics (GPUs in use/total, services up).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It does disclose some return content (GPU usage and services up) and implies an aggregate read-only snapshot, but it omits important traits such as freshness, auth requirements, and exact return shape, leaving meaningful gaps for an unannotated tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is a single front-loaded sentence with no wasted words. It quickly conveys the verb, resource, scope, and example metrics, which is appropriately sized for a parameterless stats tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a zero-parameter stats tool with no output schema, the description should explain the return value more completely. It names a few metrics but does not indicate whether the response includes other cluster health fields, formatting, or freshness, so an agent has only a partial picture of what to expect.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there are no parameter semantics to document; the baseline for a parameterless tool is 4. The description appropriately does not speculate about parameters that don't exist.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource ("Get aggregate cluster metrics") and names example metrics ("GPUs in use/total, services up"), which is clearer than a tautology. It implies an aggregate/cluster-level view rather than per-resource listing, but does not explicitly distinguish itself from siblings like service_stats, list_gpus, or list_services.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states what the tool returns but gives no guidance on when to use it versus alternatives such as service_stats or list_gpus. There are no exclusions, prerequisites, or situational cues to help an agent choose among the many sibling diagnostic/listing tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_databaseA
Provision a managed database (kind=database workload).
Provisioning is asynchronous: the call returns immediately with the
database row in ``building`` while the daemon pulls the image off-tick
and launches the server; poll ``list_databases`` (or ``get_service``)
until ``db_ready`` is true. Lifecycle (stop / restart / delete) goes
through the existing service tools.
The daemon mints the password server-side and stores it write-only — it
is NEVER returned by this tool (key names only). An app connects to this
database by declaring a ``[db.<name>]`` binding (``provider="managed"``,
``database`` = this database's name — the ``database`` field is
required, there is no implicit default); at each launch it receives
``NERDIT_DB_<NAME>_URL``, and the ``default`` binding also sets
``DATABASE_URL`` (Postgres) or ``REDIS_URL`` (Redis) with the composed
DSN so an unmodified client library connects with no code change.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Service name for the new database (lowercase DNS label, ≤ 63 chars). Omit to use the backend's own name prefix. An existing name is a conflict, not a redeploy. | |
| backend | No | Data backend to provision: ``postgres`` or ``redis``. Omit to use the daemon's ``[databases].default_backend`` (``postgres`` out of the box); an unknown value is refused, never silently defaulted. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so richly: it discloses asynchronous return with state 'building', daemon-side image pull and launch, polling requirements, server-side write-only password handling, and that passwords are never returned. It also explains how applications bind to the database and which environment variables are injected.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded, and the following paragraphs are organized around async behavior, lifecycle routing, credentials, and application binding. Despite its length, each section provides operationally relevant context without filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given zero annotations, no output schema, and fully documented optional parameters, the description covers the critical unknowns: asynchronous state, polling, lifecycle boundaries, credential non-return, and binding semantics. An agent has enough information to invoke the tool and interpret the immediate result correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents name, backend, and idempotency_key fully. The description does not add parameter-level meaning beyond the schema, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: provisioning a managed database as a database workload. It clearly distinguishes creation from lifecycle operations by saying stop/restart/delete go through service tools, so an agent can tell it apart from siblings like restart_service or list_databases.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains the asynchronous provisioning flow and explicitly routes polling to list_databases or get_service until db_ready is true. It also explicitly excludes lifecycle operations by directing stop/restart/delete to existing service tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_projectA
Create an empty project, reserving its name for your token.
A project groups one app's services, the models and databases they
reference, and their public addresses. The name is reserved for the
token that created it: another token's deploy, ``serve_model`` or
``create_database`` of that name is refused with 409 ``project.owned``
(an admin bypasses), and the project remains after ``remove_service``
until ``delete_project`` releases it. You rarely need this before a
deploy — every deployed app already becomes a project of its own name —
but it lets you hold a name ahead of the first deploy. A name another
token already reserved through ``set_secret`` is 409
``service.name_claimed``; a name in use is 409 ``project.exists``.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | New project name: a lowercase DNS label of at most 40 characters (letters, digits, '-'), never containing '--'; reserved platform names are refused with 422. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden and does: it discloses ownership semantics, the admin bypass, persistence until delete_project, and the three distinct 409/422 failure modes with their error codes and meanings. This is exactly the failure-mode context an agent cannot infer from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and effect are front-loaded, then lifecycle, then error codes, in a logical order with no filler. It runs long and packs multiple escape-coded conditions into one paragraph, which costs a bit of scannability, but every clause conveys distinct behavioral information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter creation tool with no annotations and no output schema, the description covers ownership, lifecycle, and every documented failure path. The only gap is that it never indicates what is returned on success (e.g. a project record or just the reserved name), which the agent must discover empirically.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters (name format rules, idempotency_key retry semantics) are already fully documented in the schema. The description adds contextual meaning about what the name reservation implies, but no syntax or defaulting detail beyond the schema, which is the baseline-3 case.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ("Create an empty project") plus the non-obvious effect of reserving the name for the calling token. It is clearly distinguishable from siblings: deploy/serve_model/create_database implicitly produce projects, create_project pre-claims a name, and delete_project releases it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when NOT to use it ("You rarely need this before a deploy — every deployed app already becomes a project of its own name") and when it is warranted ("it lets you hold a name ahead of the first deploy"). Competing paths (deploy, serve_model, create_database, set_secret) are named with the condition that selects each.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_projectA
Delete a project: every service in it, then the row, releasing the name.
Services go one by one through the same cascade as ``remove_service``
(owner-or-admin each; a dependency guard or an in-flight run refuses a
service exactly as there). The project row goes last and only when
every service went: a refusal leaves the project in place with 409
``project.delete_incomplete`` listing ``deleted`` and ``failed``, and
re-running after the fix is idempotent. Owner or admin only.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Immutable prj_ ID or name of an existing project. Prefer the ID from list_projects: a retired ID never addresses a same-name replacement. | |
| purge | No | CSV of durable state to destroy alongside EVERY service in the project: ``secrets``, ``data``, ``images``, ``workspace``. Default ``secrets``; an empty string purges nothing; an unknown token is a 422 ``service.invalid_purge``. | secrets |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so richly: it discloses destructive cascade order, that the row is deleted only if all services succeed, the 409 project.delete_incomplete response with deleted/failed lists, idempotent re-run behavior, and the owner-or-admin authorization requirement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action ('Delete a project:...') and every following sentence adds concrete behavior (cascade, refusal shape, idempotency, auth). It is dense and slightly long-winded with parentheticals, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive mutation with no annotations and no output schema, the description covers order of operations, failure response, idempotency, and permissions well. The one meaningful gap is that it does not restate that purge destroys durable state (secrets/data/images/workspace), leaving that critical destructive detail entirely to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so name, purge, and idempotency_key are already fully documented in the schema, establishing the baseline of 3. The description's mention of 'releasing the name' mildly reinforces the name parameter but adds no syntax, defaults, or purge semantics beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Delete a project') and enumerates exactly what is removed and in what order, including that the name is released. It is distinguishable from sibling remove_service by explicitly noting the project row and the cascade through all contained services.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
By saying services go through 'the same cascade as remove_service,' it implicitly tells the agent that single-service removal belongs to remove_service and full-project teardown belongs here. It does not fully spell out when-not/exclusions, so it stops short of a 5, but the routing signal is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
deployA
Use when: the source is a local folder. Asynchronous — follow with wait_for_service.
Deploys that folder (build + run + URL), or rolls back with
``rollback=True``. The response carries ``next_step`` — a machine-shaped
``{tool, args, why}`` naming the very call to make next — because a 201
here means "the build was accepted", never "the app is up".
``path`` is read by the process serving this tool, so it works only on
the local ``nerdit mcp`` process; on a remote/HTTP connection it is
refused with ``mcp.local_path_unavailable``. Use ``write_app_files`` +
``deploy_app`` there, or ``deploy_git`` / ``deploy_template``.
``rollback=True`` needs no path and works over either transport.
If the app's ``nerdit.toml`` declares ``[ai.*]`` bindings, each is
injected at launch as ``NERDIT_AI_<NAME>_URL/_KEY/_MODEL``, and the
``default`` binding also sets ``OPENAI_BASE_URL/OPENAI_API_KEY/
OPENAI_MODEL`` — point the app's OpenAI SDK at these; no code change
needed. ``dry_run=True``
returns the build/config plan diff (env key names only, values never).
``nerdit.toml`` ``[deploy]`` keys — anything else is IGNORED and
reported back in the response ``hints``: ``name``, ``port``, ``gpus``,
``start``, ``health``, ``health_type`` (``http``|``tcp``),
``memory_limit``, ``cpu_limit``, ``volumes``, ``release``, ``cutover``,
``auto_deploy``, ``edge_auth``, ``build_settings``. Generated Node builds run
``scripts.build`` automatically;
override it through ``[deploy.build_settings]`` or use a Dockerfile.
``release`` runs once inside the new image before traffic moves; if it
fails the deploy settles ``failed`` and the image reverts, never the data —
whatever the migration already committed stays, so write idempotent
migrations. ``cutover`` null = zero-downtime swap
when eligible, false = same-port swap.
On a successful non-dry-run deploy the
response carries ``summary`` (app/status/version/public_url), ``hints``
(ordered one-liners, never empty) and ``next_step`` (the structured
follow-up call); a ``dry_run`` plan and a ``rollback`` response carry
none of the three — read a plan's advisories from its ``warnings``. On a
node in ``path`` proxy mode the app is served at ``/<name>/``, so a
frontend must be built with that base
path; in ``subdomain`` mode it is served at the root of its own
hostname and needs none — read ``capabilities.proxy.mode``.
``build_settings`` overrides
preset/install/build/start/node_version/package_manager/subdir/public_env.
``preset`` selects node/nextjs/python/dockerfile; null resets to
repository/default detection.
An existing Dockerfile retains precedence.
Omit it to preserve saved overrides; a null field resets to repository/default,
and ``build: false`` skips compilation.
``public_env`` passes public build-time variables (shown in clear in a dry
run; secret references are refused). Secret mounts are unsupported;
runtime env is unchanged.
SANDBOX: by DEFAULT containers run with all Linux capabilities dropped
(``cap_drop=["ALL"]``) and no-new-privileges — both are operator settings
(``[containers].drop_all_caps`` / ``[containers].no_new_privileges``), so
read the live profile in ``capabilities.sandbox`` rather than assuming: an
operator may have relaxed it. Under that default, an image whose entrypoint
does root work — ``chown``/``chmod`` of its own runtime dirs, dropping
privileges via ``setuid``/``setgid``, writing ``/var/run`` — dies before
your app ever starts. Stock ``nginx`` is the classic trap. Use a non-root
image and a non-root ``USER`` that owns the files it writes: for a static
site, ``nginxinc/nginx-unprivileged`` (listens on **8080**, so set
``port=8080``) or any tiny static server. A crash from this reports
remediation code ``image_needs_privileges`` in ``diagnose_service``. PORT
CONTRACT: the container MUST listen on the declared ``port`` (the tool
argument, else ``nerdit.toml`` ``[deploy].port``, else **8000**) — that is
the only port the daemon publishes and health-checks, so listening anywhere
else fails the health probe with a healthy-looking container. A port below
1024 is NOT the reason a root entrypoint is needed: every container runs on
the docker bridge in its own network namespace (never host networking),
where Docker sets ``net.ipv4.ip_unprivileged_port_start=0``, so binding 80
needs no capability and no root — the chown/setuid work does.
| Name | Required | Description | Default |
|---|---|---|---|
| env | No | Runtime env for the container: values are literal strings, never resolved (a ``${secrets.*}`` reference is passed through as text); a null value deletes that key on redeploy. Secrets go through ``set_secret``, which overrides an ``env`` key of the same name at launch. | |
| gpus | No | GPUs to reserve for the container (0 = none). Omit to use ``[deploy].gpus``, else the count already recorded on a redeploy, else 0. | |
| name | No | App name (lowercase DNS label); an existing name redeploys it in place. Omit to use the folder's ``nerdit.toml`` ``[deploy].name``, else the folder's own name. Required with ``rollback=True``. | |
| path | No | Path to the app folder ON THE DAEMON HOST (``~`` expanded); its contents are zipped and uploaded. Required unless ``rollback=True``. Usable ONLY from the local ``nerdit mcp`` process: over a remote/HTTP connection to a daemon it is refused with ``mcp.local_path_unavailable``, since it would read that host's disk and not yours — send the source with ``write_app_files`` + ``deploy_app`` instead. | |
| port | No | Port the container listens on: the only port published and health-checked. Omit to use ``nerdit.toml`` ``[deploy].port``, else the port already recorded on a redeploy, else 8000. | |
| start | No | Start command run inside the built image (shell syntax). Omit to use ``[deploy].start`` or the buildpack default. | |
| health | No | HTTP health path probed on ``port`` (e.g. ``/health``); the app is ``healthy`` once it answers 2xx. Omit to keep ``[deploy].health`` (or the existing app's probe on redeploy). | |
| vendor | No | GPU vendor to reserve when ``gpus`` > 0 (``nvidia`` or ``amd``); omit to let the daemon choose on a fresh deploy — a redeploy keeps the vendor already recorded. | |
| dry_run | No | true = validate and return the plan (what would change) with zero writes; nothing is built, deployed or audited as a change. | |
| rollback | No | true = re-point the service at its previous image instead of building: only ``name`` and ``idempotency_key`` are read, no folder is zipped and every other argument is ignored. Refused together with ``dry_run``. | |
| build_settings | No | Build overrides, same keys as ``[deploy.build_settings]`` in ``nerdit.toml``: ``preset`` (node/nextjs/python/dockerfile), ``install``, ``build`` (``false`` skips compilation), ``start``, ``node_version``, ``package_manager``, ``subdir``, ``public_env`` (build-time variables baked into the bundle, never secrets). Commands run inside the build container. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so extensively: async acceptance vs. app readiness, local-path transport restrictions, [deploy] key handling and ignored keys, release/cutover failure semantics, dry_run no-write behavior, sandbox capability defaults, and port publishing/health-check rules. These are substantive behavioral disclosures, not restatements of schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is front-loaded with the usage condition and async contract, and structured into clear operational concerns. It is unusually long and packs deployment manual detail into the description, but nearly all of it is actionable for a complex deploy tool, so it avoids fluff even if it is not terse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter deploy tool with no annotations and no output schema, the description is complete: it explains what is returned on success, what next_step is, what dry_run and rollback responses omit, and how to follow up. Nothing critical to correct invocation appears missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already defines each parameter. The description still adds cross-parameter meaning: rollback reads only name and idempotency_key, path is local-process-only, build_settings nulls reset to repository/default, and public_env refuses secrets. This goes beyond the schema, though some of it duplicates schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening states a specific verb and resource: deploying a local folder (build + run + URL), with rollback as a secondary mode. It explicitly distinguishes this tool from deploy_git, deploy_template, deploy_app, and the write_app_files path, so an agent can route correctly without opening another schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives an explicit selection rule ('Use when: the source is a local folder'), states the asynchronous follow-up (wait_for_service), and names alternatives for remote/HTTP connections (write_app_files + deploy_app, deploy_git, deploy_template). It also clarifies rollback usage and dry_run boundaries.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
deploy_appA
Use when: you used write_app_files. Asynchronous — follow with wait_for_service.
Distinct from ``deploy`` (which uploads a folder from the machine the MCP
server runs on) and from ``deploy_git`` (which clones a repository): this
one deploys the workspace of the same name, so it is the deploy verb for
an app you wrote in this conversation. Call it again after each
``write_app_files`` to ship an edit — ``redeploy_service`` refuses
workspace apps by design and points back here.
If the workspace's ``nerdit.toml`` declares ``[ai.*]`` bindings, each is
injected at launch as ``NERDIT_AI_<NAME>_URL/_KEY/_MODEL``, and the
``default`` binding also sets ``OPENAI_BASE_URL/OPENAI_API_KEY/
OPENAI_MODEL``. A dry run returns the build/config plan diff with env key
names only, values never, and mints no idempotency key.
``nerdit.toml`` ``[deploy]`` keys — anything else is IGNORED and
reported back in the response ``hints``: ``name``, ``port``, ``gpus``,
``start``, ``health``, ``health_type`` (``http``|``tcp``),
``memory_limit``, ``cpu_limit``, ``volumes``, ``release``, ``cutover``,
``auto_deploy``, ``edge_auth``, ``build_settings``. Use ``[deploy.build_settings]``
for build overrides, or a Dockerfile for custom builds.
``release`` runs once inside the new image before traffic moves; if it
fails the deploy settles ``failed`` and the image reverts, never the data —
whatever the migration already committed stays, so write idempotent
migrations. ``cutover`` null = zero-downtime swap
when eligible, false = same-port swap. ``env`` values are literal and
never resolve ``${secrets.*}``: a secret reaches the app through
``set_secret`` / ``nerdit secrets set`` (injected at launch, overriding
an ``env`` key of the same name).
On a successful non-dry-run deploy the
response carries ``summary`` (app/status/version/public_url), ``hints``
(ordered one-liners, never empty) and ``next_step`` (the structured
follow-up call); a ``dry_run`` plan carries none of the three — read a
plan's advisories from its ``warnings``. On a node in ``path``
proxy mode the app is served at ``/<name>/``, so a frontend must be
built with that base path.
``build_settings`` overrides
preset/install/build/start/node_version/package_manager/subdir/public_env.
``preset`` selects node/nextjs/python/dockerfile; null resets to
repository/default detection.
An existing Dockerfile retains precedence.
Omit it to preserve saved overrides; a null field resets to repository/default,
and ``build: false`` skips compilation. Commands run inside the build container.
``public_env`` passes public build-time variables (shown in clear in a dry
run; secret references are refused). Secret mounts are unsupported;
runtime env is unchanged.
SANDBOX: by DEFAULT containers run with all Linux capabilities dropped
(``cap_drop=["ALL"]``) and no-new-privileges — both are operator settings
(``[containers].drop_all_caps`` / ``[containers].no_new_privileges``), so
read the live profile in ``capabilities.sandbox`` rather than assuming: an
operator may have relaxed it. Under that default, an image whose entrypoint
does root work — ``chown``/``chmod`` of its own runtime dirs, dropping
privileges via ``setuid``/``setgid``, writing ``/var/run`` — dies before
your app ever starts. Stock ``nginx`` is the classic trap. Use a non-root
image and a non-root ``USER`` that owns the files it writes: for a static
site, ``nginxinc/nginx-unprivileged`` (listens on **8080**, so set
``port=8080``) or any tiny static server. A crash from this reports
remediation code ``image_needs_privileges`` in ``diagnose_service``. PORT
CONTRACT: the container MUST listen on the declared ``port`` (the tool
argument, else ``nerdit.toml`` ``[deploy].port``, else **8000**) — that is
the only port the daemon publishes and health-checks, so listening anywhere
else fails the health probe with a healthy-looking container. A port below
1024 is NOT the reason a root entrypoint is needed: every container runs on
the docker bridge in its own network namespace (never host networking),
where Docker sets ``net.ipv4.ip_unprivileged_port_start=0``, so binding 80
needs no capability and no root — the chown/setuid work does.
| Name | Required | Description | Default |
|---|---|---|---|
| env | No | Runtime env for the container: values are literal strings, never resolved (a ``${secrets.*}`` reference is passed through as text); a null value deletes that key on redeploy. Secrets go through ``set_secret``, which overrides an ``env`` key of the same name at launch. | |
| gpus | No | GPUs to reserve for the container (0 = none). Omit to use ``[deploy].gpus``, else the count already recorded on a redeploy, else 0. | |
| name | Yes | Name of an existing workspace (also the app name it deploys under). No workspace by that name is ``404 workspace.not_found``. | |
| port | No | Port the container listens on: the only port published and health-checked. Omit to use ``nerdit.toml`` ``[deploy].port``, else the port already recorded on a redeploy, else 8000. | |
| start | No | Start command run inside the built image (shell syntax). Omit to use ``[deploy].start`` or the buildpack default. | |
| health | No | HTTP health path probed on ``port`` (e.g. ``/health``); the app is ``healthy`` once it answers 2xx. Omit to keep ``[deploy].health`` (or the existing app's probe on redeploy). | |
| vendor | No | GPU vendor to reserve when ``gpus`` > 0 (``nvidia`` or ``amd``); omit to let the daemon choose on a fresh deploy — a redeploy keeps the vendor already recorded. | |
| dry_run | No | true = validate and return the plan (what would change) with zero writes; nothing is built, deployed or audited as a change. | |
| build_settings | No | Build overrides, same keys as ``[deploy.build_settings]`` in ``nerdit.toml``: ``preset`` (node/nextjs/python/dockerfile), ``install``, ``build`` (``false`` skips compilation), ``start``, ``node_version``, ``package_manager``, ``subdir``, ``public_env`` (build-time variables baked into the bundle, never secrets). Commands run inside the build container. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so extensively: async behavior, dry-run side effects, release failure semantics, env/secret handling, response fields, sandbox constraints, and port contract. No contradiction with annotations is possible because none are provided.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the key usage rule and sibling distinctions, and it is organized into useful paragraphs. However, it is unusually long and dense for a tool description; nearly every detail is relevant, but the length reduces scannability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex mutation tool with 10 parameters, no annotations, and no output schema, the description is complete enough to invoke and interpret correctly. It covers usage, behavior, response shape, failure semantics, sandbox requirements, and build/deploy configuration.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds substantial parameter meaning beyond the schema. It explains dry-run plan behavior, port and sandbox implications, build_settings reset/precedence rules, env secret overrides, and idempotency-key minting behavior.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: deploying the workspace app of the same name. It explicitly distinguishes this tool from sibling tools `deploy` and `deploy_git`, so an agent can select it correctly without opening other schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit triggers and conditions: use after `write_app_files`, call again after each edit, and follow asynchronously with `wait_for_service`. It also names alternatives and exclusions, including that `redeploy_service` refuses workspace apps by design.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
deploy_gitA
Use when: the app lives in a Git repo. Asynchronous — follow with wait_for_service.
Clones ``repo_url`` server-side (public GitHub by default), then builds
and runs it like ``deploy``. The token reference is resolved server-side
— a raw credential never passes through the tool.
``dry_run=True`` returns the build/config plan diff (env key names only,
values never).
If the repo's ``nerdit.toml`` declares ``[ai.*]`` bindings, each is
injected at launch as ``NERDIT_AI_<NAME>_URL/_KEY/_MODEL``, and the
``default`` binding also sets ``OPENAI_BASE_URL/OPENAI_API_KEY/
OPENAI_MODEL`` — point the app's OpenAI SDK at these; no code change
needed.
``nerdit.toml`` ``[deploy]`` keys — anything else is IGNORED and
reported back in the response ``hints``: ``name``, ``port``, ``gpus``,
``start``, ``health``, ``health_type`` (``http``|``tcp``),
``memory_limit``, ``cpu_limit``, ``volumes``, ``release``, ``cutover``,
``auto_deploy``, ``edge_auth``, ``build_settings``. Generated Node builds run
``scripts.build`` automatically;
override it through ``[deploy.build_settings]`` or use a Dockerfile.
``release`` runs once inside the new image before traffic moves; if it
fails the deploy settles ``failed`` and the image reverts, never the data —
whatever the migration already committed stays, so write idempotent
migrations. ``cutover`` null = zero-downtime swap
when eligible, false = same-port swap.
On a successful non-dry-run deploy the
response carries ``summary`` (app/status/version/public_url), ``hints``
(ordered one-liners, never empty) and ``next_step`` (the structured
follow-up call); a ``dry_run`` plan carries none of the three — read a
plan's advisories from its ``warnings``. On a node in ``path``
proxy mode the app is served at ``/<name>/``, so a frontend must be
built with that base path.
``build_settings`` overrides
preset/install/build/start/node_version/package_manager/subdir/public_env.
``preset`` selects node/nextjs/python/dockerfile; null resets to
repository/default detection.
An existing Dockerfile retains precedence.
Omit it to preserve saved overrides; a null field resets to repository/default,
and ``build: false`` skips compilation.
``public_env`` passes public build-time variables (shown in clear in a dry
run; secret references are refused). Secret mounts are unsupported;
runtime env is unchanged.
SANDBOX: by DEFAULT containers run with all Linux capabilities dropped
(``cap_drop=["ALL"]``) and no-new-privileges — both are operator settings
(``[containers].drop_all_caps`` / ``[containers].no_new_privileges``), so
read the live profile in ``capabilities.sandbox`` rather than assuming: an
operator may have relaxed it. Under that default, an image whose entrypoint
does root work — ``chown``/``chmod`` of its own runtime dirs, dropping
privileges via ``setuid``/``setgid``, writing ``/var/run`` — dies before
your app ever starts. Stock ``nginx`` is the classic trap. Use a non-root
image and a non-root ``USER`` that owns the files it writes: for a static
site, ``nginxinc/nginx-unprivileged`` (listens on **8080**, so set
``port=8080``) or any tiny static server. A crash from this reports
remediation code ``image_needs_privileges`` in ``diagnose_service``. PORT
CONTRACT: the container MUST listen on the declared ``port`` (the tool
argument, else ``nerdit.toml`` ``[deploy].port``, else **8000**) — that is
the only port the daemon publishes and health-checks, so listening anywhere
else fails the health probe with a healthy-looking container. A port below
1024 is NOT the reason a root entrypoint is needed: every container runs on
the docker bridge in its own network namespace (never host networking),
where Docker sets ``net.ipv4.ip_unprivileged_port_start=0``, so binding 80
needs no capability and no root — the chown/setuid work does.
| Name | Required | Description | Default |
|---|---|---|---|
| env | No | Runtime env for the container: values are literal strings, never resolved (a ``${secrets.*}`` reference is passed through as text); a null value deletes that key on redeploy. Secrets go through ``set_secret``, which overrides an ``env`` key of the same name at launch. | |
| ref | No | Branch or tag to clone. Omit for the repository's default branch. Recorded on the app, so ``redeploy_service`` re-clones this ref. | |
| gpus | No | GPUs to reserve for the container (0 = none). Omit to use ``[deploy].gpus``, else the count already recorded on a redeploy, else 0. | |
| name | Yes | App name (lowercase DNS label). A new name creates the app; an existing one redeploys it in place. | |
| port | No | Port the container listens on: the only port published and health-checked. Omit to use ``nerdit.toml`` ``[deploy].port``, else the port already recorded on a redeploy, else 8000. | |
| start | No | Start command run inside the built image (shell syntax). Omit to use ``[deploy].start`` or the buildpack default. | |
| health | No | HTTP health path probed on ``port`` (e.g. ``/health``); the app is ``healthy`` once it answers 2xx. Omit to keep ``[deploy].health`` (or the existing app's probe on redeploy). | |
| subdir | No | Subdirectory of the repo to build (monorepo subtree). Omit to build from the repository root. | |
| vendor | No | GPU vendor to reserve when ``gpus`` > 0 (``nvidia`` or ``amd``); omit to let the daemon choose on a fresh deploy — a redeploy keeps the vendor already recorded. | |
| dry_run | No | true = validate and return the plan (what would change) with zero writes; nothing is built, deployed or audited as a change. | |
| repo_url | Yes | ``https://`` clone URL, on a host the daemon allows (``capabilities.deploy.git_allowed_hosts``, ``github.com`` by default). A URL carrying credentials is refused — pass ``token_ref`` instead. | |
| token_ref | No | Private-repo credential as a *reference*, never a raw token: ``${secrets.KEY}``, ``${secrets.shared.KEY}``, or the literal ``${github.installation}`` on a node linked to an account with the Nerdit GitHub App installed on that repo. Omit for a public repo. | |
| build_settings | No | Build overrides, same keys as ``[deploy.build_settings]`` in ``nerdit.toml``: ``preset`` (node/nextjs/python/dockerfile), ``install``, ``build`` (``false`` skips compilation), ``start``, ``node_version``, ``package_manager``, ``subdir``, ``public_env`` (build-time variables baked into the bundle, never secrets). Commands run inside the build container. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With zero annotations the description carries the full burden and does so in depth: async lifecycle, release runs once before traffic with revert-the-image-never-the-data failure semantics, cutover null vs false, dry_run writing nothing, and the exact response fields (summary/hints/next_step vs dry_run warnings). It also discloses the sandbox default (cap_drop ALL, no-new-privileges), the operator-relaxable caveat, and the image_needs_privileges remediation code.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded well with 'Use when' and the async warning, but the body sprawls: the PORT CONTRACT material restates the port priority chain already in the schema, and the sandbox/root-entrypoint section is long enough to bury operational facts. Dense and mostly load-bearing, yet clearly over-budget for a tool description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 14-parameter, no-annotation mutation tool with no output schema, everything an agent needs is present: prerequisites, async follow-up, failure modes, response shape, port/privilege contract, and secret-handling boundaries. Nothing material is left for the caller to guess.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3; the description adds real meaning on top: which nerdit.toml [deploy] keys are honored and that everything else is IGNORED and echoed back in hints, how build_settings interacts with a repo Dockerfile, and that public_env values are shown in clear in a dry run while secret references are refused.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb chain and resource: clones repo_url server-side, then builds and runs it, i.e. deploy-from-Git. The opening 'Use when: the app lives in a Git repo' instantly separates it from the local-directory siblings like deploy / deploy_app / deploy_template.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit entry condition ('Use when: the app lives in a Git repo') and an explicit follow-up routing ('Asynchronous — follow with wait_for_service'), plus a clear dry_run branch for plan-only use. It never names the alternative sibling (deploy) as an exclusion, so the agent must infer when-not, keeping it a notch below 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
deploy_templateA
Use when: you want a starter app. Asynchronous — follow with wait_for_service.
Resolves ``template_id`` (see ``list_app_templates``), clones its
catalog repo server-side, and deploys it under ``name``. ``env`` and the
deploy overrides layer over the template's defaults.
The response carries ``summary``, ``hints``
(never empty) and ``next_step`` — the structured follow-up call — since
a 201 here means the build was accepted, not that the app is up.
An existing Dockerfile retains precedence over ``build_settings``.
Omission preserves overrides; a null field resets to repository/default.
``dry_run=True`` previews without writes,
building or storing secrets. ``public_env`` passes public build-time
variables (shown in clear in a dry run; secret references are refused);
secret mounts are unsupported.
If the template declares ``[ai.*]`` bindings, each is injected at launch
as ``NERDIT_AI_<NAME>_URL/_KEY/_MODEL``, and the ``default`` binding also
sets ``OPENAI_BASE_URL/OPENAI_API_KEY/OPENAI_MODEL`` — point the app's
OpenAI SDK at these; no code change needed. WARNING: the ``secrets`` values you pass
here transit this agent's transcript in plaintext; for high-value keys
prefer ``nerdit secrets set`` from the CLI and deploy without ``secrets``.
| Name | Required | Description | Default |
|---|---|---|---|
| env | No | Runtime env for the container: values are literal strings, never resolved (a ``${secrets.*}`` reference is passed through as text); a null value deletes that key on redeploy. Secrets go through ``set_secret``, which overrides an ``env`` key of the same name at launch. | |
| gpus | No | GPUs to reserve for the container (0 = none). Omit to use the template's default, else the repo's ``[deploy].gpus``. | |
| name | Yes | App name (lowercase DNS label). A new name creates the app; an existing one redeploys it in place. | |
| port | No | Port the container listens on: the only port published and health-checked. Omit to use the template's default, else the repo's ``[deploy].port``, else 8000. | |
| start | No | Start command run inside the built image (shell syntax). Omit to use the template's default, else the repo's ``[deploy].start`` or the buildpack default. | |
| health | No | HTTP health path probed on ``port`` (e.g. ``/health``); the app is ``healthy`` once it answers 2xx. Omit to use the template's default, else the repo's ``[deploy].health``. | |
| vendor | No | GPU vendor to reserve when ``gpus`` > 0 (``nvidia`` or ``amd``); omit to let the daemon choose on a fresh deploy — a redeploy keeps the vendor already recorded. | |
| dry_run | No | true = validate and return the plan (what would change) with zero writes; nothing is built, deployed or audited as a change. | |
| secrets | No | Write-only secrets for the template's required secret inputs; stored server-side right AFTER the app row is written (the row is the authorization point) and before the first launch, so a failed secret write leaves the app created. Only key names are ever read back. Omit when the template declares none. | |
| template_id | Yes | Template id from ``list_app_templates`` (its ``id`` field). | |
| build_settings | No | Build overrides, same keys as ``[deploy.build_settings]`` in ``nerdit.toml``: ``preset`` (node/nextjs/python/dockerfile), ``install``, ``build`` (``false`` skips compilation), ``start``, ``node_version``, ``package_manager``, ``subdir``, ``public_env`` (build-time variables baked into the bundle, never secrets). Commands run inside the build container. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: async semantics ('a 201 here means the build was accepted, not that the app is up'), the follow-up call, override precedence (existing Dockerfile wins over build_settings), null-resets-vs-omission semantics, unsupported secret mounts, and an explicit plaintext-transcript warning about passing secrets.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the trigger, then the async contract, then behavior, then the safety warning. Dense but nearly every sentence carries operational information; the AI-binding paragraph is the longest block and borders on verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter mutation with no annotations and no output schema, the description covers the response shape (summary, hints never empty, next_step), the async contract, and the destructive/secret-handling risks. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real meaning beyond the schema: env/overrides layer over template defaults, public_env is public build-time variables with secret references refused, and AI bindings get injected as NERDIT_AI_<NAME>_*. The gpus/vendor/port interactions are left to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the specific action chain: resolves template_id, clones the catalog repo server-side, deploys under name. An agent can tell it is the template-based deploy path from list_app_templates. Sibling differentiation against deploy_app/deploy_git is only implied, not stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use when: you want a starter app' plus the explicit instruction to follow with wait_for_service gives clear entry and exit conditions. dry_run=True is offered as the preview path. It never says when NOT to use this versus deploy_app or deploy_git.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagnose_projectA
Diagnose one service of an explicit project under the existing owner/admin policy.
Prefer an immutable project ID. The daemon resolves project membership and
reuses diagnose_service's failure bundle; this grants no additional authority.
| Name | Required | Description | Default |
|---|---|---|---|
| project | Yes | Immutable prj_ ID or name of an existing project. Prefer the ID from list_projects: a retired ID never addresses a same-name replacement. | |
| service | No | Service inside the project; omit for web. | web |
| log_tail | No | Log lines to bundle; clamped to [1, 200]. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does reasonably well: it discloses the owner/admin authorization requirement, that the daemon resolves membership, that output reuses diagnose_service's failure bundle, and that it 'grants no additional authority' (a useful privilege-escalation clarification). It omits return shape and read-only nature, but the key behavioral facts are present.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Very short and front-loaded: purpose first, then the ID preference, then behavior. The 'under the existing owner/admin policy' clause is slightly awkwardly placed but no sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter, fully-schema-documented tool with no output schema and no annotations, the description covers authorization, escalation posture, and result provenance. What is missing — contents of the failure bundle — is minor given the absence of an output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so all three parameters are documented in the schema, including the immutability/retired-ID rationale and the log_tail clamp. The description only echoes the 'prefer the ID' guidance, adding negligible meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with scope: 'Diagnose one service of an explicit project.' Naming diagnose_service as the bundle source implies the relationship to the sibling, though it never explicitly contrasts when to pick this over diagnose_service.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only usage steering is 'Prefer an immutable project ID,' plus the mention that it reuses diagnose_service's bundle. There is no explicit statement of when to call this instead of diagnose_service, or of any preconditions beyond the owner/admin policy note.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagnose_serviceA
Use when: a service is failing and you need the reason, not the logs.
Bundles the deploy phase, crash forensics (``last_exit_code``,
``oom_killed``), a fresh health probe, AI-binding readiness, a bounded
log tail and a single ``remediation_code`` to branch on — call it after
``wait_for_service`` returns ``failed`` instead of scraping logs.
Owner-or-admin read: the bundle carries env/secret key *names* and app
log lines, never secret values.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Service name or job id of an existing service (app, model or database); both resolve to the same row. | |
| log_tail | No | Log lines bundled into the diagnosis. Default 50; clamped to [1, 200] here and again server-side. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it declares this is an 'Owner-or-admin read', discloses exactly what sensitive data the bundle can expose (env/secret key *names*, app log lines) and what it never exposes (secret values), and notes the log tail is bounded. It stops short of saying whether the fresh health probe makes the call slow or what happens when the service has no deploy history.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with an explicit 'Use when:' clause and only two further sentences, both of which add real routing or safety information. Slightly dense with reST-style double-backtick markup that reads as noise rather than signal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by enumerating the bundle's return contents and flagging remediation_code as the branching field, plus the safety profile. An agent knows what it will get back and how to act on it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the two parameters are already fully documented including the default and the [1, 200] clamp. The description adds only the phrase 'bounded log tail', which is marginal value over the schema; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (diagnose a failing service) and enumerates exactly what the bundle contains: deploy phase, crash forensics, health probe, AI-binding readiness, log tail, remediation_code. This clearly separates it from service_logs and get_service, which an agent could otherwise confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit trigger ('Use when: a service is failing and you need the reason, not the logs'), explicit sequencing ('call it after wait_for_service returns failed'), and an explicit anti-pattern to avoid ('instead of scraping logs'). That is a when/when-not/alternative triad.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
doctorA
Run the daemon's bounded environment health checks (docker/gpu/proxy/db/...).
Returns per-check ``{status, detail}`` plus a worst-of top-level
status. Every check is timeout-bounded server-side; details carry key
*names* only, never paths or secret values — safe for every role.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does substantial work: it discloses that checks are timeout-bounded server-side, that details expose key names only (no paths or secret values), and that it is safe for every role. Missing only notes on latency/cost or whether checks can be selectively run — but there are no params anyway.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, verb-and-scope front-loaded, followed by the return shape and the safety guarantee. Nothing is padded or restated from the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by describing the return shape (per-check {status, detail} plus a worst-of top-level status) and the safety characteristics of those details. An agent has everything needed to call it and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. The description correctly implies no input is needed, and the enumerated check domains clarify what the argument-less call will cover.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Run') and resource ('daemon's bounded environment health checks') with the checked domains enumerated (docker/gpu/proxy/db), which distinguishes it from per-service siblings like diagnose_service and diagnose_project. It stops short of naming those siblings explicitly, so the distinction is inferred from scope rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The scope ('daemon's environment health') implies a preflight/triage use case, but the description never says when to call this versus diagnose_service, diagnose_project, or capabilities/proxy_status. Usage must be inferred from the enumerated check categories.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
dump_databaseA
Capture a logical, application-consistent dump of a managed database.
The daemon runs the engine's own dump tool — ``pg_dump --format=custom``
for Postgres, ``redis-cli --rdb`` for Redis — from a throwaway container
built from the database's OWN image, against the running server. This is
the dump to take before a migration or a destructive change: unlike the
volume backup (``nerdit backup --volume``, no tool), it is consistent by
the engine's rules rather than by the filesystem's.
CUSTODY: the artifact is a server-side tar under the daemon's backups
directory holding **every row** of ``name``; it is never served over
HTTP and nothing but metadata comes back here — basename, size, sha256,
engine, format, duration. Treat the basename as the handle: it is what
``nerdit db restore`` takes.
RETENTION: the daemon keeps the last ``[retention].dump_keep_last``
dumps per database (default 5) and prunes older ones on its hourly
sweep, so a dump is not an archive. Copy one off the box if it must
outlive that window.
TIMEOUT: the default matches the usual MCP client read budget, not
the route's own 900: if your client gives up first, **a longer dump still completes
server-side and appears in ``list_database_dumps``**. So a read timeout
here is not a failure — call ``list_database_dumps`` and take the newest
entry. Do NOT blind-retry: this tool mints its own idempotency key per
call, so a retry is a second real dump (and the first one may still be
running, which answers ``409 dump.in_progress``).
Authorization is **owner-or-admin plus token scope**: a scoped submitter
can dump the databases it created, which is what makes this usable over
the (submitter-capped) cloud link. Refusals you should branch on: ``409
dump.database_not_ready`` (not running, or still doing initdb — poll
``list_databases`` for ``db_ready``), ``409 dump.in_progress`` (this
database already has one running; distinct from the daemon-wide
``backup.in_progress``), ``409 dump.too_many_in_flight``, ``409
dump.insufficient_disk`` (the error object carries top-level
``required_bytes`` / ``free_bytes``), ``422 dump.not_a_database``, and
``500 dump.failed``
whose ``hint`` is the tool's own last output line. There is deliberately
**no restore tool** — restoring replaces live data and stays on the CLI
(``nerdit db restore``) and REST.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name of an existing managed database (``kind=database``); an app or model row is refused. | |
| timeout_s | No | Seconds the dump tool may run server-side; omit for 300. Floored at 1 and otherwise passed straight through, so a value above the daemon's ``[services].dump_timeout_max_s`` gets the authoritative 422 ``dump.timeout_too_large`` instead of being silently clamped. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: artifact custody (server-side tar, metadata only returned, never served over HTTP), retention (last N per DB pruned hourly, not an archive), per-call idempotency key semantics making retries unsafe, authorization model (owner-or-admin plus token scope), and a branchable error-code catalogue including the distinction between dump.in_progress and backup.in_progress.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence and the remainder is organized under explicit CUSTODY / RETENTION / TIMEOUT / authorization headings, so it scans well. It is long and dense, and the enumerated 409 codes push toward the verbose end, but nearly every clause carries decision-relevant information for a tool with no annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive-ish long-running operation with no annotations and no output schema, the description supplies everything an agent needs: the returned metadata fields (basename, size, sha256, engine, format, duration), how to use the basename with restore, retention lifetime, and the failure modes to branch on.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds real meaning to timeout_s by explaining that the default matches the client read budget rather than the route's own 900s, and that a client-side timeout does not mean the server-side dump failed. Input `name` is only lightly reinforced beyond the schema, hence not a full 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Capture a logical, application-consistent dump of a managed database") and immediately names the underlying engine tooling (pg_dump custom format, redis-cli --rdb). It also distinguishes itself from the sibling volume-backup path, so an agent can tell which backup mechanism it is choosing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit timing guidance: "the dump to take before a migration or a destructive change", contrasted against the filesystem-based volume backup. It also gives operative alternatives for the edge cases — on timeout call list_database_dumps rather than retrying, and restore is deliberately out of scope on the CLI/REST. When-to-use, when-not-to-retry, and the alternative path are all spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_ai_usageA
AI gateway usage per (UTC day, app, alias): requests, prompt and completion tokens, upstream errors. No cost estimate, no prompt trace.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | UTC days back, today included (1-90). | |
| service | No | Only this app's usage; omit for every app. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It usefully discloses the aggregation dimensions, included metrics, and two important exclusions, but it does not mention permissions, pagination, ordering, rate limits, or the exact return format.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two compact sentences with no waste. The core resource and metrics are front-loaded, and the limitations are stated briefly afterward.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter, read-only usage reporting tool with a fully described input schema, the definition is largely complete. It explains the included metrics and exclusions, though without an output schema it could say slightly more about the returned grouping structure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% description coverage, with both parameters documented directly. The description reinforces that usage is reported per UTC day and app, but it does not add parameter details beyond the schema's existing descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the resource and metrics returned: AI gateway usage grouped by UTC day, app, and alias, including requests, tokens, and upstream errors. It is specific enough for an agent to understand what the tool provides, though it does not explicitly distinguish itself from sibling stats tools such as cluster_stats or service_stats.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the description: this tool is for AI gateway usage reporting. The note 'No cost estimate, no prompt trace' usefully excludes expected content, but there is no explicit guidance about when to choose this tool over sibling statistics or audit tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_app_configA
Read a deployed app's daemon-persisted config (deploy fields + ai bindings).
Secret values are never returned — only ``${secrets.X}`` refs and env
key names. Each ``[ai.<name>]`` binding shown here is injected into the
app at launch as ``NERDIT_AI_<NAME>_URL/_KEY/_MODEL``, and the
``default`` binding also sets ``OPENAI_BASE_URL/OPENAI_API_KEY/
OPENAI_MODEL`` (drop-in OpenAI SDK).
``deploy.release`` is the command run once inside the new image before
traffic moves (a failure aborts the deploy and reverts the image,
never the data — write idempotent migrations); ``deploy.cutover`` null =
zero-downtime swap when eligible, false = same-port swap. ``env_keys``
are literal runtime env names; secret refs are accepted only by
``ai.*.api_key``, ``db.*.password``, ``edge_auth.password`` and a git
``token_ref`` — a ``${secrets.shared.KEY}`` there resolves at launch for
any owner, so a human can place the secret and the agent only names it.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name of a deployed app (``kind=service``). A served model or a managed database is a 404 ``config.not_an_app``; an unknown name a 404 ``not_found``. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With zero annotations the description carries the full burden and does so richly: secret values are never returned (only ${secrets.X} refs and env key names), ai bindings are injected at launch as NERDIT_AI_<NAME>_* vars, deploy.release failures abort and revert the image, and cutover null vs false is spelled out. It also names which fields accept secret refs — high-value behavioral context an agent could not get elsewhere.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence and subsequent paragraphs map to real returned fields rather than restating the name. It is dense but mostly earns its space; the parenthetical '(write idempotent migrations)' is advisory padding that could be trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must convey the return shape — it covers deploy fields, ai bindings, env_keys, and secret refs, which is the bulk of what matters. It does not enumerate other config sections (db, domains, edge_auth) even though edge_auth.password is referenced, leaving the full response shape partially described.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single 'name' parameter already has a detailed description with 404 semantics, so the schema does the heavy lifting. The tool description adds no parameter-level information (no naming conventions or format), which is acceptable at this coverage level but earns only the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'Read a deployed app's daemon-persisted config (deploy fields + ai bindings)'. An agent knows exactly what it gets. It does not, however, distinguish itself from the nearby sibling 'get_config' or 'get_service', leaving the sibling boundary to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'deployed app's' implicitly scopes usage to apps (kind=service) rather than models or databases, but the explicit exclusion only appears in the schema's name description, not the tool description. No alternative tool (get_config, get_service) is named, so when-not branches must be inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_auditA
Read the audit log (admin-scoped), bounded to limit entries per page.
Returns an ``AuditLogPage`` dict. Non-admin tokens get a structured
``forbidden`` (403) error.
All filters compose with AND, and all are applied in SQL — narrowing is
cheap, so prefer a filter over paging.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max entries in one page, clamped to [1, 200] before the call (the daemon rejects anything outside that range); omit for 50. | |
| since | No | Keep only entries at or after this inclusive ISO-8601 UTC timestamp (``2026-08-07T10:00:00Z``); omit for no lower bound. | |
| until | No | Keep only entries at or before this inclusive ISO-8601 UTC timestamp (``2026-08-07T10:00:00Z``); omit for no upper bound. | |
| action | No | Keep only entries whose action equals this exactly (e.g. ``deploy.create``); omit for every action, or use ``action_prefix`` for a family. | |
| cursor | No | Opaque paging cursor from the previous page's response; omit for page 1. | |
| result | No | Keep only entries with this outcome — ``ok``, ``error``, ``denied`` or ``replay``; omit for all four. | |
| target | No | Keep only entries acting on this exact target id (e.g. a service name); omit for every target. | |
| target_type | No | Keep only entries whose target is of this type (e.g. ``service``, ``model``); omit for every type. | |
| principal_id | No | Keep only entries written by this token id — everything that caller did; omit for every principal. | |
| action_prefix | No | Keep only actions starting with this **literal** prefix, never a pattern (``deploy.`` matches deploy.create, deploy.git_create, deploy.plan). Grammar ``[a-z0-9._]``, 1-40 chars, else ``bad_request``; omit for every family. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations at all, the description carries the full burden and does well: it discloses the admin requirement, that non-admin tokens get a structured 403 "forbidden" error, that it returns an AuditLogPage dict, and that filtering happens in SQL. It does not state result ordering or default sort, which matters for a log-reading tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short paragraphs, front-loaded with the verb, resource and scope; the operational advice about filtering over paging comes last where it belongs. No sentence repeats the schema, and the RST-style backticks are the only minor friction.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a ten-parameter read tool with no output schema, the description supplies the return type, the auth failure mode, and the filter-composition rule. The remaining gap is ordering/pagination behavior across pages, which the cursor parameter hints at but the description never explains.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so per-param meaning is already covered and a 3 would be the floor. The description still adds value beyond the schema by explaining that all filters compose with AND and are applied server-side, which tells the agent how to combine the ten optional filters rather than just what each one does.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Read the audit log") plus the key scoping constraint ("admin-scoped") and paging bound. It's clear what it does, but it never distinguishes itself from the closest sibling, get_events, which an agent could easily confuse with it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives real usage direction: admin token required, filters compose with AND, and "narrowing is cheap, so prefer a filter over paging" is actionable advice about how to call it. It stops short of naming alternatives (e.g. get_events) or saying when not to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_configA
Read daemon config: one section view, or all sections when omitted.
Secret-bearing values are redacted server-side.
| Name | Required | Description | Default |
|---|---|---|---|
| section | No | Config section to read (e.g. ``proxy``, ``services``, ``retention``); omit to return every section. An unknown name is a 404 ``config.unknown_section`` listing the known ones. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It usefully discloses that secret-bearing values are redacted server-side, which is meaningful. It does not explicitly describe read-only safety, permission requirements, or the exact response shape, leaving clear gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short sentences and front-loads the core action immediately. Every phrase adds useful scope or behavioral information, with no wasted text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-parameter config read, the description covers the main action, section-vs-all behavior, and redaction. Because there is no output schema, it could say more about the return structure, but the core behavior is adequately conveyed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents the optional 'section' parameter thoroughly, including examples and the 404 behavior for unknown sections. The description reinforces the omit-to-return-all behavior but adds no new parameter semantics beyond the schema, matching the baseline for high coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: 'Read daemon config.' It clarifies that the tool returns either one section or all sections when omitted, which is useful scope detail. It does not explicitly distinguish itself from sibling tools such as set_config or get_app_config, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage by saying it reads daemon config and returns one section or all sections when omitted. However, it gives no explicit guidance on when to use this tool instead of related siblings like get_app_config or set_config, nor does it state exclusions or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_eventsA
Use when: you need the daemon's own account of what it just did.
The durable feed of autonomous transitions (``service.failed``,
``service.degraded``, ``service.deploy_succeeded``, ``model.ready``,
...), readable by any authenticated token. Two directions, and picking
the wrong one walks the wrong way through history.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max rows in one page, clamped to [1, 200] here and server-side; omit for 50. | |
| types | No | Comma-separated event types to keep (e.g. ``service.failed,model.ready``); only the first 10 entries are honoured. Omit for every type. | |
| cursor | No | Browse **backwards** from here (id DESC, newest first): pass the previous page's ``next_cursor`` to see what just happened. Omit for the newest page; passing it together with ``since_id`` is a 400. | |
| service | No | Keep only events for this exact service name; omit for every service. | |
| since_id | No | Replay **forwards** from this event id (id ASC, rows with id > it) — the resume mode after processing up to that id. Omit to browse backwards instead; passing it together with ``cursor`` is a 400. To keep replaying forward, pass the page's ``next_cursor`` back as ``since_id``, never as ``cursor``. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the load and does disclose real behavioral facts: the feed is durable, it is autonomous-transition oriented, and it is readable by any authenticated token (auth requirement). It omits return shape and retention/pagination behavior, and the "two directions" warning is stated so elliptically that it doesn't say which parameter goes which way.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with a "Use when:" clause and kept to three short sentences with no filler. The phrase "picking the wrong one walks the wrong way through history" is atmospheric rather than precise, costing a bit of clarity for its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-optional-parameter read tool with no output schema and no annotations, the description covers purpose, auth scope, durability, and the directionality trap. What's missing is minor: the vocabulary of event types is only sampled, and nothing is said about what a returned page contains beyond the schema's next_cursor reference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already explains limit clamping, type filtering, and the cursor/since_id mutual exclusion with 400 errors. The description reinforces the bidirectional model but adds no syntax, format, or constraint detail beyond what the schema states, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Describes the tool concretely as the durable feed of autonomous daemon transitions, with example event types (service.failed, model.ready) that make the resource tangible. It implicitly separates itself from service_logs and get_audit by emphasizing daemon-level events readable by any token, but never names those siblings, so the distinction must be inferred.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Use when: you need the daemon's own account of what it just did" gives a clear triggering condition, and the note about two directions warns that argument choice changes traversal. No explicit when-not or named alternative among the many log/audit siblings, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_projectA
The one-call picture of a project: read this before you deploy or diagnose.
Returns the project's services with their state, last deploy and
endpoint; the models and databases they reference with a readiness
flag (``null`` when readiness cannot be judged without a secret); every
public address under ``addresses``; and ``home``, the node it lives on
(always this node today). A name outside your scope is 403; an unknown
name is 404. Secret values never appear here.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Immutable prj_ ID or name of an existing project. Prefer the ID from list_projects: a retired ID never addresses a same-name replacement. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses 403 for out-of-scope names, 404 for unknown names, that secret values never appear, that readiness may be null when a secret is needed, and that home is always this node today. Missing only a clear statement that this is a read-only, non-mutating call and any freshness/caching caveat.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Opens with the one-line value proposition, then front-loads the return inventory and closes with error and secrecy caveats. No sentence is filler; the markup-heavy phrasing is dense but each clause carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must describe the return shape and it does so comprehensively, down to the nested readiness flag and the addresses/home fields. Combined with error semantics and the secret-exclusion guarantee, an agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema itself already explains the immutable prj_ ID vs name tradeoff and the retired-ID trap, leaving little for the description to add. The 403/404 mentions give peripheral meaning to name resolution but no additional format or syntax detail, so baseline 3 is right.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource and enumerates exactly what comes back: services with state/last deploy/endpoint, referenced models and databases with readiness, public addresses, and home node. This is clearly distinguishable from narrower siblings like get_service, list_services, or diagnose_project.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Read this before you deploy or diagnose" gives clear situational context that ties it to deploy/diagnose_project siblings. It stops short of naming those alternatives or stating when-not to use it (e.g. when you only need one service's logs), so it is strong but not fully explicit routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_serviceC
Get one service.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Service name or job id of an existing service (app, model or database); both resolve to the same row. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, yet it discloses nothing: not whether the call is read-only (only implied by 'get'), not what happens when the name is unknown, and not whether it errors or returns empty. Only the thinnest behavioral implication is present.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The single sentence has zero filler and is front-loaded, but it is underspecified rather than genuinely concise for a tool with no annotations and no output schema. Brevity here costs information rather than saving it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There are no annotations and no output schema, so the description should say what a 'service' record contains and how missing names are handled. Neither is covered, leaving an agent unable to predict the response shape or failure mode.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the parameter description already explains that name accepts a service name or job id and that both resolve to the same row. The description adds nothing beyond that, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Get one service" states a specific verb and resource, so the basic meaning is inferable. But it does nothing to distinguish itself from siblings like list_services, service_stats, or diagnose_service, and 'service' is ambiguous until the schema clarifies app/model/database.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this versus list_services or service_stats, and no mention of prerequisites or the name-vs-job-id resolution behavior that the schema documents. The agent must infer usage entirely from the name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_ai_provider_modelsA
List the model ids an OpenAI-compatible provider offers (submitter or admin).
The daemon calls ``GET {base_url}/models`` with the referenced shared
key, so you can pick a model for ``set_ai_route`` while the key stays on
the machine. Returns ``{base_url_host, models}`` (sorted ids only).
Read-only despite the POST underneath (no idempotency key).
Refusals: 422 ``ai_gateway.base_url_invalid`` / ``ai_gateway.secret_ref_invalid``,
503 ``secret_missing``, 502 ``ai_gateway.provider_unreachable`` /
``ai_gateway.provider_error`` (the HTTP status, never the provider's text).
| Name | Required | Description | Default |
|---|---|---|---|
| base_url | Yes | OpenAI-compatible base URL, usually ending in ``/v1``; https to a public host, or http to loopback or the models bridge. | |
| api_key_ref | Yes | A ``${secrets.shared.KEY}`` reference to the provider key, set beforehand with ``set_secret`` on scope ``shared``. Never the key itself. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it discloses the upstream call (GET {base_url}/models using the referenced shared key), that the key never leaves the machine, the return shape {base_url_host, models}, that it is read-only despite an underlying POST, and the exact refusal codes (422/503/502) without leaking provider text.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first line, followed by mechanism, return shape, safety note, and error codes in a tight order. Dense but every chunk carries information; the error-code block is the only part that could be trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description supplies the exact return shape and field semantics, plus the failure modes an agent must handle. Nothing material needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both base_url and api_key_ref are already documented as an /v1 URL and a ${secrets.shared.KEY} reference. The description reinforces the secret-stays-local guarantee but adds little syntax or format detail beyond the schema, matching the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource with scope: 'List the model ids an OpenAI-compatible provider offers (submitter or admin).' That is clearly distinct from the local-model sibling list_models, and it names the downstream consumer (set_ai_route), though it never explicitly contrasts itself with list_models.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear usage context — call it to pick a model id before configuring set_ai_route — plus the caller role requirement (submitter or admin). It stops short of naming an explicit alternative or when-not condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_ai_routesA
List the machine AI gateway's aliases and whether the gateway is enabled.
Each alias shows its provider, provider model, base_url and the
``${secrets.shared.KEY}`` reference of its key: never a key value.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full load and does well: it discloses the return fields (provider, provider model, base_url, key reference) and an important security behavior — keys appear only as ${secrets.shared.KEY} references, never values. It does not mention whether the gateway must be configured or any permission requirements, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the core action and then the return-shape detail. The stray indentation and RST-style double backticks are cosmetic clutter but do not obscure meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, read-only listing tool with no output schema, the description supplies what the agent needs: what is listed and what each entry contains. It is only slightly short on prerequisites (does the gateway need to be enabled/configured for this to return data?).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline 4 applies. No misleading parameter hints are present.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: lists the AI gateway's aliases plus the gateway enabled flag. This is clearly distinct from set_ai_route/remove_ai_route (mutations) and from list_ai_provider_models (provider catalog), though it never names those siblings to reinforce the distinction.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer this is the read-only inspection call for AI routes. There is no explicit 'use this when...' or reference to the alternative siblings (list_ai_provider_models, get_ai_usage, set_ai_route) that an agent would weigh before calling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_app_filesA
List an app's workspace: paths, sizes, sha256 and totals.
What this lists is exactly what ``deploy_app`` would build — the exclude
rules are enforced at write time, not at deploy time. Bounded at 500
files by construction, so there is no paging.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name of an existing workspace (also the app name it deploys under). No workspace by that name is ``404 workspace.not_found``. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and discloses output fields, the 500-file bound, no paging, and write-time exclusion semantics. It does not state auth/permission requirements or explicitly confirm read-only/no side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with what the tool returns and followed by the key constraints. No sentence repeats the name/title or wastes space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter list tool with no output schema and no annotations, the description explains returned contents, the file bound, no paging, and the deploy relationship. It still omits an explicit read-only/auth note, though the schema covers the parameter and 404 case.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the schema already documents the name parameter, existing workspace, deploy-name relationship, and 404 behavior. The description adds only "app's workspace" context, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("List an app's workspace") and enumerates returned fields (paths, sizes, sha256, totals). It references deploy_app to explain the relationship, but does not explicitly distinguish itself from read_app_file or write_app_files.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context that the listing mirrors deploy_app's build and that excludes are enforced at write time, so an agent can infer it is useful for inventory/preview. It does not explicitly name when to use it instead of read_app_file or list_app_templates, nor does it state exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_app_templatesA
List the app template store — deployable starter apps (id/name/coordinates).
Deploy one with ``deploy_template``. These are full app templates
(web/API/AI starters), not per-service presets.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavioral burden. It discloses that this is a listing operation returning id/name/coordinates and what kind of templates are included, but it does not explicitly state read-only safety, pagination, ordering, or any filtering limits. For a simple zero-parameter list this is adequate but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loaded: it first states what is listed, then gives the deployment alternative, then clarifies the template scope. Every sentence adds useful selection or invocation context without waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a zero-parameter, no-annotation, no-output-schema list tool, the description supplies enough context to select and call it correctly. It identifies the resource, the returned fields, the intended follow-up tool, and the scope distinction; only minor operational details like ordering or pagination are absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is no parameter semantics to clarify. The description does not need to compensate for schema gaps, and the empty schema is unambiguous.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource ('List the app template store') and clarifies exactly what the listed items are ('deployable starter apps (id/name/coordinates)'). It also explicitly distinguishes these from per-service presets and points to the sibling action tool, so an agent can identify this as the read-only catalog lister without opening another schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly directs the agent to use `deploy_template` when it wants to deploy one of the templates, which is the key alternative action. It also gives scope guidance by clarifying that these are full app templates rather than per-service presets, though it does not enumerate other list tools for comparison.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_database_dumpsA
List the dump tars this daemon holds for one managed database.
Newest first, ``{dump, size_bytes, created_at}`` per row, where
``created_at`` is the tar's mtime (the listing never opens an archive).
Metadata only, like ``dump_database``: the tars themselves stay under
the daemon's backups directory and are never served over HTTP, and each
one holds every row of ``name``.
Two things this read is for. It is the recovery path when a
``dump_database`` call outran your client's read budget — **the dump
still completes server-side and shows up here**, so list before you
retry. And it is how you check retention: the daemon keeps the last
``[retention].dump_keep_last`` per database (default 5) and prunes the
rest hourly, so on a default daemon what is listed here is all there is.
Retention can be turned off (``dump_keep_last = 0``), so the listing is
capped at the newest 500 instead: ``truncated`` is true when older tars
exist on the box that this page does not name.
Owner-or-admin plus token scope — the same gate as the dump that
produced them, because knowing which dumps a database has is knowing
something about the data.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name of an existing managed database (``kind=database``); an app or model row is refused. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and covers it: ordering (newest first), that archives are never opened (mtime only), that tars stay under the daemon's backups directory and are never served over HTTP, retention defaults (dump_keep_last=5, hourly pruning), the 500-row cap, the truncated flag, and the owner-or-admin plus token scope gate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and return shape, then organized by use case and retention rules; the prose is dense with information rather than padded. Slightly long with markdown styling and some redundancy, but nearly every sentence adds a behavioral fact.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description supplying the row shape ({dump, size_bytes, created_at}), the meaning of created_at, and the truncated flag is essential and provided. Authorization requirements and retention behavior round it out; nothing an agent needs to call or interpret the result is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the single parameter and its kind=database constraint are already documented. The description adds only marginal meaning ('each one holds every row of ``name``'), which is consistent with the schema but does not extend it substantially, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the dump tars this daemon holds for one managed database'), scoping it to a single database. It is clearly distinguishable from siblings like list_databases and dump_database by naming dump_database directly and contrasting the listing with the dump operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names two situations: the recovery path after a dump_database call outran the client read budget ('list before you retry'), and retention checking. It also states what the listing contains under pruning and truncation, so when-not conditions are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_databasesA
List managed databases (kind=database workloads), bounded to limit per page.
Returns a cursor-paginated page. A newly created database shows
``building`` until its off-tick image pull and readiness probe complete
(``db_ready`` true).
The ``endpoint`` is password-free by construction; lifecycle actions go
through the service tools.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Databases per page; omit for 50. Clamped to 200, the daemon's own page cap. | |
| cursor | No | Opaque paging cursor from the previous page's response; omit for page 1. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose meaningful traits: cursor pagination, page bounding, the transient 'building' state with its 'db_ready' flag, and that the endpoint is password-free. It does not state read-only semantics outright or note whether the listing includes all projects, but what is present is substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Short and front-loaded: purpose and pagination scope come first, then return-shape details. The quoted/backticked formatting and multi-line splitting are slightly noisy but every sentence contributes information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description correctly steps in to explain the notable return values ('building', 'db_ready', password-free 'endpoint') and the paging model. It stops short of enumerating other fields, but the essentials for correct invocation and interpretation are present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema already documents the 50 default and the 200 clamp in more detail than the description's 'bounded to limit per page'. The description adds the pagination framing but no parameter meaning beyond the schema, so the baseline applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List managed databases') and narrows scope with 'kind=database workloads'. It also distinguishes itself from the mutation siblings by noting that 'lifecycle actions go through the service tools', so an agent can tell it apart from create_database and the service-management tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The closing sentence routes lifecycle operations elsewhere, which establishes this as the read path and implicitly excludes it from create/start/stop flows. It never names the specific sibling tool or states an explicit precondition, so routing is clear but not fully prescriptive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_gpusA
List GPUs known to the daemon, with live utilization metrics.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. 'List' plus 'live utilization metrics' signals a read-only, real-time snapshot scoped to the local daemon, which is genuinely useful context, but it doesn't say whether results are cached, how metrics are sampled, or what an empty result means.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no wasted words; the resource comes first and the payload detail follows.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-argument read tool with no output schema, the description gives enough to call it confidently and hints at the return content. The only gap is that the specific utilization fields returned are not enumerated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to clarify and the baseline of 4 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('List') and resource ('GPUs known to the daemon') plus the scope of the payload ('live utilization metrics'). It is distinguishable from siblings like cluster_stats or system_disk, though it never names those alternatives explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied: an agent would call this when it needs a GPU inventory or current GPU load. There is no explicit when-to-use, no exclusion relative to cluster_stats/system_disk, and no note on what to do when no GPUs exist.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_hooksA
List a deployed app's inbound webhooks (owner or admin only).
Returns ``{service_name, hooks: [{name, sender, path, header, prefix,
secret_ref, secret_key, url, created_at}]}``. ``url`` is null until the
machine is linked, and answers only once the app is shared.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name (or row id) of an existing deployed app — only kind 'service' can be exposed: ``share_service``/``add_domain`` refuse a model or database with 422 ``*.kind_unsupported``, while the remove tools just find nothing to undo. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses the owner/admin access restriction, the shared-app prerequisite, the exact return shape, and the condition under which url is null. It stops short of describing pagination, ordering, or error behavior, so a 3 would be too harsh but 4 captures the remaining gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and access constraint, then provides return shape and important null semantics. Every sentence adds useful information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although there is no output schema, the description supplies the return structure in detail, including the fields of each hook and the null-url condition. Combined with the fully documented single parameter, this is complete enough for an agent to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the single parameter is fully documented in the schema with details about app kind restrictions and error behavior. The description only reinforces that the name refers to a deployed app, so the baseline of 3 is appropriate when the schema already handles parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description begins with a specific verb and resource: "List a deployed app's inbound webhooks." It distinguishes itself from add_hook/remove_hook through the verb "List" and scopes the resource to inbound webhooks on a deployed app, so an agent can identify the correct operation without opening sibling schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage context by stating "owner or admin only" and that answers come only once the app is shared. These are meaningful preconditions. It does not explicitly name add_hook or remove_hook as alternatives for creation or deletion, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_modelsA
List served AI models (kind=model workloads), bounded to limit per page.
Returns a cursor-paginated page; pass ``cursor`` from the previous page
to continue. A newly served model shows ``building`` until its off-tick
pull completes; lifecycle actions go through the service tools.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Models per page; a value outside 1–200 is clamped into it (0 becomes 1, 10000 becomes 200). Omit for 50. | |
| cursor | No | Opaque paging cursor from the previous page's response; omit for page 1. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the full burden and does reasonably well: it discloses cursor pagination, the fact that newly served models appear as 'building' until the off-tick pull completes, and that lifecycle operations live elsewhere. It still says nothing about permissions, rate limits, or result ordering.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the resource and scope, then pagination, then the lifecycle caveat. Slight redundancy with the schema on limit/cursor, but no filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description is the only source of truth, and it never says what a model record contains (name, id, status fields) or what ordering to expect. Pagination and the 'building' state are covered, but the return shape is left undefined.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already fully documented, including clamping behavior and the default of 50. The description only restates 'bounded to limit per page' and 'pass cursor from the previous page', adding no format or edge-case detail beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Uses a specific verb+resource ('List served AI models') and narrows scope with '(kind=model workloads)', which separates it from cluster/host listings. It never names the closest-looking sibling, list_ai_provider_models or list_services, so the boundary is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'lifecycle actions go through the service tools' steers the agent away from using this tool for mutation and points at the service family. It gives no explicit condition for choosing between this and list_ai_provider_models or list_services, so a small inference remains.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_projectsA
List the projects this token can see, bounded to limit per page.
Each entry carries the project's services (state, endpoint) and every
advertised address. A scoped token sees only the projects its scope
names. Cursor-paginated; use ``get_project`` for the full picture of one.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Projects per page; omit for 50. Clamped to 200, the daemon's own page cap. | |
| cursor | No | Opaque paging cursor from the previous page's response; omit for page 1. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the burden and does a good job: it discloses token-scope filtering, per-page bounding, cursor pagination, and the shape of each entry (services with state/endpoint, plus advertised addresses). It doesn't cover ordering or behavior at the page cap, but for a read-only list the disclosure is solid.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and scope in the first clause, then return shape and the alternative in two short follow-ons. No filler; the slight repetition of the per-page bound is negligible.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description responsibly explains what each entry carries and how paging works, and the token-scope caveat prevents misinterpretation of sparse results. Only minor gaps remain, such as result ordering and what an exhausted cursor looks like.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters are already well documented there (default 50, clamped to 200; opaque cursor). The description only restates 'bounded to `limit` per page' and 'cursor-paginated,' adding no syntax or semantics beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the projects this token can see') and adds a real scope constraint — a scoped token sees only the projects its scope names. It also distinguishes itself from the sibling detail tool by naming `get_project` for 'the full picture of one.'
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to `get_project` when it needs a single project's full detail, and states the listing is cursor-paginated. It gives clear context but no exclusions (e.g., when to prefer `list_services` or how to filter), so it stops just short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_routesA
List the DB-authoritative route inventory, annotated with live Caddy state.
Models appear with ``route: null`` (loopback-only by design); each row
carries its live-table annotation.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max rows in one page, clamped to [1, 200] here and server-side; omit for 50. | |
| cursor | No | Opaque paging cursor from the previous page's response; omit for page 1. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden and does provide useful non-obvious context: the inventory is DB-authoritative and annotated with live Caddy state, and models intentionally show route: null because they are loopback-only. It does not discuss permissions, freshness or pagination behavior, but for a list operation this is a strong disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in the first sentence, and the second sentence adds only non-obvious detail about route: null and live-table annotations. There is no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple, with two optional paging parameters fully documented in the schema, and the description explains the key output nuance around route: null. However, with no output schema, the description should do more to explain the returned row shape beyond saying each row carries a live-table annotation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so limit and cursor are already fully documented in the schema. The description adds no parameter-level information beyond what the schema provides, which matches the baseline of 3 when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: it lists the DB-authoritative route inventory annotated with live Caddy state. That is materially more informative than the tool name alone, and the note about models appearing with route: null adds concrete scope. It does not explicitly distinguish this tool from the sibling list_ai_routes, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Use is implied by the phrase 'DB-authoritative route inventory' and the live Caddy annotation, so an agent can infer this is the tool for inspecting route state. However, there is no explicit when-to-use guidance, no exclusion, and no naming of alternatives such as list_ai_routes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_secret_namesA
List a service's secret key names (values are never returned).
| Name | Required | Description | Default |
|---|---|---|---|
| service | Yes | Service (app, model or database) whose secret key names to read, or ``shared`` for the global scope, whose names any authenticated principal may read. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden; it usefully discloses that values are never returned, which sets expectations for the response. It omits read-only confirmation, authentication requirements, and the fact that the 'shared' scope is readable by any authenticated principal (only stated in the schema).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no waste; the security-relevant caveat is folded into the same sentence rather than padding it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read tool with a fully documented schema, the description supplies the essential behavioral note about returned values. Only auth/permission context is left implicit, which is a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single 'service' parameter is documented in detail, including the special 'shared' value. The description adds no parameter-level meaning beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List a service's secret key names') and adds the crucial scope qualifier that only names, not values, come back. It implicitly contrasts with set_secret/remove_secret, though it never names them or the 'shared' scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The parenthetical implies this is the read-only inspection path for secrets, which is enough to infer when to call it. There is no explicit guidance on alternatives (e.g. use this before remove_secret, or that it covers the same 'shared' scope as the other secret tools).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_servicesB
List services (apps, models and databases), newest first.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Services per page. Default 50; clamped to [1, 200] here and bounded again server-side. Page 2 comes from ``next_cursor``, not a larger limit. | |
| cursor | No | Opaque paging cursor from the previous page's response; omit for page 1. | |
| status | No | Keep only services in this exact lifecycle state (``building``/``running``/``degraded``/``restarting``/``stopped``/``failed``); omit for every state. A value outside the daemon's job-status enum is a 422; a legacy batch state (``pending``, ``completed``, …) is accepted and simply matches nothing. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It only discloses newest-first ordering; it does not clarify read-only/non-destructive behavior, pagination, permissions, or return shape, even though the schema covers paging parameters.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence states the action, resource scope, and ordering with no filler. It is terse but structurally efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 3-parameter list tool with full schema coverage, the description is adequate to know it lists all service types newest first. However, with no annotations and no output schema, it leaves gaps around return shape and when to choose it over list_models, list_databases, or get_service.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so limit, cursor, and status are fully documented in the schema. The description adds no parameter detail, which is acceptable under the baseline-3 rule when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the specific verb 'List' and resource 'services', parenthetically scopes services to apps, models, and databases, and specifies newest-first ordering. It does not explicitly differentiate from siblings such as list_models, list_databases, or get_service, so it falls short of full sibling routing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no when-to-use, when-not-to-use, prerequisites, or named alternatives. With many sibling tools for listing models/databases and getting service detail, the agent must infer that this is the broad discovery tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
project_logsA
Read bounded logs of one service resolved within an explicit project.
Prefer the immutable project ID returned by list_projects. Membership is
resolved by the daemon; a same-name replacement cannot inherit a retired ID.
Existing node grants and local token roles still apply.
| Name | Required | Description | Default |
|---|---|---|---|
| grep | No | Literal substring filter; never a regex. | |
| tail | No | Newest matching lines; clamped to [1, 1000]. | |
| since | No | Inclusive ISO-8601 timestamp filter. | |
| source | No | Log stream: all, build or runtime. | all |
| project | Yes | Immutable prj_ ID or name of an existing project. Prefer the ID from list_projects: a retired ID never addresses a same-name replacement. | |
| service | No | Service inside the project; omit for web. | web |
| since_id | No | Exclusive log cursor; ignored while tail is sent. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden. It usefully discloses that membership is resolved by the daemon, retired IDs never address same-name replacements, and existing grants/token roles apply. It does not cover return format, pagination behavior, or other operational details, leaving clear gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action and is only three sentences long. It avoids repetition and keeps the important project-ID guidance visible, though the final sentence about grants and token roles could be integrated more tightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a seven-parameter log-reading tool with complete schema coverage but no annotations or output schema, the description covers purpose, project resolution, and auth context. It is largely sufficient for correct invocation, though it could say more about the returned log data or filtering behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all seven parameters. The description reinforces the project ID preference but adds little semantic meaning beyond what the schema already states, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: "Read bounded logs of one service resolved within an explicit project." This is clear enough for an agent to understand the core operation. It does not explicitly distinguish itself from the sibling tool service_logs, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description offers guidance to prefer the immutable project ID returned by list_projects and notes that node grants and local token roles still apply. However, it does not explicitly say when to use this tool versus alternatives such as service_logs, nor does it state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
proxy_statusA
Get the embedded proxy's typed state (TLS, apex, respawn, live routes).
Authenticated read: proxy state, TLS subjects + CA fingerprint, apex
registration, respawn backoff, and a tri-state live route table read
from the Caddy admin API. Complements ``list_routes`` (the
DB-authoritative inventory).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does substantial work: it declares this an 'Authenticated read', names the upstream source (Caddy admin API), and characterizes the route table as tri-state. It does not mention failure modes (e.g., proxy down, auth failure) or whether the admin API call can be slow, which keeps it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded summary sentence followed by one supporting sentence that adds the auth source and the sibling distinction. Nothing is padding; the parenthetical field list doubles as return-value documentation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must preview the return shape, and it does: TLS subjects plus CA fingerprint, apex registration, respawn backoff, and a tri-state route table. The term 'tri-state' is left unexplained and failure/empty-state behavior is not covered, but an agent has enough to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing to disambiguate and the baseline of 4 applies. The description correctly avoids inventing inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb ('Get') plus a well-scoped resource ('the embedded proxy's typed state') and an enumerated list of what that state covers. It explicitly distinguishes itself from the sibling list_routes by calling itself a complement to the DB-authoritative inventory, so an agent can choose between them without reading schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The line 'Complements list_routes (the DB-authoritative inventory)' signals the intended division of labor: this tool for live Caddy-runtime state, list_routes for the stored inventory. There is no explicit 'use when / do not use when' phrasing, but the routing context is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_app_fileA
Read one file back from an app's workspace as text.
Use it before patching a file you did not write in this conversation, so
the next ``write_app_files`` replaces content you have actually seen.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name of an existing workspace (also the app name it deploys under). No workspace by that name is ``404 workspace.not_found``. | |
| path | Yes | Workspace-relative path of one file, exactly as ``list_app_files`` reports it (relative, no ``..``). Its text is returned; ≤ 256 KiB by construction, since that is the per-file write cap. A path naming no file answers the same ``404 workspace.not_found`` as an absent workspace. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations, so the description must carry the behavior burden. It discloses the return form ('as text') and the read-then-write rationale, but says nothing about binary/non-text files, error behavior, or permissions — the 404 semantics live only in the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the action and followed by the workflow rationale; nothing wasted. The rationale clause is slightly wordy but earns its place by explaining why to call this first.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-param read tool with no output schema, the description explains what comes back ('as text'), which is the key missing piece. It leaves open handling of non-text files and failure modes, though the schema covers the 404 cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters are thoroughly documented there (workspace name, 404 behavior, path format, 256 KiB cap). The description adds no parameter detail beyond what the schema already supplies, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read one file back from an app's workspace as text'), which cleanly distinguishes it from the listing sibling. It implies the contrast with write_app_files but never names list_app_files, which is the closest read sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete trigger: read before patching a file you did not write in this conversation so write_app_files replaces content you have seen. No explicit when-not or alternative (e.g., 'use list_app_files to discover paths'), so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
redeploy_serviceA
Use when: a git app needs a new commit. Asynchronous — follow with wait_for_service.
Re-clones the repository and branch/tag the service was deployed from
and rebuilds it, so picking up a new commit is one call with the service
name alone. Use this instead of ``deploy_git`` when the service already
exists — every coordinate (repo, ref, subdir, private-repo credential
reference) is read back off the service. A service deployed from a
folder/zip has no recorded source and is refused. ``dry_run=True`` returns
the build/config plan diff (env key names only, values never). A
non-dry-run response carries
``summary``, ``hints`` (never empty) and ``next_step`` — the structured
follow-up call.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name of an existing app deployed from Git; its recorded repo, ref, subdir and credential reference are re-read, so no coordinates are passed here. | |
| dry_run | No | true = validate and return the plan (what would change) with zero writes; nothing is built, deployed or audited as a change. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden and does: it declares the call asynchronous and names the follow-up (wait_for_service), explains that repo/ref/subdir/credentials are re-read off the service, that folder/zip-deployed services are refused, that dry_run makes zero writes, and that a real run returns summary/hints/next_step.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the trigger condition and tightly written for the amount of behavior it covers. It is dense and slightly overstuffed with response-field detail, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description supplies the async contract, the follow-up call, the dry-run semantics, the refusal case, and the shape of the response. That is enough for an agent to invoke it correctly on the first try.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description still adds meaning beyond the schema: it explains why only a name is needed (coordinates are re-read), and that the dry-run diff shows env key names but never values, which the schema does not say.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb pair (re-clone the recorded repo plus ref, then rebuild) against a named resource (an existing git-deployed service). It explicitly contrasts with the sibling deploy_git, so an agent can pick between them without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Leads with a 'Use when: a git app needs a new commit' condition, names the alternative ('use this instead of deploy_git when the service already exists'), and states an exclusion (services deployed from a folder/zip are refused). When-to-use, when-not-to-use and the alternative are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_ai_routeA
Remove a machine AI gateway alias (submitter or admin).
Refused with 409 ``ai_gateway.alias_in_use`` (naming the apps) while a
running app's ``[ai.*]`` uses it, unless ``force``.
| Name | Required | Description | Default |
|---|---|---|---|
| alias | Yes | Machine alias an app names in ``[ai.<name>] model`` with ``provider = "gateway"``: a lowercase letter, then up to 31 of a-z, 0-9, '_' or '-'. | |
| force | No | true = remove even while a running app uses the alias (its AI calls then fail with 404 ``alias_not_found``). | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the permission requirement, the specific 409 error code (`ai_gateway.alias_in_use`), that dependent apps are named, and the force escape hatch. It stops short of stating irreversibility or the success-side effect, but the conflict behavior is unusually well documented.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is short and front-loads the verb and resource, then layers the conflict/force behavior. The line-broken 409 clause is slightly awkward to parse but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no annotations and no output schema, the description covers permissions, failure conditions, and the force override adequately. It omits what a successful removal does to existing configuration or whether it is reversible, which would complete the picture, but the essentials are present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds value by explaining the 409 behavior tied to the force parameter, giving semantic context beyond the schema's field-level text. The alias and idempotency parameters are already fully documented in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb (Remove) and resource (machine AI gateway alias), and the 'remove' prefix clearly distinguishes it from the sibling set_ai_route. The permission qualifier 'submitter or admin' adds useful scope that an agent could not infer from the name alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear operational context by explaining the 409 conflict condition and the force override, which tells the agent when removal will be refused and how to proceed. It does not explicitly contrast with alternatives like set_ai_route, keeping it shy of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_domainA
Remove a custom domain; its route disappears on the next reconcile tick. Idempotent.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name (or row id) of an existing deployed app — only kind 'service' can be exposed: ``share_service``/``add_domain`` refuse a model or database with 422 ``*.kind_unsupported``, while the remove tools just find nothing to undo. | |
| domain | Yes | The bound domain to unbind, case and one trailing dot folded as on add. Grammar is not ENFORCED on delete (a legacy or now-reserved binding stays removable): a name that is not bound simply removes nothing. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the full behavioral burden. It usefully discloses that the route disappears on the next reconcile tick and that the operation is idempotent, but it omits auth requirements, whether the domain binding is permanently destroyed, and any effects on certificates or DNS.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact clauses, with the core action stated first and the timing/idempotency caveats appended. Every phrase earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no annotations, the description gives important timing and idempotency context, and the schema is fully described. However, it leaves gaps around authorization, permanence, and edge-case behavior that an agent might need before invoking it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameters are already well documented. The description reinforces domain removal but does not add syntax, format, or parameter-level meaning beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Remove a custom domain'. It is clearly distinguishable from the sibling 'add_domain' and from service removal tools like 'remove_service'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies a deletion use case but does not explicitly state when to use this versus alternatives such as 'unshare_service' or 'remove_ai_route'. The schema carries most of the relevant conditions, including that removal is a no-op when nothing is bound.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_hookA
Remove an inbound webhook; its address stops answering. Idempotent.
The signing secret stays set (remove it with ``remove_secret``). A
webhook still declared in nerdit.toml comes back with a NEW address on
the next deploy.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name (or row id) of an existing deployed app — only kind 'service' can be exposed: ``share_service``/``add_domain`` refuse a model or database with 422 ``*.kind_unsupported``, while the remove tools just find nothing to undo. | |
| hook_name | Yes | Webhook name: lowercase letters, digits and '-', 1-32 characters, starting with a letter (e.g. ``stripe``); maps to ``NERDIT_HOOK_<NAME>_SECRET`` and ``NERDIT_HOOK_<NAME>_URL``. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden and does well: it discloses idempotency, that the endpoint stops answering, that the signing secret survives, and the non-obvious redeploy resurrection with a fresh address. It omits auth/permission requirements and any indication of what the call returns, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action and effect lead the description, with the two caveats following as short, self-contained notes. Every sentence conveys a distinct behavioral fact; nothing is redundant with the name or the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-parameter mutation tool with no annotations and no output schema, the description covers the consequential behaviors (idempotency, secret persistence, redeploy recreation) that an agent would otherwise get wrong. The remaining gap is what a successful call returns or errors on, which is minor given full schema coverage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both required parameters and idempotency_key are fully documented in the schema itself. The description adds only indirect context ('a webhook still declared in nerdit.toml' hints at hook_name) and no syntax or semantics beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Remove an inbound webhook') plus the observable effect ('its address stops answering'), which distinguishes it from add_hook/list_hooks and from remove_secret. An agent can tell exactly what this tool does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly routes the secret-removal case to remove_secret and warns that a webhook still declared in nerdit.toml will be recreated with a NEW address on the next deploy, which is precisely the condition an agent needs before calling. It stops short of stating 'use this when you want to stop receiving deliveries' or naming list_hooks for discovery, so it is clear context rather than full when/when-not coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_secretA
Delete one secret key, or all of a service's secrets when key is omitted.
Deleting a shared key can break every app still referencing it via
``${secrets.shared.KEY}``.
| Name | Required | Description | Default |
|---|---|---|---|
| key | No | The one secret key to delete; omit it — null or an empty string — to delete ALL of the scope's secrets at once. Deleting a key that does not exist is a 404. | |
| service | Yes | Service (app, model or database) whose secrets this call modifies — need not exist yet: a set on an undeployed name reserves it for this token until deployed — or ``shared`` for the global scope (set: unscoped submitter or admin; delete: admin), read by a service only where a ``${secrets.shared.KEY}`` reference is honoured (``ai``/``db``/``edge_auth`` refs, a git ``token_ref``), never via ``env``. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose one real behavioral trait: deleting a shared key can break every app referencing it via ${secrets.shared.KEY}. It omits reversibility, permission requirements for the shared scope (documented only in the schema's service param), and whether omitted-key deletion is atomic.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the core action and the destructive branch. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a destructive mutation tool with no annotations and no output schema, so the description should carry more weight. It covers the main risk but leaves out permission requirements, irreversibility, and what a bulk delete returns — the schema fills some of this, but not all.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description restates the key-omission semantics but adds no format or behavioral detail beyond what the schema already documents for key, service, and idempotency_key.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (delete) and resource (one secret key, or all secrets for a service), and the scope distinction (single key vs. whole service scope) is spelled out. It is clearly separable from siblings like set_secret and list_secret_names.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'key omitted' branch clarifies which calling mode produces which effect, which is implied usage guidance. However, it names no alternative tool (set_secret for replacement, list_secret_names for discovery) and gives no explicit when-not-to-use condition beyond a consequence warning.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_serviceB
Delete a service (teardown + remove).
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Service name or job id of an existing service (app, model or database); both resolve to the same row. | |
| force | No | true bypasses the dependency guard (a model or database other apps still bind), kills an in-flight run and cancels an in-flight cutover; a cross-owner dependent makes it admin-only. false (the default) refuses those with 409 ``resource.in_use`` / ``service.run_in_progress`` / ``service.cutover_in_progress``. | |
| purge | No | CSV of durable state to destroy alongside the row: ``secrets``, ``data``, ``images``, ``workspace``. Default ``secrets``; an empty string purges nothing; an unknown token is a 422 ``service.invalid_purge``. Deleting a managed DATABASE requires ``data`` in the set (409 ``db.delete_requires_purge``, not bypassable by ``force``), and purging ``data`` always purges ``secrets`` too. | secrets |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full behavioral burden, yet it only says 'teardown + remove'. It omits irreversibility, dependency guards, 409 behaviors, admin-only cases, and purge semantics — all of which live in the schema, not the description. 'Teardown' hints at state destruction but is too vague for a destructive tool with zero annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single short sentence, front-loaded with the verb and resource, with zero filler. It is exactly as long as the description needs to be, given the schema handles the details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a destructive operation with no annotations and no output schema, the description is minimally complete: it tells the agent the operation removes a service, but not enough about risk, prerequisites, or the stop-vs-delete decision. The rich schema compensates for parameter-level gaps but not for top-level behavioral framing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the parameter docs are unusually rich (force dependency bypass, purge token semantics, idempotency replay). The description adds nothing beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Delete a service') and adds a scoping note ('teardown + remove') indicating it does more than stop it. However, it does not distinguish itself from sibling stop_service, which is the closest alternative an agent would consider.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no exclusion criteria, and no mention of stop_service as an alternative for reversible shutdowns. The agent must infer that permanent removal versus stopping are different paths.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_variablesA
What a launch would see: per key, the winning scope and whether it is plain. No values.
The loop is "the agent asks, the human supplies". Call this before a
deploy to see which keys the service will receive (``scope`` is
``project`` or ``production/<service>``). When a key the app needs is
missing, do NOT invent or request the value in chat: ask the human to
run ``nerdit vars set <project> --secret --prompt KEY``, then call this
again to confirm the key is present. A secret value is never returned by
any tool. Owner or admin only; a name outside your scope is 403.
| Name | Required | Description | Default |
|---|---|---|---|
| project | Yes | Immutable prj_ ID or name of an existing project. Prefer the ID from list_projects: a retired ID never addresses a same-name replacement. | |
| service | No | Service inside the project whose launch to resolve for; omit for ``web``, the service of a single-app project. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so well: it discloses that no values are returned, secret values are never returned by any tool, access is owner/admin only, and out-of-scope names produce 403. It also explains the missing-key workflow, which is important agent behavior not captured by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the return shape and scope, then moves directly into the deploy-time usage and missing-key workflow. Despite covering several behaviors, every sentence contributes to correct invocation and safe handling of secrets.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema and no annotations, so the description must explain return semantics, safety, and permissions; it does all three. An agent knows what the tool returns, when to call it, how to handle missing keys, and that secret values will never be exposed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so project and service are already documented in the schema, including the prj_ ID preference and web default. The description adds context about scopes and service launches but does not add parameter-level syntax or constraints beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific operation and result shape: resolving what a launch would see per key, including winning scope and whether it is plain, with "No values." It clearly contrasts with mutation tools like set_variable by emphasizing inspection only and never returning secret values.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says to call this before a deploy to see which keys the service will receive, and it gives a precise recovery path when a key is missing: ask the human to run `nerdit vars set <project> --secret --prompt KEY`, then call again. It also states what not to do: do not invent values or request them in chat.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restart_daemonA
Restart the daemon to apply restart-required config (admin-scoped, audited).
Returns 202 with drain counts. **Over the HTTP MCP transport this kills
the connection serving this call**: a dropped response after issuing it
means the restart most likely started. Confirm with ``capabilities``
(``uptime_s`` resets); retrying with the same idempotency key answers
``409 daemon.restart_in_progress`` or a fresh 202, never a second
restart mid-drain.
| Name | Required | Description | Default |
|---|---|---|---|
| drain_timeout_s | No | Seconds to let in-flight builds, runs and releases drain before the daemon self-execs, clamped server-side to [0, 300]; omit for 60. At 0 the SIGTERM can beat the 202 response. | |
| idempotency_key | No | Caller-chosen key; the daemon REQUIRES one and the MCP tool mints a fresh uuid4 when you omit it. A retry with the same key is safe: it answers ``409 daemon.restart_in_progress`` (or replays the first 202), never a second restart mid-drain. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden and does: it declares admin scope and auditing, the 202 response with drain counts, and the critical caveat that over HTTP the call kills its own connection (so a dropped response means success, not failure). It also fully specifies retry behavior with an idempotency key (409 daemon.restart_in_progress or replayed 202, 'never a second restart mid-drain').
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded: the action and its purpose come first, then the return contract, then the failure/recovery caveat. Slightly noisy from leaked reStructuredText backticks (``capabilities``, ``uptime_s``) and multi-line wrapping, but no sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates with the status code, the transport-specific failure mode, and the exact recovery/verification procedure. For a daemon-killing mutation with no annotations, this is everything an agent needs to call it and interpret an ambiguous result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds value by framing why drain_timeout_s and idempotency_key matter in the failure scenario the agent will actually hit (a dropped response, then a safe retry). It reinforces rather than duplicates the schema's own parameter prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ('Restart the daemon') plus the condition that motivates it ('to apply restart-required config') and its scoping ('admin-scoped, audited'). The phrase 'the daemon' distinguishes it from the sibling restart_service without needing to name it, so an agent can select correctly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly states when to use it (config marked restart-required) and states the admin scope prerequisite, plus it names capabilities as the post-hoc verification path. It does not explicitly exclude or compare against restart_service for the case where only a single service changed, which is the main remaining inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restart_serviceB
Restart a service (clears backoff).
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Service name or job id of an existing service (app, model or database); both resolve to the same row. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it discloses one genuinely non-obvious mutation effect: backoff state is reset. It omits downtime/disruption, whether the call blocks, and what happens if the service does not exist, which are exactly the traits an agent needs for a mutating tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single short sentence with the resource up front and the notable behavior in parentheses; no waste. It is arguably too terse rather than padded, so it loses a point for thinness rather than verbosity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutating, annotation-free tool with no output schema, the description never says what the call returns (immediate ack vs. blocking until healthy) or how failures surface. That is a meaningful gap an agent must guess at before invoking.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema itself explains that name accepts a service name or job id and that idempotency_key replays a prior result, so the description adds nothing but does not need to. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Restart a service" is a specific verb+resource, and the parenthetical "clears backoff" disambiguates it from stop_service and redeploy_service in the sibling list. It stops short of naming an alternative outright, so it does not fully earn a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase "clears backoff" implies the usage context (a service stuck in crash backoff), but the description never says when to prefer this over redeploy_service, stop_service, or wait_for_service, and gives no exclusions or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_commandA
Run a one-off command in a deployed service's image (migrations, seeds).
The command runs in a throwaway container built from the service's
current image with the same env, secrets, AI/DB bindings and named
volumes as the live container — the service itself keeps serving.
**Bounded-synchronous**: this call BLOCKS until the command exits or
``timeout_s`` seconds elapse, then returns ``{exit_code, timed_out,
oom_killed, duration_s, run_id, log_tail, ...}``. Branch on
``exit_code``/``timed_out`` — a non-zero exit is a normal 200 result,
not an error. One run at a time per service (409
``service.run_in_progress``).
Because the call blocks for minutes, **supply your own
``idempotency_key`` and REUSE it verbatim if you retry** — that is the
only thing standing between a client-side read timeout and a migration
running twice. A retried key REPLAYS an ``idempotent_replay`` envelope,
NOT the command's output — the run's stdout is deliberately never
cached at rest. That replay is an HTTP 200 carrying ``code:
"idempotent_replay"`` and NO ``exit_code``, so check for that code
before reading ``exit_code``. Re-run under a fresh key if you need the
output again, or read it from ``diagnose_service``'s ``last_run``.
**Key reuse protects a COMPLETED run only.** A failed call un-pins the
key, so a same-key retry really re-executes. In particular ``503
run.interrupted`` means the container started and was lost — the
command may have partially applied — and retrying it, with any key,
runs it again: stop and inspect instead. And if the daemon died
mid-run, the key stays claimed for 24 h and the retry returns ``409
idempotency_in_progress``; mint a fresh key once you have confirmed
the run is over.
| Name | Required | Description | Default |
|---|---|---|---|
| env | No | Env overrides for this run only (≤ 64 keys); omit for none. They beat the app's config env and its secrets, but lose to platform-computed keys (resolved AI/DB binding vars, ``PORT``, ``NERDIT_RUN_ID``). Put credentials HERE: values are masked in audit, scrubbed from the returned tail and never echoed back. | |
| name | Yes | Name (or row id) of a deployed APP. A model or database is refused with 422 ``run.not_supported`` — their commands and credentials are platform-managed. | |
| command | Yes | Argv, run unshelled — no globbing, no pipes (wrap in ``["sh", "-c", "…"]`` for those). It REPLACES the image's CMD and is APPENDED to its ENTRYPOINT when one is declared. 1-256 arguments, none empty or NUL-bearing. Never put credentials here: argv is host-visible via ``docker inspect`` and stored verbatim in ``last_run``. | |
| log_tail | No | Lines of scrubbed output returned. Default 200; clamped to [1, 200] here and again server-side. | |
| timeout_s | No | Seconds before the container is killed and ``timed_out: true`` returned. Default 300; floored at 1 and otherwise passed straight through, so a value above ``[services].run_timeout_max_s`` gets the authoritative 422 ``run.timeout_too_large`` instead of being silently truncated. | |
| idempotency_key | No | Caller-chosen key; omit and a fresh one is minted per call. A retry with the same key replays the first result ONLY if that run completed (2xx). Any other outcome — including 503 ``run.interrupted``, where the container started and its exit is unknown — releases the key, so the retry runs the command AGAIN: check ``last_run`` and the app before retrying a migration. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: blocking semantics, the exact return envelope, the rule that a non-zero exit is a 200 not an error, the one-run-at-a-time 409, and the fact that volumes/env/secrets are shared with the live container. The idempotency deep-dive (replay yields `idempotent_replay` with no `exit_code`; failure un-pins the key; 503 `run.interrupted` may mean partial application; 24h key claim on daemon death) discloses exactly the risky, non-obvious behavior an agent would otherwise get wrong.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then behavior, then retry semantics — a sensible order for a blocking mutation. It is long but nearly all of it is load-bearing; the main waste is the idempotency paragraph restating what the `idempotency_key` schema description already says.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema and no annotations, yet the description supplies the return envelope, error codes, timeout behavior, concurrency limit, and credential-masking implications. For a destructive-capable, minutes-blocking operation that is everything an agent needs to call it safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns a bump by front-loading the operational consequence of `idempotency_key` and `timeout_s` (non-zero exit vs. timed_out, 422 rather than silent truncation). It does duplicate the schema's own idempotency wording, so the added value is emphasis and retry procedure rather than new meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb and resource ('Run a one-off command in a deployed service's image') and immediately disambiguates with concrete use cases (migrations, seeds). The throwaway-container clause sharpens the scope further, distinguishing it from a restart/redeploy and from the live service's own process.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives strong when-to-use context (migrations, seeds), an explicit exclusion (models and databases are refused with 422 run.not_supported), and points to `diagnose_service`'s `last_run` when you only need prior output. What it omits is any comparison to siblings that could otherwise do the job, notably `add_hook` for migrations that should run on every deploy rather than once — with ~70 siblings that is a real gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
serveC
Register a service from a prebuilt image.
| Name | Required | Description | Default |
|---|---|---|---|
| env | No | Environment variables injected into the container, as literal strings. Omit for none. Secrets belong in ``set_secret``, which overrides an ``env`` key of the same name at launch. | |
| gpus | No | GPUs the service needs; default 0 = none. Allocation is shared, not exclusive, and is checked against the token's quota. | |
| name | Yes | Name for the NEW service: a lowercase DNS label, 1-63 chars (``^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$``). Register-only — an existing name is refused with 409 ``service.name_taken`` rather than redeployed. | |
| port | No | Container port published on the host. Default 8000; 1-65535. | |
| image | Yes | Tag of an image that already exists on the daemon's runtime; it is never built and never pulled here, and a missing one is refused with 400 ``image_not_found``. | |
| vendor | No | GPU vendor to reserve when ``gpus`` > 0 (``nvidia`` or ``amd``); omit to let the daemon choose on a fresh deploy — a redeploy keeps the vendor already recorded. | |
| command | No | Command overriding the image's CMD, split into argv like a shell would (``shlex``) but run WITHOUT a shell — no pipes, redirects or ``$VAR``; write ``sh -c '…'`` for those. Omit to run the image's own CMD. | |
| script_path | No | Host path to a script run under ``nerdit-runtime`` instead of the image CMD. Omit for the image CMD; it bind-mounts a host directory and needs an admin token (403 ``sandbox.script_path_forbidden``). | |
| health_check | No | Probe policy ``{path, type: http|tcp, timeout_s, unhealthy_threshold, start_period_s}``; omit for liveness-only supervision. Repeated failures mark the service ``degraded`` and leave it running — only a dead container is restarted. | |
| restart_policy | No | What the daemon does when the container exits: ``always`` (the default), ``on-failure`` or ``no``. | always |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full behavioral burden and does not meet it. It omits that names are register-only (409 on collision), that the image must already exist on the daemon, whether the container is started immediately, permission requirements, and idempotency behavior — facts that exist only in the schema property descriptions, not the tool description.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence with no filler, so nothing is wasted — but for an 11-parameter mutation tool it is under-specified rather than concise. Brevity here costs the agent needed routing and behavior information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no annotations, no output schema, and 11 parameters, the definition should explain what a successful call yields (a service record, an endpoint, a status) and how it relates to list_services/get_service/wait_for_service. Only the input schema compensates, leaving the post-call workflow undocumented.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the per-parameter text is unusually rich (name regex, script_path admin-token requirement, command argv semantics, health-check shapes). The description adds nothing beyond that, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'register a service', qualified by 'from a prebuilt image', which signals it will not build or pull. It is clear on its own, but it never names or distinguishes itself from the many near-neighbours (deploy, deploy_template, deploy_app, serve_model, redeploy_service), so the agent must infer the difference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no exclusions, and no named alternative. An agent facing 60+ siblings that all create or deploy services gets no rule for choosing 'serve' over 'deploy' or 'deploy_template'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
serve_modelA
Serve a local AI model as an OpenAI-compatible endpoint.
Serving is asynchronous: the call returns immediately with the
model row in ``building`` while the daemon pulls the image and weights
off-tick; poll ``list_models`` (or ``get_service``) until it is
``running``. Lifecycle (stop / restart / delete) goes through the
existing service tools (``stop_service`` / ``restart_service`` /
``remove_service``).
An app connects to this model by declaring an ``[ai.<name>]`` binding
(provider ``ollama``, model = this model); at each launch it receives
``NERDIT_AI_<NAME>_URL/_KEY/_MODEL``, and the ``default`` binding also
sets ``OPENAI_BASE_URL/OPENAI_API_KEY/OPENAI_MODEL`` so an unmodified
OpenAI SDK reaches this endpoint with no code change.
| Name | Required | Description | Default |
|---|---|---|---|
| gpus | No | GPUs to reserve for the model server; 0 (the default) is CPU inference, and allocated GPUs are shared with other workloads. The ``vllm`` backend needs at least 1 and refuses 0 with ``model.gpu_required``. | |
| name | No | Service name for the model (lowercase DNS label). Omit and the name is the backend-prefixed, sanitized model reference (``llama3.1:8b`` on ollama → ``ollama-llama3-1-8b``). | |
| model | Yes | Model reference to pull and serve, e.g. ``llama3.1:8b`` (ollama) or a Hugging Face repo id (vLLM): letters, digits, ``. - _ /`` with an optional ``:tag``. | |
| backend | No | Serving backend: ``ollama`` (CPU or GPU) or ``vllm`` (GPU-only, one model per server, weights from Hugging Face). Omit to use the daemon's configured default; an unknown name is refused with ``model.unknown_backend``. | |
| max_model_len | No | vLLM only: context-window cap in tokens (``--max-model-len``), 256 to 262144. Omit and the daemon decides: an operator flag in ``[models].vllm_extra_args``, else 4096 on a GPU under 16 GB VRAM, else vLLM's own default. Any other backend refuses it with ``model.backend_param``. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. | |
| gpu_memory_utilization | No | vLLM only: fraction of VRAM the engine may claim (``--gpu-memory-utilization``), 0.1 to 0.95. Omit and the daemon decides: an operator flag in ``[models].vllm_extra_args``, else 0.85 on a GPU under 16 GB VRAM, else vLLM's own default. Any other backend refuses it with ``model.backend_param``. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so well: it discloses asynchronous immediate-return semantics, the 'building' intermediate state, background image/weight pulling, and where lifecycle actions live. It also explains how apps bind to the endpoint and what env vars result.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then async behavior, then app binding. Efficient overall, though the [ai.<name>] binding paragraph is somewhat tangential to invoking the tool and could be trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-param mutation tool with no annotations and no output schema, the description covers the async lifecycle, polling target, and error behavior well enough to call correctly. It does not describe the shape of the returned 'model row', though the schema and error codes compensate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter (gpus, backend, max_model_len, idempotency_key, etc.) is already documented with constraints and error codes. The description adds no parameter-level meaning beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Serve a local AI model as an OpenAI-compatible endpoint.' It is distinguishable from siblings like list_models and get_service, and it explicitly routes lifecycle operations to stop_service/restart_service/remove_service.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operational context: serving is asynchronous, poll list_models or get_service until running, and use the existing service tools for lifecycle. It does not, however, distinguish this tool from the sibling 'serve' tool, leaving one alternative unaddressed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
service_logsA
Use when: you need the raw output a service or its build printed.
``source`` picks which output you get. **Pass ``source='runtime'`` when
you are debugging a running app** — the build and the app used to share
one stream, so a bare ``grep`` over a deployed app still matches
BuildKit layer chatter (``404B``, ``CACHED``, ``sha256:…``) from the
build that produced it. Lines written by an older daemon are stored as
stdout and therefore read as ``'runtime'`` whichever program printed
them.
``grep`` keeps only lines CONTAINING that text. It is a plain
**literal substring**, never a regex.
All three filters run server-side inside the ``tail`` bound, so ``tail``
counts matching lines: ``grep='Traceback', source='runtime', tail=20``
gives the last 20 app tracebacks out of a million-line log in one
bounded query. Prefer that over pulling a large tail and searching it
yourself.
| Name | Required | Description | Default |
|---|---|---|---|
| grep | No | Keep only lines containing this literal substring (never a regex: no anchors, no character classes, nothing to escape). Truncated to its first 200 characters server-side. Omit to keep every line. | |
| name | Yes | Service name or job id of an existing service (app, model or database); both resolve to the same row. | |
| tail | No | Most recent matching entries to return. Default 100; clamped to [1, 1000] here and bounded again server-side. Counts lines left AFTER ``grep``/``since``/``source``, not lines scanned. | |
| since | No | Keep only lines at or after this ISO-8601 UTC timestamp, inclusive (``2026-08-07T10:00:00Z``). Omit for no lower bound. | |
| source | No | Which stream: ``runtime`` (the container's stdout/stderr plus its crash tail), ``build`` (the image build's output), or ``all`` (the default — both, plus the daemon's own lifecycle lines). Sent only when it is not ``all``; the daemon owns the vocabulary and 422s anything else. | all |
| since_id | No | Exclusive forward cursor: only entries with a larger id. Default 0 = from the start. Ignored whenever ``tail`` is sent — and this tool always sends it — so a page is always the NEWEST matching lines, not the ones after this id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden and does well: it explains server-side filtering, literal substring grep, source stream mixing, and the runtime/build ambiguity for older daemon lines. It does not discuss permissions or response shape, which are minor gaps for a read-only log retrieval tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the use condition and then explains the filters in a logical order. It is somewhat long and repeats some schema details, but most of the text earns its place by clarifying tricky log semantics.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
It thoroughly covers input semantics and filtering behavior for a 6-parameter tool. However, with no output schema, it does not explain the return format or whether lines are plain strings versus objects with timestamps or ids, leaving the agent to infer response structure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds meaningful interpretation beyond the schema, especially for source='runtime' and the interaction between grep, source, and tail, though it does not mention the since_id behavior documented in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly establishes that this tool retrieves raw service or build output, with source-specific filtering. It does not explicitly differentiate itself from sibling tools such as project_logs or diagnose_service, leaving that routing to the agent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear when-to-use condition: when the raw output a service or build printed is needed. It also advises using bounded grep/tail queries instead of pulling large tails, but it does not name alternative tools or state when not to use this one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
service_statsA
Get live CPU, memory, network and PID usage for a running service.
Returns ``{available, stats: {cpu_pct, mem_used_bytes, mem_limit_bytes,
mem_pct, net_rx_bytes, net_tx_bytes, pids}, gpus, cached}``.
**Branch on ``available``, never on zeroes.** ``available: false`` with
``stats: null`` is the normal answer when the service has no running
container or the daemon cannot reach Docker; every individual counter
is likewise ``null`` when unknown, so a missing metric never
masquerades as an idle one. ``cpu_pct`` follows the docker convention —
``100.0`` is one fully-used core, so a multi-core host can exceed 100.
For *why* a service is unhealthy use ``diagnose_service``; this tool
answers *how much* a healthy one is consuming. The daemon caches the
sample for 2 seconds, so polling it in a loop is cheap.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Service name or job id of an existing service (app, model or database); both resolve to the same row. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it discloses the availability contract, null-vs-zero semantics, the docker cpu_pct convention where 100.0 is one core, and the daemon cache TTL. These are non-obvious traits an agent cannot infer from the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose, then the return shape, then the critical branching rule, then routing guidance. Every sentence adds decision-relevant information, including the counterintuitive null-masquerade warning; no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description supplies the response shape explicitly and warns how to interpret it. For a single-parameter read tool, nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter and schema coverage is 100%, so the schema already documents that 'name' accepts a service name or job id. The description adds nothing about the parameter, which is acceptable given the baseline for fully-covered single-parameter schemas.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Get live CPU, memory, network and PID usage') and a precise resource scope ('for a running service'). It also explicitly separates itself from the sibling diagnose_service by framing this tool as answering 'how much' rather than 'why'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit routing rule: 'For why a service is unhealthy use diagnose_service; this tool answers how much a healthy one is consuming.' It also tells the agent that loop-polling is acceptable due to the 2-second cache, which is actionable when-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_ai_routeA
Create or replace a machine AI gateway alias (submitter or admin).
Apps then declare ``[ai.default] provider = "gateway"`` and
``model = "<alias>"``: the daemon injects the gateway URL and a per-app
virtual key, and the provider key never enters a container. Answers
``enabled: false`` while ``[ai_gateway]`` is off (the alias is stored
and serves once it is enabled). Refusals: 422 ``ai_gateway.alias_invalid``,
``ai_gateway.base_url_invalid`` (not https, private address, userinfo),
``ai_gateway.secret_ref_invalid``.
| Name | Required | Description | Default |
|---|---|---|---|
| alias | Yes | Machine alias an app names in ``[ai.<name>] model`` with ``provider = "gateway"``: a lowercase letter, then up to 31 of a-z, 0-9, '_' or '-'. | |
| model | Yes | Provider model the alias maps to (an ollama model name for provider 'ollama'). | |
| base_url | No | Provider ``api`` only: OpenAI-compatible base URL, usually ending in ``/v1``; https to a public host, or http to loopback or the models bridge. | |
| provider | No | ``api`` (an OpenAI-compatible provider) or ``ollama`` (a model served on this machine). | api |
| api_key_ref | No | Provider ``api`` only: a ``${secrets.shared.KEY}`` reference to the provider key, set beforehand with ``set_secret`` on scope ``shared``. Never the key itself. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full burden and does so well: it discloses that this is an upsert (replace, not just create), that submitter or admin privileges are required, that the daemon injects the gateway URL and a per-app virtual key so the provider key never enters a container, and that a disabled gateway yields enabled: false while still storing the alias. It even enumerates the specific 422 refusal codes (alias_invalid, base_url_invalid, secret_ref_invalid), which is exactly the kind of failure-mode context annotations would otherwise provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The primary action is front-loaded in the first clause, and the remaining sentences earn their place by covering the app-side contract, the disabled-gateway behavior, and refusal codes. It is dense and slightly prose-heavy, but no sentence is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter mutation tool with no annotations and no output schema, the description supplies the missing pieces an agent needs: mutation semantics, authorization, the substitute response shape (enabled: false), and enumerated error codes. Nothing material is left to inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all six parameters including alias naming rules, base_url constraints, and the ${secrets.shared.KEY} reference form; baseline is 3. The description reinforces two things the schema also states (alias/model pairing, secret refs via set_secret on the shared scope) but adds no syntax or edge-case detail beyond the structured fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource with upsert semantics: 'Create or replace a machine AI gateway alias', plus the actor scope '(submitter or admin)'. An agent can distinguish this from list_ai_routes and remove_ai_route purely from the verb, without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the downstream use case (apps then declare provider = "gateway" and model = "<alias>") and the disabled-gateway condition, so the agent knows the context in which this is the right call. It stops short of naming alternatives explicitly (e.g. 'use list_ai_routes to inspect, remove_ai_route to delete'), so it lacks a true when-not clause.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_app_configA
Write an app's deploy or ai config section (admin/owner-scoped).
Writing the ``ai`` section re-wires the app's bindings: on the next
launch/restart each ``[ai.<name>]`` binding is injected as
``NERDIT_AI_<NAME>_URL/_KEY/_MODEL``, and the ``default`` binding also
sets ``OPENAI_BASE_URL/OPENAI_API_KEY/OPENAI_MODEL`` — pass
``restart=True`` to apply it immediately. A dry run needs neither an
``If-Match`` nor an idempotency key.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name of a deployed app (``kind=service``). A served model or a managed database is a 404 ``config.not_an_app``; an unknown name a 404 ``not_found``. | |
| values | Yes | Keys to merge into that section: an omitted key keeps its value, a null deletes it (a whole binding, or a ``deploy`` key back to its default). In ``ai``/``db`` the unit is the binding — each ``[ai.<name>]``/``[db.<name>]`` table REPLACES the stored one wholesale, so send the whole binding. In ``deploy`` name and port are immutable (422); ``get_app_config`` lists the writable keys. | |
| dry_run | No | true = validate and return the plan (what would change) with zero writes; nothing is built, deployed or audited as a change. | |
| restart | No | true = restart the service right after a real write, whether or not the change needed one. false leaves the running container alone and the response's ``requires_restart`` says whether it should be restarted. No effect when ``dry_run`` is true. | |
| section | Yes | Section to write: ``deploy``, ``ai`` or ``db`` (anything else is a 422 ``config.unknown_section``). ``env`` is not writable here — it belongs to the deploy tools and ``set_secret``. | |
| if_match | No | ETag from a previous read of this app's config, sent as ``If-Match`` (409 ``config.stale`` when it no longer matches). Omit and the current ETag is read and used for you; ``*`` matches unconditionally. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden and does so well: it explains that writing `ai` re-wires bindings into `NERDIT_AI_<NAME>_URL/_KEY/_MODEL` and `OPENAI_*` on next launch, that ETag mismatch yields 409 `config.stale`, that retries replay via idempotency key, and that a dry run is neither built, deployed nor audited.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and scope, then the highest-value behavioral note about binding re-wiring. Dense but nearly every clause carries information; the em-dash-heavy formatting is slightly harder to scan than plain sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 7 parameters, a nested `values` object, no output schema and no annotations, the description covers authorization scope, side effects, error codes, idempotency and dry-run behavior. An agent has what it needs to call this safely without further discovery.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, which sets baseline 3, but the description adds real meaning beyond the schema: the binding-level replace semantics, the restart-on-write behavior, and the note that a dry run skips `If-Match` and idempotency keys. The merge/delete semantics are covered by the schema rather than the description, keeping it off a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource — 'Write an app's deploy or ai config section' — and states the scope (admin/owner). It implicitly distinguishes itself by noting that `env` is not writable here and belongs to the deploy tools and `set_secret`, though it never names its closest siblings `set_config` or `apply_config`.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clear operational guidance: pass `restart=True` to apply immediately, use `dry_run` to validate with zero writes, and a dry run needs neither `If-Match` nor an idempotency key. It also excludes `env` explicitly. What's missing is when to reach for this tool over `set_config`/`apply_config`, which the description never addresses.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_configB
Write a daemon config section (admin-scoped, validated, audited).
| Name | Required | Description | Default |
|---|---|---|---|
| values | Yes | Keys to merge into that section: an omitted key keeps its stored value, a null value deletes a NULLABLE key (reverting it to its default; a null on a non-nullable key is a 422 ``config.invalid``), and a nested table is merged one level deep. An unknown key is refused (422 ``config.invalid``) rather than silently dropped; ``auth_token`` is refused (403). | |
| dry_run | No | true = validate and return the plan (what would change) with zero writes; nothing is built, deployed or audited as a change. | |
| section | Yes | Config section to write, one per call (e.g. ``proxy``, ``services``, ``retention``). An unknown name is a 404 ``config.unknown_section``. | |
| if_match | No | ETag from a previous read of this section, sent as ``If-Match``: the write is refused with 409 ``config.stale`` if the config changed since. Omit to write unconditionally (no ETag is fetched for you); ``*`` always matches. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries real weight, and it does disclose three useful traits not in the schema: admin scoping, validation, and that the change is audited. It omits reversibility, the effect on the running daemon (reload vs restart), and any rate or concurrency behavior, so it is helpful but incomplete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler and the key qualifiers packed into the parenthetical. It is arguably too terse rather than padded, but every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The rich schema covers parameters, error codes, and safety mechanisms, and no output schema exists to explain. What is missing is context an agent would want for a destructive write: whether it takes effect immediately, what to do on config.stale, and how it relates to apply_config.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the property descriptions already explain merge semantics, dry_run, if_match, and idempotency in detail. The tool description adds nothing beyond that, which is the baseline case for a fully documented schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Write') and resource ('daemon config section'), and the parenthetical scoping qualifiers make it clear this mutates a section of the daemon configuration. It does not explicitly differentiate itself from close siblings like apply_config or set_app_config, so an agent must infer that this is the per-section write primitive.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance at all: nothing tells the agent to prefer this over apply_config, set_app_config, set_variable, or set_secret, nor when to use dry_run first. Only the 'admin-scoped' hint implies a permission prerequisite.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_secretA
Set/merge write-only secrets for a service; returns key names only.
WARNING: the values you pass here transit this agent's transcript in
plaintext; for high-value shared keys (broadly-scoped API keys,
credentials shared across every app) prefer ``nerdit secrets set --shared`` from the CLI
instead of routing them through an agent. The leak-free path for any
value: a human runs ``nerdit secrets set <service> --prompt KEY``
(hidden input) and you only ever name ``KEY``; it is injected at
launch, overriding an ``env`` key of the same name. You may set secrets
before the service exists; the name is then reserved for your token
until you deploy it (another token's deploy of that name gets 409
``service.name_claimed``).
| Name | Required | Description | Default |
|---|---|---|---|
| values | Yes | KEY → value pairs merged into the stored set: a listed key is overwritten, an unlisted one kept. Key names are env-var identifiers (``[A-Za-z_][A-Za-z0-9_]*``); a value may be multi-line but may contain no NUL and no control character other than tab/newline/CR. An empty map is refused. | |
| service | Yes | Service (app, model or database) whose secrets this call modifies — need not exist yet: a set on an undeployed name reserves it for this token until deployed — or ``shared`` for the global scope (set: unscoped submitter or admin; delete: admin), read by a service only where a ``${secrets.shared.KEY}`` reference is honoured (``ai``/``db``/``edge_auth`` refs, a git ``token_ref``), never via ``env``. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it discloses that values are plaintext in the transcript, that storage is write-only, that merges overwrite listed keys and keep unlisted ones, that deployment injects the secret overriding an env key of the same name, and that only key names come back. This is unusually complete risk and side-effect disclosure for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core verb and return contract before any warnings. The warning block is long and partly reads as CLI advocacy, but each sentence carries a distinct risk or escape hatch, so little is genuinely redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description states the return (key names only). For a mutation tool with no annotations and nested value objects, it covers safety, scope, merge behavior, failure mode and alternative paths, leaving nothing an agent needs before calling it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameters, key-name regex, value character restrictions, empty-map rejection, the ``shared`` scope and idempotency replay are all already documented in the schema. The description adds context about injection overriding env keys but does not extend parameter meaning beyond what structured fields provide, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Set/merge write-only secrets for a service") plus the return contract ("returns key names only"). The merge semantics and write-only nature distinguish it from siblings such as set_variable, remove_secret and list_secret_names without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent away from this tool for high-value shared keys, naming the exact alternative (``nerdit secrets set --shared``) and the leak-free human path (``--prompt KEY`` with hidden input). It also states that pre-deploy reservation is allowed and what conflict (409 ``service.name_claimed``) to expect.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_variableA
Set/merge a project's variables; write-only unless secret=false. Returns names only.
WARNING: the values you pass here transit this agent's transcript in
plaintext, whether ``secret`` is omitted, ``true`` or ``false``. For any
credential, do not pass the value at all: ask the human to run
``nerdit vars set <project> --secret --prompt KEY`` (hidden input) and
only ever name ``KEY`` yourself. Use this tool for values that are fine
to appear in a transcript (a log level, a feature flag, a public URL).
A variable reaches a service's environment at launch. Precedence, lowest
to highest: the manifest ``env`` table, the project scope, the service
scope, then platform-injected bindings (``OPENAI_BASE_URL``,
``DATABASE_URL``…), which a variable can never override. Setting a key
again flips its plain/secret flag in that scope. Only the project's owner
or an admin may write (another token gets 403).
A running service picks the change up on its next restart or redeploy.
The machine-wide scope is not reachable here: use ``set_secret`` with
``shared``.
| Name | Required | Description | Default |
|---|---|---|---|
| secret | No | Omit (or ``true``) for a write-only SECRET: no API, tool or dashboard ever returns the value again. ``false`` is the explicit PLAIN write: the project's owner or an admin can read the value back. When unsure, omit it. | |
| values | Yes | KEY → value pairs merged into the scope: a listed key is overwritten, an unlisted one kept. Key names are env-var identifiers (``[A-Za-z_][A-Za-z0-9_]*``); a value may be multi-line but may contain no NUL and no control character other than tab/newline/CR. An empty map is refused. | |
| project | Yes | Immutable prj_ ID or name of the project to modify. An unknown name creates it for your token; an unknown or retired ID is refused. | |
| service | No | Service inside the project (``web`` for a single-app project) to set the key for that service only; omit for the project scope, shared by every service of the project. On a key set in both, the service scope wins. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden and does so well: it discloses write-only vs plain behavior, transcript plaintext risk, return shape, precedence rules, owner/admin authorization with 403, and the fact that running services only pick up changes on restart or redeploy.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and return behavior, then moves into safety warnings and operational details. It is long, but most content is high-value for a mutation tool that handles credentials and has no annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the absence of annotations and output schema, the description is complete enough: it explains return values, permissions, precedence, secret handling, transcript risk, restart semantics, and the correct alternative for machine-wide scope.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is already 100%, so the schema documents each parameter in detail. The description adds useful meaning beyond the schema, especially around credential handling, secret-vs-plain semantics, and service/project precedence, though it does not discuss idempotency_key.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: set/merge a project's variables. It also distinguishes the write-only secret behavior and notes that only names are returned, so an agent can immediately understand the operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says when not to use the tool for credentials and directs the agent to ask the human to run a hidden-input CLI command instead. It also names an alternative for machine-wide scope: use set_secret with shared. This is unusually clear routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
stop_serviceC
Stop a service (desired_state → stopped).
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Service name or job id of an existing service (app, model or database); both resolve to the same row. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and only discloses the end state. It says nothing about whether the call blocks until the service is actually down, whether it is async and needs wait_for_service, whether in-flight traffic is drained, or what happens if the service is already stopped.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with zero waste and the state transition up front. It is perhaps too terse for a mutation tool, but that is a completeness issue rather than a structural one.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a state-changing operation with no annotations and no output schema, the description leaves out whether the stop is synchronous, whether a subsequent wait_for_service or get_service check is needed, and whether the action is reversible. An agent has to infer all of this from sibling names.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The 'name' and 'idempotency_key' semantics, including retry replay behavior, are fully documented in the schema and the description adds nothing beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (stop a service) plus the resulting state transition (desired_state → stopped), which is more than a restated name. It does not explicitly differentiate itself from siblings like restart_service or remove_service, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this versus restart_service (bounce without changing desired state) or remove_service (tear down entirely), nor on prerequisites such as the service being deployed. The intended use is only implied by the verb.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
system_diskA
Report disk usage: docker totals + named-volume/model/archive/backup trees.
Any authenticated read. Names and byte counts only (no absolute paths);
lists orphan images and orphan data dirs (reclaim them with
``system_gc``). Concurrent ``du`` walks run under a soft budget — an
overrun returns a partial body with a ``scan_timeout`` warning.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and does so well: it states the tool is an authenticated read, limits output to names and byte counts without absolute paths, discloses orphan listing behavior, and explains that concurrent du walks run under a soft budget and may return a partial body with a scan_timeout warning.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then adds compact behavioral notes. Every clause earns its place by covering scope, auth, output constraints, orphan handling, and timeout behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description still explains enough about return content and edge behavior for an agent to call the tool correctly. It covers what is reported, what is omitted, and how partial results are signaled.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so parameter semantics are largely moot. The description does not add parameter detail, but the empty schema is complete and the baseline for a no-parameter tool is 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: report disk usage. It also scopes the report to docker totals plus named-volume/model/archive/backup trees, and explicitly routes the reclaim action to the sibling system_gc, so an agent can distinguish this inspection tool from garbage collection.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes clear this is a read-only inspection call and explicitly names system_gc as the alternative when orphan images or data dirs need to be reclaimed. It does not give broader when-not guidance, but the primary alternative for the destructive follow-up is clearly identified.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
system_gcA
Garbage-collect orphan app images (admin-scoped, audited).
Reclaims ``nerdit-app/*`` image repos with no live workload row, verified
by re-listing so an in-use tag is reported skipped, never removed.
| Name | Required | Description | Default |
|---|---|---|---|
| dry_run | No | true = enumerate what would be reclaimed and remove nothing; false (the default) actually removes. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of running a second gc. Omit and a real run mints a fresh key per call, so each call acts; a dry run mints none and needs none. | |
| include_orphan_data | No | true also deletes service data directories with no live workload row — IRREVERSIBLE. false (the default) reclaims orphan images only. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses admin scoping, auditing, the exact namespace targeted, and the safety mechanism (re-listing verification so in-use tags are reported skipped, never removed). It does not cover reversibility of the base operation or what the result looks like, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences: identity and scope first, safety behavior second. Zero filler and nothing that repeats the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-param tool with a fully documented schema, no output schema, and no annotations, this covers purpose, scope, and the key safety invariant. It would be complete with a brief note on whether the run reports which repos were reclaimed or skipped.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so dry_run, idempotency_key, and include_orphan_data are all fully documented in the schema; baseline is 3. The description adds mechanism context (verification re-listing, skip-not-remove) but does not itself explain any parameter's effect.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (garbage-collect) and resource (orphan app images) plus the exact namespace it operates on (nerdit-app/*). It clearly distinguishes itself from the rest of the cluster/service-management siblings, though it does not explicitly contrast with the nearest adjacent tool (system_disk).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The condition for use is implied — orphan image repos with no live workload row — and admin scoping is noted, but there is no explicit 'use this when X, not Y' guidance and no prerequisite/permission statement beyond the parenthetical. Adequate but leaves the agent to infer when to reach for it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_serviceA
Use when: a deploy is in flight and you need its real outcome.
Blocks until the service converges (healthy) or fails, then returns
``{outcome: converged|failed|timeout|superseded, ...}`` — always, never
raising on a timeout. After ``stop_service``, ``converged`` means the
service is actually stopped.
On ``outcome: failed`` the response also carries ``diagnosis`` — the
FULL ``diagnose_service`` bundle (``remediation.code`` + ``detail``,
crash forensics, health probe, binding readiness and a bounded log
tail), folded in so a failure needs no second call. Branch on
``diagnosis.remediation.code``. It is ``null`` on every non-failed
outcome, and ``null`` on a failure your token is not owner-or-admin for
(the bundle carries app log lines) — in that case call
``diagnose_service`` yourself with a token that owns the app.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Service name or job id of an existing service (app, model or database); both resolve to the same row. | |
| timeout | No | Seconds to block before returning ``outcome: timeout``. Default 60; floored at 1 here and capped at 300 by the daemon. | |
| version | No | Deploy generation to converge on — the ``last_deploy.version`` from a ``deploy``/``deploy_git``/``deploy_app``/``deploy_template`` 201. Omit and the generation recorded on the row when the call starts is used, so a redeploy that landed between your 201 and this call is reported as ``converged`` as if it were yours. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully carries the behavioral burden. It discloses blocking behavior, timeout handling without raising, the possible outcome values, the presence and shape of diagnosis on failure, and the important authorization case where diagnosis is null.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the use case and outcome shape, and each paragraph serves a clear purpose. It is somewhat dense with parenthetical detail, but the complexity of the tool justifies most of the length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that there is no output schema and no annotations, the description supplies the essential return contract and failure semantics. It covers the key runtime behavior an agent needs to invoke and branch on the result correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema description coverage is 100%, so the parameters are already fully documented in the schema, including timeout defaults/caps and version semantics. The description does not add meaningful parameter guidance beyond that, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: it blocks until a service converges or fails, then returns a structured outcome. It clearly distinguishes the tool from related siblings like diagnose_service by explaining that failure diagnosis is folded into this call and only falls back to diagnose_service when authorization prevents it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit triggering condition: use when a deploy is in flight and you need its real outcome. It also clarifies semantics after stop_service and tells the agent exactly when to call diagnose_service instead, including the authorization condition that requires it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
write_app_filesA
Write files into an app's server-side workspace, then deploy it.
The two-step idiom for building an app from this conversation:
``write_app_files`` (as many batches as you like) then ``deploy_app``.
The workspace survives the deploy and IS the working copy, so editing is
"write the one changed file → ``deploy_app`` again".
One batch is all-or-nothing: an invalid entry rejects the whole request
and nothing is written. Binary content is refused — deploy binaries from
a repo with ``deploy_git``; assets normally come from the build
(npm/pip). A secret belongs in ``set_secret``, which injects it at launch
without it ever living in a file. WARNING: file contents you pass here
transit this agent's transcript in plaintext; never write secrets into
app files.
SANDBOX: by DEFAULT containers run with all Linux capabilities dropped
(``cap_drop=["ALL"]``) and no-new-privileges — both are operator settings
(``[containers].drop_all_caps`` / ``[containers].no_new_privileges``), so
read the live profile in ``capabilities.sandbox`` rather than assuming: an
operator may have relaxed it. Under that default, an image whose entrypoint
does root work — ``chown``/``chmod`` of its own runtime dirs, dropping
privileges via ``setuid``/``setgid``, writing ``/var/run`` — dies before
your app ever starts. Stock ``nginx`` is the classic trap. Use a non-root
image and a non-root ``USER`` that owns the files it writes: for a static
site, ``nginxinc/nginx-unprivileged`` (listens on **8080**, so set
``port=8080``) or any tiny static server. A crash from this reports
remediation code ``image_needs_privileges`` in ``diagnose_service``. PORT
CONTRACT: the container MUST listen on the declared ``port`` (the tool
argument, else ``nerdit.toml`` ``[deploy].port``, else **8000**) — that is
the only port the daemon publishes and health-checks, so listening anywhere
else fails the health probe with a healthy-looking container. A port below
1024 is NOT the reason a root entrypoint is needed: every container runs on
the docker bridge in its own network namespace (never host networking),
where Docker sets ``net.ipv4.ip_unprivileged_port_start=0``, so binding 80
needs no capability and no root — the chown/setuid work does.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Workspace name, a DNS label (lowercase a-z0-9 and ``-``, 1-63 chars). A new name creates the workspace; an existing one is edited in place. It is also the app name ``deploy_app`` deploys it under. | |
| files | Yes | Workspace-relative path -> that file's full UTF-8 text; a write replaces the file whole. Paths are relative with no ``..``; ``.git``, ``node_modules``, ``__pycache__``, ``.venv``, ``data/`` and ``*.pyc`` are refused, and ``.env`` / ``.env.*`` by name. Text only (NUL or non-UTF-8 is refused). Caps: 256 KiB per file, 10 MiB and 500 files per workspace. | |
| delete | No | Workspace-relative paths to remove, applied with the writes in the same all-or-nothing batch. Omit (null) to delete nothing; a path that does not exist is a no-op; a path may not be in both ``files`` and ``delete``. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: all-or-nothing batch semantics, binary refusal, the plaintext-transcript warning for file contents, default sandbox capability drops with the image_needs_privileges remediation code, and the port contract with its precedence chain. These are non-obvious failure modes an agent would otherwise hit blind.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core idiom before the caveats, and the WARNING/SANDBOX/PORT CONTRACT labels make it scannable. It is long, and the port-below-1024 aside is more explanation than an agent needs to select the tool, but nearly every sentence carries actionable content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A mutation tool with zero annotation coverage and no output schema would normally be a big gap, but the description supplies batch atomicity, size/path constraints context, secret-handling policy, sandbox failure modes, and port requirements. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so name, files, delete, and idempotency_key are already fully documented. The description adds only the port precedence rule (tool argument → nerdit.toml → 8000), which is useful but belongs to deploy_app rather than this schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Write files into an app's server-side workspace, then deploy it') and immediately differentiates itself from siblings: deploy_git for binaries, set_secret for secrets, deploy_app as the follow-up step. An agent can place this tool precisely among the deploy/serve/apply family without opening another schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit two-step idiom (write_app_files in batches, then deploy_app) and the iterative editing pattern ('write the one changed file → deploy_app again'). It also names the alternative tool for each excluded case: deploy_git for binary content, set_secret for credentials, build tooling for assets.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
write_project_filesA
Write a project's source tree (its nerdit.toml included), then apply_project.
Exactly ``write_app_files`` on the workspace named after the project:
same all-or-nothing batch, same text-only rule, same caps, and
``list_app_files`` / ``read_app_file`` read it back under the project
name. One tree holds EVERY service; a service built from a subfolder
says so with ``build_settings.subdir``. The root ``nerdit.toml`` is the
declaration::
[project]
name = "asso"
[services.web]
port = 3000
[services.api]
port = 8000
build_settings = { subdir = "apps/api" }
[vars]
required = ["API_KEY"]
``[services.<name>]`` takes the ``[deploy]`` keys except ``name``: the
service ``web`` is served under the project name (``asso``), any other
under ``<service>--<project>`` (``api--asso``), and that label is the
name every other tool takes. ``[ai.*]`` / ``[db.*]`` bindings stay
top-level tables shared by every service; a declaration cannot create
a database (``create_database`` first, then bind it). WARNING: file
contents you pass here transit this agent's transcript in plaintext;
never write secrets into project files.
| Name | Required | Description | Default |
|---|---|---|---|
| files | Yes | Workspace-relative path -> that file's full UTF-8 text; a write replaces the file whole. Paths are relative with no ``..``; ``.git``, ``node_modules``, ``__pycache__``, ``.venv``, ``data/`` and ``*.pyc`` are refused, and ``.env`` / ``.env.*`` by name. Text only (NUL or non-UTF-8 is refused). Caps: 256 KiB per file, 10 MiB and 500 files per workspace. | |
| delete | No | Workspace-relative paths to remove, applied with the writes in the same all-or-nothing batch. Omit (null) to delete nothing; a path that does not exist is a no-op; a path may not be in both ``files`` and ``delete``. | |
| project | Yes | Project name: the ONE source tree of the project, a workspace of the same name. A new name creates the workspace; an existing one is edited in place. It must equal ``[project].name`` in the tree's ``nerdit.toml``. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden and does so thoroughly: it discloses the all-or-nothing batch, text-only rule, caps, the key warning that file contents transit the agent transcript in plaintext (secrets risk), and that the root nerdit.toml is the declaration. It also explains service naming rules and how bindings work, which are behavioral traits not captured by the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and then provides a dense but well-organized block of details, including a concrete TOML example. It is longer than typical, but the length is justified by the complexity; some sentences (e.g., restating the write_app_files equivalence) could be trimmed without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex, multi-parameter mutation tool with no annotations and no output schema, the description is nearly complete: it covers purpose, sequencing, file rules, TOML format, service naming, and a critical security warning. It does not cover expected return values or error semantics, but with no output schema declared, that is a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns a 4 by adding meaning beyond the schema: the files parameter must include the tree's nerdit.toml, and the project name must equal [project].name. It also explains the TOML structure and service naming conventions that govern the contents of those parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Write a project's source tree') and explicitly distinguishes itself from the sibling write_app_files ('Exactly write_app_files on the workspace named after the project'). The mention of nerdit.toml and apply_project makes the scope unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear sequencing guidance: write the tree, then apply_project; also notes that a declaration cannot create a database and that create_database must come first. It does not explicitly say when not to use this tool versus write_app_files, but the equivalence statement effectively routes the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
67 tool updates
v0.1.0- First observed
add_domain - First observed
add_hook - First observed
apply_config - First observed
apply_project - First observed
capabilities - First observed
cluster_stats - First observed
create_database - First observed
create_project - First observed
delete_project - First observed
deploy - First observed
deploy_app - First observed
deploy_git - First observed
deploy_template - First observed
diagnose_project - First observed
diagnose_service - First observed
doctor - First observed
dump_database - First observed
get_ai_usage - First observed
get_app_config - First observed
get_audit - First observed
get_config - First observed
get_events - First observed
get_project - First observed
get_service - First observed
list_ai_provider_models - First observed
list_ai_routes - First observed
list_app_files - First observed
list_app_templates - First observed
list_database_dumps - First observed
list_databases - First observed
list_gpus - First observed
list_hooks - First observed
list_models - First observed
list_projects - First observed
list_routes - First observed
list_secret_names - First observed
list_services - First observed
project_logs - First observed
proxy_status - First observed
read_app_file - First observed
redeploy_service - First observed
remove_ai_route - First observed
remove_domain - First observed
remove_hook - First observed
remove_secret - First observed
remove_service - First observed
resolve_variables - First observed
restart_daemon - First observed
restart_service - First observed
run_command - First observed
serve - First observed
serve_model - First observed
service_logs - First observed
service_stats - First observed
set_ai_route - First observed
set_app_config - First observed
set_config - First observed
set_secret - First observed
set_variable - First observed
share_service - First observed
stop_service - First observed
system_disk - First observed
system_gc - First observed
unshare_service - First observed
wait_for_service - First observed
write_app_files - First observed
write_project_files
TDQS
Scored across 67 tools
The descriptions work hard to separate tools ('Distinct from deploy...', 'Use this instead of deploy_git when...'), but six deploy-family verbs (deploy, deploy_git, deploy_app, deploy_template, redeploy_service, apply_project) plus paired log/diagnose tools (service_logs vs project_logs, diagnose_service vs diagnose_project) force an agent to read a paragraph to pick correctly. Resource-oriented lists (list_services/list_models/list_databases/list_projects) are cleanly distinct, but the parallel project-scoped vs service-scoped duplicates create real hesitation.
The dominant pattern is snake_case verb_noun, but it breaks in several places: bare verbs/nouns (deploy, serve, doctor, capabilities), noun-first reads (service_logs, project_logs, system_disk, system_gc), and mismatched creation/deletion verbs across similar entities (create_database vs add_domain vs add_hook; remove_service vs delete_project). Still readable, but not a predictable grammar.
67 tools for a single-node PaaS is far past a well-scoped surface; several families (four deploy verbs, four config tools, three file tools, paired project/service variants) exist largely to model the same operations at different scopes. The result is a heavy, hard-to-navigate set where an agent can miss the right tool even though each one is documented.
Coverage of the domain is genuinely broad: deploys from folder/git/template/workspace, full service lifecycle, models, managed databases with dumps, projects, secrets/variables, AI routing, domains, hooks, config, audit, events, and system/health. Minor gaps are deliberate and documented (no restore tool, no volume-backup tool), though some of the breadth is bloat rather than coverage.
Maintenance
Related MCP Connectors
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
- UnifAPIOAuthcom.unifapi
Hosted MCP server for live public-data APIs and Skills for AI agents.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceUnified deployment dashboard MCP server for AI agents. 9 tools to manage services across Vercel, Render, Railway, and Fly.io — deploy status, logs, service listing, environment variables, rollback, and health checks from one endpoint. Free tier: 50 requests/IP/day.3MIT
- AlicenseAqualityDmaintenanceMCP server for Emergent.sh that enables AI assistants to create, monitor, and interact with full-stack app projects, including responding to agent questions and taking preview screenshots.111MIT
- AlicenseAqualityBmaintenanceMCP server for the Partiri Cloud PaaS platform. Enables AI agents to manage workspaces, projects, services, deployments, and metrics.231MIT
- AlicenseAqualityAmaintenanceOne MCP server to manage self-hosted Coolify instances: verify connectivity, discover servers, deploy applications, tail logs, diagnose incidents, and run emergency ops from any MCP client.1942 npmMIT