MCP API reference
Complete reference for every tool exposed by Hezo's built-in MCP server. For how to connect, authenticate, and register for access, see Hezo's MCP server.
Connecting
- Endpoint:
POST /mcp- JSON-RPC 2.0 over Streamable HTTP. - Authentication:
Authorization: Bearer <token>, where the token is an instance-scoped API key (hezo_…). - Discovery: call
tools/listfor the live machine-readable schemas, then invoke a tool withtools/call. - File uploads: binary files cannot ride a JSON-RPC call -
POSTthem to/mcp/assetsasmultipart/form-data(afilefield, plus an optionalprojectfield). They then appear inlist_project_assets/read_project_asset.
Conventions
- Project scope (
project): most tools take an optionalproject(slug or ID). Omit it to act in the project your run is already in; an API key and instance agents (CEO/Coach) must name the project they are acting in. - Authorization: every call is scoped to the resolved project's team and the caller must have access to it. Tools that restrict callers further note it under Authorization below.
- Errors: a handled failure comes back as
{ "error": "<message>" }in the tool result (the HTTP response itself stays successful). - Result size: a tool result is capped at 64 KB (higher for a few
full-resource inspection tools, e.g.
get_agent_system_prompts); over the cap you get{ "error": "result_too_large", … }. Narrow it with filters, a single-resourceget_*,beforepagination, orexcerpt_chars.read_project_docnever returns that error for a big doc: it returns a UTF-8 byte window with anext_offsetcursor so you can page the rest (see its entry below). - Excerpts (
excerpt_chars): list tools acceptexcerpt_charsto truncate long text fields, adding_truncated/_lengthcompanions. - Pagination (
before):list_commentswalks older items by passing the oldestidyou have seen asbefore. - Secrets: agents reference secrets by placeholder (
__HEZO_SECRET_<NAME>__); the egress proxy substitutes the real value only for the secret'sallowed_hosts. - Write tools: tools marked Write tool persist data - a successful call from an agent run marks the run as having produced output.
Teams
list_teams
Read-only.
List teams accessible to the caller. An API key and the instance CEO (cross-team session) get every team in the instance; an ordinary agent run gets only its own team.
Parameters: none.
Returns: An array of team rows (id, name, slug, description, …). An API key, the instance CEO, and an agent run with cross-team scope get every team; an ordinary agent run gets only its own team; a board user gets the teams they belong to (all teams for a superuser).
get_team
Read-only.
Get the team backing a project
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
Returns: The single team row backing the resolved project, or null if none.
create_team
Write tool.
Create a new team (superuser only)
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Team name |
description | string | No | Team description |
Returns: The created team row.
Authorization: Superuser only.
Projects
update_project_progress
Write tool.
Replace the project's progress summary shown at the top of the Progress page. Only the Captain does this, and only from within a progress-update run. Keep it a concise summary, not a backlog: lead with the key points in bold, then a short narrative of what is done, what is in progress, and what is still to do. You may reference a few of the most relevant tickets by their bare identifier (e.g. BE-2) - link sparingly. This overwrites the whole summary, so include everything that should remain.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
summary | string | Yes | Markdown summary of project progress. Lead with the key points in bold, then a short narrative of done / in-progress / to-do. Link only a few key tickets by identifier; keep it a summary. |
Returns: { summary, updated_at } after replacing the project’s progress summary (shown at the top of the Progress page). Returns { error } if the project is HQ/internal (no progress summary) or the call is not from within an agent run.
Authorization: Captain only, and only from within a progress-update agent run.
create_project
Write tool.
Create a new project together with its dedicated team. CEO-only. Call this ONLY after the admin has explicitly approved the finalised scope AND team type in the intake conversation - a plain reply approving it is enough (there is no inbox button to wait on), but do not call it while still scoping, on assumed defaults, or in the same turn you propose the plan; creating a project stands up a full team + container, so wait for the go-ahead. Provisions the team from the chosen source (pass template_id from list_team_templates, source_team_id to clone an existing team, or marketplace_slug to provision a marketplace team; defaults to Blank), creates the project, its planning ticket, and the initial CEO coherence/setup ticket the planning ticket is blocked on, then provisions the container. The coherence/setup ticket is created unassigned and does NOT start automatically on this path: first author its description (update_task on the returned coherence_task_identifier) to capture the concrete setup you agreed in intake - the exact roles to hire, any system-prompt rewrites, and the reporting structure - then call start_team_setup(project) to begin the run. When intake_task_id is given, the intake conversation is closed with a completion note. Returns the new project plus its planning and coherence ticket identifiers.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Project name |
description | string | Yes | Project description |
task_prefix | string | No | Optional 2-4 char uppercase ticket prefix; derived from the name when omitted |
initial_project_plan | string | No | Optional project plan document (markdown), seeded as project-plan.md |
template_id | string | No | Team-type template id (from list_team_templates). Mutually exclusive with source_team_id; defaults to Blank when neither is given. |
source_team_id | string | No | Existing team to clone into a fresh template. Mutually exclusive with template_id. |
marketplace_slug | string | No | A marketplace team slug (from get_marketplace_team / the intake baseline) to provision the roster from directly. Mutually exclusive with template_id and source_team_id. |
intake_task_id | string | No | The HQ project-intake ticket this fulfils (its identifier, e.g. "HQ-1", or its UUID); it is closed with a completion note on success. |
Returns: The new project row plus team_slug, planning_task_id, planning_task_identifier, and the initial coherence/setup ticket (coherence_task_id, coherence_task_identifier). The coherence ticket is created unassigned and does NOT auto-run on this path - draft its description then call start_team_setup. Returns { error } if validation fails.
Authorization: CEO only - call after the admin has explicitly approved the scope and team type in intake.
start_team_setup
Write tool.
Kick off the initial team-coherence/setup run for a project you created via create_project. CEO-only. Projects created directly from the admin form start their coherence pass automatically; projects you create do NOT. First author the coherence ticket with update_task - replace its description with the concrete plan you agreed in intake (the exact roles to hire and why, any system-prompt rewrites, and the reporting structure) - then call this to assign the ticket to yourself and start the run. Returns the started ticket; errors if there is no open setup ticket for the project or a run is already active on it.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
Returns: { started: true, task_id, task_identifier } after assigning the project’s open coherence/setup ticket to the CEO and waking them to run it. Returns { error } if there is no open setup ticket for the project or a run is already active on it.
Authorization: CEO only - for a project the CEO created via create_project; author the coherence ticket description first.
list_team_templates
Read-only.
List local team templates: the built-in Blank template plus any custom templates saved from existing teams. The default specialist rosters (e.g. the software-development "Startup" team) live in the marketplace, not here. Use when recommending a team structure to hire.
Parameters: none.
Returns: An array of local templates (id, name, description, is_builtin, agent_types[] where each entry has slug, name, role_description). Only the built-in Blank template and custom saved templates appear here - the default specialist rosters live in the marketplace (get_marketplace_team).
list_marketplace_teams
Read-only.
Browse the team marketplace: every ready-made team available to this instance, with its name, description, summary, role count, and version. Callable by the CEO or a team Captain. Use it before staffing a team - the marketplace carries proven, fully-written roles, so check whether one already covers the role you need (then pull its prompt with get_marketplace_team) instead of authoring a system prompt from scratch. You can take a whole roster (apply_marketplace_team) or lift out a single role (apply_marketplace_agent).
Parameters: none.
Returns: { teams } - every marketplace team available to this instance, each with slug, name, description, summary, version, and roster_count. Search keywords are omitted. Fetch one team’s full roster and prompts with get_marketplace_team.
Authorization: CEO or a team Captain.
get_marketplace_team
Read-only.
Fetch one marketplace team's full definition: its version, changelog, and every role's title, reporting line, and CURRENT system prompt (including the Captain override). Callable by the CEO or a team Captain. Use it when adding/updating a team, to compare the marketplace's prompts to the agents you already have and decide what to refresh; and when hiring, to start a role from a proven marketplace prompt instead of writing one from scratch - find candidate teams with list_marketplace_teams first.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
slug | string | Yes | The marketplace team slug (e.g. "software-development"). |
Returns: The marketplace team’s slug, name, version, changelog[], captain (system_prompt, team_context), and roster[] (each with slug, title, reports_to_slug, role_description, summary, team_context, system_prompt). Returns { error } if the slug is unknown.
Authorization: CEO or a team Captain.
apply_marketplace_team
Write tool.
Add or update a marketplace team's roster on a project's team. CEO-only. Fetches the named marketplace team and provisions its members directly onto the project's existing team - a direct add, not an approval-gated hire proposal, so use it only for a team the admin already chose. Roles the team already has are SKIPPED by default; pass refresh_existing=true to instead refresh those roles' descriptions and system prompts to this team's current versions (use this when the project was created from an earlier version of THIS SAME team - it is a version update, not a duplicate add). refresh_existing overwrites prompts, so before using it on roles that may carry local customizations, read them (get_agent_system_prompt) and the new versions (get_marketplace_team) and refresh selectively with update_agent_system_prompt instead. After it returns, reconcile the merged roster. Returns the roles added, refreshed, and skipped.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
slug | string | Yes | The marketplace team slug to add (e.g. "software-development"). |
refresh_existing | boolean | No | When true, refresh roles the team already has to this team's current prompts/descriptions instead of skipping them. Default false. Use for a version update of the same team; prefer selective update_agent_system_prompt when roles carry customizations. |
Returns: { added, refreshed, skipped, captain_updated, version } - the roster slugs added, refreshed in place (with refresh_existing), and skipped. Provisions members directly (no approval flow). Returns { error } if the slug is unknown.
Authorization: CEO only - use only for a team the admin already chose; reconcile the merged roster afterwards.
apply_marketplace_agent
Write tool.
Add ONE role from a marketplace team to a project's team. CEO-only. Use this when the admin wants a single role (e.g. just the security engineer) rather than a whole roster - it provisions that one member directly, a direct add rather than an approval-gated hire proposal, and leaves the rest of the roster, including the Captain, untouched. The team already having that slug is a no-op (skipped). The role's prompt was written for its home team, so AFTER this returns you MUST fit it to this project: rewrite its system prompt and team context (update_agent_system_prompt, set_agent_team_context) so every teammate and hand-off they name is an agent that actually exists here, set a real manager with set_agent_reports_to, and update the existing agents whose work now flows through it. When the role's own manager is not on this team the reporting line is wired to the Captain as a placeholder and reports_to_fell_back comes back true - re-point it. Returns whether the role was added or skipped, plus the reporting line applied.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
slug | string | Yes | The marketplace team slug the role comes from (e.g. "software-development"). |
role | string | Yes | The roster role slug to add (e.g. "security-engineer"), as listed by get_marketplace_team. The Captain is not a roster role and cannot be added this way. |
Returns: { role, added, skipped, reports_to, reports_to_fell_back, version } for the single role provisioned. skipped is true when the team already had that slug. reports_to_fell_back is true when the role’s own manager is not on this team, so the line was wired to the Captain as a placeholder. Returns { error } if the team slug or role slug is unknown.
Authorization: CEO only - use only for a role the admin already chose; fit the role’s prompt and reporting line to the existing roster afterwards.
list_projects
Read-only.
List projects. With CEO cross-team access (or as superuser) returns every project across the instance; a board user gets the projects on teams they belong to; an agent run gets its own project. Pass excerpt_chars (e.g. 300) to truncate description; omit for full content.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
excerpt_chars | integer | No | When set, truncates description and adds description_truncated/_length |
Returns: An array of project rows (id, team_id, name, slug, task_prefix, description, is_internal, created_at, updated_at). With excerpt_chars, description is truncated and description_truncated/description_length companions are added.
Authorization: An API key, CEO cross-team access, or a superuser returns every project; a board user gets the projects on their teams; an agent run gets its own project.
Tasks
list_tasks
Read-only.
List a project's tasks. Returns up to 50 tasks ordered by creation date (newest first). Omit project to use the project your run is in; pass it (slug or ID) to inspect another project. Narrow with status (comma-separated) or assignee_id/assignee_slug. The Project State block in your system prompt already gives you the active tickets in the current project - only call this if you need older or terminal tickets, another project, or a specific status filter. Pass excerpt_chars (e.g. 300) to truncate description and rules to triage-sized excerpts; omit for full content.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
status | string | No | Filter by status (comma-separated) |
assignee_id | string | No | Filter by assignee - an agent slug (e.g. "engineer") or a member UUID |
assignee_slug | string | No | Filter by assignee agent slug (alternative to assignee_id) |
excerpt_chars | integer | No | When set, replaces description and rules with first-paragraph excerpts capped at this many characters, plus _truncated and _length companion fields |
Returns: Up to 50 task rows ordered newest-first, each including project_name. With excerpt_chars, description and rules are replaced with excerpts plus _truncated/_length companions.
get_task
Read-only.
Get task details, including the ticket's declared blockers (upstream - what this ticket is waiting on) and dependents (downstream - tickets that are blocked on this one). Each entry has identifier, title, and current status. A non-empty blockers list means an automatic agent run on this ticket is paused until every blocker reaches a terminal status (done, cancelled). The dependents list shows which teammates' tickets will be auto-unblocked when this ticket is marked terminal - you do not need to @-mention them, the auto-wake handles it.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID |
Returns: The task row plus blockers[] (upstream) and dependents[] (downstream); each entry has dependency_id, id, identifier, title, status. Returns null if the task is not found.
create_task
Write tool.
Create a new task. Use parent_task_id for sub-tasks - prefer this over a top-level ticket whenever the new work is part of the ticket you are on. Sub-tasks themselves can have sub-tasks, but no deeper (depth is capped at 2). Use assignee_slug as alternative to assignee_id. As an agent caller, you may only assign to yourself or to your direct subordinates - to request work from anyone else (peers, your manager, or agents elsewhere in the org), use create_comment with @
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
title | string | Yes | Task title |
description | string | No | Task description |
priority | string | No | Priority: low, medium, high, urgent |
assignee_id | string | No | Assignee member ID |
assignee_slug | string | No | Assignee agent slug (alternative to assignee_id) |
parent_task_id | string | No | Parent task to nest this under as a sub-task - a task identifier (e.g. "BE-2") or UUID. Sub-tasks can themselves have sub-tasks, but no deeper - depth is capped at 2. |
runtime_type | string | No | Pin this task to a specific AI runtime (claude_code, codex, gemini). Leave unset to use the instance default. |
blocked_by_task_ids | string[] | No | Task identifiers (e.g. ["BE-2", "BE-3"]) or UUIDs that must reach a terminal status before this ticket is started. The assignee will not be woken on this ticket until every blocker is satisfied. |
goal_id | string | No | UUID of the project goal this task advances. Links the task to the goal for traceability; it does not gate or change how the task runs. (Captain) set this when filing work to move a goal forward. |
Returns: The created task row (it may carry an advisory warning string, e.g. when the description backticks a Hezo reference such as an assets/<path> - flagged even before that asset exists). Returns { error } on a validation failure.
Authorization: An agent caller may only assign to itself or a direct subordinate; sub-task depth is capped at 2.
create_tasks
Write tool.
Create multiple tasks in one call (max 50). Items are created in order; each has the same shape as create_task, and per-item errors are returned without aborting the rest. When the items are slices of the ticket you are on - delegated tracks handed to direct reports, parallel slices, phases of its deliverable - set parent_task_id on EACH item (normally your current ticket) so they are sub-tasks; filing them top-level detaches them and lets the parent close while they are still open. Within a batch, blocked_by_task_ids entries may reference an earlier item in the same call by zero-based index token - '#0' is the first item. To chain sequential work (e.g. implementation phases that must run one at a time), set blocked_by_task_ids: ['#
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
items | object[] | Yes | Up to 50 items. |
Returns: An array of per-item results: { ok: true, index, task } or { ok: false, index, error }. Items are created in order; a per-item failure does not abort the rest. blocked_by_task_ids may reference an earlier item with a #<index> token.
Authorization: Same as create_task; up to 50 items per call.
update_task
Write tool.
Update an task. Agents can use this to change status, update progress, set rules, and record branch names. To finish a ticket, set status to done - that is the final completed state and wakes Coach to review the ticket for prompt-learning (the task stays done). Use cancelled for abandoned work. Setting done is rejected for agent callers while the task has an @admin question no human has answered yet - keep the task in_progress or move it to review until the admin replies. Re-opening a completed task (done/cancelled) is admin-only. As an agent caller, reassigning is limited to yourself or your direct subordinates; to hand work to a peer or manager use create_comment with @parent_task_id to move this task under a different parent, or to an empty string to promote it to a top-level task; prefer that over cancelling a mis-filed sub-task and re-filing it as a new top-level task. In description, progress_summary, and rules, reference teammates with @
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID |
title | string | No | New title |
description | string | No | New description |
status | string | No | New status (backlog, in_progress, review, blocked, done, cancelled). done = completed (final); marking a ticket done wakes Coach to review it for prompt-learning but leaves it done. cancelled = abandoned. Re-opening a completed task (done/cancelled) is admin-only. |
priority | string | No | New priority |
assignee_id | string | No | New assignee - an agent slug (e.g. "engineer") or a member UUID |
progress_summary | string | No | Progress summary update |
rules | string | No | How-to-work-on guardrails for this ticket - approach constraints that shape execution (e.g. "run tests before committing", "consult the architect before auth changes"). Not a channel for passing project domain knowledge to other agents; put that in description instead. |
branch_name | string | No | Git branch name for this task |
runtime_type | string | No | Override the AI runtime for this task (claude_code, codex, gemini). Pass an empty string to clear. |
parent_task_id | string | null | No | Move this task under a different parent - a task identifier (e.g. "BE-2") or UUID. Pass an empty string or null to promote it to a top-level task. Omit to leave the parent unchanged. The parent must be in the same project, cannot be the task itself or one of its own sub-tasks, and the whole sub-tree being moved must still fit within the depth cap of 2. An open task cannot be nested under a parent that is already done or cancelled. |
Returns: The updated task row (may carry a warning string), { unchanged: true } when no fields changed, null if not found, or { error } on a validation failure.
Authorization: done is the final completed state; marking a ticket done wakes Coach to review it but the task stays done. cancelled is for abandoned work. Agents cannot set done while an @admin mention on the task is unanswered by a human; human admins are exempt. Only the admin can re-open a completed (done/cancelled) task. An agent run is scoped to its own task and may reassign only to itself or a direct subordinate. A parent_task_id change is rejected when the new parent is in a different project, is the task itself or one of its own sub-tasks, would push the moved sub-tree past the depth cap of 2, or is already done or cancelled while the task being moved is still open. Moving a task out of its former parent wakes that parent when it was the last open sub-task, exactly as closing it would.
add_task_blocker
Write tool.
Declare that one task blocks another. The downstream ticket will not start an automatic agent run until the blocker reaches a terminal status (done, cancelled). Use this when you discover that a ticket you have been woken on depends on work that has not landed yet - declare the blocker and end your turn; the system will wake you again when the blocker resolves. Cycles are rejected.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID that should be blocked |
blocked_by_task_id | string | Yes | Task identifier or UUID of the upstream blocker |
Returns: The dependency row (id, task_id, blocked_by_task_id, created_at). Returns { error } for a self-block, an existing dependency, a missing task, or a cycle.
remove_task_blocker
Write tool.
Remove a blocker between two tasks. Call this when a dependency that was previously declared no longer applies. If removing this dependency clears the downstream ticket's last open blocker, its assignee is woken automatically.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID that is currently blocked |
blocked_by_task_id | string | Yes | Task identifier or UUID of the blocker to remove |
Returns: { removed: true }, or { error } if the dependency or blocker is not found. Clearing the last open blocker wakes the downstream assignee.
list_task_runs
Read-only.
List the agent runs (container executions) recorded for a task, newest first (up to 50). Each row is one run: which agent ran, its status and exit code, when it started/finished, the invocation command, and the log length. Metadata only - fetch a run's actual container log with get_run_log(run_id). Useful for reviewing HOW a task was worked (e.g. the Coach checking what an agent actually did, beyond the comments it left).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID |
Returns: An array of up to 50 run rows for the task, newest-first: id, status, exit_code, started_at, finished_at, invocation_command, log_length (characters), plus agent_title/agent_slug. Metadata only - fetch a run's log with get_run_log.
get_run_log
Read-only.
Fetch the container log for a single agent run (a run_id from list_task_runs). Returns the run's log capped to the most recent excerpt_chars characters (default 12000 - the tail, where the outcome and any errors are) with truncated/length flags so you can tell when earlier output was dropped. Team-scoped: the run must belong to the project you're acting in.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
run_id | string | Yes | Run ID (UUID) from list_task_runs |
excerpt_chars | integer | No | Max characters to return from the END of the log (default 12000). |
Returns: { id, status, exit_code, task_id, log, length, truncated } for one run - log is the tail of the container log capped at excerpt_chars (default 12000); truncated flags dropped earlier output. Returns { error } for a malformed run_id or a run outside the resolved project's team.
Goals
suggest_goal
Write tool.
Suggest a project goal for the admin to approve. Callable only by the team Captain (or the CEO targeting a team via project). Goals come from the admin, so ask first: before suggesting anything, ask the admin what they want the project to achieve (on the planning/onboarding task or via an @admin comment), wait for their reply, and formulate each suggestion from their stated objectives - never file a suggestion the admin's own words do not support. This does NOT create a goal directly - it files a suggestion the admin reviews as an Approve/Deny card; the real goal exists only once they approve. A goal is an OUTCOME or MILESTONE the admin wants the project to achieve - a state of the world to reach, or reach and hold (e.g. "reach 10k monthly readers", "100 active customers, held"); its measurement judges results, never activity performance. If the candidate reads as "do X every day/week" - monitor, sweep, deliver a periodic report, keep a process running - it is NOT a goal: that is recurring operational work, filed with create_task as a standing task that stays open (optionally linked to a goal via goal_id), and so is any finite deliverable with a fixed done state - a document to produce, a one-time analysis, a feature to ship. Pass a title, a measurement (the precise definition of when it is achieved - the bar to judge against; write it SMART), optional actions (guidance on what to do/check when assessing it), a check_frequency (daily/weekly/monthly - how often the Captain re-assesses progress, not a schedule for doing work), and an optional target_date (deadline, ISO YYYY-MM-DD - milestones with target dates are legitimate goals). Pass task_id (recommended - usually your planning task) to surface the suggestion as an Approve/Deny card in that task's thread; it also appears on the project's Goals page.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
title | string | Yes | Short goal title. |
measurement | string | No | The precise, measurable definition of when the goal is achieved. |
actions | string | No | Optional guidance on what the Captain should do or check when assessing the goal. |
check_frequency | daily | weekly | monthly | No | How often the goal is re-assessed once created (default daily). This is the Captain's re-assessment cadence, not a schedule for doing work: pick by how often the measurement meaningfully changes - daily for fast-moving measurements, weekly for steady ones, monthly for slow-moving outcomes. Checks recur indefinitely - this is a cadence, not a deadline. |
target_date | string | No | Optional deadline as an ISO date (YYYY-MM-DD). |
task_id | string | No | Optional originating task to attach the suggestion card to - a task identifier (e.g. "HM-1") or UUID. |
Returns: { approval_id, status: "pending", payload }. Files a goal suggestion the admin must approve - no goal exists until then. On approval the real goal is created and appears on the Goals page. Surfaces as an Approve/Deny card on the task_id thread (when given) and on the project Goals page. Returns { error } if the caller is not the Captain/CEO, the project is HQ/internal, or the inputs are invalid.
Authorization: Captain (its own team) or CEO (any team via project), and only from within an agent run.
list_goals
Read-only.
List a project's goals (the objectives the Captain tracks). Each goal has a title, a measurement (the precise definition of when the goal is achieved - the bar to judge against), optional actions (admin guidance on what to do/check toward it), the Captain's current progress_percent (0-100), a health (pending/on_track/at_risk/off_track), a status_blurb, a check_frequency (daily/weekly/monthly), an optional target_date (deadline), and last_checked_at. As the Captain, call this during your heartbeat to see which goals are due for a fresh assessment, then call update_goal_progress for each. Archived goals are excluded unless include_archived is true.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
include_archived | boolean | No | Include archived goals (default false). |
Returns: An array of the project's goal rows, each with project_name/project_slug and an embedded history[] of recent progress snapshots ({ t, percent, health }). Archived goals are excluded unless include_archived is true.
update_goal_progress
Write tool.
Record your current assessment of a goal's progress. Only the Captain does this, and only from within a progress-update run. Pass progress_percent (0-100, your honest estimate - do not lower it without a reason in the blurb), health (on_track / at_risk / off_track, weighing progress against the target_date), and a one-paragraph status_blurb explaining where the goal stands and what is needed next. This updates the goal's live status and appends a point to its progress history; the goal then won't be re-surfaced for checking until its cadence elapses again. Reaching 100 does not end tracking: the goal stays on its cadence forever (progress can later drop back below 100, and some goals are never-ending, measured continuously), so keep recording your honest current assessment on every check.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
goal_id | string | Yes | UUID of the goal to update. |
progress_percent | integer | Yes | Estimated progress toward the goal, 0-100. |
health | on_track | at_risk | off_track | Yes | on_track, at_risk, or off_track. |
status_blurb | string | Yes | One-paragraph summary of where the goal stands and the next step. |
Returns: The updated goal row (with the new progress_percent, health, status_blurb, and a refreshed last_checked_at). Appends a point to the goal’s progress history keyed to the calling run. Returns { error } if the goal is not in the project or the inputs are invalid.
Authorization: Captain only, and only from within a progress-update agent run (the run records the history point).
Comments & reactions
list_comments
Read-only.
List comments for an task. Returns up to 50 most-recent comments (newest first). Pass before (a comment ID) to walk older. Pass excerpt_chars (e.g. 500) to truncate long text comments; structured comments (system/option/task_link) are always returned whole. Each row includes parent_comment_id (UUID or null) so you can see reply threading - when you reply substantively to a comment, pass that comment's id back as parent_comment_id in create_comment. Each row also has a public_id (a creation-timestamp slug like 20261009112345); that's how you cite a specific comment elsewhere: write a comment link as
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID |
before | string | No | A comment id (UUID) or public_id - return only comments created before that one |
excerpt_chars | integer | No | When set, truncates content.text on text-typed comments to this many characters and adds text_truncated/text_length |
Returns: Up to 50 comment rows newest-first, each with id, public_id, task_id, author_member_id, author_api_key_id, parent_comment_id, content_type, content, chosen_option, created_at, author_type, author_name, reactions[], and attachments[]. Pass before to walk older; excerpt_chars truncates text comments (adds text_truncated/text_length).
add_reaction
Write tool.
React to a comment without waking its author. Use this to acknowledge mentions or signal "seen / picked up" without forcing the original commenter to run again. Prefer this over a follow-up create_comment when you have nothing substantive to add - comments wake the author, reactions do not. Only react when the situation calls for it: a clean handoff to your own new ticket (✓ on the mention), or a brief acknowledgement that a request landed. If you need the original commenter to read something, post a comment instead.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID the comment belongs to |
comment_id | string (uuid) | Yes | UUID of the comment to react to, as returned by list_comments. Sentinels like "last" / "latest" are not supported - you must pass an explicit UUID. |
kind | ack | Yes | Reaction kind. v1 supports: ack |
Returns: { comment_id, kind, reactions[] }, or { error } if the comment is invalid. Reacting does not wake the comment author.
remove_reaction
Write tool.
Remove your own reaction from a comment. Removing a reaction does not wake the comment author.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID the comment belongs to |
comment_id | string (uuid) | Yes | UUID of the comment to remove the reaction from, as returned by list_comments. Sentinels like "last" / "latest" are not supported - you must pass an explicit UUID. |
kind | ack | Yes | Reaction kind. v1 supports: ack |
Returns: { comment_id, kind, reactions[] }, or { error } if the reaction is not found.
create_comment
Write tool.
Add a comment to an task. In content, reference teammates with @
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID |
content | string | Yes | Comment text |
parent_comment_id | string | No | The comment you are replying to - its id (UUID) or its public_id. Setting this wakes that comment's author with source=reply and renders this comment as "replying to ..." in the UI. |
Returns: The created comment row (id, public_id, created_at, …), optionally with an advisory warning string. Returns { error } if parent_comment_id does not belong to the task. Setting parent_comment_id wakes the parent comment's author.
update_comment
Write tool.
Edit the text of a comment you posted earlier in THIS run - use it to fix a mistake (a typo, a broken reference, wrong markdown) instead of posting a correction as a new comment. You can only edit a text comment authored by your current run; comments from earlier runs, other agents, or humans are not editable. Editing re-runs the same notification side effects create_comment does, but idempotently: a teammate already notified by this comment is not woken again, while a mention you ADD in the edit (e.g. a bare @
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID the comment belongs to |
comment_id | string (uuid) | Yes | UUID of the comment to edit, as returned by create_comment or list_comments. |
content | string | Yes | The replacement comment text (overwrites the existing body). |
Returns: The updated comment row, optionally with an advisory warning string. Returns { error } if the comment is not a text comment the caller authored during the current run. Re-runs create-time side effects (mention/reply wakeups, task links) idempotently, so only references the edit newly introduces notify anyone.
Authorization: An agent editing a text comment its own current run authored. Comments from earlier runs, other agents, or humans are not editable.
Agents & hiring
list_agents
Read-only.
List the agents on a project's team
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
Returns: An array of agent rows (id, agent_type_id, title, slug, daily_budget_cents, weekly_budget_cents, monthly_budget_cents, runtime_status, admin_status).
update_hire_proposal
Write tool.
Revise the draft of a pending hire approval. Captain-only. Use this to expand or rewrite the system prompt, adjust role description, budget, heartbeat, or touches_code before admin review. All fields are optional - pass only what you want to change.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
approval_id | string | Yes | Hire approval ID |
title | string | No | Updated role title |
role_description | string | No | Updated short role description |
system_prompt | string | No | Updated system prompt. If provided, it must keep every required substitution variable ({{team_name}}, {{reports_to}}, {{skills_context}}, {{project_docs_context}}, {{team_preferences_context}}) or the revision is rejected. |
reports_to | string | No | Updated manager - an existing agent's slug. Pass an empty string to clear the reporting line. |
default_effort | string | No | Updated default effort: minimal, low, medium, high, max |
heartbeat_interval_min | number | No | Updated heartbeat interval (min) |
monthly_budget_cents | number | No | Updated monthly budget in cents |
touches_code | boolean | No | Whether this agent reads/writes repo code |
Returns: The updated approval row, or { error } if no field changed or the approval is invalid.
Authorization: Captain only; the approval must be a pending hire request on the Captain's team.
create_hire_proposal
Write tool.
File a new hire proposal. Callable by a team Captain (for its own team) or the CEO (for any team - pass project to target it, including HQ). Use this when directed or deciding to staff or expand a team: author the full role spec - title, role description, and a complete system prompt - and submit it. The proposal surfaces as a pending approval in the admin inbox; the admin reviews, may modify it, and approves, at which point the agent is created automatically. Pass task_id to link the proposal back to the ticket that prompted it.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
title | string | Yes | Role title (the slug is derived from it) |
role_description | string | No | Short role description |
system_prompt | string | No | Full system prompt for the new agent. If provided, it MUST contain every required substitution variable ({{team_name}}, {{reports_to}}, {{skills_context}}, {{project_docs_context}}, {{team_preferences_context}}) or the proposal is rejected - these inject the agent's identity, manager, and live skills/docs/preferences context. Author it in the style of the built-in role docs. |
reports_to | string | No | The manager this agent reports to - an existing agent's slug (e.g. "architect"). Sets the structural reporting line so work can be delegated to and from this agent. Must be an agent already on the team. |
default_effort | string | No | Default reasoning effort: minimal, low, medium, high, max |
heartbeat_interval_min | number | No | Heartbeat interval (min) |
daily_budget_cents | number | No | Daily budget in cents |
weekly_budget_cents | number | No | Weekly budget in cents |
monthly_budget_cents | number | No | Monthly budget in cents |
touches_code | boolean | No | Whether this agent reads/writes repo code |
task_id | string | No | Optional originating ticket to link the proposal to - a task identifier (e.g. "HM-1") or UUID |
Returns: { approval_id, status, payload } for the new pending hire approval, or { error } if the spec is rejected (missing title, invalid effort/budget, reserved or duplicate slug, or an unknown task_id).
Authorization: A team Captain (for its own team) or the CEO (for any team - pass project, including HQ). The proposal surfaces as a pending approval for the admin.
report_no_work
Read-only.
Declare that, after evaluating the current task this run, there is genuinely nothing to do - no comment, sub-task, status change, code change, or other action is warranted. Records the run as an intentional no-op so it is NOT flagged as a failed empty run, and is the correct, auditable way to end such a turn (preferred over posting a redundant "nothing to do" comment). Use ONLY when you have truly concluded no action is needed this turn - never to skip, defer, or avoid real work.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
reason | string | Yes | One-line explanation of why there is nothing to do this run. |
Returns: { ok: true }, or { error } outside an agent run. Records the run as an intentional no-op so it is not flagged as a failed empty run.
Authorization: Available only within an agent run (requires a run identity).
set_agent_reports_to
Write tool.
Set or change the manager an agent reports to - the structural reporting line in the org chart that gates delegation. Work can only be assigned to/from an agent along this line, so an agent whose manager is unset can't be delegated to or hand work down. Use this to wire up reporting structure (e.g. after hiring specialists, point them at their lead) or fix it during a coherence review. Pass the target agent and its new manager (both by slug or member ID); pass an empty reports_to to clear the line. Callable by the team's Captain or an HQ instance agent (CEO/Coach) acting in the team. The Captain, CEO, and Coach have fixed reporting lines (Captain → CEO; CEO/Coach → admin) that cannot be changed.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
agent_id | string | Yes | Target agent - its slug (e.g. "engineer") or member ID |
reports_to | string | Yes | The new manager - an existing agent's slug (or member ID) on this team. Pass an empty string to clear the reporting line. |
Returns: { applied: true, agent, reports_to } (reports_to is null when cleared), or { error } if the agent/manager is not in the team, the target is the Captain/CEO/Coach (whose reporting lines are fixed), the manager is the agent itself, or the link would create a reporting cycle.
Authorization: The team's Captain, or an HQ instance agent (CEO/Coach) acting in the team.
set_agent_status
Write tool.
Retire (disable) or reinstate (enable) an agent on a project's team. Callable by the team's Captain or by the CEO running in the team. Disabling stops the agent from being scheduled and unassigns it from every open task; enabling resumes scheduling. The change is fully reversible and preserves all of the agent's history, so this is the right way to remove a role the team no longer needs (e.g. after a coherence review). The Captain and the instance agents (CEO/Coach) cannot be disabled this way. Confirm with the admin before retiring an agent.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
agent | string | Yes | Target agent - its slug (e.g. "engineer") or member ID. Must be a member of this project's team. |
status | enabled | disabled | Yes | "disabled" retires the agent; "enabled" reinstates it. |
Returns: { updated: true, agent_id, slug, admin_status }, or { error }. Disabling unassigns the agent from every open task; the change is reversible.
Authorization: The team's Captain or the CEO. The Captain, CEO, and Coach roles cannot be disabled with this tool.
Agent prompts & context
get_agent_system_prompt
Read-only.
Read an agent's system prompt. Accessible by any agent or the admin in the same team. Returns the resolved role doc by default - {{…}} placeholders substituted with the real team name, manager, skills, project docs, and team context - so you can see what the agent actually says about itself with real values. Pass placeholders=false to get the raw stored template with {{…}} placeholders intact; only do this when you intend to edit the prompt and need a safe round-trip back through update_agent_system_prompt.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
agent_id | string | Yes | Target agent - its slug (e.g. "engineer") or member ID |
placeholders | boolean | No | When true (default) substitutes {{…}} placeholders with real team/team values. When false returns the raw stored template - needed when reading before update_agent_system_prompt so placeholders survive the round-trip. |
Returns: { title, slug, system_prompt }, or { error } if the agent is not in the team. By default {{…}} placeholders are resolved; pass placeholders: false for the raw stored template.
Authorization: Any agent or the admin in the same team.
get_agent_system_prompts
Read-only.
Read multiple agent system prompts in one call (max 50). Per-item mode chooses the resolution depth: placeholders (default) substitutes {{…}} with real values and stops, matching get_agent_system_prompt's default; preview additionally appends the resolver's runtime blocks (Project State, Team Context, Teammates, Working Guidelines) minus the per-run Run Context, matching the web UI's preview panel; raw returns the stored template untouched. Use this to compare prompts across the team in one round-trip - e.g. Captain auditing how team_context renders for every agent. SIZE: this tool has a raised 128KB result cap (a fully-resolved preview prompt is large), but still batch multiple items only as raw/placeholders and fetch previews one at a time so a multi-preview call can't exceed even the raised cap (result_too_large). For a single prompt, use get_agent_system_prompt.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
items | object[] | Yes | Up to 50 items. |
Returns: An array of per-item results: { index, ok: true, title, slug, system_prompt } or { index, ok: false, agent_id, error }. Up to 50 items; each mode is placeholders (default), preview, or raw.
Authorization: Any agent or the admin in the same team.
update_agent_system_prompt
Write tool.
Apply a system prompt change for an agent. Callable by the Coach agent (for after-task learned-rules updates), the CEO (during cross-project coherence, from anywhere including its live chat), or the Captain of the same team (during team-coherence reviews). The change is applied immediately and a revision snapshot is stored so the admin can restore previous versions.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
agent_id | string | Yes | Target agent - its slug (e.g. "engineer") or member ID |
new_system_prompt | string | Yes | The full updated system prompt. It MUST keep every required substitution variable ({{team_name}}, {{reports_to}}, {{skills_context}}, {{project_docs_context}}, {{team_preferences_context}}) - read the current prompt with get_agent_system_prompt(placeholders=false) first and preserve them, or the update is rejected. (The CEO and Coach are exempt.) |
change_summary | string | Yes | Summary of what changed and why |
Returns: { applied: true, document_id }, or { error } if denied or the agent is not in the team. A revision snapshot is stored so the admin can restore previous versions, and a team-coherence review is filed.
Authorization: The CEO, the Coach, or the team's Captain.
update_agent_system_prompts
Write tool.
Apply system prompt changes to MULTIPLE agents in one call - the preferred way when a review touches several agents at once (e.g. the Coach applying learned rules across everyone in a feedback loop). Same callers and rules as update_agent_system_prompt (the CEO, the Coach, or the team's Captain); each change is applied immediately with its own revision snapshot. Files a SINGLE team-coherence review that summarises all the updates, so the Captain/CEO can account for them together. Prefer this over calling update_agent_system_prompt in a loop. Up to 50 at once.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
updates | object[] | Yes | Up to 50 prompt updates. |
Returns: Batch form - { results, applied_count }, where results is a per-item array ({ index, agent_id, slug, ok: true, document_id } or { index, agent_id, ok: false, error }). Each applied change stores its own revision, and a SINGLE team-coherence review is filed summarising all of them. Up to 50 updates per call; prefer this over calling update_agent_system_prompt in a loop.
Authorization: The CEO, the Coach, or the team's Captain.
get_project_custom_prompt
Read-only.
Read this project's Custom Prompt - the project-wide instruction block (the project context / "preferences") that is injected verbatim into every agent's system prompt in this project. Returns the current content plus its length and last-updated time (empty content when none is set yet). Read this before update_project_custom_prompt so you extend the existing guidance rather than overwrite it.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
Returns: { content, length, updated_at } - the project's Custom Prompt (the project-wide instruction block injected verbatim into every agent's system prompt in the project). content is empty when none is set yet.
update_project_custom_prompt
Write tool.
Replace this project's Custom Prompt - the project-wide instruction block (the project context / "preferences") injected verbatim into every agent's system prompt in this project. Reach for this when guidance should apply to ALL of the project's agents from the very start of every run (a shared convention, standard, or fact) - it saves editing each agent's prompt one by one. The content you pass REPLACES the whole value, so call get_project_custom_prompt first and extend it. Applied immediately; a revision snapshot is stored so the admin can restore previous versions. Only callable by the CEO, Coach, or the project's Captain.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
content | string | Yes | The full new Custom Prompt content (Markdown). Replaces the current value entirely - include the existing guidance you want to keep. |
change_summary | string | No | Short summary of what changed and why (stored on the revision). |
Returns: { applied: true, document_id, length }, or { error } if denied. Replaces the project Custom Prompt wholesale; a revision snapshot is stored so the admin can restore previous versions, and a content change files a team-coherence review so it is reviewed against the roster.
Authorization: The CEO, the Coach, or the team's Captain.
set_agent_summary
Write tool.
Save a short human-readable summary for an agent (≤1000 chars, single paragraph, plain prose). Callable by any agent in the same team or any the admin; the Captain is the expected caller, but agents may also self-summarise.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
agent_id | string | Yes | Target agent - its slug (e.g. "engineer") or member ID |
summary | string | Yes | The new summary, ≤1000 chars |
Returns: { updated: true }, or { error } (summary empty, over 1000 chars, or agent not in team).
Authorization: Any agent or the admin in the same team (the Captain is the expected caller; agents may self-summarise).
set_team_summary
Write tool.
Save the team-level collaboration summary for a team (≤4000 chars, plain prose, may span paragraphs). Only callable by the Captain of that team.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
summary | string | Yes | The new team summary, ≤4000 chars |
Returns: { updated: true }, or { error } (summary empty or over 4000 chars).
Authorization: The team's Captain only.
set_agent_team_context
Write tool.
Save the team-relationships context for an agent (≤6000 chars, plain prose, second-person 'you', describes how this agent relates to its manager, direct reports, peers, indirect reports, and humans). This blob is injected into the agent's system prompt at the start of every run. Only callable by the Captain of the same team.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
agent_id | string | Yes | Target agent - its slug (e.g. "engineer") or member ID |
content | string | Yes | The new team_context, ≤6000 chars |
Returns: { updated: true }, or { error } (content empty, over 6000 chars, or agent not in team).
Authorization: The team's Captain only.
get_agent_team_context
Read-only.
Read an agent's stored team-relationships context. Useful for the Captain when regenerating siblings' contexts. Accessible by any agent or the admin in the same team.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
agent_id | string | Yes | Target agent - its slug (e.g. "engineer") or member ID |
Returns: { title, slug, team_context }, or { error } if the agent is not in the team.
Authorization: Any agent or the admin in the same team.
update_chat_memory
Write tool.
Replace your long-term chat memory - the durable notes carried into every turn of your live operator chat. Pass the FULL revised markdown; it overwrites the stored memory wholesale (there is no append). Record durable, standing knowledge only: operator preferences, decisions, and a rough gist of off-project threads. Do NOT store live data you can re-fetch each turn (project/ticket/roster state). Memory is compacted automatically when the conversation window fills - you'll be handed the window and asked to fold it in via this tool - but you may also call it any time to record something standing.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
content | string | Yes | The full long-term memory markdown (replaces existing memory) |
Returns: { written: true, updated_at }. Overwrites the calling agent's long-term chat memory wholesale (no append; no revision history).
Authorization: An agent updating its own memory only.
Approvals
list_approvals
Read-only.
List pending approvals. Pass excerpt_chars (e.g. 500) to truncate long fields inside payload (e.g. skill-proposal content); omit for full payload.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
excerpt_chars | integer | No | When set, truncates long string fields inside payload (e.g. skill-proposal content) and adds *_truncated/_length companions |
Returns: An array of pending approval rows (id, team_id, type, status, requested_by_member_id, resolution_note, resolved_at, created_at, payload). excerpt_chars truncates long string fields inside payload.
resolve_approval
Write tool.
Approve or deny an approval
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
approval_id | string | Yes | Approval ID |
status | approved | denied | Yes | Resolution status |
resolution_note | string | No | Note |
Returns: The updated approval row, or { error } if not found or denied.
Authorization: Authorized against the approval's own team/project; an agent run must be scoped to act on it.
Skills & search
propose_skill
Write tool.
Propose a new skill for the team's skills database (reusable team know-how: MCP server usage, integration steps, conventions, how agents coordinate). Creates an approval request; when approved the skill is written to the skills database. Choose scope: 'global' shares it with every project, 'project' keeps it private to this project. Defaults to 'project'.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
skill_name | string | Yes | Human-readable skill name |
skill_slug | string | Yes | URL-safe slug for the skill file |
content | string | Yes | Skill content (markdown) |
reason | string | Yes | Why this skill should be added |
scope | project | global | No | 'global' shares the skill with every project; 'project' keeps it private to this project. Defaults to 'project'. |
Returns: { approval_id, status } - creates a skill-proposal approval that writes the skill when approved.
full_text_search
Read-only.
Full-text keyword search across the team skills database, tasks, project docs, and task comments. Returns results ranked by relevance (keyword + stemming match). A bare task number or full identifier (e.g. "169" or "HM-169") resolves directly to that task, ranked first.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
query | string | Yes | Search query (keywords) |
scope | all | tasks | skills | project_docs | comments | No | Limit search to specific content type (default: all) |
limit | number | No | Max results per type (default: 10) |
Returns: { results, count } - full-text (keyword + stemming) matches ranked by relevance across skills, tasks, project docs, and comments. A bare task number or full identifier resolves directly to that task, ranked first.
list_skills
Read-only.
List the team's skills database - the manifest of reusable team know-how (MCP server usage, integration steps, conventions, how agents coordinate). Returns each skill's name, slug, and description; call get_skill to load a skill's full body on demand.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
tags | string | No | Filter by tag (comma-separated) |
Returns: { skills: [{ id, name, slug, description, tags, created_at, updated_at }] }. Pass tags (comma-separated) to filter.
get_skill
Read-only.
Load the full body of a skill from the team's skills database by slug. Use after list_skills surfaces a relevant skill in the manifest.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
slug | string | Yes | Skill slug |
Returns: The full skill row (including content), or { error } if not found.
create_skill
Write tool.
Add or update a skill in the team's skills database directly (no approval needed) - record reusable team know-how such as MCP server usage, integration steps, conventions, and how agents coordinate. Use propose_skill when approval is required. If description is omitted it is derived from the skill body. Choose scope deliberately: 'global' when the know-how helps agents in ANY project (related or not), 'project' when it is specific to this project. Omitting scope defaults to 'project'.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
name | string | Yes | Human-readable skill name |
slug | string | Yes | URL-safe slug |
content | string | Yes | Skill content (markdown) |
description | string | No | Short description |
tags | string | No | Comma-separated tags |
scope | project | global | No | 'global' shares the skill with every project; 'project' keeps it private to this project. Defaults to 'project'. |
Returns: { skill_id, slug, created: true }. Upserts by slug and writes a skill revision; description is derived from the body when omitted.
Credentials & connectors
request_credential
Write tool.
Ask the human assignee to provide a secret value (API key, SSH private key, OAuth token, etc.). Posts a structured comment on the task with a paste form. The agent never sees the value; it gets a placeholder string to embed in env vars or HTTP headers, which the egress proxy later substitutes. Returns immediately with the placeholder; the agent should stop work on whatever needed the credential and wait for a credential_provided wakeup. For HTTP-auth kinds (api_key, oauth_token, github_pat) allowed_hosts is REQUIRED - scope it to the provider API host(s) so the secret can only ever reach those hosts. Always ask for the narrowest scope and shortest expiry the provider offers. If a registered connector capability already covers the provider (e.g. a remote MCP server with OAuth), prefer register_connector over a raw paste.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID - the request comment is posted here |
name | string | Yes | Secret name. Must match [A-Z][A-Z0-9_]{0,63} (e.g. GITHUB_PAT, ANTHROPIC_API_KEY). The placeholder returned will be _HEZO_SECRET |
kind | api_key | ssh_private_key | github_pat | oauth_token | webhook_secret | other | Yes | Type of credential - drives validation when the human submits the value |
instructions | string | Yes | Human-facing prose explaining why you need this credential and how the human can obtain it. Tell the human to set the minimal scope and the shortest expiry the provider supports (e.g. "I need a GitHub PAT with only repo scope to push branches, ideally expiring in 7 days. Create one at https://github.com/settings/tokens"). |
input_type | text | textarea | file | No | Form input type. Defaults: text for short keys, textarea for SSH/multiline. |
confirmation_text | string | No | Optional yes/no confirmation prompt instead of a paste form (e.g. "Have you added the public key to github.com/owner/repo/settings/keys?"). When set, input_type is ignored. |
allowed_hosts | string[] | No | Hostname allowlist for the egress proxy. The credential is only substituted into outbound requests to these hosts. REQUIRED for HTTP-auth kinds (api_key, oauth_token, github_pat) - e.g. ["api.netlify.com"]. Wildcards: *.github.com matches one label segment. |
allow_body_substitution | boolean | No | Request that this credential may be substituted into a small JSON request body, not just headers/URL - for APIs that take the secret in the body, e.g. a login POST that returns a token. The human sees this as a pre-checked box on the paste form and can decline it. Body substitution is gated to a single application/json request under 8KB with a fixed Content-Length; after a login, read the returned token and use it via the Authorization header on later calls. |
Returns: { placeholder, comment_id, status: "pending", reused }. The agent never sees the value; it embeds placeholder (__HEZO_SECRET_<NAME>__) and the egress proxy substitutes the real value. Returns { error } for an invalid name, or for an HTTP-auth kind requested without allowed_hosts. Idempotent on name.
register_connector
Write tool.
Register a third-party connector for the team and ask the human to authenticate. Posts a connect_required comment on the task with a Connect button; the human completes it inline (in the task comment or on the Connectors page). The agent never sees the token; subsequent runs receive the connector via the egress proxy + placeholder substitution. Idempotent: re-registering an already-active connector returns its current state and fires the wakeup immediately.
Two kinds:
- kind "saas" (default): a hosted MCP server. Give mcp_url. Auth is chosen by what the provider supports: servers that advertise OAuth Dynamic Client Registration (most MCP servers) authorize with zero config; providers whose Authorization Server cannot do DCR (e.g. GitHub) require a pre-registered client_id and the device flow - register those with provider_id set to a known registry key (e.g. "github").
- kind "api": a credentialed REST API the agent calls directly (no MCP server). Give base_url + allowed_hosts (+ optional auth placement). For an OAuth-backed API, also set oauth_provider_id to a bundled OAuth-broker provider (e.g. "google-youtube"): the human then completes the OAuth device flow by pasting just a client id, with the provider pre-selected and locked. For a plain static-key API, omit oauth_provider_id and the human attaches an API key.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
task_id | string | Yes | Task identifier or UUID where the connect_required comment is posted |
display_name | string | Yes | Human-readable connector name shown in the task chat and on the Connectors page (e.g. "DatoCMS", "Linear"). |
kind | saas | api | No | Connector kind. 'saas' (default) = a hosted MCP server (needs mcp_url). 'api' = a credentialed REST API the agent calls directly with no MCP server (needs base_url + allowed_hosts) - use this for an OAuth-backed HTTP API like a Google API. |
mcp_url | string | No | URL of the MCP server (HTTP / SSE) - required for kind 'saas'. The OAuth dance is discovered by probing this URL for a 401 + WWW-Authenticate header. |
mcp_transport | http | sse | No | Transport for the MCP server. Defaults to http. |
provider_id | string | No | Optional MCP capability-registry key (e.g. "datocms", "github"). When set, capability defaults from the shared registry pre-fill display name and allowed hosts. This is the MCP-server registry namespace - not the OAuth-broker provider (see oauth_provider_id). |
base_url | string | No | For kind 'api' - the REST API base URL agents call (e.g. https://www.googleapis.com/youtube/v3). |
allowed_hosts | string[] | No | For kind 'api' - the hosts the credential may be sent to (e.g. ["*.googleapis.com"]). Required for api connectors. |
auth | object | No | For kind 'api' - where the credential rides. Defaults to an Authorization: Bearer header when omitted (the right default for OAuth access tokens). |
oauth_provider_id | string | No | For kind 'api' only - a bundled OAuth-broker provider key (e.g. "google-youtube") to pre-select for the human. The provider is then LOCKED in the completion UI: the human finishes the OAuth device flow inline (in the task comment or on the Connectors page) by pasting only a client id - no provider picker. Omit for a plain API-key REST connector. |
skill_id | string | No | Optional ID of a previously-fetched skill document (see fetch_skill_file). When set, the skill file is exposed to every team agent run via the per-adapter skill path. |
access | read | write | No | How much of the server you need. 'write' (default) leaves every method the server advertises available. 'read' asks for read-only: once the human connects it, every write method the server advertises is disabled automatically, and runs never see them. Ask for 'read' whenever the task only needs to look things up - it is the narrowest scope that still does the job, and the human can widen it later. This is a request, not a grant: if the human has already chosen which methods are enabled, their choice stands. |
Returns: { connector_id, status, name, display_name, comment_id?, reused }. status is active (OAuth already complete) or pending (a connect_required comment is posted for the human). Idempotent. Pass access: "read" when the task only needs to look things up: every write method the server advertises is disabled once the human connects it, and the connect card says so before they authorize. The request narrows only - it never widens access, and it is skipped entirely if the human has already chosen which methods are enabled.
fetch_skill_file
Read-only.
Fetch a remote agent skill file (Markdown describing how to use a third-party MCP server) and store it as a skill (auto_load). Returns the skill_id and slug. Subsequent agent runs get this skill file injected into their adapter's skills directory. Idempotent on the derived slug - re-fetching the same URL updates the existing skill. Choose scope: 'global' shares it with every project (e.g. a widely-used MCP's usage docs), 'project' keeps it private to this project. Defaults to 'project'.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
url | string | Yes | HTTPS URL of the skill file. Only http/https schemes are allowed; response must be < 256KB; 10s timeout. |
title | string | No | Human-readable title shown in the team KB. Defaults to the URL pathname. |
scope | project | global | No | 'global' shares the skill with every project; 'project' keeps it private to this project. Defaults to 'project'. |
Returns: { skill_id, slug, source_url, size_bytes, reused }, or { error } (invalid URL, non-HTTP(S), over 256 KB, or fetch failure). Stored as an auto-load global skill; idempotent on the derived slug.
MCP connections
list_connectors
Read-only.
List the connectors available to agent runs in your project (its own connectors plus global "all projects" ones; a project connector shadows a global one of the same name). Each row includes a derived oauth_status so you can tell whether a connector is usable: "active" means OAuth completed and the MCP tools should appear in your tool list on your next run; "pending" means waiting on the human to click Connect; "failed" means the OAuth flow errored (see auth_error); "revoked" means a human disconnected it; "none" means no OAuth needed (e.g., an env-var-token MCP or a public one). Do NOT confuse install_status (which tracks local-package install state and is meaningless for SaaS MCPs) with oauth_status. An active OAuth-backed connector also carries rest_auth = { placeholder, allowed_hosts, scopes }: put placeholder (e.g. in an Authorization: Bearer <placeholder> header) on a raw HTTP request to authenticate the provider's REST API directly when no MCP tool covers what you need - the egress proxy substitutes the real token, but ONLY for requests to allowed_hosts; you never see the value. Use this instead of requesting a PAT (e.g. for GitHub repo-settings edits that the github MCP does not expose). A connector of kind api (a credentialed REST API with no MCP server) carries api_auth = { base_url, placeholder, allowed_hosts, placement, name, docs_url } instead: put placeholder in the name header (when placement is "header", prefixed by any scheme) or name query parameter (when placement is "query") and send the request to base_url - the egress proxy substitutes the real key, scoped to allowed_hosts. placeholder is null until a human attaches the credential on the Connectors page; api_auth is null for non-api rows. An api connector may instead be OAuth-backed (a human connected it via the device flow): then api_auth.placeholder is a broker-managed OAuth access token that Hezo keeps refreshed host-side - use it exactly the same way.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
Returns: An array of connector rows with a derived oauth_status (active | pending | failed | revoked | none) and, for an active OAuth-backed connector, rest_auth = { placeholder, allowed_hosts, scopes } (else null). Other fields include id, name, display_name, kind, config, project_id, oauth_account_label, install_status, install_error, skill_id, created_by_task_id, activated_at, revoked_at, auth_error. A hosted MCP connector whose methods have been listed also carries method_access = { mode: "all" | "restricted", enabled, total, disabled_write } (else null) - when mode is restricted, the withheld methods are absent from your tool list on purpose, so a tool you expect and cannot see is disabled rather than missing. Scoped to your project: its own connectors plus global ("all projects") ones, with a project connector shadowing a global one of the same name.
test_connector
Read-only.
Test an MCP connector end-to-end from the server side. Resolves the stored OAuth token from the vault and makes a direct HTTP call to the MCP server (bypassing the agent container and its egress proxy entirely). Returns the upstream status code, response excerpt, and the secret name + masked-token-prefix used. Use this when oauth_status says "active" but the MCP's tools are absent from your tool list - it isolates "is the token still valid against the provider?" from "does the proxy chain in the container work?".
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
connector_id | string | Yes | connector id or name (both shown by list_connectors) |
Returns: { ok, status, mcp_url, secret_name, token_prefix, token_length, www_authenticate, body_excerpt, hint } from a direct server-side probe of the MCP URL. Returns { error } if the connector is missing, not saas, or its token cannot be decrypted.
add_connector
Write tool.
Register a connector for your project - a SaaS HTTP MCP server (saas), a local stdio MCP server (local), or a credentialed REST API you call directly with no MCP server (api). The connection is scoped to your project - available to this project's agent runs, alongside any global "all projects" connectors. SaaS servers go into the agent's descriptor list immediately. Header values may include HEZO_SECRETapi connector has no MCP server: attach a credential to it (Connectors page → API key) and it surfaces in list_connectors as an api_auth block whose placeholder you put in the auth header/query and send to base_url directly - the egress proxy substitutes, scoped to allowed_hosts.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
name | string | Yes | Server identifier - used as the MCP descriptor name and as the unique key. |
kind | saas | local | api | Yes | saas = HTTP MCP, local = stdio MCP, api = direct REST API (no MCP server) |
config | object | Yes | For saas: { url, headers? }. For local: { command, args?, env?, package? }. For api: { base_url, allowed_hosts: string[], auth: { placement: "header"|"query", name, scheme? }, docs_url? }. |
Returns: { id, install_status, note }, or { error } if config.url (saas) / config.command (local) is missing. Upserts by name within your project.
remove_connector
Write tool.
Remove one of your project's registered MCP connections. Only connectors owned by your project can be removed - global "all projects" connectors and other projects' are managed elsewhere. The next agent run will not see it.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
id | string | Yes | connector id or name (returned by add_connector or list_connectors) |
Returns: { removed: true, id }, or { error } if the connection is not found. Removes only your project's own connector (never a global or another project's).
Project docs & assets
list_project_docs
Read-only.
List project documentation files (PRD, spec, implementation plan, etc.). Each entry carries its filename and a one-line description (what the doc is / when to read it, '' if unset). Archived (soft-deleted) docs are excluded by default - set filter: 'archived' or 'all' to see them (entries then carry an archived flag).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
filter | active | archived | all | No | Which archive states to consider: 'active' (default - archived items are excluded), 'archived' (only archived), or 'all'. |
Returns: { files: [{ id, filename, description, updated_at }] } - the markdown project docs, where description is the overall "what this is" summary ('' if unset). The filter param defaults to 'active' (archived docs excluded); with 'archived' or 'all' each entry also carries archived: boolean.
list_project_assets
Read-only.
List the project's assets - files in the assets library (UI mockups, wireframes, diagrams, images, PDFs, scripts, and generated markdown such as blog posts or reports). Filenames may carry a folder prefix up to 2 levels deep (e.g. launch/images/hero.png); reference one in a comment or doc as assets/<path> exactly as returned here (e.g. assets/launch/images/hero.png), no backticks. Author both text and binary assets with write_project_asset (binary via encoding: 'base64') and reorganize with move_project_asset / copy_project_asset; obsolete assets are archived with archive_project_asset (hard deletion is admin-only). Archived assets are excluded by default - set filter: 'archived' or 'all' to see them (entries then carry an archived flag). Raster image entries (PNG/JPEG/GIF/WebP) also carry their pixel width/height. Results are ordered newest-first by default; pass sort: 'oldest' or 'alphabetical' to change the order.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
filter | active | archived | all | No | Which archive states to consider: 'active' (default - archived items are excluded), 'archived' (only archived), or 'all'. |
sort | newest | oldest | alphabetical | No | Order of the returned assets: 'newest' (default - most recently created first), 'oldest', or 'alphabetical' (by filename, A→Z). |
Returns: { files: [{ id, filename, content_type, created_at, width?, height? }] } - the project asset files; raster images (PNG/JPEG/GIF/WebP) also carry pixel width/height. filename is the full path and may carry a folder prefix up to 2 levels (e.g. launch/images/hero.png). The filter param defaults to 'active' (archived assets excluded); with 'archived' or 'all' each entry also carries archived: boolean.
write_project_asset
Write tool.
Save a file to the project assets library so a human can open it AND other agents (your teammates and your own future runs) can read it back with read_project_asset - including a binary deliverable or generation output you produced (a rendered image, chart, diagram, screenshot, PDF, dataset, or media file). This is how such a file reaches both the admin and the next agent: a file left on the ephemeral container disk vanishes when the run ends and is invisible to everyone else, so anything a later step or teammate will reuse belongs here. Text formats (.html, .svg, .txt, .md, plus script/text formats stored as plain text: .sh, .py, .js, .ts, .json, .csv, .yaml, .yml) are written with the default encoding "utf8". Binary formats - any type a human can upload (.png, .jpg, .jpeg, .gif, .webp, .pdf, .mp3, .mp4, .webm, archives such as .zip/.tar/.tar.gz/.7z, …) - MUST pass encoding: "base64" with the file's bytes base64-encoded in content. For a LARGE binary, upload it instead via a multipart/form-data POST to /mcp/assets (fields file and path for the full destination path, plus optional overwrite=true to replace an existing asset in place, same Bearer auth): base64 in a JSON-RPC tool call can be silently truncated by a runtime's argument-size cap, whereas the multipart endpoint streams the bytes; the result is identical and shows up in list_project_assets / read_project_asset. When you DO write a binary through this tool, pass byte_size (the file's exact byte length) so a truncated content is rejected instead of stored corrupt. The filename may include a folder path up to 2 levels deep (e.g. "scripts/deploy-check.sh" or "launch/images/hero.png") - folders spring into existence with their first asset. Re-saving the same path overwrites it, so the reference stays stable; overwrite matching is PATH-EXACT ("x.html" and "blog/x.html" are different assets - after a move, write to the new full path or you will fork the file). IMPORTANT: any write to an existing path deletes ALL of its pending review comments (the admin's feedback returned by read_project_asset) - capture every comment in your context before the first write, and make all desired edits in one consolidated write. Returns the reference string to drop into a comment as assets/<path> (no backticks). HTML opens interactively in a new tab; markdown renders with a rich preview and a view-source toggle; images render inline in the assets library. Use a markdown asset for a standalone deliverable opened from the assets library; use write_project_doc for project context docs (specs, PRDs, research). Mockups and other deliverables belong here, never committed to the source repo.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
filename | string | Yes | Path to write, optionally foldered (e.g. "ui-mockups.html", "launch/images/hero.png") |
content | string | Yes | File content - raw text for utf8, or base64-encoded bytes for base64 |
encoding | utf8 | base64 | No | utf8 (default) for text assets; base64 for binary assets (images, PDFs, media) - required for any non-text type |
byte_size | integer | No | For a base64 binary: the file's exact byte length. When provided, the decoded content is checked against it and a truncated upload (a runtime capping the tool-call argument size, cutting content mid-stream) is rejected instead of silently stored. Strongly recommended for binaries. |
Returns: { written: true, id, reference: "assets/<path>", byte_size, width?, height? } (raster images also report their pixel width/height), or { error }. Accepts any type a human can upload: text formats (.html, .svg, .txt, .md, and .sh/.py/.js/.ts/.json/.csv/.yaml/.yml stored as plain text) with the default encoding: "utf8", and binary formats (.png, .jpg, .gif, .webp, .pdf, media, archives such as .zip/.tar/.tar.gz/.7z, …) with encoding: "base64" - a non-text type written without base64 is rejected, as is invalid or truncated base64 (a runtime argument-size cap can cut a large base64 content mid-stream - pass byte_size (the file’s exact byte length) so a short decode is rejected, or upload large binaries via a multipart POST to /mcp/assets with a path field and optional overwrite=true, which streams the bytes with no argument limit). Also errors if the type is unsupported, the path is invalid (max 2 folder levels), the content exceeds 10 MB, or an archived asset holds the path (unarchive it first or pick another path). Re-saving the same path overwrites it; matching is path-exact. Overwriting deletes ALL pending review comments on the asset (the admin feedback returned by read_project_asset) - read them first and make all edits in one consolidated write.
read_project_asset
Read-only.
Read a project asset's contents by path (e.g. "ui-mockups.html" or "scripts/check.sh") - the files that list_project_assets returns (UI mockups, wireframes, SVG diagrams, text exports, scripts, markdown deliverables). Use the full path exactly as listed, folder prefix included. Text-based assets (HTML, SVG, plain text, markdown) come back inline as content. Raster images (PNG/JPEG/GIF/WebP) come back with their pixel width/height AND the image itself inline, so a vision-capable model can see it to review it - pass include_image: false to skip the pixels and get metadata only, and images above ~4 MB return metadata + url only. Other binary assets (PDFs, media, archives) are not inlined; the response gives a signed download url - fetch it with a plain curl -fsSL '<url>' -o /tmp/<filename> (no auth header needed; the URL is valid for 24h, re-call this tool for a fresh one). An archive (.zip, .tar, .tar.gz/.tgz, .7z) is downloaded that same way and then unpacked in your container - unzip, tar and 7z are preinstalled. If an admin has left review comments on the asset they come back as review_comments: for text assets (markdown, plain text) each anchors to an exact quote (with occurrence = 0-based Nth match of that snippet); a comment without a quote applies to the whole file. Capture them all before any write_project_asset to the path - overwriting deletes every review comment. Archived assets are not readable by default - set filter: 'archived' or 'all' to read one. For markdown project docs use read_project_doc instead.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
filename | string | Yes | Asset path to read (e.g. "ui-mockups.html", "launch/images/hero.png") |
filter | active | archived | all | No | Which archive states to consider: 'active' (default - archived items are excluded), 'archived' (only archived), or 'all'. |
include_image | boolean | No | For raster images (PNG/JPEG/GIF/WebP): when true (default) the image is returned inline so a vision-capable model can see it. Pass false to get metadata only (dimensions + download URL) and skip the pixels. |
Returns: For a text asset, { filename, content_type, content }. For a raster image (PNG/JPEG/GIF/WebP) at or under ~4 MB, the image is returned inline as an MCP image content block alongside a text block of { filename, content_type, byte_size, binary: true, width, height, url } so a vision-capable model can see it - pass include_image: false (or exceed the size cap) for that metadata alone with no image block. Other binary assets - PDFs, media, and archives (.zip, .tar, .tar.gz/.tgz, .7z, .rar) - return { filename, content_type, byte_size, binary: true, url } - a signed download URL valid for 24h; fetch it with plain curl (no auth header), and re-call the tool for a fresh one if it expires. An archive is unpacked in the run container after download. Either shape also carries review_comments: [{ id, quote?, occurrence?, comment, created_at }] when the admin has left pending review feedback on the asset: on a text asset (markdown, plain text) a comment anchors to an exact quote snippet (occurrence disambiguates repeats); a comment without a quote applies to the whole file. Any write to the asset's path deletes all of its review comments, so capture them before writing. Returns { error } if not found - match the full path, folder prefix included - or if the asset's archive state doesn't match filter (default 'active', so archived assets need filter: 'archived' or 'all'; an archived read carries archived: true).
move_project_asset
Write tool.
Move or rename a project asset within the assets library: change its folder (up to 2 levels deep), its filename, or both - folders spring into existence when the first asset lands in them and vanish with their last one. The stored file does not change, so the destination must keep the same extension. Moves never overwrite: if the destination path is taken the call fails. IMPORTANT: existing text references to the old assets/<path> in comments and docs are NOT rewritten - they degrade to plain text - so update the places that cite the old path, and prefer organizing assets early over moving them later. To retire an obsolete asset, use archive_project_asset instead of moving it aside (hard deletion is admin-only).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
from | string | Yes | Current asset path (e.g. "hero.png" or "launch/hero.png") |
to | string | Yes | Destination path (e.g. "launch/images/hero.png") |
Returns: { moved: true, id, from, reference: "assets/<path>", note }, or { error } when the source is missing or archived, the destination exists (moves never overwrite; an archived asset still holds its path), the extension changes, or a path is invalid. Metadata-only - the stored bytes do not move. Existing text references to the old path are not rewritten.
copy_project_asset
Write tool.
Copy a project asset to a new path in the assets library (any type, including binary). The copy is a new asset with its own id; the source is untouched and existing references keep pointing at it. Copies never overwrite: if the destination path is taken the call fails. Use it to duplicate a template before editing, or to stage related files into a folder.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
from | string | Yes | Source asset path (e.g. "templates/report.md") |
to | string | Yes | Destination path (e.g. "2026-q3/report.md") |
Returns: { copied: true, id, reference: "assets/<path>" } - a new asset with its own id, any type including binary. Returns { error } when the source is missing or archived, the destination exists (copies never overwrite), or a path is invalid.
archive_project_asset
Write tool.
Archive a project asset - the reversible soft delete, and the ONLY way an agent retires an asset (hard deletion is admin-only, so treat any "delete this asset" instruction as archive). The asset disappears from list_project_assets and default reads but keeps its path reserved; existing assets/
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
filename | string | Yes | Asset path to archive - the full path exactly as list_project_assets returns it (e.g. "drafts/old-v1.md") |
Returns: { archived: true, reference: "assets/<path>", changed } (changed: false when it was already archived - the call is idempotent), or { error } if the asset is not found. The archived asset leaves listings and default reads but keeps its path reserved; existing assets/<path> references keep resolving.
Authorization: Archival is the agent-facing soft delete; hard deletion of assets is admin-only in the web app.
unarchive_project_asset
Write tool.
Restore an archived project asset to active. It reappears in list_project_assets, becomes readable and writable again, and its assets/
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
filename | string | Yes | Asset path to restore (the same path it was archived under) |
Returns: { archived: false, reference: "assets/<path>", changed } (changed: false when it was already active), or { error } if the asset is not found.
read_project_doc
Read-only.
Read a markdown project doc by filename (e.g. "spec.md") - the high-level project context (PRDs, specs, architecture decisions, research) that list_project_docs returns; the full body comes back inline as content. These docs live in the project-doc store in the database, NOT on the filesystem: there is no /workspace/.hezo/project-docs path, so do not reach for the Read/cat file tools - always load a doc through this tool by its bare filename. Archived docs are not readable by default - set filter: 'archived' or 'all' to read one. When the admin has left review feedback on the doc, the result includes review_comments - each anchors a comment to a quote (an exact text snippet; occurrence disambiguates repeated snippets). Action them when asked to. IMPORTANT: any write to the doc deletes ALL of its review comments, so capture every comment from this result BEFORE your first write_project_doc call - after one write they are gone. For non-markdown assets (mockups, wireframes, diagrams) use read_project_asset instead. Large docs come back one byte-window at a time: when truncated is true, call again with offset set to the returned next_offset and keep going until next_offset is null.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
filename | string | Yes | Filename to read (e.g. "spec.md") |
filter | active | archived | all | No | Which archive states to consider: 'active' (default - archived items are excluded), 'archived' (only archived), or 'all'. |
offset | integer | No | Byte offset to start reading from (default 0). To page through a doc too large for one read, pass back the next_offset from the previous call. Snapped down to a UTF-8 character boundary so a window never begins mid-character. |
max_bytes | integer | No | Max bytes of content to return in this window (default and ceiling is the read budget, so a normal-size doc comes back whole). Clamped to the budget; the returned slice ends on a UTF-8 character boundary, so it can come back a few bytes short. |
Returns: { filename, content, offset, returned_bytes, total_bytes, next_offset, truncated }. content is a UTF-8 byte window of the markdown body starting at offset (default 0). A doc that fits in one read comes back whole (offset: 0, next_offset: null, truncated: false, returned_bytes === total_bytes). A larger doc is paged: truncated is true, next_offset is the byte offset to pass back as offset on the next call, and a paging_hint string spells out the loop - keep calling until next_offset is null, concatenating each content. The optional max_bytes param shrinks a window. description is included when the doc has an overall summary set. review_comments: [{ id, quote, occurrence, comment, created_at }] is included when the admin has left pending review feedback (each anchors to an exact quote snippet; occurrence disambiguates repeats); any write to the doc deletes all of its review comments, so capture them before writing. Returns { error } if the file is not found or its archive state doesn't match filter (default 'active', so archived docs need filter: 'archived' or 'all'; an archived read carries archived: true).
write_project_doc
Write tool.
Write a project documentation file. Project docs are markdown only - the filename must end in .md. For high-level project context: PRD, spec, implementation plan, research. Make ALL desired edits in ONE consolidated write per run, for two reasons: (1) writing a doc deletes ALL of its pending review comments (the admin's highlight feedback returned by read_project_doc) - a single write clears the whole review, so capture every comment in your context before the first write; (2) docs are revisioned - every content-changing write records a revision, so many partial writes bury the history in noise. Pass a changelog summarizing what changed in this write and why - it becomes that revision's entry in the document's history; keep update/changelog logs OUT of the document body and put them in changelog instead. Also pass a description: an overall summary of what the doc is and when to read it, in no more than one or two sentences, shown next to the filename in the Documents list and the doc header so teammates and future runs can tell what the doc is at a glance. Describe the doc's stable purpose, NOT its current contents: do not list its sections, findings, dates, counts, or latest revisions (those live in the body and the changelog), so the description stays steady across updates. Keep it short and out of the body. Non-markdown files (mockups, wireframes, images, PDFs) live in the project assets library instead - reference those as assets/<filename>. In content, reference teammates with @
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
filename | string | Yes | Markdown filename to write (e.g. "spec.md") |
content | string | Yes | File content (markdown) |
description | string | No | An overall summary of what this doc is and when to read it, in no more than one or two sentences (e.g. "How we track and report campaign analytics each week"). Describe its stable purpose, not its current contents: do NOT list the sections, findings, dates, counts, or latest revisions here (those belong in the body and the changelog), so the description stays steady across updates. Shown next to the filename in the Documents list and the doc header so teammates and future runs can tell what the doc is without opening it. It is NOT the changelog and NOT part of the body. Omit to leave any existing description unchanged. |
changelog | string | No | Markdown summary of what changed in THIS update and why - recorded as the revision's changelog and shown in the document's revision history. Put update/status notes here, never in the document body. Reference tickets/docs/agents by bare identifier as in content. |
Returns: { written: true, id, filename }, or { error } if the filename is not .md or the doc is archived (unarchive first - archived docs are read-only). Make all edits in one consolidated write: a content-changing write deletes ALL pending review comments on the doc (read them first) and records a document revision, so many partial writes lose review context and bury the revision history. The optional description sets the doc's overall "what this is" summary - one or two sentences describing the doc's stable purpose, not its current contents (shown in the Documents list and doc header; omit to leave it unchanged). The optional changelog is stored as that revision's changelog and shown in the document's history - put update/status notes there, not in the document body.
archive_project_doc
Write tool.
Archive a project doc - the reversible soft delete, and the ONLY way an agent retires a doc (hard deletion is admin-only, so treat any "delete this doc" instruction as archive). The doc disappears from list_project_docs, default reads, and future runs' context, but keeps its filename reserved and its revision history; existing references keep resolving. Reverse with unarchive_project_doc. No approval needed.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
filename | string | Yes | Doc filename to archive (e.g. "old-plan.md") |
Returns: { archived: true, filename, changed } (changed: false when it was already archived - the call is idempotent), or { error } if the file is not found. The archived doc leaves listings, search, and agent-run context but keeps its filename reserved and its revision history.
Authorization: Archival is the agent-facing soft delete; hard deletion of docs is admin-only in the web app.
unarchive_project_doc
Write tool.
Restore an archived project doc to active. It reappears in list_project_docs and agent-run context, and becomes readable and writable again with its content and revision history intact.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
filename | string | Yes | Doc filename to restore (e.g. "old-plan.md") |
Returns: { archived: false, filename, changed } (changed: false when it was already active), or { error } if the file is not found.
Costs
get_costs
Read-only.
Get the cost summary for a project
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
project | string | No | Project slug or ID. Omit to use the project your run is already in; instance agents (CEO/Coach) must name the project to act in. |
group_by | agent | day | No | Group costs by |
Returns: With group_by: "agent", an array of { member_id, agent_title, total_cents }; with group_by: "day", an array of { day, total_cents }; otherwise { total_cents, entry_count }.
Onboarding
register
Read-only.
Register this agent with Hezo. Returns an access token (shown once) - set it as your Authorization: Bearer token. The registration is inert until a Hezo admin approves it under Settings → API keys; once approved you have full instance access (every project and team). Poll connection_status to learn when you are approved.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | A human-readable name for this agent, shown to the admin who approves it. |
client_info | object | No | Optional MCP client info (e.g. {"name":"claude","version":"…"}). |
Returns: { id, token, status, message } - the hezo_… token is shown once. Returns { error } if name is missing.
Authorization: No token required - this is how an external agent self-registers. The registration stays inert until a Hezo admin approves it.
connection_status
Read-only.
Check whether this agent has been approved yet. Send your token as the Authorization: Bearer token. Returns {"status":"pending"} or {"status":"approved"}.
Parameters: none.
Returns: { status: "pending" | "approved" }, or { error } if no/unknown token is sent.
Authorization: Keyed by the bearer token from register; no approved principal required.
Generated from the MCP tool registry. Full docs: https://hezo.ai/docs/introduction