Skip to main content
Glama

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 plori

Codex 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/mcp

API 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, and storage_readiness while storage starts), create_workspace (a Workspace with its first revision. Unless you pass default_manager_agent_id, it also creates a default agent. idempotency_key makes 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 as content, or omit content for a one-time upload_url for 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, with wait_seconds to set how long to hold, idempotency_key to make a retry return the original run, and callback_url plus callback_secret to 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_inputs lists the workers' open questions and approvals and next_run_id names the run that continues it), list_runs (an agent's run history, most recent first), cancel_run (stop an in-flight run, which reports cancelling and then cancelled), schedule_run (run an agent once later, after a delay or at a timestamp. It returns awaiting_confirmation and a confirm_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 an approve_url that 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_workers and get_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_changesets and get_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-card

  • OAuth discovery: RFC 9728 protected-resource metadata on api.plori.ai, dynamic client registration supported

  • Registry entry: ai.plori/plori in 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

Available Tools

24 tools
accept_workspace_changesetAccept Workspace changesetA
DestructiveIdempotent
Inspect

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.

NameRequiredDescriptionDefault
changeset_idYesThe changeset_id from submit_workspace_changeset or list_workspace_changesets.
workspace_idYesThe Workspace UUID.
validation_evidenceYes1-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_revisionYesThe changeset's comparison_current_revision from get_workspace_changeset.

Output Schema

NameRequiredDescription
phaseYesThe 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.
stateYessubmitted (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.
changesNoThe changed paths, at most 500. get_workspace_changeset returns them; list_workspace_changesets leaves them out.
comparedYesTrue when the comparison is complete and changes and conflicts are known.
conflictsNoThe paths that conflict, when state is conflicted.
no_changeNoTrue when the worker changed no files.
created_atYesWhen the changeset was submitted.
updated_atYesWhen the changeset last changed.
auto_acceptNoSet 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_countYesThe number of changed paths.
changeset_idYesThe changeset UUID.
workspace_idYesThe Workspace UUID.
base_revisionYesThe revision the worker's copy started from.
result_revisionNoThe new current revision of the Workspace once an accepted changeset is saved.
terminal_reasonNoWhy a failed changeset failed.
working_copy_idYesThe worker's copy that the changes come from.
changes_truncatedNoTrue when there are more than 500 changed paths.
incoming_revisionYesThe worker's saved revision. read_workspace_file reads its files.
validation_evidenceNoThe evidence given when the changeset was accepted.
comparison_current_revisionNoThe Workspace revision the changes were compared with. accept_workspace_changeset takes it as expected_current_revision.

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 questionA
Destructive
Inspect

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.

NameRequiredDescriptionDefault
noteNoAn optional note recorded with the answer.
valueNoThe answer to a question.
run_idYesThe paused run's run_id.
approvedNofalse denies an approval request. true is refused: only the account owner approves, in the Plori web app.
tool_call_idYesThe tool_call_id of the approval request or question, from the run result or list_pending_inputs.
max_turn_secondsNoOptional 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

NameRequiredDescription
run_idNoThe continuation run that continues the task after this answer; poll it with get_run_result. Absent while continuation_pending is true.
statusYesAnswer status.
alreadyNoWhether this request had already been answered.
session_idNoThe continuation run's session.
tool_call_idYesThe pending tool call that was answered.
continuation_errorNoWhy the continuation has not started or will not start, when the platform recorded a reason. The answer stays recorded.
continuation_pendingNoTrue 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

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 runA
Destructive
Inspect

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.

NameRequiredDescriptionDefault
run_idYesThe run to cancel.
agent_idNoThe agent that runs the run (agent_id in the run result). Give this or workspace_id.
workspace_idNoThe Workspace the run belongs to. Give this or agent_id; with both, agent_id is used.

Output Schema

NameRequiredDescription
runIdYesThe run whose cancellation was requested.
statusYesCancellation request status.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 WorkspaceA
DestructiveIdempotent
Inspect

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.

NameRequiredDescriptionDefault
nameYesA display name for the Workspace. Names are not unique and do not identify the Workspace.
accountNoOmit 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_keyYesA 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_idNoThe 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

NameRequiredDescription
idYesThe Workspace UUID.
nameYesThe display name; not unique.
roleYesThe caller's role: owner, member or viewer.
stateYesactive, adopting (its files are moving to new storage; runs are refused until it is active again), deleting or deleted.
accountYesThe account that owns the Workspace, with its user_id and email.
created_atYesWhen the Workspace was created.
updated_atYesWhen it last changed.
main_session_idYesThe main conversation id.
current_revisionYesThe saved revision of the Workspace's current files; read_workspace_file reads it by default.
default_agent_idYesThe 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_readinessNoPresent while the Workspace's storage is still starting: state, since, pending_reason, retryable.
root_working_copy_idYes
default_manager_agent_idYesThe same value as default_agent_id.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness3/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 workerA
DestructiveIdempotent
Inspect

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.

NameRequiredDescriptionDefault
nameNoA 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.
taskYesThe task for the worker, in plain text (at most 65536 bytes).
workspace_idYesThe Workspace UUID.
task_group_idNoAn 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_keyYesA 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_tokensNoOptional 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_idNoAn 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

NameRequiredDescription
causeNoMachine-readable cause of a run that did not finish normally.
run_idNoThe 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.
statusYesWhere 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).
activityNoThe worker's expiring activity hint; absent when expired or unavailable. The saved changeset is authoritative.
agent_idYesThe agent that runs the worker. get_run_result and cancel_run take it with run_id.
run_statusNoThe run's status: running, awaiting_input (paused on an approval or question; get_run_result lists them), completed, error or cancelled.
save_stateYesWhether 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_idYesThe worker's own conversation id. It is private to the worker; send_workspace_message cannot select it.
stop_reasonNoThe stop reason of an ended run, when one was recorded.
changeset_idNoThe changeset submitted for this worker's files, if any.
queue_reasonNoWhy a waiting worker has not started, such as a capacity or balance limit.
save_failureNoWhy the save failed, when save_state is failed.
workspace_idYesThe Workspace UUID.
base_revisionYesThe saved revision the worker's copy started from.
change_statusYesunsubmitted 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_idYesThe task group of the worker. get_workspace_costs and stop_workspace_task_group take it.
working_copy_idYesThe copy of the Workspace files that this worker edits. The Workspace's current files do not change until its changes are accepted.
saved_revision_idNoThe saved revision that holds the worker's files once save_state is ready. read_workspace_file reads files from it.
worker_request_idYesThe worker's id; get_workspace_worker takes it.
saved_operation_idNoThe save that produced saved_revision_id.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 WorkspaceA
DestructiveIdempotent
Inspect

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.

NameRequiredDescriptionDefault
workspace_idYesThe Workspace UUID.

Output Schema

NameRequiredDescription
idNoThe Workspace UUID.
nameNoThe display name; not unique.
roleNoThe caller's role: owner, member or viewer.
stateNoactive, adopting (its files are moving to new storage; runs are refused until it is active again), deleting or deleted.
statusNo204 means the Workspace was already deleted.
accountNoThe account that owns the Workspace, with its user_id and email.
created_atNoWhen the Workspace was created.
updated_atNoWhen it last changed.
main_session_idNoThe main conversation id.
current_revisionNoThe saved revision of the Workspace's current files; read_workspace_file reads it by default.
default_agent_idNoThe 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_readinessNoPresent while the Workspace's storage is still starting: state, since, pending_reason, retryable.
root_working_copy_idNo
default_manager_agent_idNoThe same value as default_agent_id.

TDQS

A4.3/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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)A
Read-only
Inspect

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.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
packsYesCredit 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.
plansYesSubscription plans on offer, with their monthly credit grant.
limitsYesThe caps this account's plan tier enforces.
balanceYesThe account's remaining prepaid balance, in credits. 1,000,000 credits = 1 US dollar.
user_idYesThe identifier of the account this balance belongs to.
audienceYesanon: an anonymous trial; registered_free: a registered account without an active subscription; subscribed: an account with an active subscription.
plan_tierYesThe plan tier this account resolves to: free, pro or power. An account with no active plan is free.
active_planYesThe account's current subscription, or null when it has none and is on the free tier.
balance_usdYesThe account balance formatted in US dollars, without a currency symbol.
account_emailYesThe email address of the account this balance belongs to.
can_manage_billingYesWhether this account has a billing portal to manage its subscription (it has, or had, a plan); false for an anonymous trial.
low_credit_thresholdYesThe balance, in the same credits, below which this account is warned it is running low.

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 resultA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
waitNotrue: 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_idYesThe run_id to read: from a run result, continuation_run_id or resume_run_id.
agent_idNoThe agent that ran the run (agent_id in the result that returned the run_id). Give this or workspace_id.
wait_secondsNoHold 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_idNoThe Workspace the run belongs to. Give this or agent_id; with both, agent_id is used.

Output Schema

NameRequiredDescription
urlNoA deep link to this run's session in the plori web app.
hintNoWhat to do next with this run, in one sentence. Present only while the run is non-terminal.
textNoThe 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.
causeNoMachine-readable cause for a non-normal terminal state.
errorNoWhy 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.
filesNoFiles 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_idYesThe public run identifier; empty for an answered message whose continuation has not started.
statusYesThe 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.
tokensNoAttributed token count; null when attribution is unavailable.
advisorNoAdvisor calls used and allowed, spend this turn, and its optional spend cap in micro-US-dollars.
creditsNoAttributed spend in micro-US-dollars; null when attribution is unavailable.
agent_idNoThe agent that runs the run. get_run_result and cancel_run take this value or workspace_id.
ended_atNoWhen the run reached a terminal state.
steer_idNoDurable 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.
retryableNoWhether sending the same message again could plausibly succeed. A time_limit run can continue with a follow-up message.
session_idYesThe durable conversation/session identifier.
started_atNoWhen the run started.
file_sourceNoWhere this run's file links read from and whether its files are saved. Execution status does not report the save; check state here.
stop_reasonNoController-selected stop reason, when present.
input_statusNoThe 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_worklogNoThe 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_failureNoPresent 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_idNoThe Workspace UUID.
input_expiredNoTrue 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_msNoThe same wait as poll_after_seconds, in milliseconds.
resume_run_idNoThe exact auto-resume successor for an interrupted run; poll this run next.
resume_statusNoAuto-resume disposition for an interrupted run: pending, resumed, failed, or unknown.
tool_progressNoDurable tool execution progress; absent when this run has no tool-progress telemetry.
usage_by_roleNoAttributed spend, tokens, and model-call counts split into executor, advisor, and reviewer roles.
last_tool_stepNoWhat 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_inputsNoHuman inputs blocking an awaiting_input run.
elapsed_secondsNoSeconds since the run started; absent for a terminal result.
upstream_statusNoThe model provider's HTTP status when this run died on an upstream fault; absent otherwise.
last_activity_atNoWhen 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_atNoMost recent durable executor heartbeat.
continuation_errorNoWhy the answered message has not started its continuation.
poll_after_secondsNoSuggested seconds before polling again, paced to this run's recent tool-completion rate; absent for a terminal result.
continuation_run_idNoThe exact continuation created for an answered input; poll this run next.
continuation_pendingNoThe answer was recorded and its continuation has not started yet. Retry this message with the same idempotency key to get the continuation.

TDQS

A4/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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 changesetA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
changeset_idYesThe changeset_id from submit_workspace_changeset or list_workspace_changesets.
workspace_idYesThe Workspace UUID.

Output Schema

NameRequiredDescription
phaseYesThe 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.
stateYessubmitted (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.
changesNoThe changed paths, at most 500. get_workspace_changeset returns them; list_workspace_changesets leaves them out.
comparedYesTrue when the comparison is complete and changes and conflicts are known.
conflictsNoThe paths that conflict, when state is conflicted.
no_changeNoTrue when the worker changed no files.
created_atYesWhen the changeset was submitted.
updated_atYesWhen the changeset last changed.
auto_acceptNoSet 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_countYesThe number of changed paths.
changeset_idYesThe changeset UUID.
workspace_idYesThe Workspace UUID.
base_revisionYesThe revision the worker's copy started from.
result_revisionNoThe new current revision of the Workspace once an accepted changeset is saved.
terminal_reasonNoWhy a failed changeset failed.
working_copy_idYesThe worker's copy that the changes come from.
changes_truncatedNoTrue when there are more than 500 changed paths.
incoming_revisionYesThe worker's saved revision. read_workspace_file reads its files.
validation_evidenceNoThe evidence given when the changeset was accepted.
comparison_current_revisionNoThe Workspace revision the changes were compared with. accept_workspace_changeset takes it as expected_current_revision.

TDQS

A3.7/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 costsA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
toNoEnd of the window, RFC 3339, not in the future. Omitted, now. The window is at most 366 days.
fromNoStart of the window, RFC 3339. Omitted, 30 days before to.
workspace_idYesThe Workspace UUID.
task_group_idNoOnly report the charges of this task group of the Workspace.

Output Schema

NameRequiredDescription
idYesThe Workspace or task group UUID.
toYesEnd of the time window, RFC 3339.
fromYesStart of the time window, RFC 3339.
rowsYesThe charges that make up the total, one row per run and kind of usage, at most 200.
notesYesWhat the total includes and excludes.
scopeYesworkspace or task_group.
coverageYespartial 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_truncatedNoTrue when the scope has more than 200 charge rows; the total still includes all of them.
charged_micro_usdYesThe total charged to the account's balance for runs in this scope and window, in micro-US-dollars.
pending_compute_runsYesRuns whose compute charge is not settled yet; the total grows when they settle.

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 workerA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
workspace_idYesThe Workspace UUID.
worker_request_idYesThe worker_request_id that create_workspace_worker returned.

Output Schema

NameRequiredDescription
causeNoMachine-readable cause of a run that did not finish normally.
run_idNoThe 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.
statusYesWhere 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).
activityNoThe worker's expiring activity hint; absent when expired or unavailable. The saved changeset is authoritative.
agent_idYesThe agent that runs the worker. get_run_result and cancel_run take it with run_id.
run_statusNoThe run's status: running, awaiting_input (paused on an approval or question; get_run_result lists them), completed, error or cancelled.
save_stateYesWhether 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_idYesThe worker's own conversation id. It is private to the worker; send_workspace_message cannot select it.
stop_reasonNoThe stop reason of an ended run, when one was recorded.
changeset_idNoThe changeset submitted for this worker's files, if any.
queue_reasonNoWhy a waiting worker has not started, such as a capacity or balance limit.
save_failureNoWhy the save failed, when save_state is failed.
workspace_idYesThe Workspace UUID.
base_revisionYesThe saved revision the worker's copy started from.
change_statusYesunsubmitted 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_idYesThe task group of the worker. get_workspace_costs and stop_workspace_task_group take it.
working_copy_idYesThe copy of the Workspace files that this worker edits. The Workspace's current files do not change until its changes are accepted.
saved_revision_idNoThe saved revision that holds the worker's files once save_state is ready. read_workspace_file reads files from it.
worker_request_idYesThe worker's id; get_workspace_worker takes it.
saved_operation_idNoThe save that produced saved_revision_id.

TDQS

A4.1/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 questionsA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
agent_idNoThe agent UUID (agent_id in a run result). Give this or workspace_id.
workspace_idNoThe 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

NameRequiredDescription
pending_inputsYesRuns 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

A3.9/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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 runsA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
limitNoHow many runs to return, newest first (default 20, maximum 100).
cursorNoThe next_cursor from a previous list_runs result, to continue where it stopped. Omit for the newest page.
agent_idNoThe agent UUID (agent_id in a run result). Give this or workspace_id.
workspace_idNoThe 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

NameRequiredDescription
itemsYesOne page of the agent's runs, most recently started first.
next_cursorNoPass this back as cursor to read the next page. Absent when this page is the end of the history.

TDQS

A4.1/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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 changesetsA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
limitNoChangesets per page, 1-100. Omitted, 50.
cursorNonext_cursor from the previous page.
workspace_idYesThe Workspace UUID.

Output Schema

NameRequiredDescription
itemsYesOne page of the Workspace's changesets, without their changed paths.
next_cursorNoPass this back as cursor to read the next page. Absent on the last page.

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 WorkspacesA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
workspace_idNoThe Workspace UUID. Omitted, all Workspaces are returned.

Output Schema

NameRequiredDescription
workspacesYesThe caller's own and shared Workspaces; one entry when workspace_id was given.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 workersA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
limitNoWorkers per page, 1-100. Omitted, 25.
cursorNonext_cursor from the previous page.
workspace_idYesThe Workspace UUID.
task_group_idNoOnly list the workers of this task group.

Output Schema

NameRequiredDescription
itemsYesOne page of the Workspace's workers, oldest first.
next_cursorNoPass this back as cursor to read the next page. Absent on the last page.

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 fileA
Read-only
Inspect

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.

NameRequiredDescriptionDefault
pathYesThe file or directory path, relative to the Workspace root, for example src/main.go or / for the root.
cursorNoFor a directory: next_cursor from the previous page.
revision_idNoThe saved revision to read. Omitted, the Workspace's current revision.
workspace_idYesThe Workspace UUID.

Output Schema

NameRequiredDescription
kindYesfile or dir.
pathYesThe path that was read.
sizeNoThe file's size in bytes.
textNoThe file's UTF-8 text, for a file.
entriesNoThe directory's entries, for a directory.
next_cursorNoFor a directory with more entries: pass it back as cursor to read the next page.
revision_idYesThe saved revision that was read.
workspace_idYesThe Workspace UUID.

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 changesetA
DestructiveIdempotent
Inspect

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.

NameRequiredDescriptionDefault
changeset_idYesThe changeset_id from submit_workspace_changeset or list_workspace_changesets.
workspace_idYesThe Workspace UUID.

Output Schema

NameRequiredDescription
phaseYesThe 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.
stateYessubmitted (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.
changesNoThe changed paths, at most 500. get_workspace_changeset returns them; list_workspace_changesets leaves them out.
comparedYesTrue when the comparison is complete and changes and conflicts are known.
conflictsNoThe paths that conflict, when state is conflicted.
no_changeNoTrue when the worker changed no files.
created_atYesWhen the changeset was submitted.
updated_atYesWhen the changeset last changed.
auto_acceptNoSet 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_countYesThe number of changed paths.
changeset_idYesThe changeset UUID.
workspace_idYesThe Workspace UUID.
base_revisionYesThe revision the worker's copy started from.
result_revisionNoThe new current revision of the Workspace once an accepted changeset is saved.
terminal_reasonNoWhy a failed changeset failed.
working_copy_idYesThe worker's copy that the changes come from.
changes_truncatedNoTrue when there are more than 500 changed paths.
incoming_revisionYesThe worker's saved revision. read_workspace_file reads its files.
validation_evidenceNoThe evidence given when the changeset was accepted.
comparison_current_revisionNoThe Workspace revision the changes were compared with. accept_workspace_changeset takes it as expected_current_revision.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 runA
Destructive
Inspect

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.

NameRequiredDescriptionDefault
promptYesThe message to send the agent when the schedule fires.
fire_atNoFire at this RFC3339 timestamp (mutually exclusive with delay_seconds).
agent_idNoThe agent's UUID. Give this or workspace_id.
session_idNoA 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_idNoThe Workspace UUID; the Workspace's agent runs the prompt. Give this or agent_id; with both, agent_id is used.
delay_secondsNoFire this many seconds from now (mutually exclusive with fire_at).

Output Schema

NameRequiredDescription
idYesThe schedule's id.
kindYesonce: a single run at fire_at.
promptYesThe message the agent receives when the schedule fires.
statusYesawaiting_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_atNoWhen it fires, RFC 3339.
agent_idYesThe agent the run is scheduled for.
attemptsYesDelivery attempts so far.
metadataNoExtra data recorded with the request; not needed to use it.
thread_idNoThe 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_atYesWhen the request was made.
last_errorNoWhy the last delivery attempt failed, when it did.
confirm_urlNoWhere the owner confirms, in the Plori web app.
confirmed_atNoWhen the owner confirmed it.
last_fired_atNoWhen it last fired.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 WorkspaceA
Destructive
Inspect

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.

NameRequiredDescriptionDefault
waitNoQueued 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.
messageYesThe message for the agent, in plain text.
session_idNoA 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_urlNoOptional callback URL for this run. Must use http or https and resolve only to public addresses.
wait_secondsNoHold 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_idYesThe Workspace UUID.
callback_secretNoOptional secret used to sign callback deliveries with HMAC-SHA256.
idempotency_keyNoA 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_tokensNoOptional 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_secondsNoOptional 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_usdNoOptional 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

NameRequiredDescription
urlNoA deep link to this run's session in the plori web app.
hintNoWhat to do next with this run, in one sentence. Present only while the run is non-terminal.
textNoThe 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.
causeNoMachine-readable cause for a non-normal terminal state.
errorNoWhy 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.
filesNoFiles 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_idYesThe public run identifier; empty for an answered message whose continuation has not started.
statusYesThe 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.
tokensNoAttributed token count; null when attribution is unavailable.
advisorNoAdvisor calls used and allowed, spend this turn, and its optional spend cap in micro-US-dollars.
creditsNoAttributed spend in micro-US-dollars; null when attribution is unavailable.
agent_idNoThe agent that runs the run. get_run_result and cancel_run take this value or workspace_id.
ended_atNoWhen the run reached a terminal state.
steer_idNoDurable 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.
retryableNoWhether sending the same message again could plausibly succeed. A time_limit run can continue with a follow-up message.
session_idYesThe durable conversation/session identifier.
started_atNoWhen the run started.
file_sourceNoWhere this run's file links read from and whether its files are saved. Execution status does not report the save; check state here.
stop_reasonNoController-selected stop reason, when present.
input_statusNoThe 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_worklogNoThe 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_failureNoPresent 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_idNoThe Workspace UUID.
input_expiredNoTrue 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_msNoThe same wait as poll_after_seconds, in milliseconds.
resume_run_idNoThe exact auto-resume successor for an interrupted run; poll this run next.
resume_statusNoAuto-resume disposition for an interrupted run: pending, resumed, failed, or unknown.
tool_progressNoDurable tool execution progress; absent when this run has no tool-progress telemetry.
usage_by_roleNoAttributed spend, tokens, and model-call counts split into executor, advisor, and reviewer roles.
last_tool_stepNoWhat 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_inputsNoHuman inputs blocking an awaiting_input run.
elapsed_secondsNoSeconds since the run started; absent for a terminal result.
upstream_statusNoThe model provider's HTTP status when this run died on an upstream fault; absent otherwise.
last_activity_atNoWhen 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_atNoMost recent durable executor heartbeat.
continuation_errorNoWhy the answered message has not started its continuation.
poll_after_secondsNoSuggested seconds before polling again, paced to this run's recent tool-completion rate; absent for a terminal result.
continuation_run_idNoThe exact continuation created for an answered input; poll this run next.
continuation_pendingNoThe answer was recorded and its continuation has not started yet. Retry this message with the same idempotency key to get the continuation.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness3/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 runA
Destructive
Inspect

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.

NameRequiredDescriptionDefault
run_idYesThe running run to send the message to.
messageYesThe message for the agent, in plain text (at most 65536 bytes).
idempotency_keyNoOptional string of 1-255 bytes you generate for this message. Omitted, each call sends a new message.

Output Schema

NameRequiredDescription
run_idYesThe run that holds the message.
steer_idYesThe id of the delivered message.
dispositionYessteering: 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

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 groupA
DestructiveIdempotent
Inspect

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.

NameRequiredDescriptionDefault
workspace_idYesThe Workspace UUID.
task_group_idYesThe task group to stop (task_group_id of a worker).

Output Schema

NameRequiredDescription
runsYesThe group's runs whose cancellation this call requested.
stateYesstopping until every worker run of the group has ended, then stopped. A stopped group starts no new workers.
task_group_idYesThe task group UUID.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 reviewA
DestructiveIdempotent
Inspect

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.

NameRequiredDescriptionDefault
workspace_idYesThe Workspace UUID.
worker_request_idYesThe worker whose saved files to submit (worker_request_id).

Output Schema

NameRequiredDescription
phaseYesThe 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.
stateYessubmitted (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.
changesNoThe changed paths, at most 500. get_workspace_changeset returns them; list_workspace_changesets leaves them out.
comparedYesTrue when the comparison is complete and changes and conflicts are known.
conflictsNoThe paths that conflict, when state is conflicted.
no_changeNoTrue when the worker changed no files.
created_atYesWhen the changeset was submitted.
updated_atYesWhen the changeset last changed.
auto_acceptNoSet 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_countYesThe number of changed paths.
changeset_idYesThe changeset UUID.
workspace_idYesThe Workspace UUID.
base_revisionYesThe revision the worker's copy started from.
result_revisionNoThe new current revision of the Workspace once an accepted changeset is saved.
terminal_reasonNoWhy a failed changeset failed.
working_copy_idYesThe worker's copy that the changes come from.
changes_truncatedNoTrue when there are more than 500 changed paths.
incoming_revisionYesThe worker's saved revision. read_workspace_file reads its files.
validation_evidenceNoThe evidence given when the changeset was accepted.
comparison_current_revisionNoThe Workspace revision the changes were compared with. accept_workspace_changeset takes it as expected_current_revision.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 fileA
Destructive
Inspect

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).

NameRequiredDescriptionDefault
pathYesThe file's path, relative to the Workspace root, for example docs/notes.md. Missing directories are created.
contentNoThe file's UTF-8 text, up to 262144 bytes. Omit it, or pass an empty string, to get an upload URL instead.
workspace_idYesThe Workspace UUID.

Output Schema

NameRequiredDescription
pathYesThe file's path, from the Workspace root.
sizeNoThe bytes written, when written is true.
commandNoThe curl command that uploads the file: replace LOCAL_FILE with the local file's path and run it in a shell.
writtenYesTrue when content was written to the file. False when the call returned an upload URL instead.
max_bytesNoThe largest file upload_url accepts, in bytes.
expires_atNoWhen upload_url stops being accepted.
upload_urlNoThe URL that accepts one upload of the file as multipart form part file. It needs no other credential.
workspace_idYesThe Workspace UUID.

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

  1. 42 tool updatesv0.17.1
    • Addedaccept_workspace_changeset
    • Changedanswer_pending_input8 fields changed
      • changedInput schema / properties / approved / description
        Previous 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."
      • changedInput schema / properties / max_turn_seconds / description
        Previous 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."
      • changedInput schema / properties / run_id / description
        Previous value: -"The parked run's id."New value: +"The paused run's run_id."
      • changedInput schema / properties / tool_call_id / description
        Previous 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."
      • changedInput schema / properties / value / description
        Previous value: -"For an input request: the value to supply."New value: +"The answer to a question."
      • addedOutput schema / properties / continuation_error
        Added value: +{
        +  "description": "Why the continuation has not started or will not start, when the platform recorded a reason. The answer stays recorded.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / continuation_pending
        Added 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"
        +}
      • changedOutput schema / properties / run_id / description
        Previous 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."
    • Changedcancel_run4 fields changed
      • changedInput schema / properties / agent_id / description
        Previous value: -"The agent's UUID."New value: +"The agent that runs the run (agent_id in the run result). Give this or workspace_id."
      • changedInput schema / properties / run_id / description
        Previous value: -"The run id returned by invoke_agent."New value: +"The run to cancel."
      • addedInput schema / properties / workspace_id
        Added value: +{
        +  "description": "The Workspace the run belongs to. Give this or agent_id; with both, agent_id is used.",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "agent_id",
        -  "run_id"
        -]New value: +[
        +  "run_id"
        +]
    • Removedcreate_agent
    • Removedcreate_workflow
    • Addedcreate_workspace
    • Addedcreate_workspace_worker
    • Removeddelete_agent
    • Addeddelete_workspace
    • Removededit_workflow
    • Removedempty_trash
    • Removedget_agent
    • Changedget_credits3 fields changed
      • addedOutput schema / properties / audience / description
        Added value: +"anon: an anonymous trial; registered_free: a registered account without an active subscription; subscribed: an account with an active subscription."
      • addedOutput schema / properties / can_manage_billing / description
        Added value: +"Whether this account has a billing portal to manage its subscription (it has, or had, a plan); false for an anonymous trial."
      • changedOutput schema / properties / limits / properties / max_concurrent_runs / description
        Previous 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)."
    • Removedget_disk
    • Changedget_run_result25 fields changed
      • changedInput schema / properties / agent_id / description
        Previous 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."
      • changedInput schema / properties / run_id / description
        Previous 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."
      • changedInput schema / properties / wait / description
        Previous 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."
      • changedInput schema / properties / wait_seconds / description
        Previous 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."
      • addedInput schema / properties / workspace_id
        Added value: +{
        +  "description": "The Workspace the run belongs to. Give this or agent_id; with both, agent_id is used.",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "agent_id",
        -  "run_id"
        -]New value: +[
        +  "run_id"
        +]
      • addedOutput schema / properties / agent_id
        Added value: +{
        +  "description": "The agent that runs the run. get_run_result and cancel_run take this value or workspace_id.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / continuation_error
        Added value: +{
        +  "description": "Why the answered message has not started its continuation.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / continuation_pending
        Added 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"
        +}
      • addedOutput schema / properties / file_source
        Added 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"
        +  ]
        +}
      • changedOutput schema / properties / files / description
        Previous 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."
      • changedOutput schema / properties / files / items / properties / path / description
        Previous 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."
      • changedOutput schema / properties / files / items / properties / url / description
        Previous 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."
      • changedOutput schema / properties / files / items / required
        Previous value: -[
        -  "path",
        -  "url"
        -]New value: +[
        +  "path"
        +]
      • changedOutput schema / properties / input_expired / description
        Previous 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."
      • addedOutput schema / properties / pending_inputs / items / properties / assigned_to
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "email": {
        +      "type": "string"
        +    },
        +    "user_id": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "user_id",
        +    "email"
        +  ],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / pending_inputs / items / properties / open_to_members_at
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / pending_inputs / items / required
        Previous value: -[
        -  "tool_call_id",
        -  "kind",
        -  "prompt"
        -]New value: +[
        +  "assigned_to",
        +  "tool_call_id",
        +  "kind",
        +  "prompt"
        +]
      • changedOutput schema / properties / poll_after_ms / description
        Previous 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."
      • changedOutput schema / properties / retryable / description
        Previous 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."
      • changedOutput schema / properties / run_id / description
        Previous value: -"The public run identifier."New value: +"The public run identifier; empty for an answered message whose continuation has not started."
      • addedOutput schema / properties / save_failure
        Added 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"
        +  ]
        +}
      • changedOutput schema / properties / status / description
        Previous 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."
      • addedOutput schema / properties / steer_id
        Added 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"
        +}
      • addedOutput schema / properties / workspace_id
        Added value: +{
        +  "description": "The Workspace UUID.",
        +  "type": "string"
        +}
    • Removedget_usage
    • Removedget_workflow
    • Removedget_workflow_execution
    • Removedget_workflow_version
    • Addedget_workspace_changeset
    • Addedget_workspace_costs
    • Addedget_workspace_worker
    • Removedinvoke_agent
    • Removedlist_agents
    • Removedlist_connections
    • Changedlist_pending_inputs12 fields changed
      • changedInput schema / properties / agent_id / description
        Previous value: -"The agent's UUID."New value: +"The agent UUID (agent_id in a run result). Give this or workspace_id."
      • addedInput schema / properties / workspace_id
        Added 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"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "agent_id"
        -]
      • changedOutput schema / properties / pending_inputs / description
        Previous 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."
      • addedOutput schema / properties / pending_inputs / items / properties / agent_name
        Added value: +{
        +  "type": "string"
        +}
      • changedOutput schema / properties / pending_inputs / items / properties / args / description
        Previous value: -"Arbitrary JSON owned by the producing engine."New value: +"Extra data recorded with the request; not needed to use it."
      • addedOutput schema / properties / pending_inputs / items / properties / assigned_to
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "email": {
        +      "type": "string"
        +    },
        +    "user_id": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "user_id",
        +    "email"
        +  ],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / pending_inputs / items / properties / can_act
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / pending_inputs / items / properties / open_to_members_at
        Added value: +{
        +  "type": "string"
        +}
      • changedOutput schema / properties / pending_inputs / items / properties / schema / description
        Previous value: -"Arbitrary JSON owned by the producing engine."New value: +"Extra data recorded with the request; not needed to use it."
      • addedOutput schema / properties / pending_inputs / items / properties / worker_request_id
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / pending_inputs / items / required
        Previous 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"
        +]
    • Changedlist_runs9 fields changed
      • changedInput schema / properties / agent_id / description
        Previous value: -"The agent's UUID."New value: +"The agent UUID (agent_id in a run result). Give this or workspace_id."
      • addedInput schema / properties / workspace_id
        Added 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"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "agent_id"
        -]
      • addedOutput schema / properties / items / items / properties / events_expired_at
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • addedOutput schema / properties / items / items / properties / history_error
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / private_history_expired_at
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • addedOutput schema / properties / items / items / properties / retention_policy
        Added value: +{
        +  "description": "Extra data recorded with the request; not needed to use it."
        +}
      • addedOutput schema / properties / items / items / properties / save_failure
        Added 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"
        +  ]
        +}
      • changedOutput schema / properties / items / items / properties / session_id / description
        Previous 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."
    • Removedlist_workflow_executions
    • Removedlist_workflows
    • Addedlist_workspace_changesets
    • Addedlist_workspace_workers
    • Addedlist_workspaces
    • Addedread_workspace_file
    • Addedreject_workspace_changeset
    • Removedrun_workflow
    • Changedschedule_run18 fields changed
      • changedInput schema / properties / agent_id / description
        Previous value: -"The agent's UUID."New value: +"The agent's UUID. Give this or workspace_id."
      • changedInput schema / properties / session_id / description
        Previous 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."
      • addedInput schema / properties / workspace_id
        Added 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"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "agent_id",
        -  "prompt"
        -]New value: +[
        +  "prompt"
        +]
      • addedOutput schema / properties / agent_id / description
        Added value: +"The agent the run is scheduled for."
      • addedOutput schema / properties / attempts / description
        Added value: +"Delivery attempts so far."
      • addedOutput schema / properties / confirm_url / description
        Added value: +"Where the owner confirms, in the Plori web app."
      • addedOutput schema / properties / confirmed_at / description
        Added value: +"When the owner confirmed it."
      • addedOutput schema / properties / created_at / description
        Added value: +"When the request was made."
      • addedOutput schema / properties / fire_at / description
        Added value: +"When it fires, RFC 3339."
      • addedOutput schema / properties / id / description
        Added value: +"The schedule's id."
      • addedOutput schema / properties / kind / description
        Added value: +"once: a single run at fire_at."
      • addedOutput schema / properties / last_error / description
        Added value: +"Why the last delivery attempt failed, when it did."
      • addedOutput schema / properties / last_fired_at / description
        Added value: +"When it last fired."
      • changedOutput schema / properties / metadata / description
        Previous value: -"Arbitrary JSON owned by the producing engine."New value: +"Extra data recorded with the request; not needed to use it."
      • addedOutput schema / properties / prompt / description
        Added value: +"The message the agent receives when the schedule fires."
      • addedOutput schema / properties / status / description
        Added 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."
      • addedOutput schema / properties / thread_id / description
        Added 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."
    • Addedsend_workspace_message
    • Removedset_workflow_agent
    • Addedsteer_workspace_worker
    • Addedstop_workspace_task_group
    • Addedsubmit_workspace_changeset
    • Addedupload_workspace_file
  2. 7 tool updatesv0.17.0
    • Changedanswer_pending_input3 fields changed
      • removedInput schema / properties / always_allow
        Removed 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"
        -}
      • changedInput schema / properties / approved / description
        Previous 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."
      • removedInput schema / properties / scope
        Removed 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"
        -}
    • Changedempty_trash1 field changed
      • addedOutput schema / properties / disk / properties / agents
        Added 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"
        +  ]
        +}
    • Changedget_disk1 field changed
      • addedOutput schema / properties / agents
        Added 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"
        +  ]
        +}
    • Changedget_run_result1 field changed
      • addedOutput schema / properties / pending_inputs / items / properties / approve_url
        Added value: +{
        +  "type": "string"
        +}
    • Changedinvoke_agent1 field changed
      • addedOutput schema / properties / pending_inputs / items / properties / approve_url
        Added value: +{
        +  "type": "string"
        +}
    • Changedlist_pending_inputs1 field changed
      • addedOutput schema / properties / pending_inputs / items / properties / approve_url
        Added value: +{
        +  "type": "string"
        +}
    • Changedschedule_run2 fields changed
      • addedOutput schema / properties / confirm_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / confirmed_at
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
  3. 7 tool updatesv0.16.2
    • Changedcreate_agent2 fields changed
      • addedOutput schema / properties / advisor_max_spend_micro_usd
        Added 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"
        +  ]
        +}
      • changedOutput schema / required
        Previous 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"
        +]
    • Changedget_agent2 fields changed
      • addedOutput schema / properties / advisor_max_spend_micro_usd
        Added 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"
        +  ]
        +}
      • changedOutput schema / required
        Previous 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"
        +]
    • Changedget_run_result3 fields changed
      • addedOutput schema / properties / advisor
        Added 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"
        +}
      • addedOutput schema / properties / error / properties / upgrade
        Added 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"
        +  ]
        +}
      • addedOutput schema / properties / usage_by_role
        Added 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"
        +  ]
        +}
    • Changedget_usage11 fields changed
      • addedOutput schema / properties / by_role
        Added 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"
        +}
      • addedOutput schema / properties / recent_runs / items / properties / advisor
        Added 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"
        +}
      • addedOutput schema / properties / recent_runs / items / properties / credits / description
        Added value: +"The net charge after any refund."
      • addedOutput schema / properties / recent_runs / items / properties / error / properties / upgrade
        Added 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"
        +  ]
        +}
      • addedOutput schema / properties / recent_runs / items / properties / gross_micro_usd
        Added value: +{
        +  "description": "Gross consumption before any refund.",
        +  "type": "integer"
        +}
      • addedOutput schema / properties / recent_runs / items / properties / refund_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / recent_runs / items / properties / refund_withheld_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / recent_runs / items / properties / refunded_micro_usd
        Added value: +{
        +  "description": "The refund reported once for this run.",
        +  "type": "integer"
        +}
      • addedOutput schema / properties / recent_runs / items / properties / usage_by_role
        Added 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"
        +  ]
        +}
      • changedOutput schema / properties / recent_runs / items / required
        Previous 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"
        +]
      • changedOutput schema / required
        Previous 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"
        +]
    • Changedinvoke_agent4 fields changed
      • addedInput schema / properties / max_advisor_spend_micro_usd
        Added 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"
        +}
      • addedOutput schema / properties / advisor
        Added 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"
        +}
      • addedOutput schema / properties / error / properties / upgrade
        Added 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"
        +  ]
        +}
      • addedOutput schema / properties / usage_by_role
        Added 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"
        +  ]
        +}
    • Changedlist_agents2 fields changed
      • addedOutput schema / properties / items / items / properties / advisor_max_spend_micro_usd
        Added 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"
        +  ]
        +}
      • changedOutput schema / properties / items / items / required
        Previous 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"
        +]
    • Changedlist_runs9 fields changed
      • addedOutput schema / properties / items / items / properties / advisor
        Added 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"
        +}
      • addedOutput schema / properties / items / items / properties / credits / description
        Added value: +"The net charge after any refund."
      • addedOutput schema / properties / items / items / properties / error / properties / upgrade
        Added 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"
        +  ]
        +}
      • addedOutput schema / properties / items / items / properties / gross_micro_usd
        Added value: +{
        +  "description": "Gross consumption before any refund.",
        +  "type": "integer"
        +}
      • addedOutput schema / properties / items / items / properties / refund_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / refund_withheld_reason
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / refunded_micro_usd
        Added value: +{
        +  "description": "The refund reported once for this run.",
        +  "type": "integer"
        +}
      • addedOutput schema / properties / items / items / properties / usage_by_role
        Added 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"
        +  ]
        +}
      • changedOutput schema / properties / items / items / required
        Previous 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"
        +]
  4. 26 tool updatesv0.16.0
    • Changedanswer_pending_input2 fields changed
      • addedInput schema / properties / scope
        Added 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"
        +}
      • changedOutput 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"
        +}
    • Changedcancel_run1 field changed
      • changedOutput 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"
        +}
    • Changedcreate_agent2 fields changed
      • removedInput schema / properties / model
        Removed 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"
        -}
      • changedOutput 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"
        +}
    • Changedcreate_workflow4 fields changed
      • changedInput schema / properties / cron_expr / description
        Previous 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."
      • changedInput schema / properties / description / description
        Previous 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."
      • changedInput schema / properties / trigger_kind / description
        Previous 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."
      • changedOutput 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"
        +}
    • Changeddelete_agent1 field changed
      • changedOutput 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"
        +}
    • Changededit_workflow1 field changed
      • changedOutput 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"
        +}
    • Addedempty_trash
    • Changedget_agent1 field changed
      • changedOutput 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"
        +}
    • Changedget_credits1 field changed
      • changedOutput 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"
        +}
    • Changedget_disk1 field changed
      • changedOutput 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"
        +}
    • Changedget_run_result3 fields changed
      • addedInput schema / properties / wait
        Added 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"
        +}
      • addedInput schema / properties / wait_seconds
        Added 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"
        +}
      • changedOutput 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"
        +}
    • Changedget_usage1 field changed
      • changedOutput 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"
        +}
    • Changedget_workflow1 field changed
      • changedOutput 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"
        +}
    • Changedget_workflow_execution1 field changed
      • changedOutput 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"
        +}
    • Changedget_workflow_version1 field changed
      • changedOutput 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"
        +}
    • Changedinvoke_agent7 fields changed
      • addedInput schema / properties / callback_secret
        Added value: +{
        +  "description": "Optional secret used to sign callback deliveries with HMAC-SHA256.",
        +  "type": "string"
        +}
      • addedInput schema / properties / callback_url
        Added value: +{
        +  "description": "Optional callback URL for this run. Must use http or https and resolve only to public addresses.",
        +  "type": "string"
        +}
      • changedInput schema / properties / max_turn_seconds / description
        Previous 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."
      • changedInput schema / properties / max_turn_tokens / description
        Previous 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."
      • changedInput schema / properties / wait / description
        Previous 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."
      • addedInput schema / properties / wait_seconds
        Added 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"
        +}
      • changedOutput 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"
        +}
    • Changedlist_agents1 field changed
      • changedOutput 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"
        +}
    • Changedlist_connections1 field changed
      • changedOutput 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"
        +}
    • Changedlist_pending_inputs1 field changed
      • changedOutput 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"
        +}
    • Changedlist_runs3 fields changed
      • addedInput schema / properties / cursor
        Added value: +{
        +  "description": "The next_cursor from a previous list_runs result, to continue where it stopped. Omit for the newest page.",
        +  "type": "string"
        +}
      • addedInput schema / properties / limit
        Added value: +{
        +  "description": "How many runs to return, newest first (default 20, maximum 100).",
        +  "maximum": 100,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • changedOutput 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"
        +}
    • Changedlist_workflow_executions1 field changed
      • changedOutput 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"
        +}
    • Changedlist_workflows1 field changed
      • changedOutput 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"
        +}
    • Changedrun_workflow1 field changed
      • changedOutput 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"
        +}
    • Changedschedule_run1 field changed
      • changedOutput 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"
        +}
    • Removedset_agent_model
    • Addedset_workflow_agent
  5. 2 tool updatesv0.9.1
    • Changedanswer_pending_input1 field changed
      • addedInput schema / properties / max_turn_seconds
        Added 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"
        +}
    • Changedinvoke_agent1 field changed
      • addedInput schema / properties / max_turn_seconds
        Added 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"
        +}
  6. 4 tool updatesv0.9.0
    • Addedcancel_run
    • Addededit_workflow
    • Addedget_workflow_version
    • Changedinvoke_agent1 field changed
      • addedInput schema / properties / max_turn_tokens
        Added 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"
        +}
  7. 14 tool updatesv0.7.0
    • Changedanswer_pending_input1 field changed
      • addedInput schema / properties / always_allow
        Added 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"
        +}
    • Changedcreate_agent1 field changed
      • changedInput schema / properties / model / description
        Previous 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."
    • Changedcreate_workflow1 field changed
      • changedInput schema / properties / agent_id / description
        Previous 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."
    • Addedget_agent
    • Addedget_usage
    • Addedget_workflow
    • Changedinvoke_agent1 field changed
      • changedInput schema / properties / session_id / description
        Previous 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."
    • Addedlist_connections
    • Addedlist_runs
    • Addedlist_workflow_executions
    • Changedlist_workflows1 field changed
      • addedInput schema / properties / agent_id
        Added value: +{
        +  "description": "Optional: a UUID of one of your agents to list only its workflows, or \"none\" for the unassigned ones.",
        +  "type": "string"
        +}
    • Addedrun_workflow
    • Addedschedule_run
    • Addedset_agent_model
  8. 13 tool updatesv0.3.0
    • Changedcreate_agent1 field changed
      • changedInput schema / properties / model / description
        Previous 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."
    • Removedget_agent
    • Changedget_credits1 field changed
      • addedInput schema / properties
        Added value: +{}
    • Changedget_disk1 field changed
      • addedInput schema / properties
        Added value: +{}
    • Removedget_usage
    • Changedinvoke_agent1 field changed
      • addedInput schema / properties / idempotency_key
        Added 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"
        +}
    • Changedlist_agents1 field changed
      • addedInput schema / properties
        Added value: +{}
    • Removedlist_brains
    • Removedlist_runs
    • Changedlist_workflows1 field changed
      • addedInput schema / properties
        Added value: +{}
    • Removedrun_workflow
    • Removedschedule_run
    • Removedset_agent_model
  9. 6 tool updatesv0.1.1
    • Changedcreate_agent1 field changed
      • changedInput schema / properties / name / description
        Previous value: -"A human-readable name for the agent."New value: +"The agent's name. Reusing a previous name returns that existing agent."
    • Addedcreate_workflow
    • Addedget_workflow_execution
    • Changedinvoke_agent1 field changed
      • changedInput schema / properties / wait / description
        Previous 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."
    • Addedlist_workflows
    • Addedrun_workflow
  10. 15 tool updatesv0.1.0
    • First observedanswer_pending_input
    • First observedcreate_agent
    • First observeddelete_agent
    • First observedget_agent
    • First observedget_credits
    • First observedget_disk
    • First observedget_run_result
    • First observedget_usage
    • First observedinvoke_agent
    • First observedlist_agents
    • First observedlist_brains
    • First observedlist_pending_inputs
    • First observedlist_runs
    • First observedschedule_run
    • First observedset_agent_model

TDQS

A4.1/5.0

Scored across 24 tools

Disambiguation4/5

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.

Naming Consistency5/5

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.

Tool Count3/5

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.

Completeness4/5

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

ActivityActive
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Host 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