0.0 / 30
What changed in the harness
Selection accuracy 100→98, token cost up 8%, unconfirmed writes 0%→0%.
Category breakdown
Where the score comes from.
Earned points across the four signals Gradable measures. Safety and Legibility are scored out of 30; Economics and Discoverability are scored out of 20.
01Safety
02Legibility
19.0 / 30
03Economics
12.5 / 20
04Discoverability
14.4 / 20
Highest-impact fix
Estimated gain +30 pointsAdd explicit identity and permission preflight tools
Expose machine-readable principal/tenant confirmation and a non-mutating permission check so agents can verify both before destructive actions.
Description evidence
Defects and rewrites.
35 defects found across the exposed tool descriptions. Suggested rewrites make purpose, inputs, boundaries, and returns easier for an agent to understand.
| Tool | Defect types | Suggested rewrite |
|---|---|---|
list_tasks |
no_return_description |
List tasks from Delega. Visibility depends on your role: workers see tasks they created, were assigned, completed, or claimed; coordinators and admins see all account tasks — including other agents' work, so act only on tasks assigned to you or unowned ones you claim, and coordinate on teammates' tasks via add_comment. Returns an array of matching task objects (each with an id usable with get_task, plus content, status, and assignment/claim details). Optionally filtered by project, label, due date, or completion status. To resume work at the start of a session, call with completed:false, then use get_task_context on your tasks to recover prior decisions and state instead of starting from zero. |
get_task |
name_restates_behavior no_return_description |
Fetch the complete record for a single task, including its subtasks. Pass the task ID from list_tasks (e.g. '3a7d...'). Returns the task object with its fields (id, content, status, project, labels, priority, due date, assignee, evidence policy) plus the nested subtasks. Use this when you need full detail on one task rather than the filtered list. |
link_task |
no_return_description |
Attach a branch, commit, pull request, or URL link to a task. Use this when work in a repo, PR, or external artifact should travel with the task. Requires task_id, kind (branch/commit/pr/url), and ref (branch name, commit SHA, PR number, or URL); repo and url are optional. Returns confirmation of the created link (kind and ref) now attached to the task, which appears in later list_task_links calls. |
list_task_links |
name_restates_behavior no_return_description |
Return all branch, commit, pull request, and URL links attached to a task. Pass the task_id from list_tasks. Returns an array of link objects for that task, each with a kind (branch/commit/pr/url) and a ref (branch name, commit SHA, PR number, or URL) matching what link_task stored. |
create_task |
name_restates_behavior no_return_description |
Create a new task in Delega. Only content (title) is required; optionally set description, project_id, labels, priority (1=normal to 4=urgent), due_date (YYYY-MM-DD), and evidence_policy='required' to force structured completion evidence before the task can be completed. Returns the created task object including its new id, usable with get_task, update_task, assign_task, or complete_task. |
list_recurrences |
no_return_description |
List recurring task templates. Recurrences spawn normal task instances on schedule; completing an instance does not delete the schedule. Returns an array of recurrence templates with their ids, rule configuration, and active status — pass a recurrence_id to update_recurrence or delete_recurrence. |
create_recurring_task |
params_unexplained no_return_description |
Create a recurring task template; the hosted scheduler spawns normal task instances from it on schedule and links them with source_recurrence_id. Requires content and rule_type (daily/weekly/monthly/yearly). Configure the cadence with interval, timezone, and the matching anchors (anchor_day, anchor_month, anchor_weekday), plus optional next_due_at, priority, labels, project_id (the project spawned instances belong to), assigned_to_agent_id, and skip_if_open. Returns the created template with its recurrence_id for later updates. |
update_recurrence |
no_return_description |
Update a recurring task template, including pausing/resuming with active=false/true. Pass recurrence_id plus any fields to change; passing null clears optional fields such as project_id, assigned_to_agent_id, anchor_day, anchor_month, or anchor_weekday. Returns the updated recurrence template confirming the new configuration and schedule. |
delete_recurrence |
no_return_description |
Delete a recurring task template by its recurrence_id. Existing spawned task instances remain as normal tasks and are not deleted. Returns confirmation of the deletion; the schedule stops spawning further instances. |
update_task |
name_restates_behavior no_return_description |
Modify fields of an existing task passed via task_id: content, description, labels, priority, due_date (YYYY-MM-DD), move to another project with project_id, reassign with assigned_to_agent_id (null to unassign), or change evidence_policy (null clears a required policy, though removing one already set to required needs an admin key). Only fields you supply are changed. Returns the updated task object reflecting the new state. |
assign_task |
name_restates_behavior no_return_description |
Set the owner of an existing task: pass task_id with the agent_id to assign to, or pass null to unassign. Prefer delegate_task for multi-agent handoffs so the delegation chain is recorded. Returns the updated task with its new assignee (or none when unassigned). |
delegate_task |
no_return_description |
Delegate a task: create a child task linked to a parent, and the parent's status flips to 'delegated'. Use this (not assign_task) for multi-agent handoffs so the delegation chain is recorded. Requires task_id (parent) and content; optionally set description, project_id, labels, priority, due_date, and assigned_to_agent_id for the child. Returns the created child task (with its id) and the updated parent; the full chain is visible via get_task_chain. |
get_task_chain |
no_return_description |
Get the full delegation chain for a task: the root plus all descendants, sorted by depth. Pass any task_id in the chain. Returns the chain of related tasks with their parent/child relationships and depth, for inspecting parent/child accountability. |
get_task_context |
no_return_description |
Read a task's persistent context blob — the shared state, decisions, and notes saved across sessions. Call this when resuming a task to recover what was decided and done before, so work continues instead of restarting; pair with update_task_context to write state back. Pass task_id, and optionally include_provenance to include per-key author/source/version metadata for current entries. Returns the context as an object of key-value entries (plus provenance when requested). |
find_duplicate_tasks |
no_return_description |
Check whether a proposed task is similar to existing open tasks using TF-IDF + cosine similarity. Call this before create_task to avoid redundant work. Pass the content to check and optionally a threshold (0-1, default 0.6). Returns the existing open tasks that exceed the threshold with their similarity scores, or an empty list when none are similar. |
get_usage |
no_return_description |
Get quota and rate-limit information for the current plan. Hosted API only (api.delega.dev) — custom endpoints receive a clear error. Returns the plan's quota and rate-limit state (the current usage/limits and remaining allowance), with no parameters. |
heartbeat_task |
no_return_description |
Extend the lease on a task you have claimed. Call this periodically (before lease_expires_at) while working on a long task so the claim is not reclaimed by another agent. Optionally set lease_seconds (30-3600, default 300) and report a state (working/waiting_input/errored) with an optional detail, so humans and orchestrators see why the claim is held. Fails with 409 if you no longer hold an active claim — claim a task again rather than continuing. Returns the new lease expiry and current state. Hosted API only. |
set_task_state |
no_return_description |
Report the session state of a task you have claimed — working, waiting_input, or errored — without extending the lease. Use this to flag that you are blocked on input or hit an error: the claim stays visible as held-but-stuck instead of faking liveness. Requires task_id and state; detail (max 500 chars, e.g. 'needs prod API key') is optional. Humans and orchestrators see the state via list_tasks/get_task. Fails with 409 if you no longer hold an active claim. Returns confirmation of the recorded state. Hosted API only. |
delete_task |
name_restates_behavior no_return_description |
Permanently removes the task with the given task_id from Delega. The deletion is irreversible and cannot be undone, so only call this when the task should be gone for good; the task will no longer appear in any lists or project views. Returns confirmation that the task was deleted. |
add_comment |
name_restates_behavior no_return_description |
Appends the given content as a comment on the task identified by task_id, using the optional author name for attribution. Adds to the task's history even when the task is under an active claim (comments are append-only). Returns confirmation that the comment was added and is now attached to the task. |
list_projects |
name_restates_behavior no_return_description |
Returns every project in your Delega account with its details so you can discover project IDs for other calls. Read-only; takes no parameters. |
get_stats |
no_return_description |
Returns a statistics summary for your Delega data: totals, completed today, due today, overdue, and breakdowns by project, so you can gauge outstanding work. Read-only; takes no parameters. |
list_agents |
no_return_description |
Returns the registered agents in Delega; admin keys get the full view, while coordinators get a read-only directory (name, role, activity) used to resolve agent IDs on tasks. Read-only; takes no parameters. |
set_agent_role |
no_return_description |
Changes the role of the agent identified by agent_id (admin key required): worker (own-task scope), coordinator (sees and can comment on all account tasks), or admin (full account management). Sandbox agents graduate via the claim flow and cannot be assigned a role. Returns the updated agent record or confirmation that the role was changed. |
delete_agent |
name_restates_behavior no_return_description |
Removes the agent identified by agent_id from Delega. The API may refuse if the agent has active tasks or is the last active agent, so verify those conditions first. Returns confirmation that the agent was deleted, or an error explaining why the deletion was refused. |
list_webhooks |
name_restates_behavior no_return_description |
Returns the webhooks configured for your account (admin only), including each webhook's configuration and the events it subscribes to, so you can manage existing endpoints. Read-only; takes no parameters. |
create_webhook |
no_return_description |
Registers a webhook at the given HTTPS url to receive POST notifications for the subscribed events (e.g., task.created, task.updated, task.completed) so your system can react to Delega activity (admin only). Returns the created webhook with its ID and configuration. |
delete_webhook |
name_restates_behavior no_return_description |
Removes the webhook identified by webhook_id (admin only) so it stops receiving event notifications to that endpoint. Returns confirmation that the webhook was deleted; deliveries to it cease after deletion. |
list_automations |
no_return_description |
Returns the automation rules configured for your account (admin only, hosted API only), including each rule's run and failure counts so you can monitor rule health. Read-only; takes no parameters. |
create_automation |
no_return_description |
Creates an automation rule (admin only, hosted API only): when event fires and all conditions match, the actions run in-process with no webhook receiver needed, e.g., when a task labeled bug is created, assign it to an agent at priority 3. Cascades are depth- and budget-capped, rules never react to tasks they created, and field mutations on tasks under a live claim are always skipped (comments are append-only and still allowed). Returns the created rule with its automation ID and configuration. |
update_automation |
no_return_description |
Updates the automation rule identified by automation_id (admin only, hosted API only). Only supplied fields change; setting active true re-enables a rule that was auto-disabled after repeated failures. Returns the updated rule or confirmation of the changes. |
delete_automation |
name_restates_behavior no_return_description |
Removes the automation rule identified by automation_id together with its run log (admin only, hosted API only), so the rule stops firing on future events. Returns confirmation that the rule and its run log were deleted. |
list_ingress_sources |
no_return_description |
Returns the inbound connector sources configured for your account (admin only, hosted API only), including per-source delivery counters so you can see how many deliveries each endpoint has handled. Read-only; takes no parameters. |
create_ingress_source |
no_return_description |
Creates an inbound connector (admin only, hosted API only): a signed public endpoint that turns external events (CI failures, alerts, calendars) into Delega tasks. Senders must sign each POST body with HMAC-SHA256 in header X-Delega-Ingress-Signature (t=<unix>,v1=<hex>, 5-minute tolerance). Ingress can ONLY create tasks; routing (project/assignee) is pinned here and never payload-controlled; every created task carries the 'ingress' label and provenance marker; automation rules ignore ingress tasks unless they explicitly opt in with a source=ingress condition. Returns the created source with its endpoint URL and signing secret (shown once; keep it safe). |
update_ingress_source |
no_return_description |
Updates the inbound connector source identified by source_id (admin only, hosted API only). Only supplied fields change; pass rotate_secret true to mint a new signing secret (shown once — the old secret stops working immediately). Returns the updated source or confirmation of the changes. |
Selection evidence
Confusable tool pairs.
14 pairs where similar names or overlapping descriptions may send an agent toward the wrong tool.
| Tool A | Tool B | Confidence | Why they collide |
|---|---|---|---|
assign_task |
delegate_task |
high | A natural 'hand this task off to agent Y' request routes to assign_task, but delegate_task itself warns 'Use this (not assign_task) for multi-agent handoffs' — a documented selection trap for tools with nearly identical signatures. |
link_task |
list_task_links |
medium | 'What links are attached to task X?' could select link_task (a write) since both tools share the link/task_id/kind vocabulary; attaching vs retrieving links is easily mistaken when the query only says 'get the links'. |
get_task |
get_task_context |
medium | 'Get the context/state for task X so I can resume' is ambiguous: get_task returns task detail while get_task_context returns the persistent notes/blob, and both accept only task_id. |
get_task |
get_task_chain |
medium | 'Show me the full task and everything under it' is ambiguous: get_task advertises subtasks while get_task_chain returns root + all descendants; the word 'full' appears in both descriptions. |
get_task_context |
get_context_history |
medium | 'Read the history of decisions/context for task X' could select either the live context blob (get_task_context) or the append-only provenance ledger (get_context_history), since both read task context keyed by task_id. |
update_task |
update_task_context |
medium | 'Update the notes/shared state saved on task X' reads like editing the task itself, but the correct tool is the context-blob merge; both names start with 'update task' and take task_id. |
create_task |
create_recurring_task |
medium | 'Create a daily/weekly task' without the literal word 'recurring' can select one-off create_task instead of the recurring-task template, especially with matching create/content/priority schemas. |
list_tasks |
list_recurrences |
medium | 'List all my recurring tasks' is genuinely ambiguous: recurring templates (list_recurrences) vs the normal task instances they spawn (list_tasks); list_recurrences even notes spawned instances are ordinary tasks. |
delete_recurrence |
delete_task |
medium | 'Delete this recurring task' leaves unclear whether to remove the schedule (delete_recurrence) or a spawned instance (delete_task); delete_recurrence noting that instances survive adds to the confusion. |
assign_task |
claim_task |
medium | 'Take/grab this task for me' could select either queue-based claim_task or explicit assign_task to an agent (e.g. self), since both act on the task-agent relationship and take task_id. |
create_webhook |
create_automation |
medium | 'Set up automation so when a task event fires we get notified' is ambiguous: create_webhook POSTs events to a URL while create_automation runs in-process actions; both are event-driven, admin-only, and share the same event enums. |
list_tasks |
list_task_links |
low | 'List the links on my tasks' lacks the single task_id list_task_links requires, so an agent may fall back to list_tasks expecting link info; retrieving links vs listing tasks only mildly collides. |
get_task |
get_stats |
low | 'Show me the status/overview of our tasks' leans toward get_stats but could be read as fetching a specific task's details; shared 'get'+'task' phrasing rarely collides in practice. |
list_tasks |
list_projects |
low | 'List everything in my Delega account' could route to either directory listing, but tasks and projects are usually named explicitly in the request, so confusion is uncommon. |
Compare the field