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

# Agents and packages

> Shared agent packages, installs, the marketplace and paired devices.

33 tools. Each one is also a REST route and a CLI command, from the same definition: the same input, the same output, the same errors.

| Tool                                                | What it does                                | Kind                                                  |
| --------------------------------------------------- | ------------------------------------------- | ----------------------------------------------------- |
| [`discover_packages`](#discover_packages)           | Search the reviewed catalogue               | Read · idempotent · no outside service                |
| [`get_install_files`](#get_install_files)           | Read the files of an install                | Read · idempotent · no outside service                |
| [`get_run_state`](#get_run_state)                   | Get a run's state                           | Read · idempotent · no outside service                |
| [`get_submission_status`](#get_submission_status)   | Where your submission stands                | Read · idempotent · no outside service                |
| [`list_categories`](#list_categories)               | The catalogue's categories                  | Read · idempotent · no outside service                |
| [`list_device_calls`](#list_device_calls)           | Pull queued calls for this Mac              | Read · idempotent · no outside service                |
| [`list_devices`](#list_devices)                     | List paired Macs                            | Read · idempotent · no outside service                |
| [`list_installs`](#list_installs)                   | What you have installed                     | Read · idempotent · no outside service                |
| [`list_package_grants`](#list_package_grants)       | Who you sent a package to                   | Read · idempotent · no outside service                |
| [`list_packages`](#list_packages)                   | List what you have published                | Read · idempotent · no outside service                |
| [`list_shared_with_me`](#list_shared_with_me)       | Packages sent to you                        | Read · idempotent · no outside service                |
| [`preview_install_update`](#preview_install_update) | What an update would bring                  | Read · idempotent · no outside service                |
| [`preview_listing`](#preview_listing)               | Read a catalogue entry before installing it | Read · idempotent · no outside service                |
| [`preview_package`](#preview_package)               | Read a package before installing it         | Read · idempotent · no outside service                |
| [`apply_install_update`](#apply_install_update)     | Move an install to the latest version       | Write · idempotent · no outside service               |
| [`approve_run`](#approve_run)                       | Approve a run waiting on the Mac            | Write · no outside service                            |
| [`delegate_task`](#delegate_task)                   | Queue a task for an agent on a paired Mac   | Write · no outside service                            |
| [`detach_install`](#detach_install)                 | Keep it, without the link                   | Write · destructive · no outside service              |
| [`grant_package_access`](#grant_package_access)     | Send a package to someone                   | Write · no outside service                            |
| [`install_package`](#install_package)               | Install a package from its address          | Write · idempotent · no outside service               |
| [`publish_package`](#publish_package)               | Publish a package, or a new version of one  | Write · no outside service                            |
| [`record_package_view`](#record_package_view)       | Record that a catalogue entry was opened    | Write · idempotent · no outside service               |
| [`register_device`](#register_device)               | Register this desktop on the account        | Write · no outside service                            |
| [`reject_run`](#reject_run)                         | Reject a run waiting on the Mac             | Write · no outside service                            |
| [`reply_to_run`](#reply_to_run)                     | Send a message into a run on the Mac        | Write · no outside service                            |
| [`report_package`](#report_package)                 | Report a package to the safety queue        | Write · idempotent · no outside service               |
| [`report_run_state`](#report_run_state)             | The Mac publishes a run step                | Write · no outside service                            |
| [`revoke_device`](#revoke_device)                   | Revoke a paired device                      | Write · no outside service                            |
| [`revoke_package_grant`](#revoke_package_grant)     | Take a send back                            | Write · destructive · idempotent · no outside service |
| [`submit_for_review`](#submit_for_review)           | Offer a version for Discover                | Write · no outside service                            |
| [`uninstall_package`](#uninstall_package)           | Uninstall                                   | Write · destructive · idempotent · no outside service |
| [`unpublish_package`](#unpublish_package)           | Take a package down                         | Write · destructive · idempotent · no outside service |
| [`withdraw_listing`](#withdraw_listing)             | Take your Agent out of Discover             | Write · destructive · no outside service              |

## discover\_packages

**Search the reviewed catalogue.**

Approved Agents somebody else published, most curated first. Matches the approved name, summary, publisher handle and declared integrations. Several categories **widen** the result (OR); text and categories **narrow** each other (AND).

Never returns what you own, what you already installed, a version no reviewer approved, or anything suspended. Writes nothing.

|           |                                                                                                                                                                                                       |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                                                                                                                                                |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                                                                       |
| REST      | `GET https://api.doers.sh/v2/marketplace/discover`                                                                                                                                                    |
| CLI       | `doers marketplace discover-packages`                                                                                                                                                                 |
| Touches   | `categories`, `installs`, `listingCategories`, `listings`, `packageReports`, `packageVersions`, `packageViews`, `publishers`, `reviews`, `safetyRestrictions`, `sharedPackages`, `versionPermissions` |
| Operation | `discoverPackages`                                                                                                                                                                                    |

### Input

| Field                | Type      | Required | Default | Allowed values      | Description                                                               |
| -------------------- | --------- | -------- | ------- | ------------------- | ------------------------------------------------------------------------- |
| `query` (query)      | string    | no       |         | 0 to 200 characters | Free text over name, summary, publisher handle and declared integrations. |
| `categories` (query) | string\[] | no       |         | at most 9 items     | Category slugs. Several widen the result rather than narrowing it.        |
| `limit` (query)      | integer   | no       | `24`    | 1 to 48             | How many to return. The app asks for one page at a time.                  |
| `cursor` (query)     | string    | no       |         | 0 to 512 characters | From a previous page's `nextCursor`. Opaque: do not construct one.        |

### Output

<Accordion title="Output fields">
  | Field                              | Type           | Allowed values                        | Description                                                                                                                                                                                                              |
  | ---------------------------------- | -------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
  | `listings`                         | object\[]      |                                       |                                                                                                                                                                                                                          |
  | `listings[].packageId`             | string         |                                       |                                                                                                                                                                                                                          |
  | `listings[].kind`                  | string         | `agent`, `note`, `folder`             | An agent and its notes, a note on its own, or a folder of them.                                                                                                                                                          |
  | `listings[].name`                  | string         |                                       |                                                                                                                                                                                                                          |
  | `listings[].emoji`                 | string \| null |                                       |                                                                                                                                                                                                                          |
  | `listings[].summary`               | string         |                                       |                                                                                                                                                                                                                          |
  | `listings[].version`               | integer        | -9007199254740991 to 9007199254740991 |                                                                                                                                                                                                                          |
  | `listings[].publisher`             | object         |                                       |                                                                                                                                                                                                                          |
  | `listings[].publisher.id`          | string         |                                       |                                                                                                                                                                                                                          |
  | `listings[].publisher.kind`        | string         | `personal`, `official`                |                                                                                                                                                                                                                          |
  | `listings[].publisher.handle`      | string         |                                       |                                                                                                                                                                                                                          |
  | `listings[].publisher.displayName` | string         |                                       |                                                                                                                                                                                                                          |
  | `listings[].categories`            | object\[]      |                                       |                                                                                                                                                                                                                          |
  | `listings[].categories[].id`       | string         |                                       |                                                                                                                                                                                                                          |
  | `listings[].categories[].slug`     | string         |                                       |                                                                                                                                                                                                                          |
  | `listings[].categories[].label`    | string         |                                       |                                                                                                                                                                                                                          |
  | `listings[].categories[].position` | integer        | -9007199254740991 to 9007199254740991 |                                                                                                                                                                                                                          |
  | `listings[].licence`               | string \| null | `mit`, `cc-by-4.0`                    |                                                                                                                                                                                                                          |
  | `listings[].integrations`          | string\[]      |                                       | What the approved version declares it reaches.                                                                                                                                                                           |
  | `listings[].installers`            | integer        | -9007199254740991 to 9007199254740991 | Accounts that installed it, counted once each. See `since`.                                                                                                                                                              |
  | `listings[].since`                 | number \| null |                                       | When installer counting began, or `null` when nobody has installed it yet. Never a guess: earlier installs are not in the count, and inventing a start date would present an incomplete observation as a lifetime total. |
  | `listings[].approvedAt`            | number         |                                       | Epoch milliseconds.                                                                                                                                                                                                      |
  | `total`                            | integer        | -9007199254740991 to 9007199254740991 | Matches before `limit` is applied.                                                                                                                                                                                       |
  | `nextCursor`                       | string \| null |                                       | Opaque cursor for the next page, or null.                                                                                                                                                                                |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "discover_packages",
      "arguments": {
        "query": "Acme",
        "limit": 24
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- Acme by ada v3"
        }
      ],
      "structuredContent": {
        "listings": [
          {
            "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
            "kind": "agent",
            "name": "Acme",
            "emoji": "rocket",
            "summary": "Notes for the Acme launch.",
            "version": 3,
            "publisher": {
              "id": "4f03a060-b7eb-4329-82dc-b327f2c989b1",
              "kind": "personal",
              "handle": "ada",
              "displayName": "Acme"
            },
            "categories": [
              {
                "id": "edb2cd3b-74c9-49af-80f0-b7054990f207",
                "slug": "acme",
                "label": "Acme",
                "position": 3
              }
            ],
            "licence": "mit",
            "integrations": ["Notes for the Acme launch."],
            "installers": 3,
            "since": 3,
            "approvedAt": 1790069400000
          }
        ],
        "total": 3,
        "nextCursor": "Notes for the Acme launch."
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers marketplace discover-packages --query Acme --limit 24
  ```
</CodeGroup>

## get\_install\_files

**Read the files of an install.**

The contents of the exact version installed, file by file. Separate from the install list so that listing what someone has does not ship every file body they hold. Answers 404 for an install belonging to another account. Writes nothing and installs nothing.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                                                                                                        |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `GET https://api.doers.sh/v2/installs/{installId}/files`                                                                                                      |
| CLI       | `doers installs get-install-files`                                                                                                                            |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `getInstallFiles`                                                                                                                                             |

### Input

| Field              | Type   | Required | Default | Allowed values | Description                               |
| ------------------ | ------ | -------- | ------- | -------------- | ----------------------------------------- |
| `installId` (path) | string | yes      |         | UUID           | The install to read, from `listInstalls`. |

### Output

<Accordion title="Output fields">
  | Field             | Type      | Allowed values | Description |
  | ----------------- | --------- | -------------- | ----------- |
  | `files`           | object\[] |                |             |
  | `files[].path`    | string    |                |             |
  | `files[].content` | string    |                |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_install_files",
      "arguments": {
        "installId": "1e142e62-77b1-4b7e-8110-478a24caee8f"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "1 file(s)."
        }
      ],
      "structuredContent": {
        "files": [
          {
            "path": "Acme/Weekly review",
            "content": "Notes for the Acme launch."
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs get-install-files --install-id 1e142e62-77b1-4b7e-8110-478a24caee8f
  ```
</CodeGroup>

## get\_run\_state

**Get a run's state.**

When the Mac has never pulled, `message` is "will start when your Mac is online".

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/runs/{runId}`                                      |
| CLI       | `doers devices get-run-state`                                                   |
| Touches   | `deviceCalls`, `devices`, `tasks`                                               |
| Operation | `getRunState`                                                                   |

### Input

| Field          | Type   | Required | Default | Allowed values | Description          |
| -------------- | ------ | -------- | ------- | -------------- | -------------------- |
| `runId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field                | Type           | Allowed values                                                         | Description         |
  | -------------------- | -------------- | ---------------------------------------------------------------------- | ------------------- |
  | `call`               | object         |                                                                        |                     |
  | `call.id`            | string         |                                                                        |                     |
  | `call.deviceId`      | string         |                                                                        |                     |
  | `call.operation`     | string         | `delegateTask`, `approveRun`, `rejectRun`, `replyToRun`, `getRunState` |                     |
  | `call.state`         | string         | `queued`, `running`, `needs-approval`, `done`, `failed`                |                     |
  | `call.waitingForMac` | boolean        |                                                                        |                     |
  | `call.message`       | string \| null |                                                                        |                     |
  | `call.createdAt`     | number         |                                                                        | Epoch milliseconds. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_run_state",
      "arguments": {
        "runId": "acba2551-2100-480b-86fc-3ccd14c65be5"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "State: queued."
        }
      ],
      "structuredContent": {
        "call": {
          "id": "7edb360f-06ac-4ef2-8c80-dba16cf563f1",
          "deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
          "operation": "delegateTask",
          "state": "queued",
          "waitingForMac": true,
          "message": "Notes for the Acme launch.",
          "createdAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers devices get-run-state --run-id acba2551-2100-480b-86fc-3ccd14c65be5
  ```
</CodeGroup>

## get\_submission\_status

**Where your submission stands.**

The decision on your latest submission and, when it was rejected, the reason given. Also says which version Discover is serving, which is not always the one under review.

|           |                                                                                                                                                                                                       |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                                                                                                                                                |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                                                                       |
| REST      | `GET https://api.doers.sh/v2/marketplace/submissions/{packageId}`                                                                                                                                     |
| CLI       | `doers marketplace get-submission-status`                                                                                                                                                             |
| Touches   | `categories`, `installs`, `listingCategories`, `listings`, `packageReports`, `packageVersions`, `packageViews`, `publishers`, `reviews`, `safetyRestrictions`, `sharedPackages`, `versionPermissions` |
| Operation | `getSubmissionStatus`                                                                                                                                                                                 |

### Input

| Field              | Type   | Required | Default | Allowed values | Description          |
| ------------------ | ------ | -------- | ------- | -------------- | -------------------- |
| `packageId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field                      | Type            | Allowed values                            | Description                                        |
  | -------------------------- | --------------- | ----------------------------------------- | -------------------------------------------------- |
  | `submission`               | object          |                                           |                                                    |
  | `submission.packageId`     | string          |                                           |                                                    |
  | `submission.version`       | integer         | -9007199254740991 to 9007199254740991     |                                                    |
  | `submission.state`         | string          | `none`, `pending`, `approved`, `rejected` | `none` when this package has never been submitted. |
  | `submission.reason`        | string \| null  |                                           | Why it was rejected. Null unless it was.           |
  | `submission.licence`       | string \| null  | `mit`, `cc-by-4.0`                        |                                                    |
  | `submission.submittedAt`   | number \| null  |                                           |                                                    |
  | `submission.decidedAt`     | number \| null  |                                           |                                                    |
  | `submission.listedVersion` | integer \| null | -9007199254740991 to 9007199254740991     |                                                    |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_submission_status",
      "arguments": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "none (v3)."
        }
      ],
      "structuredContent": {
        "submission": {
          "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
          "version": 3,
          "state": "none",
          "reason": "Notes for the Acme launch.",
          "licence": "mit",
          "submittedAt": 1790069400000,
          "decidedAt": 1790069400000,
          "listedVersion": 3
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers marketplace get-submission-status --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e
  ```
</CodeGroup>

## list\_categories

**The catalogue's categories.**

The categories an Agent can be listed under, in the order they are shown. A retired category is not returned, while a listing that still names one keeps its historical label. Writes nothing.

|           |                                                                                                                                                                                                       |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                                                                                                                                                |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                                                                       |
| REST      | `GET https://api.doers.sh/v2/marketplace/categories`                                                                                                                                                  |
| CLI       | `doers marketplace list-categories`                                                                                                                                                                   |
| Touches   | `categories`, `installs`, `listingCategories`, `listings`, `packageReports`, `packageVersions`, `packageViews`, `publishers`, `reviews`, `safetyRestrictions`, `sharedPackages`, `versionPermissions` |
| Operation | `listCategories`                                                                                                                                                                                      |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                   | Type      | Allowed values                        | Description |
  | ----------------------- | --------- | ------------------------------------- | ----------- |
  | `categories`            | object\[] |                                       |             |
  | `categories[].id`       | string    |                                       |             |
  | `categories[].slug`     | string    |                                       |             |
  | `categories[].label`    | string    |                                       |             |
  | `categories[].position` | integer   | -9007199254740991 to 9007199254740991 |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_categories",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "Acme"
        }
      ],
      "structuredContent": {
        "categories": [
          {
            "id": "edb2cd3b-74c9-49af-80f0-b7054990f207",
            "slug": "acme",
            "label": "Acme",
            "position": 3
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers marketplace list-categories
  ```
</CodeGroup>

## list\_device\_calls

**Pull queued calls for this Mac.**

The desktop half of the relay. Marks the device seen so new delegations are not "will start when your Mac is online". Revoked devices get an empty list.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/devices/{deviceId}/calls`                          |
| CLI       | `doers devices list-device-calls`                                               |
| Touches   | `deviceCalls`, `devices`, `tasks`                                               |
| Operation | `listDeviceCalls`                                                               |

### Input

| Field             | Type   | Required | Default | Allowed values | Description          |
| ----------------- | ------ | -------- | ------- | -------------- | -------------------- |
| `deviceId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field                   | Type           | Allowed values                                                         | Description         |
  | ----------------------- | -------------- | ---------------------------------------------------------------------- | ------------------- |
  | `calls`                 | object\[]      |                                                                        |                     |
  | `calls[].id`            | string         |                                                                        |                     |
  | `calls[].deviceId`      | string         |                                                                        |                     |
  | `calls[].operation`     | string         | `delegateTask`, `approveRun`, `rejectRun`, `replyToRun`, `getRunState` |                     |
  | `calls[].state`         | string         | `queued`, `running`, `needs-approval`, `done`, `failed`                |                     |
  | `calls[].waitingForMac` | boolean        |                                                                        |                     |
  | `calls[].message`       | string \| null |                                                                        |                     |
  | `calls[].createdAt`     | number         |                                                                        | Epoch milliseconds. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_device_calls",
      "arguments": {
        "deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "1 call(s)."
        }
      ],
      "structuredContent": {
        "calls": [
          {
            "id": "7edb360f-06ac-4ef2-8c80-dba16cf563f1",
            "deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
            "operation": "delegateTask",
            "state": "queued",
            "waitingForMac": true,
            "message": "Notes for the Acme launch.",
            "createdAt": 1790069400000
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers devices list-device-calls --device-id 263a4dbe-4148-4fb8-8214-b0032339dbb9
  ```
</CodeGroup>

## list\_devices

**List paired Macs.**

Paired desktops on this account, including revoked ones so Settings can show them.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/devices`                                           |
| CLI       | `doers devices list`                                                            |
| Touches   | `deviceCalls`, `devices`, `tasks`                                               |
| Operation | `listDevices`                                                                   |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                  | Type           | Allowed values | Description |
  | ---------------------- | -------------- | -------------- | ----------- |
  | `devices`              | object\[]      |                |             |
  | `devices[].id`         | string         |                |             |
  | `devices[].name`       | string         |                |             |
  | `devices[].kind`       | string         | `"desktop"`    |             |
  | `devices[].lastSeenAt` | number \| null |                |             |
  | `devices[].revokedAt`  | number \| null |                |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_devices",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- Acme"
        }
      ],
      "structuredContent": {
        "devices": [
          {
            "id": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
            "name": "Acme",
            "kind": "desktop",
            "lastSeenAt": 1790069400000,
            "revokedAt": 1790069400000
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers devices list
  ```
</CodeGroup>

## list\_installs

**What you have installed.**

Each install with the version you are on, and whether a newer one exists. A package its author took down still appears: what you installed is yours. File contents are not included: read one install's files with `getInstallFiles`.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                                                                                                        |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `GET https://api.doers.sh/v2/installs`                                                                                                                        |
| CLI       | `doers installs list`                                                                                                                                         |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `listInstalls`                                                                                                                                                |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                              | Type            | Allowed values                        | Description                                                      |
  | ---------------------------------- | --------------- | ------------------------------------- | ---------------------------------------------------------------- |
  | `installs`                         | object\[]       |                                       |                                                                  |
  | `installs[].id`                    | string          |                                       |                                                                  |
  | `installs[].packageId`             | string          |                                       |                                                                  |
  | `installs[].kind`                  | string          | `agent`, `note`, `folder`             | An agent and its notes, a note on its own, or a folder of them.  |
  | `installs[].slug`                  | string          |                                       |                                                                  |
  | `installs[].name`                  | string          |                                       |                                                                  |
  | `installs[].emoji`                 | string \| null  |                                       |                                                                  |
  | `installs[].summary`               | string          |                                       |                                                                  |
  | `installs[].version`               | integer         | -9007199254740991 to 9007199254740991 |                                                                  |
  | `installs[].latestVersion`         | integer \| null | -9007199254740991 to 9007199254740991 | `null` once the author has taken it down.                        |
  | `installs[].updateAvailable`       | boolean         |                                       |                                                                  |
  | `installs[].publisher`             | object          |                                       |                                                                  |
  | `installs[].publisher.id`          | string          |                                       |                                                                  |
  | `installs[].publisher.kind`        | string          | `personal`, `official`                |                                                                  |
  | `installs[].publisher.handle`      | string          |                                       |                                                                  |
  | `installs[].publisher.displayName` | string          |                                       |                                                                  |
  | `installs[].installedAt`           | number          |                                       | Epoch milliseconds.                                              |
  | `installs[].revoked`               | boolean         |                                       | The author took the package down. What is installed still works. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_installs",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- [1e142e62-77b1-4b7e-8110-478a24caee8f] Acme v3 ↑"
        }
      ],
      "structuredContent": {
        "installs": [
          {
            "id": "1e142e62-77b1-4b7e-8110-478a24caee8f",
            "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
            "kind": "agent",
            "slug": "acme",
            "name": "Acme",
            "emoji": "rocket",
            "summary": "Notes for the Acme launch.",
            "version": 3,
            "latestVersion": 3,
            "updateAvailable": true,
            "publisher": {
              "id": "4f03a060-b7eb-4329-82dc-b327f2c989b1",
              "kind": "personal",
              "handle": "ada",
              "displayName": "Acme"
            },
            "installedAt": 1790069400000,
            "revoked": true
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs list
  ```
</CodeGroup>

## list\_package\_grants

**Who you sent a package to.**

Everyone named on this package, and whether they took it up.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                                                                                                        |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `GET https://api.doers.sh/v2/packages/{packageId}/grants`                                                                                                     |
| CLI       | `doers installs list-package-grants`                                                                                                                          |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `listPackageGrants`                                                                                                                                           |

### Input

| Field              | Type   | Required | Default | Allowed values | Description          |
| ------------------ | ------ | -------- | ------- | -------------- | -------------------- |
| `packageId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field                 | Type           | Allowed values                   | Description                             |
  | --------------------- | -------------- | -------------------------------- | --------------------------------------- |
  | `grants`              | object\[]      |                                  |                                         |
  | `grants[].id`         | string         |                                  |                                         |
  | `grants[].recipient`  | string         |                                  | The username or address it was sent to. |
  | `grants[].status`     | string         | `pending`, `accepted`, `revoked` |                                         |
  | `grants[].createdAt`  | number         |                                  | Epoch milliseconds.                     |
  | `grants[].acceptedAt` | number \| null |                                  |                                         |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_package_grants",
      "arguments": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- [3492ad65-d05a-473f-8f8c-825521eeb41a] Notes for the Acme launch. · pending"
        }
      ],
      "structuredContent": {
        "grants": [
          {
            "id": "3492ad65-d05a-473f-8f8c-825521eeb41a",
            "recipient": "Notes for the Acme launch.",
            "status": "pending",
            "createdAt": 1790069400000,
            "acceptedAt": 1790069400000
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs list-package-grants --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e
  ```
</CodeGroup>

## list\_packages

**List what you have published.**

Your packages, newest first, each with the version currently published.

|           |                                                                                  |
| --------- | -------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                           |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)  |
| REST      | `GET https://api.doers.sh/v2/packages`                                           |
| CLI       | `doers packages list`                                                            |
| Touches   | `packageVersionFiles`, `packageVersions`, `sharedPackages`, `versionPermissions` |
| Operation | `listPackages`                                                                   |

### Input

| Field                        | Type    | Required | Default | Allowed values | Description                       |
| ---------------------------- | ------- | -------- | ------- | -------------- | --------------------------------- |
| `includeUnpublished` (query) | boolean | no       | `false` |                | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field                      | Type           | Allowed values                        | Description                                                     |
  | -------------------------- | -------------- | ------------------------------------- | --------------------------------------------------------------- |
  | `packages`                 | object\[]      |                                       |                                                                 |
  | `packages[].id`            | string         |                                       |                                                                 |
  | `packages[].kind`          | string         | `agent`, `note`, `folder`             | An agent and its notes, a note on its own, or a folder of them. |
  | `packages[].slug`          | string         |                                       |                                                                 |
  | `packages[].name`          | string         |                                       |                                                                 |
  | `packages[].emoji`         | string \| null |                                       |                                                                 |
  | `packages[].summary`       | string         |                                       |                                                                 |
  | `packages[].latestVersion` | integer        | -9007199254740991 to 9007199254740991 |                                                                 |
  | `packages[].fileCount`     | integer        | -9007199254740991 to 9007199254740991 | Files in the version currently published.                       |
  | `packages[].published`     | boolean        |                                       | `false` once taken down. Existing installs are unaffected.      |
  | `packages[].createdAt`     | number         |                                       | Epoch milliseconds.                                             |
  | `packages[].updatedAt`     | number         |                                       | Epoch milliseconds.                                             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_packages",
      "arguments": {
        "includeUnpublished": false
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- [bc4a7118-0870-4794-8155-fbb02f4b0a2e] Acme v3"
        }
      ],
      "structuredContent": {
        "packages": [
          {
            "id": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
            "kind": "agent",
            "slug": "acme",
            "name": "Acme",
            "emoji": "rocket",
            "summary": "Notes for the Acme launch.",
            "latestVersion": 3,
            "fileCount": 3,
            "published": true,
            "createdAt": 1790069400000,
            "updatedAt": 1790069400000
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers packages list --include-unpublished false
  ```
</CodeGroup>

## list\_shared\_with\_me

**Packages sent to you.**

What someone named you on, installed or not. Matched by account and by the address on your account, so a package sent before you signed up appears once you do.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                                                                                                        |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `GET https://api.doers.sh/v2/shared-with-me`                                                                                                                  |
| CLI       | `doers installs list-shared-with-me`                                                                                                                          |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `listSharedWithMe`                                                                                                                                            |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                              | Type           | Allowed values            | Description                                                     |
  | ---------------------------------- | -------------- | ------------------------- | --------------------------------------------------------------- |
  | `packages`                         | object\[]      |                           |                                                                 |
  | `packages[].packageId`             | string         |                           |                                                                 |
  | `packages[].kind`                  | string         | `agent`, `note`, `folder` | An agent and its notes, a note on its own, or a folder of them. |
  | `packages[].name`                  | string         |                           |                                                                 |
  | `packages[].emoji`                 | string \| null |                           |                                                                 |
  | `packages[].summary`               | string         |                           |                                                                 |
  | `packages[].publisher`             | object         |                           |                                                                 |
  | `packages[].publisher.id`          | string         |                           |                                                                 |
  | `packages[].publisher.kind`        | string         | `personal`, `official`    |                                                                 |
  | `packages[].publisher.handle`      | string         |                           |                                                                 |
  | `packages[].publisher.displayName` | string         |                           |                                                                 |
  | `packages[].installed`             | boolean        |                           |                                                                 |
  | `packages[].contentDigest`         | string \| null |                           |                                                                 |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_shared_with_me",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- Acme from Acme"
        }
      ],
      "structuredContent": {
        "packages": [
          {
            "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
            "kind": "agent",
            "name": "Acme",
            "emoji": "rocket",
            "summary": "Notes for the Acme launch.",
            "publisher": {
              "id": "4f03a060-b7eb-4329-82dc-b327f2c989b1",
              "kind": "personal",
              "handle": "ada",
              "displayName": "Acme"
            },
            "installed": true,
            "contentDigest": "Notes for the Acme launch."
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs list-shared-with-me
  ```
</CodeGroup>

## preview\_install\_update

**What an update would bring.**

The newer version's files, changelog and permission differences, without applying anything. `permissions.added` is what the newer version asks for that its installer has never accepted: applying an update that adds any is refused until they are, because a manifest is not consent and an update is not a moment to grant something quietly.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                                                                                                        |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `GET https://api.doers.sh/v2/installs/{installId}/update`                                                                                                     |
| CLI       | `doers installs preview-install-update`                                                                                                                       |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `previewInstallUpdate`                                                                                                                                        |

### Input

| Field              | Type   | Required | Default | Allowed values | Description          |
| ------------------ | ------ | -------- | ------- | -------------- | -------------------- |
| `installId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field                   | Type            | Allowed values                        | Description                                        |
  | ----------------------- | --------------- | ------------------------------------- | -------------------------------------------------- |
  | `version`               | integer \| null | -9007199254740991 to 9007199254740991 | `null` when there is nothing newer.                |
  | `changelog`             | string          |                                       |                                                    |
  | `files`                 | object\[]       |                                       |                                                    |
  | `files[].path`          | string          |                                       |                                                    |
  | `files[].content`       | string          |                                       |                                                    |
  | `permissions`           | object          |                                       |                                                    |
  | `permissions.added`     | string\[]       |                                       | Asked for by the newer version and never accepted. |
  | `permissions.removed`   | string\[]       |                                       | Accepted before, and no longer asked for.          |
  | `permissions.unchanged` | string\[]       |                                       | Asked for and already accepted.                    |
  | `contentDigest`         | string \| null  |                                       |                                                    |
  | `publishedAt`           | number \| null  |                                       |                                                    |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "preview_install_update",
      "arguments": {
        "installId": "1e142e62-77b1-4b7e-8110-478a24caee8f"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "v3: 1 file(s)."
        }
      ],
      "structuredContent": {
        "version": 3,
        "changelog": "Notes for the Acme launch.",
        "files": [
          {
            "path": "Acme/Weekly review",
            "content": "Notes for the Acme launch."
          }
        ],
        "permissions": {
          "added": ["Notes for the Acme launch."],
          "removed": ["Notes for the Acme launch."],
          "unchanged": ["Notes for the Acme launch."]
        },
        "contentDigest": "Notes for the Acme launch.",
        "publishedAt": 1790069400000
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs preview-install-update --install-id 1e142e62-77b1-4b7e-8110-478a24caee8f
  ```
</CodeGroup>

## preview\_listing

**Read a catalogue entry before installing it.**

The **approved** version in full (its files, its licence, the permissions it declares and the publisher behind it) which is not always the newest one frozen. Discover has no share token, so this is the preview every install from the catalogue converges on.

Answers 404 for a package no reviewer approved and for a suspended one alike: neither is something a browser gets told about. Writes nothing and installs nothing.

|           |                                                                                                                                                                                                       |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                                                                                                                                                |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                                                                       |
| REST      | `GET https://api.doers.sh/v2/marketplace/listings/{packageId}`                                                                                                                                        |
| CLI       | `doers marketplace preview-listing`                                                                                                                                                                   |
| Touches   | `categories`, `installs`, `listingCategories`, `listings`, `packageReports`, `packageVersions`, `packageViews`, `publishers`, `reviews`, `safetyRestrictions`, `sharedPackages`, `versionPermissions` |
| Operation | `previewListing`                                                                                                                                                                                      |

### Input

| Field              | Type   | Required | Default | Allowed values | Description              |
| ------------------ | ------ | -------- | ------- | -------------- | ------------------------ |
| `packageId` (path) | string | yes      |         | UUID           | From `discoverPackages`. |

### Output

<Accordion title="Output fields">
  | Field                           | Type           | Allowed values                        | Description                                                     |
  | ------------------------------- | -------------- | ------------------------------------- | --------------------------------------------------------------- |
  | `package`                       | object         |                                       |                                                                 |
  | `package.packageId`             | string         |                                       |                                                                 |
  | `package.kind`                  | string         | `agent`, `note`, `folder`             | An agent and its notes, a note on its own, or a folder of them. |
  | `package.slug`                  | string         |                                       |                                                                 |
  | `package.name`                  | string         |                                       |                                                                 |
  | `package.emoji`                 | string \| null |                                       |                                                                 |
  | `package.summary`               | string         |                                       |                                                                 |
  | `package.version`               | integer        | -9007199254740991 to 9007199254740991 | The version on offer today, not any version already installed.  |
  | `package.changelog`             | string         |                                       |                                                                 |
  | `package.publishedAt`           | number         |                                       | Epoch milliseconds.                                             |
  | `package.publisher`             | object         |                                       |                                                                 |
  | `package.publisher.id`          | string         |                                       |                                                                 |
  | `package.publisher.kind`        | string         | `personal`, `official`                |                                                                 |
  | `package.publisher.handle`      | string         |                                       |                                                                 |
  | `package.publisher.displayName` | string         |                                       |                                                                 |
  | `package.files`                 | object\[]      |                                       |                                                                 |
  | `package.files[].path`          | string         |                                       |                                                                 |
  | `package.files[].content`       | string         |                                       |                                                                 |
  | `package.contentDigest`         | string \| null |                                       |                                                                 |
  | `package.reviewStatus`          | string         | `approved`, `unreviewed`              |                                                                 |
  | `package.approvedAt`            | number \| null |                                       |                                                                 |
  | `package.licence`               | string \| null | `mit`, `cc-by-4.0`                    |                                                                 |
  | `package.permissions`           | string\[]      |                                       | Operation ids the version declares it needs.                    |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "preview_listing",
      "arguments": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "Acme v3 by ada · 1 file(s)."
        }
      ],
      "structuredContent": {
        "package": {
          "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
          "kind": "agent",
          "slug": "acme",
          "name": "Acme",
          "emoji": "rocket",
          "summary": "Notes for the Acme launch.",
          "version": 3,
          "changelog": "Notes for the Acme launch.",
          "publishedAt": 1790069400000,
          "publisher": {
            "id": "4f03a060-b7eb-4329-82dc-b327f2c989b1",
            "kind": "personal",
            "handle": "ada",
            "displayName": "Acme"
          },
          "files": [
            {
              "path": "Acme/Weekly review",
              "content": "Notes for the Acme launch."
            }
          ],
          "contentDigest": "Notes for the Acme launch.",
          "reviewStatus": "approved",
          "approvedAt": 1790069400000,
          "licence": "mit",
          "permissions": ["Notes for the Acme launch."]
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers marketplace preview-listing --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e
  ```
</CodeGroup>

## preview\_package

**Read a package before installing it.**

Everything the address describes: the version on offer, its changelog, and **every file in full**. Writes nothing and installs nothing: the page that offers an agent has to be able to show what that agent says, because an installed agent runs on the caller's workspace with the caller's key.

Answers 404 for a token that is unknown or has been taken down. The author of a package may read their own, unlike installing it.

A POST that reads: the token is the whole capability, and a query string is written to every access log and sent onward in a `Referer`.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                                                                                                        |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `POST https://api.doers.sh/v2/packages/preview`                                                                                                               |
| CLI       | `doers installs preview`                                                                                                                                      |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `previewPackage`                                                                                                                                              |

### Input

| Field   | Type   | Required | Default | Allowed values      | Description                                |
| ------- | ------ | -------- | ------- | ------------------- | ------------------------------------------ |
| `token` | string | yes      |         | 1 to 128 characters | The token from a package's public address. |

### Output

<Accordion title="Output fields">
  | Field                           | Type           | Allowed values                        | Description                                                     |
  | ------------------------------- | -------------- | ------------------------------------- | --------------------------------------------------------------- |
  | `package`                       | object         |                                       |                                                                 |
  | `package.packageId`             | string         |                                       |                                                                 |
  | `package.kind`                  | string         | `agent`, `note`, `folder`             | An agent and its notes, a note on its own, or a folder of them. |
  | `package.slug`                  | string         |                                       |                                                                 |
  | `package.name`                  | string         |                                       |                                                                 |
  | `package.emoji`                 | string \| null |                                       |                                                                 |
  | `package.summary`               | string         |                                       |                                                                 |
  | `package.version`               | integer        | -9007199254740991 to 9007199254740991 | The version on offer today, not any version already installed.  |
  | `package.changelog`             | string         |                                       |                                                                 |
  | `package.publishedAt`           | number         |                                       | Epoch milliseconds.                                             |
  | `package.publisher`             | object         |                                       |                                                                 |
  | `package.publisher.id`          | string         |                                       |                                                                 |
  | `package.publisher.kind`        | string         | `personal`, `official`                |                                                                 |
  | `package.publisher.handle`      | string         |                                       |                                                                 |
  | `package.publisher.displayName` | string         |                                       |                                                                 |
  | `package.files`                 | object\[]      |                                       |                                                                 |
  | `package.files[].path`          | string         |                                       |                                                                 |
  | `package.files[].content`       | string         |                                       |                                                                 |
  | `package.contentDigest`         | string \| null |                                       |                                                                 |
  | `package.reviewStatus`          | string         | `approved`, `unreviewed`              |                                                                 |
  | `package.approvedAt`            | number \| null |                                       |                                                                 |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "preview_package",
      "arguments": {
        "token": "acme-example-token"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "Acme v3 by Acme · 1 file(s)."
        }
      ],
      "structuredContent": {
        "package": {
          "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
          "kind": "agent",
          "slug": "acme",
          "name": "Acme",
          "emoji": "rocket",
          "summary": "Notes for the Acme launch.",
          "version": 3,
          "changelog": "Notes for the Acme launch.",
          "publishedAt": 1790069400000,
          "publisher": {
            "id": "4f03a060-b7eb-4329-82dc-b327f2c989b1",
            "kind": "personal",
            "handle": "ada",
            "displayName": "Acme"
          },
          "files": [
            {
              "path": "Acme/Weekly review",
              "content": "Notes for the Acme launch."
            }
          ],
          "contentDigest": "Notes for the Acme launch.",
          "reviewStatus": "approved",
          "approvedAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs preview acme-example-token
  ```
</CodeGroup>

## apply\_install\_update

**Move an install to the latest version.**

Returns the files to write. A package that has been taken down cannot be updated, and neither can one whose newer version asks for more than its installer accepted: send `acceptedDigest` to accept the widened manifest, exactly as installing does.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Write · idempotent · no outside service                                                                                                                       |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `POST https://api.doers.sh/v2/installs/{installId}/update`                                                                                                    |
| CLI       | `doers installs apply-install-update`                                                                                                                         |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `applyInstallUpdate`                                                                                                                                          |

### Input

| Field              | Type           | Required | Default | Allowed values      | Description                                                                                                                                                                                                                                   |
| ------------------ | -------------- | -------- | ------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `installId` (path) | string         | yes      |         | UUID                | Identifier of a row.                                                                                                                                                                                                                          |
| `acceptedDigest`   | string \| null | no       |         | 64 to 64 characters | The digest of the update preview whose permissions were accepted. Required only when the newer version asks for something the installer has never accepted; anything other than an exact match with the version on offer is refused with 409. |

### Output

<Accordion title="Output fields">
  | Field                           | Type            | Allowed values                        | Description                                                      |
  | ------------------------------- | --------------- | ------------------------------------- | ---------------------------------------------------------------- |
  | `install`                       | object          |                                       |                                                                  |
  | `install.id`                    | string          |                                       |                                                                  |
  | `install.packageId`             | string          |                                       |                                                                  |
  | `install.kind`                  | string          | `agent`, `note`, `folder`             | An agent and its notes, a note on its own, or a folder of them.  |
  | `install.slug`                  | string          |                                       |                                                                  |
  | `install.name`                  | string          |                                       |                                                                  |
  | `install.emoji`                 | string \| null  |                                       |                                                                  |
  | `install.summary`               | string          |                                       |                                                                  |
  | `install.version`               | integer         | -9007199254740991 to 9007199254740991 |                                                                  |
  | `install.latestVersion`         | integer \| null | -9007199254740991 to 9007199254740991 | `null` once the author has taken it down.                        |
  | `install.updateAvailable`       | boolean         |                                       |                                                                  |
  | `install.publisher`             | object          |                                       |                                                                  |
  | `install.publisher.id`          | string          |                                       |                                                                  |
  | `install.publisher.kind`        | string          | `personal`, `official`                |                                                                  |
  | `install.publisher.handle`      | string          |                                       |                                                                  |
  | `install.publisher.displayName` | string          |                                       |                                                                  |
  | `install.installedAt`           | number          |                                       | Epoch milliseconds.                                              |
  | `install.revoked`               | boolean         |                                       | The author took the package down. What is installed still works. |
  | `install.files`                 | object\[]       |                                       |                                                                  |
  | `install.files[].path`          | string          |                                       |                                                                  |
  | `install.files[].content`       | string          |                                       |                                                                  |
  | `files`                         | object\[]       |                                       |                                                                  |
  | `files[].path`                  | string          |                                       |                                                                  |
  | `files[].content`               | string          |                                       |                                                                  |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "apply_install_update",
      "arguments": {
        "installId": "1e142e62-77b1-4b7e-8110-478a24caee8f",
        "acceptedDigest": "Notes for the Acme launch. Acme Acme Acme Acme Acme Acme Acme Ac"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: now on v3."
        }
      ],
      "structuredContent": {
        "install": {
          "id": "1e142e62-77b1-4b7e-8110-478a24caee8f",
          "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
          "kind": "agent",
          "slug": "acme",
          "name": "Acme",
          "emoji": "rocket",
          "summary": "Notes for the Acme launch.",
          "version": 3,
          "latestVersion": 3,
          "updateAvailable": true,
          "publisher": {
            "id": "4f03a060-b7eb-4329-82dc-b327f2c989b1",
            "kind": "personal",
            "handle": "ada",
            "displayName": "Acme"
          },
          "installedAt": 1790069400000,
          "revoked": true,
          "files": [
            {
              "path": "Acme/Weekly review",
              "content": "Notes for the Acme launch."
            }
          ]
        },
        "files": [
          {
            "path": "Acme/Weekly review",
            "content": "Notes for the Acme launch."
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs apply-install-update --install-id 1e142e62-77b1-4b7e-8110-478a24caee8f --accepted-digest "Notes for the Acme launch. Acme Acme Acme Acme Acme Acme Acme Ac"
  ```
</CodeGroup>

## approve\_run

**Approve a run waiting on the Mac.**

Queues an approval for the Mac. Does not run the agent on the server.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/runs/{runId}/approve`                             |
| CLI       | `doers devices approve-run`                                                     |
| Touches   | `deviceCalls`, `devices`, `tasks`                                               |
| Operation | `approveRun`                                                                    |

### Input

| Field          | Type   | Required | Default | Allowed values | Description          |
| -------------- | ------ | -------- | ------- | -------------- | -------------------- |
| `runId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field                | Type           | Allowed values                                                         | Description         |
  | -------------------- | -------------- | ---------------------------------------------------------------------- | ------------------- |
  | `call`               | object         |                                                                        |                     |
  | `call.id`            | string         |                                                                        |                     |
  | `call.deviceId`      | string         |                                                                        |                     |
  | `call.operation`     | string         | `delegateTask`, `approveRun`, `rejectRun`, `replyToRun`, `getRunState` |                     |
  | `call.state`         | string         | `queued`, `running`, `needs-approval`, `done`, `failed`                |                     |
  | `call.waitingForMac` | boolean        |                                                                        |                     |
  | `call.message`       | string \| null |                                                                        |                     |
  | `call.createdAt`     | number         |                                                                        | Epoch milliseconds. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "approve_run",
      "arguments": {
        "runId": "acba2551-2100-480b-86fc-3ccd14c65be5"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: approved 7edb360f-06ac-4ef2-8c80-dba16cf563f1."
        }
      ],
      "structuredContent": {
        "call": {
          "id": "7edb360f-06ac-4ef2-8c80-dba16cf563f1",
          "deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
          "operation": "delegateTask",
          "state": "queued",
          "waitingForMac": true,
          "message": "Notes for the Acme launch.",
          "createdAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers devices approve-run --run-id acba2551-2100-480b-86fc-3ccd14c65be5
  ```
</CodeGroup>

## delegate\_task

**Queue a task for an agent on a paired Mac.**

Does not run the agent on the server. The Mac pulls this call and runs it in the vault. `agentFolder` is the vault-relative folder (the product's agent id).

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/devices/{deviceId}/delegate`                      |
| CLI       | `doers devices delegate-task`                                                   |
| Touches   | `deviceCalls`, `devices`, `tasks`                                               |
| Operation | `delegateTask`                                                                  |

### Input

| Field             | Type   | Required | Default | Allowed values       | Description                       |
| ----------------- | ------ | -------- | ------- | -------------------- | --------------------------------- |
| `deviceId` (path) | string | yes      |         | UUID                 | Identifier of a row.              |
| `taskId`          | string | yes      |         | UUID                 | Identifier of a row.              |
| `agentFolder`     | string | yes      |         | 1 to 1024 characters | *No description in the registry.* |
| `model`           | string | no       |         | 1 to 500 characters  | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field                | Type           | Allowed values                                                         | Description         |
  | -------------------- | -------------- | ---------------------------------------------------------------------- | ------------------- |
  | `call`               | object         |                                                                        |                     |
  | `call.id`            | string         |                                                                        |                     |
  | `call.deviceId`      | string         |                                                                        |                     |
  | `call.operation`     | string         | `delegateTask`, `approveRun`, `rejectRun`, `replyToRun`, `getRunState` |                     |
  | `call.state`         | string         | `queued`, `running`, `needs-approval`, `done`, `failed`                |                     |
  | `call.waitingForMac` | boolean        |                                                                        |                     |
  | `call.message`       | string \| null |                                                                        |                     |
  | `call.createdAt`     | number         |                                                                        | Epoch milliseconds. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "delegate_task",
      "arguments": {
        "deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
        "taskId": "0ebb429f-a86d-481c-8630-fac53db1c91c",
        "agentFolder": "Notes for the Acme launch.",
        "model": "Notes for the Acme launch."
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: run 7edb360f-06ac-4ef2-8c80-dba16cf563f1."
        }
      ],
      "structuredContent": {
        "call": {
          "id": "7edb360f-06ac-4ef2-8c80-dba16cf563f1",
          "deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
          "operation": "delegateTask",
          "state": "queued",
          "waitingForMac": true,
          "message": "Notes for the Acme launch.",
          "createdAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers devices delegate-task --device-id 263a4dbe-4148-4fb8-8214-b0032339dbb9 --task-id 0ebb429f-a86d-481c-8630-fac53db1c91c --agent-folder "Notes for the Acme launch." --model "Notes for the Acme launch."
  ```
</CodeGroup>

## detach\_install

**Keep it, without the link.**

The package becomes an ordinary folder in your own vault: the files are returned for the client to keep, and the install is forgotten. No further updates, and nothing the author does afterwards reaches it.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Write · destructive · no outside service                                                                                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `POST https://api.doers.sh/v2/installs/{installId}/detach`                                                                                                    |
| CLI       | `doers installs detach`                                                                                                                                       |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `detachInstall`                                                                                                                                               |

### Input

| Field              | Type   | Required | Default | Allowed values | Description          |
| ------------------ | ------ | -------- | ------- | -------------- | -------------------- |
| `installId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field             | Type      | Allowed values | Description |
  | ----------------- | --------- | -------------- | ----------- |
  | `name`            | string    |                |             |
  | `slug`            | string    |                |             |
  | `files`           | object\[] |                |             |
  | `files[].path`    | string    |                |             |
  | `files[].content` | string    |                |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "detach_install",
      "arguments": {
        "installId": "1e142e62-77b1-4b7e-8110-478a24caee8f"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: Acme is yours now."
        }
      ],
      "structuredContent": {
        "name": "Acme",
        "slug": "acme",
        "files": [
          {
            "path": "Acme/Weekly review",
            "content": "Notes for the Acme launch."
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs detach --install-id 1e142e62-77b1-4b7e-8110-478a24caee8f
  ```
</CodeGroup>

## grant\_package\_access

**Send a package to someone.**

`target` is a username or an email address. This records the send and puts the package in their list; it does **not** gate installation, which the package's address already allows. The address is not returned here: it was shown once, when the package was first published.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                                                                                                    |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `POST https://api.doers.sh/v2/packages/{packageId}/grants`                                                                                                    |
| CLI       | `doers installs grant-package-access`                                                                                                                         |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `grantPackageAccess`                                                                                                                                          |

### Input

| Field              | Type   | Required | Default | Allowed values      | Description                       |
| ------------------ | ------ | -------- | ------- | ------------------- | --------------------------------- |
| `packageId` (path) | string | yes      |         | UUID                | Identifier of a row.              |
| `target`           | string | yes      |         | 1 to 254 characters | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field              | Type           | Allowed values                   | Description                             |
  | ------------------ | -------------- | -------------------------------- | --------------------------------------- |
  | `grant`            | object         |                                  |                                         |
  | `grant.id`         | string         |                                  |                                         |
  | `grant.recipient`  | string         |                                  | The username or address it was sent to. |
  | `grant.status`     | string         | `pending`, `accepted`, `revoked` |                                         |
  | `grant.createdAt`  | number         |                                  | Epoch milliseconds.                     |
  | `grant.acceptedAt` | number \| null |                                  |                                         |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "grant_package_access",
      "arguments": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
        "target": "Notes for the Acme launch."
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: sent to Notes for the Acme launch.."
        }
      ],
      "structuredContent": {
        "grant": {
          "id": "3492ad65-d05a-473f-8f8c-825521eeb41a",
          "recipient": "Notes for the Acme launch.",
          "status": "pending",
          "createdAt": 1790069400000,
          "acceptedAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs grant-package-access --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e --target "Notes for the Acme launch."
  ```
</CodeGroup>

## install\_package

**Install a package from its address.**

Returns the files for the client to write. Installing something you already have is not an error: it returns what you are on rather than moving you, so re-opening a link never changes what is on your disk behind your back.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Write · idempotent · no outside service                                                                                                                       |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `POST https://api.doers.sh/v2/installs`                                                                                                                       |
| CLI       | `doers installs install-package`                                                                                                                              |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `installPackage`                                                                                                                                              |

### Input

| Field            | Type           | Required | Default | Allowed values      | Description                                                                                                                                                                                                                                                                                                                                                                                                          |
| ---------------- | -------------- | -------- | ------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `token`          | string         | no       |         | 1 to 128 characters | From a share link.                                                                                                                                                                                                                                                                                                                                                                                                   |
| `packageId`      | string         | no       |         | UUID                | From a package already granted to you.                                                                                                                                                                                                                                                                                                                                                                               |
| `acceptedDigest` | string \| null | yes      |         | 64 to 64 characters | The content digest of the preview whose permissions were accepted: **required**, because an install with nothing to compare against is an install nobody consented to. Send `null` only when the preview showed none, which is what a version frozen before digests existed reports. Anything other than an exact match with the version on offer is refused with 409 rather than quietly installing something else. |

### Output

<Accordion title="Output fields">
  | Field                           | Type            | Allowed values                        | Description                                                      |
  | ------------------------------- | --------------- | ------------------------------------- | ---------------------------------------------------------------- |
  | `install`                       | object          |                                       |                                                                  |
  | `install.id`                    | string          |                                       |                                                                  |
  | `install.packageId`             | string          |                                       |                                                                  |
  | `install.kind`                  | string          | `agent`, `note`, `folder`             | An agent and its notes, a note on its own, or a folder of them.  |
  | `install.slug`                  | string          |                                       |                                                                  |
  | `install.name`                  | string          |                                       |                                                                  |
  | `install.emoji`                 | string \| null  |                                       |                                                                  |
  | `install.summary`               | string          |                                       |                                                                  |
  | `install.version`               | integer         | -9007199254740991 to 9007199254740991 |                                                                  |
  | `install.latestVersion`         | integer \| null | -9007199254740991 to 9007199254740991 | `null` once the author has taken it down.                        |
  | `install.updateAvailable`       | boolean         |                                       |                                                                  |
  | `install.publisher`             | object          |                                       |                                                                  |
  | `install.publisher.id`          | string          |                                       |                                                                  |
  | `install.publisher.kind`        | string          | `personal`, `official`                |                                                                  |
  | `install.publisher.handle`      | string          |                                       |                                                                  |
  | `install.publisher.displayName` | string          |                                       |                                                                  |
  | `install.installedAt`           | number          |                                       | Epoch milliseconds.                                              |
  | `install.revoked`               | boolean         |                                       | The author took the package down. What is installed still works. |
  | `install.files`                 | object\[]       |                                       |                                                                  |
  | `install.files[].path`          | string          |                                       |                                                                  |
  | `install.files[].content`       | string          |                                       |                                                                  |
  | `files`                         | object\[]       |                                       |                                                                  |
  | `files[].path`                  | string          |                                       |                                                                  |
  | `files[].content`               | string          |                                       |                                                                  |
  | `alreadyInstalled`              | boolean         |                                       |                                                                  |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "install_package",
      "arguments": {
        "acceptedDigest": "Notes for the Acme launch. Acme Acme Acme Acme Acme Acme Acme Ac",
        "token": "acme-example-token"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "Already installed: Acme v3."
        }
      ],
      "structuredContent": {
        "install": {
          "id": "1e142e62-77b1-4b7e-8110-478a24caee8f",
          "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
          "kind": "agent",
          "slug": "acme",
          "name": "Acme",
          "emoji": "rocket",
          "summary": "Notes for the Acme launch.",
          "version": 3,
          "latestVersion": 3,
          "updateAvailable": true,
          "publisher": {
            "id": "4f03a060-b7eb-4329-82dc-b327f2c989b1",
            "kind": "personal",
            "handle": "ada",
            "displayName": "Acme"
          },
          "installedAt": 1790069400000,
          "revoked": true,
          "files": [
            {
              "path": "Acme/Weekly review",
              "content": "Notes for the Acme launch."
            }
          ]
        },
        "files": [
          {
            "path": "Acme/Weekly review",
            "content": "Notes for the Acme launch."
          }
        ],
        "alreadyInstalled": true
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs install-package acme-example-token --accepted-digest "Notes for the Acme launch. Acme Acme Acme Acme Acme Acme Acme Ac"
  ```
</CodeGroup>

## publish\_package

**Publish a package, or a new version of one.**

Publishing to a slug you already used adds a version to that package rather than creating a second one, and un-retires it if it had been taken down. The public address is returned **once**, on the first publish: only a hash of its token is stored.

|           |                                                                                  |
| --------- | -------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                       |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)  |
| REST      | `POST https://api.doers.sh/v2/packages`                                          |
| CLI       | `doers packages publish`                                                         |
| Touches   | `packageVersionFiles`, `packageVersions`, `sharedPackages`, `versionPermissions` |
| Operation | `publishPackage`                                                                 |

### Input

| Field             | Type           | Required | Default | Allowed values            | Description                                                                                                                                                                                    |
| ----------------- | -------------- | -------- | ------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `kind`            | string         | yes      |         | `agent`, `note`, `folder` | An agent and its notes, a note on its own, or a folder of them.                                                                                                                                |
| `slug`            | string         | yes      |         | 1 to 80 characters        | *No description in the registry.*                                                                                                                                                              |
| `name`            | string         | yes      |         | 1 to 200 characters       | *No description in the registry.*                                                                                                                                                              |
| `emoji`           | string \| null | no       |         | 0 to 200 characters       | *No description in the registry.*                                                                                                                                                              |
| `summary`         | string         | no       | `""`    | 0 to 10000 characters     | *No description in the registry.*                                                                                                                                                              |
| `changelog`       | string         | no       | `""`    | 0 to 10000 characters     | *No description in the registry.*                                                                                                                                                              |
| `licence`         | string \| null | no       |         | `mit`, `cc-by-4.0`        | Chosen explicitly. Omitted means unlicensed: nothing is licensed on the author's behalf.                                                                                                       |
| `permissions`     | string\[]      | no       | `[]`    | at most 32 items          | Operation ids this version asks to be allowed to call, by name (`listTasks`). Enforced by the server at every execution boundary, never by the package. An id this API does not have is a 400. |
| `files`           | object\[]      | yes      |         | at most 64 items          | *No description in the registry.*                                                                                                                                                              |
| `files[].path`    | string         | yes      |         |                           | Relative, `/`-separated, no `..`.                                                                                                                                                              |
| `files[].content` | string         | yes      |         |                           | *No description in the registry.*                                                                                                                                                              |

### Output

<Accordion title="Output fields">
  | Field                   | Type           | Allowed values                        | Description                                                       |
  | ----------------------- | -------------- | ------------------------------------- | ----------------------------------------------------------------- |
  | `package`               | object         |                                       |                                                                   |
  | `package.id`            | string         |                                       |                                                                   |
  | `package.kind`          | string         | `agent`, `note`, `folder`             | An agent and its notes, a note on its own, or a folder of them.   |
  | `package.slug`          | string         |                                       |                                                                   |
  | `package.name`          | string         |                                       |                                                                   |
  | `package.emoji`         | string \| null |                                       |                                                                   |
  | `package.summary`       | string         |                                       |                                                                   |
  | `package.latestVersion` | integer        | -9007199254740991 to 9007199254740991 |                                                                   |
  | `package.fileCount`     | integer        | -9007199254740991 to 9007199254740991 | Files in the version currently published.                         |
  | `package.published`     | boolean        |                                       | `false` once taken down. Existing installs are unaffected.        |
  | `package.createdAt`     | number         |                                       | Epoch milliseconds.                                               |
  | `package.updatedAt`     | number         |                                       | Epoch milliseconds.                                               |
  | `url`                   | string \| null |                                       | The public address, on the FIRST publish only. `null` afterwards. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "publish_package",
      "arguments": {
        "kind": "agent",
        "slug": "acme",
        "name": "Acme",
        "files": [
          {
            "path": "Acme/Weekly review",
            "content": "Notes for the Acme launch."
          }
        ],
        "emoji": "rocket",
        "summary": ""
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: Acme v3 published. Send this now: https://acme.example/brief"
        }
      ],
      "structuredContent": {
        "package": {
          "id": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
          "kind": "agent",
          "slug": "acme",
          "name": "Acme",
          "emoji": "rocket",
          "summary": "Notes for the Acme launch.",
          "latestVersion": 3,
          "fileCount": 3,
          "published": true,
          "createdAt": 1790069400000,
          "updatedAt": 1790069400000
        },
        "url": "https://acme.example/brief"
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers packages publish --kind agent --slug acme --name Acme --emoji rocket --summary ""
  # files: structured argument(s) the CLI cannot pass as flags.
  ```
</CodeGroup>

## record\_package\_view

**Record that a catalogue entry was opened.**

Counts one view per account per package per day, so opening the same card twice is one view rather than two. The viewer is stored as a hash and a share token is never written alongside it: an analytics table that held one would be a list of working private links.

|           |                                                                                                                                                                                                       |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Write · idempotent · no outside service                                                                                                                                                               |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                                                                       |
| REST      | `POST https://api.doers.sh/v2/marketplace/views`                                                                                                                                                      |
| CLI       | `doers marketplace record-package-view`                                                                                                                                                               |
| Touches   | `categories`, `installs`, `listingCategories`, `listings`, `packageReports`, `packageVersions`, `packageViews`, `publishers`, `reviews`, `safetyRestrictions`, `sharedPackages`, `versionPermissions` |
| Operation | `recordPackageView`                                                                                                                                                                                   |

### Input

| Field       | Type   | Required | Default | Allowed values | Description                          |
| ----------- | ------ | -------- | ------- | -------------- | ------------------------------------ |
| `packageId` | string | yes      |         | UUID           | The catalogue entry that was opened. |

### Output

<Accordion title="Output fields">
  | Field      | Type    | Allowed values | Description                                   |
  | ---------- | ------- | -------------- | --------------------------------------------- |
  | `recorded` | boolean |                | False when this viewer already counted today. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "record_package_view",
      "arguments": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: counted."
        }
      ],
      "structuredContent": {
        "recorded": true
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers marketplace record-package-view --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e
  ```
</CodeGroup>

## register\_device

**Register this desktop on the account.**

A signed-in desktop registers itself as a device. The phone lists paired Macs. No extra pairing code: both sides use the account session.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/devices`                                          |
| CLI       | `doers devices register`                                                        |
| Touches   | `deviceCalls`, `devices`, `tasks`                                               |
| Operation | `registerDevice`                                                                |

### Input

| Field  | Type   | Required | Default | Allowed values      | Description                       |
| ------ | ------ | -------- | ------- | ------------------- | --------------------------------- |
| `name` | string | yes      |         | 1 to 200 characters | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field               | Type           | Allowed values | Description |
  | ------------------- | -------------- | -------------- | ----------- |
  | `device`            | object         |                |             |
  | `device.id`         | string         |                |             |
  | `device.name`       | string         |                |             |
  | `device.kind`       | string         | `"desktop"`    |             |
  | `device.lastSeenAt` | number \| null |                |             |
  | `device.revokedAt`  | number \| null |                |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "register_device",
      "arguments": {
        "name": "Acme"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: device Acme."
        }
      ],
      "structuredContent": {
        "device": {
          "id": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
          "name": "Acme",
          "kind": "desktop",
          "lastSeenAt": 1790069400000,
          "revokedAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers devices register --name Acme
  ```
</CodeGroup>

## reject\_run

**Reject a run waiting on the Mac.**

Queues a rejection with a note. Does not run the agent on the server.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/runs/{runId}/reject`                              |
| CLI       | `doers devices reject-run`                                                      |
| Touches   | `deviceCalls`, `devices`, `tasks`                                               |
| Operation | `rejectRun`                                                                     |

### Input

| Field          | Type   | Required | Default | Allowed values      | Description                       |
| -------------- | ------ | -------- | ------- | ------------------- | --------------------------------- |
| `runId` (path) | string | yes      |         | UUID                | Identifier of a row.              |
| `note`         | string | yes      |         | 1 to 500 characters | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field                | Type           | Allowed values                                                         | Description         |
  | -------------------- | -------------- | ---------------------------------------------------------------------- | ------------------- |
  | `call`               | object         |                                                                        |                     |
  | `call.id`            | string         |                                                                        |                     |
  | `call.deviceId`      | string         |                                                                        |                     |
  | `call.operation`     | string         | `delegateTask`, `approveRun`, `rejectRun`, `replyToRun`, `getRunState` |                     |
  | `call.state`         | string         | `queued`, `running`, `needs-approval`, `done`, `failed`                |                     |
  | `call.waitingForMac` | boolean        |                                                                        |                     |
  | `call.message`       | string \| null |                                                                        |                     |
  | `call.createdAt`     | number         |                                                                        | Epoch milliseconds. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "reject_run",
      "arguments": {
        "runId": "acba2551-2100-480b-86fc-3ccd14c65be5",
        "note": "Notes for the Acme launch."
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: rejected 7edb360f-06ac-4ef2-8c80-dba16cf563f1."
        }
      ],
      "structuredContent": {
        "call": {
          "id": "7edb360f-06ac-4ef2-8c80-dba16cf563f1",
          "deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
          "operation": "delegateTask",
          "state": "queued",
          "waitingForMac": true,
          "message": "Notes for the Acme launch.",
          "createdAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers devices reject-run --run-id acba2551-2100-480b-86fc-3ccd14c65be5 --note "Notes for the Acme launch."
  ```
</CodeGroup>

## reply\_to\_run

**Send a message into a run on the Mac.**

Queues a reply. The Mac sends it on the conversation.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/runs/{runId}/reply`                               |
| CLI       | `doers devices reply-to-run`                                                    |
| Touches   | `deviceCalls`, `devices`, `tasks`                                               |
| Operation | `replyToRun`                                                                    |

### Input

| Field          | Type   | Required | Default | Allowed values      | Description                       |
| -------------- | ------ | -------- | ------- | ------------------- | --------------------------------- |
| `runId` (path) | string | yes      |         | UUID                | Identifier of a row.              |
| `message`      | string | yes      |         | 1 to 500 characters | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field                | Type           | Allowed values                                                         | Description         |
  | -------------------- | -------------- | ---------------------------------------------------------------------- | ------------------- |
  | `call`               | object         |                                                                        |                     |
  | `call.id`            | string         |                                                                        |                     |
  | `call.deviceId`      | string         |                                                                        |                     |
  | `call.operation`     | string         | `delegateTask`, `approveRun`, `rejectRun`, `replyToRun`, `getRunState` |                     |
  | `call.state`         | string         | `queued`, `running`, `needs-approval`, `done`, `failed`                |                     |
  | `call.waitingForMac` | boolean        |                                                                        |                     |
  | `call.message`       | string \| null |                                                                        |                     |
  | `call.createdAt`     | number         |                                                                        | Epoch milliseconds. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "reply_to_run",
      "arguments": {
        "runId": "acba2551-2100-480b-86fc-3ccd14c65be5",
        "message": "Notes for the Acme launch."
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: replied 7edb360f-06ac-4ef2-8c80-dba16cf563f1."
        }
      ],
      "structuredContent": {
        "call": {
          "id": "7edb360f-06ac-4ef2-8c80-dba16cf563f1",
          "deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
          "operation": "delegateTask",
          "state": "queued",
          "waitingForMac": true,
          "message": "Notes for the Acme launch.",
          "createdAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers devices reply-to-run --run-id acba2551-2100-480b-86fc-3ccd14c65be5 --message "Notes for the Acme launch."
  ```
</CodeGroup>

## report\_package

**Report a package to the safety queue.**

Tells staff that something is wrong with a catalogue entry. One report per account per package: reporting twice replaces nothing and adds nothing, so a single account cannot weigh on the queue by clicking.

Answers the same whether or not anybody else has reported it. A count would tell the reporter whether theirs was the first, which is the author's business and not theirs.

|           |                                                                                                                                                                                                       |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Write · idempotent · no outside service                                                                                                                                                               |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                                                                       |
| REST      | `POST https://api.doers.sh/v2/marketplace/packages/{packageId}/report`                                                                                                                                |
| CLI       | `doers marketplace report-package`                                                                                                                                                                    |
| Touches   | `categories`, `installs`, `listingCategories`, `listings`, `packageReports`, `packageVersions`, `packageViews`, `publishers`, `reviews`, `safetyRestrictions`, `sharedPackages`, `versionPermissions` |
| Operation | `reportPackage`                                                                                                                                                                                       |

### Input

| Field              | Type   | Required | Default | Allowed values                                                              | Description                                |
| ------------------ | ------ | -------- | ------- | --------------------------------------------------------------------------- | ------------------------------------------ |
| `packageId` (path) | string | yes      |         | UUID                                                                        | The catalogue entry being reported.        |
| `reason`           | string | yes      |         | `malicious`, `deceptive`, `stolen`, `unsafe_permissions`, `broken`, `other` | Which of the six kinds of problem this is. |
| `detail`           | string | no       |         | 0 to 2000 characters                                                        | What the reporter saw, in their own words. |

### Output

<Accordion title="Output fields">
  | Field      | Type    | Allowed values | Description                                   |
  | ---------- | ------- | -------------- | --------------------------------------------- |
  | `reported` | boolean | `true`         | Always true: a repeat report is not an error. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "report_package",
      "arguments": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
        "reason": "malicious",
        "detail": "Notes for the Acme launch."
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: reported."
        }
      ],
      "structuredContent": {
        "reported": true
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers marketplace report-package --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e --reason malicious --detail "Notes for the Acme launch."
  ```
</CodeGroup>

## report\_run\_state

**The Mac publishes a run step.**

Desktop only: step events (running, needs-approval, done, failed). Also writes a run-status realtime event for the phone.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/runs/{runId}/state`                               |
| CLI       | `doers devices report-run-state`                                                |
| Touches   | `deviceCalls`, `devices`, `tasks`                                               |
| Operation | `reportRunState`                                                                |

### Input

| Field          | Type   | Required | Default | Allowed values                                          | Description                       |
| -------------- | ------ | -------- | ------- | ------------------------------------------------------- | --------------------------------- |
| `runId` (path) | string | yes      |         | UUID                                                    | Identifier of a row.              |
| `state`        | string | yes      |         | `queued`, `running`, `needs-approval`, `done`, `failed` | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field                | Type           | Allowed values                                                         | Description         |
  | -------------------- | -------------- | ---------------------------------------------------------------------- | ------------------- |
  | `call`               | object         |                                                                        |                     |
  | `call.id`            | string         |                                                                        |                     |
  | `call.deviceId`      | string         |                                                                        |                     |
  | `call.operation`     | string         | `delegateTask`, `approveRun`, `rejectRun`, `replyToRun`, `getRunState` |                     |
  | `call.state`         | string         | `queued`, `running`, `needs-approval`, `done`, `failed`                |                     |
  | `call.waitingForMac` | boolean        |                                                                        |                     |
  | `call.message`       | string \| null |                                                                        |                     |
  | `call.createdAt`     | number         |                                                                        | Epoch milliseconds. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "report_run_state",
      "arguments": {
        "runId": "acba2551-2100-480b-86fc-3ccd14c65be5",
        "state": "queued"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: queued."
        }
      ],
      "structuredContent": {
        "call": {
          "id": "7edb360f-06ac-4ef2-8c80-dba16cf563f1",
          "deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
          "operation": "delegateTask",
          "state": "queued",
          "waitingForMac": true,
          "message": "Notes for the Acme launch.",
          "createdAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers devices report-run-state --run-id acba2551-2100-480b-86fc-3ccd14c65be5 --state queued
  ```
</CodeGroup>

## revoke\_device

**Revoke a paired device.**

Kills the tunnel. Queued calls for that device are no longer returned to it.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/devices/{deviceId}/revoke`                        |
| CLI       | `doers devices revoke`                                                          |
| Touches   | `deviceCalls`, `devices`, `tasks`                                               |
| Operation | `revokeDevice`                                                                  |

### Input

| Field             | Type   | Required | Default | Allowed values | Description          |
| ----------------- | ------ | -------- | ------- | -------------- | -------------------- |
| `deviceId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field               | Type           | Allowed values | Description |
  | ------------------- | -------------- | -------------- | ----------- |
  | `device`            | object         |                |             |
  | `device.id`         | string         |                |             |
  | `device.name`       | string         |                |             |
  | `device.kind`       | string         | `"desktop"`    |             |
  | `device.lastSeenAt` | number \| null |                |             |
  | `device.revokedAt`  | number \| null |                |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "revoke_device",
      "arguments": {
        "deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: revoked Acme."
        }
      ],
      "structuredContent": {
        "device": {
          "id": "263a4dbe-4148-4fb8-8214-b0032339dbb9",
          "name": "Acme",
          "kind": "desktop",
          "lastSeenAt": 1790069400000,
          "revokedAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers devices revoke --device-id 263a4dbe-4148-4fb8-8214-b0032339dbb9
  ```
</CodeGroup>

## revoke\_package\_grant

**Take a send back.**

Removes the package from their list. **Anything already installed stays installed**: this un-sends a recommendation, it does not reach onto someone's disk.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Write · destructive · idempotent · no outside service                                                                                                         |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `POST https://api.doers.sh/v2/packages/{packageId}/grants/{grantId}/revoke`                                                                                   |
| CLI       | `doers installs revoke-package-grant`                                                                                                                         |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `revokePackageGrant`                                                                                                                                          |

### Input

| Field              | Type   | Required | Default | Allowed values | Description          |
| ------------------ | ------ | -------- | ------- | -------------- | -------------------- |
| `packageId` (path) | string | yes      |         | UUID           | Identifier of a row. |
| `grantId` (path)   | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field     | Type    | Allowed values | Description |
  | --------- | ------- | -------------- | ----------- |
  | `revoked` | boolean |                |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "revoke_package_grant",
      "arguments": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
        "grantId": "3492ad65-d05a-473f-8f8c-825521eeb41a"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: taken back."
        }
      ],
      "structuredContent": {
        "revoked": true
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs revoke-package-grant --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e --grant-id 3492ad65-d05a-473f-8f8c-825521eeb41a
  ```
</CodeGroup>

## submit\_for\_review

**Offer a version for Discover.**

Submits one frozen version for review. The version must already be published, carry a licence and declare its permissions: nothing is licensed or declared on your behalf.

**A submission does not disturb what Discover already serves**: the approved version stays live until a reviewer admits the new one. Submitting again replaces a pending submission for the same package.

|           |                                                                                                                                                                                                       |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                                                                                                                                            |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                                                                       |
| REST      | `POST https://api.doers.sh/v2/marketplace/submissions`                                                                                                                                                |
| CLI       | `doers marketplace submit-for-review`                                                                                                                                                                 |
| Touches   | `categories`, `installs`, `listingCategories`, `listings`, `packageReports`, `packageVersions`, `packageViews`, `publishers`, `reviews`, `safetyRestrictions`, `sharedPackages`, `versionPermissions` |
| Operation | `submitForReview`                                                                                                                                                                                     |

### Input

| Field       | Type    | Required | Default | Allowed values                        | Description                                                |
| ----------- | ------- | -------- | ------- | ------------------------------------- | ---------------------------------------------------------- |
| `packageId` | string  | yes      |         | UUID                                  | The package to submit.                                     |
| `version`   | integer | yes      |         | -9007199254740991 to 9007199254740991 | Which frozen version to offer. Not necessarily the newest. |

### Output

<Accordion title="Output fields">
  | Field                      | Type            | Allowed values                            | Description                                        |
  | -------------------------- | --------------- | ----------------------------------------- | -------------------------------------------------- |
  | `submission`               | object          |                                           |                                                    |
  | `submission.packageId`     | string          |                                           |                                                    |
  | `submission.version`       | integer         | -9007199254740991 to 9007199254740991     |                                                    |
  | `submission.state`         | string          | `none`, `pending`, `approved`, `rejected` | `none` when this package has never been submitted. |
  | `submission.reason`        | string \| null  |                                           | Why it was rejected. Null unless it was.           |
  | `submission.licence`       | string \| null  | `mit`, `cc-by-4.0`                        |                                                    |
  | `submission.submittedAt`   | number \| null  |                                           |                                                    |
  | `submission.decidedAt`     | number \| null  |                                           |                                                    |
  | `submission.listedVersion` | integer \| null | -9007199254740991 to 9007199254740991     |                                                    |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "submit_for_review",
      "arguments": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
        "version": 3
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: v3 submitted for review."
        }
      ],
      "structuredContent": {
        "submission": {
          "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
          "version": 3,
          "state": "none",
          "reason": "Notes for the Acme launch.",
          "licence": "mit",
          "submittedAt": 1790069400000,
          "decidedAt": 1790069400000,
          "listedVersion": 3
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers marketplace submit-for-review --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e --version 3
  ```
</CodeGroup>

## uninstall\_package

**Uninstall.**

Forgets the install. The client removes the files it wrote.

|           |                                                                                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Write · destructive · idempotent · no outside service                                                                                                         |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                               |
| REST      | `DELETE https://api.doers.sh/v2/installs/{installId}`                                                                                                         |
| CLI       | `doers installs uninstall-package`                                                                                                                            |
| Touches   | `installConsents`, `installerLedger`, `installs`, `packageGrants`, `packageVersions`, `publishers`, `reviews`, `sharedPackages`, `user`, `versionPermissions` |
| Operation | `uninstallPackage`                                                                                                                                            |

### Input

| Field              | Type   | Required | Default | Allowed values | Description          |
| ------------------ | ------ | -------- | ------- | -------------- | -------------------- |
| `installId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field       | Type   | Allowed values | Description |
  | ----------- | ------ | -------------- | ----------- |
  | `packageId` | string |                |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "uninstall_package",
      "arguments": {
        "installId": "1e142e62-77b1-4b7e-8110-478a24caee8f"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: uninstalled."
        }
      ],
      "structuredContent": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers installs uninstall-package --install-id 1e142e62-77b1-4b7e-8110-478a24caee8f
  ```
</CodeGroup>

## unpublish\_package

**Take a package down.**

The public address stops resolving and nobody new can install it. **Existing installs are untouched**: what someone already has on their disk is theirs, and taking it back is not something publishing gave you the right to do.

|           |                                                                                  |
| --------- | -------------------------------------------------------------------------------- |
| Kind      | Write · destructive · idempotent · no outside service                            |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)  |
| REST      | `POST https://api.doers.sh/v2/packages/{packageId}/unpublish`                    |
| CLI       | `doers packages unpublish`                                                       |
| Touches   | `packageVersionFiles`, `packageVersions`, `sharedPackages`, `versionPermissions` |
| Operation | `unpublishPackage`                                                               |

### Input

| Field              | Type   | Required | Default | Allowed values | Description          |
| ------------------ | ------ | -------- | ------- | -------------- | -------------------- |
| `packageId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field                   | Type           | Allowed values                        | Description                                                     |
  | ----------------------- | -------------- | ------------------------------------- | --------------------------------------------------------------- |
  | `package`               | object         |                                       |                                                                 |
  | `package.id`            | string         |                                       |                                                                 |
  | `package.kind`          | string         | `agent`, `note`, `folder`             | An agent and its notes, a note on its own, or a folder of them. |
  | `package.slug`          | string         |                                       |                                                                 |
  | `package.name`          | string         |                                       |                                                                 |
  | `package.emoji`         | string \| null |                                       |                                                                 |
  | `package.summary`       | string         |                                       |                                                                 |
  | `package.latestVersion` | integer        | -9007199254740991 to 9007199254740991 |                                                                 |
  | `package.fileCount`     | integer        | -9007199254740991 to 9007199254740991 | Files in the version currently published.                       |
  | `package.published`     | boolean        |                                       | `false` once taken down. Existing installs are unaffected.      |
  | `package.createdAt`     | number         |                                       | Epoch milliseconds.                                             |
  | `package.updatedAt`     | number         |                                       | Epoch milliseconds.                                             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "unpublish_package",
      "arguments": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: Acme taken down."
        }
      ],
      "structuredContent": {
        "package": {
          "id": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
          "kind": "agent",
          "slug": "acme",
          "name": "Acme",
          "emoji": "rocket",
          "summary": "Notes for the Acme launch.",
          "latestVersion": 3,
          "fileCount": 3,
          "published": true,
          "createdAt": 1790069400000,
          "updatedAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers packages unpublish bc4a7118-0870-4794-8155-fbb02f4b0a2e
  ```
</CodeGroup>

## withdraw\_listing

**Take your Agent out of Discover.**

Stops offering it in Discover. **Existing installs keep working**: withdrawing un-lists, it does not reach onto anybody's disk or revoke what they already accepted.

|           |                                                                                                                                                                                                       |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Kind      | Write · destructive · no outside service                                                                                                                                                              |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`)                                                                                                                       |
| REST      | `POST https://api.doers.sh/v2/marketplace/listings/{packageId}/withdraw`                                                                                                                              |
| CLI       | `doers marketplace withdraw-listing`                                                                                                                                                                  |
| Touches   | `categories`, `installs`, `listingCategories`, `listings`, `packageReports`, `packageVersions`, `packageViews`, `publishers`, `reviews`, `safetyRestrictions`, `sharedPackages`, `versionPermissions` |
| Operation | `withdrawListing`                                                                                                                                                                                     |

### Input

| Field              | Type   | Required | Default | Allowed values | Description          |
| ------------------ | ------ | -------- | ------- | -------------- | -------------------- |
| `packageId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field       | Type    | Allowed values | Description |
  | ----------- | ------- | -------------- | ----------- |
  | `withdrawn` | boolean |                |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "withdraw_listing",
      "arguments": {
        "packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: withdrawn from Discover."
        }
      ],
      "structuredContent": {
        "withdrawn": true
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers marketplace withdraw-listing --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e
  ```
</CodeGroup>
