| Tool | What it does | Kind |
|---|---|---|
discover_packages | Search the reviewed catalogue | Read · idempotent · no outside service |
get_install_files | Read the files of an install | Read · idempotent · no outside service |
get_run_state | Get a run’s state | Read · idempotent · no outside service |
get_submission_status | Where your submission stands | Read · idempotent · no outside service |
list_categories | The catalogue’s categories | Read · idempotent · no outside service |
list_device_calls | Pull queued calls for this Mac | Read · idempotent · no outside service |
list_devices | List paired Macs | Read · idempotent · no outside service |
list_installs | What you have installed | Read · idempotent · no outside service |
list_package_grants | Who you sent a package to | Read · idempotent · no outside service |
list_packages | List what you have published | Read · idempotent · no outside service |
list_shared_with_me | Packages sent to you | Read · idempotent · no outside service |
preview_install_update | What an update would bring | Read · idempotent · no outside service |
preview_listing | Read a catalogue entry before installing it | Read · idempotent · no outside service |
preview_package | Read a package before installing it | Read · idempotent · no outside service |
apply_install_update | Move an install to the latest version | Write · idempotent · no outside service |
approve_run | Approve a run waiting on the Mac | Write · no outside service |
delegate_task | Queue a task for an agent on a paired Mac | Write · no outside service |
detach_install | Keep it, without the link | Write · destructive · no outside service |
grant_package_access | Send a package to someone | Write · no outside service |
install_package | Install a package from its address | Write · idempotent · no outside service |
publish_package | Publish a package, or a new version of one | Write · no outside service |
record_package_view | Record that a catalogue entry was opened | Write · idempotent · no outside service |
register_device | Register this desktop on the account | Write · no outside service |
reject_run | Reject a run waiting on the Mac | Write · no outside service |
reply_to_run | Send a message into a run on the Mac | Write · no outside service |
report_package | Report a package to the safety queue | Write · idempotent · no outside service |
report_run_state | The Mac publishes a run step | Write · no outside service |
revoke_device | Revoke a paired device | Write · no outside service |
revoke_package_grant | Take a send back | Write · destructive · idempotent · no outside service |
submit_for_review | Offer a version for Discover | Write · no outside service |
uninstall_package | Uninstall | Write · destructive · idempotent · no outside service |
unpublish_package | Take a package down | Write · destructive · idempotent · no outside service |
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
Output fields
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. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "discover_packages",
"arguments": {
"query": "Acme",
"limit": 24
}
}
}
{
"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."
}
}
}
doers marketplace discover-packages --query Acme --limit 24
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
Output fields
Output fields
| Field | Type | Allowed values | Description |
|---|---|---|---|
files | object[] | ||
files[].path | string | ||
files[].content | string |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_install_files",
"arguments": {
"installId": "1e142e62-77b1-4b7e-8110-478a24caee8f"
}
}
}
{
"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."
}
]
}
}
}
doers installs get-install-files --install-id 1e142e62-77b1-4b7e-8110-478a24caee8f
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
Output fields
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. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_run_state",
"arguments": {
"runId": "acba2551-2100-480b-86fc-3ccd14c65be5"
}
}
}
{
"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
}
}
}
}
doers devices get-run-state --run-id acba2551-2100-480b-86fc-3ccd14c65be5
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
Output fields
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 |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_submission_status",
"arguments": {
"packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
}
}
}
{
"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
}
}
}
}
doers marketplace get-submission-status --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e
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
Output fields
Output fields
| Field | Type | Allowed values | Description |
|---|---|---|---|
categories | object[] | ||
categories[].id | string | ||
categories[].slug | string | ||
categories[].label | string | ||
categories[].position | integer | -9007199254740991 to 9007199254740991 |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_categories",
"arguments": {}
}
}
{
"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
}
]
}
}
}
doers marketplace list-categories
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
Output fields
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. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_device_calls",
"arguments": {
"deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9"
}
}
}
{
"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
}
]
}
}
}
doers devices list-device-calls --device-id 263a4dbe-4148-4fb8-8214-b0032339dbb9
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
Output fields
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 |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_devices",
"arguments": {}
}
}
{
"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
}
]
}
}
}
doers devices list
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 withgetInstallFiles.
| 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
Output fields
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. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_installs",
"arguments": {}
}
}
{
"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
}
]
}
}
}
doers installs list
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
Output fields
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 |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_package_grants",
"arguments": {
"packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
}
}
}
{
"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
}
]
}
}
}
doers installs list-package-grants --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e
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
Output fields
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. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_packages",
"arguments": {
"includeUnpublished": false
}
}
}
{
"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
}
]
}
}
}
doers packages list --include-unpublished false
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
Output fields
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 |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_shared_with_me",
"arguments": {}
}
}
{
"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."
}
]
}
}
}
doers installs list-shared-with-me
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
Output fields
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 |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "preview_install_update",
"arguments": {
"installId": "1e142e62-77b1-4b7e-8110-478a24caee8f"
}
}
}
{
"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
}
}
}
doers installs preview-install-update --install-id 1e142e62-77b1-4b7e-8110-478a24caee8f
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
Output fields
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. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "preview_listing",
"arguments": {
"packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
}
}
}
{
"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."]
}
}
}
}
doers marketplace preview-listing --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e
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 aReferer.
| 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
Output fields
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 |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "preview_package",
"arguments": {
"token": "acme-example-token"
}
}
}
{
"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
}
}
}
}
doers installs preview acme-example-token
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: sendacceptedDigest 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
Output fields
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 |
Example
{
"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"
}
}
}
{
"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."
}
]
}
}
}
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"
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
Output fields
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. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "approve_run",
"arguments": {
"runId": "acba2551-2100-480b-86fc-3ccd14c65be5"
}
}
}
{
"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
}
}
}
}
doers devices approve-run --run-id acba2551-2100-480b-86fc-3ccd14c65be5
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
Output fields
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. |
Example
{
"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."
}
}
}
{
"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
}
}
}
}
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."
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
Output fields
Output fields
| Field | Type | Allowed values | Description |
|---|---|---|---|
name | string | ||
slug | string | ||
files | object[] | ||
files[].path | string | ||
files[].content | string |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "detach_install",
"arguments": {
"installId": "1e142e62-77b1-4b7e-8110-478a24caee8f"
}
}
}
{
"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."
}
]
}
}
}
doers installs detach --install-id 1e142e62-77b1-4b7e-8110-478a24caee8f
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
Output fields
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 |
Example
{
"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."
}
}
}
{
"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
}
}
}
}
doers installs grant-package-access --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e --target "Notes for the Acme launch."
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
Output fields
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 |
Example
{
"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"
}
}
}
{
"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
}
}
}
doers installs install-package acme-example-token --accepted-digest "Notes for the Acme launch. Acme Acme Acme Acme Acme Acme Acme Ac"
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
Output fields
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. |
Example
{
"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": ""
}
}
}
{
"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"
}
}
}
doers packages publish --kind agent --slug acme --name Acme --emoji rocket --summary ""
# files: structured argument(s) the CLI cannot pass as flags.
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
Output fields
Output fields
| Field | Type | Allowed values | Description |
|---|---|---|---|
recorded | boolean | False when this viewer already counted today. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "record_package_view",
"arguments": {
"packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
}
}
}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "OK: counted."
}
],
"structuredContent": {
"recorded": true
}
}
}
doers marketplace record-package-view --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e
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
Output fields
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 |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "register_device",
"arguments": {
"name": "Acme"
}
}
}
{
"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
}
}
}
}
doers devices register --name Acme
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
Output fields
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. |
Example
{
"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."
}
}
}
{
"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
}
}
}
}
doers devices reject-run --run-id acba2551-2100-480b-86fc-3ccd14c65be5 --note "Notes for the Acme launch."
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
Output fields
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. |
Example
{
"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."
}
}
}
{
"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
}
}
}
}
doers devices reply-to-run --run-id acba2551-2100-480b-86fc-3ccd14c65be5 --message "Notes for the Acme launch."
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
Output fields
Output fields
| Field | Type | Allowed values | Description |
|---|---|---|---|
reported | boolean | true | Always true: a repeat report is not an error. |
Example
{
"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."
}
}
}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "OK: reported."
}
],
"structuredContent": {
"reported": true
}
}
}
doers marketplace report-package --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e --reason malicious --detail "Notes for the Acme launch."
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
Output fields
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. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "report_run_state",
"arguments": {
"runId": "acba2551-2100-480b-86fc-3ccd14c65be5",
"state": "queued"
}
}
}
{
"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
}
}
}
}
doers devices report-run-state --run-id acba2551-2100-480b-86fc-3ccd14c65be5 --state queued
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
Output fields
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 |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "revoke_device",
"arguments": {
"deviceId": "263a4dbe-4148-4fb8-8214-b0032339dbb9"
}
}
}
{
"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
}
}
}
}
doers devices revoke --device-id 263a4dbe-4148-4fb8-8214-b0032339dbb9
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
Output fields
Output fields
| Field | Type | Allowed values | Description |
|---|---|---|---|
revoked | boolean |
Example
{
"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"
}
}
}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "OK: taken back."
}
],
"structuredContent": {
"revoked": true
}
}
}
doers installs revoke-package-grant --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e --grant-id 3492ad65-d05a-473f-8f8c-825521eeb41a
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
Output fields
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 |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "submit_for_review",
"arguments": {
"packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e",
"version": 3
}
}
}
{
"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
}
}
}
}
doers marketplace submit-for-review --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e --version 3
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
Output fields
Output fields
| Field | Type | Allowed values | Description |
|---|---|---|---|
packageId | string |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "uninstall_package",
"arguments": {
"installId": "1e142e62-77b1-4b7e-8110-478a24caee8f"
}
}
}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "OK: uninstalled."
}
],
"structuredContent": {
"packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
}
}
}
doers installs uninstall-package --install-id 1e142e62-77b1-4b7e-8110-478a24caee8f
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
Output fields
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. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "unpublish_package",
"arguments": {
"packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
}
}
}
{
"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
}
}
}
}
doers packages unpublish bc4a7118-0870-4794-8155-fbb02f4b0a2e
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
Output fields
Output fields
| Field | Type | Allowed values | Description |
|---|---|---|---|
withdrawn | boolean |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "withdraw_listing",
"arguments": {
"packageId": "bc4a7118-0870-4794-8155-fbb02f4b0a2e"
}
}
}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "OK: withdrawn from Discover."
}
],
"structuredContent": {
"withdrawn": true
}
}
}
doers marketplace withdraw-listing --package-id bc4a7118-0870-4794-8155-fbb02f4b0a2e