Commit Graph
462 Commits
Author SHA1 Message Date
DottaandClaude Opus 5.5 50df9a19b9 perf(inbox): read only the execution workspaces Mine rows reference (#20388)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The Mine inbox is the first page a board user opens to see the tasks
that need them
> - The page loaded the company's full execution-workspace summary list
and kept task rows hidden until that list arrived
> - On a company with thousands of workspaces, that read checks each
workspace row against the privacy predicate. It was the slowest request
on the page
> - The inbox needs workspace names only for the workspaces its rows
reference, and only when the view shows workspace data
> - This pull request adds an `ids` filter to the summary read, makes
the inbox request only referenced workspaces, and stops rows from
waiting for workspace data when the view does not show it
> - The benefit is that Mine rows appear when the task data arrives, and
the workspace read becomes a small bounded query

## Linked Issues or Issue Description

**What existing behavior does this improve?**
The Mine inbox (`/:companyPrefix/issues?view=mine`) shows its task rows
late on companies with many execution workspaces.

**Subsystem affected**
Board UI inbox and the execution-workspace summary API.

**Current behavior**
The page calls `GET
/api/companies/:id/execution-workspaces?summary=true` with no filter. On
a large company this returned 8,758 rows (2.5 MB) and took 12.3 s on the
server. The reveal gate included this read, so rows appeared at 13.4 s
although `inbox/mine` arrived at 1.6 s.

**Proposed behavior**
The inbox requests summaries only for the workspaces its rows reference.
Rows appear when the Mine task data arrives, unless the view shows
workspace data.

**Reason and benefit**
The workspace read becomes a small bounded query, and it leaves the
critical path for the default Mine view.

**Breaking changes**
None. The `ids` parameter is optional and additive.

## What Changed

- `packages/shared`: add `executionWorkspaceSummaryIdsQuerySchema`
(comma-separated UUIDs, 1–100 distinct values) and
`EXECUTION_WORKSPACE_SUMMARY_IDS_MAX`.
- `server`: `GET /companies/:companyId/execution-workspaces` accepts
`ids`. Bad input returns 422. The service adds
`inArray(execution_workspaces.id, ids)`. The company scope and the actor
read condition still apply, so privacy does not change.
- `ui/src/api/execution-workspaces.ts`: `listSummaries` accepts `ids`.
New `listSummariesByIds` reads ids in chunks of 100 and concatenates the
results.
- `ui/src/pages/Inbox.tsx`: the workspace query is keyed on the sorted
distinct `executionWorkspaceId`s of the rows the inbox holds (Mine,
touched, context and remote search issues). It uses `keepPreviousData`
and runs only when isolated workspaces are on and at least one id
exists.
- Reveal gate: rows wait for the workspace read only when workspace data
changes what the rows show. This is workspace grouping, a visible
Workspace column, or an active search (workspace names are searchable).
Otherwise rows reveal without it.
- Tests: route ids pass-through and 422 cases (non-uuid, empty,
separators only, more than 100); service test for the id filter with
company scope and the read condition; UI api chunking test; Inbox tests
for "rows reveal while the workspace read is pending when no workspace
column or grouping is active", rows waiting when the Workspace column is
visible, and "shows the resolved isolated workspace name" with the
id-filtered call.

Follow-ups (not changed here, they still read the unfiltered list):
- `ui/src/pages/LegacyInbox.tsx:772`
- `ui/src/components/IssuesList.tsx:985`
- `ui/src/components/LegacyIssuesList.tsx:888`
- `ui/src/components/NewIssueDialog.tsx:570` (filtered by project and
reuse, but not by ids)

## Verification

Focused checks on this revision:
- `cd server && npx vitest run
src/__tests__/execution-workspaces-routes.test.ts
src/__tests__/execution-workspaces-service.test.ts -t "summar|ids"`: 14
passed (embedded Postgres ran the service test).
- `cd ui && npx vitest run src/api/execution-workspaces.test.ts
src/pages/Inbox.test.tsx`: all passed.
- `pnpm --filter @paperclipai/server --filter @paperclipai/ui --filter
@paperclipai/shared typecheck`: passed.
- `pnpm check:token-gates`: clean.
- `pnpm verify` selected 2,481 Vitest files (the shared validator change
reaches most suites). I stopped it at a 25-minute limit on a heavily
loaded shared host. Before the limit, three server tests outside this
change failed: `agent-commentary-skills` (skill mount),
`agent-config-read-access` (24.8 s timeout) and
`agent-directory-working-copies`. Required CI supplies the full
coverage.
- Review fix `fc3f82dae0`: when workspace data is visible, the reveal
gate also waits while `keepPreviousData` supplies the previous id set's
summaries. A new test switches Mine → Recent to a new workspace and
checks the Recent row stays hidden until its workspace loads. It fails
without the change.
- Follow-up commits `bf34f84823` and `8fc743b5ca` add a 100-row Mine
test with a counted workspace id scan. It fails with the old `= []`
defaults and passes with the stable `NO_ISSUES` default.

Performance (local, synthetic fixture):
- Instance: isolated worktree instance, `authenticated` mode, signed in
as a non-admin company member so the real workspace privacy predicate
runs. Production UI bundle (`PAPERCLIP_UI_DEV_MIDDLEWARE=false`).
Headless Chromium 1440×900, a new browser context per run (cold HTTP
cache and cold query cache). macOS, Apple Silicon, with other local
sessions running.
- Fixture: 8,750 execution workspaces (each with a source task and a
privacy-source key), 38,750 tasks, 150 Mine tasks; the Mine snapshot
returns 100 rows that reference 100 workspaces.
- Finish event: the first `[data-slot="task-row"]` is in the DOM.

| Measurement | Before (`02bfe71a6b`) | After |
| --- | --- | --- |
| Cold time to rows, median of 7 | 1,209 ms (1,046–1,312) | 702 ms
(567–1,209) |
| Workspace summary read, server wait (time to first byte), median of 7
| 496 ms unfiltered, 2.0 MB | 18 ms with 100 ids, 22 KB |

The difference of medians is 507 ms. This is close to the unfiltered
read's wait on this fixture (about 550–590 ms in the browser runs). The
runs were sequential batches, not alternating pairs.

Limits: this fixture does not reproduce the 12.3 s server time seen on
the development instance. Here the unfiltered read cost 0.5–1.7 s and
grew with the company's task count. The browser gain on the original
instance should be close to that instance's unfiltered read time, but I
did not measure it there.

## Risks

- Low risk. The `ids` filter only narrows the existing query. It does
not change the read condition or the company scope.
- A row whose workspace is not readable by the actor shows no workspace
name, as before.
- When the Workspace column or grouping is visible, rows still wait for
the workspace read. That read is now small.
- When the id set changes, the query refetches all chunks. Before a view
first reveals, rows wait for the new summaries if workspace data is
visible. After that, the previous names stay visible while a refresh
loads.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, via Claude Code with
tool use (shell, file edit, headless browser). Extended reasoning on.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 18:02:55 -06:00
DottaandPaperclip b09f17fbfd fix(agents): repair queued setup through task connection cards (#20361)
## Thinking Path

> - Paperclip manages AI agents doing work for people.
> - Agent verification must finish before an accepted task can start.
> - A missing AI account default can prevent verification before a
provider starts.
> - Lifecycle policy treated that owned configuration refusal as a
temporary failure and retried each minute.
> - The accepted turn remained Queued without explaining the
prerequisite.
> - Park account configuration failures and reuse the task's existing
inline connection card.
> - Successful repair rechecks verification and releases the original
queued turn under its original authority.

## Linked Issues or Issue Description

**What happened?** An OpenCode agent selected the responsible user's
OpenRouter default, but that default did not exist. Verification retried
unchanged configuration indefinitely and its accepted task stayed
Queued.

**Expected behavior:** Preserve accepted work, explain the setup
prerequisite, and let the appropriate person repair it using the
existing task connection UI. Completion must verify the agent before
starting the same queued turn. Genuine pause, approval and access gates
remain effective.

**Reproduction:** Create an OpenCode Runner agent with a
responsible-user OpenRouter binding and no personal default; assign a
task while verification is pending. The base retries verification and
shows an unexplained queue.

Related: #18702 handles pending task connection recovery after account
repair. This PR handles the earlier agent-verification boundary. #20330
addresses a separate Codex governed-wait timeout and is already merged.

## What Changed

- Share owned account-selection failure evidence through a pure library
contract. Lifecycle policy parks those configuration failures with
fixed, redacted guidance; temporary infrastructure errors retain their
retries.
- Batch setup-state reads for unstarted queued turns. Distinguish manual
repair from automatic setup retries and preserve Stop, started/history
state and lifecycle holds.
- Reuse the existing `connection_intent` card, account selection and
completion APIs. Its controller-only `agentSetup` marker accepts only
never-started legacy turns; runtime tokens still require a running run.
- Address the card to the lifecycle verifier's account owner, preserving
the task's execution principal and private-task visibility. Attach
missing cards on admission, verification, startup and full recovery,
including retained retries and continuations. Repeated delivery and
publication remain bounded. A new queued turn supersedes the setup card
of a stopped turn; generic connection cards retain cross-run reuse.
- Recheck lifecycle verification after usable-account completion, then
release the existing turn through the normal readiness path. Preserve
decline, Stop, reassignment and changed setup-owner gates. Fence an
in-flight verification failure from overwriting a repair; add no
provider wake or recurring worker.
- Park owned account refusals during resume as well as initial
verification. Bind setup cards to the lifecycle operation, settle
obsolete deliveries, and keep explicit Retry guidance accurate.
- Reuse the router’s existing lifecycle pin for setup repair without
rerouting the task, advancing the pool cursor, or replacing its saved
binding. Legacy direct-account cards remain readable.
- Hide the incorrect Resume banner during setup, retaining genuine
manual/budget pause controls. Document the execution and retry contract.

## Verification

- Red: eight original behavior assertions failed on the base, including
the real selector's retry decision and the real batched queue
projection. Six owned selection cases failed classification.
Temporary-error presentation, different task/verifier users, retained
retry/continuation recovery and the setup Resume banner also have
failing-before/passing-after regressions.
- Green: 430 affected backend, lifecycle, shared-contract and UI tests
passed before the final review corrections. Subsequent focused runs
cover one inline card, real account selection/completion, duplicate
delivery/publication, verification before readiness, unchanged run
authority, private tasks, no extra provider wake,
decline/Stop/reassignment, company isolation, invalid runtime tokens,
transient retries and redacted diagnostics.
- Final setup/card and generic connection-service suites: 49 tests
passed. The stopped-turn case failed before the correction, then passed
with real account completion, the stopped source remaining cancelled,
and the replacement source remaining queued.
- After rebase, all 129 focused assertions passed. The local queue
suite’s 88 execution assertions passed repeatedly, but its
database-fixture teardown exceeded both 30-second and 120-second hooks.
An isolated queue case completed, and the setup/connection suites fully
passed. The original queue test and cleanup remain unchanged; broad CI
supplies the full-suite result.
- Server/UI typechecks, module boundaries, token gates and diff checks
passed. `pnpm verify --explain` requested broad CI because the
execution-contract document changed; no redundant full local suite was
substituted.
- Real source acceptance: macOS arm64, Node 26.4.0, isolated embedded
PostgreSQL and local board identity. Created an OpenCode/OpenRouter
agent and task through the API with no default. Admission retained one
unstarted turn and produced the existing inline Connect OpenRouter card.
The browser opened its credential form and closed it without entering
credentials. The same card/run persisted after server restart and
reload, with the setup label and no incorrect Resume. The browser also
reproduced Stop followed by a new queued turn retaining the stale card
on the prior head. On `12f609c98372fd1e50644028db75cfcc8deb210d`,
startup superseded the stale card and retained the same replacement
turn, with the original turn still cancelled and no provider execution.
- The earlier CI case-search failure also reproduces on exact base
`0e3fdebea8257bdff11573081c76b306f12db230` without this PR. Its repair
is now in master via #20371; this branch is rebased onto it and contains
no API-search changes.
- Staging's actual Runtime test returned “Connect an account and choose
your personal default” before provider startup. The original turn later
started independently on deployed code, then hit a separate
workspace-export failure. Automatic file recovery subsequently marked
that run successful; its task remains Blocked and the trial’s useful
output is unverified. This PR is not deployed; provider authentication
through its card and downstream publication remain unverified. No
account, credential, default, permission or binding was changed during
diagnosis.
- Previous revision review: Greptile 5/5 on
`12f609c98372fd1e50644028db75cfcc8deb210d`, with all four inline
findings addressed and resolved. [Full CI
passed](https://github.com/paperclipai/paperclip/actions/runs/42713494508)
on that revision: 59 successful checks, one neutral check and three
intentional skips, with no pending or failed checks.

- Latest revision `976bcae993805a8a2222395bbff9394f6791b424`: resume,
router and Retry-copy regressions failed before repair. Green: 92
lifecycle/setup/shared tests, 83 setup/generic-connection/router tests,
and 137 UI/shared tests. Server/UI typechecks, module boundaries and
token gates passed. [Full CI
passed](https://github.com/paperclipai/paperclip/actions/runs/42720731137)
on this exact revision: 59 successful checks and three intentional
skips, with no pending or failed checks. Greptile reviewed this head at
5/5; all six review findings are addressed and resolved. Real Stop/retry
acceptance retained the same replacement turn and current-operation card
through two actual server restarts, with no provider execution.

## Risks

- Known account configuration failures now require repair or explicit
Retry. Temporary failures keep automatic retries; accepted work and
authority remain intact.
- The projection adds one company-scoped batch read only for unstarted
queued turns. Card attachment examines at most 100 active candidates and
adds no timer, worker, schema or migration.
- The optional stored setup-card marker requires an aware reader during
rollback. No run/session/checkpoint identity format changes. Setup
presentation grants no access and cannot bypass verification or other
gates.

## Model Used

- OpenAI GPT-6 (Codex), with reasoning, tool use, code editing and test
execution. The exact serving model identifier and context-window size
are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-09 17:49:34 -06:00
DottaandClaude Opus 5.5 1baac27888 feat(server): chat bootstrap reads for instant task opens (#20355)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - People open tasks from the task list to see the latest messages and
to reply to an agent
> - Before the task chat shows its first frame, it waits for about ten
separate reads: the issue, recent comments, comment input facts, recent
activity, recent runs, interactions, attachments, live runs and the
active run
> - On a busy instance each read waits for the database, and the slowest
read decides when the chat appears. A cold open takes 1.5–4 s on staging
> - This pull request adds one read that returns all of that data for up
to ten tasks, in the same JSON shapes as the existing endpoints, plus a
single-task form
> - The benefit is that the task list can preload its top tasks, and a
cold open needs one round trip instead of about ten. The UI change is in
the stacked pull request

## Linked Issues or Issue Description

**Problem or motivation**
A task open waits for about ten reads. With the database under load,
these reads queue, and a cold open takes seconds. The list cannot
preload a task cheaply, because each task costs about ten requests.

**Proposed solution**
`GET /api/companies/:companyId/issues/chat-bootstrap?ids=` returns the
first-frame data for up to 10 tasks. `GET
/api/issues/:ref/chat-bootstrap` returns it for one task. Each field
equals the matching single endpoint's JSON exactly.

**Alternatives considered**
- Prefetch the existing endpoints for each list row. For 30 rows this
sends about 210 requests to a database that is already the bottleneck.
- A new projection with different shapes. This would duplicate client
merge logic, and freshness rules could drift.

**Roadmap alignment**
This is part of the task-loading performance plan in #20276. It follows
#20277, #20284 and #20286.

## What Changed

- `packages/shared`:
  - `ISSUE_CHAT_BOOTSTRAP_MAX_IDS` (10).
- `issueChatBootstrapQuerySchema`: UUIDs or identifiers, normalized,
deduplicated and strict.
  - The `IssueChatBootstrap` and `IssueChatBootstrapItem` types.
- New `server/src/services/issue-chat-bootstrap.ts`:
- Resolves the refs inside the company and applies the `issue:read`
decision to each task.
- Reads the tasks with a concurrency of 2, and returns them in request
order.
- `server/src/routes/issues.ts`:
- The core issue read and the recent-comments read are now shared
helpers, so the bootstrap and the single endpoints use the same code.
The core view keeps its Server-Timing header.
  - Adds the batch route and the single-task route.
- Excludes the single-task route from the issue ETag middleware, so a
fetch without validators always gets a 200 with `Cache-Control: private,
no-store`.
- New `server/src/services/issue-run-presence.ts`:
- The live-runs and active-run payload builders, moved from `agents.ts`
without change.
  - The existing routes call them, and their behavior is unchanged.
- `server/src/routes/openapi.ts`: entries for both routes.

## Verification

- `cd server && npx vitest run
src/__tests__/issue-chat-bootstrap-routes.test.ts` passes 17 tests. They
run on embedded Postgres with privacy enforcement on. They cover:
- Each field deep-equals its single endpoint's JSON, for an ordinary
task and for a conversation task.
- The single-task route equals the batch item, by UUID and by
identifier. It is never answered with a 304.
  - Items keep the request order, with UUIDs and identifiers mixed.
- Private, other-company, missing and unknown tasks are omitted, and
none of their data appears. The single-task route returns 404 for them.
- Malformed, extra or repeated parameters return 400. More than 10 ids
also return 400.
  - A task-bridge key gets 403.
- A 10-task request writes nothing: no inserts, updates or deletes, and
no activity-log or comment changes.
- The issue, agent, activity, live-run, cold-open, summaries, ETag and
OpenAPI route suites pass: 56 files, 1,771 tests.
- `cd server && pnpm typecheck` passes.
- Query cost, local embedded Postgres, one 10-task request: about 49 SQL
statements per task, 55–130 ms in total. A test fails if it goes above
60 per task.

## Risks

- **Database load:** the stacked UI preloads up to 30 tasks, about 1,500
statements at idle time. This is the same work as opening those tasks,
but it is done before the person clicks. The work runs in sequential
requests of 10, with 2 tasks at a time. Most of the cost is existing run
decoration. Live runs and the active run decorate the same running run,
so that work runs twice. Sharing it is a follow-up.
- **Stricter access:** live runs and the active run now apply the
`issue:read` policy inside this endpoint. The existing routes keep their
company-only check.
- Hidden tasks are returned, as `GET /issues/:id` returns them.
- No migration and no persisted-state change.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, used in Claude Code
with tool use (shell, browser automation, file editing, subagents).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 15:05:41 -06:00
DottaandPaperclip c67909cb0f fix: keep tool approvals valid through OAuth refresh and delayed review (#20340)
## Thinking Path

> - Paperclip lets people manage agent work and approve app actions.
> - An approval must bind the action that the person reviewed.
> - OAuth access tokens can expire while that person is away.
> - The old target snapshot treated each token refresh as a new
authorization. It also imposed a one-hour review deadline.
> - This pull request separates token renewal from authorization
identity and keeps the human decision durable.
> - Current access, the reviewed arguments, meaningful target changes,
task closure, and execution receipts still control dispatch.
> - People can approve later without repeating a decision after routine
connection maintenance.

## Linked Issues or Issue Description

**What happened?**

A pending app action returned `approved_tool_target_changed` after its
OAuth tokens refreshed. The tool and connection settings were unchanged.
The same card also expired after one hour. A sign-in problem could
discard an accepted decision before provider dispatch.

**Expected behavior**

The original card remains reviewable after routine OAuth refresh and a
server restart. A later approval runs the exact reviewed action once. A
connection repair preserves the decision while Paperclip verifies the
same authorization. Meaningful changes require a new review.

**Steps to reproduce**

1. Connect an OAuth MCP app and configure an action to require approval.
2. Request the action, then refresh its access and refresh tokens before
approving.
3. Approve the original card. Before this change, it returns HTTP 409
even when the authorization is unchanged.
4. Wait more than one hour. Before this change, the card expires without
a task-specific deadline.

**Paperclip version or commit**

Reproduced from master at `76254ead2229`. The final branch is rebased
onto current master.

## What Changed

- Add versioned approval target comparison. New snapshots bind
credential identity epochs, consent, permissions, ownership, connection
configuration, tool contracts, and credential references. Authenticated
OAuth refresh preserves identity. Manual credential replacement does
not.
- Remove the implicit one-hour deadline from ordinary app action
reviews. Keep explicit deadlines and terminal-task expiry. Synchronize
the nullable interaction deadline in shared contracts and UI.
- Keep accepted, undispatched actions when sign-in is required. Show a
saved-approval repair state. Resume on committed connection changes
after target and access revalidation, without an idle retry loop.
- Preserve the existing execution claim, result receipt, and
uncertain-outcome no-replay rules.
- Explain meaningful target changes without inviting the person to retry
the stale card.
- Add a production task-thread Storybook example and document
compatibility and recovery behavior.

## Verification

- Red: production-refresher invalid-grant handling and formal-approval
withdrawal during a sign-in wait also reproduced as failing regressions
before their fixes.
- Red: before implementation, the local OAuth HTTP fixture failed for
both public and confidential clients with `approved_tool_target_changed`
after token refresh.
- Green: the extended fixture passes for public and confidential clients
with personal and shared grants. It covers actual local HTTP token
exchanges, multiple refreshes, a rebuilt gateway, an ended originating
run, approval after 25 hours, duplicate approval, preserved sharing
arguments, sign-in waiting, and event-driven repair. The gateways use
the production OAuth refresher; an invalid refresh preserves the
accepted decision before provider dispatch. Omitted-scope responses
cover equivalent scope-reporting changes. The provider is an isolated
local fixture, not a deployed Notebook service.
- Negative controls refuse changed consent, scopes, tool definition,
destination, and manual credential replacement before provider
execution.
- Existing gateway service, connected-tool acceptance, secret owner,
secret service, unsigned-review queue, and connection-health suites
passed. Explicit-deadline fixtures still prove expiry behavior,
including deadlines on accepted sign-in waits. A withdrawn formal
approval cancels a waiting action before connection recovery.
- Approval card, task-chat, error-copy and target-comparison tests
passed. Server and UI typechecks passed. Token gates and Storybook
catalog checks passed.
- Inspected the new saved-approval repair card in local Storybook using
the production task thread. It shows a reconnect link and no second
approval button or false running state.
- `pnpm verify --explain` returned exit 2 and requested broad CI
coverage. [Full
CI](https://github.com/paperclipai/paperclip/actions/runs/42677855507)
passed on `eb4f1c7caa9ee6e802c314ffc5eadec475a5de0c`, including build,
typecheck/release registry, general and serialized tests, and all eight
browser shards.
- Greptile reviewed the same final head at 5/5. Both findings from the
first review are fixed and their threads resolved; no open follow-ups
remain.

## Risks

- No database migration is needed. The new comparison reuses the vault
identity epoch. Only authenticated OAuth refresh code can preserve that
epoch; HTTP credential-write schemas cannot select that behavior.
- Earlier signed requests keep their original exact-version checks and
saved deadlines. Already-expired cards are not revived. A historical
card whose credentials already changed needs a fresh review.
- A new consent, account, permission set, destination, or manually
replaced credential must not inherit the old authorization. Reconnection
continues automatically only when revalidation proves the same saved
authorization.
- The interaction enrichment now permits a null deadline. Existing
string deadlines remain valid. The web client and shared validator
change together.
- This PR does not deploy to staging or perform a live Notebook
publication.

## Model Used

OpenAI Codex, GPT-6 family, with repository tools, code execution, and
browser inspection. The runtime does not expose the exact model ID,
context-window limit, or reasoning-mode label; those values are not
asserted.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-09 13:46:28 -06:00
Dotta a3e7e63330 Guard Native recovery with process-space proof and explicit containment (#19813)
## Thinking Path

> - Paperclip manages agents and their work.
> - Recovery must preserve execution ownership and accepted results.
> - A saved PID proves nothing outside its recorded process namespace.
> - Uncertain unfinished work must stay held until its original owners
stop.
> - Operators need a source-bound containment action and a separate
ordinary Retry.
> - Accepted results must use the existing finalizer without another
provider turn.
> - This PR keeps those paths safe, recoverable, and quiet between real
obligations.

## Linked Issues or Issue Description

Refs: #19713

Refs: #19591

Recovery could use a local PID to release or replace a controller from
another process namespace. Connected-chat Retry also rejected successful
containment on a task in `todo`. The new containment action used a
broader permission than the existing owner-stop action. A later review
found that result-less guards also rejected the existing accepted-result
confirmation action.

## What Changed

- Record and verify the controller's kernel/PID namespace. Keep unknown
and foreign unfinished ownership held. Preserve independent durable stop
evidence and the existing remote lease fences.
- Use the shared accepted-result ownership reconciler. Bind settlement
to the observed lease token, generation, boot, PID, namespace and
process birth. Retain finalizer, cleanup, current-controller, live-owner
and remote exclusions.
- Share the remote-owner reader across recovery consumers. Scope runner
leases to the same company, task and run. Do not make local PID probes
for remote accepted-result ownership.
- Gate original-host containment on `runtime:confirm_owner_stop`. Bind
it to the current task, source, assignee, original expiry, lease and
Stop state. Audit separate controller/provider containment and reviewed
action outcomes.
- Keep containment separate from ordinary Retry. Use one canonical
committed receipt and the normal admission, budget, workspace and
lineage checks. Preserve the recorded external-action outcomes.
- Keep the controller-only confirmation actionable for both result-less
work and accepted results. Result-less work gets its next source-bound
attention in the same transaction. Accepted results keep their original
result and use normal shared settlement/finalization.
- Keep identity inspection quiet. Preserve the original foreign-owner
expiry and use the existing scoped finalizer in accepted-result recovery
controls.
- Update the recovery card, validators, execution projection, docs and
access maps. Reuse existing canonical columns; add no migration or
ownership backfill.

## Verification

Current publication head: `71ea76b568de09d6313d8992e803131d9d5c54f3`.

**The current fix has a causal red/green check.** On the test-only
revision, both foreign-local stopped/fenced controller cases failed
because recovery probed saved runner, process-group and provider PIDs in
this host's namespace. This measured the wrong probes; it did not run
duplicate providers. After the fix, the same two cases passed every
no-probe, no-claim, no-controller-stamp, no-stop-receipt and
unchanged-authority assertion. Three existing remote preparation, grace
and fenced-controller progress cases also passed. Total: **5 passed, 0
failed;170 filtered rows excluded**. All three normal affected App
TypeScript programs passed on this head (660,681 and428 roots).

The fix separates a controller wait from execution stop proof.
Independent live/grace evidence still schedules recovery. A
stopped/fenced foreign controller can pass this namespace guard only for
remote execution, which keeps its later checkpoint and never-launched
checks. Foreign local execution stays held before runner or provider PID
inspection.

Earlier source-scoped results remain evidence, not fresh executions on
the current head:

- On `c86dd741`, the complete failed-owner file passed **25/25**, with
no skips or filters. Empty scans wrote no controller stamps. Foreign
ownership kept its original expiry. Normal returned-claim settlement and
attention at the exact deadline passed.
- On `c86dd741`, **15 selected accepted-result/restart controls
passed**. The81 filtered rows are excluded. Both completion cases used
the existing scoped finalizer and kept their accepted result without
another provider turn.
- Trusted CI at synthetic merge `50d072a5` (actual master `1b7fe334`
plus `c86dd741`) passed the complete **17-case maintenance-server
file**. This includes the original90-real-second quiet observation and
two qualified hourly windows. The quiet case took118,918ms. The four
jobs that failed on the earlier publication all passed on that synthetic
merge.
- On `6243b32c`, the complete ownership-report file passed **29/29**.
Native NULL namespace stayed unprovable and generic compatibility
remained. Three selected recovery controls passed;170 filtered rows are
excluded.
- On `f81f2c3c`,356 business cases passed: whole ownership-route221,
recoveryUI70, owner-proof38 and controller-confirmation8; selected
accepted-result authority18; and one real connected-chat containment,
separate authorized Retry, useful Native result and downstream reply
case. The2,024 filtered rows are excluded. A separate earlier
accepted-result causal case kept the original result and completed after
restart without replay.

Normal Shared exports, App programs, UI typecheck, token gates and map
checks passed on their recorded revisions. Unchanged DB, adapter, Eval
and Runner inputs/outputs have explicit carry proofs. The clean normal
merge with fetched master `8fe524f7` preserves all31 exclusive owned
paths and14,827 unrelated master entries. The nine overlapping paths
were reviewed, including the upstream unidentified-run stop action.
Fresh CI must validate that actual merge composition.

PG cases used existing external PG17, fresh owned databases, pools at
most4, one worker and no SQL observer during cases. Registered clients
and recorded process groups closed. Independent final SQL audits found
zero campaign sessions before normal database cleanup. Original failing
fixtures remain retained.

Original failures are preserved. One new test first failed compilation
due to a missing getter import; an import-only correction passed its
full owning programs before the causal red/green check. A local quiet
attempt stopped in the normal prerequisite hook before any business case
and its collector rejected two normal build markers. The later17-case CI
pass establishes quiet recovery; it does not turn that failed local
collector into a pass. An earlier useful case passed before its private
cleanup collector failed on an owned read-only directory; normal cleanup
completed after all owners closed. Earlier runner-shutdown cancellation
and a separate private whole-suite failure remain unexplained.

Current-head checks are complete:57 success,1 neutral and3 skipped,
including the successful aggregate CI gate. The legacy status passed.
Greptile is5/5 and Ponytail gives an explicit5/5 Ship verdict for this
head. All seven review threads are resolved. Full recursive typecheck,
the full test suite and release build were not repeated locally. No
result here proves deployed suspension, a live provider or termination
on another host.

## Risks

- Unknown physical ownership can require an owner/admin action. A false
containment statement can be unsafe.
- New work, reassignment, Stop, renewed authority, accepted results or
pending cleanup can invalidate an action. The operator must refresh.
- Controller confirmation does not prove provider/tool containment.
Completed external actions must not be replayed.
- Generic legacy and child-process compatibility remains separate from
the strict Native controller policy.
- Existing saved state and canonical schema are preserved. Permanent
safety refusals remain held with their normal named recovery path.

## Model Used

OpenAI `gpt-6.1-sol` agents implemented and tested the changes with
reasoning, repository tools and code execution. A GPT-6-based Codex
managing agent reviewed and integrated them. The host does not expose
the manager's exact build or the context-window sizes.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-11-09 12:06:11 -06:00
DottaandClaude Opus 5.5 8fe524f796 fix(issues): let the board confirm an unidentified run stopped instead of an endless Retry wait (#20310)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Before a new attempt can start on a task, Paperclip must prove the
previous run's agent stopped, so two agents never work the same task at
once
> - A local native run can be interrupted after it asked to start the
runner but before it recorded the runner's process. The runner may have
saved state and started a provider, and provider processes can outlive
it, so the existing check (#19694) rightly refuses to assume the run
stopped
> - Today that case has no way out: every Retry is accepted and then
waits forever as `process_identity_missing` (storage chaos ST1, t02/t03)
> - This pull request makes the wait explicit and actionable. The task
explains why it waits, and a board operator who has checked can confirm
the run stopped; the parked Retry then starts at the click
> - A second shape from the Daytona storage baseline (t06) parked a
Retry with no reason at all: a follow-up was interrupted by a graceful
shutdown while it was still restoring its workspace. No provider ran,
but the restore hold kept the same agent held, so the Retry never
started
> - The benefit is that no Retry stays accepted-and-waiting with nothing
anyone can do

## Linked Issues or Issue Description

Refs #19831. Storage chaos wave `w-20261109T145628-s9902` (ST1), tasks
t02 and t03.

**What happened (CHA-3, run `3c3f6241`):**
- The run requested a runner launch (`native.process_start_requested`),
and a K2 restart hit before its process identity was recorded.
- After the restart, the resumed attempt failed on the storage outage.
The task was blocked.
- The board's Retry (202) was parked as `executionWait.reason =
process_identity_missing`: "The previous run has no verified stop
record."
- `recordUnidentifiedLocalRunnerStop` cannot prove the stop because this
run's runner saved control-plane state. Once that exists, a provider may
have started (#19694), and a provider is not guaranteed to carry
`--run-id` or `PAPERCLIP_RUN_ID` (the Codex provider env omits it on
purpose). The shared owner prover needs a PID, which the run never
recorded.
- Nothing could ever clear the wait.

**Daytona storage baseline `w-20261109T154810-s9911`, task t06:**
- The run succeeded. The follow-up was cancelled
(`continuation_task_ownership_changed`), and the next run was
interrupted by a graceful shutdown (`server_shutdown_interrupted`) 3 s
into `preparing`. It was restoring the saved remote workspace and had
launched no provider.
- Restore recovery saved the files (`workspaceRecovery.status:
recovered`, system recovery `complete`). But the
`legacy_execution_requires_reconciliation` restore hold releases only
for a different owner, or for a native Stop fenced before any provider
turn, so it kept the same agent held.
- The UI Retry returned 202 and parked with `executionWait.reason:
execution_recovery`, the generic wait, so the task showed a Retry that
never started.

Automatic proof needs the runner to record its identity before saving
state and to group provider processes under it. That is follow-up runner
work; this PR removes the endless wait now.

## What Changed

- `server/src/services/native-local-process-stop.ts`: new
`confirmUnidentifiedLocalRunnerStopped`. It accepts only a finished
native run of the task with no recorded process and whose latest launch
evidence is an unconfirmed launch on this host in a local environment.
It still refuses while a runner with `--run-id <run>` is running. It
records `native.local_process_stopped` with `basis: "operator_attested"`
and the attesting user. That is the receipt the existing continuation
gate already accepts.
- `server/src/routes/issues.ts`: `POST
/issues/:id/recovery-actions/confirm-run-stopped` (`runId`,
`stopEvidence` of 20 to 12,000 characters). It is board-only and
requires issue read plus `runtime:confirm_owner_stop`, like the other
stop attestations. It logs `issue.run_stop_confirmed` with the evidence,
promotes deferred intents for the issue, and resumes each parked task
Retry, so work starts at the click. Refusals return 409 with a code.
- `packages/shared`: `confirmRunStoppedSchema`, and the presentation
user action `confirm_run_stopped`.
- `server/src/services/task-interruption-presentation.ts`: a Retry
parked as `process_identity_missing` for a native run that recorded no
process now presents as waiting for the user (`canRetry: false`,
`userAction: "confirm_run_stopped"`), with a message explaining why and
who can act. A run with a recorded process keeps the existing
verification wait.
- UI:
- `ExecutionBlockerNotice` shows the explanation and, for users who can
confirm a stop, "Confirm it stopped" with a short evidence form.
- It reuses `PreviousServerStopConfirmation`, now with optional
`action`, explicit `runId` and `formId`, and a custom button label.
  - The Inbox names the action.

- `server/src/services/execution-blocker.ts`:
`interruptedPreparationBeforeProviderWorkCondition`. The restore hold
also releases for the same agent when the stopped run was a
system-interrupted preparation (legacy runtime never resolved, still
`preparing`) with no process identity, no runner or provider events, no
finalization or result, and every lease released with a confirmed stop.
It mirrors the existing interrupted-preparation proof and still requires
the completed workspace-recovery receipt. Auto-replay is unchanged; this
only lets the user's Retry or message start.
- Review fixes:
- `unidentifiedLocalLaunchRefusal` holds the endpoint's launch, host and
lease checks, and the presentation offers `confirm_run_stopped` only
when it passes.
  - The attested stop wakes cost accounting in the same transaction.
  - The confirmation form is keyed by task and run.
  - The route is registered in OpenAPI.

## Verification

Red/green (each new test fails against master and passes with this PR):
- `server/src/__tests__/issue-confirm-run-stopped-routes.test.ts`:
- The parked Retry presents `confirm_run_stopped` with the explanation.
- Confirming records the operator-attested stop and the activity entry,
satisfies the stop check, and resumes the parked Retry: its receipt is
coalesced into a newly started run.
  - It refuses with 409 while a runner for the run is running.
  - Agents and viewers get 403.
-
`ui/src/components/ExecutionBlockerNotice.confirm-run-stopped.test.tsx`:
the notice offers "Confirm it stopped" (and no dead Retry) and posts the
run and evidence. A viewer sees the explanation without the action.

- `server/src/__tests__/interrupted-preparation-restore-retry.test.ts`
(t06 shape):
  - The restore hold no longer blocks.
- A Retry is accepted and resumed into a started run, and the audit hold
keeps `replay: blocked`.
- The hold stays when a provider turn started, when a runner event was
recorded, when an operator stopped the run, or when the sandbox has no
stop receipt.
- `issue-confirm-run-stopped-routes.test.ts`:
- A case per refusal code checks the presentation keeps the generic wait
and the endpoint returns 409.
  - An `alreadyStopped` case.
  - An accounting-wake assertion.
- The UI test switches targets with stale evidence.

Regression and static checks:
- `ExecutionBlockerNotice`, `WorkspaceExportRecovery` and its control
tests: 74 passed.
- `tsc --noEmit` passes for `packages/shared`, `server` and `ui/src`.
`pnpm check:token-gates` is clean.

## Risks

- A board operator can now attest that an unidentified run stopped. The
attestation is permission-gated, requires written evidence, is
activity-logged, and is refused while a runner for the run is visibly
running. A wrong attestation could start a second agent beside an
orphaned provider, the same trust model as the existing previous-server
attestations.
- The confirmation component now accepts a run without a recovery
action. Existing callers pass the action as before.
- No schema migration.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, via Claude Code with
tool use (shell, file edits).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 11:36:41 -06:00
DottaandPaperclip ff2d463eed feat(cli): manage agent grants and keep remote login on the public origin (#20323)
## Thinking Path

> - Paperclip lets people control their AI agents and permissions.
> - Remote operators need a browser-approved CLI login.
> - Proxies can send that login's approval link to an internal host.
> - Human member commands cannot grant an agent an explicit permission
such as commentary:view.
> - This change keeps approval on the canonical public origin and adds
Board-only single-grant commands.
> - The API checks company access and permission-management authority
and records each change.
> - An operator can sign in, grant one agent permission, and preserve
the agent's other grants.

## Linked Issues or Issue Description

**What happened?**

A proxied CLI login returned an approval URL on the upstream host. The
signed-in browser was on the public host. The CLI also had no command to
add an arbitrary explicit agent grant: member commands manage human
members, while agent permissions:update exposes fixed configuration
fields.

**Expected behavior**

Approval uses the configured canonical public origin. A Board operator
with users:manage_permissions can grant or revoke one explicit agent
permission without replacing other grants or activating an inactive
membership.

**Steps to reproduce**

Configure a public auth origin. Create a CLI challenge through a proxy
that replaces forwarded-host headers. Inspect the approval URL. Then try
to grant commentary:view to an agent through the CLI.

## What Changed

- Use the existing public-origin resolver for CLI approval URLs.
- Add agent permission:grant and permission:revoke commands.
- Add PATCH /api/agents/{id}/permission-grants with strict shared
validation and Board-only OpenAPI metadata.
- Serialize each mutation on the agent row. Preserve unrelated grants
and membership state. Commit the grant and its activity record together
and publish activity after commit.
- Document remote login and single-grant management.

## Verification

- The new approval-link regression failed before the fix and passes
after it.
- All 25 CLI auth route tests pass.
- All 72 affected CLI, login and OpenAPI tests pass.
- All 5 PostgreSQL grant tests pass, including actual commentary reads
(403 before grant, 200 after grant, 403 after revoke), preservation,
audit attribution, concurrent additions, invalid inputs, inactive or
missing membership, agent self-grants, cross-company denial, and
rollback on audit failure.
- Shared and CLI typechecks and server declaration-layer checks pass.
- pnpm verify requests broad CI coverage because doc/CLI.md is a global
verification input. Greptile reviewed final head
338c58fb24 at 5/5 with no findings. All 58
non-skipped checks pass on that head. CI run:
https://github.com/paperclipai/paperclip/actions/runs/42663640985. Live
target acceptance is in progress.

## Risks

This adds an explicit permission-management API. It requires Board
authentication, company access, and users:manage_permissions.
Foreign-company agents return 404. Granting a key intentionally makes
that key unscoped in its company; revocation removes that key. Other
keys and agent configuration remain unchanged. Inactive memberships and
unapproved or terminated agents cannot gain grants. No schema change is
needed. Revert this change to remove the new management surface;
existing grants retain their normal authorization rules.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code editing, shell tools,
and browser testing. The runtime does not expose a more specific model
ID or context window.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-09 11:35:52 -06:00
DottaandClaude Opus 5.5 4f7eee10c2 feat(recovery): let the board confirm an unrecorded owner stopped for every settling process kind (#20084)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Recovery releases in-progress records (leases, claims, intents) only
when it can prove their owner is gone
> - A record saved before its server process was fully recorded is
`unprovable`, and it is never released on its own
> - #20067 added a board-only action to confirm that such an owner
stopped, but only the environment run lease used it
> - Other settling kinds (for example the legacy controller lease, which
shows `missing_identity` rows in the Phase 2 reconciler data) stay stuck
with no way forward
> - This pull request opens the same confirmation to every settling kind
whose record names a partly recorded server process
> - The benefit is that an operator can release these stuck records
safely, and recovery settles them at once

## Linked Issues or Issue Description

Refs #20067, #20054

**What happened?**
The Phase 2 reconciler data shows `legacy_controller_lease` records that
stay `unprovable` with `missing_identity`: they were saved before
Paperclip stored the controller's PID space. Recovery never releases an
unprovable owner, and only the environment run lease offered the board's
"confirm the previous server stopped" action. These records, and records
of other settling kinds saved the same way, had no path forward.

Also, a board confirmation did not wake the reconciler. Unprovable
records are not watched, so the release waited for some unrelated pass.

**Expected behavior**
Recovery asks the board on the record's task. After the board confirms,
recovery releases the record through the kind's own compare-and-swap
settle, at once. A confirmation never releases a record that changed
since the board was asked.

**Steps to reproduce**
1. Have a legacy run whose `controller_process` was recorded without a
host hash (an older server).
2. Run the ownership reconciliation pass. The record is `unprovable`
(`missing_identity`) and no board action appears.

**Paperclip version or commit**
master at c55af26821.

## What Changed

- `ownership-registry.ts`: a new `ownerGoneAttestable` helper opts a
settling kind in. The kind asks the board (cause
`ownership_owner_unprovable`) only for a process-owned record that is
unprovable for a legacy reason and has a version. Opted in:
`legacy_controller_lease`, `environment_teardown_claim`,
`sandbox_creation_intent`, `workspace_runtime_control_operation`,
`native_workspace_finalize_attempt`, `native_finalizer_lease`,
`native_cleanup_lease`.
- `owner-gone-attestation.ts`:
- The request records the record version (`recordUpdatedAt`), and each
pass refreshes an open request to the current version.
- The board submits the version it was shown (`recordVersion`, a new
optional field in `confirmOwnerGoneSchema`). The confirmation is refused
with 409 unless that equals the request's current version and the locked
record's version.
- `recordVersionAttestations` reads back every resolved confirmation.
Any one that names the record's current version applies.
- `confirmOwnerGone` now wakes the ownership reconciler in its
transaction.
- Each opted-in kind has a version lock. For an `operator_attested`
proof, its settle runs in a transaction that locks the record row and
re-checks the confirmed version before the kind's own compare-and-swap.
- `ownership-invariant-report.ts`: in the periodic pass and in one-shot
settles, a matching confirmation turns a legacy `unprovable` verdict
into `gone` (`operator_attested`). A live or provable owner always wins.
The extra read runs only when a kind has such a record.
- `WorkspaceExportRecovery.tsx`: the board's confirmation names the
stuck record by kind (for example "This task's earlier run"), with a
generic fallback, and sends the version it showed.
- `doc/execution-semantics.md`:
- It describes the action, the version binding and which kinds are
offered.
- It updates the controller-lease section to match #20054: the holdings
list, and that the lease is off only on Railway deployments with an
exclusive volume.

## Verification

- `pnpm exec vitest run src/__tests__/owner-gone-attestation.test.ts`
(server): 10/10. The new legacy-controller cases fail without the
change:
  - the board is asked, and nothing is released before the confirmation;
- the confirmation wakes the reconciler, and the next pass settles the
record as `operator_attested`;
- a record that changed after the confirmation is not released, and a
fresh request is raised;
- a record of these kinds with no owner stamp is not offered, because
its settle could never release it;
- a confirmation for a version the record no longer has is refused, and
the refreshed request then applies;
- a write between the reconciler's listing and its settle stops the
release inside the settle's transaction.
- The 10 server ownership suites (registry, report, owner proof,
controller lease, legacy controller, teardown, finalize, token leases):
332/332.
- `pnpm exec vitest run
src/components/WorkspaceExportRecovery.control.test.tsx` (ui): 48/48.
- `pnpm check:token-gates`: all gates clean.
- `PAPERCLIP_TYPECHECK_LOW_MEMORY=1 pnpm typecheck` in `server` and
`ui`: passed.

## Risks

- A wrong release would be serious. The safeguards:
- The confirmation applies only while the record's last-write time
equals the one the board was asked about, and only while the prover
still finds the recorded process unprovable for a legacy reason.
- Each kind's settle still compare-and-swaps on the exact recorded
process.
- A record of these kinds with no owner stamp at all is not offered.
Those settles cannot release it, so it keeps its existing recovery path.
- Kinds that are unowned by design (queued pending cleanup, accounting
debt) are not offered.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), via Claude Code with tool use
(shell, file edits, test execution).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 12:16:07 -06:00
DottaandClaude Opus 5.5 0746d1203d feat(recovery): let the board confirm that an unrecorded owner stopped (#20067)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - After a restart, recovery releases an in-progress record only once
its owner is proven gone, never by age
> - A run lease saved before owners were stamped has no owner Paperclip
can judge on an ephemeral (multi-host) server, so it stays stuck and
holds its run's sandbox forever
> - Only a person can tell that the previous server stopped (for
example, its container was replaced)
> - This pull request asks the board on the stuck task and lets an owner
confirm the stop, with an activity-log entry; recovery then releases the
record on its normal path
> - The benefit is that legacy stuck records have a way out that never
guesses

## Linked Issues or Issue Description

Follow-up to the Phase 2 durable-ownership work: #20054 (controller
instance lease) and #19883 (process-space recording). It generalizes the
existing "confirm the previous server stopped" action for native
controllers (`native_controller_host_unverified`). No duplicate PR was
found.

**What happened?**

On an ephemeral server, an active run lease of a finished run that was
saved before holders were stamped has no owner stamp. The ownership
reconciler reports it `unprovable (no_owner_stamp)` and never settles
it. No operator action exists, so the lease and its sandbox stay
reserved.

**Expected behavior**

The task shows the stuck resource, and a board owner can confirm that
the previous server stopped. Recovery then releases the lease. Agents
and operators without the owner-stop permission cannot.

**Steps to reproduce**

1. Run with `PAPERCLIP_EPHEMERAL_SERVER=true`.
2. Have an active environment lease with no `leaseController` stamp,
whose run is terminal.
3. Run an ownership reconciliation pass. The lease stays `unprovable`
with no action on the task.

**Paperclip version or commit**

`master` before this PR.

## What Changed

- `packages/shared`: `confirmOwnerGoneSchema` (`actionId`, `recordId`,
`stopEvidence` of 20 to 12000 characters).
- `recovery/owner-gone-attestation.ts`:
- `requestOwnerGoneConfirmation(kind)` is an `onUnprovable` hook. For a
legacy unprovable owner (`no_owner_stamp`, `process_space_unrecorded`,
`missing_identity`) on a record that has a task, it opens one idempotent
board recovery action on that task (cause `ownership_owner_unprovable`).
- `confirmOwnerGone(...)` verifies the exact action and record. It asks
the kind to write the attestation (compare-and-swap), resolves the
action, and writes an `issue.ownership_owner_gone_confirmed`
activity-log entry with the actor and the stated evidence.
- Ownership registry:
  - `OwnableKind.attestOwnerGone` is a new optional hook.
- `environment_run_lease_active` implements it: only an unstamped active
lease of a terminal run, with the notification for the cleanup path.
- The lease's owner then reads `operator_attested`, which proves gone,
so the existing settle releases it. A holder stamped since the board was
asked owns the lease, and its stamp decides.
- Route: `POST /api/issues/<built-in function
id>/recovery-actions/confirm-owner-gone`. It uses `assertBoard` plus
`runtime:confirm_owner_stop`, the same board-only permission as
confirm-controller-stopped. It is registered in OpenAPI.
- UI: `issuesApi.confirmOwnerGone`. The task's recovery card shows the
existing `PreviousServerStopConfirmation` for this cause, with
resource-specific wording; owners confirm and operators see the wait.
`isPreviousServerStopCause` includes the cause, so the generic card does
not offer other resolutions.

## Verification

- `owner-gone-attestation.test.ts`:
  - the stuck lease opens one board action on the task;
- confirmation resolves the action, writes the activity log, and the
next pass settles the lease (`operator_attested`) exactly once;
  - a mismatched record is refused with 409;
- a holder stamped after the ask is refused and the lease stays active;
  - no action for a judgeable owner or for a record with no task.
- Red, with the `onUnprovable` hook removed: 2 of 3 fail.
- UI: `WorkspaceExportRecovery.control.test.tsx` checks that the owner
confirms with the right payload and that an operator sees the wait
without the control (47/47).
- Server suites: openapi-routes, ownership and recovery suites, plus the
existing native-controller-host recovery. Low-memory server typecheck is
clean; `check:token-gates` is clean.

## Risks

- The board can attest a server stopped that is in fact running. The
action and the UI copy ask for the evidence, and the activity log
records who attested what. This is the same trust model as
confirm-controller-stopped.
- Only run leases opt in so far. Records without a task (login/probe
leases) keep the legacy idle sweep.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), via Claude Code with
tool use.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 09:46:36 -06:00
DottaandClaude Opus 5.5 7fd98682ca fix(workspaces): give every subtask its own execution workspace (#19860)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents split work into child tasks, and each task runs in an
execution workspace (a checkout, branch, or sandbox folder)
> - Since early 2026, a new child task used its parent's realized
workspace by default: the same checkout, branch and sandbox
> - A parent and its child often run at the same time. Two writers in
one folder lose each other's files, the waking parent is cancelled with
`workspace_busy`, and sandbox lease ownership crosses from the parent
into the child, so retained-file recovery refuses the workspace as
ambiguous
> - The product rule is simple: a subtask gets its own workspace,
independent of the parent's saved files. Paperclip never needs to carry
a parent's unmerged changes into a child
> - This pull request makes that the only behaviour on every creation
path, and moves existing shared children to their own workspace on their
next run, with no user or admin action
> - The benefit is that parents and children never block or overwrite
each other, and recovery ownership stays with one task

## Linked Issues or Issue Description

**What happened?**
A child task inherited its parent's realized execution workspace by
default (`createChild` defaulted to `executionWorkspaceInheritanceMode:
"linkage"`, and `issueService.create` fell back from
`inheritExecutionWorkspaceFromIssueId` to `parentId`). When the parent
woke while the child wrote to the shared workspace, the parent run was
cancelled with `workspace_busy`. In sandbox environments, the lease
ownership chain crossed from the parent into the child, and
retained-file recovery refused the workspace with
`allocation_ownership_ambiguous`.

**Expected behavior**
Every new child task gets its own execution workspace, realized from the
project base exactly as a top-level task in that project. It never uses
the parent's checkout, branch, saved snapshot or unmerged changes. A
parent and its descendant never share a workspace by any route.

**Steps to reproduce**
1. Run a parent task in a project with isolated (git worktree) or
sandbox workspaces, so the parent has a realized execution workspace.
2. From the parent run, create a child task with only `parentId` (or
through the runner `create_task` tool, chat suggestions, decision
effects, plugins, or the New sub-task dialog).
3. See that the child's `executionWorkspaceId` is the parent's, with
`executionWorkspacePreference: "reuse_existing"`.
4. Wake the parent while the child runs in a sandbox environment. The
parent run is cancelled with `workspace_busy`.

**Additional context**
Refs #9233 (the existing `strategy_only` opt-out).
The opt-out `executionWorkspaceInheritanceMode: "strategy_only"` already
existed for accepted-plan decomposition. This change makes that
behaviour (tightened to drop a pinned existing branch) the only
behaviour.

## What Changed

- **One rule for every creation path
(`server/src/services/issues.ts`).** `issueService.create` still uses
the parent (or `inheritExecutionWorkspaceFromIssueId`) as a source for
the project, project workspace and workspace *strategy*, but it never
copies the source's `executionWorkspaceId`, `reuse_existing` preference,
or pinned existing branch. All server paths that create a task go
through `create()`/`createChild()`: issue routes (`POST /issues`, `POST
/issues/:id/children`, the run-bound default parent and run workspace
source), runner `create_task`, chat suggestion acceptance, native status
decisions, accepted-plan decomposition, decision effects, plugins
(`ctx.issues.create`), external agents, watchdog follow-ups, monitor
recovery issues, case handoffs and email channels.
- **Explicit ancestor workspaces are dropped.** If a create names an
`executionWorkspaceId` (or an `existing` workspace selection) that an
ancestor of the new task created or is bound to, `create()` drops it and
keeps only the strategy. Older clients and skills that copied the
parent's id keep working and get an independent workspace.
- **`createChild` no longer has a "linkage" mode.**
`executionWorkspaceInheritanceMode` is still accepted from internal
callers and is ignored.
- **`inheritExecutionWorkspaceFromIssueId` decision.** I kept the field
for API compatibility, but it now copies only the source issue's project
and workspace strategy. I removed its workspace-sharing behaviour for
every pair, not only parent/child: the source task and its follow-up can
run at the same time (the runner, watchdog and status-decision callers
all create the follow-up while the source run is live), so sharing would
again let two tasks write one folder. Explicit sharing between unrelated
tasks stays available through an explicit `existing` workspace
selection.
- **New `server/src/services/task-workspace-lineage.ts`.**
`buildIndependentTaskWorkspaceSettings` (strategy only: mode,
environment, runtime, network egress, shared-workspace concurrency, base
ref, branch template, commands; no `reuse_existing`, no
`operator_branch`, no `existingBranch`), `loadTaskLineageIssueIds` (the
parent chain plus, for a task that depth placement put beside its
requester, the requester's chain via `privacyParentIssueId`) and
`isAncestorExecutionWorkspace` (the workspace's `sourceIssueId` is in
that lineage, or a lineage issue is bound to it). A child in another
project does not take the parent's strategy.
- **Upgrade-safe rebind at admission.**
`executionWorkspaceService.releaseAncestorWorkspaceBindingAtAdmission`
runs at the same admission point as the pending workspace selection
(`heartbeat.ts`). For a child (or a flattened task beside its requester)
that an older release bound to an ancestor's workspace, it clears the
child's binding (keeps the project workspace and strategy, bumps the
binding revision) so the run realizes the child's own workspace. It does
nothing while another run of the child is running, while the child's
earlier run still owns workspace finalization or recovery, for native
restart/lease-owner recovery, for a process-loss retry, or for a Retry
that keeps the current workspace. The parent and its workspace are never
changed.
- **Projects without a project workspace (per-task repository
acquisition).** A parent with no project workspace worked in its own
task files, so its settings (for example `isolated_workspace`) do not
describe the project base. A child of such a parent, and an older child
released from one, takes the project's defaults exactly like a top-level
task, instead of an isolated mode that would resolve to a git worktree
with no git base ("needs a project / project workspace"). When the
child's new workspace is created at admission,
`executionWorkspaceRepositoryService.prepareForAdmission` repeats the
parent's (or requester's) repository requests as the child's own pending
requests (identity, URL, catalog id and requested ref only; no pinned
commit, branch or files). The normal acquisition path then clones a
fresh copy into the child's task files with the child's own access
checks. This runs only for a workspace created by that admission, so
existing tasks never gain repositories.
- **UI.** The New sub-task dialog no longer pre-selects the parent's
workspace. `buildSubIssueDefaults` drops `executionWorkspaceId` and
`reuse_existing`, and derives the parent's independent mode
(`shared_workspace`, `isolated_workspace` or `agent_default`) from its
preference, saved settings or current workspace. The "This sub-task will
no longer use the parent task workspace" warning is removed.
- **Contracts and docs.** Shared validator and plugin SDK comments
describe the new meaning of `inheritExecutionWorkspaceFromIssueId`.
Updated `doc/execution-semantics.md` (new rule in §6 and a wording fix
in the retained-sandbox paragraph), `doc/SPEC-implementation.md` (child
workspace rule, requester keeps *strategy* inheritance, watchdog
follow-ups), `doc/SPEC.md` (task workspace ownership),
`docs/specs/external-task-protocol.md`, `skills/paperclip/SKILL.md`
(step 9 and the workspace bullet),
`skills/paperclip/references/issue-workspaces.md`, the CEO onboarding
`HEARTBEAT.md`, and the plugin SDK README.

### Previous-release story (`rules/upgrade-safe-run-state.mdc`)

- **Migrated on next admission.** A child that the previous release
bound to its parent's (or any ancestor's) execution workspace keeps that
binding until its next normal admission. Then the server clears the
binding and the run realizes the child's own workspace from the project
base. No schema migration is needed. No user or admin action is needed.
- **In-flight writers finish first.** A running child is not
interrupted. Its current run, its native restart recovery (admitted
native input or lease owner), a process-loss retry, and a Retry that
keeps the current workspace all finish in the shared workspace. While a
child's earlier run is still running or its workspace finalization or
recovery is unsettled, the binding stays and a later admission releases
it.
- **No files are dropped.** The release changes only the child's binding
row. The parent keeps its binding, and the shared workspace row, folder,
branch and saved snapshots are not touched. Anything the child left
there stays in the parent's workspace.
- **No new refusal codes.** Saved run identity (native execution input,
leases, checkpoints) is not changed or refused; the rebind only affects
new admissions.

## Verification

- New `server/src/__tests__/subtask-workspace-independence.test.ts`
(embedded Postgres): `create` with `parentId`, `createChild` with no
mode / `"linkage"` / `"strategy_only"`,
`inheritExecutionWorkspaceFromIssueId` pointing at the parent, explicit
parent and grandparent `executionWorkspaceId`, a non-child follow-up,
and unchanged top-level defaults and explicit top-level reuse. 7
creation cases fail on `master` and pass with this change. Admission
cases: an old-release child is rebound while its parent is running and
the parent keeps its workspace; a running child is not rebound (deploy
lands mid-run); an unrelated explicit share is kept; the parent is never
rebound.
- New heartbeat case in
`server/src/__tests__/heartbeat-workspace-busy.test.ts`: an old-release
child bound to its running parent's workspace in a sandbox environment
runs to `succeeded` with no `workspace_busy`, gets a new workspace, and
the parent run and binding stay unchanged. It fails on `master` (the
child waits with `workspace_busy`).
- Updated tests that asserted the old inheritance in
`issues-service.test.ts`, `task-workspace-binding.test.ts`,
`chat-project-tools.test.ts`, `task-workspace-child-trust.test.ts`,
`heartbeat-git-restore-point-resume.test.ts` (a child bound to a closed
parent's expired workspace now starts from the project base and leaves
the parent's restore point alone), and
`ui/src/lib/subIssueDefaults.test.ts`. Remote-workspace reservation,
continuation and writer-wait suites now seed the older-release shared
shape directly (or an unrelated explicit share), so those safety paths
stay covered.
- `npx vitest run` on the changed suites and about 45 related server
suites (heartbeat workspace, recovery admission, issue routes, routines,
plugins), `ui` `subIssueDefaults` and `NewIssueDialog` tests, `pnpm
check:token-gates`, `pnpm -r typecheck`.

- New
`server/src/__tests__/heartbeat-subtask-acquired-repository.test.ts`: a
project with no project workspace, a parent whose task files hold an
acquired repository with an unmerged change, and a child (new, and the
older-release shape bound to the parent's workspace) that runs to
`succeeded` in its own task files with a fresh clone at the project base
and its own ready repository receipt. The parent's checkout keeps its
change. Both cases fail on the previous head with "needs a project /
project workspace".

## Risks

- **Project-level configuration still applies to children exactly as to
top-level tasks.** In a project configured for `shared_workspace`, every
task (top-level or child) uses the project's one folder under the
existing shared-workspace concurrency policy. A branch that the project
itself pins applies to every task in the project. This PR removes only
the parent-to-child carry-over of the realized workspace; it does not
change those project defaults.
- **Standalone follow-ups that an older release bound through
`inheritExecutionWorkspaceFromIssueId`** are migrated only when the
source is in their recorded lineage (parent or privacy parent). Others
keep their explicit share and the existing writer-wait serialization.

- **Behaviour change for agents that relied on a shared checkout.** A
child or follow-up no longer sees the parent's unpushed or uncommitted
changes. Agents must push or merge code they want a subtask to build on.
The skill and onboarding text now say this.
- **Explicit ancestor workspace ids are silently dropped** instead of
rejected, so older clients do not break. The task gets an independent
workspace.
- **First run of a migrated child starts from the project base.** If an
older child had uncommitted work in the parent's workspace, that work
stays in the parent's workspace and is not copied into the child's new
workspace.
- **Admission adds one indexed read** for tasks with a parent and a
bound workspace; the locking transaction and ancestor query run only
when the bound workspace was created by another issue.

## Model Used

- Claude Opus 5.5 (Anthropic), model ID `claude-opus-5-5`, used through
Claude Code with tool use (file edits, shell, test execution) and
extended reasoning.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 18:34:09 -06:00
DottaandClaude Opus 5.5 adb7633d7b fix(status-cards): give agents the person's restore route when archiving a card (#19903)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Status cards are saved summaries of company work. People and agents
can archive and restore them.
> - A person asked a chat agent to archive a card "to reuse it next
quarter". The agent archived it correctly.
> - The archive response had no board route, and the PATCH operation had
no description. The completion guidance tells agents not to guess
routes.
> - So the agent told the person to restore the card "by clearing
`archived`". That is an API instruction, not a route a person can use.
> - This pull request gives single-card responses an `href` to the
Status page and documents archive and restore on the PATCH operation.
> - The benefit is that an agent can give the person a usable link and a
true account of restore, which starts a fresh summary.

## Linked Issues or Issue Description

**What happened**
A chat agent archived a status card. Its reply told the person to
restore the card by clearing `archived` on the card. It gave no link to
the place where a person restores it.

**Expected behavior**
The reply links the card on the Status page, where a person can show
archived cards and click Restore. It also says that restore starts a
fresh summary.

**Steps to reproduce**
1. Enable status cards and create a card as an agent.
2. Ask the CEO agent in chat to archive the card for later reuse.
3. Read the reply. It has no usable restore route, because `PATCH
/api/status-cards/{id}` returns no `href` and has no description.

## What Changed

- `POST /api/companies/{companyId}/status-cards`, `GET
/api/status-cards/{id}` and `PATCH /api/status-cards/{id}` now return
`href`, the company-scoped Status page route for the card.
- The shared `statusCardSchema` has an optional `href` field.
- The `PATCH /api/status-cards/{id}` OpenAPI operation has a
description. It says that archive keeps the card and its history, that a
person restores it on the Status page with the returned `href`, and that
restore starts a fresh full summary.
- The create route reads the company issue prefix before it creates the
card. A failed link lookup can not delete a card whose compile task is
queued.
- Regression tests cover the `href` on the archive and get responses,
the new PATCH description, and a failed prefix read on create (no card
and no task are left).

## Verification

- `pnpm exec vitest run server/src/__tests__/status-cards.test.ts
server/src/__tests__/openapi-routes.test.ts` (71 tests pass). The new
create-route test fails on the first commit and passes on the fix.
- End to end: the chat eval `status-cards.archive-card` runs with this
change on an eval branch. The result is in the eval report for that
case.

## Risks

- Low risk. The change adds one optional response field and one
description. List responses do not change. The UI ignores the new field.
- Each single-card response does one more small company read for the
issue prefix. On create, this read occurs before the card exists, so its
failure leaves nothing behind.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), used in Claude Code
with tool use and code execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 16:28:11 -06:00
DottaandClaude Opus 5.5 f439150cb3 fix(recovery): limit the null-host owner fallback to single-host servers and record each use (#19883)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - #19868 and #19871 made restart recovery judge a recorded pid only in
the PID space that recorded it
> - Rows saved before those host columns existed have no recorded host.
They kept the previous local dead-pid proof, so in-flight native runs
would not be stranded at upgrade
> - On an ephemeral (multi-host) server that fallback is unsafe: the row
may have been written on another host
> - This pull request limits the fallback to single-host servers,
records every use, and gives ephemeral servers a working board action
> - The benefit is that single-host upgrades still recover on their own,
multi-host servers never accept a cross-host proof, and the next release
can remove the fallback with evidence

## Linked Issues or Issue Description

**Bug description**
After #19868 and #19871, a `native_run_finalizations` row with
`controller_host_hash = null`, or a run with `process_host_hash = null`,
still accepted "the pid is dead here" as proof on every server. That
includes an ephemeral server, where the row may come from another host.
Nothing recorded how often the fallback was used, so it had no safe
removal path.

**Expected behavior**
- Single-host server: the fallback applies for one release, and each use
writes a `legacy_host_unknown_dead_pid_proof` activity-log entry.
- Ephemeral server (`PAPERCLIP_EPHEMERAL_SERVER=true`): the row is
unprovable, and the board has an action to confirm the previous server
stopped.
- A mismatched host is always unprovable.

Refs #19868, #19871, #19846

## What Changed

- `native-restart-recovery.ts` `evaluateNativeControllerTakeover`:
- A coordinator row with `controllerHostHash: null` returns
`controller_host_unrecorded` when `ephemeralServerEnabled()` is true.
- Otherwise a pid proof from that row carries `legacyHostFallback:
true`.
- `operator_attested` is accepted as proof
(`operator_attested_controller_stopped`).
  - Receipt-built owners, which have no host key, are unchanged.
- New `recordLegacyHostFallbackProof` writes the activity-log entry. It
is not a run-log event: run events are progress evidence for restart
recovery's crash-loop credit, and the record must not change any
recovery decision. It is called from restart recovery, the
dead-controller result-lease release, native retirement, and remote
warm-session recovery.
- New `native-controller-host-recovery.ts`:
- `requestNativeControllerStopConfirmation` (board-owned
`native_controller_host_unverified` recovery action, idempotent, never
displaces another active action).
- `confirmNativeControllerStopped`. It verifies the exact recorded
controller and stamps `operator_attested` with compare-and-set. It then
resolves the action, wakes live-run recovery, and logs
`issue.native_controller_stop_confirmed`.
- Route `POST /issues/:id/recovery-actions/confirm-controller-stopped`.
It is board-only and requires `runtime:confirm_owner_stop`. Generic
`restored`/`false_positive` resolution of this cause is refused. A
shared `confirmNativeControllerStoppedSchema` validates the body.
- UI: `WorkspaceExportRecovery` reuses the "Confirm the previous server
stopped" control for this cause, and the generic recovery card hides it.
Adds the `issuesApi.confirmControllerStopped` client call.
- `recovery/service.ts` orphan reaper: a null `process_host_hash` is
judged only when not ephemeral. A successful use records the entry
best-effort, after the terminal write. On an ephemeral server the run is
left to its existing Stop control.
- `ephemeralServerEnabled` moves to a leaf `ephemeral-server-mode.ts`
(re-exported by `ephemeral-server-contract.ts`). Importing the contract
module from recovery code created an import cycle in the runner child
process.
- The new route is registered in OpenAPI.
- `doc/execution-semantics.md`: documents the host rule and the
one-release sunset.

## Verification

- `native-restart-recovery.test.ts`: null host on a single-host server
is released with the flag. Null host on an ephemeral server is
unprovable. A mismatched host is unprovable in both modes. An attested
controller is accepted. Receipt owners are unchanged.
- New `native-controller-host-recovery.test.ts` (embedded Postgres):
  - The fallback writes the activity-log entry and no run event.
  - Ephemeral mode creates exactly one board action.
  - A wrong run id is refused.
- Confirmation stamps the attestation, after which takeover is allowed.
The action resolves and the activity is logged. A second confirmation is
refused.
- `recovery-stale-issue-lock-sweep.test.ts`: on a single-host server a
null host is terminalized and records one event. On an ephemeral server
it is left alone with no event. The existing audit-failure case still
clears the lock.
- `WorkspaceExportRecovery.control.test.tsx`: the controller
confirmation posts to `confirmControllerStopped` and never to the
copyback endpoint.
- Locally: these suites plus `remote-warm-session-recovery`,
`native-controller-recovery.integration` and
`native-startup-cleanup-recovery` (136 passed), and after the CI fixes
`native-runner-restart-preparation` and `native-runner-restart-recovery`
integration, `openapi-routes` and the suites above (256 passed); the UI
recovery suites (52 passed); `node scripts/typecheck-layers.mjs` with no
errors in the touched files; `pnpm check:token-gates` clean.

## Risks

- Previous-release story: no schema change. Null-host rows saved by
earlier releases recover as before on single-host servers, now with an
event, and wait for the board on ephemeral servers. The next release
removes the fallback; the event count shows whether any rows remain.
- On an ephemeral server, a null-host orphaned run process is not reaped
automatically. The operator uses Stop. That is the intended "unprovable"
outcome.
- A board confirmation is an attestation. It applies only to the exact
recorded controller (boot id + pid) and only while the host is still
unrecorded.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, used with tool use and
code execution in Claude Code.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 13:25:47 -06:00
DottaandPaperclip a0ac81e114 fix(ui): show task image results in compact thumbnail grids (#19626)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task feeds show agent messages, documents, and files in time order.
> - Each image currently uses a full feed card.
> - A turn with seven screenshots makes the conversation hard to scan.
> - This pull request groups adjacent images from the same run in a
compact grid.
> - Users can scan the results and open each image in the existing
gallery.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Image results in task history and the live task feed.

**Current behavior**

Each image uses a separate full-width card. Native image upload receipt
messages can also separate related screenshots.

**Proposed behavior**

Adjacent images from one run share a wrapping thumbnail grid. New image
results join the grid. Documents, video, and authored messages keep
their positions. The grid opens the existing gallery.

**Reason and benefit**

Users can see a batch of screenshots without scrolling past one large
card for each file.

**Breaking changes**

The feed layout changes. The stored comments, files, APIs, and
permissions do not change.

Related public work: Refs #17228. Refs #8785. Refs #7667. These changes
supplied the artifact cards and media gallery that this pull request
reuses.

## What Changed

- Add one image grouping function for settled history, turn history, and
live results. Group only images with the same known run. Keep the first
row key and each image key when results arrive.
- Add a token-based grid that reuses the media artifact cards and image
gallery.
- Add an optional typed attachment-preparation marker to file
registration and chat-file reuse. Preserve the marker through comment
normalization. Use it with matching image, author, and run links to hide
generated receipts. Keep the exact historical sentence as a fallback for
old receipts.
- Add nine production component stories with seven sample-account
screenshots. Cover mobile, Classic, mixed results, single images,
missing images, streaming, gallery navigation, and the complete feed
projection.
- Add grouping and production-feed regressions. Add 18 browser cases
across light and dark themes.
- Improve contrast for the shared fallback label and gallery counter
after the accessibility checks found low contrast.
- Match alternate original-image paths when opening the gallery. Keep a
separate Open original link beside Download in the gallery.
- Record the feed layout in DESIGN.md.

## Verification

- Final qualification at `09b12381ce85bee6593050bd8a2fa18cbe2c45a6`:
[required CI
passed](https://github.com/paperclipai/paperclip/actions/runs/42317080212/job/128237094513),
including typecheck, build, all test lanes, E2E, and verify. The
snapshot has 58 successful check runs, three conditional skips, one
neutral advisory job, and a successful legacy Snyk status. No pending or
failed checks remain. Greptile and Paperclip Review both score this
exact head 5/5; all review threads are resolved.

- Current-head local checks: 544 focused UI tests passed across 11
files, with one existing skip. UI/shared typechecks and token gates
pass. All 18 focused Storybook browser cases passed after the CSS merge,
with retries disabled.
- Two database integration cases verify file registration and chat-file
reuse receipt markers. All 52 issue-validator tests and six upstream
default-model tests passed.
- Regressions failed before the fixes for unknown-run grouping, receipt
wording, and authored progress text with an image. The repair uses a
typed receipt marker and requires matching author, attachment, image,
and run links before hiding a generated receipt. All five review
findings are resolved.
- Browser checks cover loaded images, wrapping columns, overflow,
missing-image fallback, streaming stability, keyboard gallery
navigation, original-file links, and downloads. Fixtures use production
renderers. These checks do not prove deployed persistence or provider
behavior and do not compare visual baselines.
- Local limits: the preflight helper could not finish because Cargo was
absent. The earlier low-memory server typecheck and dependency-free
selector did not replace final-head CI. The now-passing final CI
supplies broad typecheck, build, server, Runner, and E2E coverage.
- Prior independent CI failures remain recorded: one Slack timer case
passed a single diagnosed rerun; its exact timer cause was not proved. A
later chat shard lost its self-hosted runner without a test assertion
failure. The current revision passes that shard and all applicable
gates. Master conflict resolution retained both image-grid and patch CSS
rules.

## Risks

- Images without a run ID remain separate. Messages and other resource
types end each batch.
- Receipt suppression requires a matching preparation marker or the
exact legacy sentence, plus matching attachment, image work product,
run, and author. Tests preserve human messages and native progress text
with attachments. The optional marker uses existing JSON metadata and
needs no database migration.
- Shared gallery and fallback text now have stronger contrast.

## Model Used

OpenAI GPT-6, through Codex. The agent used reasoning, repository tools,
code execution, and browser tests. The runtime did not expose a more
specific model ID or context window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-06 18:42:22 -06:00
Nicky LeachandClaude Opus 5.5 ff1d1dea5d fix(tools): reject non-tool connections before any write (#19492)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Apps and tools connect to Paperclip through tool connections
> - `POST /api/companies/:companyId/tools/connections` creates a tool
connection through `createConnection`
> - The request schema accepts a channel purpose and the chat and voice
transports, but `createConnection` cannot store them
> - The database then rejects the row, so the caller gets a 500 and a
stray tool application stays behind
> - This pull request rejects those requests with a 422 before any
write, and stores `config` as `transportConfig` when the caller leaves
`transportConfig` out
> - The benefit is a clear error, no leftover rows, and consistent
connection rows

## Linked Issues or Issue Description

No issue exists. The new test typecheck in #18739 found this problem.
#18739 listed it as a possible product problem and did not change it.

**What happened?**

1. `createConnection` never writes `input.connectionPurpose`, so every
row gets the database default `tool`.
2. The schema allows `transport: "chat_sdk"` and `transport: "voice"`.
The database check `tool_connections_channel_transport_check` does not
allow these transports on a `tool` row.
3. No error mapping exists for a check violation, so the route returns
500.
4. When the request has no `applicationId`, the service inserts a
`tool_applications` row first, outside the connection transaction. That
row stays after the failure.
5. The schema gave `transportConfig` a default of `{}`. The service
stores `input.transportConfig ?? config`, so it stored `{}` instead of a
copy of `config`.

**Expected behavior**

The route returns 422 for a purpose or transport that it cannot create,
and writes no rows. When the request leaves `transportConfig` out, the
row stores `config` there.

**Steps to reproduce**

1. Send `POST /api/companies/:companyId/tools/connections` with `{
"name": "x", "transport": "chat_sdk" }`.
2. See the 500 response.
3. See the new `tool_applications` row for the company.

## What Changed

- `server/src/services/tool-access.ts`: `createConnection` rejects a
purpose other than `tool`, and the `chat_sdk` and `voice` transports,
with 422. The check runs before any lookup or write. Channel connections
still come from their own services.
- `packages/shared/src/validators/tool-access.ts`: `transportConfig` is
optional and has no default. The update schema already removed defaults,
so it does not change.
- `server/src/__tests__/tool-access-service.test.ts`: added tests for
the three rejected inputs (no rows written), and for a request that
sends only `config`.

## Verification

- `pnpm exec vitest run server/src/__tests__/tool-access-service.test.ts
server/src/__tests__/generic-mcp-connection.test.ts
server/src/__tests__/tool-connection-health-work.test.ts
server/src/__tests__/openapi-routes.test.ts
server/src/__tests__/tool-access-routes.test.ts
packages/shared/src/validators`: 27 files, 995 tests pass.
- `cd server && pnpm typecheck`: passes. This includes the source layers
and the three test-tree shards.
- Not run locally: the full `pnpm test:run`, the root `pnpm build`, and
the UI typecheck. Required CI covers them.

## Risks

- Low risk. A client that sends a channel purpose or a chat or voice
transport to this route now gets 422 instead of 500. The request failed
before this change too.
- A client that sends only `config` now gets the same value in
`transportConfig`. Every reader checks `config` first, so this changes
no behavior.
- The OpenAPI output for this body no longer shows a default for
`transportConfig`.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use
(shell, file edits) and extended thinking.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 17:30:24 +00:00
DottaandPaperclip 21d2a577bb feat: show and change routine responsible users (#19128)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - Routines create tasks for repeated work.
> - Each routine has a responsible person.
> - The Overview did not show this person or permit a change.
> - People need to see who will be responsible for automatic tasks.
> - This pull request adds a small name picker beside Default agent.
> - Authorized people can adopt a routine or transfer it to an active
company member.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The routine Overview and the routine update API.

**Subsystem affected**

UI, server, and shared contracts.

**Current behavior**

The routine stores a responsible user. The Overview does not show that
person. The update API cannot change that person.

**Proposed behavior**

Show Responsible user beside Default agent. Click the name to search
active company members. Save only the new person and the current
revision ID.

**Reason and benefit**

People can see who owns future automatic tasks. An authorized person can
adopt a routine without making a new routine.

**Breaking changes**

The detail response adds an optional actor-specific field. The update
API adds an optional responsible user ID. Existing requests keep their
current behavior.

Related: #17368 covers local Board ownership migration. This change adds
the routine control and explicit transfer.

## What Changed

- Show a quiet, searchable person picker beside Default agent.
- Explain that automatic tasks use this person. Manual runs use the
person who starts them.
- Permit human operators with `tasks:assign`, instance administrators,
and local operators to transfer responsibility.
- Check active company membership inside the update transaction.
- Save a revision and record the old and new person in the activity log.
- Keep existing task responsibility and ownership during revision
restore.
- Show errors for failed saves and stale revisions.
- Add tests for permissions, company boundaries, transfers, inheritance,
and picker states.
- Keep the picker disabled until saved data is refreshed. Refresh the
activity list after a transfer.
- Capture the actual previous person under the update row lock for the
activity record.
- Use shared query error handling and retain cached people during a
connection failure.

## Verification

- Focused checks cover 145 tests in 5 files. The first post-fix run
passed 144 tests. One existing Fireflies route test timed out during the
first import while the UI typecheck also ran. The same test passed in
the pre-fix run. The isolated route suite then passed all 21 tests with
no source change.
- The new tests reproduce slow detail refreshes, activity refresh, and
two concurrent transfers without a base revision. The concurrency test
uses PostgreSQL row locks.
- UI and server TypeScript checks passed at commit `1df9587eb`.
- The UI production build passed for the updated head.
- The branch includes master through `26391707f`.
- Design token gates, query-error policy, and Git whitespace checks
passed. The query-error policy reports zero findings.
- Local browser checks passed on desktop and mobile for the initial
feature commit. Search, selection, reload persistence, and revision
creation passed. No page errors or horizontal overflow were found. The
follow-up does not change the normal layout.
- Earlier full local checks could not finish: Cargo was absent, and
concurrent full test/build checks exceeded the 8 GiB memory limit. These
attempts are not passes.
- The first CI run failed on two error-rendering policy findings. That
failure is fixed locally. The three findings from the first Greptile
review are fixed and their threads are resolved.
- Greptile reviewed `1df9587eb2d3e034c2769b1f6955ac52323c95bb` and
scored it 5/5. It confirms all three prior findings are addressed. There
are no open review threads.
- [CI attempt
1](https://github.com/paperclipai/paperclip/actions/runs/42046369415/attempts/1)
passed 53 checks. The server 8/12 shard failed only because the existing
`history-http` runtime fixture did not become ready within 10 seconds
(99 refused connections). The fixture and runtime source are unchanged
from the merged master. That case passed locally on the same PR head
with no source change. Its full 75-test suite also passed locally. The
cause of the CI failure remains unknown.
- [CI attempt
2](https://github.com/paperclipai/paperclip/actions/runs/42046369415/attempts/2)
passed on `1df9587eb`: 54 successful checks, 3 skipped, and 1 neutral.
No failed or pending checks remained. The original fixture-readiness
failure remains recorded above.
- A later review found that viewers with an explicit `tasks:assign`
grant could see an editable picker even though writes were denied.
Commit `8b95ee707` now mirrors active-membership and viewer restrictions
in the GET capability flag. Instance-admin and local-operator behavior
is preserved.
- Three membership regressions failed on the incorrect editable flag
before the fix. After the fix, all 43 routine-route and company-access
cases passed (`--testTimeout 60000` accommodated this sandbox's cold
route imports; no repository timeout was changed). The first pre-fix run
timed out during the cold import in one case; the second pre-fix run
reproduced all three assertion failures.
- Layered server typechecking and whitespace checks passed after the
permission fix.
- [Fresh
CI](https://github.com/paperclipai/paperclip/actions/runs/42057752313)
passed on `8b95ee7075417527687b4a86cbaf63ba87408364` without a retry.
Greptile reviewed this exact head, scored it 5/5, and added no new
findings. All four review threads are resolved. The security status is
also successful.
- The separate Paperclip Review check is still queued because its
assigned review worker requires runtime recovery. This is the remaining
check before completion; the CI workflow itself passed.

## Risks

- A transfer changes the person used for future automatic tasks.
Existing tasks keep their current person.
- Only people can transfer responsibility. The server checks the
permission again on every write.
- A stale revision rejects the save. The user must reload before
retrying.
- No database migration is required.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, tool use, and code
execution. The exact runtime model ID and context window are not exposed
to this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green (CI passed; separate Paperclip
Review check pending)
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-06 05:47:30 -06:00
c9c4949c86 build(deps): bump zod from 4.4.3 to 4.6.6 (#17364)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The shared validators use zod to check API input, and the Runner
contracts check some of the same values again
> - zod below 4.6.6 has a high-severity memory issue
(GHSA-mrhx-c7xc-m3w5), so this bump is necessary
> - zod 4.6 also changes string `min`, `max`, and `length`: they now
count Unicode code points, not UTF-16 units
> - The Runner question parser and the goal readers still use JavaScript
string length, so emoji text can pass zod and then fail later
> - This pull request bumps zod and keeps the string-length bound on
those schemas
> - The benefit is that we get the security fix, and these inputs still
fail at validation

## Linked Issues or Issue Description

Refs GHSA-mrhx-c7xc-m3w5.

**What happened?**
With zod 4.6, three CI tests failed on this bump. Two showed an emoji
body that is over the agent commentary ceiling and that zod now accepts.
The third is the scheduler timeout described under Verification.

**Expected behavior**
A dependency bump does not widen an API limit. Text over the limit gets
a validation error.

**Impact**
Emoji text between the two bounds passed validation and failed later:
- A question set is created, and then each answer gets a 422. The
question stays pending and nobody can answer it. A schema and parser run
confirmed the mismatch. This was not run over HTTP.
- The Muse route returns a 500 because `parsePaperclipQuestionSet`
throws an error that is not an `HttpError`. This comes from reading the
code. It was not run.
- A Runner goal normalizes to null and replaces the stored goal, or it
is marked blocked. This comes from reading the code. It was not run.

## What Changed

- Bump zod to `^4.6.6`. The lockfile resolves 4.6.7. (Dependabot)
- Add `maxStringLength` to `packages/shared/src/validators/text.ts`. It
checks zod `max` and JavaScript string length.
- Use `maxStringLength` for the question-set text fields, the Runner
goal objective, and the agent commentary body.
- Add regression tests for the question-set bound and the goal objective
bound.
- Dependabot recreated the branch on current `master` (`@dependabot
recreate`) to resolve `pnpm-lock.yaml` conflicts. This happened twice.
The lockfile is Dependabot's. Each time, the two fix commits were
applied again without changes.

## Verification

- Compared zod 4.4.3, 4.6.5, 4.6.6, and 4.6.7 directly. The change to
`max` is in 4.6.5 or earlier, and 4.4.3 does not have it.
- Passed locally: `packages/shared` tests `agent-commentary`,
`validators/issue`, and `runner-goal`, plus `tsc --noEmit` in
`packages/shared`.
- Passed locally on the first fix commit: server
`agent-commentary.integration`, `agent-commentary-helper`, and
`openapi-routes`. The later commit changes these schemas again. CI
passed these tests at `b5e9dc7352`.
- Local testing was focused. GitHub CI is the full regression check. CI
passed at `b5e9dc7352`, including `ci / verify` and `ci / e2e`.
- Greptile reviewed `b5e9dc7352`. The score is 5/5, with no inline
comments.
- After the recreate, the fix commits applied cleanly as `bad62c3ba5`
and `3294552e65` on Dependabot's `46789d1487`. Their diff is the same as
the diff Greptile reviewed. The lockfile still resolves zod 4.6.7. The
focused `packages/shared` tests (`validators/issue`, `runner-goal`) and
`tsc --noEmit` in `packages/shared` passed again locally. A second
`pnpm-lock.yaml` conflict came before CI finished at `3294552e65`.
- Second recreate: Dependabot ignored the first `@dependabot recreate`
(no reaction and no update job after 20 minutes). It acted on the second
command and pushed `83c328c15c`. The fix commits applied cleanly as
`dd3e87d93e` and `95b450048f`, with the same diff. The lockfile still
resolves zod 4.6.7. The same focused tests and `tsc --noEmit` passed
again locally. Greptile first scored `95b450048f` 4/5 with one P2: the
description did not explain the source changes. Greptile read
Dependabot's replacement description, which was live during that review.
The description was restored and the thread resolved. The new review
scored `95b450048f` 5/5 with no findings. CI failed at `95b450048f` in
two shards. Neither failure comes from the zod change:
- `server (9/12)`: `server/scripts/reporting-lock-policy.test.mjs` fails
with "Reporting lock changed; review the dependency correction before
install". #19283 added this test today. It requires the committed
`pnpm-lock.yaml` hash to match `tests/runner-e2e/report-lock.json`.
Every pull request that changes the lockfile fails it until the hashes
are renewed, for example #17172 and #17911.
- `workspaces-a (1/2)`:
`cli/src/__tests__/company-import-export-e2e.test.ts` timed out waiting
for its child server. The same test failed the same way on two unrelated
branches in the same hour (runs 42115721271 and 42109846042). A rerun of
this shard at `95b450048f` passed. The rerun of `server (9/12)` failed
again on the reporting-lock test.
- #19356 fixed the reporting-lock gate for Dependabot lockfiles and
merged. A re-run reuses the old merge commit, so the empty commit
`482d76686e` starts a run against current `master`. `pnpm-lock.yaml` and
the reporting-lock proof on `master` did not change since this branch's
base.
- CI at `482d76686e`: `ci / policy` passed, and `server (9/12)` skipped
the reporting-lock test as #19356 intends. `e2e shard (6/8)` failed once
in `cloud-auth.spec.ts` ("apiResponse.json: Response has been disposed",
a Playwright race in a route handler). The same test passed at
`95b450048f` with the same code. A rerun passed. All checks pass,
including `ci / verify` and `ci / e2e`.
- Earlier failure: `issue-monitor-scheduler.test.ts` ("lets the board
check a scheduled monitor on an in_progress task") timed out in CI at
`d60b5f56d8`. It passed 5 of 5 local runs with the first fix. The cause
is unknown. The test waits 3 seconds for heartbeat runs to settle, so CI
load is possible, but this is not proven. The test passed in the CI run
at `b5e9dc7352`. This shows recovery. It does not explain the earlier
timeout.

## Risks

- All other zod string bounds now count code points. Emoji text can be
up to 2N UTF-16 units and 4N UTF-8 bytes (it was N units and at most 3N
bytes). This pull request does not change those bounds.
- An audit of those bounds found no other concrete failure. It checked
index limits, byte limits, `.length` guards, provider limits, and
security `min` checks. It used code search and sampling, so it is not
exhaustive.
- Not verified: Slack `topic` and `purpose` use `.max(250)`, and we did
not confirm how Slack counts that limit.
- `.min(N)` is now stricter for emoji text. A single emoji no longer
passes `.min(2)`.
- `@dependabot rebase` or `@dependabot recreate` on this branch will
remove the manual commits. This happened twice to resolve lockfile
conflicts, and the commits were applied again each time.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), with tool use and code
execution, in Claude Code.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (focused tests only; see
Verification)
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes (no
documentation change needed)
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green (at `482d76686e`)
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
(5/5 at `95b450048f`)
- [x] I will address all Greptile and reviewer comments before
requesting merge

---

Bumps [zod](https://github.com/colinhacks/zod) from 4.4.3 to 4.6.6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/colinhacks/zod/releases">zod's
releases</a>.</em></p>
<blockquote>
<h2>v4.6.6</h2>
<blockquote>
<p>Six malicious commits pushed to <code>main</code> on September 21
with a compromised git credential were reverted the same day in <a
href="https://redirect.github.com/colinhacks/zod/issues/6620">#6620</a>
and have since been removed from the history of <code>main</code>. None
were ever published to npm. The npm provenance for 4.6.6 names 284243fb,
the pre-rewrite copy of 9c219833 with identical contents.</p>
</blockquote>
<h2>Commits:</h2>
<ul>
<li>0cd3af5e9f50ad11bbcd4407a46a21b8848ba574 docs: load the en locale
directly in Zod Mini</li>
<li>9d5e60f162997b764b40d45aa02481888db50dea docs: import locales from
zod/locales, not z.locales</li>
<li>34a626f307871ecbb0123947559328dc52ed5e3e docs: tighten the z.locales
tree-shaking note</li>
<li>74304ce5b5796b5edb9a88ceb8e170b6ea3e82df release: stage npm versions
instead of publishing them (<a
href="https://redirect.github.com/colinhacks/zod/issues/6622">#6622</a>)</li>
<li>b2ef983e0711ff6517d6020b021071e2e5653efa docs: add Code for Japan to
bronze sponsors</li>
<li>8fb2faf0584828a6a027d8279db36f6f52784462 docs: crop the Code for
Japan logo and list it first in bronze</li>
<li>bacad518c41610d654658172d325874bf0ee6290 docs: square the Code for
Japan logo to match the other bronze tiles</li>
<li>c42596bd1c87e941d7241d10e012c5c196adcc10 release: hold the run on
the release-approval environment until the staged versions are approved
(<a
href="https://redirect.github.com/colinhacks/zod/issues/6638">#6638</a>)</li>
<li>a2ba4a67986a3e6b2b131be30084a2f460d9ea67 fix(types): declare record
output and input as members, not base type arguments (<a
href="https://redirect.github.com/colinhacks/zod/issues/6645">#6645</a>)</li>
<li>a0ebf970f2d752e5f58527cd2942ff48be4f46bd fix(v4): check array, set
and map size bounds before parsing elements (<a
href="https://redirect.github.com/colinhacks/zod/issues/6652">#6652</a>)</li>
<li>529f78dd9431b07f49647fee3aa0819b3f8b66b7 4.6.6</li>
<li>9c219833c3a3764fa1f1ea9c5ecec8254a63c0b1 ci: stage at verbose so a
failed OIDC token exchange says why</li>
</ul>
<h2>v4.6.5</h2>
<h2>Commits:</h2>
<ul>
<li>d2b135cfb7a3582b9eb515756b9166bcb9521f4a docs: add the 4.6.x patch
highlights to the 4.6 post</li>
<li>f1448f7cee00df9fe1e9ad84a000aa1828cc8bc1 docs: fold the 4.6.x patch
highlights into the 4.6 post's own sections</li>
<li>de65a5cb39ed22a507fac935788f718fa88d104f docs: lead the properties
section with the check and add a Zod Mini tab (<a
href="https://redirect.github.com/colinhacks/zod/issues/6598">#6598</a>)</li>
<li>56222cd1532c07bcb91b67df529cab4c0a215330 feat(instanceof): key the
.properties() shape off the instance type (<a
href="https://redirect.github.com/colinhacks/zod/issues/6600">#6600</a>)</li>
<li>ca0229a404818290e6cdcfefcd7eb2d04bcbb543 Revert &quot;feat: add
z.currencyCode() over a vendored ISO 4217 list, refreshed weekly by CI
(<a
href="https://redirect.github.com/colinhacks/zod/issues/6595">#6595</a>)&quot;</li>
<li>cc4cd4ee9c52fcaa10964e48cc144541e41a5ed9 Revert &quot;Revert
&quot;feat: add z.currencyCode() over a vendored ISO 4217 list,
refreshed weekly by CI (<a
href="https://redirect.github.com/colinhacks/zod/issues/6595">#6595</a>)&quot;&quot;</li>
<li>0f3f5ee3ca56c7574bf849e54f79e9a6e02562ee 4.6.5</li>
<li>59bbc03e10c636b9eb3c393dfeb552819774ec21 chore: re-pin the
integration peers to the workspace zod after the 4.6.5 bump</li>
</ul>
<h2>v4.6.4</h2>
<p>A patch on top of <a
href="https://github.com/colinhacks/zod/releases/tag/v4.6.3">4.6.3</a>.</p>
<ul>
<li><a
href="https://github.com/colinhacks/zod/commit/d6bc1e30"><code>d6bc1e30</code></a>
feat: add <code>z.currencyCode()</code> over a vendored ISO 4217 list,
refreshed weekly by CI (<a
href="https://redirect.github.com/colinhacks/zod/pull/6595">#6595</a>)</li>
<li><a
href="https://github.com/colinhacks/zod/commit/ad32d751"><code>ad32d751</code></a>
perf: <code>z.url()</code> rejects an invalid URL with
<code>URL.canParse()</code> instead of a throwing constructor, about 50x
faster; fewer allocations on the validation path (<a
href="https://redirect.github.com/colinhacks/zod/pull/6588">#6588</a>)</li>
<li><a
href="https://github.com/colinhacks/zod/commit/2bb08717"><code>2bb08717</code></a>
chore: re-pin the integration peers to the workspace zod after the 4.6.4
bump</li>
<li><a
href="https://github.com/colinhacks/zod/commit/f6e1701a"><code>f6e1701a</code></a>
chore(deps): bump next to 15.5.25 and vite to 7.3.6 (<a
href="https://redirect.github.com/colinhacks/zod/pull/6153">#6153</a>)</li>
</ul>
<h2>v4.6.3</h2>
<p>A patch on top of <a
href="https://github.com/colinhacks/zod/releases/tag/v4.6.2">4.6.2</a>.</p>
<ul>
<li><a
href="https://github.com/colinhacks/zod/commit/413cce9a"><code>413cce9a</code></a>
fix(v4): make z.properties() a check again (<a
href="https://redirect.github.com/colinhacks/zod/pull/6594">#6594</a>) —
removes the standalone <code>z.properties()</code> schema from 4.6.0;
<code>z.instanceof().properties()</code> and
<code>.check(...z.properties())</code> are unchanged</li>
<li><a
href="https://github.com/colinhacks/zod/commit/75d63ee1"><code>75d63ee1</code></a>
docs: show only the <code>.properties()</code> method form in the 4.6
post</li>
<li><a
href="https://github.com/colinhacks/zod/commit/46da9572"><code>46da9572</code></a>
docs: match the error-message examples to what the parsers emit</li>
</ul>
<h2>v4.6.2</h2>
<p>A patch on top of <a
href="https://github.com/colinhacks/zod/releases/tag/v4.6.1">4.6.1</a>.</p>
<ul>
<li><a
href="https://github.com/colinhacks/zod/commit/9446b5cc"><code>9446b5cc</code></a>
fix: preserve undefined prefault outputs and object keys (<a
href="https://redirect.github.com/colinhacks/zod/pull/6587">#6587</a>) —
closes <a
href="https://redirect.github.com/colinhacks/zod/issues/6585">#6585</a></li>
<li><a
href="https://github.com/colinhacks/zod/commit/0c483c58"><code>0c483c58</code></a>
docs: the <a href="https://zod.dev/blog/zod-4-6">Zod 4.6 announcement
post</a> (<a
href="https://redirect.github.com/colinhacks/zod/pull/6546">#6546</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/colinhacks/zod/commit/9c219833c3a3764fa1f1ea9c5ecec8254a63c0b1"><code>9c21983</code></a>
ci: stage at verbose so a failed OIDC token exchange says why</li>
<li><a
href="https://github.com/colinhacks/zod/commit/529f78dd9431b07f49647fee3aa0819b3f8b66b7"><code>529f78d</code></a>
4.6.6</li>
<li><a
href="https://github.com/colinhacks/zod/commit/a0ebf970f2d752e5f58527cd2942ff48be4f46bd"><code>a0ebf97</code></a>
fix(v4): check array, set and map size bounds before parsing elements
(<a
href="https://redirect.github.com/colinhacks/zod/issues/6652">#6652</a>)</li>
<li><a
href="https://github.com/colinhacks/zod/commit/a2ba4a67986a3e6b2b131be30084a2f460d9ea67"><code>a2ba4a6</code></a>
fix(types): declare record output and input as members, not base type
argumen...</li>
<li><a
href="https://github.com/colinhacks/zod/commit/c42596bd1c87e941d7241d10e012c5c196adcc10"><code>c42596b</code></a>
release: hold the run on the release-approval environment until the
staged ve...</li>
<li><a
href="https://github.com/colinhacks/zod/commit/bacad518c41610d654658172d325874bf0ee6290"><code>bacad51</code></a>
docs: square the Code for Japan logo to match the other bronze
tiles</li>
<li><a
href="https://github.com/colinhacks/zod/commit/8fb2faf0584828a6a027d8279db36f6f52784462"><code>8fb2faf</code></a>
docs: crop the Code for Japan logo and list it first in bronze</li>
<li><a
href="https://github.com/colinhacks/zod/commit/b2ef983e0711ff6517d6020b021071e2e5653efa"><code>b2ef983</code></a>
docs: add Code for Japan to bronze sponsors</li>
<li><a
href="https://github.com/colinhacks/zod/commit/74304ce5b5796b5edb9a88ceb8e170b6ea3e82df"><code>74304ce</code></a>
release: stage npm versions instead of publishing them (<a
href="https://redirect.github.com/colinhacks/zod/issues/6622">#6622</a>)</li>
<li><a
href="https://github.com/colinhacks/zod/commit/34a626f307871ecbb0123947559328dc52ed5e3e"><code>34a626f</code></a>
docs: tighten the z.locales tree-shaking note</li>
<li>Additional commits viewable in <a
href="https://github.com/colinhacks/zod/compare/v4.4.3...v4.6.6">compare
view</a></li>
</ul>
</details>
<br />

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nicky Leach <nicky@paperclip.ing>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 17:41:43 -08:00
Devin FoleyandPaperclip 8f79a32898 fix(connections): keep agent access consistent through setup and permission changes (#19352)
Task-hosted tool setup kept requester-only defaults, and audience edits could leave runtime installations restricted after permission bindings were widened. Large provider catalogs could also fail before creating an access card.

Use the normal agent audience defaults for new tool setup, preserve explicit selections through verified OAuth and draft resumption, and synchronize permission bindings and runtime installations atomically. Enforce agent-edit authority and preserve existing access during additive account reuse.

Validation: 915 focused regression tests, typechecks, and builds passed. All 54 CI checks passed and Greptile Apex scored the reviewed head 5/5 with no unresolved threads. Broad local test failures, recoveries, and incomplete heartbeat coverage are documented in the PR.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-11-05 17:38:32 -08:00
f2593b7905 feat: make Coordinator and Agent Chat standard and speed up navigation (#19360)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - People enter that work through the workspace, agent conversations,
and tasks.
> - Coordinator and Agent Chat still require experimental enrollment.
> - Task link prefetches do not warm the compact queries used by the
default task view. Chat also waits for a request when its navigation
list already holds the conversation.
> - This pull request makes Coordinator and Agent Chat standard and
reuses the reads needed for navigation.
> - People can choose Classic workspace in Experimental settings. Cached
work can appear while fresh data loads.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Workspace selection, Agent Chat availability, and navigation between
Chat, Tasks, and task details.

**Subsystem affected**

Cross-cutting: UI, workspace preferences, instance settings, and the
database migration.

**Current behavior**

People must enable Coordinator and Agent Chat in Experimental settings.
Opening a task can repeat requests because prefetch warms the full
detail and comment queries, while the default view reads compact task
data and a recent comment window. Opening Chat waits for a detail
request even when the current person's conversation list contains it.

**Proposed behavior**

Coordinator is the standard workspace for everyone. Experimental
settings offer Classic workspace, off by default. Old Coordinator
experiment values do not select Classic. Agent Chat is available to
everyone, including instances with an old saved or managed off value.
Task link intent warms the queries used by the mounted view. Chat can
use the current person's company-scoped conversation list during
refresh.

**Reason and benefit**

People can use the standard workspace without setup. Repeat navigation
can show cached content while the server refreshes it.

**Breaking changes**

Existing Coordinator experiment and Agent Chat off values no longer
disable these surfaces. Classic requires an explicit new opt-in. The
workspace API keeps its existing response shape and audit checks. The
migration retains legacy values and adds a separate Classic preference.
Execution permissions, company access, and chat privacy checks still
apply.

**Additional context**

Roadmap check: this graduates existing surfaces and improves their
navigation. It does not add a new agent execution capability. Duplicate
searches found no open Coordinator workspace PR. Related server cache
work, Refs: #17828, addresses compact issue-list invalidation; this PR
addresses client navigation queries.

## What Changed

- Add a default-off Classic workspace preference. Derive the existing
workspace API response from that choice. Keep personal persistence,
account isolation, and audited writes in the workspace preference
service.
- Replace the Coordinator experiment control with Classic workspace. Use
Coordinator while preferences load. Update the existing settings
examples and navigation recipe.
- Retire the Agent Chat experiment control. Ignore old stored and
managed off values. Retain the compatibility key and the existing
execution and access checks.
- Reuse account- and company-scoped chat list data with its original
freshness timestamp.
- Share compact task and recent-comment query options between prefetch
and the task view. Keep full-history prefetch for Classic tasks and
expanded history.
- Add upgrade, replay, cache, account isolation, and browser switching
regressions. Update product, database, development, and roadmap
documentation.

## Verification

- Targeted preference, settings, migration, cache, and UI regression
tests passed during implementation. The cache tests hold refresh
requests pending and check that content still renders. They also check
account isolation and stale refresh behavior.
- A real browser test verified fresh Coordinator defaults, Classic
opt-in persistence, and return to Coordinator. It used an isolated
source checkout with fresh data on macOS.
- Token, migration numbering and safety, map, and Storybook catalog
checks pass after the rebase.
- Repository typecheck and build pass. Typecheck and token gates also
pass after review repairs. The broad local run passed all six chat
integration shards (1,931 tests). It then found the host-CLI-dependent
recovery fixture described below. Its remaining duplicate work was
stopped after the full current-head CI matrix passed; this is not a
claim that the broad local command completed green.
- Review repairs passed 419 UI/migration fixture tests, 19 Coordinator
navigation tests, and all 214 tests in the five affected server suites.
The 24 Chat/workspace browser tests pass, including standard Coordinator
switching and explicit Classic persistence.
- The broader browser repair run passed 85 tests. It retained two failed
assertions and skipped five later serial cases. The affected files then
passed all 11 tests after the fixes: reopen the desktop panel after
reload and open More for Audit and Connectors. This includes the five
serial cases that had not run.
- The broad local suite exposed a recovery fixture that executed the
host Codex CLI during a simulated remote probe. On a host with Codex
0.154.0, model fallback broke its fixed-model assertion. The fake
sandbox now reports Codex 0.160.0. All 20 selected recovery/provider
compatibility cases pass after the repair.
- A CLI company import/export suite timed out during server startup in
the second CI run. The port fallback is intentional in that fixture. No
root cause was established. That suite passes on the final commit in CI.
This records recovery, not a claimed product fix for the earlier
timeout.
- The first CI run exposed remaining assumptions about the retired flags
and Classic UI. The repair commit updates those fixtures and navigation
steps. It also restores the missing enabled Cases destination in
Coordinator. Earlier local recovery attempts used the wrong fixture
notification and advanced fake time during live execution; the corrected
tests use the subscribed recovery queue and wall time during execution.
- Greptile reviewed commit `98972b030d4505d838427a2fca6b196b8cad6d47` at
**5/5** with no new comments. The original finding is resolved.
- Current-head CI is green: **56 successful checks**, with three checks
skipped by workflow filters. This includes typecheck, build, the
complete Vitest matrix, all eight browser shards, Runner verification,
release checks, and security checks. [Final CI
run](https://github.com/paperclipai/paperclip/actions/runs/42132651414).
- Typecheck caught missing `pid` and `startedAt` fields in the simulated
command result. The fixture now returns the complete process contract,
and the server test-layer typecheck passes.
- Storybook catalog alignment was checked. Storybook play tests were not
run. Hosted latency and cold bundle loading were not measured.

## Risks

- The new default changes the workspace for people who previously left
the Coordinator experiment off. They can opt into Classic in
Experimental settings.
- The additive migration must run before the new server code. It is safe
to replay and preserves explicit Classic choices.
- Cached content can be stale during background refresh. Existing query
invalidation and source timestamps still control freshness.
- These changes reduce avoidable loading waits. They do not establish a
measured improvement in hosted request latency or initial bundle
download time.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository tools, code
execution, and browser automation. The exact serving revision and
context-window size are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Scott Tong <scott@scottsmbpm5max.lan>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-05 16:28:25 -08:00
DottaandPaperclip 55389554c2 fix(runner): paginate workspace discovery before journal persistence (#19311)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native agents discover reusable workspaces through
`list_workspaces`.
> - The tool returned every authorized workspace in one result.
> - A large inventory exceeded the durable command journal limit. The
result stayed pending, and session cleanup blocked the next turn.
> - This pull request limits discovery in SQL and returns explicit
continuation metadata.
> - Agents can inspect every authorized workspace without sending the
full inventory in one command.

## Linked Issues or Issue Description

Related: #15749 introduced the task workspace tools. No duplicate
pagination fix was found.

**What happened?**

A native workspace discovery call returned a multi-megabyte inventory.
Persisting its result failed with `command_payload_too_large`. The
preceding answer could still be saved, but cleanup retained the
unsettled tool call. A later turn failed before provider work with
`native_session_cleanup_quarantined`.

**Expected behavior**

Workspace discovery must return a manageable page. Agents must be able
to request the remaining authorized rows. Existing visibility checks and
journal integrity checks must stay effective.

**Steps to reproduce**

1. Create 2,000 task-selectable workspaces with ordinary repository
paths.
2. Call `list_workspaces` from an admitted native run.
3. On the old code, the real API regression returns 869,781 bytes. The
command journal allows about 510 KiB.
4. On the repaired code, follow `nextCursor` to inspect all rows. Pages
contain at most 100 rows and fit within 128 KiB.

**Paperclip version or commit**

Reproduced on source commit `7351a9d74f` before the repair.

**Deployment mode**

Isolated source checkout with real PostgreSQL and authenticated native
agent APIs. Hosted deployment and incident recovery remain separate.

## What Changed

- Validate workspace list limits and UUID cursors with a JSON Schema
pattern supported by strict validators. Return `workspaces`, `limit`,
`returnedCount`, `hasMore`, and `nextCursor`.
- Apply company, visibility, lifecycle, and cursor conditions before the
SQL limit. Order pages by workspace ID. Fetch one extra row to detect
continuation without a count query.
- Fit encoded pages within 128 KiB, including JSON escaping and Unicode.
If one summary cannot fit, return explicit string previews with
`truncatedFields`. The authorized detail API retains its full record.
- Keep existing unpaged summary callers on their array response and
recent-use order.
- Update the native tool descriptor, generated contracts, catalog
fixture, and execution documentation.
- Add regression coverage for large inventories, complete pagination,
stable pages, private and foreign rows, invalid inputs, and legacy
summary behavior. Add an opt-in two-turn live Codex acceptance check.

## Verification

- Red before repair: `task-workspace-api.test.ts -t "pages a large
authorized workspace inventory"` failed because the result was 869,781
bytes instead of below 128 KiB. The transport regression also failed at
2,284,671 bytes.
- Green after repair and review changes: 120 tests passed across the
workspace API, transport, routes, native authority, coordinator,
historical-question, and Codex vertical-slice suites. They cover
complete discovery, byte-sized pages, oversized individual summaries,
full detail retrieval, private/foreign/lifecycle exclusions, and strict
schema compatibility.
- Journal safety: two focused durable control-plane tests passed.
Oversized result rejection and lossless valid result delivery remain
effective.
- Tool catalog and reconciliation: 30 tests passed.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed again on final commit `bc10880da6`. Server
typecheck also passed after the review changes. The original affected
suites passed on the rebased first commit (31 tests), and the expanded
review regression set passed afterward (120 tests).
- Real provider acceptance passed again on final commit `bc10880da6`:
local macOS arm64, rebuilt native Runner, `gpt-6.1-sol`, high effort,
per-turn lifecycle, and 2,000 persisted workspaces. Both turns
succeeded. Persisted call inputs and results prove that the second page
uses the first result’s cursor, both calls succeed, their IDs do not
overlap, and the encoded results stay within 128 KiB. The second turn
kept the provider conversation and file. Both task locks were clear
after completion, and no recovered execution failure was recorded.
Duration: 166.92 seconds.
- Full local `pnpm test:run` stopped in the chat shard: 330 tests passed
and one Slack registration test failed with `socket hang up`. That exact
test passed in isolation without changes, and the final-head CI chat
shards passed. A broader local managed-Slack follow-up produced no
result after about eight minutes and was interrupted; it is not counted
as a pass. The original full-suite failure remains recorded.
- The first CI head failed native tool-schema compilation because strict
validators did not recognize `format: uuid`. The revised descriptor uses
a UUID pattern. The previously failing coordinator, native
vertical-slice, authority, and history suites now pass locally. The
stronger live cursor-receipt acceptance check passed. Final-head CI
completed on `bc10880da6`: 57 checks passed and five optional checks
were skipped, with no failures or pending checks. Greptile reviewed that
commit at 5/5; both prior findings are resolved.
- Dependency cost: paged discovery runs the existing visibility-scoped
summary query with an ID cursor and at most 101 returned rows. It adds
no count query, filesystem scan, provider call, or background worker.

## Risks

- Native `list_workspaces` now returns a page object instead of an
array. Individual summaries can be explicit previews when a single
record exceeds the byte budget. Its advertised descriptor and generated
contracts change together. Agents must follow `nextCursor` until null
for a complete inventory.
- Each page rechecks current visibility. Concurrent insertions,
deletions, or access changes require a fresh scan when a complete
point-in-time inventory is needed.
- No migration or journal-limit change. An existing cleanup quarantine
still requires normal recovery after deployment; this PR does not bypass
it.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, shell tools, code editing,
and test execution. The exact served model revision and context window
are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-05 13:24:52 -06:00
DottaandPaperclip b400f76647 feat(ui): submit task composers with Enter by default (#19272)
Use Enter to submit task replies and new tasks, with Shift+Enter for a new line. Add an experimental preference to require Command/Ctrl+Enter.

Preserve autocomplete selection and IME confirmation, and retain the modifier shortcut until saved settings load.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-11-05 11:40:18 -06:00
DottaandClaude Opus 5.5 21640b6d51 feat(connections): gate the built-in Google Workspace connector behind an experimental toggle (#19247)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Apps catalog lets operators connect external tools, including
Google services.
> - Paperclip has a built-in Google Workspace connector, but Google has
not yet verified Paperclip's Google app.
> - The built-in connector also hides the Composio and Arcade Google
apps, because native Google definitions claim those app names.
> - Users therefore see an unverified connector and cannot find the
working aggregator Google apps.
> - This pull request puts the built-in connector behind a default-off
experimental setting. When the setting is off, the aggregator Google
apps appear.
> - The benefit is that users get working Google connectors now, and the
team can still test the built-in connector on demand.

## Linked Issues or Issue Description

**Problem**
Google has not verified Paperclip's Google app yet. The Apps page still
offers the built-in Google Workspace connector. The built-in Google
definitions also suppress the Composio and Arcade Google apps (Gmail,
Google Calendar, Google Drive, Docs, Sheets, Slides, Chat), so users
cannot find them.

**Proposed solution**
Add the `enableGoogleWorkspaceConnector` experimental setting. The
default is off. When it is off, hide and block the built-in connector,
and show the aggregator Google apps. When it is on, keep the current
behavior.

**Alternatives considered**
Delete the built-in connector until verification is complete. We
rejected this option because the team must continue to test the
connector.

**Additional context**
Composio documents Gmail (63 tools), Google Calendar (50 tools), and
Google Drive toolkits that use Composio-managed OAuth. These toolkits do
not need Paperclip's Google app verification.

## What Changed

- Added the default-off `enableGoogleWorkspaceConnector` experimental
setting to the shared types, validator, feature catalog, server
defaults, and the managed-key list for Paperclip Cloud staging.
- Added `experimentalFeatureKey: "enableGoogleWorkspaceConnector"` to
the `google-workspace` app definition. The existing generic connector
gate then hides the connector in the gallery and blocks its setup,
discovery, execution, and agent suggestions when the setting is off.
- Added a "Google Workspace connector (Paperclip)" toggle card to
**Settings → Experimental**.
- Apps page (`Browse.tsx`): when the setting is off, built-in Google
rows without saved accounts no longer claim aggregator app identities.
The Composio and Arcade Google apps then show as aggregator rows. The
legacy Google slug filter now applies only to native rows, so the
Composio `gmail` row is not dropped.
- Saved per-service Google connections (Gmail, Drive, and others) are
not gated. They stay visible and usable.
- Updated `doc/connections/GOOGLE-WORKSPACE.md`.
- Tests: added tests for the hidden and visible Apps page states, the
settings toggle, and the definition gate. Existing built-in Google
Workspace tests now enable the setting.

## Verification

- `cd packages/shared && npx vitest run` passes (1055 tests).
- `cd server && npx vitest run
src/__tests__/connection-management.integration.test.ts
src/__tests__/tool-access-service.test.ts
src/__tests__/tool-gateway-service.test.ts
src/services/gmail-tool-governance.test.ts
src/services/google-chat-tool-policy.test.ts
src/__tests__/instance-settings-service.test.ts
src/__tests__/health.test.ts
src/__tests__/instance-settings-managed-overlay.test.ts` passes (864
tests).
- `cd ui && npx vitest run src/pages/apps
src/pages/InstanceExperimentalSettings.test.tsx
src/features/connections` passes.
- `tsc --noEmit` passes for `packages/shared`, `server`, and `ui`. The
`ui` run shows errors only in the untouched
`storybook/support/feature-map` files.
- `pnpm check:token-gates` passes.
- Manual check: open **Apps** with the setting off. Search for "Gmail".
The Composio Gmail row appears, and the built-in Google Workspace card
does not. Turn on the setting in **Settings → Experimental**. The
built-in card appears again.

## Risks

- Existing built-in `google-workspace` connections stop running while
the setting is off, because the generic gate blocks execution. This is
intentional, so that the unverified Google app is not used. Turn on the
setting on instances that must keep these connections.
- Saved per-service Google connections are not affected.
- When the setting is on, the behavior does not change.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Claude Opus 5.5 (Anthropic), model ID `claude-opus-5-5`, running in
Claude Code with tool use (shell, file edits, web fetch).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 14:37:24 +00:00
TonioandClaude Opus 5.5 9e9a628a57 feat(ui): turn Artifacts V1 on for every instance and hide its toggle (#19164)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Artifacts show the output of agent work on the Artifacts page, in
the panel Artifacts tab, and in the task thread
> - #17228 added the Artifacts V1 presentation behind an experimental
setting that is off by default
> - The presentation is now ready for all users, so an opt-in toggle is
no longer necessary
> - A new default alone does not reach all instances, because each
experimental write persists every flag
> - This pull request removes the toggle and turns V1 on for every
instance
> - The benefit is one artifact presentation for all users, with an off
switch for hosting operators

## Linked Issues or Issue Description

Refs #17228
Refs #17263

**Is your feature request related to a problem? Please describe.**
Artifacts V1 shows only on instances where an admin turned on an
experimental setting. Other users see the previous cards.

**Describe the solution you would like**
Show Artifacts V1 on all instances. Remove the toggle from Experimental
settings.

**Describe alternatives you have considered**
A new default without a change to the hook. This does not work, because
many instances have a stored false that nobody chose, and no toggle
would remain to change it.

## What Changed

- Removed the Artifacts V1 card from Instance Settings, Experimental.
- Changed `enableArtifactsV1` to default on in the schema, the feature
catalog, and the settings service.
- Changed `resolveArtifactsV1Enabled` to ignore a stored false. It
honours false only when the value comes from managed config.
- Kept the flag and the previous cards, so a hosting operator can hold
V1 off.
- Kept the key in the Cloud staging list, so a managed false does not
hold V1 off on staging.
- Updated unit tests, the Artifacts V1 plan, and the directions-lab
Today reference.
- Moved the attachment and upload e2e specs and the runner download
helper to the V1 rows.
- Added V1 tests for a Markdown review: expansion, deep link, and open,
raw and download actions.

## Verification

- `cd ui && npx vitest run`: one test file failed before its fix. That
file tests the previous cards, and it now mocks the hook to off. I reran
it with the other changed UI tests, and they pass. I did not repeat the
full UI run after the fix.
- `npx playwright test --config tests/e2e/playwright.config.ts
tests/e2e/text-attachment-tabs.spec.ts
tests/e2e/artifact-uploads.spec.ts
tests/e2e/artifact-tab-arrival.spec.ts`: 10 tests pass on V1.
- `tests/e2e/cloud-auth.spec.ts` failed once in CI on a task heading. It
does not touch artifacts, and 10 local runs pass.
- `cd server && npx vitest run src/__tests__/instance-settings`: 183
tests pass.
- `cd packages/shared && npx vitest run src/feature-catalog.test.ts
src/validators/instance.test.ts`: 35 tests pass.
- `pnpm run check:token-gates` and the `ui` and `server` typechecks
pass. I did not run the full repository check.
- In the artifact directions lab, with no stored settings, the Today
right panel renders the V1 rows.
- I did not test this on a live instance. After merge, confirm on
staging that the Experimental page has no Artifacts V1 card and that all
three surfaces show V1.

## Risks

- All users see V1 after the next release, not only staging users. To
revert, revert this pull request.
- Users cannot turn V1 off. Only a hosting operator can, through managed
config, and not on Cloud staging.
- An instance with a managed `enableArtifactsV1: false` stays on the
previous cards. The cloud harness source has no reference to this key,
but I cannot read the live fleet configuration.
- V1 surfaces render before settings load. An operator-held instance can
briefly show V1 before the previous cards.
- Admins who use the API can still write the flag. The write has no
effect on unmanaged instances.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with
tool use and code execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 08:14:49 +00:00
DottaandPaperclip 40b8075916 feat(ui): show scheduled task waits as Monitoring (#18624)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task indicators tell an operator whether work is active, waiting, or
complete.
> - An agent can yield until a saved monitor checks CI or another
external result.
> - The task currently keeps the In Progress icon between those runs.
> - Changing the stored status would affect monitor admission and
recovery.
> - This pull request adds a read-only Monitoring display state with a
blue clock.
> - Operators can see and filter scheduled waits while execution keeps
its existing rules.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Task status indicators, task collection filters, board columns, and
search facets.

**Current behavior**

A task that waits for a scheduled monitor shows the same In Progress
icon as active work.

**Proposed behavior**

Show Monitoring with a static blue clock when an agent-owned task has a
saved ordinary monitor and no active run, execution lock, review
participant, or active recovery action. Return to the normal task
indicator when the check starts. Preserve review, blocked, terminal, and
quota-recovery states.

**Reason and benefit**

Operators can distinguish scheduled waits from current agent work
without reading the task history.

**Breaking changes**

None to stored task statuses or execution rules. Task reads gain
optional displayStatus. Collections and search gain a separate read
filter. Existing status filters keep their lifecycle meaning.

Related historical work: #4396 covered a monitoring label exemption.
This change uses the saved monitor and a read projection.

## What Changed

- Add one SQL projection for task detail, compact lists, summaries,
relations, search results, and display-status counts.
- Show the blue clock in shared task icons and chips, task detail and
breadcrumbs, properties, references, list rows, recent navigation, and
agent task cards.
- Add Monitoring to task filtering, grouping, sorting, board columns,
and search facets. Prevent a drag from creating this derived state.
- Keep stored lifecycle statuses, monitor scheduling, checkout,
recovery, permissions, and agent status filters unchanged.
- Add database and UI regression coverage, full-page Storybook examples,
and product and access-map documentation.

## Verification

- Passed `pnpm -r typecheck`.
- Passed `pnpm build`.
- Passed `pnpm check:token-gates` and the map/catalog structural checks.
- Ran the new database suite on a disposable PostgreSQL 17 database. It
covers read surfaces, filter pagination/counts, queued/running checks,
rescheduling, completion, retained monitors, review, and recovery holds.
- Ran existing search, list, board, sidebar, task status, and filter
tests. Corrected board queries use displayStatus and eight columns.
- The full local `pnpm test:run` stopped in a chat integration shard: 12
failures (four timeouts and eight FIFO publication assertions). That run
spanned a rebase. A focused rerun on the current source passed all 21
selected cases without assertion or timeout changes. The original cause
is not established; this does not claim the full local suite passed.
Final-head required CI passed (ci / verify and ci / e2e, run
41488267209).
- Passed 82 tests for task API summaries, recovery precedence, search,
and optimistic updates; 54 tests for status cards, database reads, and
board moves; and 27 tests for blocker relations and recent-task cache
updates. One intermediate database setup hit its 20-second hook timeout;
the serial rerun passed.
- Greptile is 5/5 on d003ea672d. All
review threads are resolved. The separate optional Paperclip Review
ended early and returned neutral; GitHub rejected a direct rerun request
with HTTP 404. It is not counted as a completed review.
- Review fixes cover escalated recovery, is:open, optimistic status
changes, blocker-summary projection, and recent-task dedupe.
- Reviewed 15 screenshots from production pages and components with
isolated Storybook API fixtures: task detail/properties/breadcrumb,
list, groups, status filter, board, search/results/filter counts,
reference pills, sibling navigation, agent cards, picker, dashboard,
inbox, profile, watched status-card tasks, light theme, and mobile. This
does not claim deployed staging verification.

## Risks

- Read projections must stay consistent across full, compact, summary,
and search responses. Tests cover those paths.
- Monitoring is not a writable lifecycle status. The board does not
accept drops into its Monitoring lane or onto a monitored card. This
prevents a drag from implying a scheduled check. Move work into In
Progress through that lane instead.
- The read projection adds run/recovery existence checks. Existing
heartbeat_runs_company_issue_created_idx and
issue_recovery_actions_company_source_status_idx indexes cover the
company/task lookup. It adds no worker, timer, recurring query,
migration, or provider call. No production load benchmark is claimed.
- Older clients can ignore displayStatus. Existing lifecycle status
filters keep their behavior.

## Model Used

OpenAI Codex, GPT-6, with reasoning, repository tools, code execution,
and browser tools. The exact backend model identifier and context-window
size are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 11:35:30 -06:00
Nicky LeachandPaperclip aab87ce707 Prove workspace delivery before inspecting cleanup candidates (#18493)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Completed tasks leave workspaces that need safe cleanup.
> - Providers without ancestry inspection currently need a recorded
merged PR before cleanup can start.
> - A squash merge changes commit identity, so direct ancestry cannot
prove that delivery.
> - This change proves delivery from the finalized HEAD and captured
destination before storage inspection.
> - Fresh storage checks and a second delivery check still protect
removal.
> - This reuses the existing worker and receipts. It adds no table or
timer.

## Linked Issues or Issue Description

Refs #18410. Related: #13400 addresses workspace identity during
inspection; this change adds destination-aware delivery discovery.

## What Changed

- Resolve direct ancestry or discover an associated merged GitHub PR
without a recorded work product. Require exact HEAD, destination
repository and branch, and a reachable integration commit.
- Use the latest settled finalization receipt as a candidate. Reject
missing, failed, pending, conflicting, or changed evidence.
- Inspect storage only after positive remote proof for providers that
disable ancestry inspection. Recheck HEAD, branch, source identity and
delivery before removal intent.
- Add an optional provider capability for a specific PR recovery hint
and an optional prepared destination receipt. Older providers keep their
existing protocol.
- Wake cleanup when finalization writes settle or gain a workspace
binding. Keep remote-only retries for concrete unresolved delivery. Park
missing or unsupported candidate identity.
- Reuse the source project's explicit GitHub consent for delivery checks
through the existing authorization service. Revalidate the bound
repository and consent before removal; missing or revoked consent
retains storage without switching identities. Public sources remain
anonymous.
- Update the contracts, documentation, access map, and targeted
regressions.

## Verification

- Initial-head GitHub CI passed at
`5acd4c818be6f1764f8319f42891f9956c357c26`, including full build and
typecheck. Standard Greptile is 5/5 with no open threads. The first Apex
review scored 3/5 and found startup latency from remote proof lookups
and removal retry identity changes across provider capability changes.
Both corrections are pushed in `9d1a38df3d`, with the qualified
destination-ref length fix. Red regressions reproduced each issue.
Latest targeted checks passed: cleanup/worker 26, provider integration
41, SDK contract 8. Head `9d1a38df3d` passed standard and Apex reviews
at 5/5 with no open threads, plus all CI including full build/typecheck.
Canary Dry Run initially failed on an npm 404 fetching
`rollup-4.67.3.tgz`; the exact tarball subsequently returned HTTP 200,
and one targeted retry passed without source changes. Aggregate
verification also passed. After #18403 merged, master introduced
conflicts in shared workspace cleanup and metadata handling. Resolved
them in `7700832536`, preserving remote snapshot cleanup and Git
delivery-proof cleanup. Targeted merge verification: 93 tests passed in
the first run (59 opt-in skips), then all 16 remote lifecycle tests
passed with explicit database opt-in; map checks passed. The isolated
database is stopped. The merge head received standard review 5/5. Its CI
found two failures in unchanged test cleanup paths: native runtime
temporary-directory ENOTEMPTY and agent-chat cancellation lock timeout.
Those failures remain recorded and require successful final-head
verification. The subsequent project-consent change has targeted
coverage: authorization36, resolver33 and cleanup19 tests passed,
including revoked consent, anonymous public access and source-binding
races. The positive consent test failed before the fix. Current head
`c772679e05` has green GitHub CI, including full build/typecheck and
both previously failing test jobs, plus standard Greptile 5/5 with no
open threads. Neither cleanup failure required changes to its test path.
Apex also completed at 5/5 on this exact head (check `124651548532`,
summary updated 2026-10-31 20:45 UTC), with no open review threads. The
PR remains draft. Earlier failures remain recorded above.

- Final focused run on the rebased branch: **182 tests passed across six
files**, covering the resolver, delivery cleanup, provider bridge,
finalization notifications, existing workspace service and SDK
contracts. The disposable test database was stopped afterward.
- Targeted resolver tests: 33 passed. These cover ancestry, discovered
squash PRs, wrong HEAD/base/repository, removed integration commits,
bounded responses, cancellation and credential isolation.
- Targeted cleanup integration tests: 17 passed. Provider bridge
integration: 36 passed. SDK contract tests: 7 passed. Finalization
notification tests: 9 passed.
- A negative control that removed the final delivery check failed the
race regression as expected. The check was restored.
- Read-only live GitHub probe: the new resolver discovered PR #18410
from HEAD `3f5ade4cd42b707040e9a82fdaed343e3d736a09`, without PR hints.
It proved integration commit `6484f96c28bfb11a793ce4be6cc5ac15643a5a02`
reachable from observed master
`5bc029bf6c1db6647e96acea323f3723fd1d3eba`. GitHub also advertised the
exact original HEAD at `refs/pull/18410/head`.
- `node scripts/check-maps.mjs` passed. Structural checks do not prove
deployment behavior.
- Local tests are targeted by user request. Full build, typecheck and
test suite run in GitHub CI. A standalone server typecheck could not
complete because local Runner build declarations were absent; no
changed-file diagnostics were reported.
- Initial local execution hit a stalled pnpm wrapper, sandbox socket
denial and stale generated SDK declarations. Direct installed binaries,
the authorized isolated test database and rebuilt SDK resolved those
setup failures. No deployment was performed.

## Risks

- Destructive cleanup still requires fresh storage safety and lifecycle
checks. Remote proof alone never authorizes removal. A persisted removal
intent preserves existing recovery semantics.
- Legacy workspaces without an unambiguous destination or completion
HEAD remain retained. This does not guess the original default branch.
- Private repositories use the explicit standing GitHub consent on the
bound source project, with current membership, grant, repository access
and trust checks. No separate company token is required when that
consent is valid. Missing or revoked consent and unavailable or
rate-limited access retain storage; the worker does not borrow a task or
agent identity.
- A known undelivered commit keeps the existing five-minute retry
because external GitHub changes have no guaranteed ingress to this lane.
This can keep cleanup scheduled. Missing evidence parks instead.
- Providers need the new recovery capability to clean a squash merge
whose original HEAD is reachable only through its PR ref. Providers
without it remain conservative.
- The resolver currently supports GitHub.com. Existing local and
other-provider ancestry paths stay in place.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools and
parallel code agents. The exact runtime model ID and context-window size
were not exposed to this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 07:59:17 -08:00
TonioandClaude Opus 5.5 8ea240218d feat(ui): bring the Refine-v2 layout to the agent page (#18378)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The agent page is where an operator reads and changes one agent.
> - The page grew one tab at a time. Ten tabs sit in one flat list, the
header holds many buttons, and the audit links leave the agent.
> - A design pass, called Refine-v2, made a calmer layout for this page.
It ran in a prototype on fixture data only.
> - This pull request moves the Refine-v2 layout and behavior into the
live agent page. Where the prototype and the live page differ, the live
behavior stays. For example, the floating save bar stays on screen.
> - The benefit is a shorter navigation, edits in place, and audit data
that stays inside the agent.

## Linked Issues or Issue Description

Refs #13716
Refs #9166

Both pull requests mount plugin tabs or slots on the agent page. They
touch the same files, so one of the three needs a rebase after the
others merge.

**Subsystem affected**

The agent detail page in `ui/` (`ui/src/pages/AgentDetail.tsx`, its
sidebar, header actions, and the shared agent config form).

**Problem or motivation**

The agent page is hard to scan. The navigation shows ten items in one
list. The header shows Run now, Pause, Clear error, and Assign task as
separate buttons. The name, title, and manager are form fields deep in
the Harness tab. Activity, Runs, Costs, and Budgets open company-wide
pages, so the operator loses the agent context. Each tab uses a
different card and table style.

**Proposed solution**

Use one layout system for every agent tab. Group the navigation into
Agent and Audit. Edit the name and title in the header. Move the work
actions into the actions menu. Show audit views inside the agent. Keep
the persistent save bar and add a status dot to it.

**Alternatives considered**

We considered a flag that lets operators opt in to the new layout. We
did not use a flag, because two layouts on one page double the test
surface. We also considered moving the save button to the end of the
scrolling content, as the prototype did. We kept the floating save bar,
because it is always visible.

**Roadmap alignment**

`ROADMAP.md` has no item for the agent page. This change is a UI
refinement of an existing page. It adds one optional field to an
existing API request and no database schema change.

## What Changed

- **Navigation.** The agent sidebar shows two groups. Agent has
Overview, Identity, Harness / Runtime, Secrets & variables, Permissions
/ Trust, and Advanced. Audit has Activity, Runs, Costs, and Budgets.
Skills, Tools, Channels, and API Keys leave the navigation. Their URLs
still open. The Instructions tab is now Identity, at `/identity`. The
old `/instructions` URL redirects.
- **Header.** The agent character shows at a larger size. The name and
title edit in place. Enter or blur saves. Escape cancels. An error
restores the old value. A rename updates the URL. While a tab has
unsaved changes, the header refuses the edit and asks the operator to
save or discard first. The third line shows the title and a link to the
manager. A crown button to the right of the name replaces the "Set as my
primary" link and the separate primary indicator. It is outlined and
dimmed until the agent is your primary, then fills with a short pop.
Replacing an existing primary asks for confirmation first, and the pop
plays after the dialog closes. Reduced motion skips the pop. Run now,
Pause or Resume, Clear error, and Agent history move into the actions
menu. Assign task is the primary button. For an agent that still needs
setup, Finish setup is the primary button and Assign task moves into the
menu.
- **Agent history.** A new dialog in the actions menu replaces the
Revisions entry. Each row shows a plain-language summary, the person or
agent who made the change, the date, and Restore. Restore asks for
confirmation. A failed restore shows its reason inside the confirmation.
- **Overview.** Four metric tiles show activity this week, runs this
week, costs this month, and budget used. Each tile links to its audit
view. When the list behind a count is capped, the tile shows a lower
bound, for example 200+. The activity tile follows live updates.
Profile, Skills, and Recent tasks panels follow. The Profile panel lists
direct reports under their label in at most two rows, then a "+N more"
button that expands the list. The Latest run card is removed.
- **Identity.** The file preview shows the raw text. A pencil button
switches to a plain text editor. Copy and Delete are icon buttons. A
chip next to the file name says "Managed by you" or "Managed
externally". Per-file history and unsaved edits stay.
- **External instructions.** "Advanced settings" opens Root path and
Entry file fields and a Load profile button. Load profile asks the
server to switch only if the root directory and the entry file already
exist. If either is missing, the server refuses and the panel shows the
reason. The entry file can have any name inside the root.
- **Instructions bundle API.** `PATCH /agents/:id/instructions-bundle`
accepts an optional `requireExistingEntry` flag (`packages/shared`
validator, `server` service, `ui` client). With the flag, the server
checks the root directory and entry file before it creates or copies
anything. Without the flag, the behavior does not change.
- **Harness / Runtime.** The config form gets a `panels` layout: Harness
and Execution side by side, then the runtime test, then environment
variables. The identity and run-policy sections are hidden from this
tab.
- **Secrets & variables and Advanced.** These tabs use the same filled
panels and table headers.
- **Permissions / Trust.** The trust presets show as selectable cards.
An Allowed connectors panel shows up to three connector logos and links
to Apps, filtered to installed connectors. Capabilities sit in their own
panel. Changes on this tab save at once, with no save bar.
- **Audit inside the agent.** Activity, Runs, Costs, and Budgets render
inside the agent page. Runs is locked to the current agent. A failed
budget incident action shows its reason under the incident.
- **Save bar.** The floating save bar stays. It shows an amber dot for
unsaved changes and a green dot with "Changes saved" after a save.
Discard stays.
- **Leave guard.** If the form has unsaved changes and the operator
clicks a link, a dialog asks to keep editing or discard the changes.
Browser back and the header actions keep the native confirm.
- **Apps.** `/apps?source=installed` opens the Apps page on the
Installed filter.
- **Tokens.** New `--agent-detail-*` tokens in `ui/src/index.css` hold
every spacing and fill value. Each fill is a mix of foreground into
background, so one value works in light and dark themes.
- **Tests and maps.** Tests cover the navigation model, sidebar, header
menu, Overview layout, Identity editor, and helpers. The
agent-configuration recipe in `maps/feature-map/agents.md` describes the
new page.

## Verification

- `cd ui && npx vitest run`: 849 test files and 10,081 tests pass.
- `cd server && npx vitest run
src/__tests__/agent-instructions-routes.test.ts
src/__tests__/agent-instructions-service.test.ts`: 40 tests pass.
- `npx playwright test --config tests/e2e/playwright.config.ts
tests/e2e/onboarding.spec.ts
tests/e2e/chat-adapters-ui-providers.spec.ts`: 26 tests pass.
- `cd ui && pnpm typecheck` passes. This includes the Storybook catalog
check. The `server` and `packages/shared` typechecks pass.
- `cd ui && pnpm build` passes.
- `pnpm run check:token-gates` reports all gates clean.
- `node scripts/check-maps.mjs` and `node scripts/storybook-catalog.mjs
--check` pass.
- Manual check on a local instance, in light and dark themes:
1. Open an agent. Confirm the sidebar shows the Agent and Audit groups.
2. Click the agent name in the header. Type a new name and press Enter.
Confirm the URL changes. Rename it back.
3. Open the actions menu. Open Agent history. Confirm the rows and the
Restore confirmation.
4. Open Identity. Click the pencil. Change a line. Confirm the save bar
shows the amber dot. Click a sidebar link. Confirm the discard dialog.
Click Keep editing, then save. Confirm the green dot.
5. Open Harness / Runtime, Secrets & variables, and Permissions / Trust.
Confirm the panels and the trust cards.
6. Open Runs under Audit. Confirm the list shows only this agent and the
page stays inside the agent.

## Risks

- This changes a high-traffic page for every operator at once. There is
no flag to switch back.
- Run policy and Reports to are no longer editable on the agent page.
The header shows the manager as a link only.
- Skills, Tools, Channels, and API Keys are reachable by URL only.
Operators who use them from the sidebar must use the URL.
- The pull request conflicts with #13716 and #9166 in `AgentDetail.tsx`
and the agent sidebar.
- Storybook stories for the agent page and `DESIGN.md` are not updated
in this pull request.
- The new `requireExistingEntry` flag is opt-in. Existing API callers
keep the old behavior, which creates a missing external directory and
entry file.
- I ran two e2e spec files locally, not the full `pnpm test:e2e` or
`pnpm test:release-smoke`. CI runs the full e2e suite. I did not run the
repo-wide `pnpm -r typecheck`, because the local toolchain has no Rust.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), in Claude Code, with
reasoning and tool use (shell, file edits, and a browser for visual
checks). A person directed every design decision.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 22:27:09 -08:00
34f8d25089 fix(github): expose review finding categories (#18429)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - GitHub review bots submit structured assessments through task-bound
tools.
> - Each repository can set its own finding categories.
> - The schema accepts a string, but the server rejects values outside
the saved review policy.
> - Review instructions did not list the accepted values. The error did
not list them either.
> - This change gives agents the values before submission and keeps
server validation.

## Linked Issues or Issue Description

**What happened?**
Review submissions failed with an unknown finding category. The agent
corrected the assessment before publication. The sampled trace has two
rejections followed by a processed review. Historical tool inputs are
null. Authorized diagnostic inspection found no saved raw provider trace
for the representative run. The exact rejected values remain unknown.

**Expected behavior**
Agents can find the accepted categories before submission. Unknown
values still fail validation.

**Steps to reproduce**
Set a custom finding category. Start a review. Submit a different
category. Before this change, the instructions and error do not list the
accepted value.

## What Changed

- List configured categories in manual and automatic review
instructions.
- Return categories from the saved assessment policy in `begin_review`.
- Describe the dynamic constraint in the shared discovery schema. Keep
custom categories valid.
- List accepted values in category errors. Keep authorization and
publication checks.
- Add contract and database integration tests. Update documentation and
access maps.

### Hypothesis and thesis for a fix

The missing category guidance can cause avoidable submission retries. A
model can also ignore the policy returned by metadata reads; the
historical inputs do not establish which occurred. The repair belongs to
the GitHub review contract. Use the saved policy categories at review
start, explain the constraint, and retain server rejection. A fixed
global enum would reject valid custom categories.

## Verification

- Baseline `f1d7808`: two new contract assertions failed for missing
category guidance and error detail. The same assertions pass after the
change.
- `pnpm exec vitest run
server/src/services/chat-github-review-policy.test.ts
server/src/services/chat-github-tools.test.ts`: 41 passed.
- `pnpm exec vitest run
server/src/__tests__/chat-channels.integration.test.ts -t 'returns
snapshot finding categories'`: 1 passed. Real PostgreSQL and service
code; simulated GitHub HTTP. Checks policy changes, rejection before
publication, accepted custom category persistence, and processed
publication.
- `node scripts/check-maps.mjs`: passed. Structural evidence only.
- Shared TypeScript check passed. Server TypeScript checking was killed
by the 8 GiB memory limit, including a separate retry after the other
checks stopped.
- Full typecheck and build could not complete: `cargo` is absent. Full
tests were stopped after concurrent checks exhausted memory. CI must
supply the full checks.
- Follow-up compiler repair: the unchanged baseline reproduces TS2352 in
the category discovery test. Runtime matchers replace the unsafe schema
cast. They retain both guidance and custom-category assertions. The
repair is commit `0dcb94c676`, with current master merged at
`14d7052854`. The final head is
`c46b8f35add9255fc71be294d27f5a7865bcb47f`; the remaining code-comment
review finding was removed and resolved.
- Final-head CI: all gates pass, with no failed or pending checks.
Greptile gives this head 5/5 with no outstanding findings; the only
inline thread is resolved. The workspace test shard passed on one
bounded rerun after an earlier CLI child-server readiness timeout; no
code change was made for that rerun.
- The review host passed full recursive typecheck and build after the
compiler repair and master integration. Fresh database rechecks hit the
host PostgreSQL semaphore limit. The full local test command hit a
pre-existing chat line-selection failure before assertions. These local
limits do not replace the passing final-head CI evidence.
- No live model or GitHub publication at the changed revision. No
deployment or merge.

## Risks

- Instructions add policy text. An agent can still ignore it.
- Existing bot catalogs get the schema description when tools are
synchronized. Trusted review instructions and `begin_review` also expose
categories.
- The service test uses simulated GitHub HTTP. It does not prove that
deployed agents avoid retries.

## Model Used

The original worker used OpenAI `gpt-6.1-sol` through Codex with
reasoning, tool use, and code execution. A later Codex review repaired
the test compiler error. That review runtime exposes GPT-6 but no exact
snapshot or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Dotta <bippadotta@protonmail.com>
Co-authored-by: cryppadotta <34892728+cryppadotta@users.noreply.github.com>
2026-10-31 22:06:32 -05:00
DottaandPaperclip eb12cfc96b perf(github): activate connection work from events and deadlines (#18395)
Reviewed and verified at f77620b9a4.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 15:38:43 -05:00
DottaandPaperclip 5e4cc01073 feat(workspaces): keep remote files off the webserver disk (#18403)
Keep native sandbox workspace files independent of the webserver disk. Use encrypted saved versions and Postgres ownership so a replacement server can recover files and continue work. Enable the path by default for new eligible workspaces when durable storage is configured.

Preserve explicit opt-outs and existing host workspaces. Include safe snapshot repair, Files access, import, migration and retention. Bound saved-Files resources, preserve imported Git recovery, reject unfinished Git operations, publish immutable concurrent captures, and verify permanent object-version deletion.

Validated 471 targeted local controls, build/typechecks, all 40 CI partitions, fresh Greptile 5/5 and security review. The PR records original failed attempts and scoped retries.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 14:54:01 -05:00
Nicky Leach 6484f96c28 fix(workspaces): inspect storage only when needed (#18410) 2026-10-31 11:43:18 -07:00
DottaandPaperclip 8ff812cdde feat(chat): deliver proactive task messages to agent chats (#18374)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent Chat gives each person a persistent conversation with each
agent.
> - Tasks and routines produce results outside that conversation.
> - Those runs need a safe way to bring a requested result back to the
person.
> - The server must select the agent's own chat and check the source
task's access rules.
> - This pull request adds proactive chat messages and unread
indicators.
> - People can see the result, open its source task, and reply in the
same chat.

## Linked Issues or Issue Description

**Subsystem affected**

Server, native runner tools, shared contracts, database, and UI.

**Problem or motivation**

An agent can report progress on a task or comment on an authorized task.
It cannot send a routine result to its own standing chat with the
responsible person. A morning review routine therefore cannot leave a
visible digest in that person's chat.

**Proposed solution**

Add `send_chat_message({body, idempotencyKey})` and `POST
/api/agents/me/chat/messages`. The server selects the company, agent,
and responsible person from the active run. It saves an attributed
comment and audit record in one transaction. The chat shows a
source-task link and per-person unread state.

**Alternatives considered**

A destination parameter on a generic comment tool would expose
unnecessary routing authority. A new delivery worker would add another
durable delivery path. This change uses a dedicated tool and the
existing comment and live-event paths.

**Roadmap alignment**

This extends the experimental Agent Chat capability in `ROADMAP.md`. The
existing `enableAgentChat` setting controls it. Related public work:
Refs #13282, Refs #13283, and Refs #14408. Searches for proactive chat
and unread chat found no duplicate PR.

## What Changed

- Add a focused messaging service shared by the native tool and HTTP
route. It checks current run ownership, execution mode, recipient
membership, task access, and task privacy.
- Reuse the canonical company/agent/person conversation. Save the
comment and audit record together. Keep task completion and chat
execution separate from delivery.
- Add source-task provenance and source-scoped retry keys. Identical
retries return the saved receipt. Changed content returns a conflict.
- Enforce the conversation's fixed agent at the shared comment-write
boundary. Keep normal reply cancellation and session checks.
- Add chat unread state, accessible agent dots, aggregate Chat
indicators, and visible-message read cutoffs. Refresh through existing
live events.
- Add the request-key constraint, native tool contracts, documentation,
capability maps, stories, and regression coverage.

## Verification

- Local delivery/security proof: all 38 proactive-message cases pass.
Eight credential-scope regressions and four quota regressions fail
against the prior source. The repaired delivery and canonical
cross-issue cap suites pass all 49 cases; all 31 OpenAPI tests, server
typecheck, and capability-map checks pass. The shared per-run cap covers
native and HTTP sends, mixed ordinary mutations, concurrent last-slot
contention, and retry/recovery without double charging.
- Credential tests preserve the authenticated person and authorizer;
reject bridge/test credentials and persisted skill-test runs after
task-mode changes; and recheck API-key revocation, scope, and
responsible person after destination locking. The earlier
delivery/native-authority suites passed all 74 cases before the four
quota additions.
- Four PostgreSQL contention cases cover native and HTTP sends plus
retries during a native chat mutation. All four deadlock against the
earlier source and pass with destination-before-source/run locking.
Recovery and human-reply delivery enqueue only the human comment; a
proactive digest never wakes the chat agent.
- Passed 108 companion conversation, native-authority, and OpenAPI
tests; 112 runner catalog/workflow-report tests; 47 completion-delivery
tests; and 25 project-handoff tests. Focused runner tests cover native
tool availability without generic API tools.
- All 327 affected UI tests, UI typecheck, token gates, and catalog
checks pass. The read hook retries at most three times, respects server
retry delay, coalesces only seen cutoffs, recovers on reconnect, and
cancels on scope changes.
- Real browser journeys with a deterministic process agent verify
routine-to-chat delivery, first-chat creation, unread state across
reload, the source link, secondary chat navigation, and a follow-up
reply referring to the digest. This does not qualify live GitHub
retrieval or model output quality.
- The Storybook showcase uses production components with deterministic
network fixtures. Rendered interactions pass for the landing, ordinary
read success, transient read recovery, and persistent failure after
bounded retries. Both Chat navigation variants update from two unread
chats to one while only Kodi's dot clears. Mobile and light variants
were reviewed. The existing Coordinator Recents label contrast finding
is unchanged; no Linux visual baseline archive exists.
- Current master's independent sandbox migration retains 0418.
Regenerated the feature migration as 0419 from the combined schema and
retained exactly the newest five snapshots; numbering/safety, replay,
and schema-drift checks pass.
- Workspace typecheck and build passed before PR preparation; canonical
server/UI typechecks passed again on the combined tree. Migration
`0419_slippery_impossible_man.sql` passes safety and schema drift checks
on disposable PostgreSQL, including interrupted index repair, concurrent
migrators, one-time owner read-state backfill, preserved receipts, and
two SQL replays. A default five-second local snapshot comparison timed
out; a diagnostic 30-second run passed without drift.
- Earlier failures are retained in the record: full local `pnpm
test:run` and broad shards encountered embedded-PostgreSQL startup,
timing, and provider-recovery failures. Thirteen selected
external-channel cases pass in isolation on the original and changed
sources; an unordered comment-row assertion now explicitly orders both
reads. The earlier route registry, native tool count, runner catalog,
and accessible Chat badge-name failures were fixed and passed full
remote CI on `920b3bb7db`.
- Repeated managed-skill server8 failures came from CI's newer synthetic
merge: its Cloud guard correctly rejected the old local-disk fixture.
Master independently repaired the fixture in #18385; this branch keeps
that repair unchanged. All 57 managed-skill and Cloud prerequisite cases
pass on the combined tree, and that fixture has no remaining PR diff.
- Current reviewed head `dc16f314739a6d977bed21cb1446d0e80a541578`:
Greptile 5/5 with no findings, Superagent security assessment passed,
advisory Paperclip Review 5/5 with no findings, and zero open review
threads. All 55 current-head check runs pass, with five expected skips
and the advisory review neutral at 5/5; Snyk also passes. No checks are
pending or failing. Protected squash auto-merge is enabled and is
waiting for required code-owner approval. A normal exact-head merge was
refused by the base-branch policy; no admin bypass was used. The
previous head's Superagent quota finding is fixed and covered above.

## Risks

- Chat remains company-visible. Delivery rejects a source task with
private-task, project, or ancestor restrictions.
- Read state uses a comment timestamp cutoff. The server retains
database precision and never moves a read receipt backward.
- The new unique constraint changes comment query planning. An existing
regression now uses an explicit row order. The migration builds the
unique index concurrently, then takes a brief table lock to attach it.
It uses the existing top-level migration and interrupted-index recovery
path.
- The upgrade backfills missing chat-owner read-state rows at the latest
existing agent comment. Existing read receipts remain intact. New chats
can still be unread before the human participates.
- Quota observation commits atomically with delivery. A rejected send
rolls back its attempted denial audit row and any first-chat creation;
the canonical warning remains in server logs, and previously spent quota
remains enforced. Identical/conflicting retries and receipt recovery
spend no extra slot.
- This version delivers in-app only. It adds no external-channel, push,
or email delivery.
- Local full-suite acceptance remains limited by the failures recorded
above. The feature stays behind `enableAgentChat`.

## Model Used

OpenAI Codex. PR preparation and CI work used `gpt-6.1-sol` with tool
use and code execution. The earlier implementation also used Codex, but
its exact model ID was not recorded in the visible session. The
context-window size was not provided.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run focused tests locally and they pass; the broad local
failures are recorded above
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-30 21:39:07 -05:00
DottaandPaperclip 45a3a92e6d fix(environments): persist sandbox ownership before creation (#18357)
## Thinking Path

> - Paperclip manages companies and the agents that do their work.
> - Remote execution creates provider resources that need a durable
owner.
> - The server could create a sandbox before it saved its lease.
> - A failed lease write could leave cleanup data only on the old web
server disk.
> - This change saves a company-scoped operation before creation and
transfers ownership atomically.
> - Recovery finds the original Daytona resource or records an explicit
manual reconciliation outcome.

## Linked Issues or Issue Description

**What happened?**
A sandbox could exist without a lease after a database failure or
company rebind. Failed cleanup recording could then create a local
fallback file. Replacing that web server could lose the cleanup
reference.

**Expected behavior**
A failed admission write makes no provider call. An interrupted creation
retains a committed operation. Recovery must not create a second sandbox
or destroy an attached lease.

**Steps to reproduce**
1. Run the disposable PostgreSQL cases in
`server/src/__tests__/sandbox-creation-operations.test.ts`.
2. Reject the lease insert after the controlled provider creates its
resource.
3. Start a new receiver process with a different empty web disk. It must
find the same resource and create one cleanup owner.

Related ownership report: Refs #14672. This change addresses new
allocations before lease persistence. It does not replace existing lease
recovery.

## What Changed

- Add an idempotent migration and a small creation-operation table.
Retain original company, environment and run identities across deletion.
- Commit creation intent before run, ad-hoc lease, and plugin task
replacement calls. Fence duplicate requests and ambiguous lease commits.
- Retain a known returned task resource ID in the existing operation
before attachment. Preserve manual reconciliation and never delete an
ambiguously attached resource.
- Keep company and run authority checks and atomic lease transfer with
the lease owner.
- Reuse Daytona names, labels, read-only inspection and claimed cleanup.
Keep provider payload handling in the provider.
- Retain nonsecret credential identity hashes. Refuse recovery lookup
under a changed credential value.
- Record manual reconciliation for missing/deleted or explicitly
inactive saved credentials, versions, and provider vaults. Keep
temporary resolution failures retryable. Never reactivate a disabled
credential.
- Use transaction signals and concrete deadlines. Failed records back
off independently. Manual reconciliation stays durable and quiet.
- Remove new orphan-file fallback writes from the covered paths. Keep
legacy file replay and its tests for cutover.
- Replace obsolete fallback-producer assertions with normal-entrypoint
durability tests. Keep cleanup, diagnostics and warm handoff coverage.

## Verification

- [Independent current-head
verification](https://github.com/paperclipai/paperclip/pull/18357#issuecomment-6534744320)
passed 190/190 combined tests, 40/40 incoming TestOps tests, full
workspace typecheck, and build. PR head
`958af986130f25e136065ad30d1fdd843c46255c` has tree
`e6c3e5b02182d5941a70ccf5bf55638df3c2e28d`, identical to tested combined
commit `b9d7a9c2e9b30f0153685fb24a5f70b56132201f`. Real PostgreSQL,
compiled Rust Runner and controlled object providers were used;
external-S3 integration remains outside this local proof.
- Current head `958af986130f25e136065ad30d1fdd843c46255c` normally
merges master `8595efc20bda3ce20a9fbbf34a5d156a6fcf6d57`. The sole
conflict was the maintenance test: a parameterized case now preserves
both legacy-local `local_storage` and valid shared-S3
`provider_mismatch` checks, including the parent local receipt, exact
version identity, missing-snapshot/no-seed refusal, and unchanged
persisted row. The three master TestOps files remain intact. No
production, schema, migration, or package changes were made after the
fully qualified prior head `0b4d05505e`. Independent review approved the
resolution; the full managed-skill-content file and Cloud guard controls
pass 58/58 (105.11 seconds). [Required PR CI passed on this exact merge
head, first
attempt](https://github.com/paperclipai/paperclip/actions/runs/41136987412):
54 successful checks and three intended skips. The additional Paperclip
review is neutral at 4/5; two external Superagent checks (Contributor
trust and Security Scan) remain in progress with zero annotations and no
assessment, so they are not passing scan evidence. Greptile reviewed
exact head `958af986130f25e136065ad30d1fdd843c46255c` at 5/5; the final
thread audit has zero unresolved threads. All completed evidence below
retains its recorded revision scope. The additional Paperclip Review on
`958af98613` is neutral at 4/5 with a Ship verdict and no must-fix or
should-fix item. Its optional observation is that a generic create
rejection remains pending/manual even when an operator believes
allocation did not occur. This change preserves uncertainty because the
generic create-error contract does not prove provider absence; no new
error classification or provider-specific compensation was added.

- [Independent final-source
verification](https://github.com/paperclipai/paperclip/pull/18357#issuecomment-6534328247)
passed all 189 real-PostgreSQL/Runner and controlled-fixture cases, full
workspace typecheck, and build. The integration commit
`c8411a8528386f4824b340ec5fdaaed1efb9ea69` has the same source tree as
final PR head `0b4d05505e` (tree
`bda65efc14b4c904d0f589154db77bb160641c8c`). Controlled object-provider
coverage passed; the separately guarded external-S3 suite was not run
because the bounded local MinIO pull was unavailable. This includes the
two final compatibility fixes.
- The first final-head CI attempt exposed one E2E timing failure in
`disconnect-write-recovery.spec.ts:181`: the title stayed unchanged
through the 15-second session-recovery poll. The same original case
passed in 13.8 seconds on immediately prior head `7ec06f77b7`, and all
UI/session/E2E source is identical across those heads. The failure log
and CI artifacts are retained; no cause is claimed. One failed-job-only
retry is authorized on this evidence, without changing a timeout,
assertion, or production behavior. [The single failed-job retry
completed
successfully](https://github.com/paperclipai/paperclip/actions/runs/41133619710/attempts/2):
all 35 E2E shard cases passed (6.6 minutes), including the original
session-recovery case in 14.0 seconds. The initial failure remains
disclosed and its cause remains unproven.
- Final head `0b4d05505ee0aa72f2981cdff74761406960ec73` adds two
independently reviewed integration fixes after the complete 7ec CI
matrix exposed two deterministic failures. Server 9/12 failed legacy
local-storage maintenance because the CLI reached the new Cloud server
startup guard; server 5/12 found the Daytona package version did not
match its bumped manifest. The failed run is retained at
https://github.com/paperclipai/paperclip/actions/runs/41131204203. It is
not passing evidence and was not blindly retried.
- Maintenance now constructs the existing explicit storage dependency
after loading the required persisted Cloud snapshot, and passes it to
both maintenance owners. It can verify legacy local storage before
provider cutover while normal Cloud server startup remains guarded. The
original case reproduced red locally, then the complete
managed-skill-content and managed-cloud-prerequisites files passed 57/57
(32.05 seconds), including missing-snapshot refusal, unchanged stored
configuration, and existing server guard controls. Daytona package
version now matches manifest 0.1.10; the complete bundled package
identity file passed 14/14 (3.98 seconds), and explicit
manifest/lifecycle controls passed 2/2 (328 intentionally filtered; 3.42
seconds). An initial workspace-filter command matched no project and is
not counted as pass evidence. The final diff changes no sandbox runtime
or schema behavior. [Full CI is green on this exact final
head](https://github.com/paperclipai/paperclip/actions/runs/41133619710/attempts/2):
56 successful checks, three intended skips, one additional
incomplete/neutral Paperclip Review, and no pending or failed checks.
The neutral review is not a passing assessment. [Greptile reviewed the
exact final head at
5/5](https://github.com/paperclipai/paperclip/pull/18357#issuecomment-6529396969),
with no new actionable issues and all review threads resolved.
- Final combined head `7ec06f77b7c14a745c569d18401f16df3d26b626`
includes master managed-skills migration 0417 and shared-storage
prerequisites from `198218bf55` through normal merges. Sandbox creation
moves to generated `0418_curved_lady_mastermind.sql`; its idempotent SQL
is byte-for-byte unchanged. The regenerated 0418 snapshot contains both
sandbox creation operations and the master skill mutation receipts, and
points to the master 0417 snapshot. Master SQL and journal history
remain intact. Exactly five snapshots remain, 0414 through 0418. The
only sandbox-specific changes since the approved credential policy are
migration metadata/number and the matching test/document references; the
sandbox runtime files are unchanged.
- [Independent final combined
verification](https://github.com/paperclipai/paperclip/pull/18357#issuecomment-6533960026)
passed on integration revision `e6f05b4cf0cd`, containing final sandbox
head `7ec06f77b7` and actual master `198218bf55`: migration/declaration
checks, all 158 real-PostgreSQL/Runner and controlled-fixture cases (251
seconds), full workspace typecheck (81 seconds), and build (35 seconds).
- Final combined migration proof: fresh real PostgreSQL has both tables.
A separate original-0417 sandbox table with a retained pending row
survives two applications of the renamed 0418 SQL unchanged, with the
expected primary/index and foreign-key structure. Migration
numbering/safety checks pass. The normal runtime migration reapply case
passes 1/1 (20 intentionally filtered cases; 46.69 seconds). The first
temporary qualification harness stopped before any database assertion
because its external `.ts` file selected CommonJS; the `.mts` harness
corrected that setup and passed. Independent review approved the exact
metadata and reference diff. Earlier full suite and live-provider
results below retain their stated revision scope.

- Credential-policy head `c606d473b03709f27577a55a1dfc0b0d3b4359fd`
handles the remaining inactive-credential review warning. The existing
boundary accepts only concrete secret-owner 422 codes and exact
no-details disabled/coming-soon vault messages. Unknown 422,
authorization errors, provider wrappers, and temporary database/provider
failures still propagate. Independent source review approved this
three-file correction. No generic resolver, schema, provider protocol,
retry cap, or activation behavior changed.
- Creation/cleanup qualification at `c606d473b0`: all 39 cases pass
against real PostgreSQL (81.27 seconds). The new cases use actual
disabled/archived saved secrets, a valid disabled version, and provider
vaults created ready before normal API updates disable them or mark them
coming soon. Each remains manual through restart/repeated scans, with
zero provider lookup and no retry deadline. The independent plugin idle
blocker remains intact. The temporary 503 control retains retry
ownership and later recovers one cleanup owner. Before this correction,
all five inactive-state cases remained pending; that failed evidence is
retained. The prior 18-case known-ID task proof below belongs to
`237144fcf6`, whose helper and task path are unchanged by this
correction.

- Known-ID head `237144fcf69a249c0e0310563428c0f55ed6d55c` also
addresses the independent task-replacement reliability warning. The
existing creation operation now saves only the known nonsecret returned
resource ID before expiry validation and attachment. The write is scoped
to operation/company/original environment and allows only a missing or
matching ID. It changes no ownership state and copies no resolved
configuration, credentials, or provider payload. Independent source
review approved this four-file fix.
- The complete real-PostgreSQL task suite passes 18/18 (9.52 seconds).
Rejected attachments retain the ID through manual reconciliation and
repeated scans. A real committed attachment followed by an injected lost
response retains the same active lease and attached operation, with no
release or second create. Same-ID retries work; conflicting IDs and
foreign companies cannot change it. The initial three regression cases
failed because the ID was absent, before the fix.
- The shipped Daytona manifest does not declare task support, so it
cannot enter this generic replacement path. The dispatcher requires both
declared task support and an environmentTask worker method. Generic
drivers without creation lookup still use manual reconciliation, with a
known returned ID retained when the database write can commit. No
automatic lookup capability or unconditional compensation was added.

- Previous boundary-fix head `8ba77def151ea85eeae2db7693254db7f87673b0`
fixes the fresh review finding about missing credentials. Only known
secret-owner 404 results at the recovery secret-resolution boundary
select the existing manual outcome. Provider inspection and transient
database/provider errors remain retryable. Independent source review
approved this change.
- Secret-boundary focused acceptance at `8ba77def15`: all 34 cases pass
against isolated real PostgreSQL. The complete creation suite passes
16/16 (100.75 seconds); the complete cleanup coordinator suite passes
18/18 (99.83 seconds). The new cases use normal saved-secret creation
and deletion, confirm zero provider lookup, restart/repeated scans, no
automatic deadline, preserved independent plugin idle blocking, and no
additional idle blocker after the controlled worker supplies its quiet
proof. A temporary 503 resolution failure preserves pending ownership
and later recovers one cleanup owner. No additional live provider
resource was created.
- Failed attempts remain part of the evidence. The initial red run
reproduced the pending-operation bug and also exposed a numeric-deadline
test harness mistake, which was corrected. A later combined run reported
an existing replacement-receiver failure and a new idle-fixture
assertion failure; it was interrupted while the next test file remained
in imports. An isolated diagnostic confirmed that the manual state was
correct but the installed fixture plugin correctly blocked sleep without
its independent quiet proof. The corrected test retains that blocker
assertion before supplying the controlled worker witness. The unchanged
replacement-receiver case passes in the final complete 16-case run; its
earlier failure is not counted as a pass or assigned a proven cause. No
timeout or production idle guard was relaxed.
- Greptile reviewed previous combined head
`7ec06f77b7c14a745c569d18401f16df3d26b626` at 5/5, with no unresolved
review threads. Its CI produced the two concrete integration failures
addressed above. The earlier CI and live evidence below remain
historical evidence, not a claim that the current full gates have
completed.

- Master integration update: merged `dbff3747b8` and then latest master
`76fde891cc` without rewriting branch history. Only `doc/DATABASE.md`
conflicted; the sandbox ownership, object-backed run evidence, and cloud
configuration sections all remain. The master merges changed no sandbox
implementation, migration, or provider code. Migration numbering/safety
checks pass and exactly five schema snapshots remain. At merge head
`f5d23d4a59828835d01c150f83fa2645fb2d3bec`, the two focused
creation/coordinator suites pass all 32 cases against isolated real
PostgreSQL (64.57 seconds). Those merge-head checks precede the
missing-credential fix below. The earlier live Daytona proof still
covers the unchanged normal creation/lookup/teardown path; the new
missing-credential branch is qualified with real PostgreSQL and
controlled provider hooks.

The optional Superagent Security Scan was inconclusive on prior head
`7ec06f77b7`: its pinned PR merge-base checkout failed or timed out,
with a neutral conclusion and zero annotations. An earlier scan could
not start within 120 seconds; a bounded rerun request returned HTTP 404.
These scanner failures are not passing security-scan evidence. On final
head `0b4d05505e`, the additional Paperclip Review check is neutral: its
assigned review execution did not complete and produced no validated
assessment. Fresh Greptile 5/5 and independent source review are
separate evidence. Previous-head required CI, independent review, and
the live Daytona qualification below passed.

- [Complete previous-head
CI](https://github.com/paperclipai/paperclip/actions/runs/41105726052)
passed at `0b5cbb763ab8faa25aa0ff1d8a405cdc0d3db409`: 53 successful
checks and three intended skips, including typecheck, full tests, build
and E2E. Greptile is 5/5 on this head and both original findings are
resolved.

- Initial head: 200 PostgreSQL runtime, creation and coordinator tests
passed. The corrected head also passes all 32 creation and coordinator
tests, including deletion before/during lookup, a failed lookup after
deletion, restart, settled polling and actual idle-safety checks. Cases
cover failed admission, failed lease writes, concurrent recovery, lost
provider replies, ambiguous transfer retries, company rebind,
environment deletion, stopped runs, lookup backoff, restart, drain and
settled SQL quiet.
- Separate receiver processes: passed. A controlled HTTP provider
retains the resource while three independent receiver processes use two
empty web disks. Recovery creates one cleanup owner and never repeats
creation.
- Fresh PostgreSQL migration and two additional applications: passed.
The pending creation row survives unchanged.
- Server TypeScript and SDK/shared build checks pass after the
corrections. Migration numbering/safety checks passed. Exactly five
schema snapshots remain.
- Daytona adapter: all 330 tests passed, including stable-name lookup,
ownership checks, deletion and the updated manifest version. An earlier
run exposed the version expectation and it was corrected. Previous-head
CI passed.
- Live Daytona acceptance passed on `0b5cbb763a`: isolated real
PostgreSQL, normal runtime acquisition through independent receiver
processes, actual Daytona plugin/SDK 0.203.0, one disposable Ubuntu
24.04 sandbox (1 CPU / 1 GiB RAM / 1 GiB disk). A forced lease insert
failure retained the committed operation; a fresh receiver with empty
disk found the same sandbox, repeated recovery retained one cleanup
owner, and the actual claimed cleanup sweep expired the lease and
resolved the operation. Independent SDK lookup returned typed not-found;
ordinary recorded-ID inspection returned destroyed. This successful
attempt made one create, one recovery lookup, and one teardown. Two
earlier failed harness/provider-confirmation attempts are disclosed in
the [live acceptance
record](https://github.com/paperclipai/paperclip/pull/18357#issuecomment-6530313054).
The coordinator independently queried all three exact resource IDs
through the SDK and confirmed typed not-found for each.
- Complete CI-affected heartbeat/plugin warm-task suites passed 21/21
after test corrections. An unchanged workspace exposure case passed in
isolation after the prior CI shard reported an unhandled readiness
rejection. Complete previous-head CI and refreshed review passed.

## Risks

- Deleted companies retain an explicit manual reconciliation outcome.
Recovery does not retry missing credentials or insert a lease for a
deleted company.
- Only Daytona declares automatic creation lookup. Other uncertain
providers retain `needs_reconciliation`. A missing creation name alone
cannot prove that a late allocation will never appear.
- Pending operations use the existing process-local signal and startup
recovery model. This does not add cross-replica wake delivery or prove
deployed sleep.
- Legacy direct provider probes and custom-image setup use separate
lifecycles. They are outside this replacement of the run-lease
orphan-file fallback. The normal Test path that acquires a runtime lease
is covered.
- Existing orphan files still require the separate cutover inventory and
settlement. This change does not delete them.
- The schema change is additive. The new SQL can be reapplied.
Historical SQL and journal entries are preserved; only the oldest
generated snapshot is pruned.

## Model Used

OpenAI `gpt-6.1-sol`, with tool use, code execution and repository
review. The harness did not report the context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge


The required branch status checks (`ci / verify`, `ci / e2e`) and all
test/build jobs passed on this head. The non-required Superagent
Contributor trust and Security Scan checks are still running without
findings; they are not claimed as passes. No required check or branch
rule is overridden.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-30 17:38:23 -05:00
DottaandPaperclip 0e15c92073 feat(skills): make managed content independent of web-server disk (#18334)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents use installed skills and exact version pins during execution.
> - Managed skills still depended on mutable directories on the web
server.
> - A replacement server could lose acknowledged edits or remove an
unassigned skill whose directory was absent.
> - This pull request makes immutable versions the authority for managed
content and installed repository reads.
> - The server can rebuild delivery files from durable content after
replacement.
> - This establishes skills readiness for ephemeral web servers. General
server draining and workspace recovery remain separate work.

## Linked Issues or Issue Description

**Subsystem affected**

Skills services, shared contracts, database receipts, Skill Studio, and
runtime delivery.

**Problem or motivation**

A fresh web server must discover, read, edit, and deliver protected
installed skills using the same database, object storage, secrets, and
supported application artifacts. It must not need its predecessor's
files or process memory.

**Proposed solution**

Use `managed` ownership with a null source locator. Read installed
content by immutable version. Prepare packages before a short
publication transaction. Persist execution selections before
materialization. Recover exact pinned runtime assets and reject deletion
while active or recovering pins exist.

**Alternatives considered**

Reconstructing a mutable installed directory preserves the old
source-of-truth ambiguity. Permanent dual writes create two competing
authorities. This change uses one managed model after a bounded legacy
conversion.

**Roadmap alignment**

This improves the existing Skills Manager, Studio, version history, and
Cloud execution capabilities. The maintainer supplied the implementation
contract. This does not add a separate skills product or deploy fleet
changes.

Related work: #18082 supplies immutable package storage. #17273
addresses edits outside the API for linked local skills; this PR keeps
that source category separate. #2648 is a closed earlier
ephemeral-filesystem proposal.

## What Changed

- Add managed ownership and focused content publication and execution
materialization modules. Keep the archive format and package storage
tables.
- Publish managed create, save, delete, fork, rename, restore, and
catalog content with version checks. Add durable create receipts.
Preserve file-save receipt responses.
- Return file version identities. Keep Studio drafts after a conflict
and provide an explicit reload action. A delayed reload cannot overwrite
newer typing or navigation.
- Persist exact runtime selections, including empty selections. Rebuild
pinned assets and verify their admitted digests on a replacement server.
- Preserve source access on forks and disconnected copies. Keep the
existing workspace policy category for managed skills.
- Add bounded conversion, eligibility, and independent verification
phases. Load persisted Cloud configuration in the standalone CLI without
seeding or changing it. Reject partial current versions against
installed inventories; recover only complete saved content or the exact
source. Document storage migration blockers and the compatible rollback
floor.
- Add separate-process PostgreSQL/S3 qualification and update domain,
retention, policy, and UI regressions.
- Pass the plugin worker manager into Studio execution, admit restricted
`skill_test` mode through native Runner contracts, and preserve admitted
scope across native and REST tools. Native tests cannot create ordinary
tasks, browse company data, or use external tools.
- Select the exact durable Studio revision even when unassigned or Beta
skills is off. Persist Studio output and audit atomically with native
task completion, preserving the result on replay.

## Verification

- Final revision `13e8af480b88ba6fea5737bac4bd81104d604792` passed full
CI: all 49 workflow jobs completed successfully ([run
41127396098](https://github.com/paperclipai/paperclip/actions/runs/41127396098)).
This includes typecheck, test suites, Runner checks, browser checks and
build. Greptile review 15 is 5/5 on that same revision, with zero
unresolved threads. The PR is ready for review.
- Local workspace typecheck and build passed after integrating master.
Focused checks passed: 33 execution/completion cases, 52 Runner HTTP
cases, 16 managed-content cases, 17 Studio cases, the new real-process
CLI regression, map checks and UI token gates. The CLI regression proves
inspection does not seed missing Cloud configuration. Server typecheck
passed after that fix.
- The independent-process PostgreSQL/S3 matrix passed through normal
HTTP skill routes. It covers A → B → C replacement, lost commit
responses, upload crashes, concurrent saves, binary contents and
executable delivery. Metadata listing and warm selected delivery retain
zero object downloads. Local timing measurements are recorded; they do
not establish hosted latency.
- Hosted A → B → C passed on the owned disposable test tenant with
external Postgres, S3 and a real remote Paperclip Computer. Predecessor
temporary homes were absent. C read and executed B's acknowledged
managed save. New runs used repository v1 while v2 was installed. Hashes
matched an independently checked exact upstream commit.
- Compatible image rollback to `6518b323` passed. Studio retained the
unassigned fork's C save. A fresh remote run executed the newer managed
content and historical repository pin. The actual shell event confirmed
expected hashes, stdout, exit 0 and mode 0555.
- Runtime candidate `9200e3fcb4` deployed successfully ([Cloud run
41124147876](https://github.com/paperclipai/paperclip-cloud/actions/runs/41124147876)).
The final Studio test delivered only the unassigned fork's exact v3,
executed its script and persisted a successful output snapshot.
Independent command-event inspection confirmed all three hashes, stdout,
exit 0 and mode 0555. All 14 installations were version-backed.
Independent verification checked all 25 versions: 23 remote objects, two
bundled database snapshots, zero blockers.
- The deployed image is `9200e3fcb4`. Later master integration, the
client-only delayed-reload draft guard and the CLI bootstrap have
separate automated proof. The CLI bootstrap was also exercised against
the tenant's stored configuration and storage through the same read-only
services. This PR does not claim that the deployed image is the final PR
revision.
- Live Studio checks exposed worker wiring, admission, access scope,
exact selection and completion-publication gaps. They are fixed. Failed
attempts remain in the evidence. The full local suite exceeded 80
minutes under host contention and was stopped. Later combined/isolated
local attempts also timed out; they are not counted as passes. Full CI
covers the integrated suites. Earlier CI found an obsolete restart-scope
fixture, which was corrected and passed all 52 HTTP cases.
- Reproduction and migration:
[`doc/skill-ephemeral-web-servers.md`](doc/skill-ephemeral-web-servers.md).
Source revisions, deployments, versions, run IDs, hashes and failure
history:
[`doc/plans/2026-10-30-ephemeral-web-skills.md`](doc/plans/2026-10-30-ephemeral-web-skills.md).

## Risks

- Legacy conversion requires stopped admission and retired
filesystem-authoritative writers. Pre-conversion binaries are not
supported rollback targets afterward.
- Cloud readiness requires remote object storage. Local provider
receipts and provider mismatches remain blockers until objects are
copied and verified.
- Linked local sources retain filesystem semantics and are outside the
cloud guarantee.
- Cold reads still fetch the existing archive format. Warm runtime
preparation retains the verified-cache path.
- Bundled reconciliation preserves an installed head. Existing release
snapshots remain selectable. An older server must not replace a newer
head with its shipped files.
- No production volumes, fleet defaults, or general deployment
coordination change in this PR.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, code
execution, and browser use. The exact backend model ID and
context-window size are not exposed in this session. No subagents were
used.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-30 16:18:27 -05:00
DottaandPaperclip 5c807d11fa fix(github): prevent duplicate review score headings (#18321)
Clarify the shared GitHub review submission contract for new and existing bots.
Remove copied score headings while preserving the structured score and saved assessment.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-30 10:19:31 -05:00
Nicky Leach fba0ab8162 fix(runner): preserve GitHub helpers and Codex probe policy (#18212) 2026-10-30 07:42:10 -07:00
Nicky LeachandPaperclip 35ab90ad0f Map runtime activity to authorized task plugin panels (#18131)
## Thinking Path

> - Paperclip manages agents and tasks.
> - Plugins contribute views to the task sidebar.
> - A ready view can belong to an earlier task.
> - Runner records activity under its authenticated run.
> - This PR maps that activity to installed task-panel declarations.
> - The sidebar checks readiness after current-run use and restores use
after reconnect.

## Linked Issues or Issue Description

Builds on merged contract #18129 and Runner publisher #18050. This PR
targets
master and is ready for review. Earlier combined verification is
retained in
[the verification
archive](https://github.com/paperclipai/paperclip/pull/18050#issuecomment-6489369676).

**Subsystem affected**

Run-event reads, plugin task contributions and the task sidebar.

**Problem or motivation**

Readiness polling can show a view left ready by another task. Reload and
reconnect must recover current-run use without losing concurrent live
activity.

**Proposed solution**

Map recorded activity to installed task-panel declarations. Merge
authorized
history and live activity, then perform bounded readiness checks for the
running agent. Preserve the existing read-only view.

## What Changed

- Add optional `{ namespace, activityKey }` activation mappings to
task-panel
declarations. Legacy declarations remain valid but contribute no task
panel.
- Add `view=plugin-panels` to the existing run-events route. Preserve
run-read and
telemetry-read authorization, secret redaction and private-run denial.
Map
activity to installed contributions and return at most 128 panel
identities.
- Scope activation caches to current panel versions and activity
declarations.
Preserve unchanged panels during unrelated plugin updates and history
reads.
- Merge history and live hints without losing concurrent activations.
Filter by
  company, task, run and agent. Restore history on mount and reconnect.
- Replace periodic availability checks with up to three readiness
attempts after
activity. Fresh activity restarts settled transient failures. Pending
checks,
  successful readiness and HTTP 4xx failures are left alone.
- Reuse live run updates with the panel cache key. Recover only panel
history
after a pending subscription read. Mark expected not-ready query results
so
  the global error reporter skips them; real failures remain reportable.
- Preserve current-run dismissal and the read-only plugin view. Update
manifest
  comments and producer/consumer documentation.

## Verification

- Current head: `5e04d757c`, based on master `09c05c550`. Range
comparison
confirmed all six feature commits were unchanged by the rebase. The
final
follow-up keys readiness by the plugin installation ID and availability
path.
- `cd ui && node ../node_modules/vitest/vitest.mjs run
src/hooks/useTaskPluginPanels.test.tsx`
— all 45 cases passed. `cd ui && node ../node_modules/typescript/bin/tsc
-b` passed.
- The shared query-client and live-update recovery selection passed 96
cases on
  `49c544cd2`. Token gates passed before the final hook-only changes.
- Earlier focused verification passed 57 manifest cases, 69
database/history cases,
event-registry cases and route authorization cases, including
private-run denial.
- Regression coverage includes subscription/history races, task changes
during
recovery, unfocused run completion, bounded readiness retries, denied
reads,
expected not-ready responses, changed activity mappings, unchanged panel
preservation, old cache scopes, and same-version route or installation
changes.
- [Current-head
CI](https://github.com/paperclipai/paperclip/actions/runs/40942001707)
passed: 54 successful checks, two skips, no failures or pending checks.
- [Standard and final
review](https://github.com/paperclipai/paperclip/pull/18131#issuecomment-6489842168)
both scored 5/5 on `5e04d757c`. The final review used the Apex tier,
added no
comments, and left no unresolved findings. The PR is conflict-free and
ready for review.
- Local checks stay targeted. GitHub CI provides the broad build, test,
typecheck,
browser and Runner coverage. No deployment or live-provider acceptance
is claimed.

<details>
<summary>Retained failures and recovery evidence</summary>

- `ac9329548` twice failed a browser reload assertion while conversation
history
was concealed. Master fixed its readiness wait in #17923. The approve
journey
then passed locally on `fea63a418` with installed Chrome (1 passed, 39
seconds).
All eight browser shards passed in later CI. The browser test is outside
this diff.
- A canary checkout failed with Git HTTP 408; its unchanged-head retry
passed.
- `de07d09fa` failed the mobile Cases card click after a ten-second
stability wait.
The same read-only journey passed locally on that exact head (1 passed,
26 seconds).
Its unchanged-head CI retry passed 22 cases, with one skip. The original
artifact
  is retained; the cause of that click timeout is not established.
- [CI on
`49c544cd2`](https://github.com/paperclipai/paperclip/actions/runs/40903679075)
passed 54 checks with two skips. CI also passed on `de07d09fa` after the
recorded retry.
- The `1e59ab441` merge checkout passed all browser and server suites.
Runner
shard 2 passed 2,252 cases and timed out waiting for a
controller-recovery command.
The test had landed on master in #18161 after the former branch base.
Rebasing
aligned the local checkout with that code; Runner shard 2 then passed on
`fcf7380d3`.
The original timeout cause remains unproven; no unrelated timeout was
changed.
- [CI on
`fcf7380d3`](https://github.com/paperclipai/paperclip/actions/runs/40940235193)
recorded runner shutdown signals in typecheck and a workspace shard. A
chat
recovery test observed a null wake deadline, and one Runner transport
fixture
failed during close. Those separate assertion failures remain
unexplained.
All of those jobs passed on the final readiness-key head. Those later
passes
establish recovery; they do not prove the cause of the earlier assertion
failures.
- Local browser setup first stopped at pnpm version-download
verification, then a
sandbox IPC restriction, then a missing bundled browser. Installed pnpm
9.15.4
  and Chrome completed the journeys. No dependency files were changed.
- Earlier optional-property TypeScript errors were corrected. Embedded
PostgreSQL
needed its install hook run from its package directory. Older CI also
recorded
fixture-cleanup lock timeouts, attention-fixture timeouts, and canceled
server
shards after runner shutdown. The parent fixed its FIFO snapshot-copy
failure
before merge. The linked verification archive retains earlier combined
evidence.

</details>

## Risks

Activity is a hint and grants no access. Missing plugins, denied reads
and
unavailable views contribute no panel. Older runs without activity
records show
no task plugin tab. A used view stays available for the running task;
reconnect
reconciles readiness. Matching producer and consumer builds are
required. No
migration, dependency, image publication or deployment is included.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository tools and code
execution.
The exact serving snapshot is not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-29 13:56:48 -07:00
scotttongandPaperclip 71f0c0c99e feat: add opt-in Coordinator workspace for chat, tasks, and decisions (#17983)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/147/changes/paperclip/147
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - People coordinate work through conversations, tasks, and requests
for input.
> - These surfaces must share task state and preserve the context of
each decision.
> - The existing workspace makes people switch surfaces to follow that
context.
> - This pull request adds an optional Coordinator workspace with linked
conversations, tasks, documents, and decisions.
> - Each person can enable it in Settings > Experimental and return to
the classic workspace.
> - The benefit is a coherent path from a request to an assigned task
and reviewed work.

## Linked Issues or Issue Description

**Subsystem affected**
UI, server, shared contracts, and database.

**Problem or motivation**
People need a consistent way to start tasks from agent conversations,
answer questions, review work, and return to the source context.
Decisions and task state must agree across these surfaces.

**Proposed solution**
Add a personal, default-off workspace experiment. Keep one conversation
per agent. Add task proposals, compact task and decision cards,
contextual document panels, and a Needs You queue with search, filters,
sorting, grouping, and history.

**Alternatives considered**
Replacing the classic workspace for everyone would remove the opt-out
path. Keeping separate decision state in each surface would create
conflicting answers. This change uses the existing canonical task and
interaction records instead.

**Roadmap alignment**
This supports the existing agent chat, task management, and human review
capabilities. It is an experimental presentation choice. The user
requested this isolated implementation after design review. No Discord
discussion is claimed.

## What Changed

- Add per-person workspace preferences, a default-off setting, and an
additive migration.
- Add Coordinator navigation, pinned destinations, task lists, agent
switching, and contextual panels.
- Link task suggestions and creation to the source conversation. Default
new task ownership to the current agent unless the user specifies
another owner.
- Share pending questions, decision receipts, exact review targets, and
history across tasks, chat, and Needs You.
- Preserve task access, assignment authorization, revision binding, and
required output review gates.
- Add compact document links, relative timestamps, composer controls,
and reduced-motion support for task and decision transitions.
- Add component stories, regression coverage, and capability-map
documentation.

## Verification

- Final head: `4b839aae1e314bd7e8635a766f1d205ff1c03ba6`, based on
master `8bc051245f77a47bee0f8ba45896b8bfa5922e0a`. Verified October 29,
2026 at 00:10 UTC: **MERGEABLE, 56 checks passed, four conditional
skips, no pending or failed checks**. [Current CI
run](https://github.com/paperclipai/paperclip/actions/runs/40790639688)
passed without a rerun on this head.
- Fresh Greptile **5/5**, zero new comments and zero open review
threads; Superagent passed with no suspicious changes.
[Checks](https://github.com/paperclipai/paperclip/pull/17983/checks).
- Local workspace typecheck/build passed after the latest rebase. The
final account-read patch passed UI typecheck/build and all 12 related
preference/settings tests, including a delayed real-client request
across account changes. Earlier scoped checks cover review
deduplication/replay, decision deep links, cross-surface state, access
boundaries, and migration replay.
- Local database/browser rechecks after the latest rebase were limited
by exhausted macOS shared-memory IDs: `initdb` failed before database
creation. The local run passed 31 UI/snapshot tests and skipped 24
database tests; those skips and the blocked local browser start are not
claimed as passes. The independent Linux CI database and browser checks
passed. No running dev database or host setting was changed.
- Upstream migration 0403 is preserved. Preferences and durable review
retry aliases are generated as replay-safe migrations
`0404_tense_silver_sable.sql` and `0405_harsh_avengers.sql`; five newest
snapshots are retained. Every detected conflict was rebased and pushed
before waiting for CI/review, as requested.
- The PR is unmerged. The active master ruleset still requires
code-owner approval for the changed Paperclip skill; no approval or rule
change was performed.

<details>
<summary>Earlier verification failures, integration history, and
evidence</summary>

These entries preserve prior checkpoints and failures; the current
acceptance result is above.

- Focused UI and server checks from the isolated build are recorded in
the implementation plan.
- Browser checks covered the opt-in shell, navigation, task/document
links, and decision card states. No new live provider trial is claimed
for this handoff.
- Current acceptance head: `4b839aae1e314bd7e8635a766f1d205ff1c03ba6`,
rebased onto master `8bc051245` immediately after its GitHub
review-repair migration took 0403. Preferences are generated as
idempotent `0404_tense_silver_sable.sql`, preserving upstream
SQL/journal/snapshot history and five newest snapshots. GitHub reports
MERGEABLE after the immediate lease-protected push. Scott's updated
instruction is to rebase and push every conflict resolution first,
without waiting for CI or Greptile; verification follows the push.
- The final reviewed feature tree was consolidated for repeatable
single-commit rebases. The complete previous commit history remains
reachable through local recovery ref
`codex/coordinator-recovery-before-rebase-20261028` (resolved snapshot
`0e1bbdf4e`). The actual rebase completed, and its tree hash exactly
matches that resolved snapshot. The force-with-lease required the known
remote head `0e6ef7c44`, protecting against concurrent branch changes.
No PR merge or permission/runner setting change occurred. Fresh
CI/review are in progress for the current head.
- `2001132fa` received Greptile 5/5 with one nonblocking account-switch
read finding. Current head detaches path-coalesced preference GETs and
disables HTTP caching, retaining React Query's account-scoped sharing. A
delayed real-client GET regression proves account B can load its saved
choice before account A responds, and A's late response only updates A's
cache. Preference/settings tests 12/12 and UI typecheck passed; its
review thread is resolved. Fresh current-head CI/reviews are pending.
The prior CI chat shard 3 ended with “The operation was canceled” and no
assertion failure ([job
123171595631](https://github.com/paperclipai/paperclip/actions/runs/40789688333/job/123171595631),
`/tmp/pr17983-2001132-chat3.log`); no code/timeout change is attributed
to that cancellation.
- `843e823b4` reached fresh Greptile 5/5 with zero comments/open threads
and Superagent pass. All browser tests including the repaired YAML shard
passed, and 54 checks passed. General server shard 9 ended with “The
operation was canceled” and no failed assertion; its test step was
marked cancelled (job
[123164350893](https://github.com/paperclipai/paperclip/actions/runs/40787501761/job/123164350893),
log `/tmp/pr17983-843e-server9.log`). A single unchanged-head rerun was
started after the workflow completed, but master moved while it ran. A
local nested-clone check timed out in its 30-second database-startup
hook and then failed cleanup before the 20 database cases ran; this is
retained as a local verification limit
(`/tmp/pr17983-843e-nested-clone-check.log`), not claimed as a pass or
proof of the CI cancellation cause.
- Following Scott's instruction, the new conflict was rebased and pushed
immediately without waiting for that rerun. Upstream's
`0403_natural_cerise.sql` is preserved; regenerated preferences and
retry-alias migrations are `0404_tense_silver_sable.sql` and
`0405_harsh_avengers.sql`, replay-safe with five newest snapshots
retained. The YAML helper conflict combines upstream's click and header
behavior with the editor-selection guard and injected regression.
Recovery ref `codex/coordinator-recovery-843e823b4` preserves pre-rebase
work. Current head is MERGEABLE. Full workspace typecheck/build passed;
UI and snapshot checks passed 31 tests, but 24 database tests were
skipped by the local support probe, and the local browser server could
not initialize PostgreSQL. A direct disposable `initdb` diagnostic
established the host limitation: `could not create shared memory
segment: No space left on device` (`shmget`, shared-memory IDs
exhausted, not disk space). No dev database or host setting was changed.
Diagnostics: `/tmp/pr17983-2001132-initdb-probe.log`,
`/tmp/pr17983-2001132-db-probe.log`; checks:
`/tmp/pr17983-2001132-tests.log`, `/tmp/pr17983-2001132-browser.log`,
`/tmp/pr17983-2001132-types.log`, `/tmp/pr17983-2001132-build.log`.
These local skipped/blocked checks are not claimed as passes; fresh CI
on independent runners is in progress.
- `d18f683cd` reached fresh Greptile 5/5 with zero comments/open threads
and Superagent pass, but [E2E shard
7](https://github.com/paperclipai/paperclip/actions/runs/40785966243/job/123159719925)
failed parsing an Advanced YAML clipboard read beginning with “Skip to
Main Content.” The log is retained at `/tmp/pr17983-d18f-e2e7.log`.
Current head hardens the test helper to verify editor focus and
selection, clear stale clipboard content, and require the YAML header at
the start of a fresh copy before parsing. Saved-state assertions and
timeouts are unchanged. All six Advanced YAML browser journeys passed on
a disposable local instance (41.0s); the exact lost-response journey
also passed with a one-time injected surrounding-page copy, verifying
rejection/reacquisition (17.6s). The precise browser focus/clipboard
timing in CI remains unproven; the observed invalid-read path is now
guarded and deterministically exercised. Logs:
`/tmp/pr17983-yaml-clipboard-scope-browser.log`,
`/tmp/pr17983-yaml-clipboard-injected-browser.log`. Fresh current-head
CI and reviews are pending.
- `19e6dcb0b` passed Superagent and Greptile 5/5, with one nonblocking
deep-link finding. Current head preserves attention links using
`?decisionId=`: the requested pending decision is rendered even beyond
the first 40 cards, focused and scrolled into view, then only that
parameter is consumed so later refreshes do not refocus. Other URL
parameters remain. Needs You tests 10/10 and UI typecheck passed; its
review thread is resolved. The preceding post-rebase regression run
passed 45/45 tests. Fresh current-head CI/reviews are pending.
- `6d772b7cc` reached Greptile 5/5 with zero comments/open threads and
Superagent pass. While 32 checks had passed, master moved and caused a
documentation conflict in `maps/feature-map/onboarding.md`. Rebased
immediately, preserving both onboarding paragraphs. The complete
four-commit branch was pushed as `19e6dcb0b` before waiting on
CI/review, per Scott's instruction. A transient Git index lock
interrupted the first continue; the command sequence briefly pushed
intermediate `34e298c07`, then the completed rebase was immediately
pushed. All feature and security/retry fixes are present; local recovery
ref `codex/coordinator-recovery-6d772b7cc` preserves the pre-rebase
history. The only tree differences from that ref are upstream's two
smoke-test files and the combined documentation paragraph. GitHub
reports MERGEABLE. Fresh current-head verification is in progress;
prior-head review results are not current acceptance.
- `21efa3120` passed Superagent but Greptile scored 4/5 for a valid
retry-key persistence bug: an acknowledged duplicate key could reopen a
resolved review. Current head adds an additive, replay-safe
`0404_light_swarm.sql` migration for indexed, task-scoped aliases from
acknowledged retry keys to the canonical interaction. Alias registration
and retry lookup occur under the existing task lock; payload/actor
mismatch still conflicts, and each canonical review permits at most 100
aliases. Original and acknowledged keys replay the terminal result
rather than creating a new gate. Five newest migration snapshots are
retained. Service/routes tests 165/165 passed; final quality review plus
migration replay/snapshot checks 25/25 passed; server typecheck passed.
The P1 thread is resolved in code; fresh current-head reviews and CI are
pending.
- `69c2c7543` passed 55 checks and Greptile 5/5 with no open Greptile
findings, but Superagent check
[123140675812](https://github.com/paperclipai/paperclip/pull/17983/checks?check_run_id=123140675812)
correctly flagged unbounded pending quality-card creation. Current head
fixes that under the existing task-row lock: equivalent requests with
fresh idempotency keys reuse the pending card; conflicting requests for
an unresolved deliverable return the existing interaction ID; pending
cards are capped at ten per task across all reviewers. Distinct outputs
remain independent, and already-answered items in a partially pending
batch can receive a fresh review. Added real-database concurrency,
cross-card duplicate, partial-answer, and hard-cap regressions. Quality
review 22/22 tests and final server typecheck passed; earlier
service/routes 163/163 tests passed before the final partial-answer
refinement. One added assertion initially expected a service HTTP error,
but duplicate keys are rejected earlier by the existing shared schema;
the assertion now verifies that validation. Fresh current-head
CI/reviews are pending; the action-required security result is not
treated as passed.
- `c9c575e5f` completed all 56 checks successfully with four conditional
skips, Greptile 5/5, and Superagent pass. Its two P2 review findings are
fixed in the current head: independently bound quality approvals now
each remain visible in attention; changing/clearing URL-backed
assignee/status filters updates the URL and survives task navigation.
Both review threads are resolved. Regression evidence: attention service
34/34 tests passed, CoordinatorTasks 20/20 passed, UI and server
typechecks and the full workspace build passed on `69c2c7543`. The first
new UI test run caught an assertion racing React Router's transition;
waiting for the navigation before asserting passes without weakening the
navigation/remount checks. These older-head green checks are not claimed
for the new fix commit.
- Preceding `0e6ef7c44` completed all 56 checks successfully with four
conditional skips, fresh Greptile 5/5 and no open findings, and passed
Superagent. A fifth migration-metadata collision arrived before the
final Runner job finished. Those green results are preserved as
prior-head evidence, not current acceptance.
- Previous fully verified migration head:
`0e6ef7c44696a377f35e69521b93587576374bd0`, integrating master
`f8226b051` after the fourth migration-number collision. Master added
terminal GitHub-response migration 0401 while the final native check
ran; upstream 0401 SQL/journal/snapshot is preserved unchanged, and
preferences are generated as idempotent `0402_yielding_blink.sql` on
top. Exactly the five newest snapshots remain. GitHub reports MERGEABLE
after the push. All 1,155 relevant
migration/review/interaction/native-execution/remote-assets tests,
workspace typecheck/build, migration guards and whitespace checks pass.
Fresh exact-head CI/Greptile/Superagent are pending.
- Immediately preceding head `36c67cf03` completed all 56 checks
successfully with four conditional skips, fresh Greptile 5/5 and no open
findings, plus passed Superagent security. No retry was needed for that
head's CI. Master advanced and introduced only a migration-metadata
conflict while its final native check ran, so that green result does not
establish acceptance of the current integration. Four consecutive
collisions (0398, 0399, 0400, 0401) during verification are retained as
concrete integration churn; a brief pause of competing migration merges
was requested, without assuming it happened or changing any repo
setting. The PR has not been merged.
- Prior fully verified head: `36c67cf03`, on the clean `30059c0ed`
integration of master `efd65c112`. The last Greptile P2 is fixed: Needs
attention retains the participant-agent scope through authoritative
server membership queries for each pending task, including historical
participation when another agent currently owns the task. It does not
approximate participation with current assignment or enumerate every
company task. The actual view-switch regression and all 31 focused
task/routing/collection tests, UI typecheck/build, token gates and
whitespace checks pass. Greptile completed a fresh 5/5 review on this
exact head (review 19) with zero new comments and no open review
threads. CI and Superagent remain in progress; no current-head CI
failure has been reported.
- Head `30059c0ed` received Greptile 5/5 with that one nonblocking
participant finding, now fixed. Superagent passed that head.
Current-base integration restored the ephemeral RunsOn fleet after a
superseded workflow retained queued aggregate jobs: normal cancellation
was insufficient; the single force-cancel request was interrupted but
readback confirmed that obsolete run cancelled and current CI began on
the trusted fleet. No cancellation retry or runner/security/workflow
changes were made. Its partial CI was superseded by the necessary
participant fix and is not current acceptance.
- Previous compatibility/base-sync head:
`30059c0ededc0eab4e04e8299a884f36db8b292f`, integrating master
`efd65c112` and the Inbox/workspace compatibility fixes. GitHub reports
MERGEABLE after the push. Coordinator keeps Inbox standalone under More
without rewriting the instance's Combined Inbox preference; opting out
restores that preference. Saved merged-Inbox URLs resolve to their
original owner, task status presets remain usable, and canonical
repeated `workspace` parameters retain scoped, deduplicated pagination
(including Needs attention). All 192 broader
routing/Inbox/sidebar/privacy/review tests and the final 16 task-page
tests pass, as do workspace typecheck/build, token gates and whitespace
checks. The two review threads are resolved. Fresh exact-head CI,
Greptile and Superagent results are pending.
- The preceding `d5b9be5bd` remained mergeable but its CI routing gate
intentionally fell back to GitHub-hosted runners: “stacked base merge
commit does not contain the current base branch.” All 45 downstream jobs
stayed queued. Current master was merged cleanly to refresh the pinned
base; no runner/security settings or workflow logic were changed.
Greptile scored that preceding head 4/5 with the two compatibility
findings fixed here. Its automatic Superagent scan was inconclusive at
checkout; the documented retry was still pending when superseded. Those
results do not establish acceptance of this current head.
- Previous approval/migration head:
`d5b9be5bd3b8d6b0437e42bf48138377f34fa67d`, integrating master
`ba5bba86d` and the stale-output approval correction. GitHub reports
MERGEABLE after the push. The fresh P1 finding is fixed: every submitted
item now validates and locks its bound output inside the resolution
transaction, whether or not it carries a required-quality-review
binding. Real database regressions verify that an advanced document
revision or deleted attachment refuses the entire batch without
recording approvals, and current ordinary output reviews still resolve.
All 272 combined migration/review/interaction tests pass; workspace
typecheck/build passed. Fresh exact-head Greptile and CI are pending.
The automatic Superagent scan ended inconclusive at checkout; one
documented on-demand retry is pending. These are explicit verification
limits, not passed security results. The P1 thread is resolved.
- Master consumed the next migration slot three times during this
verification pass: confirmation recovery took 0398, continuation
recovery took 0399, and GitHub acknowledgement recovery took 0400. Each
upstream SQL/journal/snapshot is preserved unchanged. Preferences are
now generated as idempotent `0401_white_lenny_balinger.sql` from
upstream 0400; exactly five snapshots remain, and replay coverage
locates this migration by table content. This is recorded concurrent
integration churn, not a claim that older green results apply to the
latest base.
- Head `ed3b68da9` fixed the two history/URL findings with 26 focused
regression tests, server/UI typechecks, workspace build and token gates
passing. Greptile then scored that head 4/5 with the stale-output P1
corrected in the current head. Its partial CI is superseded, not counted
as current acceptance.
- Previous filter-fix head: `ed3b68da9`, based on the `8458d39d9` merge
of master `063cfd438`. The two fresh Greptile findings are fixed:
history outcome filters now match recorded per-item verdicts in SQL
before pagination (mixed reviews remain in both applicable outcomes),
and same-page URL assignee changes/back/forward navigation update that
filter without clearing independent filters. All 26 focused
database/navigation/collection tests, server/UI typechecks, workspace
build, token gates and whitespace checks pass. The two review threads
are resolved. Fresh exact-head CI, Greptile and Superagent results are
pending.
- The `8458d39d9` migration integration also passed all 328 targeted
migration/interaction/confirmation tests, workspace typecheck/build and
Superagent security scan. Greptile scored that head 4/5 with the two
functional gaps fixed in the current head; those prior-head checks are
not current acceptance.
- Migration integration head:
`8458d39d9721f4cb312c2390070a0609f8cddd1a`, integrating master
`063cfd43813cabf18417605fb9eefb9aacf95c8d`. GitHub reports MERGEABLE
after the push. Master advanced twice during this conflict-resolution
pass: first its confirmation-recovery migration took 0398, then its
continuation-recovery migration took 0399. Both upstream migrations and
journal entries remain unchanged; Coordinator preferences are now
generated as idempotent `0400_sad_guardian.sql` from upstream's latest
snapshot. Exactly the five newest snapshots remain. The replay
regression now locates the table migration by content instead of
hardcoding a renumbered filename.
- All 328 targeted question/review/confirmation/migration tests passed
again after the second merge. Workspace typecheck/build and fresh
exact-head CI/reviews are in progress. The preceding `0c46f46d6` passed
workspace typecheck/build and Superagent security scan, but was
superseded because master consumed migration 0399 while those checks
ran. That prior-head result is not acceptance of the current head. No
production settings or runner/security permissions were changed, and the
PR has not been merged.
- Previous integration head: `0c46f46d6f2b23417ab872ce3cb6ff2673647287`,
integrating master `287b04d72f1b9fca1412e05435c75b8302ba0710`. GitHub
reports MERGEABLE after the push. The renewed conflicts were
`0398_snapshot.json`, `_journal.json`, and the top imports in
`issue-thread-interactions.ts`. Upstream's `0398` confirmation-recovery
index and journal history are preserved unchanged; Coordinator
preferences were regenerated as idempotent `0399_bouncy_miek.sql`, with
replay coverage updated and exactly the five newest snapshots retained.
Both terminal confirmation notifications and Coordinator task
assignment/required review behavior are preserved.
- All 328 targeted interaction/review/confirmation/migration tests pass,
as do workspace typecheck, map validation and whitespace checks. The
workspace build and fresh exact-head CI/Greptile/Superagent checks are
pending. The first migration-generation attempt hit the sandbox's local
IPC restriction before generating files; the unchanged authorized local
generation completed successfully. Prior-head green checks below do not
establish acceptance of this merge.
- Previous acceptance head: `8b7dcf739ed15afc51351fdfa0e0e5fbc75ab788`,
with master `1aa3a21ac` integrated and GitHub reporting MERGEABLE.
Greptile completed a fresh 5/5 review on this exact head with zero new
actionable findings and no open review threads. The [fresh CI
workflow](https://github.com/paperclipai/paperclip/actions/runs/40752864319)
completed SUCCESS on attempt 2 at 19:40:08 UTC, including all eight E2E
shards. Final completed check set: 55 succeeded, four conditional checks
skipped, zero pending/queued/running checks, and one
neutral/inconclusive Superagent scan. The auxiliary commitperclip review
and isolated native Runner compilation/cache-reuse check both passed.
This is not a claim that Superagent produced a passed security verdict.
GitHub still reports MERGEABLE against current master
`60b8089a44b4eaa37e627adbfdf2f130bda13335`.
- Current-head E2E: all eight shards and the aggregate passed, including
the previously failing YAML browser journey. Serialized server shard 9/9
failed: the protected YAML projection test exceeded its original
15-second timeout; its late update request then reached the next test's
reset mock (the captured payload is the prior test's model/label
update). All 88 tests in that exact unchanged file passed locally in
38.03 seconds, with no timeout or assertion changes. The original
slow-request cause remains unproven. CI failure log:
`/tmp/pr17983-8b7-serialized9.log`; local recovery:
`/tmp/pr17983-adapter-yaml-repro.log`. The single bounded unchanged
shard rerun passed, and the workflow completed SUCCESS. Rerun log:
`/tmp/pr17983-8b7-serialized9-rerun.log`. The initial failure is
retained; a passing retry does not establish its original slow-request
cause.
- Greptile scored preceding head `4873704be` 5/5 with one valid P2:
opened task decision records missed company-scoped live invalidation.
The current head uses the existing company decision prefix for
resolution and effect-completion events, and resets private record
payloads on access changes. Its thread is resolved. All 107 focused
record/live-update tests, UI typecheck/build, token checks and
whitespace checks pass.
- CI on `4873704be` failed E2E shard 7/8 in the Advanced YAML
lost-creation-response journey: its clipboard helper selected page text
starting with “Skip to Main Content” instead of YAML. The exact
unchanged journey passed in a disposable local browser instance (1 test,
17.1 seconds). No assertion, timeout or production behavior was
weakened; the original failure cause remains unproven. Failure log:
`/tmp/pr17983-487-e2e7.log`; local check:
`/tmp/pr17983-agent-yaml-repro.log`. The full unchanged Advanced YAML
browser suite also passed locally (6 tests, 37.8 seconds). Fresh
current-head CI subsequently passed this journey and all other E2E
shards.
- Both the automatic and one supported on-demand Superagent scan on
`4873704be` ended neutral/inconclusive: “Pinned PR scan merge-base
checkout failed or timed out.” These do not count as a passed security
verdict. The current head's automatic scan and one documented on-demand
retry also returned the identical neutral checkout failure, with zero
annotations or further diagnostics. This is an external scanner blocker,
not a passed security verdict. No security settings or permissions were
changed.
- Recorded decision links now render and focus the full source-task
record in both Classic and Coordinator, including recorded choice,
submitted inputs, and the existing effect-result resolver. Fresh
terminal records take precedence over older open-decision cache entries.
Context and account checks keep mismatched or inaccessible records out
of the DOM; no decision-history tab was added to tasks or chat. The
shared company live-run feed now drives live-only filtering, including
ended runs and terminal tasks with stale run entries. All 213 focused
tests, UI typecheck/build, token and whitespace checks pass; the final
focus follow-up passed all 188 task-detail tests and UI typecheck. The
first new navigation test failed because its test host omitted company
context; the host was corrected before the passing run.
- Previous integration head: `375c5e89516705050d94bab99336212841b2e6e1`
merges master `1aa3a21ac` after four additional upstream commits. The
sole conflict was competing imports in `server/src/services/issues.ts`;
both quality-review policy and inbound wake-notice notifications are
preserved. The PR-specific review import now sits beside
execution-policy imports instead of the frequently changing first line.
GitHub mergeability is rechecked after the push.
- On the combined master tree, workspace typecheck/build, all 153
affected UI tests, map validation, and whitespace checks pass. Four
server suites passed 77 tests; the fifth suite's module-import hook
timed out while broad verification was running. Its unchanged isolated
run passed all 41 tests in 7.2 seconds with the original timeout. This
records recovery without claiming the original import-timeout cause is
proven. CI on `375c5e895` passed every substantive job, including all
eight E2E shards and Superagent; Greptile found the two functional gaps
fixed in the current head. A short-lived `669d90876` commit added the
main fixes before the focused navigation follow-up.
- Immediately preceding head `9d9737b49` completed all 56 checks
successfully with four conditional skips, Greptile 5/5 and no open
findings, plus a successful Superagent scan. The signoff E2E shard
passed on its single accepted rerun; its initial cancellation/timing
failure is retained below. Master moved again while those checks ran,
requiring this final integration rather than treating the prior head's
green result as current acceptance.
- Previous head `9d9737b496911a6054d0ea22d1b42b28b115e9ab` includes
master `d30c8f42b842327ee1c18c41a2efd6ba623da5cd`; that head was
subsequently conflicted by moving master. The master merge preserved
durable account-bound writes and Coordinator UX. Workspace
typecheck/build, 416 focused UI tests, and 142 affected comment-route
tests passed. A stable full UI run on preceding head `938ad1665` passed
all 9,833 tests across 836 files; its final full workspace build also
passed.
- Greptile found nested proposal project inheritance and Classic
bound-revision links on `91be74952`. Both were fixed with 142
interaction-route tests, 113 focused UI tests, and UI/server typechecks.
Its next review identified a valid draft-preservation bug in the new
Classic loading UI. Head `9d9737b49` keeps loading/error notices outside
editors and annotations while preserving dirty drafts; 115 focused
review UI tests pass, including pending/failed revision loads and
continued draft editing. All related threads are resolved. Greptile
completed a fresh 5/5 review of
`9d9737b496911a6054d0ea22d1b42b28b115e9ab` with no open findings.
- CI on `938ad1665` exposed an integration regression with the newly
merged durable startup saves: the personal preference gate blocked the
task page before its first session lookup. The guarded title editor now
mounts while that lookup is pending, with presentation-specific tools
still gated. All 216 affected component tests pass. The unchanged
five-test `disconnect-write-recovery.spec.ts` browser suite passes
against a newly launched disposable local-trusted PostgreSQL instance on
port 33219, including the exact failed startup-save journey. No live
provider, hosted authentication or production proof is claimed. The
helper-owned test server exited and the port has no listener. UI
typecheck, built-browser assets, token and whitespace checks pass.
- Initial durable-write merge tests found duplicate imports and unscoped
draft fixtures, fixed before 416 focused tests passed. A sandbox
typecheck could not create its IPC socket; the supported rerun passed.
The first revision-link test used a wrong Return to latest button
assertion, corrected before the 113-test pass. The startup E2E
reproduction initially still failed because an outer shell gate also
blocked the page; the subsequent fix passed all five cases without
changing the test or its timeouts. A focused loading-header assertion
initially used an incorrect fixture title; correcting it preceded the
216-test pass. These failures remain recorded.
- Earlier routing gates fell back to GitHub-hosted runners while master
was moving or conflicted. Superseded queued runs were cancelled, then
the `938ad1665` routing gate explicitly selected the ephemeral RunsOn
fleet. Its CI actively executed and completed most tests; only the
diagnosed startup E2E shard and aggregate failed, alongside the valid
Greptile finding. Auxiliary GitHub-hosted workflows also completed
successfully on earlier heads, so queueing alone is not an
administrative blocker. Fresh [CI on
`9d9737b49`](https://github.com/paperclipai/paperclip/actions/runs/40744012678)
is the acceptance target; the previously failing startup E2E shard now
passes. A different signoff E2E shard failed during executor
resubmission when its fixture run was cancelled as
`issue_continuation_waiting_on_review`. The exact unchanged journey
passed locally (1 test, 46 seconds), and the preceding head with
identical server/signoff code passed that CI shard. This supports a
bounded rerun but does not establish the timing failure's root cause.
After the workflow finished, GitHub accepted one rerun of that failed
shard and its dependent aggregate; both passed, completing all checks on
that head. The failure log is retained at `/tmp/pr17983-9d9737-e2e7.log`
and the local reproduction at `/tmp/pr17983-signoff-repro.log`. No
assertion or timeout was weakened.
- On the first merge, full workspace typecheck/build, all 9,622 UI
tests, 267 tests across seven affected server suites, two migration
checks, map validation, token gates, and the PR diff whitespace check
passed. Greptile then found duplicate local task-search filtering and
lost completed item-review detail. Both are fixed, with 42 passing
focused UI tests and passing UI typecheck/build.
- A subsequent Greptile review found attachment confirmations without
working links and mobile history without a visible host. Confirmation
layouts now derive the authenticated immutable-content endpoint from the
attachment ID, and Needs You uses the existing full-screen mobile sheet.
All 119 focused tests pass, including missing/stale display URLs, both
review layouts, and both mobile history entry buttons. UI
typecheck/build and token checks pass. Full workspace typecheck/build
also pass after the second master merge.
- Greptile gave head 22f69c304 a 5/5 score with one non-blocking
desktop-history reopening finding. Head 6dd52b6d3 fixed it, passed all
nine history tests, UI typecheck/build, token gates, and the full
9,679-test UI suite, then received a fresh 5/5 review with zero open
findings. These are prior-head results; review on the master-sync commit
is pending.
- The chat and workspace CI jobs on head 22f69c304 were interrupted by
runner shutdown signals and cancellation before completing their tests.
Their logs do not report failing assertions. Those interrupted jobs are
not claimed as passes. The new head starts fresh runs.
- The first merge CI had a Slack session-sync idle assertion fail after
an unexpected database read. Its exact isolated reproduction passes, and
the chat CI shard passed on head 618c5a2a3. The original failure's cause
remains undetermined. The broader local reproduction, run concurrently
with full verification, instead encountered 21 timeout failures across
its two test chunks; it is not claimed as a passing full local server
run. A concurrent local UI run had eight failures (seven timeouts and
one delayed autosave assertion). The complete UI run on the final head
passed all 9,679 tests across 830 files with two workers; no test
timeout or assertion was weakened. This establishes recovery without
claiming that every earlier timeout's cause has been proved. An earlier
intermediate UI run also overlapped the second master merge and failed
the newly added Advanced-sidebar expectation, so it is not treated as
stable-tree evidence. The newly merged UI dependencies initially
required refreshing the local install from the upstream package
manifest; the generated local lockfile update is not committed, per
repository policy.
- Superagent returned neutral/inconclusive scans on the preceding heads
because its pinned merge-base checkout failed or timed out. The
available retry endpoint returned 404. These are not successful security
verdicts. The fresh scan on `91be74952` passed (PR scan passed; no
suspicious PR changes detected). The `938ad1665` scan again returned
neutral/inconclusive with the same pinned merge-base checkout error; the
check-suite rerun endpoint returned 404. The fresh `9d9737b49` scan
completed successfully at 18:22 UTC with no suspicious changes detected.
Earlier neutral scans are not counted as successful security verdicts.
- Prior head `57902152ac3218096fca669d33ff18400a2a86ae` passed 9,618 UI
tests across 826 files, received Greptile 5/5 with no open findings, and
completed CI with 56 passes and four conditional skips. These are
historical results, not acceptance of the latest merge commit.
- The first full build found generated capability-contract drift. The
generated outputs were refreshed. Initial sandbox runs could not open
local IPC sockets; verification was rerun with local test access.
- Current master was merged. The workspace preference migration was
regenerated after the existing migration history.
- The UI run first found two outdated expectations: early custom-answer
validation and the document access error copy. Both were corrected, and
the full UI suite then passed.
- The local server run found three failures in unchanged tests. The Muse
test passes with Python 3.13 instead of the host's Python 3.9. The two
workspace tests pass when their test process uses the expected master
default branch. These environment settings do not change application
behavior or global machine settings. The unsharded server run was
stopped after those reproductions; CI supplies the full sharded server
result. No successful full local server run is claimed.
- Skill inventory generation needs an external eval checkout, which is
absent locally. The existing generator functions refreshed only the live
skill inventory and its derived files. The checked-in eval inventory was
preserved. The inventory validation gate passes.
- Greptile found a dropped MCP review requirement, missing per-item
output links, generic item-review summaries, and a history-refresh
failure. The fixes have 32 passing database-backed server tests and
focused rendered-card tests. A follow-up partial-review finding was
corrected by forwarding the canonical mutation status before settling
the card. Attachments open through the authenticated immutable-content
route in both card layouts. The final focused UI set has 117 passing
tests, including these regressions.
- Both browser shards that first failed expected a disabled-chat
message. The copy was restored, and those shards passed in CI on the
next commit. The two journeys also passed locally. One local attempt
first timed out before feature disable while waiting for the provider's
initial message; its isolated reproduction passed. That earlier timing
failure remains recorded and is not presented as an explained
infrastructure failure.
- Serialized server shard 9 first failed during pnpm setup with
ECONNRESET, before dependencies or tests ran. Its single rerun passed
setup and all tests. The build and production runtime boot passed on the
first attempt, but that run's public-install step timed out during Pi
setup. The single build-job rerun passed compilation, runtime boot, and
clean public-install verification. Those setup scripts are unchanged by
this PR. The successful retry establishes recovery; the earlier Pi
timeout's underlying cause remains undetermined. The aggregate CI gate
is green: [workflow
run](https://github.com/paperclipai/paperclip/actions/runs/40637789695).

</details>

## Risks

- This touches shared task, interaction, and completion paths.
Regression tests must cover classic and experimental behavior,
authorization, duplicate answers, and stale review targets.
- The additive preference table must migrate before the setting is used.
The setting defaults off.
- The experiment changes navigation and message presentation. Canonical
task and document records remain the source of truth.
- The initial task brief and saved plan can repeat information. This
change fixes chronology; a broader redundancy policy remains a design
decision.

## Model Used

OpenAI GPT-6 Codex with reasoning and tool-assisted code editing, tests,
and browser verification. Earlier iterations used Codex models in this
task; their exact model IDs are not available in the current context.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used
- [x] I have checked ROADMAP.md
- [x] I have searched GitHub for duplicate or related PRs
- [x] I have described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change
- [x] I have run relevant tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have documented risks
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open recommendations or follow-ups
- [x] I will address review comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 17:20:01 -07:00
Nicky LeachandPaperclip c57af3c564 Reuse prepared Runner storage and installed skill selections (#18089)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/207/changes/paperclip/207
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages AI agents and their work.
> - The native Runner prepares selected skills, instructions, and
provider storage.
> - Repeated preparation imports the company skill inventory and
rebuilds Claude storage.
> - Execution environments can already maintain prepared resources.
> - This pull request lets them reuse account storage while Core keeps
execution policy.
> - New retry runs resolve current skills and keep the failed attempt's
history.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Native Runner preparation and retry skill selection.

**Current behavior**

Explicit installed selections still trigger company inventory
reconciliation. Plugin preparation receives account identity only on
warm transitions. Claude's isolated mode requires a session-specific
configuration directory.

**Proposed behavior**

Skip inventory imports when explicit selections are installed, while
retaining current authorization and version resolution. Send account
identity on initial preparation. Allow an execution environment to
provide persistent Claude storage without enabling preconfigured
permission behavior. A new retry resolves current skill assignments.

**Reason and benefit**

Remove repeated preparation work without adding environment-specific
policy to Core. Related: #13984 describes a similar storage-lifetime
problem in the separate claude_local adapter; this PR does not change
that adapter.

## What Changed

- Derive Claude’s configuration path from the single authoritative
prepared-storage input; separately supplied CLAUDE_CONFIG_DIR values are
overridden.
- Add an explicit prepared Claude storage binding, forward it to the
sidecar, and retain recovery and provider lifetime fencing.
- Refresh Core-owned Claude settings after acquiring the lifetime lease.
Reuse environment-prepared skills.
- Reuse installed explicit skill selections and preserve
missing-selection initialization and current access checks.
- Reserve the prepared-home marker for environment provisioning; task
overrides are rejected and configured bindings are stripped before
native launch.
- Clear inherited skill selection snapshots on new retries. Keep
admitted execution recovery and failed attempt metadata.

## Verification

- Current single-input follow-up `8dbc2f6ec`: 154 focused Runner checks
pass with one existing skip; four Grok identity checks and four Pi
packaged-probe checks pass. Shared immutable source identities advance
to Grok10/Pi32/Copilot74. All56 current-head CI checks pass (four
intentionally skipped); standard and enhanced reviews are both5/5 with
no unresolved threads.
- Focused Runner sandbox tests: 29 passed. Focused environment tests: 16
passed.
- company-skills-empty-runtime: 10 passed.
- Plugin Runner and runtime selection database tests were attempted.
Local execution is blocked because embedded PostgreSQL cannot load
libzstd.1.dylib; these checks remain for CI.
- New database regressions cover installed-selection reuse, initial
account preparation, and retry snapshot removal.
- Prepared-home trust-boundary regressions: 4 targeted checks passed
(task schema, all env binding scopes, native executor).
- Focused Pi public-install probe checks: 4 passed. The build smoke
probe now asserts the current Pi 32 profile and exact digest.
- CI found and fixed retry-context TypeScript inference, stale Pi
identity fixtures, Docker source identity inputs, and the
skill-observability test’s old assumption that every selection imports
inventory. Cold and reused selection coverage remain.
- CI chat shard 2 initially failed three GitHub/Discord idle-database
assertions. An unchanged-head rerun passed; the original cause remains
unexplained.
- Runtime head `f5b53679a` passes all 56 current CI checks (four jobs
intentionally skipped), including the full build/public-install probe,
TypeScript, Rust, Runner and server matrices. Greptile is 5/5 with no
unresolved review threads.
- The requested enhanced review scored 5/5 on `f5b53679a`, with one
nonblocking documentation request. Documentation follow-up `1ac5d26a8`
adds only the documented existing ownership/0700 requirement; the thread
is resolved and all 56 current-head checks pass (four intentionally
skipped). The subsequent single-input runtime follow-up8dbc2f6ec
repeated the complete CI → standard5/5 → enhanced5/5 cycle successfully.
- Broader verification is delegated to GitHub CI as requested. The
initial policy check rejected a generated lockfile repair; that change
was removed because Core CI already resolves stale importer entries.

## Risks

Prepared storage must be provisioned by the execution environment before
launch. It is not credential isolation. Core replaces managed Claude
settings under the existing provider lease. No new per-run harness homes
are created by this option. New retries may select a newer skill
version; recovery of an already admitted provider execution keeps its
saved input.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning and tool use. The exact model
revision is not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
related context above
- [x] I have described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change
- [x] I have run focused local tests; database and full verification
remain for CI as explained above
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have considered and documented risks
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 17:09:24 -07:00
DottaandPaperclip b14e1ecaf8 feat: add a complete agent YAML configuration editor (#18036)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/175/changes/paperclip/175
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operators configure each agent through several settings tabs.
> - Operators also need one complete, editable configuration document.
> - The document must retain each resource service's access and
validation rules.
> - This pull request defines the `paperclip/v1` Agent YAML format and
adds an Advanced editor.
> - The editor previews changes, rejects stale core writes, and explains
partial saves.
> - Operators can edit agent settings in one place and verify the saved
state after reload.

## Linked Issues or Issue Description

Refs #2219. Related settings work: #10974.

**Problem or motivation**

Agent configuration spans profile, runtime, instructions, skills, tools,
channels, permissions, secrets, keys, and revision history. Operators
cannot inspect and edit those settings as one versioned YAML document.

**Proposed solution**

Add an Advanced agent tab with a YAML editor. Define a shared document
schema. Read and write resources through their existing APIs. Separate
editable settings, explicit commands, and read-only observed state.

**Alternatives considered**

A raw agent-row editor would omit related resources. A generic database
update would bypass resource ownership. The editor therefore uses the
existing resource contracts and records partial results when a later
request fails.

**Roadmap alignment**

This extends the shipped agent configuration capability. It relates to
easy AGENTS.md configuration, multi-harness teams, governed tool access,
and secrets management. Stored credentials remain redacted. This format
is an editable settings view; it does not add company portability or
provider consent.

## What Changed

- Add the `paperclip/v1` Agent document schema and format documentation.
- Add the Advanced route, sidebar entry, YAML editor, validation, change
summary, save progress, and reload recovery.
- Cover core settings, instruction files, skill pins, tool
installs/profiles/policies, channels, permissions, secret operations,
API keys, and revision restore.
- Add private-keyed configuration revisions checked under the agent
write lock. Read the current key through its owner so file-based
rotation does not require restarting the server. Preserve unchanged
secret markers at their original paths.
- Retain drafts and returned credentials after partial saves. Require
reload before retrying commands. Prevent duplicate submissions. Keep new
key tokens visible through rename and disable saves with an empty change
plan.
- Send only changed channel settings. Require explicit intent for shared
profile edits. Load destination instruction files when changing their
location.
- Update Storybook fixtures, verification maps, and regression tests.
Add browser acceptance through real APIs and PostgreSQL.

## Verification

- `pnpm -r typecheck` passes.
- `pnpm build` passes.
- The focused UI suite passes all 50 tests. The API/revision helper
suites pass all 93 tests.
- All 65 lifecycle tests pass with a dedicated PostgreSQL database. They
exercise real row locks, redaction, revision history, audit, and company
access.
- All six browser acceptance cases pass. They check saved settings and
clears, secret redaction, key creation/revocation, stale drafts,
lost-response recovery, instruction relocation, revision restore, and
key-token retention through rename. The tests use real resource APIs and
storage. The MCP target uses the existing local provider fixture. No
model run or provider login is claimed.
- Signing-key regressions cover both environment changes and real
in-place key-file rotation. The protected database save/fencing cases
pass after removing the cache. A local measurement of 1,000 file-backed
revision calculations took 48 ms.
- `pnpm check:token-gates`, `node scripts/check-maps.mjs`, and Storybook
catalog checks pass.
- The full [PR CI
run](https://github.com/paperclipai/paperclip/actions/runs/40725425470)
passes on `34ed97bbf9`: all 48 jobs, including all eight browser shards.
Greptile is 5/5 on this commit, with no unresolved review threads. This
final commit refreshes CI after a runner-routing fallback; its source
tree matches `fb4cf488cf`.
- Paperclip Review and Superagent Security Scan ended neutral because
their external agents did not complete a valid assessment/receipt.
Superagent passed on `fb4cf488cf`, which has the identical source tree.
One request to retry the final scan returned HTTP 404. Neither check
reports a code finding.
- The local full-suite attempt was blocked by host System V semaphore
exhaustion. Acceptance and lifecycle verification used an isolated
PostgreSQL 18 container. Earlier CI runners were interrupted. A local
combined run hit hook/test timeouts; the full 88-test route file passed
after the builds finished. The final full CI run passes. Earlier failure
logs and browser traces remain retained outside the repository.

To run the browser regression:

```sh
pnpm exec playwright test --config tests/e2e/playwright.config.ts tests/e2e/agent-configuration.spec.ts
```

## Risks

- Multi-resource saves are sequential. Earlier operations can remain
saved if a later operation fails. The editor reports the completed steps
and requires reload.
- Core settings and managed instruction files have atomic revision/hash
checks. Other unversioned resource writes and external supporting files
retain a race window after preflight.
- Shared profile definitions affect other bindings. The editor requires
`updateSharedDefinition: true` for those edits.
- The editor follows native service normalization and experimental
settings. Canonical reload can add generated access profiles or mask
environment values.
- New editor dependencies require the repository's normal automated
lockfile update. This pull request does not edit the lockfile or add a
database migration.

## Model Used

OpenAI Codex, GPT-6 family. The exact current model version was not
exposed. The work used reasoning, repository tools, code execution, and
browser automation. Earlier work in this chat used the configured Codex
model before a model switch; its exact model ID and context window were
not exposed. The current context window size is also not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 11:49:24 -05:00
DottaandPaperclip 13709b4c7a feat(connections): let agents configure connections within delegated authority (#17737)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Connections provide governed tools, chat channels, model accounts,
and gateways.
> - Several management routes require a human board actor even when an
agent has the required grant.
> - Default agents must configure these resources within the responsible
user's authority.
> - This pull request adds a shared authorization path to the existing
REST and native API surface.
> - Human authentication, execution approvals, and local host boundaries
remain enforced.
> - The benefit is that a standard agent can complete authorized setup
with a bounded human handoff.

## Linked Issues or Issue Description

**Subsystem affected**

Server authorization, connection services, shared contracts, native API
discovery, database schema.

**Problem or motivation**

Connection administration is available in the web app but often
unavailable to agents. Agent grants, responsible-user authority,
credential ownership, and actor attribution need separate checks.
Opening gateway-token creation also requires preserving the issuing
agent's delegated authority during token use.

**Proposed solution**

Use the existing authorization evaluator for every connection family.
Enforce current responsible-user authority, effective trust, grant
scope, resource visibility, and target-agent access. Keep existing agent
grants unchanged. Expose authorized configuration through default
`search_api` and `call_api`. Save human authentication steps and let
agents continue after completion.

**Roadmap alignment**

This change completes the API access path for the existing Connected
Apps, Personal & Shared AI Accounts, and governed MCP Gateway
capabilities in `ROADMAP.md`. It follows the maintainer's requested
design. Related work: #11899 enforces connection execution access and
creator/manager rules; this PR extends agent management across
connection families. It does not replace that execution-policy work.

## What Changed

- Add shared connection management context and mandatory
responsible-user, trust, scope, and target checks.
- Allow authorized agents to configure tool, chat/email, GitHub/Slack,
AI, profile, and gateway resources through existing routes.
- Preserve human credential ownership and record the actual agent,
responsible user, and run or key in audit data.
- Preserve saved browser authentication handoffs and callback session
checks.
- Bind agent-issued durable gateway tokens to their responsible user and
recheck delegated authority at use.
- Add explicit REST transport and management capability metadata,
built-in guidance, and sensitive-response handling.
- Intersect caller and endpoint-agent Slack test/invitation policies,
including independent and shared rates. Require the addressed human’s
current endpoint identity link before completing identity handoffs.
- Add production-authenticated integration scenarios. Companion #17739
contains the saved setup UI (including the required human
import/rotation step), product and permission documentation,
catalog/Vercel credential and callback ownership, and operation maps to
keep each review below 100 files. Both PRs must ship together; merge
this implementation first, then its companion.

## Verification

- Current implementation head:
`2ecd6451d0d0c8d82121a4e3fa4ce94c5befbbd6`, including master
`ea727dc3c2`, 99 files. The latest follow-up fixes the two valid
findings from the preceding f9 review. Exact-head Greptile has completed
at5/5 with no findings and Superagent passed. Full exact-head Linux CI
workflow40446606056 completed SUCCESS; only the queued external
Paperclip Review remains pending; earlier Linux passes do not qualify
this successor.
- Latest preserved-stack verification passed **2,165 tests** in fresh
PostgreSQL: **70 actual-auth scenarios**, 27 OpenAPI contracts, 2,022
native API tests and 46 saved GitHub wizard cases. **141 existing
gateway/policy acceptance tests** also passed. Workspace
typecheck/build, maps and token gates passed. The first workspace
typecheck was blocked by sandbox tsx IPC permissions; its authorized
rerun passed. This is focused local evidence; the full Linux CI matrix
is still required.
- Issuer/target gateway policy regressions were red before the fix. Both
decisions now intersect, including Block/Ask first/rates, same
credential identity and current token/user/agent authority after
approval. Invocations retain their token and actual requesting agent;
deleted tokens fail closed. Thirteen actual-auth cases cover revocation,
narrowed scope, approvals, shared rates and board compatibility.
Intermediate missing-token attribution, review-context and
implicit-session actor failures remain in the qualification record; all
final cases pass.
- Activity pagination now retains a bounded cursor across private-only
windows. The actual-JWT regression reaches three older readable events
after 27 private ones without exposing private details. A native
device-login regression was red for plaintext receipts; local check and
test-call results now use existing protected-response handling. The
passing actual-auth case proves encrypted persistence, exact replay,
redacted history and no response asset.

- Previous-head `5b55195593` Linux CI initially failed e2e shard 4/8 in
the existing connection-intent continuation test: periodic recovery
queued a repair at 01:21:47, the scripted journey completed the task at
01:21:48, and the extra queued run was cancelled at 01:21:49 because the
task was terminal. The assertion selected that latest cancelled run.
GitHub refused the first attempt while the workflow was nonterminal.
After completion, the single evidence-supported failed-job rerun was
accepted as **attempt 2** on the same head (workflow 40431202466). The
failed shard and final E2E aggregate passed on attempt 2, and the
complete Linux workflow for that head is successful. The original
failure remains part of qualification. No additional unchanged-code
rerun will be used for this failure.

- Companion CI also has an unchanged login-cleanup idleness timeout,
retained in its qualification record. That same 16-case suite passed in
this parent Linux run and a fresh local database. Both preceding
workflows passed after their single failed-job reruns as attempt 2; the
original failures remain recorded. No additional unchanged-code rerun
was used.

- Migration `0380_broken_aqueduct.sql` was regenerated through the
repository workflow after master took 0379 for project Git
authorization. It adds the responsible-user column with `IF NOT EXISTS`,
preserves upstream migrations, and satisfies snapshot retention and
migration safety checks.
- Upstream published Copilot v62 and v63 identities remain byte-for-byte
unchanged. The combined guidance is now v64, digest
`sha256:22e31f95ef972bcead98a4a707c9f33433558fd111e390e027a2bbb4346e112a`.
The normal shared TypeScript/Rust identity check and **61 Copilot
installation tests passed**. The old source-identity assertion first
failed against unchanged published v63; regenerating a new v64 preserves
the published release.
- Workspace `pnpm -r typecheck` and `pnpm build`, map validation, and UI
token gates passed on the final combined stack after the upstream merge.
Node 24.22.1 / pnpm 9.15.4 were used.
- **Earlier 82 API/OpenAPI tests passed** in fresh PostgreSQL 18: 55
assembled-server scenarios and 27 contracts. They use real persistent
agent keys, run JWTs, human sessions, production defaults, and
deterministic provider fixtures. No actor injection establishes access.
- The new email regression was red before per-account scope filtering.
The Arcade regression was red before human ownership and inventory-key
fixes; it also verifies actual-agent audit identity and a human-session
inventory read. The activity regression measured **200 authorization
checks before the fix and one afterward** for the same one-item page.
- **82 GitHub UI tests passed**, including all three new
failed-replacement regressions that were red before their fix. The UI
preserves an earlier copy only after confirming its committed
generation. Changed or unreadable results block copying and reconnecting
until reconciled. Human-only secret responses now include their
nonsecret committed generation.
- Private test status now rechecks the originating principal and linked
task, including mandatory agent/responsible-user privacy. Cross-agent
tests require the full caller tool access decision and the same
credential identity, regardless of auth label; caller and target
policies/approvals and rate limits apply before execution and after
human approval. A profile-only precondition was found to reject valid
allow-policy and scoped-grant access and has been removed. Both
permitted-access cases and a no-auth-label identity regression were red
before the correction; caller-specific Block still prevents provider
execution. The private-status regression was also red before its fix.
- The tool-activity regression measured 100 capability decisions and 102
run captures on a 100-event page before the fix. It now uses two task
decisions and at most two captures while retaining the same 50 visible
events, private-event filtering, and 403 after audit-grant revocation.
The regression was red before request-context reuse and task-decision
sharing; final server typecheck/build also pass.
- Generic chat configure/reconnect now hands agent-supplied verification
credentials to the addressed human before provider work or vault
changes. Actual key/JWT regressions were red for Slack signing-key
replacement and generic channel secret-reference rebinding. They now
prove unchanged refs and vaulted signing value, human setup, permitted
agent bot-token repair, and governed test messages. All 82 API/OpenAPI
cases pass in fresh PostgreSQL. Eight native receipt protections and
final server typecheck/build also pass.
- The preceding review found that old healthy state could retire a
credential-entry card before a human changed anything. The actual-JWT
regression was red. Saved field generations now change only with
protected values and commit with refs plus a verification fence; retries
retain the baseline. Old health, bot-token repair and unchanged entry
stay pending. New signing verification and current authority permit
continuation. A separate red race proved that user revocation during
provider authentication could return 403 after refs changed; authority
is now checked before persistence and inside the credential transaction.
The final 82 API/OpenAPI cases, four neighboring real-database
Slack/GitHub lifecycle cases, and final server typecheck/build pass.
- A preceding full run crossed a rate-window boundary. Database rows
prove one consumed slot at 23:35 and another at 23:36 for the same
policy/bucket. Only Date is frozen in the rate test cases; transport and
asynchronous timers remain real. Production rate behavior is unchanged,
and the final full run passes. An intermediate fixture failure that
overwrote hidden generation metadata with an API projection is retained
in the qualification record.
- Linux CI on an earlier head found two rate-admission assertions that
omitted the newly persisted bucket key. The failures were reproduced
locally; both assertions now verify the exact actor/tool bucket and all
49 policy-service tests pass. The companion qualification record retains
the initial and intermediate failures. Catalog creator attribution is
preserved in the companion to keep this implementation review at 99
files.
- The latest review reproduced three regressions before repair: complete
human replacements failed on unavailable old signing secrets, fresh
GitHub links incorrectly selected reconnect, and different
credential-entry requests shared an idempotency key. Each old protected
ref now has a narrow known-unavailable fallback; unexpected resolver
failures and company/scope violations still abort. Fresh imports keep
their credential form, configured endpoints keep reconnect, and
canonical field sets/completion modes distinguish handoffs while
matching retries retain their baseline. All 55 actual-auth scenarios and
27 separately run OpenAPI contracts pass, as do server typecheck/build.
Companion #17739 also passes all 41 wizard tests including actual
fresh-form submission, UI typecheck, maps and token gates. Earlier red
results and a mistyped OpenAPI filename are retained in qualification.
- The configured GitHub handoff regression was red in the
browser-component tests and actual-auth link/persistence tests. Saved
links now name requested fields and all/any completion mode; the
companion form submits those supplied fields through reconnect and
retains other saved credentials. Webhook/client-secret reconnect remains
human-only; first-setup secret restrictions remain. All 46 wizard tests
pass, including combined modes and legacy links. A duplicate review
referenced the older companion bf760912; the current form is already
fixed, linked in the reply, and its thread is resolved.
- Linux CI on bf760912 failed automatic Slack provisioning because vault
persistence cleared an already verified manifest-update challenge. The
same regression was reproduced locally. The provider-owned helper now
preserves proof only for the current signing fingerprint and callback
URL. Eight existing compatibility cases pass, including this case and
initial GitHub secret rejection. The first uncommitted GitHub-field
variant also failed that initial boundary and was narrowed to reconnect;
both failures remain in qualification.
- The upstream merge conflicted only in generated migration metadata.
Upstream 0379 is preserved, normal generation/pruning produced 0380, and
two repeated applications of the idempotent additive SQL passed. The
final combined stack passed **128 tests** (55 actual-auth, 27 OpenAPI
and 46 wizard cases) in fresh PostgreSQL. Eight Google UI cases also
pass; the two protocol cases could not initialize embedded PostgreSQL in
this fresh local attempt. Their earlier passing evidence remains
historical; fresh Linux CI must execute them. Vercel personal credential
attribution is preserved in companion #17739 with its other
ownership/consent follow-ups, keeping this PR at 99 files.
- The suite covers fresh defaults, restricted users/agents, scopes,
personal isolation, token revocation, human handoffs, callback replay,
execution approvals, authorized self-targeted policy changes,
self-approval denial, and current authority before commit. Reproduce API
checks with `pnpm exec vitest run
server/src/__tests__/connection-management.integration.test.ts
server/src/__tests__/openapi-routes.test.ts`, using a fresh database
through `PAPERCLIP_CONNECTION_MANAGEMENT_TEST_DATABASE_URL` or the
default embedded test database.
- Companion #17739 also records consent separately from token refresh so
saved Google choices survive refresh. Its eight service-picker and two
local-HTTP OAuth tests pass; both new UI cases were red before the fix.
Normal migration generation confirms no SQL change is needed for the
additive JSON metadata.
- The integration module shares one assembled server, authentication
factory, and provider lifecycle to preserve the
HTTP-to-vault-to-task-continuation proof. A reused external database
caused a Slack fixture identity conflict; the fresh final run passed.
Earlier fixture/transport and contract-update failures remain in the
companion qualification record.
- The broad local `pnpm test:run` attempt remains blocked by macOS
embedded PostgreSQL's host semaphore limit. It is not a clean pass. The
fresh Linux CI matrix must complete. Provider fixtures do not prove live
setup or an empirical LLM success rate.
- A current-head completed Paperclip assessment is not yet recorded. Its
earlier external recovery boundary has not been bypassed, and no
incomplete assessment is reported as passing. The user authorized both
merges when checks pass; merge this implementation first, then replay,
retarget, and requalify companion #17739 against the squash-merged
master.

- After the master refresh, local workspace typecheck/build, **97
actual-auth/OpenAPI cases** and **141 gateway/policy cases** pass. The
original fixed database port was occupied; Docker assigned a free
localhost port. The first neighbor setup command could not resolve root
`tsx`, leaving its schema uninitialized; the built database package
migrated the separate fixture and all unchanged cases passed. Both setup
failures are retained in qualification. Fresh Linux CI remains required;
no full local test-sweep pass is claimed.

- The f9 Greptile review scored **2/5** for two reproduced findings:
Slack test sends skipped the caller’s tool policy, and healthy App
credentials completed an unconfirmed identity handoff. Both are fixed in
this head and have resolved evidence threads
([Slack](https://github.com/paperclipai/paperclip/pull/17737#discussion_r4384927765),
[identity](https://github.com/paperclipai/paperclip/pull/17737#discussion_r4384927895)).
Actual key/JWT cases cover twelve Slack caller/target/recipient
combinations; the human-session GitHub OAuth callback alone remains
pending until explicit confirmation. All **99 API/OpenAPI tests** (72
actual-auth + 27 contracts), workspace typecheck and build pass. On the
combined companion, all four focused cases (including the twelve Slack
combinations), typecheck/build and maps also pass. The continuation
suite’s 50 embedded-PG cases were skipped because its database could not
start locally; fresh Linux CI must run them. Initial fixture
credential-collision and audit-projection assertion failures are
retained with the red reproductions in the companion qualification
record. No full local sweep or live consent is claimed.

## Risks

- The maintainer explicitly confirmed authorized policy administration,
including self-targeted changes that loosen controls. These writes
require management grants and the responsible user’s current authority.
Agents cannot approve their own governed action requests or edit their
own principal permission grants. The actual-auth regression exercises
both permitted administration and those denials.
- This is a broad authorization change. Incorrect scope or owner
resolution could deny permitted setup or expose another user's
resources. Integration cases cover both permitted and denied requests
with actual authentication.
- The additive nullable gateway-token column does not infer identities
for legacy clients or backfill agent grants. Legacy agent tokens without
a responsible user fail closed.
- Provider fixtures test supported setup and callback contracts. They do
not prove live provider availability.

## Model Used

- OpenAI Codex, GPT-6 family, with reasoning, repository tools, and code
execution. The runtime does not expose a more specific deployment ID or
context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass — focused suites above;
full local sweep remains blocked as documented
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green — exact `2ecd6451d0` Linux CI
completed SUCCESS; external Paperclip Review is still queued
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups —
exact `2ecd6451d0` review completed; both f9 findings have resolved
evidence replies
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 08:20:24 -05:00
Nicky LeachandPaperclip 835966dec8 Prepare agent-owned environments during hiring (#17761)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/1/changes/paperclip/1
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages agents and their execution environments.
> - New agent setup saves an inactive agent before model connection
tests.
> - Some plugins need that agent to prepare its execution resource.
> - The wizard tested without the agent ID, while the setup hold
prevented preparation.
> - Environment changes also discarded the selected model account.
> - This change prepares the saved draft during setup and keeps normal
execution held.
> - Users can test the prepared resource before they finish hiring.

## Linked Issues or Issue Description

**What happened?**

An agent-owned plugin environment could not acquire a test lease during
hiring. Changing environments also returned the user to Connect and
cleared the selected account.

**Expected behavior**

Keep the selected account, invalidate its test, and prepare the saved
agent resource in the background. Test that same agent before finishing
setup.

**Steps to reproduce**

1. Start a new Claude or Codex agent and select a saved account.
2. Change to an agent-owned plugin environment.
3. Try to finish setup or reconnect the account.

Related: #17750 defers probes until after hire submission. This change
implements preparation during the wizard instead. The related PR search
and ROADMAP review found no other implementation of this setup
preparation path.

## What Changed

- Add the optional `requiresAgent` driver declaration. Require agent
lifecycle participation when it is set.
- Prepare saved drafts on creation or environment changes. Keep the
setup hold and wait in `verifying` without background verification
scans.
- Bind tests to the saved agent. Return a warning without allocating a
lease when the required agent is absent or still preparing.
- Preserve the account and configuration step when the environment
changes. Save the selection and invalidate the old test.
- Show active preparation and support authorized retries. Keep approval,
company, budget, and normal task admission controls.
- Document the contract and cover lifecycle, lease, manifest, and wizard
behavior.

## Verification

- Server and UI TypeScript checks passed.
- 112 wizard and setup helper tests passed. The shared manifest suite
passed.
- 123 lifecycle, policy, lease, and environment-test API cases passed
after the approval-gate fix. The diagnostic and driver suites and all 80
agent adapter route tests also passed.
- Token gates, module boundaries, map validation, and whitespace checks
passed.
- All 66 lifecycle/policy cases passed after the stopping-draft
permission fix. The new real-DB route case verifies creator success,
other-creator denial, and refusal to complete a hire while stopping.
- Full workspace typecheck and build were attempted. Both stop at the
unchanged Rust Runner step because Cargo is not installed on this host.
- CI on 43be3c93d passed all automated checks, including full test
shards, typecheck, build, Rust checks, browser suites, and canary
checks:
https://github.com/paperclipai/paperclip/actions/runs/40368174530.
- The full local repository test command was started. Two unchanged
workspace tests assume Git's initial branch is master; this host
defaults to main. Both fail in isolation under the host default and pass
with process-scoped init.defaultBranch=master. The broad run was stopped
after those confirmed fixture failures; CI supplies the full clean
check.
- Early new-test failures were fixture collisions and an unscoped sweep
assertion; the fixtures and assertion were corrected. One route-suite
load raced with SDK output regeneration; rebuilding first and running
the suite afterward passed.
- Initial CI exposed a route mock missing the new prerequisite lookup.
The fixture was updated and a real HTTP no-lease case was added; all 54
cases in that route suite pass. Security review identified allocation
before required approval; the new approval gate and its tests address
it.
- CI on 50b5a08af reported 32 of 33 expected calls in the unchanged
cleanup-history scheduling test. Its isolated case passed locally
without cleanup-code changes; the original failure remains recorded and
the final CI run passes on the current head.
- Standard Greptile reviewed 43be3c93d at 5/5. A subsequent deeper
review identified runner selection, stale detail reads, error retention,
and test file size issues; 70343387b addresses all four with resolved
threads. Standard review returned 5/5 on that commit and again on
rebased head fda42c5ab. The rebase preserves master's new managed
environment skill declarations alongside requiresAgent. Full CI on
fda42c5ab passes: 55 successful checks, two intentional skips, no
failures. Run:
https://github.com/paperclipai/paperclip/actions/runs/40405121641.
- After those fixes, 133 UI tests and 61 lifecycle/policy cases pass;
all eight focused UI regressions fail against the previous
implementation and pass with the fix. Token, map, and whitespace gates
pass. The stale-read fixture initially omitted the setup URL because
navigation is mocked; following the URL activates the real detail query
and reproduces the race.
- UI TypeScript passes. This host's server dependency links now point to
a separate scratch checkout lacking requiresAgent, so the ordinary
server check reports that missing property. A no-emit check pinned to
this branch's shared declarations passes; it disables declaration
generation and supplies explicit local type roots. The first temporary
configuration lacked those type roots; the corrected configuration
passes. CI remains the full workspace verification.
- After rebasing onto 8373d7867, all 133 UI, 61 lifecycle/policy, and 44
manifest cases pass again, as do UI TypeScript, token, map, and
whitespace checks. The server no-emit check now hits three mismatched
SDK/Runner declarations from the scratch dependency links; these are
outside this change. Full CI builds the complete dependency set.
- Review cycle: the first Apex review scored 3/5 with four findings. All
were fixed together, the branch was rebased to resolve a schema
conflict, full CI and standard Greptile passed, and a second Apex review
returned 5/5 on fda42c5ab with zero new comments. All six review threads
are resolved, and the PR is conflict-free. Review:
https://github.com/paperclipai/paperclip/pull/17761#issuecomment-6422635718.
- No live provider resource was created and no deployment was performed.

## Risks

Plugins must opt in and ship a compatible declaration. Companies
requiring hire approval keep drafts paused and defer allocation and
verification until approval. Other companies prepare drafts during the
wizard under their existing agent-creation authority; the setup hold
still blocks ordinary work. Preparation uses existing lifecycle
ownership, retry, and cleanup paths. The open wizard polls only while
preparation or stopping is active. No database migration is required.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, tool use, and code
execution. The exact serving model ID and context window size are not
exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have described the issue in-PR using the bug report fields
- [x] I have not referenced internal or instance-local issues or links
- [x] My branch name describes the change and contains no internal
ticket id
- [x] I have run the targeted tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have considered and documented the risks
- [x] All Paperclip gates are green — 55 successful checks and two
intentional skips on fda42c5ab
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 15:21:47 -07:00
Nicky LeachandPaperclip c7c12dbc79 Support plugin panels in task sidebars (#17796)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task side panels keep live work beside the conversation.
> - Plugins can already provide agent detail tabs.
> - Those tabs have no generic way to appear beside the task that is
using the agent.
> - This pull request adds an optional task-side-panel declaration to
agent detail tabs.
> - The plugin owns the label, component and availability. Core supplies
the task's running agent.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Access to plugin-contributed live views from task chat.

**Subsystem affected**

Plugin manifest validation, slot discovery, and task side-panel
UI/state.

**Current behavior**

Agent detail-tab contributions appear on agent pages. A task cannot
offer the same view through a plugin-owned availability decision.

**Proposed behavior**

An agent detail tab can declare `taskSidePanel: { availabilityPath }`.
Core substitutes the running agent into the plugin-local path. A
declared board GET route scoped to that agent returns `{ available:
boolean }`. Available contributions appear in desktop and mobile task
side panels.

**Reason and benefit**

Keep the task and its live plugin views together. Preserve plugin
ownership of provider protocols and product behavior. Core contains no
concrete plugin identifiers, routes, labels or readiness rules.

**Breaking changes**

None. The field is optional. Existing contributions remain unchanged.
Missing, disabled or unavailable plugins add no panel.

**Additional context**

Related: #17111 established the agent detail-tab and scoped API
extension surfaces. Roadmap and related PR searches found no duplicate
of this extension.

## What Changed

- Extend the manifest with optional task-panel metadata. Validate safe
plugin-local paths and require a declared board GET route with
agent-scoped authorization.
- Discover and load only opted-in agent contributions. Poll their
generic availability responses and mount the existing components with
agent context.
- Add generic panel tabs, launcher entries, dismissal and inactive-view
removal in desktop/mobile task chat.
- Reuse the existing live-run polling guard so idle tasks with a healthy
live connection stop polling.
- Add provider-neutral fixtures, schema/authorization tests, task tests
and SDK/feature documentation.

## Verification

- PASS: 301 focused tests including the full task-detail file, generic
panel discovery, persistence, slot loading and manifest validation.
Regressions cover POST-before-GET route order, mobile drawer dismissal,
recovery without focus and the absence of the hidden desktop task panel
on mobile.
- PASS: UI and shared-package typechecks; production UI build; token
gates, feature-map and module-boundary checks; diff and secrets/PII
review.
- PASS on final head: all 795 UI files / 9,186 tests, and all 95
shared-package files / 1,038 tests. Commands: `node
node_modules/vitest/vitest.mjs run --project @paperclipai/ui
--maxWorkers 3` and the corresponding `--project @paperclipai/shared`
command with local socket access.
- On the final head, server shards 7/12 and 10/12 and workspace shard
a-1/2 were interrupted by runner shutdown/communication loss. GitHub
reported infrastructure failures; no assertion failure was surfaced in
the available diagnostics. The queued summary was cancelled, then `gh
run rerun --failed` successfully requested retries for only those three
jobs. They are currently queued for CI runners; the 50 successful checks
remain passing. Interrupted attempts are not counted as passing.
[Final-head CI and
retry](https://github.com/paperclipai/paperclip/actions/runs/40396870920).
- Earlier verification exposed an empty-panel rerender loop, which was
fixed. The sandboxed combined run also failed five shared port-registry
tests because it could not bind loopback listeners; the full shared
rerun with socket access passed. These earlier failures are retained
here rather than reported as passing runs.
- Full workspace typecheck/build were attempted with pinned pnpm 9 after
resolving the initial local package-manager setup. Both stop at the
unchanged Runner Rust step because `cargo` is not installed. Full local
workspace checks are not reported as passing; final CI must provide
those broader checks.
- No live provider or plugin-specific transport acceptance is claimed by
Core's synthetic fixtures.

## Risks

- Availability is polled every three seconds only while an authorized
running agent exists. Plugins own the side effects and meaning of that
read.
- A view uses the running agent's context. It is not a separate per-task
resource.
- Optional metadata adds no backend endpoint or permission bypass. The
host requires existing board and agent authorization.
- Reverting the optional contract and UI integration removes task panels
without a data migration.

## Model Used

OpenAI Codex (GPT-6), with reasoning, repository tools and code
execution. The exact backend snapshot ID and context window size are not
exposed by this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
ticket id
- [x] I have run focused tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 14:47:15 -07:00
Nicky LeachandPaperclip 4ff493fb40 feat(plugins): include managed skills for selected environments (#17774)
## Thinking Path

> - Paperclip manages agents and their execution environments.
> - Plugins can vendor company skills and provide environments.
> - Environment tools need their instructions before the provider
starts.
> - Persistent computers also need those skills before any run begins.
> - This change adds environment requirements to normal skill selection
and lifecycle synchronization.
> - Plugin names prevent ambiguity, and required skills take delivery
precedence without deleting company data.

## Linked Issues or Issue Description

**Problem or motivation**

An environment can provide desktop tools while its agent receives no
instructions for those tools. A first-run-only import also leaves idle
computers without required skills. Same-name company skills can make
provider discovery ambiguous.

**Proposed solution**

Let plugin environment drivers declare their managed `skillKeys`.
Install missing requirements during lifecycle reconciliation or new-run
preparation. Deliver updates through the durable runtime event journal.
Give managed imports stable plugin names and report shadowed
assignments.

**Alternatives considered**

ROM links do not make a skill a normal Paperclip selection. Polling
duplicates the existing lifecycle delivery queue. Replacing a same-name
company record would destroy independent data and assignments.

**Roadmap alignment**

This extends the shipped Plugin system and Skills Manager. The existing
related-PR search found no duplicate contract.

## What Changed

- Validate `environmentDrivers[].skillKeys` as unique references to the
same plugin's managed skills. Require a ready, enabled plugin with
`skills.managed` authority.
- Resolve company-scoped skills before version capture. Preserve
explicit pins, company edits, and saved recovery selections. Serialize
concurrent first installs.
- Allow lifecycle callers to request missing-skill installation through
`agents.getRuntime`. Ordinary task and recovery reads do not install new
declarations. Pass task-selected environment IDs through the SDK.
- Add SQL migration `0378_environment_skill_runtime_hooks`. Required
skill edits, effective default changes, environment changes, and plugin
requirement changes enqueue durable runtime events. Reuse lifecycle
delivery and retries; add no polling.
- Import managed defaults as `plugin-<short-plugin-id>-<skill-slug>`,
including the SKILL.md name. Preserve canonical keys. Keep same-name
company records separate without counter suffixes.
- Required environment skills win delivery over same-name company
assignments. Preserve saved assignments and library content. Record
shadowed and winning keys in run warnings, run snapshots, and plugin
runtime state. Removing the environment requirement restores the
ordinary assignment.
- Document the contract for `driver: "plugin"`. Other drivers and
plugins without requirements keep existing behavior. Existing managed
copies retain edits and names until reset.

## Verification

- Latest targeted local checks: environment skills (5), managed skills
(9), heartbeat execution configuration (27), and SDK worker RPC host
(23): **65 tests passed** (including the targeted schema-drift check).
Disposable PostgreSQL exercised the migration, first install before any
run, concurrent lifecycle reads, implicit edit events, inherited
defaults, rollback, plugin requirement changes, shadowing, preserved
records, version capture, and recovery.
- Review follow-up also verifies case-insensitive/runtime-name aliases,
recovery of a task-mentioned shadowed skill, preserved quoted/multiline
YAML, and zero runtime events for repeated local-folder settings writes.
- Migration numbering and safety checks passed. Whitespace and
secret/PII scans passed.
- Earlier targeted manifest validation passed (43 tests). No validator
behavior changed in this follow-up.
- Broad tests, typecheck, build and end-to-end verification passed in
[GitHub
CI](https://github.com/paperclipai/paperclip/actions/runs/40387647219)
for current head `ce57f2a4d`. Greptile is 5/5 with no unresolved
threads. The [commitperclip review
check](https://github.com/paperclipai/paperclip/actions/runs/40387646208)
also passed after restoring its required duplicate-search checkbox.
- Earlier attempts found a SQL alias collision, an unparenthesized CASE
expression, and fixture assumptions about bundled catalog rows and YAML
quoting. These were corrected before the passing checks. The first broad
CI run also exposed a schema-drift check that assumed every journal
entry had a schema snapshot; it now reads the latest actual snapshot, so
SQL-only migrations need no invented snapshot. A test callback
replacement also affected an unrelated fixture; it was restored before
the final passing execution-configuration suite. Sandbox runs could not
start PostgreSQL; the reported database tests used local socket access.

## Risks

- Apply migration 0378 before using the updated lifecycle contract. It
adds trigger functions and event producers; it does not rewrite agent
assignments or skill content.
- Required environment skills take precedence over same-name
assignments, including task-selected skills. Both library records
remain. Run warnings identify omissions.
- Company edits are preserved. Plugin upgrades do not reset installed
content or rename existing copies. Explicit reset adopts current
defaults.
- Namespaced library slugs can be shared by distinct canonical records.
Callers must use IDs or canonical keys when a slug is ambiguous.
- No live provider request or deployment was performed. The downstream
plugin must be built against this Core revision. Persistent-home
synchronization retains its existing edit-conflict and retry behavior.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, and code
execution. The exact model identifier and context-window size are not
exposed in this task context.

## Checklist

- [x] Thinking path and issue description included
- [x] Model and available capabilities recorded
- [x] Roadmap and related PRs checked
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] Public references only; no internal issue IDs or instance URLs
- [x] Targeted local tests pass; broad verification delegated to GitHub
CI
- [x] New behavior covered and documentation updated
- [x] Current-head CI green and Greptile 5/5 with no unresolved comments

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 14:11:35 -07:00
DottaandPaperclip d0c8f0b090 fix: explain project access denials and add an authorized repair path (#17509)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Low-trust agents may read only the projects in their allowed scope.
> - Workspace setup correctly stops a task outside that scope.
> - The task previously showed a generic failure, and agent settings did
not offer an additive repair.
> - This pull request explains the denial and lets authorized operators
add projects while preserving other restrictions.
> - The saved task then offers an explicit retry. Saving access does not
start work.

## Linked Issues or Issue Description

**What happened?**
A project access denial appeared as an ordinary failed attempt.
Operators could not add a second allowed project from agent settings.

**Expected behavior**
The task should explain the denied access and link to a working
permission editor. The editor should preserve existing scope and
restrictions, enforce operator authority, and retain drafts after a
failed save.

**Steps to reproduce**
1. Assign a low-trust agent to a task whose project is outside its
allowed projects.
2. Let workspace setup deny project access.
3. Open the task, follow Manage project access, add the project, save,
reload, and return to the task.
4. Confirm that the saved message remains and Retry task is a separate
action.

## What Changed

- Record a typed, non-retryable project denial before provider dispatch.
Project denials do not enter automatic continuation or provider comment
policy.
- Project current and historical setup denials into a safe task notice.
Keep unrelated failures, prior assignees, and approval/pause/budget
gates separate. Recheck current project authority, including standard
trust and root-issue grants. Accepted retries keep their working state.
- Add board-only project-access reads and additive saves under the agent
row lock. Enforce company scope, agent-management authority,
pending-approval restrictions, and an audit record for new additions.
- Add the production notice and searchable multi-project editor,
including read-only, saving, cancellation, and failed-save states.
Preserve the return-to-task query through canonical agent redirects.
- Register board-only project-access routes in OpenAPI with a strict
request schema.
- Add production Storybook examples and API/persistence/concurrency
regressions. Retain the approved design snapshot and update the behavior
maps and implementation contract.

## Verification

- Passed: `pnpm -r typecheck`, `pnpm build`, `pnpm build-storybook`,
`pnpm check:token-gates`, `node scripts/check-maps.mjs`, and `node
scripts/storybook-catalog.mjs`.
- Passed: 11 permission/projection tests and 30 run-completion tests
against an isolated PostgreSQL database. These cover historical
failures, concurrent additions, idempotent audit, preserved
restrictions, foreign projects, read-only users, agent self-grants, and
no automatic wakeup.
- Passed: all 27 OpenAPI route tests, including route coverage and the
new board-only request/response contract.
- Browser: the real app displayed a historical denial; Manage project
access opened the editor; saving retained the original project and
survived reload; Return to task showed the ready notice. Saving created
one audit event and zero runs. Explicit Retry returned 202 and reached
the separate sandbox requirement, which remained enforced. No external
provider was used.
- All five production Storybook interaction checks pass: blocked task,
save, cancellation, failed-save recovery, and read-only settings. These
use fixture callbacks; durable authorization is covered separately
above.
- `pnpm test:run` was attempted locally but stopped after repeated
embedded PostgreSQL startup failures caused by macOS semaphore
exhaustion. Full-suite CI is required before merge. The separate UI
suite passed all 9,095 tests. The 41 focused server regressions also
passed after rebasing onto the latest master. A further 26
recovery-classification tests pass, including a red-to-green regression
for automatic continuation after a project denial.

## Risks

- No schema migration. The new endpoint only adds same-company project
IDs and preserves the rest of the stored policy.
- The historical notice recognizes one exact setup denial message. It
does not display arbitrary run errors or disclose a different source
project's identity.
- The retry still passes all current admission and isolation checks. The
notice does not promise that other execution requirements are satisfied.
- Related open work: #13309 covers inherited secret restrictions; #11234
covers the broader repository catalog. This change does not replace
either policy surface.

## Model Used

OpenAI Codex (GPT-6), with code execution and browser tools. The precise
runtime model ID and context-window size were not exposed in this
session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` OR (b) described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (focused server and full UI
suites; full-suite infrastructure limit above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-24 16:16:29 -07:00
DottaandPaperclip 0eb2c964a7 fix(agents): allow runner qualification with agent configuration permission (#17448)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent owners configure the harness and computer used for that work.
> - A legacy runner upgrade must first qualify an unverified sandbox.
> - The upgrade called an instance-admin probe, so a company owner with
agent configuration permission received HTTP 403.
> - This pull request qualifies the saved computer through the agent's
existing configuration authorization.
> - Company owners can complete the upgrade while general instance
environment management stays restricted.

## Linked Issues or Issue Description

Refs #17361. Related: #17122.

**What happened?**

Upgrade runner displayed for an existing Claude agent on a Daytona
Paperclip Computer. Clicking it returned “Instance admin access
required” for a cloud company owner. The agent remained on the legacy
runner.

**Expected behavior**

A caller permitted to update the agent can qualify that agent's saved
computer and upgrade. Instance-admin access is not required for this
agent-scoped operation.

**Steps to reproduce**

1. Sign in as a cloud company owner with `agents:configure` and no
instance-admin role.
2. Open an existing legacy Claude agent on an unqualified Daytona
snapshot.
3. Select Upgrade runner.

## What Changed

- Add `POST /api/agents/{id}/qualify-runner` with the existing
`agent_config:update` guard.
- Reuse the server's effective environment resolver. The submitted
environment ID only detects stale state; it cannot select a different
computer.
- Preserve company binding checks, check binding again at lease
acquisition, and record agent-scoped audit activity.
- Return qualification status and the lease receipt without
instance-level provider metadata or raw provider errors.
- Use the new endpoint for the existing-agent upgrade. Keep the generic
environment probe restricted to instance admins.
- Disable Upgrade runner when an unsaved computer change resolves to a
different target, with a save-first explanation. Other draft settings
still accompany an upgrade.
- Add real-database authorization regression tests and update the API
contract and access maps.

## Verification

- Red: the existing UI called the instance-wide probe and failed the new
agent-scoped call assertions in eight upgrade cases.
- Green: 349 related route, provider qualification, runner selection,
and UI tests passed.
- Green: 12 authorization cases passed with real PostgreSQL, real HTTP
routes, real saved role grants, and a simulated provider boot. They
cover the cloud owner, removed grants, foreign agent/computer, inherited
targets, stale target, invalid body, archived/local target, redacted
failure, audit scope, and unchanged agent settings.
- Review regression: two cases first reproduced the enabled upgrade
button after an unsaved computer change; both now pass, along with all
168 related UI tests. Qualified/unqualified computers and restoring the
saved selection are covered.
- All 26 OpenAPI cases passed; the 12 real-database authorization cases
also passed after rebase.
- The host exhausted PostgreSQL semaphores. For the 12 cases, a
temporary local-only setup used disposable PostgreSQL 18 in Docker
instead of the embedded database launcher. The committed tests use the
normal embedded database helper. No authorization decisions were mocked.
- `pnpm -r typecheck`, `pnpm build`, `pnpm check:token-gates`, map
validation, module-boundary validation, and `git diff --check` passed.
- `pnpm test:run` was attempted but did not establish a full local pass:
the host could not start embedded PostgreSQL clusters. All current-head
CI gates passed, including the full suite in CI. The commitperclip
review workflow timed out before reporting any executed steps on its
first attempt and passed on one retry.
- Fresh staging acceptance remains pending deployment. Verify persisted
native configuration and a successful runtime test on the existing
Daytona computer after merge. Earlier live Daytona proof from #17361 is
separate evidence.

## Risks

- Qualification can start a fresh, temporary sandbox. It uses the
existing probe lifecycle and cleanup contract.
- The new path must remain scoped to the saved agent and its company.
Denial and redaction tests cover that boundary. General instance probe
authorization is unchanged.
- No migration, role change, credential change, or automatic agent
upgrade is included.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, code execution, and
browser tools. The exact deployed model variant and context-window size
were not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-24 10:31:40 -07:00
Nicky Leach aa0037a137 Support Codex warm plugin task reuse and recovery (#17390) 2026-10-23 19:14:14 -07:00
Nicky LeachandPaperclip a708a13336 Separate plugin workspace completion from maintenance inspection (#17329)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Storage plugins own remote task workspaces.
> - Run completion currently requests the same inspection used for
storage cleanup.
> - That inspection can fetch remote refs and scan files after the agent
has finished.
> - Completion needs retained workspace identity and durable writes, not
permission to delete files.
> - This change adds an optional completion operation and keeps
maintenance inspection separate.

## Linked Issues or Issue Description

**What happened?**

A successful plugin-backed run can fail during completion because the
storage provider performs a slow remote-recoverability inspection. Dirty
or unpublished output does not need a deletion-safety proof to remain
valid task output.

**Expected behavior**

Completion verifies the assigned workspace and confirms durable writes
through the provider. Cleanup still requires the existing full
inspection.

**Steps to reproduce**

Run a task with plugin-owned storage whose inspection fetches remote
refs. Let the agent finish, then observe completion waiting for the
maintenance inspection.

Related context: #16428 added finalization observability. The duplicate
search found no existing PR for this provider contract.

## What Changed

- Add optional `workspaceProvider.finalizationVersion: 1` and strict
`finalize` / `finalized` schemas.
- Pass original run and agent context through live completion and
recovered completion.
- Give the new operation a 30-second deadline and keep ownership checks
and lifecycle serialization.
- Retain the inspection fallback for providers without the capability.
Keep maintenance inspection and removal unchanged.

## Verification

- SDK build passed.
- Targeted SDK and completion unit tests: 7 passed.
- Added integration coverage for capability selection, legacy fallback,
maintenance separation, and failure propagation.
- Local integration setup timed out starting PostgreSQL; the integration
suite passed in GitHub CI.
- Full build/typecheck and broader tests passed in GitHub CI (55
successful checks, 2 skipped). Local checks remained targeted as
requested.
- Diff reviewed for secrets and operational identifiers.

## Risks

The capability is opt-in. Providers must not advertise it until their
completion implementation is available. An unavailable provider or
failed durability barrier remains retryable. No schema or stored-binding
migration is required.

Test-file size exception: the provider integration suite grows from 973
to 1,002 lines. The 29-line case follows the same prepared binding
through legacy completion, opted-in completion, and maintenance
inspection using the existing single-connection database fixture.
Keeping it there avoids a second embedded-Postgres lifecycle for one
transition test. The completion helper unit tests are in a separate
focused file.

## Model Used

OpenAI GPT-6 Codex, with reasoning and code/test tools.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-23 09:07:35 -07:00
Nicky LeachandPaperclip 989ee668e0 Support provider-owned fresh retry workspaces (#17252)
## Thinking Path

> - Paperclip coordinates AI agents and retains their work across
failures.
> - A retry can require a new workspace while preserving the failed
attempt.
> - Core rejects this recovery strategy for provider-owned storage.
> - Providers should implement the required outcome using their own
storage design.
> - This pull request adds a semantic fresh-preparation contract and
delegates recovery preparation.
> - The benefit is that a supported provider can run a fresh retry
without losing prior work.

## Linked Issues or Issue Description

**What happened?**
A retry that selects `fresh_isolated_workspace` fails with
`fresh_workspace_storage_unsupported` for provider-owned storage.

**Expected behavior**
Core asks a capable provider to prepare new storage and attach verified
recovery files. The failed workspace remains intact.

**Steps to reproduce**
Run a task in a task-capable plugin environment. Let the task fail
without a verified workspace preservation receipt. Retry the task so
Core selects a fresh attempt.

**Paperclip version or commit**
6204239cf (rebased on current master).

**Deployment mode**
Self-hosted server with a plugin task environment and managed workspace
provider.

Search found no duplicate implementation. This branch includes the
default-provider changes from #17247 and preserves their source
selection behavior.

## What Changed

- Define an opt-in fresh-preparation contract with a stable attempt
identity and verified recovery file descriptors.
- Describe retained-storage and recovery-attachment guarantees without
requiring a Git storage layout.
- Reserve replacement task bindings with revision checks and keep the
failed workspace intact. Projectless and project-backed task
environments both replay their stable attempt reservation.
- Reconcile an interrupted preparation against its reserved workspace
and stable operation identity.
- Stage verified recovery archives at stable transfer paths. Delegate
attachment materialization to the provider.
- Preserve projectless attempt directory identities through later turns
and pin the intent into each execution lease.
- Protect fresh intent and projectless ownership from caller metadata
replacement or injection.

## Verification

- SDK workspace-provider tests: 4 passed.
- Targeted reservation and task-dispatch tests: 31 passed.
- Recovery transfer staging and lifecycle focus: 7 passed. The separate
cache-cleanup failure reconciliation case also passed.
- After rebasing on current master, 7 focused preparation and ownership
cases passed. These cover inherited provider defaults, fresh
preparation, stable projectless identity, and authorization denial.
- The focused metadata authority regression passed, including forged
intent, replacement, and null metadata patches.
- Three assembled interrupted task-reservation cases passed:
projectless, project with a saved source, and project with a newly
selected default source.
- Targeted tests use worktree SDK sources. No full local build or
typecheck ran.
- Local checks remain targeted as requested. Latest-head GitHub CI
passed: 54 successful checks, including typecheck, build, server suites,
Runner validation, and E2E shards; 2 unrelated Storybook checks were
skipped.
- Greptile reviewed commit 73595b0c61 at
5/5 with zero unresolved threads.
- Live VM E2E has not run.

## Risks

- Existing providers retain their existing behavior. Fresh attempts
require explicit version support.
- The companion provider implementation must materialize recovery
snapshots safely and preserve the old workspace.
- Fresh retries require the companion provider implementation. Providers
without the version marker fail closed.

## Model Used

- OpenAI GPT-6.1 (`gpt-6.1-sol`), reasoning and coding tools. The
runtime does not expose the context-window limit.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-22 17:46:27 -07:00
Nicky LeachandPaperclip 6204239cfc Support installed default project workspace providers (#17247)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Storage plugins already own project storage and task checkout
preparation.
> - Core only selected these plugins through an explicit project policy.
> - Installation could therefore leave new and existing projects on
incompatible Core preparation.
> - This pull request adds one generic manifest declaration and one
shared effective-policy resolver.
> - Project configuration shows inheritance while durable workspace
bindings retain their owners.

## Linked Issues or Issue Description

**Subsystem affected**

Plugin contracts, project configuration, and execution workspace
preparation.

**Problem or motivation**

An installed storage provider cannot become the company default.
Projects without an explicit provider keep Core preparation, even when
their execution environment cannot use a Core Git checkout.

**Proposed solution**

A provider declares supported `workspaceProvider.defaultForProjects`
mode and strategy. Company-enabled installations supply inherited
defaults. Explicit plugin selections and explicit Core/local
(`storageProviderPluginId: null`) win. Conflicting defaults require an
operator choice. The declaration and implementation contain no
provider-specific identifiers.

**Alternatives considered**

Rewriting every project would lose the distinction between inheritance
and overrides. Selecting by worker health would silently change storage
on an outage.

**Roadmap alignment**

Extends the existing workspace and sandbox provider contracts. The
roadmap has no duplicate default-provider implementation. Related public
work includes #17243, which covers prepared execution directories rather
than provider selection.

## What Changed

- Add a validated generic default-provider declaration and document it
in the SDK.
- Resolve provider selection and Git defaults consistently in project
responses, source selection, heartbeat source resolution, reservation,
and preparation.
- Keep stored policy separate from effective configuration. Add the
normal project configuration selector for inheritance, explicit plugins,
and Core/local.
- Preserve existing local and plugin workspace ownership. Pin selection
through preparation and keep provider failures visible.
- Add database, API, manifest, heartbeat, and UI regressions. Update the
verification maps.

## Verification

- Targeted Vitest runs cover manifest validation, project defaults and
API access, explicit overrides, existing ownership, new/imported task
inheritance, heartbeat routing, source-free tasks, selection pinning
during setup, and UI configuration.
- Combined policy, provider integration, and heartbeat run: 58 tests
pass; 60 unrelated cases excluded. After the final shared-provider
fallback fix, all 47 policy tests pass, including shared and
operator-mode regressions.
- Server and UI TypeScript checks, SDK build, verification-map
validation, credential-pattern scan, added-comment scan, and `git diff
--check` pass.
- A downstream integration uses this Core resolver and preparation
service with a real storage hook and mocked remote infrastructure. A new
Git project reaches the hook without a stored provider ID.
- Standard Greptile and Apex both scored 5/5 on
5d42998466. All review threads are
resolved.
- Final GitHub CI is fully green on
5d42998466. Browser shard 3 initially hit
a PostgreSQL deadlock during cleanup cancellation, which left an
experiment flag enabled for a later test. A failed-job retry passed all
26 browser tests. The workflow completed successfully on attempt 2. Full
final verification was delegated to CI at the user's request.
- No live provider or hosted tenant run was performed.

## Risks

- Installing one default-claiming provider changes effective selection
for unconfigured projects. Existing explicit settings and workspace
ownership remain intact; incompatible explicit settings fail clearly.
- Each configuration/admission resolution reads installed plugin
metadata and the selected company's enablement. Project list reads share
one catalog query. Selection does not call workers or external
providers.
- Deploy the Core contract before any downstream manifest uses the
declaration. No migration or backfill is required. A downstream
immutable image pin must include this change before packaging its
declaration.
- No merge or deployment is authorized by this PR.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, and code
execution. The exact served model ID and context-window size are not
exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
ticket id
- [x] I have run targeted tests locally and they pass; full gates are
delegated to CI at the user's request
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green on
5d42998466ad42400564ba34f48124f40c53fbc5; the branch has no merge
conflicts
- [x] Standard Greptile is 5/5 on 5d4299846 after all fixes, with no
unresolved threads
- [x] Apex is 5/5 on 5d42998466, after
standard Greptile 5/5 on that same head
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-22 17:12:29 -07:00
DottaandPaperclip 9bf7dc0c8f feat(agents): bulk edit connections and default models (#17215)
Add harness-scoped bulk connection and default-model edits to the agent roster, with compatible choices, change previews, per-agent save results, and retries.

Use an icon-based harness filter, keep agent rows readable, remove the status selector and selection hint, and redirect legacy status URLs to the full roster.

Preserve authorization, audit history, unrelated settings, and optimistic concurrency checks through the existing agent update route.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-22 18:47:06 -05:00
TonioandClaude Fable 5.1 341b622604 feat(ui): Artifacts V1 behind an experimental setting — Artifacts page, panel tab and task thread (#17228)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents produce artifacts: documents, files, pictures, video and
links. The app shows them on the Artifacts page, in the right panel's
Artifacts tab and in the task thread
> - The artifact directions lab (#17213) settled a presentation for
those surfaces, MVP V1, drawn from the PCLP-Core mocks. It is a
reference, not product code
> - Shipping it means product components on product data, token-only,
behind a switch, one surface at a time, so the current presentation
stays the default until the new one has been used
> - This pull request adds the switch (Settings > Experimental >
Artifacts V1), the `--artifact-*` tokens, the V1 primitives as product
components, and the V1 presentation on all three surfaces behind the
switch: the Artifacts page, the panel's Artifacts tab and the task
thread
> - The benefit is the redesign in the product, reversible by one
setting, with every existing behaviour of those surfaces kept

## Linked Issues or Issue Description

No public issue exists. This section follows the feature request
template; the plan is `doc/plans/2026-10-22-artifacts-mvp-v1.md`.

**Subsystem affected**

The web UI (`ui/`): the Artifacts page, the right panel's Artifacts tab
and the task thread. The experimental settings contract in
`packages/shared` and `server` gains one boolean.

**Problem or motivation**

The three artifact surfaces grew separately and their artifact
presentation is dated and inconsistent. The lab produced a measured
direction; nothing in the product uses it yet.

**Proposed solution**

An experimental setting, `enableArtifactsV1`, default off, with the same
plumbing as the other experimental settings. Product primitives under
`ui/src/components/artifacts/v1` (kind helpers and adapters, the sheet
and print artwork, the stack, the page tiles with the Paper Mono pill,
the row the panel and thread will share), driven by `--artifact-*`
tokens in `index.css` with light and dark values. With the setting on:
the Artifacts page shows one row of views (Tasks, All files, Images,
Videos, Documents, Text, Files) and the V1 tiles, a task with several
artifacts as a stack whose newest artifact is the first page, everything
else as single tiles; the panel's Artifacts tab is one flat list of V1
rows, newest first, with the expandable rows (Markdown review surface,
document annotations, deep links) keeping their behaviour behind the row
as their face; the thread shows a message's files as rows under its
footer and registered deliverables and documents as one row each. The
hover movement respects reduced motion.

**Alternatives considered**

Replacing the current cards outright: no fallback and three surfaces to
land at once. Mounting the lab's components: they are typed on lab
fixtures and keep lab-local tokens, which the token gates reject. The
primitives were ported instead and the lab stays a reference.

**Roadmap alignment**

Supports the "Artifacts & Work Products" theme in `ROADMAP.md`.
Presentation only; no data model change.

**Additional context**

No new API fields: the tiles show title, identifier, count and "Updated
…"; rows take sizes from the work-product and attachment payloads; a
picture's aspect ratio comes from the loaded image, 4:3 until it loads.
The plan records what each surface keeps and what it drops (run sections
in the panel; the "Images · N / Files · N" labels and the four-up grid
in the thread).

## What Changed

- Add the `enableArtifactsV1` experimental setting: shared type,
validator and feature catalog, server defaults and managed keys, the
`useArtifactsV1Enabled` hook, and the Settings > Experimental toggle (in
its alphabetical place).
- Add the `--artifact-*` tokens and the Artifacts V1 component rules to
`ui/src/index.css`: light values on `:root`, dark overrides, and the
hover movement under `prefers-reduced-motion: no-preference`.
- Add `ui/src/components/artifacts/v1/`: `kinds.ts` (kind treatment,
labels, glyphs, the server's media-kind rule, adapters from
`CompanyArtifact`), `geometry.ts` (the measured constants), `when.ts`,
`ArtifactSheet`, `ArtifactPrint`, `ArtifactStack`, `ArtifactFront`,
`ArtifactTile` (stack and single tiles, caption, grid), `ArtifactRow`
(the row and its inline group), `ArtifactsV1Filters`, with the mock's
SVG assets.
- Wire the Artifacts page: with the setting on, the toolbar's filter row
becomes the V1 views and the grid renders V1 tiles; the toolbar takes an
optional `filters` row for this. The old cards and kind filters stay the
default.
- Wire the panel's Artifacts tab (`IssuePropertiesArtifactsTab`): with
the setting on, one flat list of V1 rows, newest first; `DocumentRow`
and `MarkdownWorkProductRow` take a `face` render prop so the V1 row
fronts their unchanged expansion, review and deep-link behaviour;
`PanelFileRow` opens attachments and attachment-backed work products the
way the shipped card does (gallery, text tab, new tab) with open and
download beside the name; other work products are a link row with their
status.
- Wire the task thread: `TaskChatBubble` hangs a message's files under
its footer as V1 rows inline (pictures and video to the gallery, text to
a text tab, files to a new tab) in place of the media grid and file
chips; `TaskChatProtocolCard`'s resource rows render deliverables,
documents and attachments as one V1 row each, opening where the card
did.
- `ArtifactRow` keeps trailing controls beside its own control (no
nested interactive elements) and can be a link, an in-app anchor, a
new-tab anchor or a button; adapters read work products, documents,
attachments and message references.
- Add a catalogued Storybook story, `Components/Artifact V1 primitives`,
under `documents-artifacts`, on fixtures.
- Add tests: the primitives (kinds, dates, print fitting, tiles, rows),
the hook, the Artifacts page, the panel's Artifacts tab, the task-chat
bubble and the protocol card, each with the setting on and off; the
settings page and server tests list the new key.
- Add `doc/plans/2026-10-22-artifacts-mvp-v1.md`.

## Verification

- Run `cd ui && pnpm typecheck`: the Storybook catalog accepts the new
story, and `tsc -b` is clean apart from the five pre-existing
`PluginOrganizationSwitcher` errors.
- Run `pnpm check:token-gates` and `node scripts/check-maps.mjs`: clean.
- Run `cd ui && npx vitest run src/components/artifacts
src/components/issue-properties
src/components/task-chat/TaskChatBubble.test.tsx
src/components/task-chat/TaskChatBubble.artifactsV1.test.tsx
src/components/task-chat/TaskChatProtocolCard.test.tsx
src/components/task-chat/TaskChatProtocolCard.artifactsV1.test.tsx
src/pages/Artifacts.test.tsx src/hooks/useArtifactsV1Enabled.test.ts
src/pages/InstanceExperimentalSettings.test.tsx`: the suites pass (151
tests in the last run).
- Run `cd packages/shared && npx vitest run src/feature-catalog.test.ts`
and `cd server && npx vitest run
src/__tests__/instance-settings-service.test.ts`: pass.
- Manual: open Settings > Experimental, turn on Artifacts V1. On the
Artifacts page the view row reads Tasks, All files, Images, Videos,
Documents, Text, Files; tasks with several artifacts show as stacks,
hovering fans the pages and lifts the artwork (not under reduced
motion); Images shows single tiles with bordered prints. Open a task's
Artifacts tab: one list of rows, newest first; a Markdown work product
still expands into its review surface, a document still opens in its
tab. In the thread, a message's files sit under its footer as rows. Turn
the setting off: everything returns to the current presentation.
- Storybook: `Tasks and conversations / Documents, attachments, and work
products / Components / Artifact V1 primitives`.
- Not run: the full `pnpm test:run` and `pnpm build` (CI runs them), and
a browser pass against a dev instance with real artifacts on the three
surfaces; that pass is the remaining step before this leaves draft.

## Risks

- Off by default; with the setting off, the only changes on a product
path are an optional `filters` prop on the toolbar, an optional `face`
prop on two panel rows, a read of the setting in the bubble and the
protocol card, and the new token declarations.
- With the setting on, the Artifacts page's view tabs set two URL
parameters (`groupBy`, `kind`) at once; the group-by menu and search are
unchanged.
- A picture with unknown dimensions renders at 4:3 until it loads, then
the print refits once; the frame's height is fixed so nothing below it
moves.
- About thirty new `--artifact-*` tokens, namespaced and documented in
place.

## Model Used

- Claude Fable 5.1 by Anthropic, model ID `claude-fable-5-1`, used
through Claude Code in the desktop app. Extended reasoning was on.
Capabilities used: tool use (shell, file edits, a headless Playwright
browser for the lab's measurements, the Figma MCP server for the mocks
during the lab work) and image input. The context window is the Claude
Code session's; its exact size is not surfaced to the session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above (#17213 is the lab this builds on)
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (the suites listed above;
CI runs the full set)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes (the
plan document; no command or product behaviour changes outside the
setting)
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-22 15:14:58 -07:00