> ## Documentation Index
> Fetch the complete documentation index at: https://docs.substrate.42.pe/llms.txt
> Use this file to discover all available pages before exploring further.

# Substrate MCP Task and Comment Write Tools (7 Total)

> The 7 Substrate MCP write tools for tasks and comments — create, update, archive, add comments, and edit them. All return an envelope.

These seven tools cover the everyday writes: creating and updating tasks, moving them between groups, and adding or editing comments. Every tool requires `agent_name`. Task writes require the `version` from your last read of that task; comment writes do not. All return a [write envelope](/mcp/envelopes-and-errors).

***

## Tasks

### `create_task`

Creates a new task and places it in the specified group.

<ParamField path="board_id" type="string" required>
  The board to create the task on.
</ParamField>

<ParamField path="group_id" type="string" required>
  The group to place the task in.
</ParamField>

<ParamField path="title" type="string" required>
  The task title.
</ParamField>

<ParamField path="agent_name" type="string" required>
  A stable identifier for the calling agent. Recorded as the creator in the event log.
</ParamField>

<ParamField path="description" type="string">
  Task description. Markdown is supported.
</ParamField>

<ParamField path="custom_data" type="object">
  Custom field values. Validated lazily against the board's `field_schema`.
</ParamField>

<ParamField path="parent_id" type="string">
  Providing a parent task id makes this a subtask.
</ParamField>

<Note>
  `custom_data` cannot include a `human_only` field. The tool refuses it — that refusal is the mechanism behind human gates. If a required field is `human_only`, create the task without it and use `list_pending_approvals` to surface the approval request.
</Note>

### `update_task`

Updates an existing task. Send only the fields you are changing — omitted fields are left as-is.

<ParamField path="id" type="string" required>
  The task id.
</ParamField>

<ParamField path="version" type="integer" required>
  The version from your last read. A stale version returns `version_mismatch`.
</ParamField>

<ParamField path="agent_name" type="string" required>
  A stable identifier for the calling agent.
</ParamField>

<ParamField path="title" type="string">
  New title.
</ParamField>

<ParamField path="description" type="string">
  New description. Markdown is supported.
</ParamField>

<ParamField path="custom_data" type="object">
  Merges key-by-key into existing `custom_data`. Set a key to `null` to delete it.
</ParamField>

<ParamField path="group_id" type="string">
  Moving the task to a different group. This change is what a transition guard inspects.
</ParamField>

**Handling a blocked move:** If a transition guard rejects the move, the tool returns a `transition_blocked` error and appends a `move_blocked` event to the task's history. Read the error message, satisfy the requirement, and retry. If the blocking field is `human_only`, you have no path to clear it yourself — call `list_pending_approvals` and report the approval command to the human.

### `archive_task`

Soft-deletes a task. Sets `archived_at`; preserves the full history. Nothing hard-deletes a task in Substrate.

<ParamField path="id" type="string" required>
  The task id.
</ParamField>

<ParamField path="version" type="integer" required>
  The version from your last read.
</ParamField>

<ParamField path="agent_name" type="string" required>
  A stable identifier for the calling agent.
</ParamField>

### `unarchive_task`

Restores an archived task. Clears `archived_at`; history is preserved.

<ParamField path="id" type="string" required>
  The task id.
</ParamField>

<ParamField path="version" type="integer" required>
  The version from your last read.
</ParamField>

<ParamField path="agent_name" type="string" required>
  A stable identifier for the calling agent.
</ParamField>

***

## Comments

### `add_comment`

Adds a comment to a task. Top-level comments and threaded replies are both supported.

<ParamField path="task_id" type="string" required>
  The task to comment on.
</ParamField>

<ParamField path="body" type="string" required>
  Comment body. Markdown is supported.
</ParamField>

<ParamField path="agent_name" type="string" required>
  A stable identifier for the calling agent.
</ParamField>

<ParamField path="parent_id" type="string">
  Providing a parent comment id makes this a reply in that thread.
</ParamField>

<ParamField path="custom_data" type="object">
  Custom field values. Validated against `field_schema.comments`.
</ParamField>

### `edit_comment`

Edits the body or custom data of an existing comment. Comments are last-write-wins — there is no version requirement.

<ParamField path="id" type="string" required>
  The comment id.
</ParamField>

<ParamField path="agent_name" type="string" required>
  A stable identifier for the calling agent.
</ParamField>

<ParamField path="body" type="string">
  Replacement body. Markdown is supported.
</ParamField>

<ParamField path="custom_data" type="object">
  Merges key-by-key. Set a key to `null` to delete it.
</ParamField>

<Note>
  Because comments are last-write-wins, the envelope returns `version: null` for comment writes.
</Note>

### `archive_comment`

Archives a comment. The comment body is retained in history.

<ParamField path="id" type="string" required>
  The comment id.
</ParamField>

<ParamField path="agent_name" type="string" required>
  A stable identifier for the calling agent.
</ParamField>

***

## Fields or Comments?

When deciding where to store information, apply this rule:

* **Put it in a field** if a policy must read it, if you will filter on it, or if it represents the task's current state.
* **Put it in a comment** if it is reasoning — why this approach was chosen, what was rejected, what the next session needs to know.

Nothing in Substrate reads prose from comments. Fields are the only surface policies and filters act on.
