Add CEO-safe company portability flows

Expose CEO-scoped import/export preview and apply routes, keep safe imports non-destructive, add export preview-first UI behavior, and document the new portability workflows.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta
2026-03-18 21:54:10 -05:00
parent 685c7549e1
commit 51ca713181
18 changed files with 1166 additions and 96 deletions

View File

@@ -241,40 +241,67 @@ PATCH /api/agents/{agentId}/instructions-path
## Key Endpoints (Quick Reference)
| Action | Endpoint |
| ------------------------------------- | ------------------------------------------------------------------------------------------ |
| My identity | `GET /api/agents/me` |
| My compact inbox | `GET /api/agents/me/inbox-lite` |
| My assignments | `GET /api/companies/:companyId/issues?assigneeAgentId=:id&status=todo,in_progress,blocked` |
| Checkout task | `POST /api/issues/:issueId/checkout` |
| Get task + ancestors | `GET /api/issues/:issueId` |
| List issue documents | `GET /api/issues/:issueId/documents` |
| Get issue document | `GET /api/issues/:issueId/documents/:key` |
| Create/update issue document | `PUT /api/issues/:issueId/documents/:key` |
| Get issue document revisions | `GET /api/issues/:issueId/documents/:key/revisions` |
| Get compact heartbeat context | `GET /api/issues/:issueId/heartbeat-context` |
| Get comments | `GET /api/issues/:issueId/comments` |
| Get comment delta | `GET /api/issues/:issueId/comments?after=:commentId&order=asc` |
| Get specific comment | `GET /api/issues/:issueId/comments/:commentId` |
| Update task | `PATCH /api/issues/:issueId` (optional `comment` field) |
| Add comment | `POST /api/issues/:issueId/comments` |
| Create subtask | `POST /api/companies/:companyId/issues` |
| Generate OpenClaw invite prompt (CEO) | `POST /api/companies/:companyId/openclaw/invite-prompt` |
| Create project | `POST /api/companies/:companyId/projects` |
| Create project workspace | `POST /api/projects/:projectId/workspaces` |
| Set instructions path | `PATCH /api/agents/:agentId/instructions-path` |
| Release task | `POST /api/issues/:issueId/release` |
| List agents | `GET /api/companies/:companyId/agents` |
| List company skills | `GET /api/companies/:companyId/skills` |
| Import company skills | `POST /api/companies/:companyId/skills/import` |
| Scan project workspaces for skills | `POST /api/companies/:companyId/skills/scan-projects` |
| Sync agent desired skills | `POST /api/agents/:agentId/skills/sync` |
| Dashboard | `GET /api/companies/:companyId/dashboard` |
| Search issues | `GET /api/companies/:companyId/issues?q=search+term` |
| Upload attachment (multipart, field=file) | `POST /api/companies/:companyId/issues/:issueId/attachments` |
| List issue attachments | `GET /api/issues/:issueId/attachments` |
| Get attachment content | `GET /api/attachments/:attachmentId/content` |
| Delete attachment | `DELETE /api/attachments/:attachmentId` |
| Action | Endpoint |
| ----------------------------------------- | ------------------------------------------------------------------------------------------ |
| My identity | `GET /api/agents/me` |
| My compact inbox | `GET /api/agents/me/inbox-lite` |
| My assignments | `GET /api/companies/:companyId/issues?assigneeAgentId=:id&status=todo,in_progress,blocked` |
| Checkout task | `POST /api/issues/:issueId/checkout` |
| Get task + ancestors | `GET /api/issues/:issueId` |
| List issue documents | `GET /api/issues/:issueId/documents` |
| Get issue document | `GET /api/issues/:issueId/documents/:key` |
| Create/update issue document | `PUT /api/issues/:issueId/documents/:key` |
| Get issue document revisions | `GET /api/issues/:issueId/documents/:key/revisions` |
| Get compact heartbeat context | `GET /api/issues/:issueId/heartbeat-context` |
| Get comments | `GET /api/issues/:issueId/comments` |
| Get comment delta | `GET /api/issues/:issueId/comments?after=:commentId&order=asc` |
| Get specific comment | `GET /api/issues/:issueId/comments/:commentId` |
| Update task | `PATCH /api/issues/:issueId` (optional `comment` field) |
| Add comment | `POST /api/issues/:issueId/comments` |
| Create subtask | `POST /api/companies/:companyId/issues` |
| Generate OpenClaw invite prompt (CEO) | `POST /api/companies/:companyId/openclaw/invite-prompt` |
| Create project | `POST /api/companies/:companyId/projects` |
| Create project workspace | `POST /api/projects/:projectId/workspaces` |
| Set instructions path | `PATCH /api/agents/:agentId/instructions-path` |
| Release task | `POST /api/issues/:issueId/release` |
| List agents | `GET /api/companies/:companyId/agents` |
| List company skills | `GET /api/companies/:companyId/skills` |
| Import company skills | `POST /api/companies/:companyId/skills/import` |
| Scan project workspaces for skills | `POST /api/companies/:companyId/skills/scan-projects` |
| Sync agent desired skills | `POST /api/agents/:agentId/skills/sync` |
| Preview CEO-safe company import | `POST /api/companies/:companyId/imports/preview` |
| Apply CEO-safe company import | `POST /api/companies/:companyId/imports/apply` |
| Preview company export | `POST /api/companies/:companyId/exports/preview` |
| Build company export | `POST /api/companies/:companyId/exports` |
| Dashboard | `GET /api/companies/:companyId/dashboard` |
| Search issues | `GET /api/companies/:companyId/issues?q=search+term` |
| Upload attachment (multipart, field=file) | `POST /api/companies/:companyId/issues/:issueId/attachments` |
| List issue attachments | `GET /api/issues/:issueId/attachments` |
| Get attachment content | `GET /api/attachments/:attachmentId/content` |
| Delete attachment | `DELETE /api/attachments/:attachmentId` |
## Company Import / Export
Use the company-scoped routes when a CEO agent needs to inspect or move package content.
- CEO-safe imports:
- `POST /api/companies/{companyId}/imports/preview`
- `POST /api/companies/{companyId}/imports/apply`
- Allowed callers: board users and the CEO agent of that same company.
- Safe import rules:
- existing-company imports are non-destructive
- `replace` is rejected
- collisions resolve with `rename` or `skip`
- issues are always created as new issues
- CEO agents may use the safe routes with `target.mode = "new_company"` to create a new company directly. Paperclip copies active user memberships from the source company so the new company is not orphaned.
For export, preview first and keep tasks explicit:
- `POST /api/companies/{companyId}/exports/preview`
- `POST /api/companies/{companyId}/exports`
- Export preview defaults to `issues: false`
- Add `issues` or `projectIssues` only when you intentionally need task files
- Use `selectedFiles` to narrow the final package to specific agents, skills, projects, or tasks after you inspect the preview inventory
## Searching Issues

View File

@@ -39,6 +39,72 @@ Detailed reference for the Paperclip control plane API. For the core heartbeat p
Use `chainOfCommand` to know who to escalate to. Use `budgetMonthlyCents` and `spentMonthlyCents` to check remaining budget.
### Company Portability
CEO-safe package routes are company-scoped:
- `POST /api/companies/:companyId/imports/preview`
- `POST /api/companies/:companyId/imports/apply`
- `POST /api/companies/:companyId/exports/preview`
- `POST /api/companies/:companyId/exports`
Rules:
- Allowed callers: board users and the CEO agent of that same company
- Safe import routes reject `collisionStrategy: "replace"`
- Existing-company safe imports only create new entities or skip collisions
- `new_company` safe imports are allowed and copy active user memberships from the source company
- Export preview defaults to `issues: false`; add task selectors explicitly when needed
- Use `selectedFiles` on export to narrow the final package after previewing the inventory
Example safe import preview:
```json
POST /api/companies/company-1/imports/preview
{
"source": { "type": "github", "url": "https://github.com/acme/agent-company" },
"include": { "company": true, "agents": true, "projects": true, "issues": true },
"target": { "mode": "existing_company", "companyId": "company-1" },
"collisionStrategy": "rename"
}
```
Example new-company safe import:
```json
POST /api/companies/company-1/imports/apply
{
"source": { "type": "github", "url": "https://github.com/acme/agent-company" },
"include": { "company": true, "agents": true, "projects": true, "issues": false },
"target": { "mode": "new_company", "newCompanyName": "Imported Acme" },
"collisionStrategy": "rename"
}
```
Example export preview without tasks:
```json
POST /api/companies/company-1/exports/preview
{
"include": { "company": true, "agents": true, "projects": true }
}
```
Example narrowed export with explicit tasks:
```json
POST /api/companies/company-1/exports
{
"include": { "company": true, "agents": true, "projects": true, "issues": true },
"selectedFiles": [
"COMPANY.md",
"agents/ceo/AGENTS.md",
"skills/paperclip/SKILL.md",
"tasks/pap-42/TASK.md"
]
}
```
### Issue with Ancestors (`GET /api/issues/:issueId`)
Includes the issue's `project` and `goal` (with descriptions), plus each ancestor's resolved `project` and `goal`. This gives agents full context about where the task sits in the project/goal hierarchy.

View File

@@ -149,3 +149,9 @@ curl -sS -X POST "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/agents"
- Built-in Paperclip runtime skills are still added automatically when required by the adapter.
- If a reference is missing or ambiguous, the API returns `422`.
- Prefer linking back to the relevant issue, approval, and agent when you comment about skill changes.
- Use company portability routes when you need whole-package import/export, not just a skill:
- `POST /api/companies/:companyId/imports/preview`
- `POST /api/companies/:companyId/imports/apply`
- `POST /api/companies/:companyId/exports/preview`
- `POST /api/companies/:companyId/exports`
- Use skill-only import when the task is specifically to add a skill to the company library without importing the surrounding company/team/package structure.