Merge pull request #19 from paperclipai/release/v2026.529.0

Release docs for paperclip v2026.529.0
This commit is contained in:
Aron Prins authored and GitHub committed 2026-05-30 19:27:21 +02:00
commit 7e14aeed6d
100 files changed
+988 -164

No files matched your search

+4 -4
View File
@@ -1,9 +1,9 @@
{
"branch_mode": "release",
"branch_mode": "nightly",
"base_release_tag": "v2026.525.0",
"base_release_sha": "60efa38f868e838e9af2e2168daf0c70afefb9e6",
"last_seen_parent_sha": "60efa38f868e838e9af2e2168daf0c70afefb9e6",
"last_applied_manifest_hash": "d53b54fba4571a8b0b20804be47ad0f8a729dcd0e1a5cd87b7cb6081c5da4c09",
"last_run_at": "2026-05-25T00:00:00Z",
"last_seen_parent_sha": "911a1e8b0d24205acd5006e837a5c5e8c4bfb447",
"last_applied_manifest_hash": "fe5efa1eb271efe303da514bb4e903fd722ae78a8e065c9692d01438d251adc6",
"last_run_at": "2026-05-30T09:15:12Z",
"last_run_outcome": "applied"
}
+41 -124
View File
@@ -2,149 +2,66 @@
> Regenerated by `/sync-docs` every nightly run. Cumulative from `base_release_tag`.
- **Base release tag:** `v2026.517.0`
- **Parent window:** `v2026.517.0` → parent `master` HEAD `e3c875c`, effective cutoff `c91a062` (24h quarantine)
- **Commits in window:** 21 (8 commits in quarantine, deferred to next run)
- **Doc-relevant manifest entries:** 14
- **Base release tag:** `v2026.525.0`
- **Parent window:** `v2026.525.0` → parent `master` HEAD `911a1e8`, effective cutoff `524e18b` (24h quarantine)
- **Commits in window:** 9 effective (5 commits in quarantine, deferred to next run)
- **Doc-relevant manifest entries:** 3 new this run (3 prior-run entries re-derived by cumulative diff, already applied)
- **Drift candidates:** 0 (check-drift.mjs against master)
- **Reconciliation candidates:** 0 (all 13 prior entries still in cumulative diff)
- **Genuine new dirs (rename-checked):** `packages/plugins/sandbox-providers/modal`
- **Reconciliation candidates:** 0 (cumulative base is the release tag; all entries are net-new or already applied)
- **Genuine new dirs (rename-checked):** none
## Auto-merge
_None._ The env-vars watcher matched only `vitest.config.ts` files (false positives from `packages/**/config.ts` glob) — skipped.
_None._ No `.env.example` / config / env-schema changes in the window — the env-vars watcher matched nothing.
## PR-tier
## Already applied (prior run, commit `51b9fe3`)
### 1. New Modal sandbox provider plugin (`#6245`, `#6290`)
These re-appear in the cumulative diff but are already documented; not re-edited this run.
- **Watcher:** adapters (sandbox-providers)
- **Parent files:** `packages/plugins/sandbox-providers/modal/**` (9 added)
- **Change kind:** added — genuine new dir, confirmed by `detect-renames.mjs`
- **Docs targets:** new page `docs/reference/adapters/modal.md` (already exists from prior nav stub); mention in `docs/reference/adapters/sandbox-providers.md`; mirror an existing sandbox-provider page as a structure neighbour.
- **Evidence:** New `packages/plugins/sandbox-providers/modal/{plugin.ts,manifest.ts,worker.ts,README.md}`. README documents install (`@paperclipai/plugin-modal`), config fields (`appName`, `image`, `tokenId`, `tokenSecret`, `environment`, `workdir`, `sandboxTimeoutMs`, `idleTimeoutMs`, `execTimeoutMs`, `blockNetwork`, `cidrAllowlist`, `reuseLease`), reuse semantics (no native pause — `reuseLease: true` keeps billing running), and Node 22+ vendor support note (Node 20 best-effort).
1. Resource memberships — join/leave projects & agents (`#6677`)
2. Document annotations & comments (`#6733`)
3. Bundled plugins in plugin manager (`#6734`)
### 2. `worktree init --force` no longer wipes repo worktrees (`#6240`)
## PR-tier — applied this run
### 1. Skills CLI command group (`#6782`)
- **Watcher:** cli-commands
- **Parent files:** `cli/src/commands/worktree.ts` (+6/-1)
- **Change kind:** modified (behaviour fix)
- **Docs targets:** `docs/reference/cli/commands.md`, `docs/reference/cli/setup-commands.md` — wherever `paperclipai worktree init --force` is described.
- **Evidence:** The `--force` branch of `runWorktreeInit` now removes only `paths.configPath` and `paths.envPath` instead of recursively removing the whole `<repo>/.paperclip/` directory. `worktrees/` checkouts survive.
- **Parent files:** `cli/src/index.ts` (`registerSkillsCommands(program)`); `cli/src/commands/client/skills.ts` (new).
- **Change kind:** added — new `paperclipai skills` command tree.
- **Surface:** `skills browse|search|inspect|install|list|show|file|import|create|scan-projects|check|update|audit|reset|remove` plus the `skills agent list|sync|clear` subgroup.
- **Docs targets:** `docs/reference/cli/control-plane-commands.md` (new "Skills Commands" workflow section); `docs/reference/cli/commands.md` (full `skills` subcommand + flag reference).
- **Evidence:** All command names, arguments, flags, and defaults (e.g. `--path` default `SKILL.md`, `--kind bundled|optional`) copied verbatim from `skills.ts`.
### 3. Routine env runtime contract (`#6212`)
### 2. App-shipped skills catalog + lifecycle (`#6782`)
- **Watcher:** schemas, server-services (routines, secrets), shared-validators
- **Parent files:** `packages/db/src/migrations/0086_routine_env_runtime_contract.sql` (new); `packages/db/src/schema/routines.ts`; `packages/shared/src/validators/routine.ts`; `packages/shared/src/validators/secret.ts`; `packages/shared/src/types/routine.ts`; `server/src/services/routines.ts`; `server/src/services/secrets.ts`; `server/src/__tests__/qa-routine-secrets-e2e.test.ts` (new).
- **Change kind:** added (new env column + revision-pinned runs)
- **Docs targets:** `docs/how-to/create-a-daily-routine.md`, `docs/reference/api/secrets.md`, `docs/reference/deploy/secrets.md`.
- **Evidence:** Migration adds `routines.env jsonb` and `routine_runs.routine_revision_id uuid` (FK → `routine_revisions.id`, SET NULL on delete) plus `routine_runs_revision_idx`. Validator + service work wires routine env to secret bindings.
- **Watcher:** rest-routes, agent-skills, schemas, server-services
- **Parent files:** `server/src/routes/company-skills.ts` (new catalog + lifecycle routes); `server/src/services/skills-catalog.ts` (new); `packages/skills-catalog/**` (new package: bundled + optional SKILL.md bundles).
- **Change kind:** added.
- **Docs targets:** `docs/reference/skills.md` (new "App-shipped catalog" section + corrected versioning row); `docs/guides/org/skills.md` (friendly "install a ready-made skill" subsection).
- **Evidence:** Browse routes (auth-only, NOT company-scoped) `GET /api/skills/catalog`, `/api/skills/catalog/{catalogId}`, `/api/skills/catalog/{catalogId}/files`; lifecycle routes (company-scoped) `POST .../skills/install-catalog` (`{ catalogSkillId, slug?, force? }`), `.../skills/:skillId/audit`, `.../install-update`, `.../reset`. `CatalogSkillKind = bundled | optional`; `sourceKind: catalog`. Soft holds (local mods, `force`-overridable) vs hard-stop audit findings.
### 4. New workspace diff viewer plugin (`#6071`) + polish (`#6383`)
### 3. Private browser first-admin claim (`#6755`)
- **Watcher:** plugin-sdk (new bundled plugin under `packages/plugins/plugin-workspace-diff/`)
- **Parent files:** `packages/plugins/plugin-workspace-diff/**` (18 added; further refined in `#6383`)
- **Change kind:** added — new first-party plugin; subsequent polish for controls + base-ref + sticky headers
- **Docs targets:** `docs/reference/plugins/workspace-diff.md` (exists; polish from `#6383` applied this run — Controls section, view fallback, sticky toolbar).
- **Evidence:** New plugin package with `manifest.ts`, `worker.ts`, `src/ui/index.tsx`, `src/workspace-diff.ts`, plus comprehensive tests. `#6383` adds split/unified toggle, `defaultBaseRef` prefill, sticky toolbar (`sticky top-0 z-30` in `src/ui/index.tsx`), and `head → working-tree` fallback when no base ref is set.
- **Watcher:** rest-routes, server-services
- **Parent files:** `server/src/routes/access.ts` (new `/bootstrap/claim` route); `server/src/first-admin-claim.ts` (new).
- **Change kind:** added.
- **Docs targets:** `docs/reference/api/instance-admin.md` ("Claim first instance admin" section); `docs/guides/getting-started/installation.md` (note under the private/Tailscale variation).
- **Evidence:** `POST /api/bootstrap/claim` — gated to `deploymentMode = authenticated` + `deploymentExposure = private` (else 404); requires signed-in browser session (else 401); promotes first signed-in user to `instance_admin` atomically; 409 if already claimed; success `{ claimed: true, userId }`.
### 5. Plugin SDK surface changes (`#6261`, plus rolling refactor)
## Considered, not documented
- **Watcher:** plugin-sdk
- **Parent files:** `packages/plugins/sdk/src/{host-client-factory,index,protocol,testing,types,worker-rpc-host}.ts`; parent `doc/plugins/PLUGIN_AUTHORING_GUIDE.md`, `doc/plugins/PLUGIN_SPEC.md`, `doc/plugins/LOCAL_PLUGIN_DEVELOPMENT.md`.
- **Change kind:** modified (public surface drift + new "managed resources" authoring concept)
- **Docs targets:** `docs/reference/plugins/sdk.md`, `docs/how-to/develop-a-plugin-locally.md`.
- **Evidence:** Six SDK source files touched; parent's PLUGIN_AUTHORING_GUIDE.md was updated for managed resources. Audit exported types/functions from `sdk/src/index.ts` against our reference page.
- **Accepted-plan decomposition exact-once guards (`#6831`)** — internal reliability/correctness guard with UI state; no user-facing surface to document.
- **CI runner Chrome for headless workflows (`#6967`, `524e18b0`)** — CI-only; not product-facing.
### 6. `environmentProbe` RPC timeout raised to 120s (`#6289`)
## ⚠ Drift
- **Watcher:** plugin-sdk
- **Parent files:** plugin SDK / host (cold-start sandboxes — Modal in particular)
- **Change kind:** modified (timeout default)
- **Docs targets:** any page that quotes a probe-timeout default (search before editing). If none, this is context-only.
- **Evidence:** Commit `e5a0f5de` — "raise environmentProbe RPC timeout to 120s for cold-start sandboxes."
_None._
### 7. SecretBindingPicker wired into JsonSchemaForm `secret-ref` fields (`#6339`)
## ↻ Renames detected
- **Watcher:** web-ui
- **Parent files:** `ui/src/components/JsonSchemaForm.tsx`, `ui/src/components/IssueProperties.tsx`, several plugin pages.
- **Change kind:** modified (user-visible UX — any JSON schema form field marked `format: secret-ref` now renders a binding picker).
- **Docs targets:** `docs/reference/api/secrets.md` if it mentions `secret-ref` schemas; plugin SDK reference if `secret-ref` is part of the manifest contract.
_None._
### 8. Provider vault secrets UX — AWS discovery + vault removal (`#6381`)
## In quarantine (deferred to next run, <24h old at run time)
- **Watcher:** web-ui, rest-routes, server-services (secrets)
- **Parent files:** `server/src/routes/secrets.ts` (+ new `POST /api/companies/:companyId/secret-provider-configs/discovery/preview` endpoint); `server/src/services/secrets.ts`; `packages/shared/src/validators/secret.ts`; `ui/src/pages/Secrets.tsx`; `ui/src/pages/Secrets.render.test.tsx`.
- **Change kind:** added (new endpoint + UX) and modified (removal flow polish)
- **Docs targets:** `docs/reference/api/secrets.md` (document the new `/secret-provider-configs/discovery/preview` endpoint and the existing `/secret-provider-configs/*` family which is currently undocumented); `docs/reference/deploy/secrets.md` (operator guidance for AWS Secrets Manager provider vault setup); `docs/administration/` (Secrets page UX for vault discovery prefill + removal confirmation).
- **Evidence:** New route at `/companies/:companyId/secret-provider-configs/discovery/preview` with `secretProviderConfigDiscoveryPreviewSchema`. Provider-vault DELETE returns `404 Provider vault not found` on missing IDs. Storybook fixtures + dark+light screenshots captured in parent PR #6381.
### 9. Guard cheap recovery model usage (`#6371`)
- **Watcher:** server-services (recovery), schemas
- **Parent files:** `server/src/services/recovery/{model-profile-hint,run-liveness-continuations,service,successful-run-handoff}.ts` (+ tests); `server/src/services/heartbeat.ts`; `server/src/services/issues.ts`; `server/src/services/productivity-review.ts`.
- **Change kind:** modified (recovery-path invariant: cheap model profile only repairs status/liveness, never propagates to source-work continuations).
- **Docs targets:** wherever recovery / cheap-model behaviour is described (search `docs/administration/`, `docs/reference/`). If currently undocumented, this is context-only — the invariant is operator-visible only when configured.
- **Evidence:** New `model-profile-hint.test.ts` and updates to `successful-run-handoff.ts` guard against cheap-profile hints following deliverable mutations.
### 10. Hide sandbox-provider plugins from Instance Settings sidebar (`#6341`)
- **Watcher:** web-ui
- **Parent files:** `ui/src/components/Sidebar*.tsx`, `ui/src/pages/PluginManager.tsx`.
- **Change kind:** modified (sidebar UX — sandbox-provider-only plugins no longer appear as their own sidebar rows; they already redirect to the Environments page).
- **Docs targets:** `docs/administration/plugins.md` if it describes per-plugin sidebar entries (a quick scan suggests not). Affects any screenshot that shows Settings sidebar with a sandbox-provider plugin listed.
### 11. Cloud tenant import without browser origin (`#6378`)
- **Watcher:** server-services
- **Parent files:** board-mutation guard / cloud tenant import path.
- **Change kind:** modified (CSRF exemption for trusted `source: "cloud_tenant"` actors).
- **Docs targets:** none — internal trust boundary. Context-only.
### 12. UI + dev-ops quality-of-life polish (`#6384`)
- **Watcher:** web-ui
- **Parent files:** many `ui/src/components/*.tsx`, `ui/src/pages/*.tsx`, `ui/src/components/DevRestartBanner.tsx`, `ui/src/components/InstanceSidebar.tsx`, `ui/src/components/SidebarAccountMenu.tsx`, `ui/src/components/MissingPluginTabPlaceholder.tsx`, etc.
- **Change kind:** modified (cosmetic + dev-ops affordances — relaxed 44px touch targets for small inline widgets, new dev restart banner, placeholder for missing plugin tabs).
- **Docs targets:** none in particular — context-only. May invalidate screenshots when `depends_on` gets populated.
### 13. Remove planning badge from inbox issue rows (`#6269`, PAP-9691) + textarea/autocomplete fixes (`#6222`, `#6311`)
- **Watcher:** web-ui
- **Parent files:** `ui/src/components/IssueRow.tsx`, `IssuesList.tsx`, `ui/src/components/NewIssueDialog.tsx`, `ui/src/context/EditorAutocompleteContext.tsx`, `ui/src/pages/Secrets.tsx`, `ui/src/components/ui/textarea.tsx`.
- **Change kind:** modified (small UX fixes).
- **Docs targets:** none directly. Manual-review flag for any user-guide screenshots showing affected components.
### 14. Runtime control-plane fixes (`#6380`)
- **Watcher:** server-services, rest-routes
- **Parent files:** `server/src/http/body-limits.ts` (new); `server/src/routes/company-import-paths.ts` (new); `server/src/routes/{companies,issues}.ts`; `server/src/services/{issues,issue-thread-interactions,plugin-lifecycle,plugin-worker-manager}.ts`; `server/src/middleware/error-handler.ts`; `server/src/app.ts`; `packages/db/src/backup-lib.ts`.
- **Change kind:** modified (correctness fixes — issue list pagination + scheduled retry comment handling, hot-reload re-applies pending plugin migrations, plugin-schema worktree seed restore, public tenant DB startup hardening, stale request-confirmation expiry after user comments, feedback export shutdown hardening, plugin worker `error` event listener guard).
- **Docs targets:** none directly — overwhelmingly internal correctness. One operator-visible constant introduced: `PORTABLE_JSON_BODY_LIMIT = 64mb` on portable import endpoints (vs `DEFAULT_JSON_BODY_LIMIT = 10mb` elsewhere). Worth a one-line note in `docs/reference/api/companies.md` or `docs/reference/deploy/limits.md` if/when those describe request size limits, but the constants are hard-coded (not env-tunable) so this is low priority. Otherwise context-only.
- **Evidence:** New `server/src/http/body-limits.ts` defines the two limits; new `server/src/routes/company-import-paths.ts` centralises the `/api/companies/import` route path. Commit message at `c91a062` enumerates each fix.
## Context-only (no direct edits)
- `chore(lockfile)` (`#6263`), Docker copy fix (`#6338`), `[codex] Roll up May 17 branch changes` (`#6210`) — internal/CI.
- Heartbeat service tests churn — many `server/src/__tests__/heartbeat-*` files updated. No documented contract change in window beyond the routine-revision wiring already captured in entry 3.
- Plugin-llm-wiki internal refinements (`ui/app.tsx`, `wiki/core.ts`) — review separately before touching `docs/reference/plugins/llm-wiki.md`.
## Edits applied this run
- `docs/reference/plugins/workspace-diff.md` — added "Controls in the Changes tab" subsection covering split/unified toggle, working-tree vs against-ref toggle, base-ref input with `defaultBaseRef` prefill, sticky toolbar. Also noted the `head → working-tree` fallback when no base ref is set. Verified against `packages/plugins/plugin-workspace-diff/src/ui/index.tsx` at parent `f2575305`.
## Notes
- 21 of 29 cumulative parent commits processed; 8 are within 24h quarantine (now=2026-05-23T08:31Z, cutoff=2026-05-22T08:31Z) — deferred to next nightly run. Quarantined commits include `#6386` (agent permissions plan), `#6547`/`#6548`/`#6549` (plugin runtime hardening + cloud upstream sync + import reliability), `#6550` (mobile board polish), `#6423` (wrapped-company issue prefix conflicts), `#6433` (invite page query-key fix), `#6560` (E2B sandbox upload/lease fix).
- Anchor-map mismatch found: watcher `db-migrations` lists `packages/db/migrations/**` but actual parent path is `packages/db/src/migrations/**`. Surface in next maintenance pass.
- Env-vars watcher matched two `vitest.config.ts` files — false positives from `packages/**/config.ts` glob. Consider tightening the watcher (e.g. `packages/*/src/config.ts`) or adding an exclude for `vitest.config.ts`.
- Rename detector reports `packages/plugins/sandbox-providers/modal` as a genuinely new dir (not a rename).
## Plugin SDK followups
<!-- TODO Items below were flagged during the SDK audit against parent c0c5a82 but could not be
fully verified against the current parent source in this pass. Spot-check before acting. -->
- TODO: `PluginRoutinesClient` is defined in `packages/plugins/sdk/src/types.ts` but not re-exported from `packages/plugins/sdk/src/index.ts`, while `ctx.routines` is reachable on `PluginContext`. Decide whether to add the type to the SDK export list upstream, or document the asymmetry permanently.
- TODO: `Routine` and `RoutineRun` are imported by the SDK from `@paperclipai/shared` and used in `PluginRoutinesClient` return types but are not re-exported from the SDK index. Plugin authors typing these returns must import from `@paperclipai/shared` directly — confirm and document if intentional.
- TODO: Verify whether any pre-managed-resources symbol names (e.g. older managed-agent helpers) were renamed in the `c0c5a82..f2575305` window. The current audit only spot-checked `index.ts` exports against the existing `sdk.md` symbol list.
`1f70fd9a` workspace finalize gates + no-remote-git enforcement (PAPA-430) · `5153b01a` Claude model refresh · `8014445b` v2026.529.0 release changelog · `aea35fe6` exe.dev config UX · `911a1e8b` continuation recovery retry streaks
+116 -14
View File
@@ -1,23 +1,125 @@
# Screenshots Pending — v2026.517.0
# Screenshots — pending recapture
> Regenerated by `/sync-docs` on release run for `v2026.517.0`.
> Regenerated by `/sync-docs` (release mode, v2026.529.0). Entries whose `depends_on` parent paths changed in the v2026.525.0 → v2026.529.0 window.
## Staleness detection: not actionable this run
- **Window:** `v2026.525.0` → `v2026.529.0` (parent `911a1e8`)
- **Stale entries:** 90 of 276
- **Recapture:** `npm run screenshots:refresh` (stale only) or `npm run screenshots:refresh:all` (full). Output PNGs land in a PR for human review — never auto-pushed.
All 274 entries in `docs/user-guides/screenshots/registry.json` have empty `depends_on` arrays, so the staleness check is a no-op. This is tracked in [`maintenance/follow-ups.md`](maintenance/follow-ups.md) under "Screenshot anchor population".
## `ui/src/components/AgentConfigForm.tsx` — 20
## UI surfaces that changed visually in v2026.517.0
- `dark/agents/adapter-type-dropdown.png`
- `dark/agents/budget-and-heartbeat-fields.png`
- `dark/agents/claude-local-config-filled.png`
- `dark/agents/codex-local-config.png`
- `dark/agents/heartbeat-toggle-disabled.png`
- `dark/agents/heartbeat-toggle-enabled.png`
- `dark/agents/http-adapter-config.png`
- `dark/agents/test-environment-fail.png`
- `dark/agents/test-environment-success.png`
- `dark/org/reassign.png`
- `light/agents/adapter-type-dropdown.png`
- `light/agents/budget-and-heartbeat-fields.png`
- `light/agents/claude-local-config-filled.png`
- `light/agents/codex-local-config.png`
- `light/agents/heartbeat-toggle-disabled.png`
- `light/agents/heartbeat-toggle-enabled.png`
- `light/agents/http-adapter-config.png`
- `light/agents/test-environment-fail.png`
- `light/agents/test-environment-success.png`
- `light/org/reassign.png`
These surfaces had material UI changes in this release. If you have screenshots of them in the registry, populate `depends_on` so the next sync flags them automatically — and consider re-capturing now:
## `ui/src/pages/AgentDetail.tsx` — 24
- **Kanban board view** of the Issues page — new density (`auto` / `comfortable` / `compact`), cold-lane mode (`auto` / `expanded` / `collapsed`), and column page-size controls. Source: `ui/src/components/KanbanBoard.tsx`, `ui/src/components/IssuesList.tsx`.
- **Issue documents section** — lock indicator on the document header, "redirected to derived document" state when an agent writes into a locked document, and live-refresh behaviour on create/update/restore/delete. Source: `ui/src/components/IssueDocumentsSection.tsx`, `ui/src/context/LiveUpdatesProvider.tsx`.
- **Issue detail page** general layout — touched alongside the documents section. Source: `ui/src/pages/IssueDetail.tsx`.
- `dark/agents/agent-detail-idle.png`
- `dark/agents/agent-detail-run-history.png`
- `dark/agents/agent-status-running.png`
- `dark/agents/budget.png`
- `dark/agents/configuration.png`
- `dark/agents/dashboard.png`
- `dark/agents/instructions.png`
- `dark/agents/run-history-in-progress.png`
- `dark/agents/run-transcript-view.png`
- `dark/agents/runs.png`
- `dark/agents/skills.png`
- `dark/costs/agent-budget-field.png`
- `light/agents/agent-detail-idle.png`
- `light/agents/agent-detail-run-history.png`
- `light/agents/agent-status-running.png`
- `light/agents/budget.png`
- `light/agents/configuration.png`
- `light/agents/dashboard.png`
- `light/agents/instructions.png`
- `light/agents/run-history-in-progress.png`
- `light/agents/run-transcript-view.png`
- `light/agents/runs.png`
- `light/agents/skills.png`
- `light/costs/agent-budget-field.png`
## Earlier carry-over surfaces (still no screenshots)
## `ui/src/pages/Agents.tsx` — 6
From the previous release window, still pending capture:
- `dark/agents/agents-list-empty.png`
- `dark/agents/list.png`
- `dark/agents/new.png`
- `light/agents/agents-list-empty.png`
- `light/agents/list.png`
- `light/agents/new.png`
## `ui/src/pages/CompanySkills.tsx` — 12
- `dark/org/skills-list.png`
- `dark/skills/add-skill-dialog-confirm.png`
- `dark/skills/add-skill-dialog.png`
- `dark/skills/assign-to-agent.png`
- `dark/skills/file-inventory.png`
- `dark/skills/list.png`
- `light/org/skills-list.png`
- `light/skills/add-skill-dialog-confirm.png`
- `light/skills/add-skill-dialog.png`
- `light/skills/assign-to-agent.png`
- `light/skills/file-inventory.png`
- `light/skills/list.png`
## `ui/src/pages/InstanceExperimentalSettings.tsx` — 2
- `dark/settings/experimental.png`
- `light/settings/experimental.png`
## `ui/src/pages/IssueDetail.tsx` — 10
- `dark/issues/detail-activity.png`
- `dark/issues/detail-chat.png`
- `dark/issues/detail-sidebar.png`
- `dark/issues/list.png`
- `dark/tasks/task-detail-with-comments.png`
- `light/issues/detail-activity.png`
- `light/issues/detail-chat.png`
- `light/issues/detail-sidebar.png`
- `light/issues/list.png`
- `light/tasks/task-detail-with-comments.png`
## `ui/src/pages/PluginManager.tsx` — 4
- `dark/plugins/install.png`
- `dark/plugins/list.png`
- `light/plugins/install.png`
- `light/plugins/list.png`
## `ui/src/pages/ProjectDetail.tsx` — 10
- `dark/projects/budget.png`
- `dark/projects/configuration.png`
- `dark/projects/issues.png`
- `dark/projects/overview.png`
- `dark/projects/workspaces.png`
- `light/projects/budget.png`
- `light/projects/configuration.png`
- `light/projects/issues.png`
- `light/projects/overview.png`
- `light/projects/workspaces.png`
## `ui/src/pages/Projects.tsx` — 2
- `dark/projects/list.png`
- `light/projects/list.png`
- **Blocked Inbox tab** (`/inbox/blocked`).
- **Issue recovery action card** on issue detail.
- **Sibling navigation footer** on issue detail.
+12 -7
View File
@@ -1,5 +1,5 @@
---
paperclip_version: v2026.513.0
paperclip_version: v2026.529.0
---
# Plugins
@@ -20,7 +20,7 @@ The Plugin Manager lives under **Settings → Plugins**. It's the single place w
The page has two sections:
- **Available Plugins** — bundled examples shipped with your Paperclip checkout. Useful for seeing what plugins can do and for smoke-testing the plugin runtime on a fresh instance.
- **Available Plugins** — the plugins bundled with your Paperclip checkout, discovered automatically from the packages on disk. This includes the reference example plugins *and* first-party plugins like the LLM Wiki when they're part of your checkout. Each is labelled **Bundled**, and ones that aren't production-ready yet carry an **Experimental** badge. Useful for seeing what plugins can do and for smoke-testing the plugin runtime on a fresh instance.
- **Installed Plugins** — everything you've installed on this Paperclip instance. Each row shows the plugin name, its package and version, a short description, a status badge, and quick actions.
### Status badges
@@ -58,11 +58,16 @@ An errored plugin stays installed — you don't need to uninstall and reinstall
There are two ways to get a plugin into Paperclip.
**From the Available Plugins list.** Bundled example plugins ship inside the Paperclip repository. On the Plugin Manager page, scroll to the **Available Plugins** section and click **Install Example** next to the one you want. Paperclip installs it straight from the local checkout — no registry round trip. The same list is what `paperclipai plugin examples` returns from the CLI.
**From the Available Plugins list.** Bundled plugins ship inside the Paperclip repository. On the Plugin Manager page, scroll to the **Available Plugins** section and click **Install** next to the one you want. Paperclip installs it straight from the local checkout — no registry round trip.
> The Available Plugins list is intentionally just the **reference examples** below — it's not the full catalogue of first-party plugins. Real first-party plugins like the [LLM Wiki](../reference/plugins/llm-wiki.md) are published to npm and installed by full package name; see *By npm package name* below.
Paperclip builds this list by scanning the plugin packages in your checkout, so what you see depends on what's bundled. Two kinds of plugin show up here:
The examples that ship today:
- **Reference examples** — small, self-contained plugins that exist to demonstrate the runtime.
- **First-party plugins** — real plugins like the [LLM Wiki](../reference/plugins/llm-wiki.md) when they're vendored into your checkout. These are also published to npm, so on instances that don't bundle them you'd install by full package name instead; see *By npm package name* below.
First-party plugins that are still maturing carry an **Experimental** badge in this list — they work, but their behaviour or configuration may change between releases, so pin versions where you can.
The reference examples that ship today:
- **plugin-hello-world-example** — adds a Hello World widget to the dashboard. The minimum-viable plugin, useful as a reference.
- **plugin-file-browser-example** — adds a Files link to project sidebars and a file-browser tab to the project detail page, scoped to the project's workspace.
@@ -195,7 +200,7 @@ The full authoring path lives outside this guide:
- The `paperclip-create-plugin` skill scaffolds a new plugin package, including the manifest, worker, and a minimal UI surface.
- The Paperclip CLI (`paperclipai`) wraps common authoring tasks — scaffolding, dev serving, building, and publishing. See the [CLI overview](../guides/getting-started/your-first-agent.md) and the plugin adapter documentation in the main Paperclip repository for details.
Once your plugin builds, install it with **Install Plugin** on the Plugin Manager page the same way you'd install anything else. During development you can also point the installer at a local path — the **Install Example** flow is the same mechanism, just targeted at `packages/plugins/examples/`.
Once your plugin builds, install it with **Install Plugin** on the Plugin Manager page the same way you'd install anything else. During development you can also point the installer at a local path — the bundled **Install** flow is the same mechanism, just targeted at a package inside your checkout.
### Developing plugins locally
@@ -219,7 +224,7 @@ A cheat sheet for operating the Plugin Manager day-to-day:
| Goal | Action |
|---|---|
| Try a bundled example | Plugin Manager → Available Plugins → **Install Example** |
| Try a bundled plugin | Plugin Manager → Available Plugins → **Install** |
| Install a third-party plugin | Plugin Manager → **Install Plugin** → enter npm package name |
| Temporarily stop a plugin's jobs | Click the power button on the plugin row (green to grey) |
| Bring a plugin back online | Click the power button again, or **Enable** from the detail page |
+12 -1
View File
@@ -1,5 +1,5 @@
---
paperclip_version: v2026.517.0
paperclip_version: v2026.529.0
---
# Issues
@@ -341,6 +341,17 @@ Once you're happy with a document — typically right after you approve a plan
Unlock the document from the same header control when you want writes to resume on the original key.
#### Annotating a document
Sometimes a comment in the Chat tab is too blunt — you want to point at one sentence in the plan, not the whole thing. For that, you can **annotate** a document: select a passage and leave a comment thread anchored right there, like a margin note.
- **Select and comment.** Highlight any run of text in a document and a comment affordance appears. Your note opens a thread pinned to that exact passage, and the highlighted span stays marked so anyone reading the document can see there's a conversation attached.
- **Threads and replies.** Each annotation is a thread. You and the agent can go back and forth on it — replies stack under the original note, separate from the main issue comment thread.
- **Resolve when settled.** Once a thread's point has been addressed, mark it **resolved** to tuck it away. You can reopen it later if the topic comes back. Filter between open and resolved threads from the annotations panel.
- **Anchors survive edits.** When the agent revises the document, Paperclip re-attaches each open thread to the new version. If the exact text it was pinned to has changed, the thread is re-anchored as best it can — and if the passage is gone entirely, the thread is flagged so you know its context moved out from under it.
Annotations are a two-way channel: agents can open threads on documents too, so an agent reviewing a plan can flag a specific line for your attention instead of burying it in a long comment. Opening or replying to an annotation wakes the issue's assignee, the same way a normal comment does.
---
## The Chat tab
+5 -1
View File
@@ -1,3 +1,7 @@
---
paperclip_version: v2026.529.0
---
# Installation
There are three ways to install Paperclip. Choose the one that fits how you work:
@@ -476,7 +480,7 @@ Common errors:
- **Hosted PostgreSQL** — set `DATABASE_URL=postgres://...` in `~/paperclip.env` before onboarding. Use the pooled connection (port 6543 on Supabase) for the app and the direct connection for migrations. See [Database deployment](../../reference/deploy/database.md).
- **Object storage** — set `PAPERCLIP_STORAGE_MODE=s3` plus the relevant S3 env vars. See [Storage deployment](../../reference/deploy/storage.md).
- **Private team server over Tailscale** instead of a public domain — skip Nginx/Certbot and use `PAPERCLIP_DEPLOYMENT_EXPOSURE=private` with `PAPERCLIP_BIND=tailnet`. See [Tailscale private access](../../reference/deploy/tailscale-private-access.md).
- **Private team server over Tailscale** instead of a public domain — skip Nginx/Certbot and use `PAPERCLIP_DEPLOYMENT_EXPOSURE=private` with `PAPERCLIP_BIND=tailnet`. See [Tailscale private access](../../reference/deploy/tailscale-private-access.md). On a private, authenticated instance you can also skip the CLI invite for the first user: the very first person to sign in from a browser can claim themselves as the instance admin straight from the UI — whoever clicks first wins, and everyone else is locked out of the claim. See [Claim first instance admin](../../reference/api/instance-admin.md#claim-first-instance-admin) for the details.
- **Docker instead of bare metal** — a production-ready image and Compose file ship in the repo. See [Docker deployment](../../reference/deploy/docker.md).
---
+17
View File
@@ -1,3 +1,7 @@
---
paperclip_version: v2026.529.0
---
# Skills
When you want an agent to follow a specific procedure — a code review checklist, a deployment runbook, a customer response template — you could put those instructions in the agent's main configuration. But if you want multiple agents to use the same procedure, or want to keep agent configurations lean and focused, that's where skills come in.
@@ -85,6 +89,19 @@ The skill is now available in the company library. When creating or editing an a
![Skills page showing available skills with their names and descriptions](../../user-guides/screenshots/light/org/skills-list.png)
### Install a ready-made skill from the built-in catalog
You don't have to write every skill from scratch. Paperclip ships with a built-in **catalog** of ready-made skills you can browse and install with a click — a head start for common procedures.
The catalog comes in two flavours:
- **Bundled** skills are the everyday kit — things like keeping docs maintained, triaging issues, planning tasks, running QA acceptance, and managing a GitHub PR workflow.
- **Optional** skills are extras you add when you need them — for example, browser-driving an agent, drafting a release announcement, or running a design critique.
Browse the catalog, pick a skill, and install it into your company library. Installing puts the skill in the library only — it doesn't attach it to any agent, so you stay in control of who uses it. From there it behaves like any other installed skill: open it, read its `SKILL.md`, and assign it to the agents that need it.
Because these skills come from Paperclip, the app knows exactly which version you installed. That means a catalog skill can be **kept up to date**: Paperclip can check whether a newer version shipped and install the update, audit the skill's contents for safety before you trust it, and reset the skill back to its original shipped version if it was edited locally. For the mechanics of installing, updating, auditing, and resetting catalog skills, see the [Skills reference](../../reference/skills.md#3-app-shipped-catalog).
---
## File inventory
+14
View File
@@ -1,3 +1,7 @@
---
paperclip_version: v2026.529.0
---
# Projects
A project is the container Paperclip uses to group related work. If goals answer "why are we doing this?" and issues answer "what exactly needs doing?", projects sit in between: they bind a body of work to a concrete place — a repository, a working directory, a budget envelope, a set of execution workspaces — where agents can actually pick up tasks and make progress.
@@ -34,6 +38,16 @@ The top-right **Add Project** button opens the New Project dialog, where you can
If the company has no projects yet, the list is replaced with an empty state prompting you to add the first one.
### Keeping projects (and agents) in your sidebar
As a company grows, the **Projects** and **Agents** groups in the left sidebar can get crowded. To keep yours focused, you can **join** or **leave** individual projects and agents — a personal setting that only affects your own navigation.
- Hover a project or agent in the sidebar and use the **Join** / **Leave** control. Leaving hides it from your sidebar; joining brings it back.
- Everything is **joined by default**, so a brand-new project shows up for everyone until they choose to leave it.
- This is purely cosmetic and per-user. Leaving a project doesn't pause it, archive it, or change anything for your teammates — it still runs, and it's still reachable from the Projects and Agents pages. You're just tidying your own view.
Each join or leave is recorded in the company activity log, so the change is auditable even though it only affects one person's sidebar.
---
## Overview Tab
@@ -1,3 +1,7 @@
---
paperclip_version: v2026.529.0
---
# Workspaces
When an agent picks up a task that involves working with code or files, it needs a place to do that work — a folder with the right code checked out at the right state, ready for the agent to read, edit, and run. That's what an execution workspace is: a snapshot of a project's working directory, tied to a specific task run.
@@ -42,6 +46,20 @@ The task runs in the project's primary checkout, not an isolated copy. Use this
---
## How Paperclip keeps reused workspaces consistent
Reusing a workspace is convenient, but it raises a fair question: what happens when two different agents — with two different intended environments — land in the same workspace? Paperclip closes that gap so a reused workspace never quietly drifts.
- **No silent environment reuse.** Each task run has an intended environment, resolved in this order: an environment set explicitly on the issue always wins; otherwise the project's workspace-policy environment applies; otherwise the agent's own default environment; and the instance default is the final fallback. (An agent deliberately pinned to the local default is never promoted off it by a project policy — only an explicit issue-level environment can move it.) When a run reuses a workspace whose environment doesn't match the run's intended one, Paperclip treats that as a conflict to surface rather than silently inheriting whatever the previous occupant left behind.
- **Dependent issues wait for finalize.** When an issue depends on another, its wake no longer fires before the upstream workspace has finished finalizing. The dependent task only starts once the workspace it relies on is in a consistent, settled state — so it never reads a half-written checkout.
- **Accepting an interaction waits too.** Accepting a plan or review (`issue.interaction.accept`) now waits for the workspace to finalize before it proceeds, for the same reason.
You don't configure any of this — it's part of how isolated and reused workspaces behave. The practical effect is simply that dependent work and reused workspaces see consistent state, every time.
> **Note:** Execution workspaces are local working copies. Paperclip does not push them to a remote git host on your behalf — finished work is reviewed and merged through Paperclip, not through a `git push` from inside the workspace.
---
## Runtime services
Each workspace can have runtime services: background processes that need to be running for the agent's work to make sense — a development server, a database, a build watcher.
+17 -1
View File
@@ -1,5 +1,5 @@
---
paperclip_version: v2026.513.0
paperclip_version: v2026.529.0
---
# Claude Local
@@ -46,6 +46,22 @@ paperclip_version: v2026.513.0
---
## Model Discovery
When you pick a model in the agent config form, Claude Local fills the model dropdown from a live query to Anthropic's API instead of a hard-coded list — so a Claude model that shipped after your last Paperclip update still shows up without waiting for a new release.
Here's how the list is built:
- **With an API key.** If `ANTHROPIC_API_KEY` is set, the adapter calls the Anthropic models endpoint (`/v1/models`) — at `ANTHROPIC_BASE_URL` if you've set one, otherwise `https://api.anthropic.com` — and offers everything it returns. The live results are merged with Paperclip's built-in list and de-duplicated, so you always see at least the known-good models, plus anything new from your account.
- **On Bedrock.** If the adapter detects AWS Bedrock (for example `CLAUDE_CODE_USE_BEDROCK=1`), it offers the region-qualified Bedrock model IDs instead.
- **No key, or the lookup fails.** If there's no API key, or the request times out or comes back empty, you simply get Paperclip's built-in fallback list. Discovery never blocks you from saving an adapter.
Discovered models are cached for about a minute (keyed to the API key and base URL in use), so reopening the form is instant. When you want the freshest list — say you've just been granted access to a new model — use the model field's **refresh** control to force a new lookup that bypasses the cache.
> **Tip:** The `model` field still accepts any model id you type in. Discovery is there to save you from remembering exact identifiers, not to restrict you to the listed choices.
---
## Session Persistence
Claude Local stores the Claude Code session id and resumes it on the next heartbeat when the working directory still matches.
+23 -1
View File
@@ -1,5 +1,5 @@
---
paperclip_version: v2026.512.0
paperclip_version: v2026.529.0
---
# Instance Admin API
@@ -39,6 +39,28 @@ Instance-admin only.
---
## Claim first instance admin
```
POST /api/bootstrap/claim
```
On a brand-new private instance that requires login, this lets the first person to sign in promote themselves to `instance_admin` — no manual database seeding. The first caller to claim wins; everyone after them is locked out.
**Availability.** This route only exists when the instance runs with `deploymentMode` set to `authenticated` **and** `deploymentExposure` set to `private`. On any other configuration it returns `404` with `Browser first-admin claim is not available`.
**Authentication.** The caller must be a signed-in browser session (a board actor whose session source is the browser). Other callers — agents, CLI tokens, unauthenticated requests — get `401` with `Sign in from a browser session before claiming first admin`.
**Behaviour.** If no `instance_admin` exists yet, the signed-in user is promoted to `instance_admin`. The claim is atomic — the table is locked so exactly one user can win. If the instance has already been claimed, the route returns `409` with `Someone else has already claimed this instance`.
The request takes no body. On success the response is:
```json
{ "claimed": true, "userId": "<the promoted user's id>" }
```
---
## LLM agent-configuration reflection
These endpoints exist so agents can introspect what server-side adapters and icons are available to them.
+94 -1
View File
@@ -1,5 +1,5 @@
---
paperclip_version: v2026.525.0
paperclip_version: v2026.529.0
---
# Issues
@@ -740,6 +740,99 @@ response = requests.put(
---
## Document Annotations
Annotations let you attach comment threads to a specific passage of an issue document — the same way you'd leave a margin note on a shared doc. Each thread is anchored to a selected range of text, carries one or more comments, and can be resolved once the conversation is settled. Both users and agents can create and reply to annotation threads.
Annotations live under a single document, addressed by the issue id and the document key.
### Anchors and revisions
A thread is pinned to the document text it was created against, using a combination of the quoted text (with surrounding context) and its character positions. Because of this, creating a thread requires you to send the document's current revision — if the document has moved on, the server rejects the request so the anchor can't land in the wrong place.
When a document is later edited, the server re-anchors each open thread against the new revision and records how confidently it could do so. A thread can end up in one of these anchor states:
- `active` — the anchored passage was found cleanly in the new revision.
- `shifted` — the passage moved but was relocated with reasonable confidence.
- `orphaned` — the anchored text no longer exists, so the thread floats free of any passage.
### List Threads
```
GET /api/issues/{issueId}/documents/{key}/annotations
```
Return the annotation threads on a document, newest activity first.
Query parameters:
- `status` — `open`, `resolved`, or `all`. Defaults to all.
- `includeComments` — when `true`, each thread embeds its full comment list. Otherwise only the thread records are returned.
The document detail route also folds annotations in directly. `GET /api/issues/{issueId}/documents/{key}` accepts `includeAnnotations` and `includeAnnotationComments` query flags and returns the matching threads on an `annotations` field. Agent callers receive annotations by default; pass `includeAnnotations=false` to opt out.
### Get a Thread
```
GET /api/issues/{issueId}/documents/{key}/annotations/{threadId}
```
Return a single thread with all of its comments. Responds `404` if the thread doesn't belong to that issue document.
### Create a Thread
```
POST /api/issues/{issueId}/documents/{key}/annotations
```
Open a new thread anchored to a passage, with its first comment in the same request.
Request body:
| Field | Type | Notes |
|---|---|---|
| `baseRevisionId` | uuid, required | The document revision the anchor was computed against. Must match the current latest revision. |
| `baseRevisionNumber` | integer, required | The matching revision number. |
| `selector` | object, required | The anchor — a `quote` selector (`exact`, plus `prefix`/`suffix` context) and a `position` selector (`normalizedStart`/`normalizedEnd` and `markdownStart`/`markdownEnd`). |
| `body` | string, required | The first comment's markdown text, 1–20,000 characters. |
Concurrency rules:
- A stale `baseRevisionId`/`baseRevisionNumber` returns `409 Conflict` with the current revision so you can re-anchor and retry.
- If the selector can't be matched against the current document text, the server returns `422 Unprocessable Entity`.
A successful create returns the thread with its first comment, records an `issue.document_annotation_thread_created` activity entry, and wakes the issue assignee.
### Reply to a Thread
```
POST /api/issues/{issueId}/documents/{key}/annotations/{threadId}/comments
```
Add a comment to an existing thread.
Request body:
- `body` — markdown comment text, 1–20,000 characters.
Adding a comment bumps the thread's activity timestamp, records an `issue.document_annotation_comment_added` entry, and wakes the assignee.
### Resolve or Reopen a Thread
```
PATCH /api/issues/{issueId}/documents/{key}/annotations/{threadId}
```
Change a thread's status.
Request body:
- `status` — `resolved` to close the conversation, or `open` to reopen it.
Resolving stamps the thread with who resolved it and when, and logs `issue.document_annotation_thread_resolved`; reopening clears those fields and logs `issue.document_annotation_thread_reopened`. Sending the status the thread already has is a no-op.
---
## Attachments
Attachments are file uploads linked to an issue, and optionally to a specific issue comment.
+24 -2
View File
@@ -1,5 +1,5 @@
---
paperclip_version: v2026.512.0
paperclip_version: v2026.529.0
---
# Plugins API
@@ -17,11 +17,33 @@ For the operator-facing walkthrough see [Administration → Plugins](../../admin
| Endpoint | Purpose |
|---|---|
| `GET /api/plugins` | List installed plugins on this instance. |
| `GET /api/plugins/examples` | List bundled example plugins available to install. |
| `GET /api/plugins/examples` | List the bundled plugins discovered in the current checkout (reference examples and vendored first-party plugins). See below. |
| `GET /api/plugins/ui-contributions` | Aggregate of UI slots and launchers contributed by enabled plugins. The Paperclip UI consumes this on page load. |
| `GET /api/plugins/tools` | Tools declared by enabled plugins. |
| `POST /api/plugins/tools/execute` | Execute a plugin-declared tool by key. |
### Bundled plugin discovery
`GET /api/plugins/examples` returns the plugins that ship inside the current Paperclip checkout. Rather than a fixed list, the server scans the bundled packages on disk for plugin manifests, so the result reflects whatever your checkout actually contains — the reference example plugins plus any vendored first-party plugins. The result is cached after the first scan.
Each entry has this shape:
```json
{
"packageName": "@paperclipai/plugin-llm-wiki",
"pluginKey": "llm-wiki",
"displayName": "LLM Wiki",
"description": "…",
"localPath": "packages/plugins/…",
"tag": "first-party",
"experimental": true
}
```
- `tag` is `example` for the reference plugins or `first-party` for vendored real plugins.
- `experimental` is `true` for first-party plugins that aren't production-ready yet; the Plugin Manager renders these with an **Experimental** badge.
- `localPath` is what the install flow points at for an in-checkout install.
## Install and lifecycle
| Endpoint | Purpose |
+134
View File
@@ -0,0 +1,134 @@
---
paperclip_version: v2026.529.0
---
# Resource Memberships
Resource memberships are how a signed-in board user curates their own sidebar. Each user decides which projects and which agents they want to keep in view by **joining** or **leaving** them. Leaving a project or agent doesn't change anything for anyone else — it just tidies your personal navigation. By default everything is treated as joined until you choose to leave it.
These routes always act on the **current user** (the `me` segment in the path). You cannot read or change someone else's memberships through this API.
> All routes are company-scoped and require board (user) authentication. Agent tokens are rejected with `403`.
---
## List Your Memberships
```
GET /api/companies/{companyId}/resource-memberships/me
```
Return the calling user's membership state for every project and agent they have explicitly joined or left in the company.
The response groups state by resource type. Each entry maps a resource id to either `joined` or `left`. Resources you have never touched simply won't appear — treat anything missing as `joined`.
```json
{
"projectMemberships": {
"1f3c…": "joined",
"8ad2…": "left"
},
"agentMemberships": {
"b91e…": "left"
},
"updatedAt": "2026-05-26T13:41:23.000Z"
}
```
`updatedAt` is the most recent change across all of your memberships, or `null` if you have never changed one.
### Example
```bash
curl -sS \
-H "Authorization: Bearer {token}" \
"https://paperclip.example.com/api/companies/{companyId}/resource-memberships/me"
```
---
## Join or Leave a Project
```
PUT /api/companies/{companyId}/resource-memberships/me/projects/{projectId}
```
Set whether the current user keeps a project in their sidebar.
Request body:
| Field | Type | Notes |
|---|---|---|
| `state` | enum, required | `joined` to keep the project in your sidebar, `left` to hide it. |
The project must belong to the company, or the server returns `404 Not Found`. Setting a state you already have is a no-op — the call still succeeds and returns your current state.
Response:
```json
{
"resourceType": "project",
"resourceId": "{projectId}",
"state": "left",
"updatedAt": "2026-05-26T13:41:23.000Z"
}
```
When the state actually changes, the server records a `resource_membership.joined` or `resource_membership.left` entry in the activity log so the change is auditable.
### Example
```bash
curl -sS -X PUT \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
"https://paperclip.example.com/api/companies/{companyId}/resource-memberships/me/projects/{projectId}" \
-d '{ "state": "left" }'
```
---
## Join or Leave an Agent
```
PUT /api/companies/{companyId}/resource-memberships/me/agents/{agentId}
```
The agent equivalent of the project route above. Set whether the current user keeps an agent in their sidebar.
Request body:
| Field | Type | Notes |
|---|---|---|
| `state` | enum, required | `joined` to keep the agent in your sidebar, `left` to hide it. |
The agent must belong to the company, or the server returns `404 Not Found`. As with projects, re-setting the same state is a no-op that returns your current state, and a real change writes a `resource_membership.joined` / `resource_membership.left` activity entry.
Response:
```json
{
"resourceType": "agent",
"resourceId": "{agentId}",
"state": "joined",
"updatedAt": "2026-05-26T13:41:23.000Z"
}
```
### Example
```bash
curl -sS -X PUT \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
"https://paperclip.example.com/api/companies/{companyId}/resource-memberships/me/agents/{agentId}" \
-d '{ "state": "joined" }'
```
---
## Notes
- **Self-service only.** A user may only read and update their own memberships. Requests authenticated as an agent, or that target a different user, are rejected with `403 Forbidden`.
- **Active company access required.** Outside local single-user instances, the calling user must have active membership in the company.
- **Default is joined.** A resource with no stored row is treated as `joined`. Leaving then re-joining a resource returns it to the default visible state.
+264 -1
View File
@@ -1,5 +1,5 @@
---
paperclip_version: v2026.525.0
paperclip_version: v2026.529.0
---
# Command Reference
@@ -565,6 +565,269 @@ eval "$(paperclipai agent local-cli claudecoder -C <company-id>)"
---
## `skills`
Company and agent skill operations. Commands split into three groups: read-only **catalog** browsing (not company-scoped), the **company skill library**, and per-agent **desired-skill sync**. Every library and agent subcommand requires a company scope and accepts the common client flags.
### `paperclipai skills browse`
Browse app-shipped catalog skills without installing them. Not company-scoped.
```
paperclipai skills browse [options]
```
| Flag | Type | Default | Description |
|---|---|---|---|
| `--kind <kind>` | enum | — | Catalog kind filter: `bundled` or `optional`. |
| `--category <slug>` | string | — | Catalog category filter. |
| `--query <text>` | string | — | Search catalog text. |
### `paperclipai skills search <query>`
Search app-shipped catalog skills without installing them. Not company-scoped.
```
paperclipai skills search [options] <query>
```
| Argument | Description |
|---|---|
| `query` | Search text. |
| Flag | Type | Default | Description |
|---|---|---|---|
| `--kind <kind>` | enum | — | Catalog kind filter: `bundled` or `optional`. |
| `--category <slug>` | string | — | Catalog category filter. |
### `paperclipai skills inspect <catalogRef>`
Inspect an app-shipped catalog skill before installing it. Not company-scoped.
```
paperclipai skills inspect [options] <catalogRef>
```
| Argument | Description |
|---|---|
| `catalogRef` | Catalog skill ID, key, or unique slug. |
### `paperclipai skills install <catalogRef>`
Install a catalog skill into the company skill library; does not attach it to agents.
```
paperclipai skills install [options] <catalogRef>
```
| Argument | Description |
|---|---|
| `catalogRef` | Catalog skill ID, key, or unique slug. |
| Flag | Type | Default | Description |
|---|---|---|---|
| `--as <slug>` | string | — | Company skill slug override. |
| `--force` | flag | `false` | Replace a same-key catalog-managed skill when the server allows it. |
| Common client flags | — | — | `-C, --company-id` (required) plus `--api-base`, `--api-key`, `--json`, etc. |
### `paperclipai skills list`
List company skills.
```
paperclipai skills list [options]
```
Common client flags; `-C, --company-id` required.
### `paperclipai skills show <skillRef>`
Show company skill details.
```
paperclipai skills show [options] <skillRef>
```
| Argument | Description |
|---|---|
| `skillRef` | Company skill ID, key, or unique slug. |
### `paperclipai skills file <skillRef>`
Print a company skill file.
```
paperclipai skills file [options] <skillRef>
```
| Argument | Description |
|---|---|
| `skillRef` | Company skill ID, key, or unique slug. |
| Flag | Type | Default | Description |
|---|---|---|---|
| `--path <path>` | string | `SKILL.md` | Relative file path. |
### `paperclipai skills import <source>`
Import company skills from a local path, GitHub, skills.sh, or URL source.
```
paperclipai skills import [options] <source>
```
| Argument | Description |
|---|---|
| `source` | Skill source: local path, GitHub repo, skills.sh reference, or URL. |
### `paperclipai skills create`
Create a managed local company skill.
```
paperclipai skills create [options]
```
| Flag | Type | Default | Description |
|---|---|---|---|
| `--name <name>` | string | — | **Required.** Skill name. |
| `--slug <slug>` | string | — | Skill slug. |
| `--description <text>` | string | — | Skill description. |
| `--body-file <path>` | string | — | Markdown body file; use `-` to read stdin. |
### `paperclipai skills scan-projects`
Scan project workspaces for skills.
```
paperclipai skills scan-projects [options]
```
| Flag | Type | Default | Description |
|---|---|---|---|
| `--project-id <id>` | string | — | Project ID to scan; may be repeated. |
| `--workspace-id <id>` | string | — | Workspace ID to scan; may be repeated. |
### `paperclipai skills check [skillRef]`
Check company skill update status. Omit the reference to check every skill.
```
paperclipai skills check [options] [skillRef]
```
| Argument | Description |
|---|---|
| `skillRef` | Optional company skill ID, key, or unique slug. |
### `paperclipai skills update [skillRef]`
Install company skill updates. Pass a single skill reference or `--all`, not both.
```
paperclipai skills update [options] [skillRef]
```
| Argument | Description |
|---|---|
| `skillRef` | Company skill ID, key, or unique slug (required unless `--all`). |
| Flag | Type | Default | Description |
|---|---|---|---|
| `--all` | flag | `false` | Check all skills and install available updates. |
| `--force` | flag | `false` | Discard local-modification or soft-audit holds; hard-stop audit findings still fail. |
### `paperclipai skills audit [skillRef]`
Audit installed company skill bytes without executing them. Omit the reference to audit every skill.
```
paperclipai skills audit [options] [skillRef]
```
| Argument | Description |
|---|---|
| `skillRef` | Optional company skill ID, key, or unique slug. |
### `paperclipai skills reset <skillRef>`
Reset a catalog-managed company skill to its pinned installed origin.
```
paperclipai skills reset [options] <skillRef>
```
| Argument | Description |
|---|---|
| `skillRef` | Company skill ID, key, or unique slug. |
| Flag | Type | Default | Description |
|---|---|---|---|
| `--yes` | flag | `false` | Confirm reset without prompting. |
| `--force` | flag | `false` | Discard local modifications or accept soft audit warnings; hard-stop audit findings still fail. |
### `paperclipai skills remove <skillRef>`
Remove a company skill.
```
paperclipai skills remove [options] <skillRef>
```
| Argument | Description |
|---|---|
| `skillRef` | Company skill ID, key, or unique slug. |
| Flag | Type | Default | Description |
|---|---|---|---|
| `--yes` | flag | `false` | Confirm removal without prompting. |
### `paperclipai skills agent list <agentRef>`
List an agent runtime skill snapshot.
```
paperclipai skills agent list [options] <agentRef>
```
| Argument | Description |
|---|---|
| `agentRef` | Agent ID or shortname/url-key. |
### `paperclipai skills agent sync <agentRef>`
Replace an agent's non-required desired company skills and sync runtime state. At least one `--skill` is required.
```
paperclipai skills agent sync [options] <agentRef>
```
| Argument | Description |
|---|---|
| `agentRef` | Agent ID or shortname/url-key. |
| Flag | Type | Default | Description |
|---|---|---|---|
| `--skill <skillRef>` | string | — | Desired company skill ID, key, or slug; may be repeated. |
### `paperclipai skills agent clear <agentRef>`
Clear an agent's non-required desired company skills and sync runtime state. Required Paperclip skills remain server-enforced.
```
paperclipai skills agent clear [options] <agentRef>
```
| Argument | Description |
|---|---|
| `agentRef` | Agent ID or shortname/url-key. |
| Flag | Type | Default | Description |
|---|---|---|---|
| `--yes` | flag | `false` | Confirm clear without prompting. |
---
## `approval`
### `paperclipai approval list`
@@ -1,3 +1,7 @@
---
paperclip_version: v2026.529.0
---
# Control-Plane Commands
Use these commands when Paperclip is already running and you want to operate a company from the terminal instead of the UI.
@@ -100,6 +104,74 @@ pnpm paperclipai agent local-cli claudecoder --company-id <company-id>
---
## Skills Commands
Use these commands when you want to browse the catalog of skills that ship with the app, stock your company's skill library, keep those skills current, and decide which skills each agent should use — all from the terminal.
It helps to think in three layers:
- The **catalog** is the read-only set of app-shipped skills (`browse`, `search`, `inspect`). You install one into your company when you want it.
- The **company skill library** is your company's own collection (`list`, `show`, `file`, `import`, `create`, `check`, `update`, `audit`, `reset`, `remove`). Installing a catalog skill copies it here; you can also import or author your own.
- **Agent sync** is the desired-skill set for a single agent (`agent list`, `agent sync`, `agent clear`). Putting a skill in the library does not attach it to anyone — you sync it onto an agent when you want that agent to use it.
### Browse and install from the catalog
Start by exploring what the app ships, then install the ones you want into your company library.
```sh
pnpm paperclipai skills browse --kind bundled --category coding
pnpm paperclipai skills search "code review" --kind optional
pnpm paperclipai skills inspect <catalog-ref>
pnpm paperclipai skills install <catalog-ref> --as my-reviewer --company-id <company-id>
```
`browse` filters by `--kind` (`bundled` or `optional`), `--category`, and `--query`; `search <query>` is the same filtered list with the text supplied as an argument. `inspect <catalogRef>` shows the full detail (files, hashes, recommended roles) before you commit. `install <catalogRef>` copies the skill into the company library — use `--as <slug>` to override the slug and `--force` to replace a same-key catalog-managed skill when the server allows it.
> **Note:** `install` does **not** attach the skill to any agent. It only adds it to the library. Attach it later with `skills agent sync`.
### Work with the company skill library
Once skills are in the library, inspect them, bring in your own, and keep everything up to date.
```sh
pnpm paperclipai skills list --company-id <company-id>
pnpm paperclipai skills show <skill-ref>
pnpm paperclipai skills file <skill-ref> --path SKILL.md
pnpm paperclipai skills import <source>
pnpm paperclipai skills create --name "House Style" --slug house-style --body-file ./house-style.md
```
`import <source>` accepts a local path, a GitHub repo, a skills.sh reference, or a URL. `create` authors a managed local skill; pass the markdown body with `--body-file <path>`, or use `--body-file -` to read it from stdin.
To keep library skills current, check for updates, then install them:
```sh
pnpm paperclipai skills check
pnpm paperclipai skills update <skill-ref>
pnpm paperclipai skills update --all
pnpm paperclipai skills audit <skill-ref>
pnpm paperclipai skills reset <skill-ref> --yes
pnpm paperclipai skills remove <skill-ref> --yes
```
`check [skillRef]` reports update status (omit the reference to check every skill). `update` installs an available update for one skill, or `--all` for every skill that has one. `audit` inspects installed skill bytes without executing them. `reset` returns a catalog-managed skill to its pinned installed origin, and `remove` deletes a skill from the library — both prompt for confirmation unless you pass `--yes`. `update`, `reset`, and `audit` accept `--force` to discard local-modification or soft-audit holds (hard-stop audit findings still fail).
### Sync skills to an agent
When you want an agent to actually use library skills, sync them onto that agent.
```sh
pnpm paperclipai skills agent list <agent-ref>
pnpm paperclipai skills agent sync <agent-ref> --skill <skill-ref> --skill <other-skill-ref>
pnpm paperclipai skills agent clear <agent-ref> --yes
```
`agent list` shows the agent's current runtime skill snapshot. `agent sync` replaces the agent's non-required desired company skills with the ones you pass (repeat `--skill` for each). `agent clear` removes all non-required desired skills; required Paperclip skills stay server-enforced either way.
All company-scoped skills subcommands accept the common client options (`--company-id`, `--api-base`, `--api-key`, `--json`, and the rest). The catalog read commands (`browse`, `search`, `inspect`) are not company-scoped. See the [Command Reference](./commands.md#skills) for the exhaustive per-flag list.
---
## Approval Commands
Use these commands to review or resolve board-gated actions.
+117 -7
View File
@@ -1,3 +1,7 @@
---
paperclip_version: v2026.529.0
---
# Skills Reference
This is the reference for company skills: the file shape on disk, the install pipeline, how skills are attached to agents, scoping rules, the canonical key form, versioning, and troubleshooting.
@@ -175,7 +179,113 @@ Bundled skills (the four `paperclip-*` skills shipped with the server) are re-im
---
## 3. Assigning skills to agents
## 3. App-shipped catalog
Beyond importing skills from GitHub, skills.sh, URLs, or local folders, Paperclip ships its own **catalog** of ready-made skills inside the app. You browse the catalog, install the skill you want into a company, and from then on Paperclip can keep that copy in step with the version it shipped — checking for updates, auditing the bytes, and resetting back to the pinned origin if needed.
Catalog skills are split into two **kinds** (`CatalogSkillKind`):
| Kind | Meaning | Examples |
|---|---|---|
| `bundled` | Core skills the app considers part of the baseline kit. | `doc-maintenance`, `issue-triage`, `task-planning`, `qa-acceptance`, `github-pr-workflow` |
| `optional` | Extra skills you opt into when you need them. | `agent-browser`, `release-announcement`, `design-critique` |
Once installed, a catalog skill becomes an ordinary company-skill row, but it is tagged as **catalog-managed**: its `sourceType` is `catalog` and its `metadata.sourceKind` is `catalog`. The catalog kind (`bundled` / `optional`) is carried through on `metadata.catalogKind`, and the byte-exact origin it was pinned to is stored in `metadata.originHash`.
> The catalog browse routes are read-only and only require an authenticated caller. The install/audit/update/reset routes mutate the company library and therefore need `agents:create` (or `permissions.canCreateAgents=true`), exactly like the other mutating skill routes.
### Browse the catalog
The catalog itself is the same for every company, so the browse routes are not company-scoped:
| Action | Endpoint |
|---|---|
| List catalog skills | `GET /api/skills/catalog` |
| Inspect one catalog skill | `GET /api/skills/catalog/{catalogId}` |
| List a catalog skill's files | `GET /api/skills/catalog/{catalogId}/files` |
The list route accepts three optional query filters:
- `kind` — `bundled` or `optional`.
- `category` — exact-match on the skill's category.
- `q` — free-text query matched against the skill's id, key, slug, name, description, category, kind, recommended roles, and tags.
Each catalog entry (`CatalogSkill`) carries `id`, `key`, `kind`, `category`, `slug`, `name`, `description`, `trustLevel`, `compatibility`, `defaultInstall`, `recommendedForRoles`, `requires`, `tags`, a `files[]` inventory (each with `path`, `kind`, `sizeBytes`, `sha256`), and a `contentHash` — the byte-exact identity of the shipped skill.
The files route returns one file at a time. By default it reads `SKILL.md`; pass `?path=references/example.md` to read another file in the inventory. Asset files are not previewable.
### Install a catalog skill
```http
POST /api/companies/{companyId}/skills/install-catalog
```
```json
{
"catalogSkillId": "<catalog id, key, or unique slug>",
"slug": "my-doc-maintenance",
"force": false
}
```
- `catalogSkillId` (required) — resolves against the catalog by id, key, or a slug that is unique in the catalog.
- `slug` (optional) — override the slug the skill takes in your company library. Leave it out (or `null`) to keep the catalog slug.
- `force` (optional) — overwrite an existing row that already occupies the target slug/key.
**Installing does not attach the skill to any agent.** It only adds the skill to the company library, just like an import. Attach it afterwards exactly as you would any other skill — see [Assigning skills to agents](#4-assigning-skills-to-agents).
The response reports an `action` of `created`, `updated`, or `unchanged`, plus the resulting company `skill`, the source `catalogSkill`, and any `warnings`. A fresh install returns `201`; an in-place refresh returns `200`.
### Keep a catalog skill current
A catalog-managed skill exposes the same `GET /skills/{skillId}/update-status` → `POST /skills/{skillId}/install-update` flow as GitHub skills, but the comparison is against the version the app currently ships rather than an upstream commit. When a newer catalog version is available, install it:
```http
POST /api/companies/{companyId}/skills/{skillId}/install-update
```
```json
{ "force": false }
```
Two kinds of **hold** can stop an update:
- **Soft hold — local modifications.** If the installed bytes no longer match the pinned `originHash`, the update is held so you do not silently lose your edits. Rerun with `{ "force": true }` to discard the local changes and take the new version.
- **Hard stop — audit findings.** If auditing the skill returns a `fail` verdict (see below), the update is blocked outright. `force` does **not** override a hard stop.
### Audit before you trust
```http
POST /api/companies/{companyId}/skills/{skillId}/audit
```
Audit inspects the installed skill's bytes **without executing them** and returns a verdict:
| `verdict` | Meaning |
|---|---|
| `pass` | No findings. |
| `warning` | Soft findings only (for example, the skill ships a script, references a network command, or its bytes drifted from `originHash`). |
| `fail` | At least one hard-stop finding (for example, a remote-fetch-and-execute pattern, a secret-exfiltration pattern, oversized or non-text files, or a missing/invalid `SKILL.md`). |
The result also includes `codes` (the deduplicated finding codes), `installedHash`, `originHash`, and a `scanVersion`. A `fail` verdict is what hard-blocks `install-update`. Audit is only supported for local-path and catalog-managed skills.
### Reset to the pinned origin
```http
POST /api/companies/{companyId}/skills/{skillId}/reset
```
```json
{ "force": false }
```
Reset restores a catalog-managed skill to the byte-exact origin it was installed from — useful when a skill was edited locally and you want the shipped version back. Reset is only supported for catalog-managed skills.
For the equivalent `paperclipai skills` CLI commands (browse, install, audit, update, reset), see [Control-plane commands](./cli/control-plane-commands.md) and the [CLI command reference](./cli/commands.md).
---
## 4. Assigning skills to agents
A skill must be installed at the company level before it can be attached to an agent. There are two ways to make the attachment.
@@ -244,7 +354,7 @@ Returns the same snapshot shape without changing anything. For adapters without
---
## 4. Scoping rules
## 5. Scoping rules
**Company-scoped, not org-scoped.** Skills live at the company level. Every agent inside the same company can be assigned any installed skill. There is no per-team or per-role scoping built in — granularity is controlled by which keys end up in each agent's `desiredSkills`.
@@ -270,7 +380,7 @@ Adapters declare which materialisation strategy they need via `requiresMateriali
---
## 5. Skill vs. plugin vs. adapter
## 6. Skill vs. plugin vs. adapter
These three extension points are easy to confuse. They sit at different layers:
@@ -288,7 +398,7 @@ Rule of thumb: **a skill is something a smart human could follow if you handed t
---
## 6. Naming collisions and resolution
## 7. Naming collisions and resolution
### Canonical key
@@ -336,7 +446,7 @@ Slugs are normalised through `normalizeAgentUrlKey`: lowercase, hyphen-separated
---
## 7. Versioning semantics
## 8. Versioning semantics
Behaviour depends on the source:
@@ -348,7 +458,7 @@ Behaviour depends on the source:
| `local_path` (managed) | Live | None — files refresh on read | Stored under `<paperclipInstanceRoot>/skills/{companyId}/`. Edited via `PATCH /skills/{id}/files`. |
| `local_path` (project scan) | Live | Re-run the scan endpoint | Skills whose `SKILL.md` disappears are pruned automatically (`pruneMissingLocalPathSkills`). |
| `paperclip_bundled` | Pinned to the Paperclip release | Upgrade Paperclip itself | Re-imported on every list call; cannot be edited. |
| `catalog` | No | None | Used by inline catalog packages; refresh by re-importing. |
| `catalog` | Pinned to the shipped catalog version (`metadata.originHash`) | `GET /skills/{id}/update-status` → `POST /skills/{id}/install-update`; `POST /skills/{id}/reset` to restore the origin | App-shipped catalog skills. Updates compare against the version the app ships. See [App-shipped catalog](#3-app-shipped-catalog). |
### `update-status` response
@@ -371,7 +481,7 @@ For non-GitHub sources, `supported: false` is returned with a reason. Calling `i
---
## 8. Troubleshooting: why a skill isn't loading
## 9. Troubleshooting: why a skill isn't loading
Walk down this list in order. The first match is usually the problem.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 281 KiB

After

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 KiB

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 285 KiB

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 KiB

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 KiB

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 KiB

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 KiB

After

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 385 KiB

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 KiB

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 KiB

After

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 KiB

After

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 303 KiB

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 449 KiB

+4
View File
@@ -286,6 +286,10 @@
"title": "Goals & Projects",
"file": "../docs/reference/api/goals-and-projects.md"
},
{
"title": "Resource Memberships",
"file": "../docs/reference/api/resource-memberships.md"
},
{
"title": "Costs",
"file": "../docs/reference/api/costs.md"