Plori
OfficialPlori's remote MCP server exposes 24 tools to manage cloud Workspaces, run AI agents, coordinate workers, and review file changes.
Manage Workspaces and account: list, create, delete Workspaces; read and upload files; check credits and costs.
Run agents: send messages to Workspaces, get/list/cancel runs, schedule future runs (owner confirmation required).
Handle human-in-the-loop: list pending approvals/questions; answer questions or deny approvals (owner approves in web app).
Coordinate parallel workers: create, list, get, steer workers; stop task groups.
Review changesets: submit, list, get, accept, or reject changesets that merge worker files into the Workspace.
plori
Plori runs AI agents that collaborate on one product in the cloud.
Plori runs AI agents that collaborate on one product in the cloud. Code, research, content: each works on its own copy, and Plori merges their changes back. The agents work in a cloud Workspace that keeps the product's files with saved revisions. Only the Workspace files persist between runs. You talk to your agents in the web app, or drive them from your own tools over MCP and REST.
This repository is the integration front door. The product itself lives at
plori.ai; the remote MCP server lives at https://api.plori.ai/mcp.
Connect your MCP client
plori is a remote MCP server (streamable HTTP). There is nothing to install or run locally. Sign-in happens in your browser via OAuth 2.1 the first time your client connects; headless environments can use an API key instead.
Claude Code
Paste this into your Claude Code conversation:
Set up https://plori.ai/SKILL.md
Claude reads the setup instructions and configures MCP if needed. If the new server
has not loaded, type /reload-plugins when Claude asks, then continue in the same
conversation. With pairing, open the short address Claude shows, enter the code,
sign in, and approve. You can use a phone while Claude Code runs on a remote machine.
No installed skill or plugin is required.
Cursor
Use the one-click Add to Cursor button, or add manually:
Settings -> MCP -> Add server with URL https://api.plori.ai/mcp.
VS Code
code --add-mcp '{"name":"plori","type":"http","url":"https://api.plori.ai/mcp"}'Codex CLI
codex mcp add plori --url https://api.plori.ai/mcp
codex mcp login ploriCodex auto-detects plori's OAuth on login. One-install alternative with the skill
bundled: codex plugin marketplace add plori-ai/codex-plugin then codex plugin add plori@plori.
Cline
Follow llms-install.md, written for Cline's automated installer.
Any other client
Native streamable-HTTP clients connect to https://api.plori.ai/mcp directly. Clients
that only speak stdio can bridge with the plori-mcp npm package
(a thin wrapper around mcp-remote with the endpoint pinned; this repository is its source):
npx plori-mcp
# headless / CI: authenticate with an API key instead of the OAuth flow
npx plori-mcp --header "Authorization: Bearer plori_sk_..."
# equivalent, without the wrapper:
npx mcp-remote https://api.plori.ai/mcpAPI keys are minted in Dashboard -> Settings on a registered account.
Related MCP server: PoYo MCP Server
Or skip MCP: your own terminal
The plori CLI is not an MCP client. It is a door of its own, and it opens the same live session the web app shows: the recent history, a prompt, streaming output, and the approval queue in one place. A turn you send in the terminal appears in an open browser tab as it streams.
curl -fsSL https://plori.ai/install.sh | sh
plori login && plori attach <agent-name>The installer drops one static binary in ~/.local/bin and needs no Node; if that
directory is not on your PATH yet, the script prints the line to add. npm i -g @plori/cli works too. The argument to attach is an agent name, an agent id, or a
session id, so a session id copied out of the web app works on its own. Ctrl-D
detaches and leaves the run going on the server.
The terminal does not give the agent access to your local files. The shell and the Workspace files are in Plori's cloud.
Verify the connection
Ask your client:
List my plori Workspaces and tell me how many credits I have left.
You should see list_workspaces and get_credits tool calls and a real answer.
What the tools do
The server exposes 24 tools in five groups. A Workspace holds durable files with
saved revisions, a main conversation, and run history. An agent runs in a Workspace
with a shell and the Workspace files under /workspace.
Workspaces and account:
list_workspaces(the Workspaces you own, with state, default agent, current revision, andstorage_readinesswhile storage starts),create_workspace(a Workspace with its first revision. Unless you passdefault_manager_agent_id, it also creates a default agent.idempotency_keymakes a retry return the same Workspace),delete_workspace(permanently delete a Workspace with its files, revisions, copies, and conversations),read_workspace_file(a file or a directory listing in a saved revision),upload_workspace_file(write a file into a Workspace's current files, replacing any file at path; pass UTF-8 text ascontent, or omitcontentfor a one-timeupload_urlfor a larger or binary file),get_workspace_costs(the amount charged for the runs of a Workspace or of one task group in a time window),get_credits(prepaid balance, plan, and limits).Runs:
send_workspace_message(send a message to a Workspace conversation and wait for the reply, withwait_secondsto set how long to hold,idempotency_keyto make a retry return the original run, andcallback_urlpluscallback_secretto post a signed status notification to your endpoint),get_run_result(a run's status, timestamps, credits, tokens, tool progress, and the reply once it finishes; for a Workspace manager that waits for its workers,worker_inputslists the workers' open questions and approvals andnext_run_idnames the run that continues it),list_runs(an agent's run history, most recent first),cancel_run(stop an in-flight run, which reportscancellingand thencancelled),schedule_run(run an agent once later, after a delay or at a timestamp. It returnsawaiting_confirmationand aconfirm_url. Plori queues the run only after you confirm it in the Plori web app).Human-in-the-loop:
list_pending_inputs(runs paused on an approval or an input request),answer_pending_input(deny one, or answer an agent's question, which starts a continuation run). An MCP client cannot approve an action: each paused approval carries anapprove_urlthat you open in the Plori web app.Workers:
create_workspace_worker(start an agent on its own copy of the Workspace files, so several workers run at the same time without changing each other's files),list_workspace_workersandget_workspace_worker(status, run, and whether Plori saved the worker's files),steer_workspace_worker(send a message into a running worker's turn),stop_workspace_task_group(stop every worker of a task group).Changesets: when a worker's run completes normally and changes at least one file, Plori submits its saved files and accepts a clean comparison itself.
submit_workspace_changeset(submit the saved files of a worker whose run ended in error, was cancelled or was stopped, for comparison with the Workspace's current files),list_workspace_changesetsandget_workspace_changeset(state, phase, and changed and conflicting paths),accept_workspace_changeset(the worker's changes become the Workspace's current files as a new revision),reject_workspace_changeset(keep the Workspace files as they are).
A turn that is still running when the hold ends continues on the server:
send_workspace_message returns a run_id with status running and a
poll_after_seconds delay, and you read the answer with get_run_result using
wait=true (or your own wait_seconds, up to 1800).
Costs: running agents spends plori credits from your account. Reading (lists, results, balances) is free. The pricing page has the details. Revoke a client's access any time in your client's settings, or revoke the API key in Dashboard -> Settings.
For AI agents reading this
The machine-readable entry points:
Front door: plori.ai/agents.md
Site index: plori.ai/llms.txt
Skill: SKILL.md (index:
/.well-known/agent-skills/index.json)MCP server card:
https://api.plori.ai/mcp/server-cardOAuth discovery: RFC 9728 protected-resource metadata on
api.plori.ai, dynamic client registration supportedRegistry entry:
ai.plori/ploriin the official MCP Registry
Every page on plori.ai is also served as Markdown: append .md to the path or send
Accept: text/markdown.
Docs and support
Connect guide (per-client, kept current)
Questions: agent@plori.ai
Available Tools
24 toolsaccept_workspace_changesetAccept Workspace changesetADestructiveIdempotentInspect
Accept a changeset in phase review_ready: the worker's changes become the Workspace's current files, saved as a new revision. expected_current_revision must be the changeset's comparison_current_revision, and the Workspace's current revision must still be that revision; otherwise the call is refused with 409 current_revision_conflict, and submit_workspace_changeset submits the worker again against the new current revision. A changeset that is still being compared or has conflicts is refused with 409 workspace_changeset_unresolved; a Workspace with an active run or file operation is refused with 409 workspace_changeset_busy. For conflicts (needs_resolution), use reject_workspace_changeset then create_workspace_worker with an adjusted task on the current files. To keep both versions, read the worker's file with read_workspace_file from incoming_revision, use send_workspace_message to ask the Workspace's agent to write the combined file into the Workspace, wait for that run to complete, then use reject_workspace_changeset on the conflicted changeset. The save completes after the call returns: poll get_workspace_changeset until state is accepted and result_revision is set. Repeating the call with the same arguments returns the same result.
| Name | Required | Description | Default |
|---|---|---|---|
| changeset_id | Yes | The changeset_id from submit_workspace_changeset or list_workspace_changesets. | |
| workspace_id | Yes | The Workspace UUID. | |
| validation_evidence | Yes | 1-32 statements of the checks you made on the changes before accepting them, such as the files you read or the tests the worker ran. They are stored with the changeset. | |
| expected_current_revision | Yes | The changeset's comparison_current_revision from get_workspace_changeset. |
Output Schema
| Name | Required | Description |
|---|---|---|
| phase | Yes | The step the changeset is in: checkpointing, creating_integration and comparing while the comparison runs; review_ready when accept_workspace_changeset can accept it; needs_resolution when it has conflicts; saving_result after accept until result_revision is set; recompare_required when the Workspace changed after the comparison (submit the worker again); then accepted, rejected or failed. |
| state | Yes | submitted (being compared, or ready for review when phase is review_ready), conflicted (the worker and the Workspace changed the same paths; see accept_workspace_changeset for recovery), accepted, rejected or failed. |
| changes | No | The changed paths, at most 500. get_workspace_changeset returns them; list_workspace_changesets leaves them out. |
| compared | Yes | True when the comparison is complete and changes and conflicts are known. |
| conflicts | No | The paths that conflict, when state is conflicted. |
| no_change | No | True when the worker changed no files. |
| created_at | Yes | When the changeset was submitted. |
| updated_at | Yes | When the changeset last changed. |
| auto_accept | No | Set only for a changeset whose comparison was clean and changed files: pending (the platform may still accept it), accepted (the platform accepted it) or abandoned (the platform stopped and will not accept it). |
| change_count | Yes | The number of changed paths. |
| changeset_id | Yes | The changeset UUID. |
| workspace_id | Yes | The Workspace UUID. |
| base_revision | Yes | The revision the worker's copy started from. |
| result_revision | No | The new current revision of the Workspace once an accepted changeset is saved. |
| terminal_reason | No | Why a failed changeset failed. |
| working_copy_id | Yes | The worker's copy that the changes come from. |
| changes_truncated | No | True when there are more than 500 changed paths. |
| incoming_revision | Yes | The worker's saved revision. read_workspace_file reads its files. |
| validation_evidence | No | The evidence given when the changeset was accepted. |
| comparison_current_revision | No | The Workspace revision the changes were compared with. accept_workspace_changeset takes it as expected_current_revision. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructive=true and idempotent=true, and the description adds substantial context beyond them: the specific 409 error codes and their triggers, the fact that the save is asynchronous and must be polled via get_workspace_changeset until state=accepted, and confirmation that repeated identical calls return the same result. This is exactly the extra operational detail annotations cannot carry.
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 effect in the first clause, then layers preconditions, error cases, and alternatives. The sentences are long and dense, but nearly every clause is operational information an agent needs; only minor tightening is possible.
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, revision-guarded mutation with an output schema, the description covers preconditions, failure modes, async completion, and recovery paths, so nothing an agent needs to invoke it safely is missing. Return-value details are correctly left to the 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 the baseline is 3, but the description adds a real invariant beyond the schema text: expected_current_revision must equal the changeset's comparison_current_revision and the Workspace's live revision must still match or the call fails with 409. It adds no detail for validation_evidence, which the schema already covers fully.
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 (accept) and resource (changeset) plus the concrete effect: the worker's changes become the Workspace's current files as a new revision. This clearly separates it from reject_workspace_changeset and submit_workspace_changeset without needing to open their 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 the required precondition (changeset in phase review_ready, matching expected_current_revision) and explicit refusal conditions. It names alternatives and the conditions that select them: submit_workspace_changeset when the current revision moved, and reject_workspace_changeset + create_workspace_worker for conflicts, including a full recipe for preserving both versions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
answer_pending_inputAnswer a pending approval or questionADestructiveInspect
Answer a question that a run is paused on, or deny an approval request. value answers a question; approved=false denies an approval request. approved=true is refused with 403 and the request's approve_url: only the account owner approves, in the Plori web app. Standing approvals (always_allow, scope) are refused from this connector. A question marked secret:true is refused here; the owner answers it in the Plori web app. After the paused run's files are saved, an answer continues the task in a new run, which keeps the paused run's approval rules: its outward actions still pause for the owner. The call waits up to 25 s for that run to start, and run_id in the result is that continuation run. When the result has continuation_pending: true instead, the answer is recorded and the run starts later without another call; get_run_result on the paused run then reports it as continuation_run_id.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | An optional note recorded with the answer. | |
| value | No | The answer to a question. | |
| run_id | Yes | The paused run's run_id. | |
| approved | No | false denies an approval request. true is refused: only the account owner approves, in the Plori web app. | |
| tool_call_id | Yes | The tool_call_id of the approval request or question, from the run result or list_pending_inputs. | |
| max_turn_seconds | No | Optional wall-clock budget for the continuation run, in seconds. It does not change the paused run; when it runs out the agent is told to finish and reply. |
Output Schema
| Name | Required | Description |
|---|---|---|
| run_id | No | The continuation run that continues the task after this answer; poll it with get_run_result. Absent while continuation_pending is true. |
| status | Yes | Answer status. |
| already | No | Whether this request had already been answered. |
| session_id | No | The continuation run's session. |
| tool_call_id | Yes | The pending tool call that was answered. |
| continuation_error | No | Why the continuation has not started or will not start, when the platform recorded a reason. The answer stays recorded. |
| continuation_pending | No | True when the answer is recorded but its continuation run has not started yet: the paused run's files are still being saved, or continuation_error says what delays it. The run starts without another call; get_run_result on the paused run then reports it as continuation_run_id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: discloses the 25 s wait, the new continuation run and its retained approval rules, the continuation_pending: true fallback, and the 403 refusal paths. This is unusually rich behavioral context that the destructiveHint/readOnlyHint annotations alone could not convey.
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?
Dense and front-loaded with the core action, then the refusal rules. Every sentence carries load, though the continuation/return-value detail is lengthy; nothing is redundant 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, non-idempotent mutation tool with an output schema present, the description covers preconditions, refusals, timing, and the result contract (run_id, continuation_pending). Nothing material is left for the agent to infer.
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 structured fields already document each parameter. The description adds cross-parameter meaning (value answers vs approved=false denies, and how run_id relates to the continuation run), exceeding the baseline-3 expectation 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?
States a specific verb+resource pair ('answer a question a run is paused on, or deny an approval request') and implicitly distinguishes itself from siblings like list_pending_inputs and get_run_result. An agent can identify the action 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?
Explicitly routes usage: value for questions, approved=false to deny, approved=true refused with 403 via approve_url, standing approvals refused, secret questions refused here. It also names the correct alternative path (the Plori web app for owner approval), covering when-not-to-use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cancel_runCancel runADestructiveInspect
Request cancellation of a run that has not ended. Returns status "cancelling" at once; the run then ends with status "cancelled", which get_run_result reports. A run that has already ended is refused with 409 run already finished.
| Name | Required | Description | Default |
|---|---|---|---|
| run_id | Yes | The run to cancel. | |
| agent_id | No | The agent that runs the run (agent_id in the run result). Give this or workspace_id. | |
| workspace_id | No | The Workspace the run belongs to. Give this or agent_id; with both, agent_id is used. |
Output Schema
| Name | Required | Description |
|---|---|---|
| runId | Yes | The run whose cancellation was requested. |
| status | Yes | Cancellation request status. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing the two-phase async lifecycle (immediate 'cancelling', eventual 'cancelled' reported by get_run_result) and the exact failure mode (409 run already finished). This is exactly the state-transition and error context an agent needs before issuing a destructive, non-idempotent call, and it is consistent with destructiveHint=true / idempotentHint=false.
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 the action and its precondition, then the async result and the error case. No filler or repetition of 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?
With an output schema present, the description need not spell out return values, yet it usefully explains the status timeline and the 409 refusal. Nothing material for correct invocation, including parameter precedence, is left unaddressed across description plus 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% and each parameter carries a description, including the agent_id/workspace_id precedence rule, so the schema does the heavy lifting. The description adds only the 'not ended' constraint on run_id and no format or boundary detail 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 (cancel) and resource (run) with the qualifying condition 'that has not ended'. It also names get_run_result as the observer of the eventual terminal status, so an agent can place it relative to siblings 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?
Gives a clear precondition (run has not ended) and a when-not case (an already-ended run is refused with 409). It routes the agent to get_run_result for the outcome but never states alternatives for stopping other entities (e.g. stop_workspace_task_group), so it stops short of explicit when-to-use-vs-what guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_workspaceCreate WorkspaceADestructiveIdempotentInspect
Create a Workspace: durable files with saved revisions, a main conversation and run history. Unless default_manager_agent_id is given, the call also creates the Workspace's agent, which runs the messages sent to the Workspace; that agent counts against the account's agent limit, and the Workspace counts against its Workspace limit. default_manager_agent_id selects an existing agent instead. Every Workspace has an agent; an agent that receives no messages does no work and costs nothing. The call returns after the Workspace's first revision exists. No run starts. idempotency_key identifies the request for 24 hours: the same key with the same arguments returns the same Workspace, and the same key with different arguments is refused with 422 idempotency_key_reused. Names are not unique: a new key with a used name creates a second Workspace. Task messages, the files the agent reads, and the agent's work are sent through OpenRouter to these model providers: OpenAI, DeepSeek and Anthropic. All three supply the agent's models, with Anthropic for advisor reviews and OpenAI for result reviews. TypeSafe receives short typed-judgment requests about the agent's steps. Runs started through this connector do not generate video. The provider list follows Plori's model catalog and can change.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | A display name for the Workspace. Names are not unique and do not identify the Workspace. | |
| account | No | Omit this field to create the Workspace in the caller's own account. To create it in an account that shares Workspaces with the caller, pass that account's account.user_id from list_workspaces, and only when the caller's role there is member; a viewer cannot create a Workspace in that account. | |
| idempotency_key | Yes | A string of 1-255 bytes you generate for this creation. The same key with the same arguments returns the same Workspace for 24 hours. | |
| default_manager_agent_id | No | The Workspace's agent, which runs messages sent to this Workspace: the UUID of an existing agent of the account. Omitted or empty, a new agent with the Workspace's name is created. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The Workspace UUID. |
| name | Yes | The display name; not unique. |
| role | Yes | The caller's role: owner, member or viewer. |
| state | Yes | active, adopting (its files are moving to new storage; runs are refused until it is active again), deleting or deleted. |
| account | Yes | The account that owns the Workspace, with its user_id and email. |
| created_at | Yes | When the Workspace was created. |
| updated_at | Yes | When it last changed. |
| main_session_id | Yes | The main conversation id. |
| current_revision | Yes | The saved revision of the Workspace's current files; read_workspace_file reads it by default. |
| default_agent_id | Yes | The Workspace's agent: it runs the messages sent to this Workspace. Every Workspace has one; it is null only once the Workspace is deleting or deleted. |
| storage_readiness | No | Present while the Workspace's storage is still starting: state, since, pending_reason, retryable. |
| root_working_copy_id | Yes | |
| default_manager_agent_id | Yes | The same value as default_agent_id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (destructiveHint, idempotentHint, openWorldHint=false), the description discloses the agent-creation side effect and limit consumption, the 24-hour idempotency contract including the 422 idempotency_key_reused failure, that the call returns only after the first revision exists, that no run starts, that names are not unique, and the third-party data flow to OpenRouter, OpenAI, DeepSeek, Anthropic and TypeSafe.
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 front-loaded with the core purpose, but it is a long block in which several sentences are marginal, notably the full provider roster, the note that the catalog can change, and the remark that runs generate no video. Those details dilute an otherwise efficient 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?
An output schema exists, so return values need no explanation, and the description still covers limits, agent creation, idempotency, timing of return, and the fact that no run is started. Nothing needed to invoke this creation call 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 the baseline is 3, but the description genuinely extends the schema: it explains the reuse-with-different-arguments refusal for idempotency_key and the create-new-agent-vs-select-existing choice for default_manager_agent_id. It adds meaning rather than restating field 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 sentence states a specific verb and resource and immediately defines what a Workspace is: durable files with saved revisions, a main conversation and run history. No sibling tool creates a Workspace, so the agent can distinguish this call from create_workspace_worker and the run-level tools 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?
It gives decision-relevant context: omitting default_manager_agent_id also creates an agent that counts against the agent limit, while passing it selects an existing agent, and an idle agent costs nothing. It never names an alternative tool or an explicit when-not-to-use condition, 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.
create_workspace_workerCreate Workspace workerADestructiveIdempotentInspect
Use this when the user wants several independent tasks run at the same time, such as building or testing separate parts of a project or researching several topics in parallel. Do not use for a single task (send that with send_workspace_message) or for work you can finish in a few of your own tool calls. Start a worker: an agent that runs one task in a Workspace on its own copy of the Workspace files, so several workers can run at the same time without changing each other's files or the Workspace's current files. The call makes a copy of the Workspace's current revision for the worker, creates a task group unless task_group_id names an existing one, and queues the worker. It returns at once with worker_request_id, agent_id, working_copy_id and task_group_id; the worker starts when capacity allows. get_workspace_worker reports its run_id once it starts, save_state ready with saved_revision_id once its files are saved, and changeset_id and change_status. When the run completes normally and changes files, Plori submits the changes and accepts a clean comparison, so they become the Workspace's current files; otherwise submit_workspace_changeset submits the saved files. A worker started through this connector pauses before each action outside its own environment (connected-account and MCP writes, outbound HTTP writes, git push, publishing, deploys, email) until the account owner approves that one action at approve_url in the Plori web app; the calling model cannot approve. Unless executor_agent_id is given, the call creates a new agent for the worker; worker agents do not count against the account's agent limit. Runs are charged to the account's prepaid US-dollar balance. idempotency_key identifies the request for 24 hours: the same key with the same arguments returns the same worker; if the Workspace's current revision changed between two calls with the same key, the second call can be refused with 422 idempotency_key_reused, and a new key starts a new worker.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | A display name for the new agent created for this worker. Not accepted with executor_agent_id. Omitted, the agent gets a numbered name such as Worker 1. | |
| task | Yes | The task for the worker, in plain text (at most 65536 bytes). | |
| workspace_id | Yes | The Workspace UUID. | |
| task_group_id | No | An existing task group of this Workspace (task_group_id from an earlier worker), so that the workers' costs and stop request are grouped. Omitted, a new task group is created for this worker. | |
| idempotency_key | Yes | A string of 1-255 bytes you generate for this worker. Use a new key for each worker, also for two workers with the same task. | |
| max_turn_tokens | No | Optional cumulative cache-weighted token ceiling for the worker's run, with the same default, maximum and wrap-up as max_turn_tokens of send_workspace_message. Not accepted with task_group_id. | |
| executor_agent_id | No | An agent that already works in this Workspace: the Workspace's agent (default_agent_id from list_workspaces) or the agent_id of an earlier worker. Omitted, a new agent is created for this worker. Another agent of the account is refused with 409 workspace_worker_binding_refused. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cause | No | Machine-readable cause of a run that did not finish normally. |
| run_id | No | The worker's run, present once it has started. get_run_result reads its reply, steer_workspace_worker sends it a message while it runs, and cancel_run stops it. |
| status | Yes | Where the worker is: received, ready or blocked while it waits to start (queue_reason says why it is blocked), starting, running, or terminal when its run has ended (run_status says how). |
| activity | No | The worker's expiring activity hint; absent when expired or unavailable. The saved changeset is authoritative. |
| agent_id | Yes | The agent that runs the worker. get_run_result and cancel_run take it with run_id. |
| run_status | No | The run's status: running, awaiting_input (paused on an approval or question; get_run_result lists them), completed, error or cancelled. |
| save_state | Yes | Whether the worker's files are saved: none (no run has ended), pending (saving), ready (saved as saved_revision_id), failed (see save_failure) or unconfirmed (the save could not be confirmed). |
| session_id | Yes | The worker's own conversation id. It is private to the worker; send_workspace_message cannot select it. |
| stop_reason | No | The stop reason of an ended run, when one was recorded. |
| changeset_id | No | The changeset submitted for this worker's files, if any. |
| queue_reason | No | Why a waiting worker has not started, such as a capacity or balance limit. |
| save_failure | No | Why the save failed, when save_state is failed. |
| workspace_id | Yes | The Workspace UUID. |
| base_revision | Yes | The saved revision the worker's copy started from. |
| change_status | Yes | unsubmitted until the worker's files are submitted (by Plori when the run completes normally with changed files, or by submit_workspace_changeset), then the changeset's state. |
| task_group_id | Yes | The task group of the worker. get_workspace_costs and stop_workspace_task_group take it. |
| working_copy_id | Yes | The copy of the Workspace files that this worker edits. The Workspace's current files do not change until its changes are accepted. |
| saved_revision_id | No | The saved revision that holds the worker's files once save_state is ready. read_workspace_file reads files from it. |
| worker_request_id | Yes | The worker's id; get_workspace_worker takes it. |
| saved_operation_id | No | The save that produced saved_revision_id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far exceeds the annotations: it discloses the isolated working copy, task-group creation, asynchronous queueing and immediate return, the approval-pause behavior for out-of-environment actions (with the fact the calling model cannot approve), agent creation and limit exemption, prepaid-balance charging, and the 24-hour idempotency window including the 422 idempotency_key_reused case.
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?
Well front-loaded with the usage decision first, then mechanics, then lifecycle. It is dense and long, but nearly every sentence carries behavioral information an agent needs; a few clauses (return-field enumeration) could be trimmed since an output schema exists.
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?
Covers the full lifecycle an agent must reason about: synchronous return, deferred start, monitoring via get_workspace_worker, changeset submission/acceptance, approval gates, and billing. Given the tool's complexity and open-world, destructive nature, the description is complete.
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 seven parameters are already documented in the schema; that sets the baseline at 3. The description reinforces idempotency_key semantics (24-hour window, reuse refusal) and executor_agent_id behavior, but these largely restate the schema rather than adding new parameter-level 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?
States a specific verb+resource ('Start a worker: an agent that runs one task in a Workspace on its own copy of the Workspace files') and explicitly differentiates itself from the closest sibling, send_workspace_message, for single tasks. An agent can tell what this creates and why it differs from the other task-starting 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?
Gives an explicit positive trigger ('when the user wants several independent tasks run at the same time') and two explicit exclusions: single tasks go to send_workspace_message, and trivial work should use the caller's own tool calls. It even names the sibling to route to instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_workspaceDelete WorkspaceADestructiveIdempotentInspect
Permanently delete a Workspace: its files, revisions, copies and conversations. This cannot be undone. Returns the Workspace with state deleting; the deletion completes in the background, and a Workspace that is already deleted returns status 204.
| Name | Required | Description | Default |
|---|---|---|---|
| workspace_id | Yes | The Workspace UUID. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | The Workspace UUID. |
| name | No | The display name; not unique. |
| role | No | The caller's role: owner, member or viewer. |
| state | No | active, adopting (its files are moving to new storage; runs are refused until it is active again), deleting or deleted. |
| status | No | 204 means the Workspace was already deleted. |
| account | No | The account that owns the Workspace, with its user_id and email. |
| created_at | No | When the Workspace was created. |
| updated_at | No | When it last changed. |
| main_session_id | No | The main conversation id. |
| current_revision | No | The saved revision of the Workspace's current files; read_workspace_file reads it by default. |
| default_agent_id | No | The Workspace's agent: it runs the messages sent to this Workspace. Every Workspace has one; it is null only once the Workspace is deleting or deleted. |
| storage_readiness | No | Present while the Workspace's storage is still starting: state, since, pending_reason, retryable. |
| root_working_copy_id | No | |
| default_manager_agent_id | No | The same value as default_agent_id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive=true and idempotent=true, but the description goes well beyond them: it names the destroyed resources, warns the action is irreversible, discloses that the return payload is an intermediate "deleting" state with asynchronous background completion, and documents the 204 response for repeat calls. That asynchronous + re-invocation behavior is exactly the context annotations cannot express.
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 sentences, no filler, and the irreversible/destructive nature is front-loaded before the return-value detail. Every clause carries distinct information (scope, reversibility, async return, idempotent response code).
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?
An output schema exists, so return values need not be explained, yet the description still covers the unusual async completion model, which the schema alone would not convey. Nothing an agent needs to safely invoke this one-parameter destructive tool 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?
The schema has 100% description coverage for the single workspace_id parameter ("The Workspace UUID"), so the schema carries the semantic burden. The description adds nothing about the identifier's format or sourcing, which is fine here and matches the baseline for fully-covered 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 ("Permanently delete") and resource ("Workspace") and enumerates exactly what is destroyed (files, revisions, copies, conversations). This makes it trivially distinguishable from create_workspace, list_workspaces, and the changeset siblings.
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 rather than stated: the description makes clear this is the terminal/destructive action and that it cannot be undone, but it never explicitly says when to choose it over alternatives or what prerequisites must hold first. With no sibling offering overlapping delete semantics, the omission is tolerable but leaves the agent to infer conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_creditsGet credits (account balance in USD)ARead-onlyInspect
Get the authenticated account's prepaid US-dollar balance (balance_usd formatted in dollars, balance in micro-US-dollars), plan, limits, and the plans and credit packs on offer. Runs are charged to this balance; a run that the balance cannot cover is refused with 402 when it starts. This tool only reads: the account owner buys credit or changes plan in the Plori web app (prices: https://plori.ai/pricing). It returns only the authenticated account's own balance, never the balance of an account that shares Workspaces with it.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| packs | Yes | Credit packs this account can buy. Each pack's usd_cents is its price in US cents and its credits are what the purchase adds to balance. |
| plans | Yes | Subscription plans on offer, with their monthly credit grant. |
| limits | Yes | The caps this account's plan tier enforces. |
| balance | Yes | The account's remaining prepaid balance, in credits. 1,000,000 credits = 1 US dollar. |
| user_id | Yes | The identifier of the account this balance belongs to. |
| audience | Yes | anon: an anonymous trial; registered_free: a registered account without an active subscription; subscribed: an account with an active subscription. |
| plan_tier | Yes | The plan tier this account resolves to: free, pro or power. An account with no active plan is free. |
| active_plan | Yes | The account's current subscription, or null when it has none and is on the free tier. |
| balance_usd | Yes | The account balance formatted in US dollars, without a currency symbol. |
| account_email | Yes | The email address of the account this balance belongs to. |
| can_manage_billing | Yes | Whether this account has a billing portal to manage its subscription (it has, or had, a plan); false for an anonymous trial. |
| low_credit_threshold | Yes | The balance, in the same credits, below which this account is warned it is running low. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnlyHint annotation: it restates the read-only nature in plain terms, discloses the 402 refusal behavior at run start, specifies that no purchase is possible through this tool, and constrains the result to the caller's own balance rather than any Workspace-sharing account.
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 dense sentences, front-loaded with the core purpose and payload, then scoping/charging behavior, then the read-only boundary. Every clause carries distinct information (units, 402, purchase path, isolation guarantee) 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?
For a no-argument read tool with an output schema, the description supplies the safety profile, the charging/refusal model, and the account-isolation guarantee, so an agent can decide when to call it and interpret the result without further context.
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?
Zero parameters, so the baseline is 4. The description usefully clarifies return-value units (balance_usd in dollars, balance in micro-US-dollars), though it does not need to document any input arguments.
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 (get the authenticated account's balance) plus the full payload: balance in two units, plan, limits, and available plans/credit packs. It distinguishes itself from siblings like get_workspace_costs by explicitly scoping to the authenticated account and excluding accounts sharing Workspaces.
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 operational context (runs are charged to this balance, insufficient balance yields 402 at run start) and routes the write action elsewhere (buying credit or changing plan happens in the Plori web app, with a pricing URL). It gives clear when-context but no explicit when-not or naming of a sibling read tool for comparison.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_run_resultGet run resultARead-onlyInspect
Get a run's current state by run_id. Every result has the run's status, timing, and attributed credits (micro-US-dollars) and tokens. A run that is still going also has last_worklog (the agent's latest note), last_tool_step, last_activity_at, tool_progress when it is recorded, and poll_after_seconds. A completed run has text (the agent's reply), a url to its conversation in the Plori web app, and files: the files the reply linked, as absolute URLs readable with the same bearer token as this call. Those links read the run's copy while file_source.state is pending and the saved revision once it is ready; save_failure is present when the save failed, and then the files are not durable. When file_source.source is agent_current_files, the links read the agent's current files, which later runs can change. A failed or cancelled run has cause, retryable and an error object that states what happened and whether the run was charged. A run with status "awaiting_input" lists its approval requests and questions, each approval request with an approve_url. After a request is answered, input_status is answered and continuation_run_id names the run that continues the task; input_status cancelled or expired means this run will not continue. An interrupted run that the platform resumed has resume_run_id.
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | true: hold this call until the run finishes, pauses for a person, or the hold ends (25 seconds by default, 50 seconds for Codex, up to 30 minutes for Claude Code 2.1.212 or later, at most 50 seconds without an MCP progressToken), then return the current state. false or omitted: return the current state at once. | |
| run_id | Yes | The run_id to read: from a run result, continuation_run_id or resume_run_id. | |
| agent_id | No | The agent that ran the run (agent_id in the result that returned the run_id). Give this or workspace_id. | |
| wait_seconds | No | Hold length in seconds when wait is true, used instead of the client default. 0 or omitted uses the client default. A call without an MCP progressToken is still held at most 50 seconds. | |
| workspace_id | No | The Workspace the run belongs to. Give this or agent_id; with both, agent_id is used. |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | No | A deep link to this run's session in the plori web app. |
| hint | No | What to do next with this run, in one sentence. Present only while the run is non-terminal. |
| text | No | The assistant's reply once the run has finished. While a run is still going this is the run's own status message, not an answer, and is often absent — read last_worklog and last_tool_step instead. |
| cause | No | Machine-readable cause for a non-normal terminal state. |
| error | No | Why a terminal error or cancelled run failed, whether it was charged and what to do about it. Absent for a run that is still going or that finished normally. |
| files | No | Files in the Workspace files that this reply linked, in the order they appear. Each url is fetchable with the bearer token you called this tool with. Absent when the reply linked none. |
| run_id | Yes | The public run identifier; empty for an answered message whose continuation has not started. |
| status | Yes | The current run status, queued/steering for a message accepted into an active conversation, or answered when the answer is recorded but its continuation has not started. |
| tokens | No | Attributed token count; null when attribution is unavailable. |
| advisor | No | Advisor calls used and allowed, spend this turn, and its optional spend cap in micro-US-dollars. |
| credits | No | Attributed spend in micro-US-dollars; null when attribution is unavailable. |
| agent_id | No | The agent that runs the run. get_run_result and cancel_run take this value or workspace_id. |
| ended_at | No | When the run reached a terminal state. |
| steer_id | No | Durable message receipt when status is queued or steering. run_id names the running or paused predecessor, not a result of this message; find the later queued turn with list_runs. |
| retryable | No | Whether sending the same message again could plausibly succeed. A time_limit run can continue with a follow-up message. |
| session_id | Yes | The durable conversation/session identifier. |
| started_at | No | When the run started. |
| file_source | No | Where this run's file links read from and whether its files are saved. Execution status does not report the save; check state here. |
| stop_reason | No | Controller-selected stop reason, when present. |
| input_status | No | The durable status of this run's human-input request, when it has one: pending, answered, cancelled or expired. cancelled and expired are terminal — that run will never resume, so stop polling it. |
| last_worklog | No | The agent's most recent one-sentence note about what it is doing, from the run's durable event log. Absent for a terminal result and for a run that has written none. |
| save_failure | No | Present when saving the run's working copy failed, so its files are not durable outputs. code names the failure. content_refusals lists up to three refused paths, relative to the copy root, each with its cause: hardlink, database_backup_required (a SQLite file that needs sqlite3 .backup) or unsupported_file_mode. |
| workspace_id | No | The Workspace UUID. |
| input_expired | No | True when this run is paused on a question its conversation has already moved past: a later run in the same conversation has completed. Do not answer it; start a new run instead. |
| poll_after_ms | No | The same wait as poll_after_seconds, in milliseconds. |
| resume_run_id | No | The exact auto-resume successor for an interrupted run; poll this run next. |
| resume_status | No | Auto-resume disposition for an interrupted run: pending, resumed, failed, or unknown. |
| tool_progress | No | Durable tool execution progress; absent when this run has no tool-progress telemetry. |
| usage_by_role | No | Attributed spend, tokens, and model-call counts split into executor, advisor, and reviewer roles. |
| last_tool_step | No | What this run last did with a tool: "running <tool>" while a call is in flight, otherwise "completed <tool>" for the most recent finished call. Absent for a terminal result and for a run with no tool-progress telemetry. |
| pending_inputs | No | Human inputs blocking an awaiting_input run. |
| elapsed_seconds | No | Seconds since the run started; absent for a terminal result. |
| upstream_status | No | The model provider's HTTP status when this run died on an upstream fault; absent otherwise. |
| last_activity_at | No | When the run last wrote a note or finished a tool call. Absent for a terminal result and for a run that has done neither. |
| last_heartbeat_at | No | Most recent durable executor heartbeat. |
| continuation_error | No | Why the answered message has not started its continuation. |
| poll_after_seconds | No | Suggested seconds before polling again, paced to this run's recent tool-completion rate; absent for a terminal result. |
| continuation_run_id | No | The exact continuation created for an answered input; poll this run next. |
| continuation_pending | No | The answer was recorded and its continuation has not started yet. Retry this message with the same idempotency key to get the continuation. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations (readOnlyHint, idempotentHint=false) with genuinely decision-relevant behavior: file links read the run's copy while state is pending and the saved revision once ready, files are non-durable when save_failure is present, and agent_current_files links are mutable by later runs. It does not contradict annotations. It stays at 4 because identity/scoping requirements (agent_id vs workspace_id) and the polling contract are left to the schema rather than restated here.
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 purpose is front-loaded in the first sentence, then the text is organized by run state, which mirrors how an agent will branch on the result. It is dense and long, and the extended enumeration of completed-run fields overlaps the existing output schema, so a little 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?
Covers every terminal and non-terminal state (running, completed, failed/cancelled, awaiting_input, interrupted/resumed) plus the durability caveats on file links, which is what an agent needs to interpret a result and choose its next call. Nothing material is missing for a read-by-id tool.
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 wait, wait_seconds, agent_id and workspace_id are fully documented in structured fields. The description only echoes 'by run_id' and adds no syntax or selection 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?
States a specific verb and resource with its identifier: 'Get a run's current state by run_id.' That cleanly separates it from list_runs (many runs) and from get_credits/get_workspace_costs (aggregate billing rather than a single run's attributed credits). An agent can pick it 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?
Usage is implied through state descriptions: poll a running run using poll_after_seconds, answer approvals when status is 'awaiting_input' (which points toward answer_pending_input), follow continuation_run_id or resume_run_id. But no sibling is ever named and there is no explicit when-to-use/when-not statement, so the routing 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_workspace_changesetGet Workspace changesetARead-onlyInspect
Get one changeset: its state and phase, the changed paths (at most 500) and conflicting paths once compared is true, comparison_current_revision for accept_workspace_changeset, and result_revision after an accepted changeset is saved. read_workspace_file reads the worker's version of a file from incoming_revision. No run starts and nothing changes.
| Name | Required | Description | Default |
|---|---|---|---|
| changeset_id | Yes | The changeset_id from submit_workspace_changeset or list_workspace_changesets. | |
| workspace_id | Yes | The Workspace UUID. |
Output Schema
| Name | Required | Description |
|---|---|---|
| phase | Yes | The step the changeset is in: checkpointing, creating_integration and comparing while the comparison runs; review_ready when accept_workspace_changeset can accept it; needs_resolution when it has conflicts; saving_result after accept until result_revision is set; recompare_required when the Workspace changed after the comparison (submit the worker again); then accepted, rejected or failed. |
| state | Yes | submitted (being compared, or ready for review when phase is review_ready), conflicted (the worker and the Workspace changed the same paths; see accept_workspace_changeset for recovery), accepted, rejected or failed. |
| changes | No | The changed paths, at most 500. get_workspace_changeset returns them; list_workspace_changesets leaves them out. |
| compared | Yes | True when the comparison is complete and changes and conflicts are known. |
| conflicts | No | The paths that conflict, when state is conflicted. |
| no_change | No | True when the worker changed no files. |
| created_at | Yes | When the changeset was submitted. |
| updated_at | Yes | When the changeset last changed. |
| auto_accept | No | Set only for a changeset whose comparison was clean and changed files: pending (the platform may still accept it), accepted (the platform accepted it) or abandoned (the platform stopped and will not accept it). |
| change_count | Yes | The number of changed paths. |
| changeset_id | Yes | The changeset UUID. |
| workspace_id | Yes | The Workspace UUID. |
| base_revision | Yes | The revision the worker's copy started from. |
| result_revision | No | The new current revision of the Workspace once an accepted changeset is saved. |
| terminal_reason | No | Why a failed changeset failed. |
| working_copy_id | Yes | The worker's copy that the changes come from. |
| changes_truncated | No | True when there are more than 500 changed paths. |
| incoming_revision | Yes | The worker's saved revision. read_workspace_file reads its files. |
| validation_evidence | No | The evidence given when the changeset was accepted. |
| comparison_current_revision | No | The Workspace revision the changes were compared with. accept_workspace_changeset takes it as expected_current_revision. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true and openWorldHint=false, so 'No run starts and nothing changes' largely restates structured data. The description nevertheless adds real behavioral context the annotations do not carry: a hard cap of 500 changed paths, the fact that conflicting paths only appear once compared is true, and state-dependent fields (comparison_current_revision vs result_revision) that depend on the changeset's lifecycle stage.
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 two sentences, front-loaded with the core 'get one changeset' purpose before the field inventory. The middle clause is dense but each element (path cap, conflict timing, revision fields) maps to a distinct part of the return value; the trailing read_workspace_file pointer is slightly tangential but useful.
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?
An output schema exists, so the description is not obligated to enumerate return fields, yet it usefully explains the state-dependent ones. Combined with the read-only annotations and full schema coverage, an agent has enough to invoke it correctly; the only gap is the absence of explicit sibling routing guidance.
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 documented in the schema (including the changeset_id provenance from submit_workspace_changeset or list_workspace_changesets). The description adds no format, syntax, or constraint detail for the two IDs, 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?
The description states a specific verb and resource ('Get one changeset') and enumerates what the result contains (state, phase, changed paths, conflicting paths, revisions), which is far beyond a restatement of the name. It implicitly separates itself from list_workspace_changesets via 'one changeset', but never names that sibling 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 through field-level routing: comparison_current_revision is flagged as the input for accept_workspace_changeset and result_revision appears after an accepted changeset, and read_workspace_file is named as the way to read a worker's file version. However, there is no explicit statement of when to call this tool versus list_workspace_changesets, nor any exclusion or precondition guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_workspace_costsGet Workspace costsARead-onlyInspect
Get the amount charged to the account's balance for the runs of a Workspace, or of one task group in it, in a time window: the total, how complete it is (coverage), and the charges that make it up per run. A token limit is not a cost. No run starts and nothing changes.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | End of the window, RFC 3339, not in the future. Omitted, now. The window is at most 366 days. | |
| from | No | Start of the window, RFC 3339. Omitted, 30 days before to. | |
| workspace_id | Yes | The Workspace UUID. | |
| task_group_id | No | Only report the charges of this task group of the Workspace. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The Workspace or task group UUID. |
| to | Yes | End of the time window, RFC 3339. |
| from | Yes | Start of the time window, RFC 3339. |
| rows | Yes | The charges that make up the total, one row per run and kind of usage, at most 200. |
| notes | Yes | What the total includes and excludes. |
| scope | Yes | workspace or task_group. |
| coverage | Yes | partial when charges were found and unavailable when none were. The total is the sum of the charges linked to runs in this scope, not a complete cost; notes say what it leaves out. |
| rows_truncated | No | True when the scope has more than 200 charge rows; the total still includes all of them. |
| charged_micro_usd | Yes | The total charged to the account's balance for runs in this scope and window, in micro-US-dollars. |
| pending_compute_runs | Yes | Runs whose compute charge is not settled yet; the total grows when they settle. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, openWorldHint=false and idempotentHint=false, so the safety profile is covered. The description adds real value beyond that: it clarifies that no run is started and no state changes, and it explicitly rules out a common misinterpretation (token limits are not costs). It does not explain why repeat calls may differ despite being read-only (the 'now'-defaulted window behind idempotentHint=false), which would have been the ideal addition.
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 sentences, front-loaded with the primary outcome and followed by two short, high-value clarifiers. Nothing is padded and every clause carries 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?
An output schema exists, so return values need no explanation, and the four parameters are fully documented in the schema. The description supplies scope, semantics and no-side-effect guarantees, leaving only the sibling-selection question unanswered.
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%: from/to defaults, RFC 3339 format, the 366-day cap, and the task_group_id narrowing are all documented in the schema. The description only restates the task-group and time-window concepts, adding no syntax or edge-case detail 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 with precise scope: charges to the account balance for a Workspace's runs (or one task group) within a time window, plus what is returned (total, coverage, per-run charges). It even disambiguates domain terms ('A token limit is not a cost'). It does not name an adjacent sibling such as get_credits, so an agent must infer the boundary between cost and credit 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 description conveys the applicable scope (a Workspace, optionally narrowed to one task group, within a time window) but never says when to choose this over siblings like get_credits or how to combine it with list_runs. Usage is implied by the resource, not stated as guidance or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_workspace_workerGet Workspace workerARead-onlyInspect
Get one worker's status: whether it has started (run_id), how its run ended (run_status), whether its files are saved (save_state ready with saved_revision_id) and whether its changes were submitted and accepted (changeset_id, change_status; Plori submits the saved files of a normally completed run itself). A completed run alone does not mean the files are saved or in the Workspace; check save_state and change_status. get_run_result with run_id and workspace_id reads the worker's reply and its approval requests. No run starts and nothing changes.
| Name | Required | Description | Default |
|---|---|---|---|
| workspace_id | Yes | The Workspace UUID. | |
| worker_request_id | Yes | The worker_request_id that create_workspace_worker returned. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cause | No | Machine-readable cause of a run that did not finish normally. |
| run_id | No | The worker's run, present once it has started. get_run_result reads its reply, steer_workspace_worker sends it a message while it runs, and cancel_run stops it. |
| status | Yes | Where the worker is: received, ready or blocked while it waits to start (queue_reason says why it is blocked), starting, running, or terminal when its run has ended (run_status says how). |
| activity | No | The worker's expiring activity hint; absent when expired or unavailable. The saved changeset is authoritative. |
| agent_id | Yes | The agent that runs the worker. get_run_result and cancel_run take it with run_id. |
| run_status | No | The run's status: running, awaiting_input (paused on an approval or question; get_run_result lists them), completed, error or cancelled. |
| save_state | Yes | Whether the worker's files are saved: none (no run has ended), pending (saving), ready (saved as saved_revision_id), failed (see save_failure) or unconfirmed (the save could not be confirmed). |
| session_id | Yes | The worker's own conversation id. It is private to the worker; send_workspace_message cannot select it. |
| stop_reason | No | The stop reason of an ended run, when one was recorded. |
| changeset_id | No | The changeset submitted for this worker's files, if any. |
| queue_reason | No | Why a waiting worker has not started, such as a capacity or balance limit. |
| save_failure | No | Why the save failed, when save_state is failed. |
| workspace_id | Yes | The Workspace UUID. |
| base_revision | Yes | The saved revision the worker's copy started from. |
| change_status | Yes | unsubmitted until the worker's files are submitted (by Plori when the run completes normally with changed files, or by submit_workspace_changeset), then the changeset's state. |
| task_group_id | Yes | The task group of the worker. get_workspace_costs and stop_workspace_task_group take it. |
| working_copy_id | Yes | The copy of the Workspace files that this worker edits. The Workspace's current files do not change until its changes are accepted. |
| saved_revision_id | No | The saved revision that holds the worker's files once save_state is ready. read_workspace_file reads files from it. |
| worker_request_id | Yes | The worker's id; get_workspace_worker takes it. |
| saved_operation_id | No | The save that produced saved_revision_id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only safety via readOnlyHint=true, and the description reinforces this with 'No run starts and nothing changes'. It adds genuinely useful lifecycle semantics beyond the annotations — that a completed run does not imply saved files or an accepted changeset, and that Plori auto-submits saved files of a normally completed run.
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?
Dense but front-loaded: the core action leads, then state fields, then the caveat, then the alternative and the read-only guarantee. Every sentence carries information, though the run_id/save_state explanation is slightly repetitive.
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 an output schema present, return values need not be explained, and the description still flags which fields matter for interpreting readiness. Annotations cover the safety profile. Only edge cases (e.g., invalid or unknown worker_request_id) are unaddressed, which is minor.
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 parameters (workspace_id, worker_request_id) are already documented, including the provenance note that worker_request_id comes from create_workspace_worker. The description repeats run_id/workspace_id in the get_run_result pointer but adds no new parameter-level detail.
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 ('Get one worker's status') and immediately enumerates the state dimensions returned (run_id, run_status, save_state, changeset_id, change_status), which lets an agent separate it from list_workspace_workers and get_workspace_changeset. The distinction from get_run_result is also named 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?
Gives a clear selection rule: 'check save_state and change_status' because 'a completed run alone does not mean the files are saved'. It also routes the agent to get_run_result for the worker's reply and approvals. No explicit when-not-to-use case, but the sibling boundary is drawn well.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_pending_inputsList pending approvals and questionsARead-onlyInspect
List the runs of a Workspace or an agent that are paused on an approval request or a question, with each request's run_id, tool_call_id and kind, and for an approval request its approve_url. Only the account owner approves, at that URL in the Plori web app. A request is not listed when a later run in the same conversation has completed.
| Name | Required | Description | Default |
|---|---|---|---|
| agent_id | No | The agent UUID (agent_id in a run result). Give this or workspace_id. | |
| workspace_id | No | The Workspace UUID. Give this or agent_id; with both, agent_id is used. Covers the runs of the Workspace's agent and its workers. |
Output Schema
| Name | Required | Description |
|---|---|---|
| pending_inputs | Yes | Runs currently paused on a human approval or input request. A request whose session has already moved on is left out: answering it would resume a superseded turn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered. The description adds genuine behavioral context beyond them: the returned fields, the account-owner-only approval constraint, and the non-obvious filtering rule that a request disappears once a later run in the same conversation completes.
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 front-loaded sentences with no filler: what is listed and its fields, the approval mechanics, then the edge-case filter. Slightly dense but every clause carries 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?
An output schema exists, so return values need no exposition. The description covers purpose, fields, and filtering behavior adequately for a two-parameter read tool, with the only gap being explicit sibling routing.
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 fully documented there, including the 'give this or that' relationship, so the baseline is 3. The description adds only the scoping phrase 'runs of a Workspace or an agent', which largely restates 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 – lists runs paused on an approval request or question – and enumerates the returned identifiers (run_id, tool_call_id, kind, approve_url). This is clearly distinguishable from list_runs and answer_pending_input by describing a filtered subset with a specific purpose.
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 explaining that only the account owner approves and that approval happens at the URL in the web app, hinting this tool is for discovery rather than approval. However it never names answer_pending_input or list_runs as alternatives, nor states an explicit when-to-use condition, leaving routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_runsList runsARead-onlyInspect
List the runs of a Workspace or an agent, most recently started first, with each run's status, timing, attributed cost and session_id (its conversation). Returns 20 runs unless limit is given (at most 100). When more runs exist, the result has next_cursor; passing it as cursor returns the next page, and its absence means the list is complete. tool_progress is null for an ended run and for a run without recorded tool progress. input_expired:true marks a run paused on a question that a later completed run in the same conversation has superseded.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many runs to return, newest first (default 20, maximum 100). | |
| cursor | No | The next_cursor from a previous list_runs result, to continue where it stopped. Omit for the newest page. | |
| agent_id | No | The agent UUID (agent_id in a run result). Give this or workspace_id. | |
| workspace_id | No | The Workspace UUID. Give this or agent_id; with both, agent_id is used. Lists the runs of its main conversation and of the Workspace's agent: the 100 newest, plus runs still running or paused. list_workspace_workers lists the workers' runs. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | One page of the agent's runs, most recently started first. |
| next_cursor | No | Pass this back as cursor to read the next page. Absent when this page is the end of the history. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint/openWorldHint/idempotentHint; the description adds real behavioral context beyond them: default page size 20 with a ceiling of 100, cursor round-trip semantics, and the meaning of null tool_progress and input_expired:true. These are exactly the semantics an agent cannot infer and are consistent with idempotentHint=false (a cursor list drifts as new runs appear).
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 and ordering, then pagination, then the two edge-case field meanings — all in dense, waste-free sentences. The final two sentences explain return-field semantics that the output schema already covers, which is the only slack.
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-param, zero-required list tool with a full output schema and read-only annotations, the description covers paging, sizing and result interpretation adequately. What it lacks is routing context against get_run_result / list_workspace_workers, which would make selection unambiguous.
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 limit, cursor, agent_id and workspace_id, including their defaults and precedence. The description restates limit/default and cursor semantics without adding syntax or format detail beyond the schema, 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 ('List the runs of a Workspace or an agent'), plus ordering ('most recently started first') and the fields surfaced per run (status, timing, cost, session_id). An agent knows exactly what this returns without opening the schema. The 'run' concept is distinct from the worker/workspace siblings even though no sibling is named.
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 explains pagination operation (next_cursor / cursor, absence means complete) which is genuine usage guidance, but it never states when to choose this tool over get_run_result or list_workspace_workers, nor when to prefer agent_id vs workspace_id at the description level. Usage is implied rather than declared.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_workspace_changesetsList Workspace changesetsARead-onlyInspect
List the changesets of a Workspace, one page at a time, with each one's state, phase and number of changed paths. get_workspace_changeset returns the changed paths. No run starts and nothing changes.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Changesets per page, 1-100. Omitted, 50. | |
| cursor | No | next_cursor from the previous page. | |
| workspace_id | Yes | The Workspace UUID. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | One page of the Workspace's changesets, without their changed paths. |
| next_cursor | No | Pass this back as cursor to read the next page. Absent on the last page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, and the description reinforces this with "No run starts and nothing changes" — the key safety fact for a workspace agent. It also discloses pagination behavior, which the annotations do not cover. It does not describe ordering or cursor invalidation, keeping it below the top mark.
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 with zero waste: scope first, then the sibling-routing hint, then the safety guarantee. Every sentence earns its place and the most important constraint is front-loaded.
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 an output schema present and full schema coverage, the description need not explain return values, and it covers pagination and side-effect freedom. Minor gaps remain: result ordering and what happens on an expired cursor are unstated.
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 documents limit, cursor and workspace_id, putting the baseline at 3. The description adds meaning by framing the call as "one page at a time," which explains why cursor and limit exist together as a pagination pair rather than independent filters.
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 changesets of a Workspace") plus the exact fields returned (state, phase, changed path count). It explicitly distinguishes itself from get_workspace_changeset, 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?
"get_workspace_changeset returns the changed paths" is an explicit routing rule to the sibling for detail work, and "one page at a time" signals the paginated listing mode. There is no explicit when-not-to-use or prerequisite context, but the alternative is named and its selection condition is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_workspacesList WorkspacesARead-onlyInspect
List the Workspaces the authenticated account owns and those other accounts share with it, with each one's id, name, state, owning account (account: user_id and email), the caller's role there (owner, member or viewer), agent (default_agent_id), main conversation id (main_session_id), current revision and root copy id. state is active, adopting (its files are moving to new storage; runs are refused until it is active again), deleting or deleted. All Workspaces are returned in one response, without paging. No run starts and nothing changes. With workspace_id, the workspaces list contains only that Workspace, including storage_readiness (state, since, pending_reason, retryable) when its storage is still starting. The root copy exists only once storage_readiness.state is ready.
| Name | Required | Description | Default |
|---|---|---|---|
| workspace_id | No | The Workspace UUID. Omitted, all Workspaces are returned. |
Output Schema
| Name | Required | Description |
|---|---|---|
| workspaces | Yes | The caller's own and shared Workspaces; one entry when workspace_id was given. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, it discloses that no run is started and nothing changes, that results are unpaged, that runs are refused while a workspace is in 'adopting' state, and when storage_readiness and the root copy become available. This is substantive behavioral context an agent cannot derive from the 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 purpose and scope are front-loaded and each clause carries information, but the enumeration of return fields (id, name, state, role, agent, main_session_id, etc.) partially duplicates the output schema that already exists, adding some avoidable 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 single-parameter read tool with an output schema and read-only annotations, the description covers scope, side-effect absence, state semantics, and the workspace_id branch. Nothing an agent needs to invoke or interpret 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 already 100%, so the baseline is 3, but the description earns extra credit by explaining the consequence of supplying workspace_id (single-workspace result plus conditional storage_readiness fields) rather than merely restating that it is optional.
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 names a specific verb and resource (list Workspaces) and defines scope precisely: workspaces the account owns plus those shared with it. It enumerates the returned fields and the state values, so an agent can tell this apart from create_workspace, delete_workspace, or the changeset tools 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?
It gives clear operational context: all workspaces come back in one unpaged response, and passing workspace_id narrows the result to a single workspace with extra storage_readiness detail. It does not explicitly name or exclude a sibling alternative, which keeps it below a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_workspace_workersList Workspace workersARead-onlyInspect
List the workers started in a Workspace, oldest first, one page at a time, with each worker's status, run_id, save_state and saved_revision_id. task_group_id limits the list to one task group. No run starts and nothing changes.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Workers per page, 1-100. Omitted, 25. | |
| cursor | No | next_cursor from the previous page. | |
| workspace_id | Yes | The Workspace UUID. | |
| task_group_id | No | Only list the workers of this task group. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | Yes | One page of the Workspace's workers, oldest first. |
| next_cursor | No | Pass this back as cursor to read the next page. Absent on the last page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, and the description adds genuinely useful behavior beyond them: 'oldest first, one page at a time' ordering/pagination semantics and the explicit reassurance 'No run starts and nothing changes', which matters because a 'workers' listing could otherwise be mistaken for triggering execution. It stops short of describing page size defaults or termination conditions, which live 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 tight sentence with the resource and ordering front-loaded, followed by scope and safety notes; nothing is padded. The trailing enumeration of returned fields is mildly redundant given an output schema exists, but it does not bloat the 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?
With an output schema present, a fully covered input schema, and annotations carrying the safety profile, the description only needs to supply ordering, pagination, scope and non-mutation guarantees — and it supplies all four. An agent has everything required 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 description coverage is 100%, so limit, cursor, workspace_id and task_group_id are all documented in the schema itself. The description only restates task_group_id's filtering role and the pagination model, adding no syntax or format detail beyond the structured fields. 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 the workers started in a Workspace') and enumerates the returned fields, so an agent knows exactly what comes back. It does not explicitly name the singular sibling get_workspace_worker or explain how it differs from list_runs, leaving differentiation to inference from the name.
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 one scoping hint ('task_group_id limits the list to one task group') and describes the page-by-page pattern, which implies when to use it. It never states when to prefer this over get_workspace_worker for a single worker or list_runs for runs, so usage is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_workspace_fileRead Workspace fileARead-onlyInspect
Read a file or list a directory in a saved revision of a Workspace: the Workspace's current_revision, a worker's saved_revision_id, or a changeset's base_revision, incoming_revision or result_revision. A file returns its UTF-8 text, up to 262144 bytes; a larger file is refused, and a binary file is refused with 415. A directory returns its entries one page at a time. No run starts and nothing changes.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | The file or directory path, relative to the Workspace root, for example src/main.go or / for the root. | |
| cursor | No | For a directory: next_cursor from the previous page. | |
| revision_id | No | The saved revision to read. Omitted, the Workspace's current revision. | |
| workspace_id | Yes | The Workspace UUID. |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | Yes | file or dir. |
| path | Yes | The path that was read. |
| size | No | The file's size in bytes. |
| text | No | The file's UTF-8 text, for a file. |
| entries | No | The directory's entries, for a directory. |
| next_cursor | No | For a directory with more entries: pass it back as cursor to read the next page. |
| revision_id | Yes | The saved revision that was read. |
| workspace_id | Yes | The Workspace UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, but the description adds substantive detail beyond them: the 262144-byte cap and refusal behaviour, HTTP 415 for binary files, paginated directory entries, and the explicit 'No run starts and nothing changes' assurance.
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 tightly-packed sentences, front-loaded with the verb and resource, then limits, then the non-mutating guarantee. Nothing is redundant and every sentence carries operational 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?
An output schema exists, so return structure need not be restated; the description covers what an agent still needs — size limits, binary rejection, pagination via cursor, and side-effect freedom — for a read tool with a rich but simple 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 the baseline is 3, but the description adds real meaning to revision_id by enumerating the accepted revision sources (current_revision, saved_revision_id, base/incoming/result_revision) that the schema's one-line field description does not.
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 a file or list a directory') and enumerates exactly which revisions can be targeted, so the agent can distinguish it from sibling mutation tools like upload_workspace_file or get_workspace_changeset 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?
Gives a clear context for use — reading from current_revision, a worker's saved_revision_id, or a changeset's base/incoming/result revision — but never explicitly routes the agent away from alternatives or states preconditions (e.g., when to prefer a changeset tool over reading a revision).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reject_workspace_changesetReject Workspace changesetADestructiveIdempotentInspect
Reject a changeset: the Workspace's files stay as they are, and the worker's copy and saved revision are kept. A rejected or accepted changeset cannot change again. Repeating the call returns the same result.
| Name | Required | Description | Default |
|---|---|---|---|
| changeset_id | Yes | The changeset_id from submit_workspace_changeset or list_workspace_changesets. | |
| workspace_id | Yes | The Workspace UUID. |
Output Schema
| Name | Required | Description |
|---|---|---|
| phase | Yes | The step the changeset is in: checkpointing, creating_integration and comparing while the comparison runs; review_ready when accept_workspace_changeset can accept it; needs_resolution when it has conflicts; saving_result after accept until result_revision is set; recompare_required when the Workspace changed after the comparison (submit the worker again); then accepted, rejected or failed. |
| state | Yes | submitted (being compared, or ready for review when phase is review_ready), conflicted (the worker and the Workspace changed the same paths; see accept_workspace_changeset for recovery), accepted, rejected or failed. |
| changes | No | The changed paths, at most 500. get_workspace_changeset returns them; list_workspace_changesets leaves them out. |
| compared | Yes | True when the comparison is complete and changes and conflicts are known. |
| conflicts | No | The paths that conflict, when state is conflicted. |
| no_change | No | True when the worker changed no files. |
| created_at | Yes | When the changeset was submitted. |
| updated_at | Yes | When the changeset last changed. |
| auto_accept | No | Set only for a changeset whose comparison was clean and changed files: pending (the platform may still accept it), accepted (the platform accepted it) or abandoned (the platform stopped and will not accept it). |
| change_count | Yes | The number of changed paths. |
| changeset_id | Yes | The changeset UUID. |
| workspace_id | Yes | The Workspace UUID. |
| base_revision | Yes | The revision the worker's copy started from. |
| result_revision | No | The new current revision of the Workspace once an accepted changeset is saved. |
| terminal_reason | No | Why a failed changeset failed. |
| working_copy_id | Yes | The worker's copy that the changes come from. |
| changes_truncated | No | True when there are more than 500 changed paths. |
| incoming_revision | Yes | The worker's saved revision. read_workspace_file reads its files. |
| validation_evidence | No | The evidence given when the changeset was accepted. |
| comparison_current_revision | No | The Workspace revision the changes were compared with. accept_workspace_changeset takes it as expected_current_revision. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, but the description adds genuinely new context: what is and isn't affected (Workspace files unchanged, worker copy and saved revision kept), that the changeset enters a terminal state after accept or reject, and that repeated calls return the same result. This clarifies the scope of the "destructive" annotation rather than repeating it.
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 sentences with zero filler. The primary effect (files stay, copy kept) is front-loaded, and the terminal-state/idempotency note follows as secondary but relevant 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?
An output schema exists, so return values need no explanation. For a two-parameter, fully-described mutation tool, the description covers the state semantics, the terminal behavior, and idempotency — everything an agent needs to invoke it 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 both parameters (changeset_id, workspace_id) are already fully documented in the schema, including where changeset_id comes from. The description adds no parameter-level meaning beyond that, which is the expected baseline when the schema does the work.
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 ("Reject a changeset") and immediately explains the resulting state, which makes it unambiguous against its sibling accept_workspace_changeset. An agent can distinguish the two 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?
The description conveys the selecting condition implicitly and clearly: rejecting keeps the Workspace's files and the worker's copy/revision, which is the semantic opposite of accepting. It does not explicitly name accept_workspace_changeset as the alternative or state when-not to use this tool, so it falls short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schedule_runSchedule a runADestructiveInspect
Use this when the user wants one task to start later, such as "run this tonight" or "check again in two hours". Do not use for a repeating schedule such as every day or every week: ask the Workspace's agent with send_workspace_message to set up a scheduled workflow, which the account owner activates. Request one run at a later time, set by delay_seconds or fire_at (RFC 3339). Nothing is scheduled until the account owner confirms the request at confirm_url in the Plori web app: until then its status is awaiting_confirmation and it never fires, and the calling model cannot confirm it. A request whose fire time passes before the owner confirms it is not armed. Returns the request with its prompt, fire_at, status and confirm_url. The run it starts is charged like any run, and its actions outside the agent's own environment pause for the owner's approval one action at a time, as for any run started through this connector.
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | The message to send the agent when the schedule fires. | |
| fire_at | No | Fire at this RFC3339 timestamp (mutually exclusive with delay_seconds). | |
| agent_id | No | The agent's UUID. Give this or workspace_id. | |
| session_id | No | A conversation of the agent to deliver the scheduled run into (session_id from an earlier result). Omitted, the conversation the agent is running in when the request is made, or a new conversation when it is idle. | |
| workspace_id | No | The Workspace UUID; the Workspace's agent runs the prompt. Give this or agent_id; with both, agent_id is used. | |
| delay_seconds | No | Fire this many seconds from now (mutually exclusive with fire_at). |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The schedule's id. |
| kind | Yes | once: a single run at fire_at. |
| prompt | Yes | The message the agent receives when the schedule fires. |
| status | Yes | awaiting_confirmation until the owner confirms at confirm_url; pending once armed; firing or dispatched while delivery is in progress; done once the run starts; cancelled or failed otherwise. |
| fire_at | No | When it fires, RFC 3339. |
| agent_id | Yes | The agent the run is scheduled for. |
| attempts | Yes | Delivery attempts so far. |
| metadata | No | Extra data recorded with the request; not needed to use it. |
| thread_id | No | The conversation the run is delivered into: the session_id given, else the conversation the agent was running in when the request was made, else a new one. |
| created_at | Yes | When the request was made. |
| last_error | No | Why the last delivery attempt failed, when it did. |
| confirm_url | No | Where the owner confirms, in the Plori web app. |
| confirmed_at | No | When the owner confirmed it. |
| last_fired_at | No | When it last fired. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only flag destructive/openWorld/non-idempotent; the description goes well beyond by disclosing the entire confirmation lifecycle: nothing is armed until the owner confirms at confirm_url, status is awaiting_confirmation until then, the calling model cannot confirm, and a fire time that passes before confirmation never arms. It also discloses billing treatment and per-action approval outside the agent environment.
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 selection rule, then the mechanics, then the return shape, with no filler sentences. It is a single dense paragraph rather than parsed sections, and the closing sentence on charging/per-action approval is marginal, but nearly every clause carries new 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?
Covers selection, parameterization, the asynchronous confirmation gate, failure mode (fire time passing), and a brief return summary; an output schema exists so return details need not be expanded. Nothing an agent needs to invoke 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 the schema already documents all six parameters including the fire_at/delay_seconds mutual exclusivity and RFC 3339 format that the description restates. The description adds no syntax or format detail 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 (schedule) and resource (one run) with explicit scope: 'Request one run at a later time, set by delay_seconds or fire_at'. It distinguishes itself from the closest sibling by name and by the one-off vs repeating distinction, so an agent can route correctly 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?
Gives an explicit when-to-use with example utterances ('run this tonight', 'check again in two hours') and an explicit when-not ('Do not use for a repeating schedule such as every day or every week') with the named alternative, send_workspace_message. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_workspace_messageSend message to WorkspaceADestructiveInspect
Use this when a build, research or recurring report should run in the background or after the chat ends. Do not use for quick lookups. Send a message to a Workspace's main conversation, or to another of its conversations named by session_id; the Workspace's agent runs it. The run works on the Workspace's current files and saves them as a new revision when it ends. Returns the run with agent_id and workspace_id. A completed run has text (the agent's reply), the files the reply linked, a url to the conversation in the Plori web app, and its credits and tokens; file_source.state ready and no save_failure mean its files are saved. A run still going has status "running", run_id and poll_after_seconds, and continues after this call returns. A paused run has status "awaiting_input" and lists its requests; tell the person each approval's approve_url and who it is assigned to. A run started through this connector pauses before each action outside the agent's own environment (connected-account, MCP and outbound HTTP writes, git push, publishing, deploys, email) until the account owner approves that one action in the Plori web app; the owner's standing approvals do not apply and the calling model cannot approve. While the conversation is running or paused, a plain-text message is accepted as steering or queued (steer_id), or answers an ordinary question assigned to its sender, and never cancels a pending request. A message with attachments or run options gets 409 conversation_busy until the conversation is idle: keep them and resend once it is idle. Runs are charged to the account's prepaid US-dollar balance; a run the balance cannot cover is refused with 402. idempotency_key identifies the request for 24 hours: the same key with the same arguments returns the original result, and the same key with different arguments is refused.
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Queued or steering messages return their receipt immediately, regardless of wait. For a newly started or continued run, true (default): hold this call until the run finishes, pauses for a person, or the hold ends. The hold is 25 seconds by default, 50 seconds for Codex, and up to 30 minutes for Claude Code 2.1.212 or later; a call without an MCP progressToken is held at most 50 seconds. If the hold ends first, the result has status "running" and the run continues. false: return the run_id at once. Clients that support MCP Tasks always receive the run_id at once. | |
| message | Yes | The message for the agent, in plain text. | |
| session_id | No | A conversation of this Workspace to continue (session_id from an earlier result). Omitted, the message goes to the main conversation. A worker's private conversation cannot be selected here. | |
| callback_url | No | Optional callback URL for this run. Must use http or https and resolve only to public addresses. | |
| wait_seconds | No | Hold length in seconds when wait is true, used instead of the client default. 0 or omitted uses the client default. A call without an MCP progressToken is still held at most 50 seconds. | |
| workspace_id | Yes | The Workspace UUID. | |
| callback_secret | No | Optional secret used to sign callback deliveries with HMAC-SHA256. | |
| idempotency_key | No | A string of 1-255 bytes you generate for this message. The same key with the same arguments returns the original run or message receipt for 24 hours instead of acting again; the same key with different arguments is refused. Without a key, every call submits a new message. | |
| max_turn_tokens | No | Optional cumulative cache-weighted token ceiling for this turn. 0 or omitted: no ceiling for a registered account, and 2,000,000 for an anonymous trial. The maximum is 5,000,000. The agent reserves its final 2% for a tool-free wrap-up that says the work so far is saved and that a new message continues the task. | |
| max_turn_seconds | No | Optional wall-clock budget for this turn in seconds, maximum 14,400. When it runs out the agent is told to finish and reply; the run is not cancelled. 0 or omitted uses the platform default, when one is set. | |
| max_advisor_spend_micro_usd | No | Optional maximum advisor-completion spend for this turn in micro-US-dollars. 0 disables advisor completions. Omit it or pass null to use the agent setting; when neither is set, at most two advisor calls can run. The maximum is 5,000,000. |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | No | A deep link to this run's session in the plori web app. |
| hint | No | What to do next with this run, in one sentence. Present only while the run is non-terminal. |
| text | No | The assistant's reply once the run has finished. While a run is still going this is the run's own status message, not an answer, and is often absent — read last_worklog and last_tool_step instead. |
| cause | No | Machine-readable cause for a non-normal terminal state. |
| error | No | Why a terminal error or cancelled run failed, whether it was charged and what to do about it. Absent for a run that is still going or that finished normally. |
| files | No | Files in the Workspace files that this reply linked, in the order they appear. Each url is fetchable with the bearer token you called this tool with. Absent when the reply linked none. |
| run_id | Yes | The public run identifier; empty for an answered message whose continuation has not started. |
| status | Yes | The current run status, queued/steering for a message accepted into an active conversation, or answered when the answer is recorded but its continuation has not started. |
| tokens | No | Attributed token count; null when attribution is unavailable. |
| advisor | No | Advisor calls used and allowed, spend this turn, and its optional spend cap in micro-US-dollars. |
| credits | No | Attributed spend in micro-US-dollars; null when attribution is unavailable. |
| agent_id | No | The agent that runs the run. get_run_result and cancel_run take this value or workspace_id. |
| ended_at | No | When the run reached a terminal state. |
| steer_id | No | Durable message receipt when status is queued or steering. run_id names the running or paused predecessor, not a result of this message; find the later queued turn with list_runs. |
| retryable | No | Whether sending the same message again could plausibly succeed. A time_limit run can continue with a follow-up message. |
| session_id | Yes | The durable conversation/session identifier. |
| started_at | No | When the run started. |
| file_source | No | Where this run's file links read from and whether its files are saved. Execution status does not report the save; check state here. |
| stop_reason | No | Controller-selected stop reason, when present. |
| input_status | No | The durable status of this run's human-input request, when it has one: pending, answered, cancelled or expired. cancelled and expired are terminal — that run will never resume, so stop polling it. |
| last_worklog | No | The agent's most recent one-sentence note about what it is doing, from the run's durable event log. Absent for a terminal result and for a run that has written none. |
| save_failure | No | Present when saving the run's working copy failed, so its files are not durable outputs. code names the failure. content_refusals lists up to three refused paths, relative to the copy root, each with its cause: hardlink, database_backup_required (a SQLite file that needs sqlite3 .backup) or unsupported_file_mode. |
| workspace_id | No | The Workspace UUID. |
| input_expired | No | True when this run is paused on a question its conversation has already moved past: a later run in the same conversation has completed. Do not answer it; start a new run instead. |
| poll_after_ms | No | The same wait as poll_after_seconds, in milliseconds. |
| resume_run_id | No | The exact auto-resume successor for an interrupted run; poll this run next. |
| resume_status | No | Auto-resume disposition for an interrupted run: pending, resumed, failed, or unknown. |
| tool_progress | No | Durable tool execution progress; absent when this run has no tool-progress telemetry. |
| usage_by_role | No | Attributed spend, tokens, and model-call counts split into executor, advisor, and reviewer roles. |
| last_tool_step | No | What this run last did with a tool: "running <tool>" while a call is in flight, otherwise "completed <tool>" for the most recent finished call. Absent for a terminal result and for a run with no tool-progress telemetry. |
| pending_inputs | No | Human inputs blocking an awaiting_input run. |
| elapsed_seconds | No | Seconds since the run started; absent for a terminal result. |
| upstream_status | No | The model provider's HTTP status when this run died on an upstream fault; absent otherwise. |
| last_activity_at | No | When the run last wrote a note or finished a tool call. Absent for a terminal result and for a run that has done neither. |
| last_heartbeat_at | No | Most recent durable executor heartbeat. |
| continuation_error | No | Why the answered message has not started its continuation. |
| poll_after_seconds | No | Suggested seconds before polling again, paced to this run's recent tool-completion rate; absent for a terminal result. |
| continuation_run_id | No | The exact continuation created for an answered input; poll this run next. |
| continuation_pending | No | The answer was recorded and its continuation has not started yet. Retry this message with the same idempotency key to get the continuation. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say destructive/openWorld/non-idempotent; the description adds substantial operational context beyond them: approval pausing before external actions, that the caller cannot self-approve, 409 conversation_busy on attachment/option messages, 402 when the prepaid balance cannot cover the run, and 24-hour idempotency_key semantics. This is exactly the kind of behavior an agent needs that structured fields do not carry.
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 rule, which is good, but the body is a very long single block that restates schema-documented material (idempotency_key behavior, run status fields) even though an output schema already exists. It is information-dense rather than wasteful, but the duplication of structured fields and the sheer length cost 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?
With 11 parameters, full schema coverage, an output schema, and annotations, the remaining burden is behavioral — and the description covers billing, approval gating, busy/error states, waiting semantics, and idempotency. Nothing an agent needs in order to invoke it correctly 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 description coverage is 100%, so the schema already documents all 11 parameters and the baseline is 3. The description adds meaning on top: it clarifies what a plain-text message does during a live conversation (steering, queued, answering a pending question) and reinforces the idempotency_key contract, going beyond the schema's field-level wording.
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 ('Send a message to a Workspace's main conversation, or to another of its conversations named by session_id; the Workspace's agent runs it') and frames the scope as background/after-chat work. An agent can distinguish this from siblings like answer_pending_input or steer_workspace_worker because the description explains that a plain-text message becomes steering when the conversation is already running.
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 when-to-use ('when a build, research or recurring report should run in the background or after the chat ends') and a when-not ('Do not use for quick lookups'), plus busy/refusal conditions. It does not name alternative tools (answer_pending_input, steer_workspace_worker) explicitly, so the routing to siblings is left partly implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
steer_workspace_workerSteer a running worker or runADestructiveInspect
Send a message into a worker's running turn, for example to correct its direction, without stopping it. run_id is the worker's run_id from get_workspace_worker; a run started by send_workspace_message is also accepted. The agent reads the message before its next step and continues the same run; disposition steering means the running turn holds the message. A run that is not running (not started yet, paused on an approval or question, or ended) is refused with 409 run_not_running: answer a paused run with answer_pending_input. If the running turn cannot take the message, for example because it is ending, the message is withdrawn and the call is refused with 409 steer_not_delivered. A message sent through this connector makes the run's later outward actions pause for the account owner's approval, as for a run started through this connector. idempotency_key identifies the message: the same key with the same message returns the first result instead of sending it twice.
| Name | Required | Description | Default |
|---|---|---|---|
| run_id | Yes | The running run to send the message to. | |
| message | Yes | The message for the agent, in plain text (at most 65536 bytes). | |
| idempotency_key | No | Optional string of 1-255 bytes you generate for this message. Omitted, each call sends a new message. |
Output Schema
| Name | Required | Description |
|---|---|---|
| run_id | Yes | The run that holds the message. |
| steer_id | Yes | The id of the delivered message. |
| disposition | Yes | steering: the running turn holds the message and the agent reads it before its next step. applied: the agent has already read it (a repeated request with the same idempotency_key). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds a great deal beyond the annotations: two distinct 409 failure modes (run_not_running, steer_not_delivered), the withdrawal of the message on undeliverable turns, the approval-pause side effect on subsequent outward actions, and the fact that the agent reads the message at its next step. The conditional idempotency via idempotency_key is also disclosed, qualifying the annotation hint rather than contradicting it.
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 and every sentence carries operational weight with no filler. It is dense and delivered as one long block, so structural breaks around errors, side effects and idempotency would improve scanability, 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?
With an output schema present, return values need not be described, and the description fills the remaining gaps: failure codes, state preconditions, side effects and alternative routing. An agent has everything needed to call this correctly on the first attempt.
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 still adds provenance for run_id (from get_workspace_worker, or a run started by send_workspace_message) and clarifies the conditional idempotency semantics of idempotency_key ('omitted, each call sends a new message').
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 ('Send a message into a worker's running turn') plus the defining constraint 'without stopping it'. This cleanly separates it from send_workspace_message (starting a run), answer_pending_input (answering a paused run) and cancel_run (stopping).
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 the conditions under which it applies (a running turn) and when it is refused (not started, paused on approval/question, or ended) and routes the agent to the correct alternative, answer_pending_input, for the paused case. No reliance on inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
stop_workspace_task_groupStop Workspace task groupADestructiveIdempotentInspect
Stop every worker of a task group: workers that have not started never start, and running worker runs are cancelled. Their copies, saved revisions and agents are kept. Plori does not submit a stopped worker's files; submit_workspace_changeset can still submit a worker whose files are saved. The group starts no new workers afterwards. To stop one running worker only, use cancel_run with its run_id and workspace_id. Returns the group state (stopping until every run has ended, then stopped) and the runs whose cancellation was requested.
| Name | Required | Description | Default |
|---|---|---|---|
| workspace_id | Yes | The Workspace UUID. | |
| task_group_id | Yes | The task group to stop (task_group_id of a worker). |
Output Schema
| Name | Required | Description |
|---|---|---|
| runs | Yes | The group's runs whose cancellation this call requested. |
| state | Yes | stopping until every worker run of the group has ended, then stopped. A stopped group starts no new workers. |
| task_group_id | Yes | The task group UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only give a generic destructive/idempotent profile; the description goes well beyond that by naming exactly what survives (copies, saved revisions, agents), what Plori does not do (does not submit a stopped worker's files), and the interaction with submit_workspace_changeset. It also describes the state lifecycle returned (stopping → stopped), which is exactly the kind of context annotations cannot convey.
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 its side effects are front-loaded, and the alternative route is placed last, which is good structure. It is fairly long (five sentences) and slightly dense, but nearly every sentence carries distinct behavioral information, so little 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?
With an output schema present, the description is not obliged to explain return values, yet it still summarizes the returned group state and cancelled runs. Combined with preserved-artifact disclosure and the sibling routing note, an agent has everything needed to invoke it 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%, so workspace_id and task_group_id are already documented in the schema. The description references run_id/workspace_id only in the context of the cancel_run alternative and adds no format or syntax detail 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?
The opening clause names a specific verb+resource+scope: 'Stop every worker of a task group', and it immediately clarifies partial-state behavior (not-started workers never start, running runs cancelled). It differentiates itself from the sibling cancel_run by explicitly noting the one-worker case.
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 states the condition that selects the alternative: 'To stop one running worker only, use cancel_run with its run_id and workspace_id.' It also gives the operational boundary (no new workers start afterwards) so an agent knows when this is or is not appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_workspace_changesetSubmit worker changes for reviewADestructiveIdempotentInspect
Submit a worker's saved files for review as a changeset: Plori compares them with the Workspace's current files. Plori submits a worker's saved files itself when its run completes normally and they change at least one file, and accepts a clean comparison; use this tool for a worker whose change_status is still unsubmitted after its run ended in error, was cancelled or was stopped, or after phase recompare_required. Submitting a worker that Plori submitted returns that changeset. The worker must have save_state ready (get_workspace_worker); otherwise the call is refused with 409 workspace_worker_not_saved. The Workspace's files do not change. The comparison runs after the call returns: poll get_workspace_changeset until compared is true, then accept_workspace_changeset accepts a changeset in phase review_ready and reject_workspace_changeset rejects one. Submitting the same worker again while the Workspace's current revision is unchanged returns the same changeset; after the current revision changes, for example because another changeset was accepted, it creates a new changeset compared with the new current revision.
| Name | Required | Description | Default |
|---|---|---|---|
| workspace_id | Yes | The Workspace UUID. | |
| worker_request_id | Yes | The worker whose saved files to submit (worker_request_id). |
Output Schema
| Name | Required | Description |
|---|---|---|
| phase | Yes | The step the changeset is in: checkpointing, creating_integration and comparing while the comparison runs; review_ready when accept_workspace_changeset can accept it; needs_resolution when it has conflicts; saving_result after accept until result_revision is set; recompare_required when the Workspace changed after the comparison (submit the worker again); then accepted, rejected or failed. |
| state | Yes | submitted (being compared, or ready for review when phase is review_ready), conflicted (the worker and the Workspace changed the same paths; see accept_workspace_changeset for recovery), accepted, rejected or failed. |
| changes | No | The changed paths, at most 500. get_workspace_changeset returns them; list_workspace_changesets leaves them out. |
| compared | Yes | True when the comparison is complete and changes and conflicts are known. |
| conflicts | No | The paths that conflict, when state is conflicted. |
| no_change | No | True when the worker changed no files. |
| created_at | Yes | When the changeset was submitted. |
| updated_at | Yes | When the changeset last changed. |
| auto_accept | No | Set only for a changeset whose comparison was clean and changed files: pending (the platform may still accept it), accepted (the platform accepted it) or abandoned (the platform stopped and will not accept it). |
| change_count | Yes | The number of changed paths. |
| changeset_id | Yes | The changeset UUID. |
| workspace_id | Yes | The Workspace UUID. |
| base_revision | Yes | The revision the worker's copy started from. |
| result_revision | No | The new current revision of the Workspace once an accepted changeset is saved. |
| terminal_reason | No | Why a failed changeset failed. |
| working_copy_id | Yes | The worker's copy that the changes come from. |
| changes_truncated | No | True when there are more than 500 changed paths. |
| incoming_revision | Yes | The worker's saved revision. read_workspace_file reads its files. |
| validation_evidence | No | The evidence given when the changeset was accepted. |
| comparison_current_revision | No | The Workspace revision the changes were compared with. accept_workspace_changeset takes it as expected_current_revision. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, idempotentHint=true, destructiveHint=true) it discloses the save_state ready precondition and the exact refusal code 409 workspace_worker_not_saved, the asynchronous comparison that runs after the call returns, and the state of the Workspace's own files. It also refines idempotency beyond the flat hint: resubmission against an unchanged revision returns the same changeset, but a changed current revision produces a new one. The statement that Workspace files do not change sits alongside destructiveHint=true without directly contradicting it, since a changeset object is created.
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 layers preconditions, error behavior, and lifecycle in a logical order; nothing is irrelevant. It is dense and long-winded in places (the auto-submission digression and the final revision-explainer), but the length is defensible for an async, stateful operation.
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 an output schema present, the description needn't document return values, and it still covers everything else an agent needs: when to call, when not to, the blocking precondition, the failure code, the post-call polling contract, and revision-sensitive idempotency. The full lifecycle from submit through accept/reject is traceable from this text.
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 documented in the schema, so the baseline is 3. The description contextualizes worker_request_id via get_workspace_worker and the save_state requirement, but adds no format or syntax detail 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?
Specific verb + resource + artifact: it submits a worker's saved files for review as a changeset and explicitly contrasts this with Plori's own automatic submission, so an agent can separate it from get_workspace_changeset/list_workspace_changesets. The scope statement ('compares them with the Workspace's current files') pins down exactly what the operation produces.
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 when-to-use condition: only for a worker whose change_status is still unsubmitted after a run ended in error, was cancelled, was stopped, or after phase recompare_required. It also states the normal-run path where Plori submits on its own, which is the key exclude condition, and names the follow-up tools (poll get_workspace_changeset, then accept/reject).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upload_workspace_fileUpload Workspace fileADestructiveInspect
Write a file into a Workspace's current files, replacing any file at path. For UTF-8 text up to 262144 bytes, pass it as content: the file is written before the call returns. For a larger or binary file, omit content: the call returns upload_url and a curl command that uploads one local file of up to 33554432 bytes (32 MiB). Run the command in a shell within 10 minutes. The URL needs no other credential and accepts one upload. While a run uses the Workspace's files, the write is refused with 409 agent_busy. Try again after the run ends. Members and viewers of a shared Workspace cannot write files (403).
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | The file's path, relative to the Workspace root, for example docs/notes.md. Missing directories are created. | |
| content | No | The file's UTF-8 text, up to 262144 bytes. Omit it, or pass an empty string, to get an upload URL instead. | |
| workspace_id | Yes | The Workspace UUID. |
Output Schema
| Name | Required | Description |
|---|---|---|
| path | Yes | The file's path, from the Workspace root. |
| size | No | The bytes written, when written is true. |
| command | No | The curl command that uploads the file: replace LOCAL_FILE with the local file's path and run it in a shell. |
| written | Yes | True when content was written to the file. False when the call returned an upload URL instead. |
| max_bytes | No | The largest file upload_url accepts, in bytes. |
| expires_at | No | When upload_url stops being accepted. |
| upload_url | No | The URL that accepts one upload of the file as multipart form part file. It needs no other credential. |
| workspace_id | Yes | The Workspace UUID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the safety profile (destructive, non-idempotent); the description adds substantial context beyond them — overwrite behavior, exact byte limits, a 10-minute/one-shot unauthenticated upload URL, and the 409 agent_busy conflict with retry guidance. This is the full behavioral picture an agent needs before invoking.
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?
Dense but every sentence carries a distinct operational fact (mode, size limits, URL lifetime, conflict, permission), and the core write action is front-loaded ahead of the edge cases.
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?
An output schema exists, so return values need no explanation here; the description instead covers the non-obvious prerequisites and failure modes. For a destructive write with three parameters, nothing 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 coverage is 100%, so the baseline would be 3, but the description adds genuine mode-selection semantics: omitting or emptying content switches the tool to returning upload_url rather than writing, with the size threshold that decides it. The schema documents fields individually but not this cross-parameter 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?
States a specific verb and resource ('Write a file into a Workspace's current files') plus the overwrite semantic ('replacing any file at path'). This clearly distinguishes it from the sibling read_workspace_file without needing to open 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?
Explicitly splits usage into two modes and names the condition that selects each: pass content for UTF-8 text up to 262144 bytes, omit content for larger or binary files. It also names failure conditions (409 agent_busy while a run uses files, 403 for members/viewers) and the retry action, leaving nothing to inference.
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.
42 tool updates
v0.17.1- Added
accept_workspace_changeset - Changed
answer_pending_input8 fields changed- changed
Input schema / properties / approved / descriptionPrevious value: -"For an approval request: set false to deny. Only the owner can approve in the Plori web app."New value: +"false denies an approval request. true is refused: only the account owner approves, in the Plori web app." - changed
Input schema / properties / max_turn_seconds / descriptionPrevious value: -"Optional soft wall-clock budget to preserve on the continuation run; it does not change the parked run or impose a hard deadline."New value: +"Optional wall-clock budget for the continuation run, in seconds. It does not change the paused run; when it runs out the agent is told to finish and reply." - changed
Input schema / properties / run_id / descriptionPrevious value: -"The parked run's id."New value: +"The paused run's run_id." - changed
Input schema / properties / tool_call_id / descriptionPrevious value: -"The tool_call_id of the pending request (from list_pending_inputs)."New value: +"The tool_call_id of the approval request or question, from the run result or list_pending_inputs." - changed
Input schema / properties / value / descriptionPrevious value: -"For an input request: the value to supply."New value: +"The answer to a question." - added
Output schema / properties / continuation_errorAdded value: +{ + "description": "Why the continuation has not started or will not start, when the platform recorded a reason. The answer stays recorded.", + "type": "string" +} - added
Output schema / properties / continuation_pendingAdded value: +{ + "description": "True when the answer is recorded but its continuation run has not started yet: the paused run's files are still being saved, or continuation_error says what delays it. The run starts without another call; get_run_result on the paused run then reports it as continuation_run_id.", + "type": "boolean" +} - changed
Output schema / properties / run_id / descriptionPrevious value: -"The continuation run created by the answer."New value: +"The continuation run that continues the task after this answer; poll it with get_run_result. Absent while continuation_pending is true."
- Changed
cancel_run4 fields changed- changed
Input schema / properties / agent_id / descriptionPrevious value: -"The agent's UUID."New value: +"The agent that runs the run (agent_id in the run result). Give this or workspace_id." - changed
Input schema / properties / run_id / descriptionPrevious value: -"The run id returned by invoke_agent."New value: +"The run to cancel." - added
Input schema / properties / workspace_idAdded value: +{ + "description": "The Workspace the run belongs to. Give this or agent_id; with both, agent_id is used.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "agent_id", - "run_id" -]New value: +[ + "run_id" +]
- Removed
create_agent - Removed
create_workflow - Added
create_workspace - Added
create_workspace_worker - Removed
delete_agent - Added
delete_workspace - Removed
edit_workflow - Removed
empty_trash - Removed
get_agent - Changed
get_credits3 fields changed- added
Output schema / properties / audience / descriptionAdded value: +"anon: an anonymous trial; registered_free: a registered account without an active subscription; subscribed: an account with an active subscription." - added
Output schema / properties / can_manage_billing / descriptionAdded value: +"Whether this account has a billing portal to manage its subscription (it has, or had, a plan); false for an anonymous trial." - changed
Output schema / properties / limits / properties / max_concurrent_runs / descriptionPrevious value: -"How many agent runs this plan tier may have in flight at once. 0 means unlimited."New value: +"How many agent runs this account may have in flight at once. Anonymous trials allow 2. All other accounts return 0 (unlimited)."
- Removed
get_disk - Changed
get_run_result25 fields changed- changed
Input schema / properties / agent_id / descriptionPrevious value: -"The agent's UUID."New value: +"The agent that ran the run (agent_id in the result that returned the run_id). Give this or workspace_id." - changed
Input schema / properties / run_id / descriptionPrevious value: -"The run id returned by invoke_agent."New value: +"The run_id to read: from a run result, continuation_run_id or resume_run_id." - changed
Input schema / properties / wait / descriptionPrevious value: -"When true, wait for a terminal result or human input (see this tool's description for how long the hold lasts). After this tool returns, continue polling while status is non-terminal; it cannot wake an idle client."New value: +"true: hold this call until the run finishes, pauses for a person, or the hold ends (25 seconds by default, 50 seconds for Codex, up to 30 minutes for Claude Code 2.1.212 or later, at most 50 seconds without an MCP progressToken), then return the current state. false or omitted: return the current state at once." - changed
Input schema / properties / wait_seconds / descriptionPrevious value: -"Optional: how many seconds to wait when wait=true (maximum 1800). Omit to use the window your MCP client can hold."New value: +"Hold length in seconds when wait is true, used instead of the client default. 0 or omitted uses the client default. A call without an MCP progressToken is still held at most 50 seconds." - added
Input schema / properties / workspace_idAdded value: +{ + "description": "The Workspace the run belongs to. Give this or agent_id; with both, agent_id is used.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "agent_id", - "run_id" -]New value: +[ + "run_id" +] - added
Output schema / properties / agent_idAdded value: +{ + "description": "The agent that runs the run. get_run_result and cancel_run take this value or workspace_id.", + "type": "string" +} - added
Output schema / properties / continuation_errorAdded value: +{ + "description": "Why the answered message has not started its continuation.", + "type": "string" +} - added
Output schema / properties / continuation_pendingAdded value: +{ + "description": "The answer was recorded and its continuation has not started yet. Retry this message with the same idempotency key to get the continuation.", + "type": "boolean" +} - added
Output schema / properties / file_sourceAdded value: +{ + "additionalProperties": false, + "description": "Where this run's file links read from and whether its files are saved. Execution status does not report the save; check state here.", + "properties": { + "agent_id": { + "description": "The Agent whose current files a pre-conversion run's links read.", + "type": "string" + }, + "saved_operation_id": { + "description": "The save operation that produced saved_revision_id.", + "type": "string" + }, + "saved_revision_id": { + "description": "The immutable revision the run's copy was saved as. Empty until the save is ready.", + "type": "string" + }, + "source": { + "description": "agent_current_files for a pre-conversion run: links read the Agent's mutable current files, and later edits change their bytes. Absent for a Workspace run.", + "type": "string" + }, + "state": { + "description": "Where this run's file links read from. pending: the run's exact working copy, while its save is in progress. ready: the immutable saved revision for a Workspace run, or the Agent's current files when source is agent_current_files. failed: the save failed; see save_failure. unavailable: no readable source is recorded. expired: the saved revision was deleted or the run's history expired.", + "type": "string" + }, + "working_copy_id": { + "description": "The working copy the run executed on.", + "type": "string" + }, + "workspace_id": { + "description": "The Workspace a Workspace run executed in.", + "type": "string" + } + }, + "required": [ + "state" + ], + "type": [ + "null", + "object" + ] +} - changed
Output schema / properties / files / descriptionPrevious value: -"Files on the agent's disk that this reply linked, in the order they appear. Each url is fetchable with the bearer token you called this tool with. Absent when the reply linked none."New value: +"Files in the Workspace files that this reply linked, in the order they appear. Each url is fetchable with the bearer token you called this tool with. Absent when the reply linked none." - changed
Output schema / properties / files / items / properties / path / descriptionPrevious value: -"The file's path on the agent's disk, rooted at the disk root."New value: +"The file's path in the Workspace files, rooted at the Workspace root." - changed
Output schema / properties / files / items / properties / url / descriptionPrevious value: -"An absolute URL that streams the file's bytes, text or binary and of any size, with its own content type. Fetch it with the same bearer token you called this tool with."New value: +"An absolute URL that streams the file's bytes, text or binary and of any size, with its own content type. Fetch it with the same bearer token you called this tool with. Absent when file_source.state is failed, unavailable or expired: the file has no readable source." - changed
Output schema / properties / files / items / requiredPrevious value: -[ - "path", - "url" -]New value: +[ + "path" +] - changed
Output schema / properties / input_expired / descriptionPrevious value: -"True when this run is parked on a question its session has already moved past: a later run in the same conversation has completed. Do not answer it; start a new run instead."New value: +"True when this run is paused on a question its conversation has already moved past: a later run in the same conversation has completed. Do not answer it; start a new run instead." - added
Output schema / properties / pending_inputs / items / properties / assigned_toAdded value: +{ + "additionalProperties": false, + "properties": { + "email": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "user_id", + "email" + ], + "type": [ + "null", + "object" + ] +} - added
Output schema / properties / pending_inputs / items / properties / open_to_members_atAdded value: +{ + "type": [ + "null", + "string" + ] +} - changed
Output schema / properties / pending_inputs / items / requiredPrevious value: -[ - "tool_call_id", - "kind", - "prompt" -]New value: +[ + "assigned_to", + "tool_call_id", + "kind", + "prompt" +] - changed
Output schema / properties / poll_after_ms / descriptionPrevious value: -"Legacy spelling of poll_after_seconds in milliseconds; the two always agree. Prefer poll_after_seconds."New value: +"The same wait as poll_after_seconds, in milliseconds." - changed
Output schema / properties / retryable / descriptionPrevious value: -"Whether sending the same message again could plausibly succeed. False for a cause the same request would hit again, including time_limit — split the work or raise max_turn_seconds instead of retrying it unchanged."New value: +"Whether sending the same message again could plausibly succeed. A time_limit run can continue with a follow-up message." - changed
Output schema / properties / run_id / descriptionPrevious value: -"The public run identifier."New value: +"The public run identifier; empty for an answered message whose continuation has not started." - added
Output schema / properties / save_failureAdded value: +{ + "additionalProperties": false, + "description": "Present when saving the run's working copy failed, so its files are not durable outputs. code names the failure. content_refusals lists up to three refused paths, relative to the copy root, each with its cause: hardlink, database_backup_required (a SQLite file that needs sqlite3 .backup) or unsupported_file_mode.", + "properties": { + "code": { + "type": "string" + }, + "content_refusals": { + "items": { + "additionalProperties": false, + "properties": { + "cause": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "cause", + "path" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + } + }, + "required": [ + "code" + ], + "type": [ + "null", + "object" + ] +} - changed
Output schema / properties / status / descriptionPrevious value: -"The current run status."New value: +"The current run status, queued/steering for a message accepted into an active conversation, or answered when the answer is recorded but its continuation has not started." - added
Output schema / properties / steer_idAdded value: +{ + "description": "Durable message receipt when status is queued or steering. run_id names the running or paused predecessor, not a result of this message; find the later queued turn with list_runs.", + "type": "string" +} - added
Output schema / properties / workspace_idAdded value: +{ + "description": "The Workspace UUID.", + "type": "string" +}
- Removed
get_usage - Removed
get_workflow - Removed
get_workflow_execution - Removed
get_workflow_version - Added
get_workspace_changeset - Added
get_workspace_costs - Added
get_workspace_worker - Removed
invoke_agent - Removed
list_agents - Removed
list_connections - Changed
list_pending_inputs12 fields changed- changed
Input schema / properties / agent_id / descriptionPrevious value: -"The agent's UUID."New value: +"The agent UUID (agent_id in a run result). Give this or workspace_id." - added
Input schema / properties / workspace_idAdded value: +{ + "description": "The Workspace UUID. Give this or agent_id; with both, agent_id is used. Covers the runs of the Workspace's agent and its workers.", + "type": "string" +} - removed
Input schema / requiredRemoved value: -[ - "agent_id" -] - changed
Output schema / properties / pending_inputs / descriptionPrevious value: -"Runs currently parked on a human approval or input request. A request whose session has already moved on is left out: answering it would resume a superseded turn."New value: +"Runs currently paused on a human approval or input request. A request whose session has already moved on is left out: answering it would resume a superseded turn." - added
Output schema / properties / pending_inputs / items / properties / agent_nameAdded value: +{ + "type": "string" +} - changed
Output schema / properties / pending_inputs / items / properties / args / descriptionPrevious value: -"Arbitrary JSON owned by the producing engine."New value: +"Extra data recorded with the request; not needed to use it." - added
Output schema / properties / pending_inputs / items / properties / assigned_toAdded value: +{ + "additionalProperties": false, + "properties": { + "email": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "user_id", + "email" + ], + "type": [ + "null", + "object" + ] +} - added
Output schema / properties / pending_inputs / items / properties / can_actAdded value: +{ + "type": "boolean" +} - added
Output schema / properties / pending_inputs / items / properties / open_to_members_atAdded value: +{ + "type": "string" +} - changed
Output schema / properties / pending_inputs / items / properties / schema / descriptionPrevious value: -"Arbitrary JSON owned by the producing engine."New value: +"Extra data recorded with the request; not needed to use it." - added
Output schema / properties / pending_inputs / items / properties / worker_request_idAdded value: +{ + "type": [ + "null", + "string" + ] +} - changed
Output schema / properties / pending_inputs / items / requiredPrevious value: -[ - "id", - "run_id", - "agent_id", - "tool_call_id", - "kind", - "prompt", - "status", - "created_at" -]New value: +[ + "assigned_to", + "open_to_members_at", + "can_act", + "id", + "run_id", + "agent_id", + "tool_call_id", + "kind", + "prompt", + "status", + "created_at" +]
- Changed
list_runs9 fields changed- changed
Input schema / properties / agent_id / descriptionPrevious value: -"The agent's UUID."New value: +"The agent UUID (agent_id in a run result). Give this or workspace_id." - added
Input schema / properties / workspace_idAdded value: +{ + "description": "The Workspace UUID. Give this or agent_id; with both, agent_id is used. Lists the runs of its main conversation and of the Workspace's agent: the 100 newest, plus runs still running or paused. list_workspace_workers lists the workers' runs.", + "type": "string" +} - removed
Input schema / requiredRemoved value: -[ - "agent_id" -] - added
Output schema / properties / items / items / properties / events_expired_atAdded value: +{ + "type": [ + "null", + "string" + ] +} - added
Output schema / properties / items / items / properties / history_errorAdded value: +{ + "type": "string" +} - added
Output schema / properties / items / items / properties / private_history_expired_atAdded value: +{ + "type": [ + "null", + "string" + ] +} - added
Output schema / properties / items / items / properties / retention_policyAdded value: +{ + "description": "Extra data recorded with the request; not needed to use it." +} - added
Output schema / properties / items / items / properties / save_failureAdded value: +{ + "additionalProperties": false, + "properties": { + "code": { + "type": "string" + }, + "content_refusals": { + "items": { + "additionalProperties": false, + "properties": { + "cause": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": [ + "cause", + "path" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + } + }, + "required": [ + "code" + ], + "type": [ + "null", + "object" + ] +} - changed
Output schema / properties / items / items / properties / session_id / descriptionPrevious value: -"The conversation this run belongs to; pass it to invoke_agent as session_id to continue it. Identical to thread_id."New value: +"The conversation this run belongs to; pass it to send_workspace_message as session_id to continue it. Identical to thread_id."
- Removed
list_workflow_executions - Removed
list_workflows - Added
list_workspace_changesets - Added
list_workspace_workers - Added
list_workspaces - Added
read_workspace_file - Added
reject_workspace_changeset - Removed
run_workflow - Changed
schedule_run18 fields changed- changed
Input schema / properties / agent_id / descriptionPrevious value: -"The agent's UUID."New value: +"The agent's UUID. Give this or workspace_id." - changed
Input schema / properties / session_id / descriptionPrevious value: -"Optional thread/session id to deliver the scheduled run into."New value: +"A conversation of the agent to deliver the scheduled run into (session_id from an earlier result). Omitted, the conversation the agent is running in when the request is made, or a new conversation when it is idle." - added
Input schema / properties / workspace_idAdded value: +{ + "description": "The Workspace UUID; the Workspace's agent runs the prompt. Give this or agent_id; with both, agent_id is used.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "agent_id", - "prompt" -]New value: +[ + "prompt" +] - added
Output schema / properties / agent_id / descriptionAdded value: +"The agent the run is scheduled for." - added
Output schema / properties / attempts / descriptionAdded value: +"Delivery attempts so far." - added
Output schema / properties / confirm_url / descriptionAdded value: +"Where the owner confirms, in the Plori web app." - added
Output schema / properties / confirmed_at / descriptionAdded value: +"When the owner confirmed it." - added
Output schema / properties / created_at / descriptionAdded value: +"When the request was made." - added
Output schema / properties / fire_at / descriptionAdded value: +"When it fires, RFC 3339." - added
Output schema / properties / id / descriptionAdded value: +"The schedule's id." - added
Output schema / properties / kind / descriptionAdded value: +"once: a single run at fire_at." - added
Output schema / properties / last_error / descriptionAdded value: +"Why the last delivery attempt failed, when it did." - added
Output schema / properties / last_fired_at / descriptionAdded value: +"When it last fired." - changed
Output schema / properties / metadata / descriptionPrevious value: -"Arbitrary JSON owned by the producing engine."New value: +"Extra data recorded with the request; not needed to use it." - added
Output schema / properties / prompt / descriptionAdded value: +"The message the agent receives when the schedule fires." - added
Output schema / properties / status / descriptionAdded value: +"awaiting_confirmation until the owner confirms at confirm_url; pending once armed; firing or dispatched while delivery is in progress; done once the run starts; cancelled or failed otherwise." - added
Output schema / properties / thread_id / descriptionAdded value: +"The conversation the run is delivered into: the session_id given, else the conversation the agent was running in when the request was made, else a new one."
- Added
send_workspace_message - Removed
set_workflow_agent - Added
steer_workspace_worker - Added
stop_workspace_task_group - Added
submit_workspace_changeset - Added
upload_workspace_file
7 tool updates
v0.17.0- Changed
answer_pending_input3 fields changed- removed
Input schema / properties / always_allowRemoved value: -{ - "description": "Approve AND stop asking for this tool on this agent (a standing grant). Only set it when the human explicitly said to stop being asked, and only on a row whose consent_tool is set; ignored without approved=true. Revoke via DELETE /v1/agents/{agent_id}/tool-consents/{tool}.", - "type": "boolean" -} - changed
Input schema / properties / approved / descriptionPrevious value: -"For an approval request: approve (true) or deny (false)."New value: +"For an approval request: set false to deny. Only the owner can approve in the Plori web app." - removed
Input schema / properties / scopeRemoved value: -{ - "description": "Set to \"thread\" to approve AND allow the rest of this conversation's writes to the same connection, method and host, instead of a standing grant. It expires after 24 hours and covers no other host, method or conversation. Only set it when the human said to stop being asked for the rest of this task; ignored without approved=true, and on a card that has no such scope. Cannot be combined with always_allow.", - "type": "string" -}
- Changed
empty_trash1 field changed- added
Output schema / properties / disk / properties / agentsAdded value: +{ + "description": "The account's Agents that have a disk, largest used_bytes first: where the account's usage is and how much of each Agent's is trash.", + "items": { + "additionalProperties": false, + "properties": { + "agent_id": { + "description": "The Agent's UUID.", + "type": "string" + }, + "agent_name": { + "description": "The Agent's name.", + "type": "string" + }, + "asleep": { + "description": "True when the Agent has no running session, which emptying its trash requires.", + "type": [ + "null", + "boolean" + ] + }, + "trash_bytes": { + "description": "How much of used_bytes emptying this Agent's trash would free. Absent when it has not been measured.", + "type": [ + "null", + "integer" + ] + }, + "used_bytes": { + "description": "Bytes this Agent's disk holds, trash included.", + "type": "integer" + } + }, + "required": [ + "agent_id", + "agent_name", + "used_bytes" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] +}
- Changed
get_disk1 field changed- added
Output schema / properties / agentsAdded value: +{ + "description": "The account's Agents that have a disk, largest used_bytes first: where the account's usage is and how much of each Agent's is trash.", + "items": { + "additionalProperties": false, + "properties": { + "agent_id": { + "description": "The Agent's UUID.", + "type": "string" + }, + "agent_name": { + "description": "The Agent's name.", + "type": "string" + }, + "asleep": { + "description": "True when the Agent has no running session, which emptying its trash requires.", + "type": [ + "null", + "boolean" + ] + }, + "trash_bytes": { + "description": "How much of used_bytes emptying this Agent's trash would free. Absent when it has not been measured.", + "type": [ + "null", + "integer" + ] + }, + "used_bytes": { + "description": "Bytes this Agent's disk holds, trash included.", + "type": "integer" + } + }, + "required": [ + "agent_id", + "agent_name", + "used_bytes" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] +}
- Changed
get_run_result1 field changed- added
Output schema / properties / pending_inputs / items / properties / approve_urlAdded value: +{ + "type": "string" +}
- Changed
invoke_agent1 field changed- added
Output schema / properties / pending_inputs / items / properties / approve_urlAdded value: +{ + "type": "string" +}
- Changed
list_pending_inputs1 field changed- added
Output schema / properties / pending_inputs / items / properties / approve_urlAdded value: +{ + "type": "string" +}
- Changed
schedule_run2 fields changed- added
Output schema / properties / confirm_urlAdded value: +{ + "type": "string" +} - added
Output schema / properties / confirmed_atAdded value: +{ + "type": [ + "null", + "string" + ] +}
7 tool updates
v0.16.2- Changed
create_agent2 fields changed- added
Output schema / properties / advisor_max_spend_micro_usdAdded value: +{ + "description": "Optional maximum advisor-completion spend per turn in micro-US-dollars. Zero disables advisor completions; null leaves no spend cap.", + "type": [ + "null", + "integer" + ] +} - changed
Output schema / requiredPrevious value: -[ - "id", - "user_id", - "name", - "backend", - "model", - "effective_model", - "config", - "created_at" -]New value: +[ + "id", + "user_id", + "name", + "backend", + "model", + "advisor_max_spend_micro_usd", + "effective_model", + "config", + "created_at" +]
- Changed
get_agent2 fields changed- added
Output schema / properties / advisor_max_spend_micro_usdAdded value: +{ + "description": "Optional maximum advisor-completion spend per turn in micro-US-dollars. Zero disables advisor completions; null leaves no spend cap.", + "type": [ + "null", + "integer" + ] +} - changed
Output schema / requiredPrevious value: -[ - "id", - "user_id", - "name", - "backend", - "model", - "effective_model", - "config", - "created_at", - "mailbox" -]New value: +[ + "id", + "user_id", + "name", + "backend", + "model", + "advisor_max_spend_micro_usd", + "effective_model", + "config", + "created_at", + "mailbox" +]
- Changed
get_run_result3 fields changed- added
Output schema / properties / advisorAdded value: +{ + "additionalProperties": false, + "description": "Advisor calls used and allowed, spend this turn, and its optional spend cap in micro-US-dollars.", + "properties": { + "calls_allowed": { + "type": "integer" + }, + "calls_used": { + "type": "integer" + }, + "spend_cap_micro_usd": { + "type": [ + "null", + "integer" + ] + }, + "spend_micro_usd": { + "description": "Gross advisor consumption for the turn; the cap compares against this amount.", + "type": "integer" + } + }, + "required": [ + "calls_used", + "calls_allowed", + "spend_micro_usd" + ], + "type": "object" +} - added
Output schema / properties / error / properties / upgradeAdded value: +{ + "additionalProperties": false, + "description": "Which plan lifts the limit this run ended at, when it ended at one.", + "properties": { + "anonymous": { + "type": "boolean" + }, + "limit": { + "type": "string" + }, + "message": { + "type": "string" + }, + "offer": { + "additionalProperties": false, + "properties": { + "discount_code": { + "type": "string" + }, + "first_period_price_micro_usd": { + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "discount_code", + "first_period_price_micro_usd", + "message" + ], + "type": [ + "null", + "object" + ] + }, + "plan": { + "type": "string" + }, + "remedies": { + "items": { + "additionalProperties": false, + "properties": { + "kind": { + "type": "string" + }, + "limits": { + "additionalProperties": false, + "properties": { + "disk_gb": { + "type": "integer" + }, + "max_active_workflows": { + "type": "integer" + }, + "max_agents": { + "type": "integer" + }, + "max_concurrent_runs": { + "type": "integer" + } + }, + "required": [ + "max_concurrent_runs", + "max_agents", + "max_active_workflows", + "disk_gb" + ], + "type": [ + "null", + "object" + ] + }, + "message": { + "type": "string" + }, + "offer": { + "additionalProperties": false, + "properties": { + "discount_code": { + "type": "string" + }, + "first_period_price_micro_usd": { + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "discount_code", + "first_period_price_micro_usd", + "message" + ], + "type": [ + "null", + "object" + ] + }, + "plan": { + "type": "string" + }, + "url": { + "type": "string" + }, + "usd_cents_per_month": { + "type": "integer" + } + }, + "required": [ + "kind", + "message" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "url": { + "type": "string" + } + }, + "required": [ + "limit", + "plan", + "message", + "remedies" + ], + "type": [ + "null", + "object" + ] +} - added
Output schema / properties / usage_by_roleAdded value: +{ + "additionalProperties": false, + "description": "Attributed spend, tokens, and model-call counts split into executor, advisor, and reviewer roles.", + "properties": { + "advisor": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + }, + "executor": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + }, + "reviewer": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + } + }, + "required": [ + "executor", + "advisor", + "reviewer" + ], + "type": [ + "null", + "object" + ] +}
- Changed
get_usage11 fields changed- added
Output schema / properties / by_roleAdded value: +{ + "additionalProperties": false, + "properties": { + "advisor": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + }, + "executor": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + }, + "reviewer": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + } + }, + "required": [ + "executor", + "advisor", + "reviewer" + ], + "type": "object" +} - added
Output schema / properties / recent_runs / items / properties / advisorAdded value: +{ + "additionalProperties": false, + "description": "Gross advisor consumption for the turn; the cap compares against this amount.", + "properties": { + "calls_allowed": { + "type": "integer" + }, + "calls_used": { + "type": "integer" + }, + "spend_cap_micro_usd": { + "type": [ + "null", + "integer" + ] + }, + "spend_micro_usd": { + "description": "Gross advisor consumption for the turn; the cap compares against this amount.", + "type": "integer" + } + }, + "required": [ + "calls_used", + "calls_allowed", + "spend_micro_usd" + ], + "type": "object" +} - added
Output schema / properties / recent_runs / items / properties / credits / descriptionAdded value: +"The net charge after any refund." - added
Output schema / properties / recent_runs / items / properties / error / properties / upgradeAdded value: +{ + "additionalProperties": false, + "description": "Which plan lifts the limit this run ended at, when it ended at one.", + "properties": { + "anonymous": { + "type": "boolean" + }, + "limit": { + "type": "string" + }, + "message": { + "type": "string" + }, + "offer": { + "additionalProperties": false, + "properties": { + "discount_code": { + "type": "string" + }, + "first_period_price_micro_usd": { + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "discount_code", + "first_period_price_micro_usd", + "message" + ], + "type": [ + "null", + "object" + ] + }, + "plan": { + "type": "string" + }, + "remedies": { + "items": { + "additionalProperties": false, + "properties": { + "kind": { + "type": "string" + }, + "limits": { + "additionalProperties": false, + "properties": { + "disk_gb": { + "type": "integer" + }, + "max_active_workflows": { + "type": "integer" + }, + "max_agents": { + "type": "integer" + }, + "max_concurrent_runs": { + "type": "integer" + } + }, + "required": [ + "max_concurrent_runs", + "max_agents", + "max_active_workflows", + "disk_gb" + ], + "type": [ + "null", + "object" + ] + }, + "message": { + "type": "string" + }, + "offer": { + "additionalProperties": false, + "properties": { + "discount_code": { + "type": "string" + }, + "first_period_price_micro_usd": { + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "discount_code", + "first_period_price_micro_usd", + "message" + ], + "type": [ + "null", + "object" + ] + }, + "plan": { + "type": "string" + }, + "url": { + "type": "string" + }, + "usd_cents_per_month": { + "type": "integer" + } + }, + "required": [ + "kind", + "message" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "url": { + "type": "string" + } + }, + "required": [ + "limit", + "plan", + "message", + "remedies" + ], + "type": [ + "null", + "object" + ] +} - added
Output schema / properties / recent_runs / items / properties / gross_micro_usdAdded value: +{ + "description": "Gross consumption before any refund.", + "type": "integer" +} - added
Output schema / properties / recent_runs / items / properties / refund_reasonAdded value: +{ + "type": "string" +} - added
Output schema / properties / recent_runs / items / properties / refund_withheld_reasonAdded value: +{ + "type": "string" +} - added
Output schema / properties / recent_runs / items / properties / refunded_micro_usdAdded value: +{ + "description": "The refund reported once for this run.", + "type": "integer" +} - added
Output schema / properties / recent_runs / items / properties / usage_by_roleAdded value: +{ + "additionalProperties": false, + "description": "Gross consumption by role; credits sum to gross_micro_usd and refunds appear only in refunded_micro_usd.", + "properties": { + "advisor": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + }, + "executor": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + }, + "reviewer": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + } + }, + "required": [ + "executor", + "advisor", + "reviewer" + ], + "type": [ + "null", + "object" + ] +} - changed
Output schema / properties / recent_runs / items / requiredPrevious value: -[ - "id", - "agent_id", - "thread_id", - "session_id", - "status", - "origin", - "started_at", - "credits", - "tokens", - "tool_progress" -]New value: +[ + "id", + "agent_id", + "thread_id", + "session_id", + "status", + "origin", + "started_at", + "credits", + "tokens", + "advisor", + "tool_progress" +] - changed
Output schema / requiredPrevious value: -[ - "totals", - "by_kind", - "tools", - "agents", - "workflows", - "workflow_executions", - "recent_runs" -]New value: +[ + "totals", + "by_role", + "by_kind", + "tools", + "agents", + "workflows", + "workflow_executions", + "recent_runs" +]
- Changed
invoke_agent4 fields changed- added
Input schema / properties / max_advisor_spend_micro_usdAdded value: +{ + "description": "Optional maximum advisor-completion spend for this turn in micro-US-dollars. 0 disables advisor completions. Omit it to use the agent setting; when neither is set, at most two advisor calls can run. The maximum is 5,000,000.", + "maximum": 5000000, + "minimum": 0, + "type": "integer" +} - added
Output schema / properties / advisorAdded value: +{ + "additionalProperties": false, + "description": "Advisor calls used and allowed, spend this turn, and its optional spend cap in micro-US-dollars.", + "properties": { + "calls_allowed": { + "type": "integer" + }, + "calls_used": { + "type": "integer" + }, + "spend_cap_micro_usd": { + "type": [ + "null", + "integer" + ] + }, + "spend_micro_usd": { + "description": "Gross advisor consumption for the turn; the cap compares against this amount.", + "type": "integer" + } + }, + "required": [ + "calls_used", + "calls_allowed", + "spend_micro_usd" + ], + "type": "object" +} - added
Output schema / properties / error / properties / upgradeAdded value: +{ + "additionalProperties": false, + "description": "Which plan lifts the limit this run ended at, when it ended at one.", + "properties": { + "anonymous": { + "type": "boolean" + }, + "limit": { + "type": "string" + }, + "message": { + "type": "string" + }, + "offer": { + "additionalProperties": false, + "properties": { + "discount_code": { + "type": "string" + }, + "first_period_price_micro_usd": { + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "discount_code", + "first_period_price_micro_usd", + "message" + ], + "type": [ + "null", + "object" + ] + }, + "plan": { + "type": "string" + }, + "remedies": { + "items": { + "additionalProperties": false, + "properties": { + "kind": { + "type": "string" + }, + "limits": { + "additionalProperties": false, + "properties": { + "disk_gb": { + "type": "integer" + }, + "max_active_workflows": { + "type": "integer" + }, + "max_agents": { + "type": "integer" + }, + "max_concurrent_runs": { + "type": "integer" + } + }, + "required": [ + "max_concurrent_runs", + "max_agents", + "max_active_workflows", + "disk_gb" + ], + "type": [ + "null", + "object" + ] + }, + "message": { + "type": "string" + }, + "offer": { + "additionalProperties": false, + "properties": { + "discount_code": { + "type": "string" + }, + "first_period_price_micro_usd": { + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "discount_code", + "first_period_price_micro_usd", + "message" + ], + "type": [ + "null", + "object" + ] + }, + "plan": { + "type": "string" + }, + "url": { + "type": "string" + }, + "usd_cents_per_month": { + "type": "integer" + } + }, + "required": [ + "kind", + "message" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "url": { + "type": "string" + } + }, + "required": [ + "limit", + "plan", + "message", + "remedies" + ], + "type": [ + "null", + "object" + ] +} - added
Output schema / properties / usage_by_roleAdded value: +{ + "additionalProperties": false, + "description": "Attributed spend, tokens, and model-call counts split into executor, advisor, and reviewer roles.", + "properties": { + "advisor": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + }, + "executor": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + }, + "reviewer": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + } + }, + "required": [ + "executor", + "advisor", + "reviewer" + ], + "type": [ + "null", + "object" + ] +}
- Changed
list_agents2 fields changed- added
Output schema / properties / items / items / properties / advisor_max_spend_micro_usdAdded value: +{ + "description": "Optional maximum advisor-completion spend per turn in micro-US-dollars. Zero disables advisor completions; null leaves no spend cap.", + "type": [ + "null", + "integer" + ] +} - changed
Output schema / properties / items / items / requiredPrevious value: -[ - "id", - "user_id", - "name", - "backend", - "model", - "effective_model", - "config", - "created_at" -]New value: +[ + "id", + "user_id", + "name", + "backend", + "model", + "advisor_max_spend_micro_usd", + "effective_model", + "config", + "created_at" +]
- Changed
list_runs9 fields changed- added
Output schema / properties / items / items / properties / advisorAdded value: +{ + "additionalProperties": false, + "description": "Gross advisor consumption for the turn; the cap compares against this amount.", + "properties": { + "calls_allowed": { + "type": "integer" + }, + "calls_used": { + "type": "integer" + }, + "spend_cap_micro_usd": { + "type": [ + "null", + "integer" + ] + }, + "spend_micro_usd": { + "description": "Gross advisor consumption for the turn; the cap compares against this amount.", + "type": "integer" + } + }, + "required": [ + "calls_used", + "calls_allowed", + "spend_micro_usd" + ], + "type": "object" +} - added
Output schema / properties / items / items / properties / credits / descriptionAdded value: +"The net charge after any refund." - added
Output schema / properties / items / items / properties / error / properties / upgradeAdded value: +{ + "additionalProperties": false, + "description": "Which plan lifts the limit this run ended at, when it ended at one.", + "properties": { + "anonymous": { + "type": "boolean" + }, + "limit": { + "type": "string" + }, + "message": { + "type": "string" + }, + "offer": { + "additionalProperties": false, + "properties": { + "discount_code": { + "type": "string" + }, + "first_period_price_micro_usd": { + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "discount_code", + "first_period_price_micro_usd", + "message" + ], + "type": [ + "null", + "object" + ] + }, + "plan": { + "type": "string" + }, + "remedies": { + "items": { + "additionalProperties": false, + "properties": { + "kind": { + "type": "string" + }, + "limits": { + "additionalProperties": false, + "properties": { + "disk_gb": { + "type": "integer" + }, + "max_active_workflows": { + "type": "integer" + }, + "max_agents": { + "type": "integer" + }, + "max_concurrent_runs": { + "type": "integer" + } + }, + "required": [ + "max_concurrent_runs", + "max_agents", + "max_active_workflows", + "disk_gb" + ], + "type": [ + "null", + "object" + ] + }, + "message": { + "type": "string" + }, + "offer": { + "additionalProperties": false, + "properties": { + "discount_code": { + "type": "string" + }, + "first_period_price_micro_usd": { + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "discount_code", + "first_period_price_micro_usd", + "message" + ], + "type": [ + "null", + "object" + ] + }, + "plan": { + "type": "string" + }, + "url": { + "type": "string" + }, + "usd_cents_per_month": { + "type": "integer" + } + }, + "required": [ + "kind", + "message" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "url": { + "type": "string" + } + }, + "required": [ + "limit", + "plan", + "message", + "remedies" + ], + "type": [ + "null", + "object" + ] +} - added
Output schema / properties / items / items / properties / gross_micro_usdAdded value: +{ + "description": "Gross consumption before any refund.", + "type": "integer" +} - added
Output schema / properties / items / items / properties / refund_reasonAdded value: +{ + "type": "string" +} - added
Output schema / properties / items / items / properties / refund_withheld_reasonAdded value: +{ + "type": "string" +} - added
Output schema / properties / items / items / properties / refunded_micro_usdAdded value: +{ + "description": "The refund reported once for this run.", + "type": "integer" +} - added
Output schema / properties / items / items / properties / usage_by_roleAdded value: +{ + "additionalProperties": false, + "description": "Gross consumption by role; credits sum to gross_micro_usd and refunds appear only in refunded_micro_usd.", + "properties": { + "advisor": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + }, + "executor": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + }, + "reviewer": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "calls" + ], + "type": "object" + } + }, + "required": [ + "executor", + "advisor", + "reviewer" + ], + "type": [ + "null", + "object" + ] +} - changed
Output schema / properties / items / items / requiredPrevious value: -[ - "id", - "agent_id", - "thread_id", - "session_id", - "status", - "origin", - "started_at", - "credits", - "tokens", - "tool_progress" -]New value: +[ + "id", + "agent_id", + "thread_id", + "session_id", + "status", + "origin", + "started_at", + "credits", + "tokens", + "advisor", + "tool_progress" +]
26 tool updates
v0.16.0- Changed
answer_pending_input2 fields changed- added
Input schema / properties / scopeAdded value: +{ + "description": "Set to \"thread\" to approve AND allow the rest of this conversation's writes to the same connection, method and host, instead of a standing grant. It expires after 24 hours and covers no other host, method or conversation. Only set it when the human said to stop being asked for the rest of this task; ignored without approved=true, and on a card that has no such scope. Cannot be combined with always_allow.", + "type": "string" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "already": { + "description": "Whether this request had already been answered.", + "type": "boolean" + }, + "run_id": { + "description": "The continuation run created by the answer.", + "type": "string" + }, + "session_id": { + "description": "The continuation run's session.", + "type": "string" + }, + "status": { + "description": "Answer status.", + "type": "string" + }, + "tool_call_id": { + "description": "The pending tool call that was answered.", + "type": "string" + } + }, + "required": [ + "status", + "tool_call_id" + ], + "type": "object" +}
- Changed
cancel_run1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "runId": { + "description": "The run whose cancellation was requested.", + "type": "string" + }, + "status": { + "description": "Cancellation request status.", + "type": "string" + } + }, + "required": [ + "runId", + "status" + ], + "type": "object" +}
- Changed
create_agent2 fields changed- removed
Input schema / properties / modelRemoved value: -{ - "description": "Optional model slug; omitted uses the Plori Router, which picks the cheapest model that fits each task from the pool the account's plan unlocks. An explicit frontier model still requires a paid plan.", - "type": "string" -} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "backend": { + "description": "The compute backend this Agent runs on.", + "type": "string" + }, + "config": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "created_at": { + "description": "When the Agent was created.", + "type": "string" + }, + "deleting": { + "description": "True while this Agent's disk is still being erased; offer no action on it besides retrying the deletion itself.", + "type": "boolean" + }, + "deleting_since": { + "description": "When the deletion was first requested; present only while deleting is true.", + "type": [ + "null", + "string" + ] + }, + "effective_model": { + "description": "The model a run on this Agent will actually use. plori-auto means the hosted router chooses per turn.", + "type": "string" + }, + "existing": { + "description": "Whether create_agent returned an existing same-name agent instead of creating one.", + "type": "boolean" + }, + "id": { + "description": "The Agent's unique identifier; pass it to other tools as agent_id.", + "type": "string" + }, + "last_run_at": { + "description": "When this Agent last started a run; absent when it has never run.", + "type": [ + "null", + "string" + ] + }, + "model": { + "description": "The model slug this Agent is configured to use. Empty means no explicit choice, which is not the same as no model — read effective_model for what a run will actually use.", + "type": "string" + }, + "moving": { + "description": "True while this Agent's files are being copied to a new disk; check storage_notice rather than a separate route for the outcome.", + "type": "boolean" + }, + "name": { + "description": "The Agent's name, chosen by its owner and unique within the account.", + "type": "string" + }, + "queued_at": { + "description": "When a still-warming attach was accepted; present only while it is queued for node capacity.", + "type": [ + "null", + "string" + ] + }, + "status": { + "description": "The live warm-session state: warming, ready, or sleeping; empty when no session is active.", + "type": "string" + }, + "storage_notice": { + "description": "The one sentence, if any, telling the owner about a storage move that stopped; show it verbatim, not paraphrased.", + "type": "string" + }, + "url": { + "description": "This Agent's page in the plori web app.", + "type": "string" + }, + "user_id": { + "description": "The identifier of the account that owns this Agent.", + "type": "string" + } + }, + "required": [ + "id", + "user_id", + "name", + "backend", + "model", + "effective_model", + "config", + "created_at" + ], + "type": "object" +}
- Changed
create_workflow4 fields changed- changed
Input schema / properties / cron_expr / descriptionPrevious value: -"Cron schedule (required when trigger_kind is \"cron\"), e.g. \"0 9 * * *\"."New value: +"Cron schedule (required when trigger_kind is \"cron\"), e.g. \"0 9 * * *\". A 5-field cron or an @daily/@hourly descriptor, evaluated in UTC." - changed
Input schema / properties / description / descriptionPrevious value: -"Optional description of what the workflow does."New value: +"Optional description of what the workflow does. It is prose for the reader; no field is derived from it." - changed
Input schema / properties / trigger_kind / descriptionPrevious value: -"Optional trigger: \"manual\" (default), \"cron\", or \"webhook\"."New value: +"Optional trigger: \"manual\" (default), \"cron\", or \"webhook\". The build can change it later: a schedule or webhook trigger step sets it." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "active_version": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": [ + "null", + "integer" + ] + }, + "agent_deleted_at": { + "type": [ + "null", + "string" + ] + }, + "agent_id": { + "type": [ + "null", + "string" + ] + }, + "created_at": { + "type": "string" + }, + "cron_expr": { + "type": "string" + }, + "current_version": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "description": { + "type": "string" + }, + "engine": { + "type": "string" + }, + "hook_key": { + "type": [ + "null", + "string" + ] + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "next_fire_at": { + "type": [ + "null", + "string" + ] + }, + "notify_pref": { + "type": "string" + }, + "paused_reason": { + "type": "string" + }, + "spend_cap_month": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "template_slug": { + "type": "string" + }, + "trigger_kind": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "id", + "user_id", + "agent_id", + "name", + "description", + "engine", + "status", + "current_version", + "active_version", + "trigger_kind", + "cron_expr", + "next_fire_at", + "hook_key", + "spend_cap_month", + "notify_pref", + "created_at", + "updated_at" + ], + "type": "object" +}
- Changed
delete_agent1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "status": { + "description": "The successful HTTP status code from the underlying operation.", + "type": "integer" + }, + "workflows_paused": { + "description": "How many workflows this agent had built and had running were paused by the deletion. They are not deleted: assign them to another agent to run them again.", + "type": "integer" + } + }, + "required": [ + "status" + ], + "type": "object" +}
- Changed
edit_workflow1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "projection": { + "description": "The value-light projection of the edited workflow definition." + }, + "resolved": { + "description": "External identifiers resolved while binding the edit.", + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "note": { + "type": "string" + }, + "prop": { + "type": "string" + }, + "step": { + "type": "string" + }, + "title": { + "type": "string" + } + }, + "required": [ + "step", + "prop", + "id" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "version": { + "description": "The new draft version created by the edit.", + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "workflow_id": { + "description": "The edited workflow.", + "type": "string" + } + }, + "required": [ + "workflow_id", + "version", + "projection" + ], + "type": "object" +}
- Added
empty_trash - Changed
get_agent1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "backend": { + "description": "The compute backend this Agent runs on.", + "type": "string" + }, + "config": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "created_at": { + "description": "When the Agent was created.", + "type": "string" + }, + "deleting": { + "description": "True while this Agent's disk is still being erased; offer no action on it besides retrying the deletion itself.", + "type": "boolean" + }, + "deleting_since": { + "description": "When the deletion was first requested; present only while deleting is true.", + "type": [ + "null", + "string" + ] + }, + "effective_model": { + "description": "The model a run on this Agent will actually use. plori-auto means the hosted router chooses per turn.", + "type": "string" + }, + "id": { + "description": "The Agent's unique identifier; pass it to other tools as agent_id.", + "type": "string" + }, + "last_run_at": { + "description": "When this Agent last started a run; absent when it has never run.", + "type": [ + "null", + "string" + ] + }, + "mailbox": { + "description": "This agent's mailbox letters, open ones (accepted, delivering, blocked) first, then applied or undeliverable ones, newest within each group, at most 20.", + "items": { + "additionalProperties": false, + "properties": { + "accepted_at": { + "type": "string" + }, + "block_reason": { + "type": "string" + }, + "consumed_at": { + "type": [ + "null", + "string" + ] + }, + "correlation_id": { + "type": "string" + }, + "from_agent": { + "type": "string" + }, + "id": { + "type": "string" + }, + "in_reply_to": { + "type": [ + "null", + "string" + ] + }, + "kind": { + "type": "string" + }, + "run_id": { + "type": [ + "null", + "string" + ] + }, + "status": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "to_agent": { + "type": "string" + } + }, + "required": [ + "id", + "kind", + "from_agent", + "to_agent", + "status", + "in_reply_to", + "correlation_id", + "run_id", + "summary", + "accepted_at", + "consumed_at" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "model": { + "description": "The model slug this Agent is configured to use. Empty means no explicit choice, which is not the same as no model — read effective_model for what a run will actually use.", + "type": "string" + }, + "moving": { + "description": "True while this Agent's files are being copied to a new disk; check storage_notice rather than a separate route for the outcome.", + "type": "boolean" + }, + "name": { + "description": "The Agent's name, chosen by its owner and unique within the account.", + "type": "string" + }, + "queued_at": { + "description": "When a still-warming attach was accepted; present only while it is queued for node capacity.", + "type": [ + "null", + "string" + ] + }, + "status": { + "description": "The live warm-session state: warming, ready, or sleeping; empty when no session is active.", + "type": "string" + }, + "storage_notice": { + "description": "The one sentence, if any, telling the owner about a storage move that stopped; show it verbatim, not paraphrased.", + "type": "string" + }, + "url": { + "description": "This Agent's page in the plori web app.", + "type": "string" + }, + "user_id": { + "description": "The identifier of the account that owns this Agent.", + "type": "string" + } + }, + "required": [ + "id", + "user_id", + "name", + "backend", + "model", + "effective_model", + "config", + "created_at", + "mailbox" + ], + "type": "object" +}
- Changed
get_credits1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "account_email": { + "description": "The email address of the account this balance belongs to.", + "type": "string" + }, + "active_plan": { + "additionalProperties": false, + "description": "The account's current subscription, or null when it has none and is on the free tier.", + "properties": { + "cancel_at_period_end": { + "type": "boolean" + }, + "current_period_end": { + "type": [ + "null", + "string" + ] + }, + "monthly_credits": { + "description": "Credits this plan adds each month, in the same credits as balance.", + "type": "integer" + }, + "sku": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "sku", + "monthly_credits", + "status", + "current_period_end", + "cancel_at_period_end" + ], + "type": [ + "null", + "object" + ] + }, + "audience": { + "type": "string" + }, + "balance": { + "description": "The account's remaining prepaid balance, in credits. 1,000,000 credits = 1 US dollar.", + "type": "integer" + }, + "balance_usd": { + "description": "The account balance formatted in US dollars, without a currency symbol.", + "type": "string" + }, + "can_manage_billing": { + "type": "boolean" + }, + "limits": { + "additionalProperties": false, + "description": "The caps this account's plan tier enforces.", + "properties": { + "max_active_workflows": { + "description": "How many active workflows this plan tier may have. 0 means unlimited. An anonymous trial cannot activate a workflow at all.", + "type": "integer" + }, + "max_agents": { + "description": "How many agents this plan tier may own. 0 means unlimited. An anonymous trial is capped at one agent whatever this says.", + "type": "integer" + }, + "max_concurrent_runs": { + "description": "How many agent runs this plan tier may have in flight at once. 0 means unlimited.", + "type": "integer" + } + }, + "required": [ + "max_agents", + "max_concurrent_runs", + "max_active_workflows" + ], + "type": "object" + }, + "low_credit_threshold": { + "description": "The balance, in the same credits, below which this account is warned it is running low.", + "type": "integer" + }, + "packs": { + "description": "Credit packs this account can buy. Each pack's usd_cents is its price in US cents and its credits are what the purchase adds to balance.", + "items": { + "additionalProperties": false, + "properties": { + "credits": { + "type": "integer" + }, + "id": { + "type": "string" + }, + "usd_cents": { + "type": "integer" + } + }, + "required": [ + "id", + "usd_cents", + "credits" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "plan_tier": { + "description": "The plan tier this account resolves to: free, pro or power. An account with no active plan is free.", + "type": "string" + }, + "plans": { + "description": "Subscription plans on offer, with their monthly credit grant.", + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "monthly_credits": { + "type": "integer" + }, + "usd_cents": { + "type": "integer" + } + }, + "required": [ + "id", + "usd_cents", + "monthly_credits" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "user_id": { + "description": "The identifier of the account this balance belongs to.", + "type": "string" + } + }, + "required": [ + "balance", + "low_credit_threshold", + "packs", + "plans", + "active_plan", + "can_manage_billing", + "audience", + "user_id", + "account_email", + "plan_tier", + "limits", + "balance_usd" + ], + "type": "object" +}
- Changed
get_disk1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "included_bytes": { + "type": "integer" + }, + "monthly_credits": { + "type": "integer" + }, + "purchased_bytes": { + "type": "integer" + }, + "storage_credits_per_gb": { + "type": "integer" + }, + "total_bytes": { + "type": "integer" + }, + "trash_bytes": { + "type": [ + "null", + "integer" + ] + }, + "usage_observed_at": { + "description": "When a mount last reported the used figure. Present only while a mount is holding one of the account's disks; when none is, nothing can be changing the figure and there is no reporting clock to quote.", + "type": [ + "null", + "string" + ] + }, + "usage_stale": { + "description": "True when a mount is holding one of the account's disks but has not reported its usage within the writer-lease lifetime. used_bytes is then the last figure that mount reported, not the current one — treat it as a floor and say so rather than quoting it as the account's usage.", + "type": "boolean" + }, + "used_bytes": { + "type": "integer" + }, + "warning_level": { + "type": "integer" + } + }, + "required": [ + "included_bytes", + "purchased_bytes", + "total_bytes", + "used_bytes", + "warning_level", + "storage_credits_per_gb", + "monthly_credits" + ], + "type": "object" +}
- Changed
get_run_result3 fields changed- added
Input schema / properties / waitAdded value: +{ + "description": "When true, wait for a terminal result or human input (see this tool's description for how long the hold lasts). After this tool returns, continue polling while status is non-terminal; it cannot wake an idle client.", + "type": "boolean" +} - added
Input schema / properties / wait_secondsAdded value: +{ + "description": "Optional: how many seconds to wait when wait=true (maximum 1800). Omit to use the window your MCP client can hold.", + "maximum": 1800, + "minimum": 0, + "type": "integer" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "cause": { + "description": "Machine-readable cause for a non-normal terminal state.", + "type": "string" + }, + "continuation_run_id": { + "description": "The exact continuation created for an answered input; poll this run next.", + "type": "string" + }, + "credits": { + "description": "Attributed spend in micro-US-dollars; null when attribution is unavailable.", + "type": [ + "null", + "integer" + ] + }, + "elapsed_seconds": { + "description": "Seconds since the run started; absent for a terminal result.", + "type": "integer" + }, + "ended_at": { + "description": "When the run reached a terminal state.", + "type": [ + "null", + "string" + ] + }, + "error": { + "additionalProperties": false, + "description": "Why a terminal error or cancelled run failed, whether it was charged and what to do about it. Absent for a run that is still going or that finished normally.", + "properties": { + "class": { + "description": "The failure class: the run's terminal cause, or \"unknown\" when none was recorded.", + "type": "string" + }, + "message": { + "description": "What happened, and whether the work was charged.", + "type": "string" + }, + "next_step": { + "description": "What to do about it.", + "type": "string" + }, + "retryable": { + "description": "Whether sending the same message again could plausibly succeed.", + "type": "boolean" + } + }, + "required": [ + "class", + "message", + "retryable", + "next_step" + ], + "type": [ + "null", + "object" + ] + }, + "files": { + "description": "Files on the agent's disk that this reply linked, in the order they appear. Each url is fetchable with the bearer token you called this tool with. Absent when the reply linked none.", + "items": { + "additionalProperties": false, + "properties": { + "path": { + "description": "The file's path on the agent's disk, rooted at the disk root.", + "type": "string" + }, + "url": { + "description": "An absolute URL that streams the file's bytes, text or binary and of any size, with its own content type. Fetch it with the same bearer token you called this tool with.", + "type": "string" + } + }, + "required": [ + "path", + "url" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "hint": { + "description": "What to do next with this run, in one sentence. Present only while the run is non-terminal.", + "type": "string" + }, + "input_expired": { + "description": "True when this run is parked on a question its session has already moved past: a later run in the same conversation has completed. Do not answer it; start a new run instead.", + "type": "boolean" + }, + "input_status": { + "description": "The durable status of this run's human-input request, when it has one: pending, answered, cancelled or expired. cancelled and expired are terminal — that run will never resume, so stop polling it.", + "type": "string" + }, + "last_activity_at": { + "description": "When the run last wrote a note or finished a tool call. Absent for a terminal result and for a run that has done neither.", + "type": [ + "null", + "string" + ] + }, + "last_heartbeat_at": { + "description": "Most recent durable executor heartbeat.", + "type": [ + "null", + "string" + ] + }, + "last_tool_step": { + "description": "What this run last did with a tool: \"running <tool>\" while a call is in flight, otherwise \"completed <tool>\" for the most recent finished call. Absent for a terminal result and for a run with no tool-progress telemetry.", + "type": "string" + }, + "last_worklog": { + "description": "The agent's most recent one-sentence note about what it is doing, from the run's durable event log. Absent for a terminal result and for a run that has written none.", + "type": "string" + }, + "pending_inputs": { + "description": "Human inputs blocking an awaiting_input run.", + "items": { + "additionalProperties": false, + "properties": { + "consent_tool": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "prompt": { + "type": "string" + }, + "risk": { + "type": "string" + }, + "tool_call_id": { + "type": "string" + } + }, + "required": [ + "tool_call_id", + "kind", + "prompt" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "poll_after_ms": { + "description": "Legacy spelling of poll_after_seconds in milliseconds; the two always agree. Prefer poll_after_seconds.", + "type": "integer" + }, + "poll_after_seconds": { + "description": "Suggested seconds before polling again, paced to this run's recent tool-completion rate; absent for a terminal result.", + "type": "integer" + }, + "resume_run_id": { + "description": "The exact auto-resume successor for an interrupted run; poll this run next.", + "type": "string" + }, + "resume_status": { + "description": "Auto-resume disposition for an interrupted run: pending, resumed, failed, or unknown.", + "type": "string" + }, + "retryable": { + "description": "Whether sending the same message again could plausibly succeed. False for a cause the same request would hit again, including time_limit — split the work or raise max_turn_seconds instead of retrying it unchanged.", + "type": [ + "null", + "boolean" + ] + }, + "run_id": { + "description": "The public run identifier.", + "type": "string" + }, + "session_id": { + "description": "The durable conversation/session identifier.", + "type": "string" + }, + "started_at": { + "description": "When the run started.", + "type": [ + "null", + "string" + ] + }, + "status": { + "description": "The current run status.", + "type": "string" + }, + "stop_reason": { + "description": "Controller-selected stop reason, when present.", + "type": "string" + }, + "text": { + "description": "The assistant's reply once the run has finished. While a run is still going this is the run's own status message, not an answer, and is often absent — read last_worklog and last_tool_step instead.", + "type": "string" + }, + "tokens": { + "description": "Attributed token count; null when attribution is unavailable.", + "type": [ + "null", + "integer" + ] + }, + "tool_progress": { + "additionalProperties": false, + "description": "Durable tool execution progress; absent when this run has no tool-progress telemetry.", + "properties": { + "active_tools": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "started_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "started_at" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "completed_count": { + "type": "integer" + }, + "last_completed_at": { + "type": [ + "null", + "string" + ] + } + }, + "required": [ + "active_tools", + "completed_count" + ], + "type": [ + "null", + "object" + ] + }, + "upstream_status": { + "description": "The model provider's HTTP status when this run died on an upstream fault; absent otherwise.", + "type": "integer" + }, + "url": { + "description": "A deep link to this run's session in the plori web app.", + "type": "string" + } + }, + "required": [ + "run_id", + "session_id", + "status" + ], + "type": "object" +}
- Changed
get_usage1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "agents": { + "items": { + "additionalProperties": false, + "properties": { + "agent_id": { + "type": "string" + }, + "backend": { + "type": "string" + }, + "breakdown": { + "items": { + "additionalProperties": false, + "properties": { + "credits": { + "type": "integer" + }, + "events": { + "type": "integer" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "kind", + "events", + "tokens", + "credits" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "credits": { + "type": "integer" + }, + "events": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "agent_id", + "name", + "backend", + "credits", + "tokens", + "events" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "by_kind": { + "items": { + "additionalProperties": false, + "properties": { + "credits": { + "type": "integer" + }, + "events": { + "type": "integer" + }, + "kind": { + "type": "string" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "kind", + "credits", + "tokens", + "events" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "recent_runs": { + "items": { + "additionalProperties": false, + "properties": { + "agent_id": { + "description": "The agent that ran it.", + "type": "string" + }, + "cause": { + "type": "string" + }, + "command_error": { + "type": "string" + }, + "command_state": { + "type": "string" + }, + "continuation_run_id": { + "type": "string" + }, + "credits": { + "type": [ + "null", + "integer" + ] + }, + "ended_at": { + "type": [ + "null", + "string" + ] + }, + "error": { + "additionalProperties": false, + "description": "Why a terminal error or cancelled run failed, and what to do about it. Absent for a run that is still going or that finished normally.", + "properties": { + "class": { + "description": "The failure class: the run's terminal cause, or \"unknown\" when none was recorded.", + "type": "string" + }, + "message": { + "description": "What happened, and whether the work was charged.", + "type": "string" + }, + "next_step": { + "description": "What to do about it.", + "type": "string" + }, + "retryable": { + "description": "Whether sending the same message again could plausibly succeed.", + "type": "boolean" + } + }, + "required": [ + "class", + "message", + "retryable", + "next_step" + ], + "type": [ + "null", + "object" + ] + }, + "id": { + "description": "The run's public identifier; pass it to get_run_result as run_id.", + "type": "string" + }, + "input_expired": { + "description": "True when this run is parked on a question its session has moved past: a later run in the same conversation has completed, so answering it would resume a superseded turn. Do not answer it; start a new run instead.", + "type": "boolean" + }, + "input_status": { + "type": "string" + }, + "input_updated_at": { + "type": [ + "null", + "string" + ] + }, + "last_heartbeat_at": { + "type": [ + "null", + "string" + ] + }, + "origin": { + "description": "What started this run: user, schedule, email, background, agent or agent_result.", + "type": "string" + }, + "parent_run_id": { + "type": "string" + }, + "resume_run_id": { + "type": "string" + }, + "resume_status": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "session_id": { + "description": "The conversation this run belongs to; pass it to invoke_agent as session_id to continue it. Identical to thread_id.", + "type": "string" + }, + "started_at": { + "type": "string" + }, + "status": { + "description": "The run's status: queued, running, awaiting_input, completed, error or cancelled.", + "type": "string" + }, + "stop_reason": { + "type": "string" + }, + "thread_id": { + "description": "The conversation this run belongs to. Identical to session_id.", + "type": "string" + }, + "tokens": { + "type": [ + "null", + "integer" + ] + }, + "tool_progress": { + "additionalProperties": false, + "description": "Durable tool execution progress, from the same telemetry get_run_result reads. Null for a run with no telemetry, and for a terminal run, which has no call in flight to report.", + "properties": { + "active_tools": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "started_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "started_at" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "completed_count": { + "type": "integer" + }, + "last_completed_at": { + "type": [ + "null", + "string" + ] + } + }, + "required": [ + "active_tools", + "completed_count" + ], + "type": [ + "null", + "object" + ] + }, + "upstream_status": { + "description": "The model provider's HTTP status when this run died on an upstream fault; absent otherwise.", + "type": "integer" + } + }, + "required": [ + "id", + "agent_id", + "thread_id", + "session_id", + "status", + "origin", + "started_at", + "credits", + "tokens", + "tool_progress" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "tools": { + "items": { + "additionalProperties": false, + "properties": { + "calls": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "free_calls": { + "type": "integer" + }, + "tool": { + "type": "string" + } + }, + "required": [ + "tool", + "calls", + "free_calls", + "credits" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "totals": { + "additionalProperties": false, + "properties": { + "credits": { + "type": "integer" + }, + "runs": { + "type": "integer" + }, + "tokens": { + "type": "integer" + } + }, + "required": [ + "credits", + "tokens", + "runs" + ], + "type": "object" + }, + "workflow_executions": { + "items": { + "additionalProperties": false, + "properties": { + "created_at": { + "type": "string" + }, + "credits": { + "type": "integer" + }, + "duration_ms": { + "type": "integer" + }, + "ended_at": { + "type": [ + "null", + "string" + ] + }, + "fault": { + "type": "string" + }, + "id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "trigger_source": { + "type": "string" + }, + "workflow_id": { + "type": "string" + }, + "workflow_name": { + "type": "string" + } + }, + "required": [ + "id", + "workflow_id", + "workflow_name", + "status", + "trigger_source", + "duration_ms", + "credits", + "created_at" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "workflows": { + "items": { + "additionalProperties": false, + "properties": { + "billed_runs": { + "type": "integer" + }, + "credits": { + "type": "integer" + }, + "exec_credits": { + "type": "integer" + }, + "model_credits": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "tokens": { + "type": "integer" + }, + "workflow_id": { + "type": "string" + } + }, + "required": [ + "workflow_id", + "name", + "billed_runs", + "exec_credits", + "model_credits", + "credits", + "tokens" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + } + }, + "required": [ + "totals", + "by_kind", + "tools", + "agents", + "workflows", + "workflow_executions", + "recent_runs" + ], + "type": "object" +}
- Changed
get_workflow1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "active_version": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": [ + "null", + "integer" + ] + }, + "agent_deleted_at": { + "type": [ + "null", + "string" + ] + }, + "agent_id": { + "type": [ + "null", + "string" + ] + }, + "created_at": { + "type": "string" + }, + "cron_expr": { + "type": "string" + }, + "current_version": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "description": { + "type": "string" + }, + "engine": { + "type": "string" + }, + "hook_key": { + "type": [ + "null", + "string" + ] + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "next_fire_at": { + "type": [ + "null", + "string" + ] + }, + "notify_pref": { + "type": "string" + }, + "paused_reason": { + "type": "string" + }, + "projection": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "spend_cap_month": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "template_slug": { + "type": "string" + }, + "trigger_kind": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "id", + "user_id", + "agent_id", + "name", + "description", + "engine", + "status", + "current_version", + "active_version", + "trigger_kind", + "cron_expr", + "next_fire_at", + "hook_key", + "spend_cap_month", + "notify_pref", + "created_at", + "updated_at", + "projection" + ], + "type": "object" +}
- Changed
get_workflow_execution1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "billed": { + "description": "The billing flag. True only for a user-fault succeeded, failed, or timed-out execution.", + "type": "boolean" + }, + "created_at": { + "type": "string" + }, + "credits": { + "type": [ + "null", + "integer" + ] + }, + "duration_ms": { + "type": [ + "null", + "integer" + ] + }, + "ended_at": { + "type": [ + "null", + "string" + ] + }, + "error": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "fault": { + "description": "Why a non-succeeded execution ended. User means the workflow's own steps or limits. A platform fault is never billed. This field is null when the execution succeeded.", + "type": [ + "null", + "string" + ] + }, + "id": { + "type": "string" + }, + "started_at": { + "type": [ + "null", + "string" + ] + }, + "status": { + "type": "string" + }, + "step_stats": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "steps": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "trigger_source": { + "type": "string" + }, + "workflow_id": { + "type": "string" + } + }, + "required": [ + "id", + "workflow_id", + "status", + "fault", + "billed", + "trigger_source", + "started_at", + "ended_at", + "duration_ms", + "credits", + "created_at" + ], + "type": "object" +}
- Changed
get_workflow_version1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "author": { + "type": "string" + }, + "chat_run_id": { + "type": [ + "null", + "string" + ] + }, + "created_at": { + "type": "string" + }, + "definition": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "id": { + "type": "string" + }, + "projection": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "version": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "workflow_id": { + "type": "string" + } + }, + "required": [ + "id", + "workflow_id", + "version", + "author", + "chat_run_id", + "created_at" + ], + "type": "object" +}
- Changed
invoke_agent7 fields changed- added
Input schema / properties / callback_secretAdded value: +{ + "description": "Optional secret used to sign callback deliveries with HMAC-SHA256.", + "type": "string" +} - added
Input schema / properties / callback_urlAdded value: +{ + "description": "Optional callback URL for this run. Must use http or https and resolve only to public addresses.", + "type": "string" +} - changed
Input schema / properties / max_turn_seconds / descriptionPrevious value: -"Optional soft wall-clock budget for this turn in seconds (0 or omitted uses forge's deployment default; maximum 14,400). It schedules an in-loop checkpoint and does not cancel the run."New value: +"Optional soft wall-clock budget for this turn in seconds, maximum 14,400. 0 or omitted uses the deployment's configured default, and where none is configured a turn has no wall-clock budget at all. It schedules an in-loop checkpoint and does not cancel the run." - changed
Input schema / properties / max_turn_tokens / descriptionPrevious value: -"Optional cumulative cache-weighted token ceiling for this turn (0 or omitted uses forge's default; maximum 5,000,000). The agent reserves its final 2% for a tool-free wrap-up."New value: +"Optional cumulative cache-weighted token ceiling for this turn. 0 or omitted uses the agent's default of 2,000,000; the maximum is 5,000,000. The agent reserves its final 2% for a tool-free wrap-up." - changed
Input schema / properties / wait / descriptionPrevious value: -"Wait (up to ~25s) for the turn and return the reply (default true). Set false to return a run_id immediately and poll get_run_result — prefer this for long or tool-heavy turns so the call doesn't block your own turn."New value: +"Wait for the turn and return the reply (default true); the hold lasts as long as your client keeps the call open, or wait_seconds. Set false to return a run_id immediately and poll get_run_result — prefer this for long or tool-heavy turns so the call doesn't block your own turn." - added
Input schema / properties / wait_secondsAdded value: +{ + "description": "Optional: how many seconds to wait for the turn before returning a \"running\" run_id (maximum 1800). Omit to use the window your MCP client can hold. Ignored when wait=false.", + "maximum": 1800, + "minimum": 0, + "type": "integer" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "cause": { + "description": "Machine-readable cause for a non-normal terminal state.", + "type": "string" + }, + "continuation_run_id": { + "description": "The exact continuation created for an answered input; poll this run next.", + "type": "string" + }, + "credits": { + "description": "Attributed spend in micro-US-dollars; null when attribution is unavailable.", + "type": [ + "null", + "integer" + ] + }, + "elapsed_seconds": { + "description": "Seconds since the run started; absent for a terminal result.", + "type": "integer" + }, + "ended_at": { + "description": "When the run reached a terminal state.", + "type": [ + "null", + "string" + ] + }, + "error": { + "additionalProperties": false, + "description": "Why a terminal error or cancelled run failed, whether it was charged and what to do about it. Absent for a run that is still going or that finished normally.", + "properties": { + "class": { + "description": "The failure class: the run's terminal cause, or \"unknown\" when none was recorded.", + "type": "string" + }, + "message": { + "description": "What happened, and whether the work was charged.", + "type": "string" + }, + "next_step": { + "description": "What to do about it.", + "type": "string" + }, + "retryable": { + "description": "Whether sending the same message again could plausibly succeed.", + "type": "boolean" + } + }, + "required": [ + "class", + "message", + "retryable", + "next_step" + ], + "type": [ + "null", + "object" + ] + }, + "files": { + "description": "Files on the agent's disk that this reply linked, in the order they appear. Each url is fetchable with the bearer token you called this tool with. Absent when the reply linked none.", + "items": { + "additionalProperties": false, + "properties": { + "path": { + "description": "The file's path on the agent's disk, rooted at the disk root.", + "type": "string" + }, + "url": { + "description": "An absolute URL that streams the file's bytes, text or binary and of any size, with its own content type. Fetch it with the same bearer token you called this tool with.", + "type": "string" + } + }, + "required": [ + "path", + "url" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "hint": { + "description": "What to do next with this run, in one sentence. Present only while the run is non-terminal.", + "type": "string" + }, + "input_expired": { + "description": "True when this run is parked on a question its session has already moved past: a later run in the same conversation has completed. Do not answer it; start a new run instead.", + "type": "boolean" + }, + "input_status": { + "description": "The durable status of this run's human-input request, when it has one: pending, answered, cancelled or expired. cancelled and expired are terminal — that run will never resume, so stop polling it.", + "type": "string" + }, + "last_activity_at": { + "description": "When the run last wrote a note or finished a tool call. Absent for a terminal result and for a run that has done neither.", + "type": [ + "null", + "string" + ] + }, + "last_heartbeat_at": { + "description": "Most recent durable executor heartbeat.", + "type": [ + "null", + "string" + ] + }, + "last_tool_step": { + "description": "What this run last did with a tool: \"running <tool>\" while a call is in flight, otherwise \"completed <tool>\" for the most recent finished call. Absent for a terminal result and for a run with no tool-progress telemetry.", + "type": "string" + }, + "last_worklog": { + "description": "The agent's most recent one-sentence note about what it is doing, from the run's durable event log. Absent for a terminal result and for a run that has written none.", + "type": "string" + }, + "pending_inputs": { + "description": "Human inputs blocking an awaiting_input run.", + "items": { + "additionalProperties": false, + "properties": { + "consent_tool": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "prompt": { + "type": "string" + }, + "risk": { + "type": "string" + }, + "tool_call_id": { + "type": "string" + } + }, + "required": [ + "tool_call_id", + "kind", + "prompt" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "poll_after_ms": { + "description": "Legacy spelling of poll_after_seconds in milliseconds; the two always agree. Prefer poll_after_seconds.", + "type": "integer" + }, + "poll_after_seconds": { + "description": "Suggested seconds before polling again, paced to this run's recent tool-completion rate; absent for a terminal result.", + "type": "integer" + }, + "resume_run_id": { + "description": "The exact auto-resume successor for an interrupted run; poll this run next.", + "type": "string" + }, + "resume_status": { + "description": "Auto-resume disposition for an interrupted run: pending, resumed, failed, or unknown.", + "type": "string" + }, + "retryable": { + "description": "Whether sending the same message again could plausibly succeed. False for a cause the same request would hit again, including time_limit — split the work or raise max_turn_seconds instead of retrying it unchanged.", + "type": [ + "null", + "boolean" + ] + }, + "run_id": { + "description": "The public run identifier.", + "type": "string" + }, + "session_id": { + "description": "The durable conversation/session identifier.", + "type": "string" + }, + "started_at": { + "description": "When the run started.", + "type": [ + "null", + "string" + ] + }, + "status": { + "description": "The current run status.", + "type": "string" + }, + "stop_reason": { + "description": "Controller-selected stop reason, when present.", + "type": "string" + }, + "text": { + "description": "The assistant's reply once the run has finished. While a run is still going this is the run's own status message, not an answer, and is often absent — read last_worklog and last_tool_step instead.", + "type": "string" + }, + "tokens": { + "description": "Attributed token count; null when attribution is unavailable.", + "type": [ + "null", + "integer" + ] + }, + "tool_progress": { + "additionalProperties": false, + "description": "Durable tool execution progress; absent when this run has no tool-progress telemetry.", + "properties": { + "active_tools": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "started_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "started_at" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "completed_count": { + "type": "integer" + }, + "last_completed_at": { + "type": [ + "null", + "string" + ] + } + }, + "required": [ + "active_tools", + "completed_count" + ], + "type": [ + "null", + "object" + ] + }, + "upstream_status": { + "description": "The model provider's HTTP status when this run died on an upstream fault; absent otherwise.", + "type": "integer" + }, + "url": { + "description": "A deep link to this run's session in the plori web app.", + "type": "string" + } + }, + "required": [ + "run_id", + "session_id", + "status" + ], + "type": "object" +}
- Changed
list_agents1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "items": { + "description": "The returned items, in the endpoint's documented order.", + "items": { + "additionalProperties": false, + "properties": { + "backend": { + "description": "The compute backend this Agent runs on.", + "type": "string" + }, + "config": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "created_at": { + "description": "When the Agent was created.", + "type": "string" + }, + "deleting": { + "description": "True while this Agent's disk is still being erased; offer no action on it besides retrying the deletion itself.", + "type": "boolean" + }, + "deleting_since": { + "description": "When the deletion was first requested; present only while deleting is true.", + "type": [ + "null", + "string" + ] + }, + "effective_model": { + "description": "The model a run on this Agent will actually use. plori-auto means the hosted router chooses per turn.", + "type": "string" + }, + "id": { + "description": "The Agent's unique identifier; pass it to other tools as agent_id.", + "type": "string" + }, + "last_run_at": { + "description": "When this Agent last started a run; absent when it has never run.", + "type": [ + "null", + "string" + ] + }, + "model": { + "description": "The model slug this Agent is configured to use. Empty means no explicit choice, which is not the same as no model — read effective_model for what a run will actually use.", + "type": "string" + }, + "moving": { + "description": "True while this Agent's files are being copied to a new disk; check storage_notice rather than a separate route for the outcome.", + "type": "boolean" + }, + "name": { + "description": "The Agent's name, chosen by its owner and unique within the account.", + "type": "string" + }, + "queued_at": { + "description": "When a still-warming attach was accepted; present only while it is queued for node capacity.", + "type": [ + "null", + "string" + ] + }, + "status": { + "description": "The live warm-session state: warming, ready, or sleeping; empty when no session is active.", + "type": "string" + }, + "storage_notice": { + "description": "The one sentence, if any, telling the owner about a storage move that stopped; show it verbatim, not paraphrased.", + "type": "string" + }, + "url": { + "description": "This Agent's page in the plori web app.", + "type": "string" + }, + "user_id": { + "description": "The identifier of the account that owns this Agent.", + "type": "string" + } + }, + "required": [ + "id", + "user_id", + "name", + "backend", + "model", + "effective_model", + "config", + "created_at" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + } + }, + "required": [ + "items" + ], + "type": "object" +}
- Changed
list_connections1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "connections": { + "description": "Third-party OAuth connection status records; never secret material.", + "items": { + "additionalProperties": false, + "properties": { + "authorized_at": { + "description": "When the grant was last authorized; null when there has never been one.", + "type": [ + "null", + "string" + ] + }, + "expires_at": { + "description": "When the current access token expires; null when the grant does not expire. A past value on an authorized row is normal — tokens refresh lazily when used.", + "type": [ + "null", + "string" + ] + }, + "needs_reauth": { + "description": "True when a human must reconnect this provider before it can be used. Read this rather than comparing expires_at to the clock.", + "type": "boolean" + }, + "provider": { + "description": "The third-party provider this row is about.", + "type": "string" + }, + "scopes": { + "description": "The scopes this provider is configured to request.", + "items": { + "type": "string" + }, + "type": [ + "null", + "array" + ] + }, + "status": { + "description": "authorized, reconnect_needed, or unauthorized.", + "type": "string" + } + }, + "required": [ + "provider", + "status", + "authorized_at", + "expires_at", + "scopes", + "needs_reauth" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + } + }, + "required": [ + "connections" + ], + "type": "object" +}
- Changed
list_pending_inputs1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "pending_inputs": { + "description": "Runs currently parked on a human approval or input request. A request whose session has already moved on is left out: answering it would resume a superseded turn.", + "items": { + "additionalProperties": false, + "properties": { + "agent_id": { + "type": "string" + }, + "args": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "connect": { + "additionalProperties": false, + "properties": { + "provider": { + "type": "string" + }, + "workflow_id": { + "type": "string" + } + }, + "required": [ + "workflow_id", + "provider" + ], + "type": [ + "null", + "object" + ] + }, + "consent_tool": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "expires_at": { + "type": [ + "null", + "string" + ] + }, + "id": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "prompt": { + "type": "string" + }, + "risk": { + "type": "string" + }, + "run_id": { + "type": "string" + }, + "schema": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "secret": { + "type": "boolean" + }, + "status": { + "type": "string" + }, + "tool_call_id": { + "type": "string" + } + }, + "required": [ + "id", + "run_id", + "agent_id", + "tool_call_id", + "kind", + "prompt", + "status", + "created_at" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + } + }, + "required": [ + "pending_inputs" + ], + "type": "object" +}
- Changed
list_runs3 fields changed- added
Input schema / properties / cursorAdded value: +{ + "description": "The next_cursor from a previous list_runs result, to continue where it stopped. Omit for the newest page.", + "type": "string" +} - added
Input schema / properties / limitAdded value: +{ + "description": "How many runs to return, newest first (default 20, maximum 100).", + "maximum": 100, + "minimum": 1, + "type": "integer" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "items": { + "description": "One page of the agent's runs, most recently started first.", + "items": { + "additionalProperties": false, + "properties": { + "agent_id": { + "description": "The agent that ran it.", + "type": "string" + }, + "cause": { + "type": "string" + }, + "command_error": { + "type": "string" + }, + "command_state": { + "type": "string" + }, + "continuation_run_id": { + "type": "string" + }, + "credits": { + "type": [ + "null", + "integer" + ] + }, + "ended_at": { + "type": [ + "null", + "string" + ] + }, + "error": { + "additionalProperties": false, + "description": "Why a terminal error or cancelled run failed, and what to do about it. Absent for a run that is still going or that finished normally.", + "properties": { + "class": { + "description": "The failure class: the run's terminal cause, or \"unknown\" when none was recorded.", + "type": "string" + }, + "message": { + "description": "What happened, and whether the work was charged.", + "type": "string" + }, + "next_step": { + "description": "What to do about it.", + "type": "string" + }, + "retryable": { + "description": "Whether sending the same message again could plausibly succeed.", + "type": "boolean" + } + }, + "required": [ + "class", + "message", + "retryable", + "next_step" + ], + "type": [ + "null", + "object" + ] + }, + "id": { + "description": "The run's public identifier; pass it to get_run_result as run_id.", + "type": "string" + }, + "input_expired": { + "description": "True when this run is parked on a question its session has moved past: a later run in the same conversation has completed, so answering it would resume a superseded turn. Do not answer it; start a new run instead.", + "type": "boolean" + }, + "input_status": { + "type": "string" + }, + "input_updated_at": { + "type": [ + "null", + "string" + ] + }, + "last_heartbeat_at": { + "type": [ + "null", + "string" + ] + }, + "origin": { + "description": "What started this run: user, schedule, email, background, agent or agent_result.", + "type": "string" + }, + "parent_run_id": { + "type": "string" + }, + "resume_run_id": { + "type": "string" + }, + "resume_status": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "session_id": { + "description": "The conversation this run belongs to; pass it to invoke_agent as session_id to continue it. Identical to thread_id.", + "type": "string" + }, + "started_at": { + "type": "string" + }, + "status": { + "description": "The run's status: queued, running, awaiting_input, completed, error or cancelled.", + "type": "string" + }, + "stop_reason": { + "type": "string" + }, + "thread_id": { + "description": "The conversation this run belongs to. Identical to session_id.", + "type": "string" + }, + "tokens": { + "type": [ + "null", + "integer" + ] + }, + "tool_progress": { + "additionalProperties": false, + "description": "Durable tool execution progress, from the same telemetry get_run_result reads. Null for a run with no telemetry, and for a terminal run, which has no call in flight to report.", + "properties": { + "active_tools": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "started_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "started_at" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "completed_count": { + "type": "integer" + }, + "last_completed_at": { + "type": [ + "null", + "string" + ] + } + }, + "required": [ + "active_tools", + "completed_count" + ], + "type": [ + "null", + "object" + ] + }, + "upstream_status": { + "description": "The model provider's HTTP status when this run died on an upstream fault; absent otherwise.", + "type": "integer" + } + }, + "required": [ + "id", + "agent_id", + "thread_id", + "session_id", + "status", + "origin", + "started_at", + "credits", + "tokens", + "tool_progress" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + }, + "next_cursor": { + "description": "Pass this back as cursor to read the next page. Absent when this page is the end of the history.", + "type": "string" + } + }, + "required": [ + "items" + ], + "type": "object" +}
- Changed
list_workflow_executions1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "executions": { + "description": "Recent workflow executions, most recent first.", + "items": { + "additionalProperties": false, + "properties": { + "billed": { + "description": "The billing flag. True only for a user-fault succeeded, failed, or timed-out execution.", + "type": "boolean" + }, + "created_at": { + "type": "string" + }, + "credits": { + "type": [ + "null", + "integer" + ] + }, + "duration_ms": { + "type": [ + "null", + "integer" + ] + }, + "ended_at": { + "type": [ + "null", + "string" + ] + }, + "error": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "fault": { + "description": "Why a non-succeeded execution ended. User means the workflow's own steps or limits. A platform fault is never billed. This field is null when the execution succeeded.", + "type": [ + "null", + "string" + ] + }, + "id": { + "type": "string" + }, + "started_at": { + "type": [ + "null", + "string" + ] + }, + "status": { + "type": "string" + }, + "step_stats": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "steps": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "trigger_source": { + "type": "string" + }, + "workflow_id": { + "type": "string" + } + }, + "required": [ + "id", + "workflow_id", + "status", + "fault", + "billed", + "trigger_source", + "started_at", + "ended_at", + "duration_ms", + "credits", + "created_at" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + } + }, + "required": [ + "executions" + ], + "type": "object" +}
- Changed
list_workflows1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "workflows": { + "description": "Workflows visible to the authenticated account and optional agent filter.", + "items": { + "additionalProperties": false, + "properties": { + "active_version": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": [ + "null", + "integer" + ] + }, + "agent_deleted_at": { + "type": [ + "null", + "string" + ] + }, + "agent_id": { + "type": [ + "null", + "string" + ] + }, + "created_at": { + "type": "string" + }, + "cron_expr": { + "type": "string" + }, + "current_version": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "description": { + "type": "string" + }, + "engine": { + "type": "string" + }, + "hook_key": { + "type": [ + "null", + "string" + ] + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "next_fire_at": { + "type": [ + "null", + "string" + ] + }, + "notify_pref": { + "type": "string" + }, + "paused_reason": { + "type": "string" + }, + "spend_cap_month": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "template_slug": { + "type": "string" + }, + "trigger_kind": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "id", + "user_id", + "agent_id", + "name", + "description", + "engine", + "status", + "current_version", + "active_version", + "trigger_kind", + "cron_expr", + "next_fire_at", + "hook_key", + "spend_cap_month", + "notify_pref", + "created_at", + "updated_at" + ], + "type": "object" + }, + "type": [ + "null", + "array" + ] + } + }, + "required": [ + "workflows" + ], + "type": "object" +}
- Changed
run_workflow1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "billed": { + "description": "The billing flag. True only for a user-fault succeeded, failed, or timed-out execution.", + "type": "boolean" + }, + "created_at": { + "type": "string" + }, + "credits": { + "type": [ + "null", + "integer" + ] + }, + "duration_ms": { + "type": [ + "null", + "integer" + ] + }, + "ended_at": { + "type": [ + "null", + "string" + ] + }, + "error": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "fault": { + "description": "Why a non-succeeded execution ended. User means the workflow's own steps or limits. A platform fault is never billed. This field is null when the execution succeeded.", + "type": [ + "null", + "string" + ] + }, + "id": { + "type": "string" + }, + "started_at": { + "type": [ + "null", + "string" + ] + }, + "status": { + "type": "string" + }, + "step_stats": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "steps": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "trigger_source": { + "type": "string" + }, + "workflow_id": { + "type": "string" + } + }, + "required": [ + "id", + "workflow_id", + "status", + "fault", + "billed", + "trigger_source", + "started_at", + "ended_at", + "duration_ms", + "credits", + "created_at" + ], + "type": "object" +}
- Changed
schedule_run1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "agent_id": { + "type": "string" + }, + "attempts": { + "maximum": 2147483647, + "minimum": -2147483648, + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "fire_at": { + "type": [ + "null", + "string" + ] + }, + "id": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "last_error": { + "type": "string" + }, + "last_fired_at": { + "type": [ + "null", + "string" + ] + }, + "metadata": { + "description": "Arbitrary JSON owned by the producing engine." + }, + "prompt": { + "type": "string" + }, + "status": { + "type": "string" + }, + "thread_id": { + "type": "string" + } + }, + "required": [ + "id", + "agent_id", + "kind", + "status", + "prompt", + "attempts", + "created_at" + ], + "type": "object" +}
- Removed
set_agent_model - Added
set_workflow_agent
2 tool updates
v0.9.1- Changed
answer_pending_input1 field changed- added
Input schema / properties / max_turn_secondsAdded value: +{ + "description": "Optional soft wall-clock budget to preserve on the continuation run; it does not change the parked run or impose a hard deadline.", + "maximum": 14400, + "minimum": 0, + "type": "integer" +}
- Changed
invoke_agent1 field changed- added
Input schema / properties / max_turn_secondsAdded value: +{ + "description": "Optional soft wall-clock budget for this turn in seconds (0 or omitted uses forge's deployment default; maximum 14,400). It schedules an in-loop checkpoint and does not cancel the run.", + "maximum": 14400, + "minimum": 0, + "type": "integer" +}
4 tool updates
v0.9.0- Added
cancel_run - Added
edit_workflow - Added
get_workflow_version - Changed
invoke_agent1 field changed- added
Input schema / properties / max_turn_tokensAdded value: +{ + "description": "Optional cumulative cache-weighted token ceiling for this turn (0 or omitted uses forge's default; maximum 5,000,000). The agent reserves its final 2% for a tool-free wrap-up.", + "maximum": 5000000, + "minimum": 0, + "type": "integer" +}
14 tool updates
v0.7.0- Changed
answer_pending_input1 field changed- added
Input schema / properties / always_allowAdded value: +{ + "description": "Approve AND stop asking for this tool on this agent (a standing grant). Only set it when the human explicitly said to stop being asked, and only on a row whose consent_tool is set; ignored without approved=true. Revoke via DELETE /v1/agents/{agent_id}/tool-consents/{tool}.", + "type": "boolean" +}
- Changed
create_agent1 field changed- changed
Input schema / properties / model / descriptionPrevious value: -"Optional model slug; omitted uses Auto, the plan-scaled default whose quality follows the account's plan. An explicit frontier model requires a paid plan."New value: +"Optional model slug; omitted uses the Plori Router, which picks the cheapest model that fits each task from the pool the account's plan unlocks. An explicit frontier model still requires a paid plan."
- Changed
create_workflow1 field changed- changed
Input schema / properties / agent_id / descriptionPrevious value: -"Optional UUID of one of your agents to record as the workflow's creator."New value: +"Optional UUID of one of your agents to own the workflow. That agent is then the one that can build, edit, and run it from a chat; leave it out and the workflow stays unassigned until you set an owner."
- Added
get_agent - Added
get_usage - Added
get_workflow - Changed
invoke_agent1 field changed- changed
Input schema / properties / session_id / descriptionPrevious value: -"Optional thread/session id to continue an existing conversation; omit to start a new one."New value: +"Optional thread/session id to continue an existing conversation (a previous invoke_agent or get_run_result result carries it as \"session_id\"); omit to start a new one."
- Added
list_connections - Added
list_runs - Added
list_workflow_executions - Changed
list_workflows1 field changed- added
Input schema / properties / agent_idAdded value: +{ + "description": "Optional: a UUID of one of your agents to list only its workflows, or \"none\" for the unassigned ones.", + "type": "string" +}
- Added
run_workflow - Added
schedule_run - Added
set_agent_model
13 tool updates
v0.3.0- Changed
create_agent1 field changed- changed
Input schema / properties / model / descriptionPrevious value: -"Optional model slug; omitted uses the account's tier default. Frontier models require a paid plan."New value: +"Optional model slug; omitted uses Auto, the plan-scaled default whose quality follows the account's plan. An explicit frontier model requires a paid plan."
- Removed
get_agent - Changed
get_credits1 field changed- added
Input schema / propertiesAdded value: +{}
- Changed
get_disk1 field changed- added
Input schema / propertiesAdded value: +{}
- Removed
get_usage - Changed
invoke_agent1 field changed- added
Input schema / properties / idempotency_keyAdded value: +{ + "description": "Optional retry guard: a string you generate for this attempt. Re-sending the same key with the same agent and message within 24h returns the ORIGINAL run instead of starting a second one. Reusing a key with a different message is an error.", + "type": "string" +}
- Changed
list_agents1 field changed- added
Input schema / propertiesAdded value: +{}
- Removed
list_brains - Removed
list_runs - Changed
list_workflows1 field changed- added
Input schema / propertiesAdded value: +{}
- Removed
run_workflow - Removed
schedule_run - Removed
set_agent_model
6 tool updates
v0.1.1- Changed
create_agent1 field changed- changed
Input schema / properties / name / descriptionPrevious value: -"A human-readable name for the agent."New value: +"The agent's name. Reusing a previous name returns that existing agent."
- Added
create_workflow - Added
get_workflow_execution - Changed
invoke_agent1 field changed- changed
Input schema / properties / wait / descriptionPrevious value: -"Wait for the turn to complete and return the reply (default true). If false, returns a run_id to poll."New value: +"Wait (up to ~25s) for the turn and return the reply (default true). Set false to return a run_id immediately and poll get_run_result — prefer this for long or tool-heavy turns so the call doesn't block your own turn."
- Added
list_workflows - Added
run_workflow
15 tool updates
v0.1.0- First observed
answer_pending_input - First observed
create_agent - First observed
delete_agent - First observed
get_agent - First observed
get_credits - First observed
get_disk - First observed
get_run_result - First observed
get_usage - First observed
invoke_agent - First observed
list_agents - First observed
list_brains - First observed
list_pending_inputs - First observed
list_runs - First observed
schedule_run - First observed
set_agent_model
TDQS
Scored across 24 tools
Tools are largely distinct by resource and action, but get_run_result and get_workspace_worker overlap when reading a worker's run reply, and list_runs vs list_workspace_workers are similar list operations. The descriptions clarify boundaries, but an agent could still mix them up in edge cases.
All tool names use consistent snake_case verb_noun patterns, such as get_workspace_changeset, accept_workspace_changeset, list_workspaces, and cancel_run. No mixed conventions or erratic verb styles are present.
24 tools is heavy for an MCP server and sits in the borderline 16-25 range. While the domain is complex, the set could likely be consolidated, and the count feels over-extended for typical agent interactions.
The core lifecycle for workspaces, workers, changesets, files, runs, and pending inputs is well covered, with few dead ends. Minor gaps exist, such as no explicit update_workspace or delete_workspace_file, but agents can generally work around them.
Maintenance
Related MCP Connectors
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Hosting for AI agents: your AI client deploys Docker apps to live HTTPS URLs over MCP.
Hosted runtime for persistent agent teams, durable workflows, memory, schedules, and goals.
Remote MCP server exposing your Node Command fleet (files, shell, processes, browser) to AI hosts.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceMulti-project execution, memory, and collaboration platform for humans and AI agents, providing MCP tools for agents to read and write project state.3MIT

PoYo MCP Serverofficial
AlicenseNot gradedqualityBmaintenanceLocal stdio bridge to the hosted PoYo MCP server, enabling discovery and execution of AI models via chat, generation tasks, and agent skills.1MIT- AlicenseAqualityBmaintenanceOutbound-only remote shell, detached long-running jobs, and temporary file courier for AI agents. Hosted Streamable HTTP plus stdio via npx -y @aicommander/mcp.111MIT
- AlicenseNot gradedqualityCmaintenanceHost apps built with AI: deploy to a live HTTPS URL, custom domains, managed sign-in, secrets and backups. Hosted remote MCP server at https://softkiln.com/mcp/ — this repository is its plugins and skills.MIT