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

# Connect a Coding Agent

> Install Erstan in Claude or Codex, authorize workspace access with OAuth, and manage the connection in Erstan.

The official Erstan plugin connects Claude and Codex to the hosted Erstan MCP server. It includes maintained Skills for working with agents, runs, Skills, tasks, projects, documents, and files. Each user signs in through browser-based OAuth and chooses exactly which workspace access to grant.

<Info>
  The plugin contains no API key. Erstan remains the source of truth for permissions, resources, expiry, and revocation. Claude or Codex can require additional confirmation, but the host cannot grant access that Erstan denied.
</Info>

## Install the official plugin

The public plugin repository is [erstanai/erstan-agent-tools](https://github.com/erstanai/erstan-agent-tools). In both command-line hosts, `erstan@erstan` means `plugin-name@marketplace-name`; it is not a secret or an account-specific identifier.

<Tabs>
  <Tab title="Codex CLI">
    <Steps>
      <Step title="Add the Erstan marketplace">
        Run:

        ```text theme={null}
        codex plugin marketplace add erstanai/erstan-agent-tools
        ```
      </Step>

      <Step title="Install Erstan">
        Run:

        ```text theme={null}
        codex plugin add erstan@erstan
        ```
      </Step>

      <Step title="Connect your Erstan account">
        Start a new Codex session, use `/plugins` to confirm that Erstan is installed, and complete browser sign-in when prompted.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Claude Code">
    <Steps>
      <Step title="Add the marketplace and plugin">
        Run these commands in your shell:

        ```text theme={null}
        claude plugin marketplace add erstanai/erstan-agent-tools
        claude plugin install erstan@erstan
        ```

        You can also use `/plugin marketplace add erstanai/erstan-agent-tools` and `/plugin install erstan@erstan` inside Claude Code.
      </Step>

      <Step title="Reload and connect">
        In Claude Code, run `/reload-plugins`, then `/mcp`. Choose `erstan` and complete browser sign-in.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Claude Cowork / Desktop">
    <Steps>
      <Step title="Open the plugin browser">
        Open **Customize → Plugins → Browse plugins**, then choose **Add marketplace**.
      </Step>

      <Step title="Add Erstan">
        Enter `https://github.com/erstanai/erstan-agent-tools`, then install **Erstan**.
      </Step>

      <Step title="Connect your Erstan account">
        Choose the Erstan connection when prompted and complete browser sign-in. Plugins are available in Claude Cowork and Claude Code, not the standard Claude Chat surface.
      </Step>
    </Steps>
  </Tab>
</Tabs>

## Choose access in Erstan

The OAuth consent screen asks you to choose a workspace, an access profile, and a resource boundary. The default **Build** profile supports agent creation and operation without allowing the external host to edit tasks, documents, or files.

| Profile         | Access                                                                                                       |
| --------------- | ------------------------------------------------------------------------------------------------------------ |
| **Review**      | Read-only access to agents, runs, work, documents, and files.                                                |
| **Build**       | Review, build, test, run, and publish agents without editing workspace work or content. This is the default. |
| **Full access** | All connected-app permissions, including task, document, and file changes.                                   |
| **Custom**      | Choose individual permissions and their required dependencies.                                               |

Custom access can use these server-enforced permissions:

| Area               | Read / operate                                 | Change                               |
| ------------------ | ---------------------------------------------- | ------------------------------------ |
| Agents             | **View agents**, **Run agents**, **View runs** | **Build agents**, **Publish agents** |
| Tasks and projects | **View work**                                  | **Manage work**                      |
| Documents          | **View documents**                             | **Edit documents**                   |
| Files              | **View files**                                 | **Edit files**                       |

For resources, choose **All I can access** or **Selected teams and projects**. Erstan always intersects that choice with the connection owner's live workspace access. Later losing access to a team, project, or agent therefore removes it from the connected app as well.

<Warning>
  Read the host's local confirmation prompt as well as the Erstan consent screen. Erstan sets the maximum allowed access; Claude or Codex may narrow it further or ask for confirmation before an action.
</Warning>

## Manage, revoke, and audit access

Open **Settings → Connected apps** in Erstan to review each connection's owner, profile, permissions, resources, last use, expiry, and status.

* Reducing access takes effect immediately.
* Increasing access requires explicit reauthorization in Claude or Codex; an app cannot expand its own grant.
* Revoking a connection invalidates it for every host session using that grant.
* Workspace owners and admins can review all workspace connections and revoke them when required.

For lifecycle evidence, open **Admin → Audit → Connected apps**. The audit records Connected, Reauthorized, Permissions changed, and Disconnected events, including disconnection by the OAuth provider. Use **Admin → Audit → Tools** for individual MCP tool calls and their outcomes.

## What the MCP server is

The plugin connects to Erstan's stateless streamable-HTTP MCP endpoint:

* `POST https://api.erstan.com/v1/mcp` carries JSON-RPC over HTTP. Each request is independent; there are no SSE sessions in v1 (`GET` and `DELETE` return `405`).
* OAuth discovery, authorization, refresh, expiry, and revocation are handled by the host and Erstan.
* `tools/list` returns only tools allowed by the grant. `tools/call` re-checks the grant, the owner's live permissions, and its resource boundary every time.
* Tool calls are rate limited per connection and written to the workspace audit trail.

### Advanced: direct API-key clients

The recommended Claude and Codex setup is the plugin and OAuth flow above. The advanced API-key option remains available for automation and MCP clients that do not support the plugin or OAuth discovery.

Create a key under **Settings → API Keys**, select only the required scopes, and configure its resource allowlists. Task visibility uses `allowedProjectIds` and `allowedTeamIds`; document and file access requires allowed teams. Follow [API keys](/developers/api-keys) for creation, storage, rotation, and revocation. Never commit a key or paste it into a shared plugin configuration.

## Send a task to the external queue

In a task, open the Agent picker and choose **Agent → Advanced → External queue**. This explicit opt-in makes the task available for external MCP pickup; choosing an internal agent keeps execution inside Erstan.

API and MCP callers use the same `externalExecution` field. Pass `externalExecution: true` when creating a top-level task or subtask that should enter the external queue. It defaults to `false`.

Opt-in does not grant access. An OAuth connection needs **View work** to discover tasks and **Manage work** to claim, comment on, or complete them; its resource boundary must include the task's project or team. An API-key client needs `tasks:execute` plus a matching `allowedProjectIds` or `allowedTeamIds` entry. The server rechecks permission, resource access, queue eligibility, and task state on every read, claim, and completion call.

## Tools

`tools/list` shows a tool only when the grant holds every required permission. Advanced API-key clients use the equivalent scopes documented in [API keys](/developers/api-keys).

### Tasks and projects

| Tool                                             | Permission      | What it does                                                                                                                                                                 |
| ------------------------------------------------ | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `get_next_task`                                  | **View work**   | Returns the oldest eligible externally opted-in task, or `{ "task": null }`.                                                                                                 |
| `read_task`                                      | **View work**   | Reads the complete Task graph: properties, parent/subtasks, labels, participants, attachments/references, activity, threads, linked runs, and approvals.                     |
| `start_task`                                     | **Manage work** | Atomically claims an eligible queued task. If it changed or another caller won, returns `task_already_claimed`.                                                              |
| `complete_task`                                  | **Manage work** | Reports `needs_review`, `failed`, or `completed`, with a required summary and optional `prLink`.                                                                             |
| `comment_on_task`                                | **Manage work** | Posts an inert task comment with optional inline file attachments; it cannot resume runs, resolve approvals, or trigger agent mentions.                                      |
| `list_tasks`                                     | **View work**   | Lists authorized task summaries with status, project, team, task-key, and external-only filters.                                                                             |
| `list_task_options`                              | **View work**   | Lists the teams, projects, Task-eligible Agents, assignable members/labels, and valid parent Tasks that can be selected on an authorized Task.                               |
| `read_project`                                   | **View work**   | Reads project details and task counts within the connection's visibility.                                                                                                    |
| `list_projects`                                  | **View work**   | Lists visible projects and task counts.                                                                                                                                      |
| `create_task`                                    | **Manage work** | Creates a task or subtask in an authorized team or project.                                                                                                                  |
| `update_task`                                    | **Manage work** | Updates Task properties, hierarchy/order, project, Agent, assignee/reviewer, labels, status, priority, schedule, metadata, completion policy, and external-execution opt-in. |
| `update_task_comment` / `delete_task_comment`    | **Manage work** | Edits a comment inertly or soft-deletes it. An API edit never routes a new Agent mention.                                                                                    |
| `add_task_attachment` / `remove_task_attachment` | **Manage work** | Adds an upload, Team-file reference, document reference, or HTTP(S) URL, or removes only the Task relationship. Inbox attachments are excluded.                              |
| `add_task_participant`                           | **Manage work** | Adds/reactivates a valid user or Agent participant; assignee/reviewer roles update those Task fields.                                                                        |
| `add_task_reaction` / `remove_task_reaction`     | **Manage work** | Changes the authenticated user's reaction on the Task description or an activity.                                                                                            |
| `get_task_lifecycle_impact`                      | **View work**   | Previews descendant Tasks, active work, run/approval history, threads, activity, and attachments affected by archive/delete.                                                 |
| `cancel_task` / `archive_task` / `restore_task`  | **Manage work** | Applies the canonical Task and active-run lifecycle transitions. Archive includes descendants.                                                                               |
| `delete_task`                                    | **Manage work** | Soft-deletes the Task and descendants while retaining audit/run integrity; exact-title confirmation is required.                                                             |
| `get_task_run` / `get_task_run_trace`            | **View work**   | Reads a run or redacted trace through an exact visible Task→execution→thread relationship, without a separate **View runs** grant.                                           |
| `reply_to_task_run` / `decide_task_run_approval` | **Manage work** | Replies to a Task-linked user-input wait or decides its exact pending approval, without a separate **Run agents** grant.                                                     |

Creating a task does not send it to the external queue by default. Set `externalExecution: true` explicitly when the new task should flow through `get_next_task`.

Use `list_task_options` before setting relationship IDs. Pass `taskId` when editing an existing Task, or `projectId`/`teamId` while constructing a new one. By default it returns all six picker domains; `include` can select `teams`, `projects`, `agents`, `members`, `labels`, and/or `parent_tasks`. `search` and `limit` keep large workspaces bounded. Agent results use the same published-version, task-ingress, marketplace-readiness, team-sharing, and current-user readability rules as the Task editor. Members are restricted to people assignable in the target team. Parent candidates are accessible, non-terminal Tasks in the correct scope; for an existing Task, Erstan excludes the Task and all descendants so the list cannot advertise a cycle. A project-only connection can anchor options through its `projectId` or an existing visible `taskId`; that does not silently grant team-wide Task creation.

`list_agents` remains the general runnable-Agent catalog under **View agents**. `list_task_options` is the Task-specific relation catalog under **View work**, so resolving a valid `workflowId` for `update_task` does not require a second Agent permission.

`read_task` returns the Task's scalar properties and stable relationship IDs, including `parentTaskId`, ordered `children`, `primaryThreadId`, `currentExecutionId`, `threadReferences`, recent `runs`, and `pendingApprovals`. Each run reference carries its `runId`/execution ID plus `threadId` and `checkpointThreadId`. Use those exact IDs with the Task-run tools; never guess a run or thread ID.

`update_task` validates subtask moves end to end. A parent must be an accessible, non-terminal Task in the same workspace/team, and the move must not create a cycle. When `parentTaskId` changes without an explicit `sortOrder`, Erstan appends the Task to the new parent's ordered children. Archive and cancellation use their dedicated lifecycle tools so active runs and descendant Tasks are handled correctly.

Parent/child links do not widen the connection's project/team resource boundary. `read_task` expands only allowlisted parent/child detail, and an archive/delete cascade fails closed unless every affected descendant remains inside that boundary.

#### Comment on a task with attachments

`attachments` is a top-level `comment_on_task` argument alongside `taskId`, optional `body`, and optional `teamId`. Each attachment needs `name`, `type`, and base64-encoded content. `body` is optional when at least one attachment is present; Erstan generates a short comment such as `Attached evidence.txt` when it is omitted.

An Erstan server cannot read a local filesystem path. The local client must read the file, encode its bytes, and supply them in the tool call:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "comment_on_task",
    "arguments": {
      "taskId": "task_abc123",
      "body": "Review the attached evidence.",
      "attachments": [
        {
          "name": "evidence.txt",
          "type": "text/plain",
          "base64": "aW52b2ljZSA0Mg=="
        }
      ]
    }
  }
}
```

Files are stored in the Task's team and linked to the new comment in one tool workflow. For a Team-less Task, Erstan uses an allowlisted workflow default team when available; otherwise pass an allowlisted `teamId`. When the Task already has a team, any supplied `teamId` must match it. A call can include up to 10 files, subject to the workspace upload limits, and the complete MCP JSON request is limited to 25 MB, including base64 expansion.

**Manage work** authorizes the task-scoped upload; callers do not also need **Edit files**. `read_task` returns each attachment's `teamFileId` and its comment `activityId`. When `fileReadable` is true, a caller that also has **View files** can pass the `teamFileId` to `read_file` to retrieve the bytes.

For a top-level Task attachment/reference, use `add_task_attachment` with one of:

* `kind: "upload"` plus `name`, `type`, and `base64`;
* `kind: "team_file"` plus `teamFileId`;
* `kind: "document"` plus `documentId`; or
* `kind: "external_url"` plus an HTTP(S) `url`.

`remove_task_attachment` removes only the TaskAttachment link. It never deletes the underlying Team file or document. Inbox attachment references are intentionally not available on this public surface.

#### Task-linked Agent runs and approvals

There are two deliberate run access paths:

* General run tools (`get_run`, `get_run_trace`, `reply_to_run`, `decide_run_approval`) remain bound to the exact OAuth grant or API key that started the run and use **View runs** / **Run agents**.
* Task-run tools first authorize the Task through **View work** / **Manage work**, then require the exact persisted Task→execution→thread relationship. They do not require a second Runs or Run agents permission. `decide_task_run_approval` records the authenticated Task collaborator as the resolver and atomically fences the current `interactionId`, approval, execution lease, thread interrupt, and resume job.

Reading and tracing remain available for historical/archived Tasks. Reply and approval mutations require an actionable, non-archived Task status. A stale `interactionId`, mismatched Task/run/thread relationship, or already-accepted decision fails closed; re-read with `get_task_run` before deciding what to do next.

### Documents and files

| Tool                                 | Permission         | What it does                                                                                |
| ------------------------------------ | ------------------ | ------------------------------------------------------------------------------------------- |
| `read_document`                      | **View documents** | Reads a document's current agent-readable content, sections, metadata, and `publishStatus`. |
| `search_documents`                   | **View documents** | Searches draft and published documents within authorized teams.                             |
| `list_folders`                       | **View documents** | Lists document folders and document counts within authorized teams.                         |
| `create_document`                    | **Edit documents** | Creates a document in an authorized team and optional folder.                               |
| `append_section` / `replace_section` | **Edit documents** | Edits sections of draft or published documents.                                             |
| `list_files`                         | **View files**     | Lists files within authorized teams and optional folders.                                   |
| `read_file`                          | **View files**     | Reads text inline up to 1 MB or returns binary content as base64 up to 25 MB.               |
| `write_file`                         | **Edit files**     | Creates or updates a versioned file.                                                        |

Documents use a draft-and-publish lifecycle. `read_document` and `search_documents` expose `publishStatus`; draft and published documents are both valid context. Archived documents appear only where a tool explicitly includes historical content.

### Agents and runs

| Tool                  | Permission      | What it does                                                                                                                        |
| --------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `list_agents`         | **View agents** | Lists agents available to the connection owner.                                                                                     |
| `run_agent`           | **Run agents**  | Starts an asynchronous published-agent run and accepts optional top-level attachments.                                              |
| `get_run`             | **View runs**   | Reads status, result, and any structured `pendingInteraction`.                                                                      |
| `continue_run`        | **Run agents**  | Sends a follow-up conversation turn to a **completed** chat-lane run — the same runId continues with its full conversation context. |
| `reply_to_run`        | **Run agents**  | Answers an actionable waiting interaction using its exact `pendingInteraction.interactionId`.                                       |
| `decide_run_approval` | **Run agents**  | Approves or rejects the exact pending approval.                                                                                     |
| `get_run_trace`       | **View runs**   | Pages through persisted, redacted trace events using the execution-bound `nextCursor`.                                              |

General run handles are bound to the exact OAuth grant or API key that started them. Another connection in the same workspace cannot use the general run tools for that run. The Task-linked tools described above are the explicit exception: they derive access from the visible Task and exact persisted relationship. Reply and approval claims are single-use. If a delayed caller addresses an older interaction, Erstan returns `run_interaction_changed`; call `get_run` or `get_task_run` again and use the new interaction. Live token deltas are not persisted; complete messages replay from `conversation_item`.

#### Multi-turn conversations

A run belongs to one conversation thread. Which tool advances it depends on the run status from `get_run`:

* Terminal (`completed`, `failed`, `cancelled`) → `continue_run` sends the next user message (optionally with attachments). Always poll `get_run` with the runId **returned by the call**: a completed plain chat run usually continues under the same runId, while other cases fork a new runId on the same thread (see below). Retries are safe with `idempotencyKey` — the same key rejoins the same turn.
* `waiting` with a `pendingInteraction` of type `user_input` → `reply_to_run` with the exact `interactionId`.
* `waiting` with a `pendingInteraction` of type `approval` → `decide_run_approval` with the exact `interactionId`.
* `running` → wait and poll `get_run`; a concurrent turn returns `run_still_active`.

How the follow-up executes mirrors the Erstan chat UI exactly:

* **Same-run continuation** — a `completed` chat-lane run of an interactive agent re-queues the same execution with full conversation context.
* **Post-run continuation (new runId)** — agents that use post-run continuation (non-interactive agents, and graphs with dedicated human-input nodes such as `user-approval`, `ai-questions`, or `ai-wait-user-input`) fork the one-node conversational shell, pinned to the source run's version and carrying the source run's tool and Skill capability envelope. This is how you ask follow-up questions about a completed structured (input-form) run, too — the shell converses about the run; it does not re-execute the authored graph.
* **Thread fork (new runId)** — a chat run that ended `failed` or `cancelled` continues the conversation on a fresh execution with the prior thread history.

Builder Preview (`test_agent`) runs are single-turn, and structured runs of interactive agents return `run_not_continuable` — start a new `run_agent` run for those.

#### Run an agent with attachments

`attachments` is a top-level `run_agent` argument alongside `agentId`, `input`, `laneId`, and `idempotencyKey`. Do not nest attachments inside `input`. Each attachment needs `name`, `type`, and either base64-encoded file content or an existing Erstan attachment `storageKey`.

An Erstan server cannot read a local filesystem path. The local client must read the file, encode its bytes, and supply them in the tool call:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "run_agent",
    "arguments": {
      "agentId": "agent_abc123",
      "input": { "message": "Process the attached supplier order." },
      "attachments": [
        {
          "name": "supplier-order.xlsx",
          "type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          "base64": "UEsDBBQAAAAI..."
        }
      ]
    }
  }
}
```

The complete MCP JSON request is limited to 25 MB, including base64 expansion. Use `list_agents` first to confirm the lane supports attachments.

### Agent and Skill authoring

| Tool                                        | Permission                        | What it does                                                                               |
| ------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------ |
| `get_agent_node_catalog`                    | **View agents**                   | Returns the live Agent Builder node catalog.                                               |
| `get_agent_builder_guide`                   | **View agents**                   | Returns graph-construction and validation guidance.                                        |
| `list_agent_tools` / `list_agent_skills`    | **View agents**                   | Lists tools and Skills that can be pinned to supported nodes.                              |
| `validate_agent_skill`                      | **Build agents**                  | Validates and normalizes a complete Skill package without saving it.                       |
| `create_agent_skill` / `update_agent_skill` | **Build agents**                  | Creates or updates a version-guarded Skill draft.                                          |
| `get_agent_skill`                           | **View agents**                   | Reads a complete workspace Skill package and its current version.                          |
| `publish_agent_skill`                       | **Publish agents**                | Re-validates and explicitly publishes the current Skill version.                           |
| `get_agent`                                 | **View agents**                   | Reads an agent's authoring state, graph, draft status, version, revision, and builder URL. |
| `create_agent`                              | **Build agents**                  | Creates a draft agent in an accessible team.                                               |
| `update_agent`                              | **Build agents**                  | Updates the complete editable draft using its latest opaque revision.                      |
| `validate_agent`                            | **Build agents**                  | Validates a draft and returns structured diagnostics without publishing.                   |
| `test_agent`                                | **Build agents** + **Run agents** | Runs the guarded current draft in Builder Preview with normal approval policies.           |
| `publish_agent`                             | **Publish agents**                | Re-validates and publishes the exact current manageable revision.                          |

See [Build agents over MCP](/developers/build-agents) for the complete revision, validation, testing, and publication contract.

## Included skills

The official plugin keeps its operating guidance versioned with the plugin instead of asking users to paste instructions into each project:

* `erstan-agent-builder` — create, revise, validate, test, and publish Agent graphs.
* `erstan-agent-review` — review definitions and diagnose runs from durable evidence.
* `erstan-run-operator` — launch published Agents and handle waits, approvals, and traces.
* `erstan-skill-manager` — manage complete, versioned Erstan Skill packages.
* `erstan-work-manager` — work with authorized tasks, projects, documents, folders, and files.

<Warning>
  The Erstan MCP server remains the enforcement boundary: it checks the OAuth grant or API-key scope, resource authorization, external-queue opt-in, task eligibility, atomic claims, and allowed state transitions on every call. A Skill or prompt cannot grant access or bypass those checks.
</Warning>

## Common error codes

| Code                                       | Meaning                                                                                                                                                                            |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `access_not_configured`                    | The connection has no selected resources covering the request, or an API key has no required project/team allowlist. Update **Settings → Connected apps** or the advanced API key. |
| `task_already_claimed`                     | The task changed eligibility or another caller claimed it first. Fetch the next task.                                                                                              |
| `task_not_eligible`                        | The task is no longer an active, authorized external task. Re-read the queue.                                                                                                      |
| `team_or_project_required`                 | A top-level task named neither a team nor a project.                                                                                                                               |
| `task_parent_terminal`                     | A subtask targeted a completed, cancelled, or archived parent.                                                                                                                     |
| `project_not_allowed` / `team_not_allowed` | The requested resource is outside the connection's boundary.                                                                                                                       |
| `folder_not_found` / `file_not_found`      | The resource does not exist or is outside the connection's visible teams.                                                                                                          |
| `file_too_large`                           | File content exceeded the supported inline or upload limit.                                                                                                                        |
| `forbidden`                                | The connection lacks the required permission or resource access.                                                                                                                   |
| `rate_limited`                             | The connection exceeded its request budget. Retry after the indicated delay.                                                                                                       |

## Next steps

<CardGroup cols={2}>
  <Card title="Erstan Agent Tools" icon="package" href="https://github.com/erstanai/erstan-agent-tools">
    Review the public plugin, Skills, manifests, and release notes.
  </Card>

  <Card title="Working with tasks" icon="list-checks" href="/tasks/working-with-tasks">
    Learn how tasks, external queues, and review work.
  </Card>

  <Card title="Build agents over MCP" icon="workflow" href="/developers/build-agents">
    Create, inspect, update, validate, test, and publish agent drafts.
  </Card>

  <Card title="API keys" icon="key-round" href="/developers/api-keys">
    Configure advanced non-OAuth automation clients.
  </Card>
</CardGroup>
