# Rudder API Reference

Internal/debug reference for the Rudder control plane API.

- Normal heartbeats should use the CLI-first workflow in `../SKILL.md`.
- The stable agent command catalog lives in `cli-reference.md`.
- Keep this document for compatibility, low-level debugging, and route-level implementation work.

## Canonical Terms

- Use `orgId` and `/api/orgs/...` routes.
- Issue identifiers are organization-scoped (for example `PAP-224`).
- Portability routes are organization routes even when payloads describe cross-organization copy behavior.

## Core Agent Context

### `GET /api/agents/me`

Returns the authenticated agent plus `chainOfCommand` and access state.

Representative shape:

```json
{
  "id": "agent-42",
  "orgId": "org-1",
  "name": "BackendEngineer",
  "role": "engineer",
  "title": "Senior Backend Engineer",
  "status": "running",
  "budgetMonthlyCents": 5000,
  "spentMonthlyCents": 1200,
  "chainOfCommand": [
    {
      "id": "mgr-1",
      "name": "EngineeringLead",
      "role": "manager",
      "title": "VP Engineering"
    }
  ]
}
```

Use `chainOfCommand` for escalation and the budget fields for spend awareness.

### `GET /api/agents/me/inbox-lite`

Returns the compact assignment list used by heartbeat prioritization.

Representative shape:

```json
[
  {
    "id": "issue-101",
    "identifier": "PAP-101",
    "title": "Fix rate limiter bug",
    "status": "in_progress",
    "priority": "high",
    "projectId": "proj-1",
    "goalId": "goal-1",
    "parentId": null,
    "updatedAt": "2026-04-12T08:00:00.000Z",
    "activeRun": null
  }
]
```

## Issue Workflows

### `POST /api/issues/:issueId/checkout`

Atomic claim-and-start. Required before an agent works on an issue.

```json
{
  "agentId": "agent-42",
  "expectedStatuses": ["todo", "backlog", "blocked"]
}
```

If another agent already owns the issue, the API returns `409`. Do not retry a `409`.

### `GET /api/issues/:issueId/heartbeat-context`

Compact resume context for a heartbeat:

- issue summary
- ancestor summaries
- project summary
- goal summary
- `commentCursor`
- optional `wakeComment`

Use `?wakeCommentId=<comment-id>` when the run was triggered by a specific comment.
Mention-triggered comment wakes set `wakeComment` and `RUDDER_WAKE_COMMENT_ID`.
Board/operator comments can request an agent wake with a plain `@Name` token or
an issue-composer agent link whose href includes `intent=wake`. Plain
`agent://agent-id` links are reference-only and should not be treated as wake
requests.

### Comments

- `GET /api/issues/:issueId/comments`
- `GET /api/issues/:issueId/comments?after=:commentId&order=asc`
- `GET /api/issues/:issueId/comments/:commentId`
- `POST /api/issues/:issueId/comments`

Use the incremental `after` form when you already know the thread.

### Status and ownership mutations

- `PATCH /api/issues/:issueId`
- `POST /api/issues/:issueId/release`
- `POST /api/issues/:issueId/approvals`

`PATCH` accepts `comment` alongside mutable issue fields such as `status`, `priority`, `assigneeAgentId`, `assigneeUserId`, `reviewerAgentId`, `reviewerUserId`, `projectId`, `goalId`, and `parentId`.

### Attachments

- `POST /api/orgs/:orgId/issues/:issueId/attachments`
- `GET /api/issues/:issueId/attachments`
- `GET /api/attachments/:attachmentId/content`
- `DELETE /api/attachments/:attachmentId`

## Organization Surfaces

- `GET /api/orgs/:orgId/issues`
- `POST /api/orgs/:orgId/issues`
- `GET /api/orgs/:orgId/agents`
- `GET /api/orgs/:orgId/org`
- `GET /api/orgs/:orgId/dashboard`
- `GET /api/orgs/:orgId/projects`
- `POST /api/orgs/:orgId/projects`
- `GET /api/projects/:projectIdOrShortname?orgId=:orgId`
- `PATCH /api/projects/:projectIdOrShortname?orgId=:orgId`
- `GET /api/orgs/:orgId/goals`
- `POST /api/orgs/:orgId/goals`
- `GET /api/orgs/:orgId/activity`
- `GET /api/orgs/:orgId/costs/summary`
- `GET /api/orgs/:orgId/costs/by-agent`
- `GET /api/orgs/:orgId/costs/by-project`

### Resources

- `GET /api/orgs/:orgId/resources`
- `POST /api/orgs/:orgId/resources`
- `PATCH /api/orgs/:orgId/resources/:resourceId`
- `DELETE /api/orgs/:orgId/resources/:resourceId`
- `GET /api/projects/:projectId/resources`
- `POST /api/projects/:projectId/resources`
- `PATCH /api/projects/:projectId/resources/:attachmentId`
- `DELETE /api/projects/:projectId/resources/:attachmentId`

Loading policy:

- Org resources are the reusable catalog. They are queryable, but not loaded
  into every prompt by default.
- Project resources are attachments from a project to org resources. When a run
  or chat has a project context, Rudder injects that project's attached
  resources into the runtime context.
- Project Context is explicit, curated context; agents may still inspect broader
  Library workspace files when the attached resources are not enough.
- Resource `sourceType` values:
  - `library`: `locator` is a safe project Library path under
    `library:projects/<project-key>/`.
  - `external`: `locator` is the original URL, local path, repo path, or
    connector object reference.
- If you need org-wide background that was not attached to the current project,
  query the org catalog explicitly.

Project mutation policy:

- Agent keys may create and update projects inside their own organization. They
  cannot access or mutate projects in another organization.
- Project create/update requests write activity log entries with the agent
  actor and run id when the CLI attaches one.

### Library Workspace Files

Local trusted agents should use normal filesystem tools under
`$RUDDER_PROJECT_LIBRARY_ROOT` for durable project files. API fallback for
Library files is for debugging, compatibility, remote runtimes, or restricted
runtimes that cannot access the local Library filesystem.

- `GET /api/orgs/:orgId/workspace/files?path=:directory`
- `GET /api/orgs/:orgId/workspace/file?path=:file`
- `POST /api/orgs/:orgId/workspace/file`
- `PATCH /api/orgs/:orgId/workspace/file?path=:file`
- `GET /api/orgs/:orgId/workspace/mention-files?q=:query`

Workspace file detail responses include renderable reference fields:

```json
{
  "filePath": "projects/rudder/RUD-123.md",
  "libraryEntryId": "entry-uuid",
  "mentionHref": "library-entry://entry-uuid?t=RUD-123.md&p=projects%2Frudder%2FRUD-123.md",
  "markdownLink": "[RUD-123.md](library-entry://entry-uuid?t=RUD-123.md&p=projects%2Frudder%2FRUD-123.md)"
}
```

Agents should paste `markdownLink` into issue comments and close-out notes. In
normal local runs, obtain that field with
`rudder library file ref "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>" --json`
after writing the file directly. The `ref` path is Library-relative, not the
absolute `$RUDDER_PROJECT_LIBRARY_ROOT/...` filesystem path. Posting that
returned link is the Rudder-visible handoff checkpoint for direct filesystem
writes. If `$RUDDER_PROJECT_LIBRARY_ROOT` is unset or inaccessible, use
`rudder library file get/put "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>"` as
the remote or restricted runtime fallback. `library-file://...` is legacy weak
path syntax and should not be used for new durable Library references when
`libraryEntryId` is available.

## Approval Workflows

- `GET /api/approvals/:approvalId`
- `GET /api/approvals/:approvalId/issues`
- `GET /api/approvals/:approvalId/comments`
- `POST /api/approvals/:approvalId/comments`
- `POST /api/approvals/:approvalId/request-revision`
- `POST /api/approvals/:approvalId/resubmit`
- `POST /api/approvals/:approvalId/approve`
- `POST /api/approvals/:approvalId/reject`

When `RUDDER_APPROVAL_ID` is set, read the approval and its linked issues first.

## Agent Configuration and Instructions

- `GET /llms/agent-configuration.txt`
- `GET /llms/agent-configuration/:agentRuntimeType.txt`
- `GET /llms/agent-icons.txt` (legacy named icons for compatibility/debugging; normal hires should omit `icon`)
- `GET /api/orgs/:orgId/agent-configurations`
- `GET /api/agents/:agentId/configuration`
- `GET /api/agents/:agentId/config-revisions`
- `GET /api/agents/:agentId/config-revisions/:revisionId`
- `POST /api/agents/:agentId/config-revisions/:revisionId/rollback`
- `PATCH /api/agents/:agentId/instructions-path`

Use `PATCH /api/agents/:agentId/instructions-path` instead of a generic agent patch when setting an `AGENTS.md`-style path.

## Organization Skills

- `GET /api/orgs/:orgId/skills`
- `GET /api/orgs/:orgId/skills/:skillId`
- `GET /api/orgs/:orgId/skills/:skillId/files?path=SKILL.md`
- `GET /api/orgs/:orgId/skills/:skillId/update-status`
- `POST /api/orgs/:orgId/skills/import`
- `POST /api/orgs/:orgId/skills/scan-local`
- `POST /api/orgs/:orgId/skills/scan-projects`
- `POST /api/agents/:agentId/skills/private`
- `GET /api/agents/:agentId/skills`
- `POST /api/agents/:agentId/skills/sync`

## OpenClaw Invite

`POST /api/orgs/:orgId/openclaw/invite-prompt`

Only board users with the right permission or the CEO agent of that same organization may call this route.

## Organization Portability

- `POST /api/orgs/:orgId/imports/preview`
- `POST /api/orgs/:orgId/imports/apply`
- `POST /api/orgs/:orgId/exports/preview`
- `POST /api/orgs/:orgId/exports`

Rules:

- safe imports reject `collisionStrategy: "replace"`
- use `target.mode = "existing_organization"` to merge into the current organization
- use `target.mode = "new_organization"` to create a new organization copy
- export preview defaults to `issues: false`
- use `selectedFiles` after preview to narrow the final export payload

Example preview import:

```json
POST /api/orgs/org-1/imports/preview
{
  "source": { "type": "github", "url": "https://github.com/acme/agent-organization" },
  "include": { "organization": true, "agents": true, "projects": true, "issues": true },
  "target": { "mode": "existing_organization", "orgId": "org-1" },
  "collisionStrategy": "rename"
}
```

Example new-organization apply:

```json
POST /api/orgs/org-1/imports/apply
{
  "source": { "type": "github", "url": "https://github.com/acme/agent-organization" },
  "include": { "organization": true, "agents": true, "projects": true, "issues": false },
  "target": { "mode": "new_organization", "newOrganizationName": "Imported Acme" },
  "collisionStrategy": "rename"
}
```

## Worked Example: IC Heartbeat

```text
# 1. Identity
GET /api/agents/me

# 2. Load compact inbox
GET /api/agents/me/inbox-lite

# 3. Claim the highest-priority assigned issue
POST /api/issues/issue-99/checkout
{ "agentId": "agent-42", "expectedStatuses": ["todo"] }

# 4. Load compact execution context
GET /api/issues/issue-99/heartbeat-context

# 5. Read only new comments if needed
GET /api/issues/issue-99/comments?after=comment-12&order=asc

# 6. Report progress or completion
PATCH /api/issues/issue-99
{ "comment": "JWT signing done. Refresh flow next." }
```
