Commit Graph
2124 Commits
Author SHA1 Message Date
3edba11576 fix(github): stop counting suspended installations as repository access (#17343)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents get GitHub access through a managed GitHub App connection.
**Refresh access** reads the installations and repositories that the
user token can reach.
> - GitHub keeps listing a suspended App installation and all of its
repositories for the user token. But the token then loses write access
and cannot read private repositories.
> - `loadGitHubGrantMetadata` did not read `suspended_at`. It counted a
suspended installation as live access ("all repos") and set the
connection to healthy.
> - So the board showed "connected, all repositories" while agents got a
403 on `git push` and a 404 on private repositories. The suspend webhook
marks the connection unhealthy, but the next refresh or reconnect
reverted that.
> - This pull request skips suspended installations. When all
installations are suspended, Refresh access fails with a clear error and
a link to the installation settings page, where an owner can click
**Unsuspend**.
> - The benefit is that the board shows the real access state, and
operators get a direct path to fix it.

## Linked Issues or Issue Description

**What happened?**
A GitHub App installation on an organization was suspended. The
Paperclip GitHub connection still showed "connected" with access to all
repositories after **Refresh access**. Agents that used the managed
token got `Permission to <org>/<repo>.git denied` (403) on push,
`Resource not accessible by integration` on branch creation, and 404 on
private repositories.

**Expected behavior**
Refresh access must not count a suspended installation as repository
access. When every installation is suspended, Refresh access must fail
with a message that says the installation is suspended, and the page
must link to the installation settings page.

**Steps to reproduce**
1. Connect GitHub to Paperclip through the GitHub App, with an
installation on an organization.
2. On GitHub, suspend that installation (Organization settings → GitHub
Apps → Configure → Suspend).
3. In Paperclip, click **Refresh access** on the GitHub connection.
4. See that the connection stays healthy and reports all repositories,
while agent pushes fail with 403.

**Paperclip version or commit**
`master` at a708a1333.

**Additional context**
`GET /user/installations` returns the suspended installation with
`suspended_at` set and `repository_selection: all`, and `GET
/user/installations/{id}/repositories` still lists its repositories.
Unsuspending the installation restored push access and private reads for
the same token.

## What Changed

- `server/src/services/tool-access/github-access-discovery.ts`:
`loadGitHubGrantMetadata` skips installations that have `suspended_at`
set. It does not add their IDs, owners, repository selection, or
repositories. When there is no usable installation and at least one is
suspended, it throws `github_installation_required` with a "suspended"
message. `managementUrl` points at the suspended installation's settings
page (or the generic installations page when more than one is
suspended).
- `server/src/services/tool-access/catalog/health.ts`:
`checkConnectionHealth` (the Refresh access path) keeps
`installationUrl` and `managementUrl` when it rebuilds a
`github_installation_required` error. Before, the links were dropped.
- `server/src/services/tool-access/catalog/failures.ts`:
`github_installation_required` keeps its own code and returns 422.
Before, it was folded into a generic `paperclip_error` with HTTP 502.
- `ui/src/pages/apps/app-detail/AccessRetryBanner.tsx` (new): the
attention banner with the saved health message and **Retry access**.
After a failed Refresh access with `github_installation_required`, it
shows an **Open installation settings on GitHub** link (https
`github.com` URLs only).
- `ui/src/pages/apps/AppDetail.tsx`: uses `AccessRetryBanner`, refetches
the connection when a refresh fails so the banner shows the saved
message, and keys the page on `connectionId` so a recovery link never
carries over to another connection. The file stays under 1,000 lines.
- Tests:
- `server/src/__tests__/github-grant-metadata.test.ts`: a mix of
suspended and active installations, and an account where all
installations are suspended.
- `server/src/__tests__/github-health-recovery.test.ts`: drives
`checkConnectionHealth` with a suspended-installation GitHub response
and checks the 422, code, and recovery links.
- `ui/src/pages/apps/AppDetail.test.tsx`: a failed Retry access renders
the installation settings link, and navigating to another cached
connection does not show it.

## Verification

- Red/green: with the source changes reverted and the tests kept, the
new tests fail (suspended installation counted as `all`; recovery link
missing from the health-check error; link not rendered; link leaking to
another connection). With the changes, they pass.
- `server`: `github-grant-metadata`, `github-health-recovery`,
`tool-access-service`, `github-operation-credentials`,
`tool-access-oauth-protocol.integration`, `tool-connection-removal`,
`tool-connection-visibility`, and the other `github-*` / `tool-access-*`
suites pass locally (630 tests).
- `ui`: `AppDetail.test.tsx` passes (78 tests). `ui` `tsc --noEmit`
shows no errors in changed files.
- Not run locally: the server `tsc`. The sandbox has a 4 GB memory
limit, and the server typecheck is killed there even on clean `master`.
CI ran the full typecheck and build, and both pass.
- CI: all gates green. One unrelated `workspace-recovery.test.ts` poll
timeout in a server shard passed on re-run.
- Live check: after the suspended installation was unsuspended, a
managed-token `git push --dry-run` succeeded and a private repository
returned 200.

## Risks

- Low risk. The change only affects installations that GitHub marks as
suspended. Active installations behave as before.
- A connection that has only suspended installations now fails Refresh
access with `github_installation_required` (422) and does not report
fake access. This is the intended behavior.
- The recovery link only renders for https `github.com` URLs.
- Keying the app page on `connectionId` remounts it when moving between
connections, which resets per-page state (for example an open rename
field). That reset is intended.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, used through the
Claude Code agent SDK with tool use (shell, file edit, 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
- [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: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 21:16:40 -07:00
TonioandClaude Fable 5.1 3e7c3ee9a9 fix(ui): fall back to the icon face when an Artifacts V1 preview fails to load (#17260)
## 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 Artifacts V1 presentation (`enableArtifactsV1`, #17228) shows
them as prints, sheets and rows on the Artifacts page, in the panel's
Artifacts tab and in the task thread
> - A picture is printed from its attachment's content path. When that
content cannot be loaded (on staging, image work products whose
attachment returns 404), the browser draws its broken-picture glyph
inside the bordered print and inside the 40px row thumbnail
> - The presentation already has a face for a file with nothing to show:
the icon sheet (the faint glyph and the type label) and the row's
document icon. A picture that cannot be loaded should take that face,
not a browser glyph
> - This pull request listens for the element's own `error` event in the
V1 primitives and falls back to the icon face on all three surfaces: the
stack front and the single tile on the Artifacts page, and the panel and
thread rows
> - The benefit is that a missing or unreadable file reads as a file of
its type everywhere, with no fetch to find out, and nothing changes for
a picture that loads

## Linked Issues or Issue Description

No public issue exists. This section follows the bug report template.

**What happened?**

With Artifacts V1 on, an image work product whose attachment content
returns 404 ("Attachment not found") shows the browser's broken-image
glyph inside the bordered print on the Artifacts page (the stack front
and the single tile) and inside the 40px thumbnail in the panel and
thread rows.

**What did you expect to happen?**

The artifact shows the icon face a file without a preview gets: the icon
sheet with the faint glyph and the type label on the Artifacts page, and
the document icon with the type label in the rows.

**Steps to reproduce**

1. Turn on Settings > Experimental > Artifacts V1.
2. Register an image work product whose attachment content returns 404,
or delete the attachment behind one.
3. Open the Artifacts page, the task's Artifacts tab and the task
thread.

**Relevant subsystem**

The web UI (`ui/src/components/artifacts/v1/`).

## What Changed

- `ArtifactPrint`: a new `usePreviewFailure(source)` hook beside
`useImageAspect`, and an `onMediaError` prop wired to the `error` event
of the print's `<img>` and `<video>`. The hook remembers the source that
failed rather than a flag, so a front that moves on to another picture
(a stack's newest artifact) gets a fresh chance.
- `ArtifactFront`: owns the failure state for its subject and renders
the icon sheet (`IconSheet`, the `icon` treatment) once the print
reports an error; it passes the error on through its own `onMediaError`.
- `ArtifactStack`: on an error it stops fitting a print and stands the
icon sheet where a sheet stands in the media stack (the portrait anchor,
where audio stands), keeping the media backing.
- `ArtifactRow`: the thumbnail listens for `error` on its `<img>` /
`<video>` and gives way to `ArtifactRowIcon`, the document icon with the
type label.
- Until the picture loads the print stays the 4:3 placeholder, and a
picture that loads behaves as before. No fetch is made to detect a
failure.
- A failed video takes the plain icon sheet with no play disc, since the
stream it would promise cannot play; a video with no URL at all keeps
the existing media-fallback treatment with the disc.
- `index.ts` exports `usePreviewFailure`; the plan doc
`doc/plans/2026-10-22-artifacts-mvp-v1.md` records the fallback.
- Tests: `ArtifactTile.test.tsx` covers the single tile (4:3
placeholder, then the icon sheet after `error`), the picture stack (the
sheet stands where the audio stack's sheet stands, on the media backing)
and a video whose stream fails (icon sheet, no play disc).
`ArtifactRow.test.tsx` covers the thumbnail and the video thumbnail
giving way to the document icon, and a new source getting its own
chance.

## Verification

- `cd ui && npx vitest run src/components/artifacts/v1` — 6 files, 33
tests pass (5 new).
- `pnpm run check:token-gates` — exits 0: all four token gates clean,
palette tokens and the ClipLab character in sync. (The bare `pnpm
check:token-gates` form reports "Command not found" under pnpm 9.15.4 in
this worktree; `pnpm run` works.)
- `cd ui && pnpm typecheck` — exits 0 with no errors.
- Browser proof on a throwaway backend-free vite page (not committed)
rendering the primitives with a 404 picture, a 404 video, a picture that
loads and audio: on the Artifacts page the 404 picture's stack front is
the PNG icon sheet at the same position as the audio stack's sheet (left
37.89px, top 13.34px) on the media backing; the single tiles show the
PNG and WEBM icon sheets with no play disc while the loading picture
keeps its fitted 240×160 print; the rows show the PNG and WEBM document
icons with no `<img>`/`<video>` left, while the loading picture's row
keeps its thumbnail. Not run: the browser suites (`pnpm test:e2e`, `pnpm
test:release-smoke`) and a live staging check.

States enumerated: loading (4:3 placeholder print, unchanged), loaded
(fitted print, unchanged), failed picture (icon sheet / document icon),
failed poster-less video (icon sheet without play disc / document icon),
source changed after a failure (print again).

## Risks

- Low risk. The change is behind `enableArtifactsV1` and only acts on
the element's `error` event, which fires for a 404, a network failure,
or content that is not decodable as a picture; nothing is fetched to
find out.
- `ArtifactFront` and `ArtifactStack` each keep the failure state for
their subject (as both already keep the loaded aspect), set from the
same event in one render; a consumer that renders `ArtifactFront` with a
print size but ignores `onMediaError` still gets the icon face, only at
the print's position.
- A picture that fails once and later becomes readable at the same URL
keeps the icon face until the surface remounts or the subject moves on
to another source; the data does not change under a mounted tile in
practice.

> 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 (Anthropic), model ID `claude-fable-5-1`, extended thinking,
running in Claude Code (desktop app) with tool use: file editing, shell,
Vitest, and the built-in browser for the proof page.

## 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 Fable 5.1 <noreply@anthropic.com>
2026-10-26 21:08:49 -07:00
conreo b46d1ab77b feat(ui): request a standalone window so the app can be installed (#13461)
## Thinking Path

> - The Paperclip board is used from phones, and
`ui/public/site.webmanifest` is what a browser reads when someone adds
the board to a home screen.
> - That manifest asks for `display: "browser"`. Chrome installs a web
app only when `display` is `fullscreen`, `standalone` or `minimal-ui`;
with `browser` it answers `manifest-display-not-supported` and adds a
shortcut rather than an app, so every launch keeps the address bar.
> - The user interface already implements the no-browser-chrome case.
`StandaloneBrowserControls` renders Refresh, Share and Open in Browser,
and it is rendered only when `mobile && isChromelessDisplayMode()`.
`ui/src/lib/pwa-display-mode.ts` exists for no other purpose than to
detect `standalone`, `fullscreen` and `window-controls-overlay`.
> - None of those modes can occur on a mobile launch while the manifest
says `browser`, so that component and its fallback controls are
unreachable in practice.
> - That makes the manifest value look like the outlier rather than the
intent, so the change is one manifest field plus the test that pins it.

## Linked Issues or Issue Description

Refs #2139 — "enh: Officially support Install as Progressive Web App",
which asks for a supported home-screen install. This pull request is the
installability half of that request; it does not touch notifications.

**Subsystem affected**

The web app manifest and the unit test that guards it:
`ui/public/site.webmanifest` and `ui/src/lib/pwa-install-mode.test.ts`.
No server, plugin, or database code.

**Problem or motivation**

Chrome's installability criteria require `display` to be one of
`fullscreen`, `standalone` or `minimal-ui`. With `display: "browser"`
Chrome reports `manifest-display-not-supported`, offers only a shortcut,
and the launch keeps browser controls, so the board never behaves like
an installed application even though the manifest, service worker, and
icons all exist.

The same value also makes existing code unreachable: the in-app
replacement controls for a chromeless launch
(`StandaloneBrowserControls`, gated on `mobile &&
isChromelessDisplayMode()`) cannot be triggered from a mobile
home-screen launch, so the app carries a fallback that nothing can
exercise.

**Proposed solution**

- Set `display: "standalone"` in `ui/public/site.webmanifest`.
- Update `ui/src/lib/pwa-install-mode.test.ts`, which asserted `display
=== "browser"`. The assertion now pins `standalone` and a comment
records why, so the next reader does not have to reconstruct this
reasoning. The assertions that keep the legacy `mobile-web-app-capable`
and the Apple metas out of `index.html` are unchanged.

`standalone` rather than `fullscreen` for two reasons. It keeps the
Android status bar showing the
clock and battery, and it avoids a known Android behaviour of
`fullscreen` launches: opening the soft
keyboard triggers a fullscreen transition and a visible flicker ([Google
issue 392925620](https://issuetracker.google.com/issues/392925620),
[Stack Overflow
71606355](https://stackoverflow.com/questions/71606355/pwa-does-not-resize-window-when-virtual-keyboard-is-active-on-fullscreen-display)),
which `standalone` does not do.

**Alternatives considered**

- `fullscreen`. Also installable, and it additionally hides the Android
status bar. Rejected as the default for that reason; it is a one-word
change if preferred.
- Adding the legacy `mobile-web-app-capable` meta. Rejected: Chrome
reads the manifest, so the meta is redundant.
- Adding the Apple `apple-mobile-web-app-capable` metas for iOS.
Rejected for this change: it is iOS-specific, and iOS is not the
platform whose installability check this fixes.
- Changing `orientation`, which #5564 reports. Rejected as out of scope;
this pull request stays on `display` only.

**Roadmap alignment**

`ROADMAP.md` does not plan this work. Its only mention of install is the
skills store.

**Additional context**

- #7792 attempted a standalone PWA earlier and was closed during triage.
It bundled a deploy-pipeline change and a heartbeat change with the
manifest change, and its title carried an internal ticket id. This pull
request is deliberately the manifest change alone.
- #5564 reports that the manifest's `orientation: any` ignores the
Android rotation lock. Related, not addressed here.
- The keyboard flicker above was reported against a board installed with
`fullscreen`, which is one of the two
reasons this pull request asks for `standalone` instead of the more
immersive mode.

## What Changed

- `ui/public/site.webmanifest`: `display` is now `"standalone"` instead
of `"browser"`.
- `ui/src/lib/pwa-install-mode.test.ts`: the expectation that pinned
`browser` now pins `standalone`, with the reasoning in a comment; the
meta assertions are unchanged.

No runtime code, no dependency, and no data change. The icons the
installability check also requires (`android-chrome-192x192.png`,
`android-chrome-512x512.png`) are already present and unchanged.

## Verification

- `vitest run src/lib/pwa-install-mode.test.ts
src/lib/pwa-display-mode.test.ts` in `ui`: 2 files, 7 tests passed (the
same 2 + 5 the sibling plugin-event change reports).
- The manifest parses as JSON, keeps `display: "standalone"`, and keeps
192 and 512 pixel icons.
- The only place in the repository that asserts the manifest's `display`
value is the test updated here; the other references to
`site.webmanifest` are request routing and HTTP log policy and are
unaffected.
- CI on the previous head of this branch had two failures unrelated to
this change: an e2e hover-opacity assertion on a sidebar star button
(`Star Zeta`: expected `1`, received `0`) and `TypeError: Cannot read
properties of undefined (reading 'logicalEffectCount')` in the runner
verify job. Both are in subsystems this change cannot reach; CI is
re-running on this commit.

## Risks

- Low. One manifest field and one test expectation; no runtime code
changes.
- The value applies to new installations. An app already installed with
the previous value keeps its installed configuration until it is
reinstalled, so nobody loses a working install.
- iOS launches are unchanged: Safari does not take `display` from the
manifest for home-screen launches, and this change does not add the
Apple metas.
- Nobody depends on the address bar being present in an installed
launch; the in-app controls that replace it
(`StandaloneBrowserControls`) are already implemented and become
reachable.

## Model Used

- Provider: DeepSeek. Model ID: `deepseek-v4-flash`. The model ran as a
tool-using coding agent (shell, file edits, headless browser automation)
inside a coding harness. The harness did not report a context-window
size or a reasoning mode.

## 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 issues and
linked them above (#2139, #7792, #5564)
- [x] I have either (a) linked existing issues with `Fixes:` / `Closes`
/ `Refs #` OR (b) described the issue in-PR following the relevant issue
template — both, see above
- [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
ticket id or instance-derived details
- [x] I have run the affected tests locally and they pass (2 files, 7
tests)
- [x] I have added or updated tests where applicable — the guard test is
updated, and it is the only test that pins this value
- [x] I have updated relevant documentation to reflect my changes — no
user-facing document describes the manifest; the updated test now
records the reasoning in place
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green — CI is re-running on this commit
after the unrelated failures described under Verification
- [ ] Greptile is 5/5 — awaiting the review run on this commit
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-10-26 20:52:20 -07:00
DottaandPaperclip 208a093d19 fix(chat): preserve resumed review waits and retry newer saved input (#17725)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/36/changes/paperclip/36
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub review agents publish findings and wait for an authorized
reply or head change.
> - Review tools could retain the requester after resume while
completion lost that same wait proof.
> - A yielded report could then queue its own continuation or repeat a
missing-wait error.
> - Ordinary Retry could also select an older failed turn while a newer
saved request had no admission.
> - This change shares the existing authority proofs and canonical
admission owners.
> - Current access, publication, execution and budget gates remain
required.

## Linked Issues or Issue Description

Refs #17318. Builds on the canonical saved-input retry owner in #17733.
Related #16550 covers deferred legacy comments after ownership waits.
The separate recovery repair in #17724 owns the cleanup-to-saved-input
handoff; this PR does not add a second admission owner.

A resumed review could publish an assessment, then turn its
`response_wake` into an immediate `issue_status_changed` wake. A
provider that omitted its continuation could instead repeat a completion
error. A newer linked-human message saved during a budget hold could
also remain unstarted because Retry selected the older failed source.

## What Changed

- Resolve passive review waits through the accepted requester ledger
used by GitHub tools. Require the latest reviewed head, exact company,
task, agent, repository and processed publication under current access.
- Fill omitted/null yielded continuation from that server proof. Permit
an inherited normal tree resume only through its accepted parent
identity. Permit an ordinary follow-up only after this run has a
processed useful reply linked to its exact inbound message. Reject
acknowledgements, partial assessments, pending or uncertain writes as
that reply proof.
- Recheck the same run/review/head/source proof during feedback,
finalization and final status commit. Preserve explicit malformed-input
rejection and Done policy. Add no monitor permission or publication
grant.
- Keep heartbeat and publication projections narrow. Preserve both
published Copilot v62 identities and generate source-bound v63 from the
pinned merged base. No v63 live qualification is claimed.
- Certify the structured isolated-directory binding failure only at its
pre-allocation boundary and only through canonical task Retry. Other
workspace validation reasons and unknown effects remain denied.
- Route Retry to eligible newer saved input through the existing
canonical owner. Preserve the old result and skipped receipt. Require
current principal, source, App, runtime fence, budget, native ownership
and exact cleanup proof.
- Recover absent historical App metadata only through an earlier trusted
processed response receipt and an immutable non-null endpoint claim.
Explicit malformed or conflicting metadata stays denied.
- Revalidate execution through the exact claimed wake, coalesced task
Retry and resolved user-continuation receipt after admission. A second
normal Retry can recover the exact never-started authorization failure
with unchanged saved input. Require empty execution evidence, exact
diagnostics and no allocated or active executor.
- Explain when a recorded result prevents exact replay. Ordinary board
Retry directs a new task message to continue from saved work. Inherited
requester identity alone never grants replay.
- Keep accepted board-message preparation failures with the canonical
task Retry owner. Certify the exact unchanged comment, original user
wake, accepted same-user identity and absence of provider execution. Pin
that source, recheck it at admission, and bind identity initialization
to the coalesced intent and exact claimed successor receipt.
Uncertifiable sources retain an actionable fresh-message refusal.
- Return safe named authority categories for board Retry refusals.
Update execution documentation and capability maps. Add no schema or
polling loop.

## Verification

- A fresh external review request exposed a separate isolated-directory
preparation failure before allocation. Its first normal Retry saved an
intent but admitted no successor. This follow-up certifies only that
exact structured preparation boundary through the existing canonical
Retry owner, with trusted failed settlement and no executor, lease,
result or output. A real HTTP/queue regression reproduces the missing
successor before the repair. Twenty-three current-source safety cases
and the final 98-case Retry/HTTP group pass, including a fresh click
after a denied intent, source revocation, accepted results and the older
direct API remaining denied. The warning case uses actual configuration
preparation and production event append; unknown warning shape or
provider provenance stays denied. Full workspace typecheck, build, maps
and diff checks pass. Renewed hosted normal Retry now succeeds on the
final combined source: it preserves the exact saved request and linked
requester, starts one native successor in a fresh attempt workspace,
publishes the current-head 2/5 assessment and commits In review with
passive response wake.

- A later hosted normal Retry published a low-score assessment but lost
its accepted source identity because the previous attempt failed before
identity initialization. It repeated continuation errors, then submitted
Done. This is failed acceptance, not a successful qualification. The
initializer now retains the exact source only after execution-time
failed-chat Retry authorization; generic Retry and Done policy are
unchanged. A real queue/initializer regression fails with a null source
on the previous code and passes with the newer saved source. Two real
database completion cases verify that source yields the authoritative
wait and commits In review. Renewed hosted normal Retry now retains the
accepted source and exposes the authoritative current-review wait. It
completed after two semantic feedback corrections (wrong contract
revision, then wrong criterion IDs); the correct contract was present in
emitted input. The third finish was accepted and committed In review,
with no missing-wait loop or Done escalation.
- Repeated board-message preparation failures now walk their canonical
intent, failed dispatch and accepted parent identity, rechecking each
contained predecessor. A production queue regression fails the second
ordinary HTTP Retry before the repair and passes afterward. Changed
source, contradictory execution evidence and cyclic receipts remain
denied; traversal stops after twenty links.

- New inherited omission cases failed before the repair. The final full
PostgreSQL 18 wait/status suite passes **252 tests** under Node 24.22.
It covers omitted/null input, malformed-first recovery, same-head
resume, exact-source replies, changed heads, revoked access,
pending/uncertain/mixed publications, final commit revalidation, no
duplicate review and no self-wake.
- **15 existing publication tests passed before the pinned merge** on a
separate fresh database. They retain default partial-delivery and
failure-fallback behavior. Context reads remain below the unchanged 16
KiB heartbeat and publication response limits with large saved output
present.
- Saved-input tests cover a real signed PR webhook, production
accounting-budget refusal, normal policy recovery and canonical Retry.
Historical producer-shaped tests prove the missing-App case red, then
check trusted prior receipts and malformed, late, revoked or mismatched
proof. A broader order-coupled test was reproduced on the prior source;
its global fault injector now targets its own authorization query. The
43-case sequence passes without changing production behavior or its
safety assertions.
- New signed-ingress and real heartbeat execution tests reproduced the
admitted-successor failure, then the next normal Retry failure. The
final pinned merged source passes 249 full GitHub review/publication and
Retry cases on a fresh database, including all 49 saved-input cases. A
separate 74-case Retry/HTTP run also passes. Exact dispatch negatives
cover source, company, agent, task, successor, receipt, pause,
assignment, accepted success, controller and cleanup proof. Bootstrap
contradictions remain denied. The canonical Retry suite passes 16 cases
through its supported external PostgreSQL test connection.
- The normal board HTTP route reproduced the unusable inherited-result
refusal. It now returns actionable guidance without starting a
successor. The actual UI Retry hook and banner tests pass 12 cases.
- A production-shaped accepted board comment followed by a pre-provider
qualification failure reproduced HTTP 409 before the repair. The final
real HTTP/queue test certifies one canonical successor and preserves the
accepted identity. It rejects changed source, actor, task, agent,
result, controller, process, profile, allocation and receipt evidence. A
post-acceptance source change keeps the same intent pending. Execution
revalidation rejects removed or mismatched proof. The probe stops
deliberately after production identity initialization; it does not claim
provider execution. The final source passes the 75-case Retry group, the
focused two-case board/inherited-policy group and 19 canonical Retry
cases. Full workspace typecheck, build and map checks pass.
- Full workspace `pnpm -r typecheck` and `pnpm build` pass. Map,
module-boundary and diff checks pass. Full local `pnpm test:run` remains
unverified. The 256-case explicit-native suite cannot initialize its
packaged PostgreSQL because libzstd is absent; an existing
command-scoped fallback did not resolve it. Current-head remote
full-suite checks are required. Merged-source full GitHub+Retry (249),
separate Retry/HTTP (74), full wait/status (252), profile/history and
completion (75), and visible Retry hook/banner (12) checks pass. The
fresh owned PostgreSQL 18 databases applied all 377 migrations.
- Actual Rust Runner, OpenCode 1.18.34 and exact DeepSeek used unchanged
production-generated synthetic contexts. Resume finished with an
explicit server wait. The author-reply trial omitted continuation twice:
its first report failed the existing empty-criteria check; the corrected
second report still omitted continuation and received the exact server
wait. It completed once with no missing-wait loop or Done escalation.
Controller acknowledgments were synthetic; these probes do not establish
hosted publication or board state.
- Hosted combined testing proved automatic admission of the exact saved
author reply, a useful GitHub answer and committed passive wait. It
required two malformed-continuation rejections before a nullish fallback
succeeded. A later normal Pause/Resume completed in one finish with
explicit response_wake and no new review/comment. The admitted normal
Retry then exposed the execution guard gap repaired here. Those remain
checkpoint results. On the final combined source, renewed normal Retry
completed actual native provider work and GitHub publication, committed
the passive wait, released ownership and cleaned up its environment. A
subsequent ordinary unmentioned author reply woke once, made no GitHub
tool calls or new assessment, and completed its first finish with an
explicit response wake. Both exact leases expired with successful
cleanup and the queue was empty. However, final destination inspection
found a separate automatic fallback overwrote the existing summary with
a generic no-final-response message. External summary preservation
therefore remains failed acceptance; the separate publication repair in
#17726 owns that producer. Full combined publication preservation has
not passed. These hosted runs include the pinned-base native additions;
they do not qualify Copilot v63.
- Current-head automated review is 5/5 with zero unresolved threads. All
current-head CI gates passed (54 successful checks/contexts, four
skipped, none pending). The earlier login-cleanup idle-work assertion
also reproduced locally while its controlled baseline passed; its cause
remains unknown, but the exact assertion passed in the fresh
current-head CI shard. No timeout, assertion or production workaround
was added. This PR is ready for review within its source, authority,
native finalization, state, wake and cleanup scope. The independent
automatic fallback publication regression is tracked by #17726; no
complete combined workflow pass is claimed.

## Risks

- The latest saved review defines the durable head boundary. Ingress
must record a new head before admission. A reply receipt proves delivery
only for its exact saved source; a shared GitHub comment ID alone cannot
authorize this wait.
- Historical App recovery cannot infer identity without direct proof or
an earlier valid server response receipt. It never replays that
response.
- This does not infer review-score policy from instructions or override
Done. No deployment, merge or repair of historical tasks is claimed by
the PR.

## Model Used

OpenAI `gpt-6.1-sol`, with reasoning, repository inspection, code
editing and test execution. The context-window size 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
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 database and
native suites; full local suite limitation described 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 (verified on immutable latest
head)
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
(verified on the latest head)
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 22:22:47 -05:00
DottaandPaperclip f0877a9c7c fix: recover native work and requalify saved computers (#17724)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/32/changes/paperclip/32
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages AI agents and preserves their work after an
interruption.
> - Native Stop must confirm termination and save the workspace.
> - Task and run views must show the current recovery receipt.
> - A new external reply can arrive while that cleanup is pending.
> - The reply must return to its original chat owner after cleanup.
> - A successful fresh retry also becomes the task’s bound workspace for
its next ordinary turn.
> - Managed computer updates can invalidate a saved snapshot
qualification.
> - This pull request fixes those instructions, acknowledgements,
handoffs and the existing native-agent Test path.
> - The operator can continue with new input while the stopped turn
remains preserved.

## Linked Issues or Issue Description

**What happened?**

Stopped native runs could keep the initial workspace-repair instruction
after files were recovered. Native Stop could also leave the shared
cancellation state at requested after remote termination was confirmed.
A new GitHub reply saved during cleanup could then remain queued because
cleanup did not ask its original inbound owner to reconsider the
receipt. After a managed snapshot update, an existing native agent could
also need qualification while the generic environment Test required
instance-admin access.

**Expected behavior**

Show the current saved-work state. Acknowledge Stop only after exact
termination proof. Let an authorized operator use the existing
saved-agent Run test to qualify its current computer. After cleanup,
recheck the saved reply's current authority and admit it once as new
input. Preserve the stopped run and uncertain external effects.

**Steps to reproduce**

1. Stop an active native turn before it returns a semantic result.
2. Send a new authorized external reply while cleanup is pending.
3. Let workspace recovery and provider cleanup finish. Inspect the run
instruction, Stop acknowledgement and queued reply.

Related work: #17594 preserves native processes through controller
outages. #17401 addresses a separate bootstrap failure. This pull
request does not replace those fixes.

## What Changed

- Use the exact run's workspace recovery receipt for task and run
guidance, including the Activity ledger.
- Retire an obsolete exact-session notice through the existing bounded
reconciler. Preserve the separate no-replay hold.
- Write the shared native Stop acknowledgement only after the audited
Stop intent and every exact remote lease receipt match.
- Delegate saved external input to the live inbound owner. Recheck its
source, actor, endpoint, principal and conversation generation. Promote
the same receipt in the transaction that creates its new run.
- Use that owner from the cleanup callback and existing stranded-queue
catch-up after a lost callback or restart. A denied source cannot abort
other items.
- Reuse the current private task directory after a successful fresh
retry. Re-read the company/task/workspace binding and validate the
canonical stable or attempt namespace without recreating missing files;
keep a later fresh retry separate.
- Extend the existing agent-scoped qualification owner to native agents.
The clean saved-agent Test qualifies its exact computer before runtime
testing. Reuse a current proof; require a real probe and verified
cleanup for a stale proof. Preserve draft tests and metadata-only
external/pool previews.
- Update execution semantics, capability maps and the recovery
verification recipe. Add a production-page Storybook interaction for the
normal native Test.

## Verification

- **Red:** persisted recovery states returned stale instructions; an
exact terminated native lease left shared Stop requested; the real
GitHub subscribed-message fixture left zero successors after cleanup.
The controlled baseline restored the previous production source,
reproduced the failure, then restored the fixed bytes with matching
SHA-256 hashes.
- **Green:** 382 durable-chat, native-continuation, Stop and recovery
tests pass. The real GitHub/PostgreSQL handoff matrix passes 12/12. It
covers callback, application restart, callback/sweep race, valid input
behind a deleted source, and denial for unknown stop, wrong allocation,
paused endpoint, revoked principal, deleted or changed source, changed
conversation generation and foreign scope. Repeated callbacks preserve
one receipt, its actor, one successor and the unchanged stopped
predecessor.
- **Workspace continuation red/green:** the real PostgreSQL preparation
flow created a fresh attempt and saved a marker, then rejected the next
ordinary turn with the same binding mismatch observed in deployed use.
The repaired preparation and filesystem suites pass 86/86: stable and
attempt-root reuse, saved-marker preservation, a later clean sibling,
changed current bindings, foreign company/task, closed workspace,
traversal, missing path and symlink refusal. No task row reset or
old-turn replay is used.
- **Qualification red/green:** a native saved-agent qualification
returned 422, and its normal Test skipped qualification. The repaired
path passes 224 qualification/immutable-snapshot/environment tests and
176 UI/upgrade tests. It covers revoked authority, foreign or changed
computer, current-proof reuse, failed/missing proof, draft settings,
settings changed during the probe, and external/pool previews. On exact
current source, the real local Harness / Runtime UI also qualified a
newly saved disposable Computer with missing proof through actual
Daytona, then completed the actual OpenCode/OpenRouter hello probe using
`openrouter/deepseek/deepseek-v4.1-flash-1017`. Supported availability
changed from Legacy-only to Paperclip Runner after proof persistence.
Qualification and runtime leases both completed normal release/cleanup.
The five prior task run IDs were unchanged; no task wake was created.
This is macOS source-server/UI with real Linux Daytona and provider
services, not a hosted UI claim. Test probes are archived by the
existing inspection contract; release does not claim physical deletion.
- Full workspace `pnpm -r typecheck`, `pnpm build`, token, map and diff
checks pass at `f6450f4739fc8141815b8b7c35fde22a655c5f90`. The broad
local `pnpm test:run` passed 24,899 tests and reported one existing
nested-clone test timeout at 15 seconds. The complete failing file then
passed 21/21 with the normal timeout; the exact case also passed on the
pinned earlier baseline. The broad runner stopped before its later
groups. No timeout or production workaround was added. Prior head
`f6450f4` has 53 successful checks, two conditional Storybook skips and
Greptile 5/5 with no inline threads. New workspace-reuse head
`fcb13399ec70f92f71bd8250081251dca3f48962` passes workspace typecheck,
full build, 86 scoped tests, maps and diff checks; Current-head CI has
53 successful checks and two conditional Storybook skips; Greptile is
5/5 with no inline findings. Deployed ordinary-turn reuse acceptance
passed as described below.

- **Hosted Stop proof:** the real GitHub issue-mention path used native
OpenCode, `openrouter/deepseek/deepseek-v4.1-flash-1017`, Daytona and an
exact low-trust task boundary. Normal UI Stop interrupted an active Bash
call. Native and shared acknowledgements matched the exact lease.
Automatic recovery saved exactly `STARTED\n` (8 bytes), with no finish
marker. Reload showed Stopped and saved work recovered. Only the
original cancelled run remained. Normal five-minute cleanup completed
its exact provider-destruction transition.
- **Limits:** the provider buffered command output, so the marker was
read after recovery. The approved local provider credential could not
inspect the hosted sandbox; its 404 is not deletion proof. Cleanup
success comes from the exact lease's platform destruction transition. An
earlier hosted stale instruction disappeared after rollout with
unchanged raw run/action data; that historical cause remains
unexplained. Original incident holds and publication receipts were
untouched.
- **Hosted handoff proof:** after QA deployed the combined candidate
containing `46b2e99`, startup admitted the previously saved GitHub
author reply without another comment, Retry or manual action. The new
native run used the exact original wake receipt and saved comment. It
completed once, committed an external-response wait, preserved the
stopped predecessor, emptied the queue and left the task In review. The
answer appeared in the original GitHub conversation. Workspace
finalization and the exact lease's normal destruction transition
succeeded.
- **Hosted workspace proof:** on the combined candidate containing
`fcb13399`, normal Retry preserved the original authenticated GitHub
request and completed a fresh native attempt. One later ordinary
same-head author reply then completed in the exact same workspace ID and
attempt directory, with no Retry/fresh directive. Its input tree digest
matched the Retry's finalized digest; final copyback preserved that
digest. The persisted assessment row and all five prior run records were
unchanged, exactly one new reply run completed, and the task returned to
In review with an empty queue and no live run. Both exact leases
completed normal verified destruction. This used real native OpenCode,
the exact DeepSeek/OpenRouter model and Daytona, without workspace-row
repair or a new remote marker.
- **Publication limit:** the workspace audit compares the persisted
assessment and run history. The ordinary reply exposed a separate
destination-summary fallback that changed the visible GitHub summary
despite the preserved assessment row. The publication track is repairing
that behavior; this proof does not claim the visible summary was
preserved.
- **Deployment boundary:** current-head CI/review and hosted same-source
Retry/ordinary-workspace reuse acceptance passed. The separate
visible-summary publication failure remains owned by the publication
track. Combined hosted UI confirmation of the native-agent Test path is
coordinated separately. Actual missing-proof UI/provider qualification
has passed in the isolated local instance above; prior hosted Stop and
same-input handoff proof remains separate. No merge or deployment is
performed by this pull request.

## Risks

Recovery state and termination receipts must match the exact source run
and allocation. Missing or foreign proof keeps the hold. The chat owner
must retain the original receipt and actor and recheck current
authority. Cleanup cannot grant authority or replay the stopped turn.
Existing native ownership, Stop, budget, permission and uncertain-effect
guards remain in place.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) through Codex, with reasoning,
repository tools, source editing and test execution. The context-window
size 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
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 (affected suites and
isolated failing file pass; broad timeout retained 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 (current fcb has 53 successful
checks/two conditional Storybook skips)
- [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 22:21:58 -05:00
Nicky Leach baec3abd67 Authorize background project Git with explicit Connector consent (#17798) 2026-10-26 17:22:49 -07:00
Devin Foleyanddevinfoley cfed739f81 fix(external-objects): stop reporting GitHub rate limits as unreachable (#17792)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/11/changes/paperclip/11
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app that people use to manage AI agents
for work.
> - Paperclip shows the status of external objects, such as GitHub pull
requests and issues.
> - A background sweep refreshes these objects and resolves a GitHub
credential.
> - The sweep read a credential only from a company secret with a
well-known name.
> - An instance without that secret made anonymous GitHub API calls.
Anonymous calls are limited to 60 per hour.
> - When the limit was reached, the sweep showed "unreachable" for
objects that it could not refresh.
> - A server environment token is instance-wide, so it must not expose a
private repository that a company cannot see.
> - This pull request reads a server token for public repositories,
reports a rate limit as its own state, and shows a warning on the pill.
> - The benefit is an accurate status, fewer misleading failures, and no
cross-company private data.

## Linked Issues or Issue Description

No public GitHub issue exists. The sections below describe the bug.

**What happened?**

The board showed "unreachable" for many GitHub links, even after a
related fix was deployed.

**Expected behavior**

The board should show "unreachable" only for real network failures. It
should show a rate limit as its own state and retry later.

**Steps to reproduce**

1. Use an instance with no GitHub token company secret and no server
token.
2. Let the external-object sweep make more than 60 anonymous GitHub
requests in one hour.
3. Open a task with GitHub links.

**Paperclip version or commit**

master (commit a67a18c at report time).

**Deployment mode**

Self-hosted server.

## What Changed

- Add `resolveGitHubApiCredential` in
`server/src/services/git-credentials.ts`. It reads a company secret with
a well-known name, then falls back to the server environment token
(`GITHUB_TOKEN`/`GH_TOKEN`), and it reports the credential `source`.
- Use the source in the GitHub external-object provider and in
`github-commit-details.ts`. A `server_env` token is limited to public
repositories. A private repository resolves only with a company
credential; otherwise the object reports `auth_required` and does not
fetch the private object.
- Add a `rate_limited` liveness state in
`packages/shared/src/constants.ts`.
- Classify a 403 with `x-ratelimit-remaining: 0`, a 429 response, and a
rate-limited repo probe as `rate_limited` instead of `unreachable`.
- Show `rate_limited` in the UI filter, icon, label, tone, overlay, and
badge maps.
- Make `ExternalObjectPill` and `ExternalObjectStatusIcon` prefer a
liveness warning icon and tone, so a rate-limited object shows a warning
even when the last status was healthy.
- Add tests for the credential source, the public-only server token, the
company-scoped private repository, and the rate-limited pill tone.

## Verification

- `vitest run server/src/__tests__/external-objects-service.test.ts
server/src/__tests__/git-credentials.test.ts
server/src/__tests__/github-commit-details.test.ts
server/src/__tests__/work-products.test.ts` — pass, with the new scoping
and credential-source tests.
- `vitest run ui/src/lib/external-objects.test.ts
ui/src/lib/issue-filters.test.ts
ui/src/components/ExternalObjectPill.test.tsx
ui/src/components/MarkdownExternalLink.test.tsx` — pass, with the new
rate-limited pill test.
- `pnpm --filter @paperclipai/shared typecheck` — pass. The full
monorepo `tsc` (server and ui) is killed by the 4GB memory cap of this
sandbox; the authoritative CI Typecheck gate runs it instead.
- One test in `git-credentials.test.ts` fails in this sandbox only. The
test "credential helper execution (real git, no network) ... env-carried
token" reads a global GitHub credential helper in the sandbox. The test
fails the same way on the base without this change.

## Risks

- Low risk. The change adds a liveness state and a credential source. It
does not change existing terminal verdicts.
- A server-environment token cannot resolve a private repository. This
is intentional. An operator who needs private repositories must add a
GitHub token as a company secret. The object then reports
`auth_required` with that instruction.
- `rate_limited` is a new value in `EXTERNAL_OBJECT_LIVENESS_STATES`. An
old client ignores an unknown value.

## Model Used

- Provider: DeepSeek (OpenRouter).
- Exact model ID: `openrouter/deepseek/deepseek-v4.1-flash`.
- Capabilities: tool use and code execution in the Paperclip runner.

## 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 similar open and closed PRs and
confirmed this is not a duplicate
- [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)
- [ ] 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
- [ ] 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

---------

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
2026-10-26 16:13:04 -07: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
DottaandPaperclip 507dc70be2 fix(evals): bind hosted controller admission to the first attempt (#17523)
Bind hosted controller admission to the repository, GitHub run, first attempt, workflow revision and selected execution before credential reads or provider launch. Keep offline evidence replay independent of the current worker environment. Preserve the single-project boundary editor and refresh project-access data with agent-detail updates.

Verified head: 1e588f75fe.
Validation: 74 synthetic source/portable controller tests, 98 focused UI tests and token gates passed before the ancestry-only final sync; four hosted/portable regressions pass again with unchanged eval and UI repair trees. Final exact-head full CI passed (40387856225), and Greptile reviewed this head at 5/5 with zero unresolved findings. The optional secondary Paperclip Review is paused and not counted as completed. No paid work or schedule changes.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-26 14:43:58 -05:00
DottaandPaperclip 5061ab7b35 perf(ui): speed up task and inbox cold opens (#17756)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task lists and inboxes are the main entry points to that work.
> - Cold opens fetch overlapping task lists, task descriptions, and run
details before useful rows settle.
> - Independent responses can insert rows above content that a person
has started to read.
> - This pull request loads a small task index first and adds details
only for visible rows.
> - It keeps row order and geometry stable while those details arrive.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Cold opens of Tasks and Inbox, including the shared navigation badge.

**Subsystem affected**

Server list reads, shared response contracts, and the React UI.

**Current behavior**

The badge fetches full task bodies. Mine fetches several overlapping
lists. Historical diagnostics and row metadata add work before the first
useful list. A fast failed-run response can appear before task rows,
then move down when tasks arrive.

**Proposed behavior**

Load the selected inbox source and its required context together. Use an
index without task descriptions or recovery diagnostics. Fetch
diagnostic details for up to 50 visible rows. Keep skeletons, recovery
indicators, external status, and live metadata in fixed space.

**Reason and benefit**

Reduce work on a cold open and prevent loading-induced row movement. On
the same 100 local fixture tasks, the compact response was 262,441
decoded bytes and the index was 110,909 bytes. This comparison excludes
compression and is not a page latency benchmark.

**Breaking changes**

Existing full and compact responses remain available. New index/row
projections are opt-in and marked as partial data. Mine keeps its
existing most-recent-100 display limit, now selected on the server.
Existing filters and group preferences remain in the client. No database
migration.

**Additional context**

Refs: #17593. Related: #13095, #17428, #13803. This change addresses
collection overfetch and layout stability. It does not replace the
blocked-inbox query work or the database activity-index work.

## What Changed

- Add authorized index and row projections, with bounded task and parent
ID batches.
- Replace badge list downloads with unread IDs and aggregate counts.
Preserve actor privacy, dismissals, and local archive behavior.
- Load only the selected inbox source, plus bounded parent and
failed-run context. Return only relevant failures from the bounded run
window.
- Batch hierarchy reads, including at most one authorized child per
collapsed parent in one request. Collapsed markers do not consume the
expanded row budget, and partial descendant counts are not shown as
totals. Enrich visible rows without replacing membership, ordering,
titles, or read state.
- Reserve row geometry on desktop and mobile. Reveal the initial inbox
only after its sources settle. Preserve legacy task-list reads.
- Start collection module downloads during access checks. Keep partial
rows out of the task-detail cache.
- Keep ETags and concurrent request sharing for the new projections, but
skip the short server response TTL so archive undo sees fresh state.

## Verification

- On final head `ef6afb2a56`, the full CI workflow passed, including
build, typecheck, server/workspace/runner suites, and all eight browser
shards. A server shard reported **1,489 passing tests** before runner
shutdown canceled the job; its single infrastructure retry passed. Both
Greptile and Paperclip Review are **5/5**, with zero unresolved review
threads.
- The optional external **Entire Gates** check remains `unassessed`
because it has no active assessed Change for this comparison. Entire is
not set up in this checkout. The repository ruleset requires `ci /
verify` and `ci / e2e`; both passed. No gate configuration was changed.

- Passed workspace typecheck after the final API batching change. The
full production build also passed on the final commit; the exact-retry
E2E run built the shipped UI.
- Passed token gates and map validation. The final batch-preview pass
has 91 passing route/hierarchy/component tests, including privacy,
request bounds, 30 collapsed parents in one read, and a 120-child parent
alongside a sibling.
- Passed the 166-test focused UI/inbox/badge run, 47 additional UI
regression tests, and 34 issue-list route tests. The latest regressions
cover low-trust agent badge IDs, cold company selection, 30
description-only Mine matches with archive actions, retrying optional
row details, and collapsed/expanded siblings.
- The full local `pnpm test:run` spanned the rebase and reported
failures in five suites before it was stopped; it is not claimed as a
complete pass. A fresh serial rerun of all five suites passed
**452/452** tests (tool gateway, native resume, project repositories,
workspace recovery, and runner selection). Full current-commit coverage
is checked by CI.
- Real browser: delayed index and row-detail responses on Tasks and
Mine. The first placeholder and first row had the same origin and
44-pixel height. Twelve rows on each page had zero position, height, or
title-width change after recovery details arrived.
- Real browser: reviewed long titles and recovery status at a 390 by 844
viewport. Task text stays on one line and recovery uses a compact
indicator.
- Three fresh document loads per page on final commit `260893bf92`, with
HTTP cache retained on a warm local development server: Tasks
1.031–1.190 seconds; Mine 0.999–1.193 seconds. Browser-control overhead
is included. These values must not be compared directly with staging
latency or the earlier local samples taken during a full test run.
- The browser archive test exposed stale results after Undo. The new
projections now bypass the server TTL; immediate-mutation regression
tests pass. The final browser retry passed: Archive followed by Undo
restored exactly one row and the badge count.

- CI exposed a hook-order crash when company selection resolved after
the first inbox render. The hook now runs before the empty-company
return. All seven affected exact-retry and legacy-continuation browser
scenarios pass locally after the fix.
- Real browser review regressions: 97 description-only source matches
retained Archive actions; deliberately failed optional row reads
displayed a retry notice while all 12 observed row positions and heights
stayed unchanged. Retry restored the recovery indicator. Network fault
injection was removed.

- The final production build and workspace typecheck passed. Final
focused verification passed 153 UI/helper tests and 26 heartbeat privacy
route tests. Final review regressions cover newer diagnostics arriving
during the index read, reloading diagnostics when the same task ID
changes version, optional source failure/retry without hiding available
rows, and required external-status filter failure. The latest-failures
route test verifies bounded selection, agent filtering, success
suppressing an older failure, and private-run redaction.
- Real browser: deliberately failed the run source, then retried it.
Twelve available task rows kept the same position and 44-pixel height
before, during, and after retry. No loading skeleton replaced them.
Fault injection was removed.
- Hierarchy review decision: the cold-open barrier stays because
inserting ancestors or expanded children after revealing index rows
would cause layout shifts. Existing hierarchy context now survives
subsequent requests, with a regression proving a new ancestor read does
not blank the list. The bounded recursive tree read can still add
latency for unusually deep expanded trees.

- Tasks now handles a failed external-status filter with an explicit
error and Retry, suppressing a false empty state. All 52 Tasks component
tests pass, including failure-to-success retry. One existing large-tree
test timed out while workspace typechecking ran concurrently; the whole
component suite passed when rerun without that competing work. Workspace
typecheck, the full production build, and token gates passed for this
fix.

## Risks

- Saved filters and grouping still operate on the existing bounded
collection. This is not a new global server pagination model.
- Fixed row slots reduce available title width. Long titles remain
accessible through task navigation.
- Recovery and related diagnostics arrive after core rows. Their
responses cannot replace ordering fields, and stale versions are
rejected.
- Index/row requests now revalidate against current data instead of a
short server TTL. They still share concurrent reads and use ETags.
- This has not been deployed by this pull request. Staging latency must
be measured after deployment under comparable conditions.

## Model Used

OpenAI Codex, GPT-6 family. The exact runtime model ID and
context-window size are not exposed in this session. Used code editing,
terminal execution, and real-browser diagnostics.

## 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-26 14:29:20 -05:00
DottaandPaperclip a67a18c171 fix(tasks): hide empty message history disclosure (#17751)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - Each task page shows the instruction and saved conversation.
> - Cold opens show recent content before older history.
> - The page used any linked run as evidence of older messages.
> - A task's first run therefore showed an empty More messages control.
> - This PR shows the control only when the preview omits comments or
runs.
> - Fresh tasks stay clear, and older task history remains available.

## Linked Issues or Issue Description

Refs: #17593.

**What happened?**

A fresh task with only its first run displayed More messages, even
though there was no earlier history to load.

**Expected behavior**

Show More messages only when older comments or runs are omitted. Runs
observed while the page stays open must not create a false disclosure.
The output control also uses actual skipped bytes, so a growing run does
not gain an empty output control.

**Steps to reproduce**

1. Create a task and let its first run start or finish.
2. Open that task with a fresh application cache.
3. Observe the empty More messages control below its instruction.

## What Changed

- Keep omitted-run evidence with the cached recent run window.
- Use omitted comments or runs to decide whether to show More messages.
- Preserve run retention, reconnect reconciliation, and expansion of
real history.
- Offer More run output when a single legacy log exceeds the compact
byte window.
- Keep first-run native diagnostics accessible through More task actions
→ Show task activity.
- Add regression coverage and update the task feature map.

## Verification

- Passed the existing 9,168-test UI suite across 794 files, then all 504
focused task-detail, history-window, real thread, and log-transport
tests after adding the activity-menu regression.
- Passed workspace build, workspace typechecks, token gates, and map
checks.
- Reproduced the bug in the earlier UI using a disposable local task.
The corrected UI hides the control with zero runs or only the first run.
- In the local browser, expanded a long task to all 80 comments. The
latest answer appeared once and the disclosure disappeared. No console
warnings or errors occurred in that journey.
- Expanded a saved 111 KB legacy log through More run output and opened
its earlier activity in the local browser.
- On a single saved native run, verified no More messages control. Used
Show task activity to reveal its earlier tool output; the latest answer
remained visible exactly once, with no console warnings or errors.
- The first broad local run stopped because the fresh dependency install
lacked PostgreSQL library symlinks. The normal package setup repaired
that environment issue.
- The next broad run hit one workspace-runtime timeout. Its focused
rerun passed with unchanged server source; the original failure remains
recorded. Stopped the already-failed broad runner after the previous
revision passed full PR CI. All final-head build, typecheck, test, and
policy CI jobs passed. Both automated reviewers scored the final head
5/5, with no unresolved threads. The separate Entire Gates check is
pending because the PR has no active assessed Change for its current
comparison. The installed Entire CLI reports no linked project trail and
exposes no Change-assessment command; no gate or repository settings
were altered. Browser verification used this branch's UI with the
existing disposable test-drive API. No agent execution was started.

## Risks

Low risk. This changes the recent run cache shape and the disclosure
condition. The full run cache remains an array. Tests cover first-run
states, observed new runs, omitted older runs, expansion, and reconnect
reconciliation. No schema or API changes. A separate run-output control
preserves access to a single truncated legacy log. The task menu
preserves first-run native activity access without implying older
messages exist.

## Model Used

OpenAI GPT-6 through Codex, with code execution and browser tools. A
more specific 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 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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 11:58:30 -05:00
Clément df5a78cf91 fix(ui): keep iPhone task chat stable while typing and streaming (#17232)
## Thinking Path

> - Paperclip keeps human-agent conversations attached to tasks.
> - People need to read and reply comfortably from a phone.
> - The mobile task page scrolled the document and positioned its
composer with a sticky navigation offset.
> - Safari's keyboard resize and later focus pan could move that
document again, causing overlap, gaps, and jumps while editing.
> - This change gives mobile and desktop the same message scroller and a
normal flex footer.
> - CSS owns the layout. A small VisualViewport adapter handles the
visible height and Safari's stale document focus scroll.
> - Streaming no longer measures every historical row while following
the bottom.

## Linked Issues or Issue Description

Fixes https://github.com/paperclipai/paperclip/issues/16497

Related: https://github.com/paperclipai/paperclip/pull/15245 also
addresses keyboard positioning. This change additionally removes mobile
document auto-follow and reduces historical-row measurement work.

## What Changed

### One scroll owner and a natural-flow composer

Before:

```text
Document scroll + mobile auto-follow
  └─ Conversation + sticky composer + animated navigation offset
```

After:

```text
Height-constrained conversation shell
  ├─ Header
  ├─ Message scroller — owns follow/reading position
  └─ Composer — normal flex footer
Navigation stays at the layout viewport bottom, behind the keyboard
```

- Reuse TaskMessageScroller on mobile. Delete the separate 136-line
useWindowAutoFollow implementation and its superseded tests.
- Keep the composer in normal flex flow. Remove its sticky bottom
positioning and navigation-offset animation.
- Constrain the mobile conversation with CSS. Classic tasks and other
pages retain their existing layout.
- Add a 47-line useMobileVisualViewport hook. It changes shell height on
resize, not on typing or incoming messages. It never translates the
shell or hides navigation.
- Reject Safari's stale document focus pan only for an unzoomed,
keyboard-open conversation. Inner message and editor scrolling stay
native.
- Keep a saved reading anchor when reading older messages. Skip
historical-row measurements while following the bottom.
- Update tests and the existing mobile streaming fixture. Keep only two
layout-contract sentences in DESIGN.md.

**Scope:** 19 files, +367 / -482 lines: 115 fewer lines overall.
Production UI/CSS alone is +158 / -190 lines. No API, database, or
dependency changes.

## Verification

Bottom-follow is also saved explicitly for Back navigation. A new
regression covers returning after rotation changes message wrapping,
without restoring historical-row scans.

### Physical iPhone acceptance

Tested on an iPhone 15 Pro running iOS 26.7.1. The reporter confirmed:

- Opening the keyboard positions the composer correctly immediately,
before any typing.
- The installed web app works.
- Long drafts, insertion, deletion, and sending are acceptable. The
reporter described long drafts as not perfect but good enough.
- Reading older messages during incoming output preserves position;
returning to the bottom resumes following.
- Rotation, keyboard close/reopen, and attachment/picker transitions
work.

Remote inspection corroborated the corrected open-keyboard state:
visible height 358px, composer bottom 358px, document scrollY 0.
Navigation remained display:block at y=631px, behind the keyboard.

Earlier candidates failed device testing. The decisive trace showed a
correct viewport resize followed about one frame later by a stale 337px
native document focus pan. Typing caused Safari to correct it. Tests now
cover that event ordering, the reverse ordering, and zoom panning.

### Performance evidence

The existing TaskChatPerfHarness supplied 200 historical responses,
4,000 collapsed tools, and 30 updates at 100ms intervals.

| Measurement | Before | After |
| --- | ---: | ---: |
| Historical row geometry reads | 6,000 | 0 |
| Renderer main-thread work | 331.2ms | 273.5ms |
| Largest task | 27.1ms | 12.3ms |

This is one instrumented Chromium development run on the Mac, not a
phone benchmark or a statistical speedup claim. The zero-row-measurement
result also has a regression test that failed with 6,000 reads before
the change.

To reproduce, serve ui/tests/task-chat-perf.html with the UI Vite
server. Record 30 streaming updates at the bottom. Inspect
TaskMessageScroller and row getBoundingClientRect calls. Existing
historical-render tests also confirm that unchanged Markdown does not
reparse on live-tail updates.

### Automated and full-app checks

- [Current-head
CI](https://github.com/paperclipai/paperclip/actions/runs/39862524031)
is green: 54 successful checks and 2 skipped checks. Greptile rates the
current head 5/5, confirms the Back-navigation fix, and has no
unresolved findings.

- **601 focused tests pass** across the task page, layout, composer,
scroller, viewport adapter, and historical-render coverage.
- UI typecheck and production build pass.
- Token gates, Storybook catalog checks, and catalog/map structural
tests pass.
- Independent review of the final source tree passed with no findings.
- The full source app ran on macOS with an isolated database and saved
conversation history. A reply sent through the real UI persisted after
reload. Provider execution was not part of this layout test.
- **Full local repository checks did not pass.** Build/typecheck stop at
missing Rust cargo. The full test run reported 142 failed server tests
and 3 failed suites; missing cargo is confirmed in those three suites.
The other server failures were not diagnosed in this UI task.
Current-head CI now supplies the repository-wide evidence; these local
failures remain disclosed.

## Risks

- Mobile conversations now share the desktop scroll owner. Navigation,
loading, history restoration, and reading-position tests cover that
change.
- The keyboard-state threshold is a 120px viewport reduction.
Accessory-only keyboards retain the normal navigation spacing.
- The document-scroll fallback is scoped to rendered conversations with
an open keyboard at scale 1. It does not handle inner scrolling or
prevent zoom panning.
- Long-draft behavior is accepted, with minor polish still possible.
- The UI change is reversible and requires no data migration.

## Model Used

OpenAI GPT-6 Astra, exact model ID gpt-6-astra, through OpenCode.
Capabilities used: reasoning, code editing, tests, Chromium performance
tracing, and Safari remote inspection. The harness does not expose the
context-window size. An independent general-purpose subagent reviewed
the final tree; its serving model ID was 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
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run focused tests locally and they pass; repository-wide
failures are disclosed 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
2026-10-26 08:44:39 -07:00
DottaandPaperclip d64cb7be52 fix(ui): identify accounts in AI connection choices (#17738)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent settings select an authorized AI account independently of the
harness and model.
> - Multiple accounts can have the same provider name.
> - The account picker and legacy adoption dialog showed only that name.
> - Operators could not distinguish a personal API key from a shared
subscription during credential repair.
> - This pull request shows the existing sign-in method, sharing scope,
and available account identity before selection and adoption.
> - Operators can select the intended account while the existing access
and validation checks remain effective.

## Linked Issues or Issue Description

Refs #14970 for the shared account selection control. No duplicate
account-identity repair was found.

**What happened?**

Two authorized OpenAI accounts appeared as identical `OpenAI` choices.
The adoption dialog repeated that ambiguous name. The list response
already contained the account method, scope, and identity, but the UI
omitted them.

**Expected behavior**

An operator can distinguish a personal API key from a company-shared
subscription and confirm the selected account before saving.

**Steps to reproduce**

1. Make a personal OpenAI API-key account and a shared OpenAI
subscription available to an agent. Give both the name `OpenAI`.
2. Open Harness / Runtime and choose a managed connection for a legacy
agent.
3. Inspect the two choices and the adoption confirmation.

**Paperclip version or commit**

Reproduced on master `a1f77821b9cd5c9c846fdf7a0fa5cc620ad2b6bb`.

**Deployment mode**

Hosted staging and the source UI regression.

## What Changed

- Show the sign-in method, personal/shared scope, and available account
or owner identity in connection labels.
- Use the same label in the selected value and legacy adoption
confirmation. Match the confirmation to both the connection and grant.
Wrap dropdown choices so narrow screens retain the account identity, and
expose the full selected label in the trigger title.
- Add a behavioral regression with duplicate provider names, exact grant
selection, and disabled unavailable accounts.
- Update affected Storybook interaction selectors, the account guide,
and the agent verification recipe.

## Verification

- Before the fix, the new regression fails because duplicate accounts
have no distinguishing metadata. The other 13 field tests pass.
- After the fix, all 67 tests in `ui/src/components/ai-connections`
pass. The regression selects the exact personal grant and keeps the
unavailable option disabled.
- `pnpm -r typecheck` and `pnpm build` pass locally. The full `pnpm
test:run` command was stopped after embedded PostgreSQL failed to
initialize after five attempts in an unrelated native-runtime suite. Its
log is retained. Current-head CI partitions must establish full test
coverage.
- Token gates, map checks, Storybook catalog checks, and all 30
map/catalog contract tests pass.
- In local Chrome, the existing production-component Storybook dropdown
shows method and scope. Its nine interaction steps pass, as do all 19
steps in the new-agent connection-modes story. At a 320-pixel preview
width, two shared OpenAI subscriptions show their distinct account
identities in full, including during keyboard selection. These fixtures
do not establish provider authentication.
- Separately, the staging credential-repair workflow validated an
existing authorized shared OpenAI connection, persisted the agent
binding across reload, and resumed the original task into real
provider/tool execution. This configuration recovery does not deploy
this UI patch or establish task completion.
- All CI completes on final head
`a283bda2ad2f026f4f3c0fee03bf2962b0ad6e02`: 55 successful checks, the
neutral Paperclip review, and two intentionally skipped Storybook
checks; no pending or failed checks. This includes the partitioned
tests, typecheck, build, runner suites, canary, and eight browser
shards. Greptile and Paperclip review both rate this exact head 5/5 with
no unresolved findings. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/40338613167).
- The review's selected-trigger truncation finding is fixed in the final
head. Its title assertion failed before the fix, and all 67
account-selection tests, UI typecheck, and token gates pass afterward.

## Risks

- Labels are longer and can truncate in narrow selected-value controls;
the trigger title exposes the complete label. Dropdown choices wrap, and
the adoption dialog uses the complete label.
- The UI uses existing authorized account metadata. It adds no
credential reads, access grants, provider fallback, or account selection
policy.

## Model Used

OpenAI Codex (GPT-6). The exact serving model identifier and context
window are not exposed in this session. The agent used code editing,
terminal tests, and browser 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-26 10:28:59 -05:00
DottaandPaperclip a1f77821b9 perf(tasks): show recent conversation before historical activity (#17593)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A task page must show the instruction and current conversation
quickly.
> - The current page waits for related task data and historical run
transcripts.
> - These reads grow with task history, even when the reader only needs
the latest answer.
> - This pull request gives cold opens a small initial view and loads
older history on demand.
> - Messages and runs observed while the page stays open remain visible.
> - The benefit is a readable task before historical diagnostics finish
loading.

## Linked Issues or Issue Description

Related: #14667 and #16229. The first changes the reveal gate and scroll
anchors. The second adds general history pagination. This PR adds a core
task read and a folded recent-conversation view. It preserves the
default full-read API contracts. The shared files will need coordination
if either related PR lands first.

**What existing behavior does this improve?**

Cold opening an ordinary task with a long conversation or large run
logs.

**Current behavior**

Task enrichment and historical transcripts delay the readable
conversation. A cold open can fetch several megabytes of tool activity
before revealing saved messages.

**Proposed behavior**

Show the task instruction, recent saved replies, latest human input, and
the latest run's conversation data first. Fetch older messages and full
run activity when the reader chooses **More messages**. Retain new
messages while the page stays open.

## What Changed

- Add an authorized core issue view that skips related enrichment. Keep
enrichment on the existing detail read. Share task mutation, rollback
and invalidation updates with the core cache.
- Add a bounded recent-comment read. Preserve the first human
instruction when no description exists, including legacy rows with a
NULL author type. Keep company and task access checks and comment
redaction.
- Add optional recent activity and run-summary views. Fetch original
input receipts for visible comments separately so delivered messages
stay out of the queue. Reconcile watched unfinished runs after a
reconnect beyond the preview window, removing deleted runs after
reconciliation.
- Filter the latest native run's initial events to assistant messages,
request lifecycles and terminal results. Full event reads remain
available on expansion. Legacy fallback reads use a small tail extended
to the first complete record. HTTP cancellation aborts the storage read.
- Retain observed messages across cursor catch-up and new runs. Apply
local cancellation and deletion to both caches and their task aliases.
Refetch locally seeded history pages on expansion. Preserve expansion
across identifier and UUID links. Keep deep links, classic tasks and
Agent Chat on their existing full-history path.
- Update API documentation, design guidance, capability maps and
regression coverage.

## Verification

- Final acceptance on `9ea0b15ae44d9f6d2c9a9f824b4835f299f92979`: all CI
gates passed, including server/UI tests, all eight browser shards,
runner checks, full typecheck and build. [Final CI
run](https://github.com/paperclipai/paperclip/actions/runs/40326990328).
GitHub reports 55 successful checks, two intentionally skipped checks,
and one neutral Paperclip Review check described below. No checks are
pending or failed; Greptile is 5/5 and no review threads remain open.
- October 26 merge update: merged current `master`. The only conflict
was in task-page imports; both the compact-history hook and the new
live-update hooks remain. All CI tests and build jobs passed on
`044fd6733d`. Fresh review found canceled-comment cache drift, legacy
human-comment filtering, send-then-expand truncation, and partial legacy
log records. These defects were fixed in `af3d66a5bd`.
- Review-fix verification: 470 tests pass across ten affected suites,
including all six PostgreSQL cold-open tests without a helper override.
Cancellation/delete and send-then-expand regression tests failed before
the fixes and pass afterward. Coverage includes task identifier/UUID
reopen, stale in-flight reads, legacy NULL author types, local-file and
object-storage tails cut inside UTF-8 text, route forwarding, and
request cancellation. Full workspace typecheck and production build,
token gates, map validation and diff checks pass.
- Follow-up review found that a failed expanded legacy read lost its
record-alignment state on retry. `9ea0b15ae4` commits the expanded
window only after a successful read. The new regression fails before the
fix and passes afterward; all 19 transcript tests, UI typecheck, UI
build and token gates pass. Greptile reviewed this commit at 5/5 with no
actionable findings, and all review threads are resolved.
- The final Paperclip Review check ended neutral because its execution
did not complete; no passing Paperclip assessment is claimed. Its
earlier four concrete findings were fixed and regression-tested.
Greptile and the security scans completed successfully on the final
commit.
- The preceding `af3d66a5bd` CI run was canceled when superseded by the
retry fix. Its server shard 11 check briefly reported failure, but the
job API records cancellation and its test step passed all 1,750 tests.
This superseded run is not used as final CI acceptance.
- 549 focused tests pass on the final implementation across nine task
UI, activity-route, OpenAPI and PostgreSQL suites. These cover pending
history, desktop/mobile visibility, expansion, retained runs, message
bursts, cancellation recovery and queued-comment removal in both views.
- Legacy expansion keeps the latest answer visible while fetching and
deduplicating older output.
- Five PostgreSQL tests pass for core access denial, recent comments,
missing-description instructions, event paging and bounded activity/run
reads. macOS could not start another PostgreSQL cluster because it
exhausted its semaphore limit. These tests used a separate disposable
database on an existing local server through a temporary test setup
override. The helper was restored afterward.
- Full workspace typecheck and build pass with the final state fixes, as
do token gates and capability-map validation.
- Token gates, capability-map validation and `git diff --check` pass.
- Browser proof used a disposable task with 80 comments and six large
run histories. The cold view showed the instruction and recent exchange.
**More messages** revealed older comments. Navigation away and back
preserved expansion.
- Local HTTP sample: core 50 ms, recent comments 24 ms, recent run
summaries 17 ms. The latest native conversation response was 839 JSON
characters / 8 ms; its full event response was 1,099,005 / 86 ms.
Browser content paint was 1.34 seconds with development assets cached.
These are local observations, not staging latency claims.
- The first CI run passed every job except four board-send browser cases
and the review threshold. Those browser fixtures only mocked the old
comments endpoint; they now serve both recent and full reads, retaining
all message and attachment assertions. Both initial review findings were
fixed with regression tests. The next CI run passed every job. The
deeper review identified core-cache mutation, older delivery receipt and
retained run-status gaps; those are now fixed with regression coverage.
Final review is 5/5 with zero unresolved findings. Final-head CI
initially failed one unchanged runner shutdown test
(`runnerd-codex-transport.test.ts`, timeout-attachment case) with
`NativeSessionCloseUnrecoverableError`; all other CI jobs passed. The
same runner code passed on 971a762f80. A targeted local reproduction
also failed during provider drain. The failure is outside the changed
task loading paths; its underlying cause remains unresolved. The single
failed-job retry passed on the same head; this demonstrates recovery,
not a root-cause fix. All CI gates passed on the previous implementation
head `9004f94f28`: [CI run and
retry](https://github.com/paperclipai/paperclip/actions/runs/40192334629).
- `pnpm test:run` was attempted and stopped after repeated embedded
PostgreSQL startup failures. The native session suite recorded 15
database-related failures; other database suites could not start. No
complete local suite pass is claimed.

## Risks

- The compact view intentionally omits older diagnostics until
expansion. Existing open questions and approvals still use the current
interaction and run paths.
- Previously observed comment and activity rows remain cached while
open. The newest preview and incoming cursor pages refresh; this does
not add a general historical-edit synchronization protocol.
- Recent views are optional. Existing full API callers retain their
response shape and behavior. No migration is required.
- A legacy tail can exceed the requested byte limit by the prefix of its
first log record. Backward reads stop at the preceding record boundary
and honor cancellation.
- Staging has not been deployed or qualified with this change. Instance
startup latency is separate from task history loading.
- The related open PRs touch the same task-history files.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository editing, shell
tools and browser testing. 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 — 549 affected task tests;
the full local suite and unrelated runner failure are documented 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-26 08:11:39 -05:00
DottaandPaperclip 5d2515e520 Simplify agent harness configuration choices (#17722)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Users choose a harness in agent setup and configuration.
> - Supported harnesses already determine their native Runner profile.
> - A second ACP agent selector lets users make a conflicting choice.
> - The harness list also shows unavailable options marked Coming soon.
> - This PR removes these extra choices and keeps each harness's
settings.

## Linked Issues or Issue Description

Refs #17142 and #17120. Related runner defaults work: #15422.

**What existing behavior does this improve?**

The Harness dropdown and native agent configuration form.

**Current behavior**

A Pi or Claude agent shows an ACP agent selector below Harness. Users
can select a different agent in that second control. The Harness list
also includes disabled Coming soon entries.

**Proposed behavior**

Use Harness as the only agent choice when it determines the Runner
profile. Hide unavailable entries from its list. Keep the generic
advanced Runner selector available where no parent harness determines
the profile.

**Reason and benefit**

Users choose the harness once. The form no longer offers a conflicting
ACP agent choice or an option they cannot use.

**Breaking changes**

No API or stored configuration changes. Unavailable harnesses are
omitted from the list; existing saved values still display.

## What Changed

- Hide the ACP agent selector when the parent Harness control determines
the Runner profile.
- Remove Coming soon options and their unused disabled-state rendering
from the Harness dropdown.
- Preserve saved Process and HTTP selections during unrelated edits
while omitting them from new choices.
- Document the field visibility contract.
- Cover new and saved Claude, Pi, Codex, and OpenCode forms. Check that
Pi thinking controls remain and an unrelated name edit does not rewrite
Runner configuration.

## Verification

- Passed after rebasing onto master: 199 tests across
AgentConfigForm.render, codex-local/config-fields, and adapter config
sections.
- Passed: UI TypeScript check, UI production build, token gates, and git
diff --check.
- Live browser verification passed for the Pi configuration page before
and after rebase. Harness remains Pi, ACP agent is absent, and the
original model and thinking level remain. The open Harness list contains
no Coming soon, Process, or HTTP entries.
- Dropdown regression cases open Harness, check the supported options,
exclude Coming soon/Process/HTTP options, and preserve saved Process and
HTTP configuration through a name-only save.
- Passed on final commit b60a02387f: all 57 check runs are terminal and
clean (53 success, 2 neutral, 2 skipped). The Snyk status is successful.
Greptile and Paperclip review both give 5/5, with no unresolved review
threads.

## Risks

- Low risk: this change only removes redundant or unavailable UI
choices. Runner routing and saved settings keep their existing
contracts.
- The advanced generic Runner form retains ACP profile selection. It has
no parent harness choice to determine that profile.
- No new agent task or provider call was needed to verify these form
changes.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code editing, command
execution, and browser use. The exact serving 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 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-26 08:11:17 -05:00
DottaandPaperclip 5cea9c7c0e fix(ui): show eligible wake targets when resuming tasks (#17521)
## Thinking Path

> - Paperclip manages agents and their assigned tasks.
> - A task pause controls execution without changing task status.
> - Resume can remove that pause and request work from eligible
assignees.
> - The preview counted blocked tasks and former executors as wake
targets.
> - The release route correctly skipped those targets, so the dialog
promised work that did not start.
> - Resume also trusted stale pause snapshots after tasks were reopened.
> - This PR aligns preview with execution eligibility and rechecks
current task state when releasing a pause.

## Linked Issues or Issue Description

**What happened?**

Pause an assigned blocked task, then open Resume. The dialog says that
one task will resume and offers to wake one agent. Applying it only
removes the pause. The route skips blocked and backlog tasks. A former
executor can also inflate the wake count after reassignment.

**Expected behavior**

The dialog must distinguish removing a pause from starting work. Its
wake count must use the current assignees and statuses accepted by the
release route. Blocked work must stay blocked.

**Steps to reproduce**

1. Open an assigned blocked task.
2. Choose Pause work, then Resume task.
3. Inspect the wake count and apply Resume work.

Related runtime recovery work is tracked separately in #17097 and
#17439. This PR does not change remote execution recovery.

## What Changed

- Share the resume status list between preview and release. Count only
current assignees on todo, in-progress, and in-review tasks for resume
wakes.
- Explain that Resume removes the pause. Show the existing preview
warnings, including tasks that remain idle.
- Disable and uncheck the wake option when no agents qualify. Send the
same choice to the server.
- Reevaluate previously skipped pause members after reopening or
releasing another hold. Retain active-pause and unsafe-execution guards.
- Add real PostgreSQL and HTTP-route regressions plus browser coverage
for both task interfaces. Keep draft, ancestor-pause, and
Stop/reconciliation coverage.
- Update the task coordination maps. Add an opt-in dedicated test
database URL for hosts where embedded PostgreSQL cannot start.

## Verification

- Final head `9548eb16736f632cc111a5c13a9a994ec1d95a13`: all 55
completed checks pass, with two optional Storybook checks skipped. [CI
40188094904](https://github.com/paperclipai/paperclip/actions/runs/40188094904)
passes, including typecheck, build, all general/serialized suites, and
all eight E2E shards. Greptile is 5/5 on this commit; the reopened-task
finding is fixed and resolved.
- Red: the real PostgreSQL regression receives three agents instead of
the one eligible current assignee on the original code.
- Green: all 27 tree-control service, route, and unit tests pass. They
cover current assignees, blocked/backlog exclusions, reopened tasks,
company boundaries, remaining pause holds, and execution blockers.
- The reopened-task route regression fails on the previous
implementation: skipped members never reach preflight/wake, and an
unsafe replay releases the hold instead of returning 409. All cases pass
with the fix.
- Browser: all five applicable cases pass together (90 seconds):
blocked-work resume in both interfaces, draft/ancestor-pause cases in
both interfaces, and the process
Stop/pause/reconciliation/restart/cancel lifecycle. The optional
native-runner fixture is skipped locally because its fixture binary is
not configured.
- All 157 task-page component tests pass on the prior commit; subsequent
changes affect the server route and Stop fixture only.
- `pnpm -r typecheck` and `pnpm build` pass before rebase, and CI
typecheck/build passed on the previous PR commit. Server typecheck
passes again after the route fix. The final-head CI run also passes
these full checks.
- `node scripts/check-maps.mjs`, `node scripts/check-token-gates.mjs`,
and `git diff --check` pass.
- Full `pnpm test:run` was attempted but did not complete: this host
cannot initialize embedded PostgreSQL, and unrelated workspace-runtime
tests timed out. The focused database tests and E2E suite use disposable
PostgreSQL 18 instead. All general-test and serialized-test CI shards
passed on the previous PR commit; the final-head CI run also passes
every test shard.
- The first CI run caught the existing Stop test trying to check a
disabled wake option for blocked legacy work. It now asserts zero wake
targets and retains the no-execution-before-reconciliation checks.
- Earlier E2E attempts exposed fixture problems: assignment started the
fixture before it was paused, and the classic interface had two matching
editor nodes. The fixture now enables dispatch after the hold exists and
scopes the final assertion to the task composer. No product assertion
was removed.

## Risks

Resume preview is a snapshot. The release route still checks current
status, assignment, and execution blockers. It does not bypass approval,
budget, or recovery gates. Pause, cancel, and restore keep their
existing affected-agent semantics. The test database override only
accepts a dedicated database name ending in `_test`; it runs migrations
before the suite and closes its clients afterward.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, browser
control, and code execution. The runtime does 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-10-25 21:49:52 -05:00
Devin FoleyandPaperclip e335265568 fix(ui): stop idle task run polling with live updates (#17608)
Stop successful empty assigned-task run queries from polling only while the matching company and session connection is open. Preserve active, pending, failed, and disconnected cadence. Share one lifecycle refresh owner between the task and chat views, discover reviewer events without task identity, and refresh after older in-flight reads settle.

All 175 focused tests, 9,079 UI tests, build, typecheck, exact-head Greptile 5/5, and required CI pass. Regression mutations catch reviewer discovery, duplicate reads, readiness, failure state, missing refreshes, and scope cleanup. Earlier E2E cleanup deadlock and server cleanup timeout remain documented; failed-only reruns passed on their same commits.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 07:54:47 -07:00
Devin FoleyandPaperclip 6aa711f6c6 fix(ui): avoid broad task refreshes after known run progress (#17602)
Use the existing live-status cache patch result to skip redundant task and history reads. Keep unknown-run discovery, lifecycle, activity, visibility, and reconnect recovery.

Verified with full build and typecheck, 9,047 UI tests, final context tests and counterfactual broad-refetch and missing-fallback failures, complete exact-head CI, and Greptile 5/5 Medium with no unresolved comments.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 06:04:09 -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
DottaandPaperclip f66d590899 fix(ui): open the new-task form immediately (#17041)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - People use New task to send work to an agent.
> - The board currently downloads the task dialog code after the first
click.
> - This shows a loading window before people can enter their request.
> - The form already loads agent and project choices after it opens.
> - This pull request loads the task dialog code with the board.
> - People can start writing immediately and keep their text as choices
arrive.

## Linked Issues or Issue Description

Related change: #16849. Commit
`fa50cab5685b9cdbb26ad9c610cc5b6c373d3ff4` added the deferred dialog and
its loading window on October 19, 2026.

**What happened?**

The first New task click shows “Loading new task…” while the browser
downloads the dialog code.

**Expected behavior**

The form opens on click. Agent and project choices load in place. Text
entered during those requests stays in the form.

**Steps to reproduce**

1. Open the board in a fresh browser session.
2. Select New task before its code is cached.
3. Observe the loading window before the form appears.

**Paperclip version or commit**

Source baseline: `8b4ab65b1c3d863d282752e83307943720a5c85c`.

**Deployment mode**

The browser code applies to local and hosted boards. Verification used a
source checkout.

## What Changed

- Import NewIssueDialog with the board. Keep the existing mount and
draft lifecycle.
- Add a first-open test that fails if the form waits for an asynchronous
render.
- Cover text entry during delayed agent and project requests and
defaults that arrive later.
- Document the behavior and its verification recipe.

## Verification

- Regression proof: the first-open test failed before the import change
and passed after it.
- All 125 tests in BoardDialogs, DeferredOverlay, NewIssueDialog and
Layout passed.
- The production UI build and UI TypeScript check passed. The typecheck
passed with `NODE_OPTIONS=--max-old-space-size=2400` after the competing
test process was stopped.
- Token gates, map validation and Git diff checks passed.
- The first UI typecheck could not resolve the unbuilt local plugin SDK.
The SDK was then built.
- Full typecheck and build attempts hit the sandbox's 4 GB memory limit
when run with the full test suite. Two later UI typecheck attempts also
hit that limit during other validation. The cgroup recorded four OOM
kills in total. The full repository test attempt and a broader UI test
attempt were stopped. No complete suite result is claimed. Serial
repository typecheck reached the missing Rust `cargo` executable. Full
CI passed on head `9dde4bc`; local limits remain recorded here.
- First CI run at `e5a99b8`: typecheck, build, all unit-test shards and
seven browser shards passed. Browser shard 2 failed at
`chat-adapters-ui-providers.spec.ts:185`, waiting for Slack setup
Success after reload. The saved page showed the working connection and
Continue button. The cause is not confirmed; this failure is retained
for follow-up. [Failed
job](https://github.com/paperclipai/paperclip/actions/runs/39522214527/job/118968542923).
- Removed the added import comment after Greptile review. Head `9dde4bc`
changes only that comment. The review thread is resolved. Fresh CI
passed on head `9dde4bc`. Greptile reviewed that exact head at 5/5 with
no open findings. All eight browser shards passed, including the earlier
Slack failure. The earlier failure remains unexplained; the only
intervening code change removed a source comment. A passing retry
establishes recovery, not its cause.
- Component tests use mocked directory requests. No deployed latency or
browser persistence claim is made.

Latest CI: [run
39523376437](https://github.com/paperclipai/paperclip/actions/runs/39523376437).
Reviewed head: `9dde4bc0caa3556e315a2fc197268b7c9879efa4`.

## Risks

- Task dialog code is part of board startup again. This adds its
dependencies to the initial code graph. No startup latency benchmark is
claimed.
- Other creation dialogs retain their existing lazy imports and loading
behavior.

## Model Used

OpenAI Codex, GPT-6, with reasoning, repository tools and code
execution. The runtime does not expose a more precise 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-10-24 08:15:35 -07:00
DottaandPaperclip 87bf89756e fix: support Daytona runner upgrades and ignore obsolete Claude options (#17361)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Existing Claude and Codex agents can upgrade to Paperclip Runner.
> - A Daytona computer needs platform qualification before Runner
becomes its default.
> - The upgrade notice required that default, so it hid the action that
could start qualification.
> - Saved Claude turn limits also caused conversion to fail even though
Runner can run without them.
> - This pull request verifies the computer on click and ignores
obsolete Claude options with a warning.
> - Agents retain their model, account, environment, instructions, and
permission policy.

## Linked Issues or Issue Description

Related: #17122.

**What happened?**

A legacy Claude agent on a Daytona snapshot had no upgrade button until
its environment had platform qualification. A saved `maxTurnsPerRun:
1000` then caused conversion to return HTTP 422.

**Expected behavior**

The upgrade action verifies a supported Daytona computer and converts
the agent. Unsupported tuning options produce a visible warning and do
not block execution.

**Steps to reproduce**

1. Create a legacy Claude agent with `maxTurnsPerRun: 1000` on an active
Daytona snapshot.
2. Open Runtime before the environment has platform qualification.
3. Try to upgrade to Paperclip Runner.

**Paperclip version or commit**

After #17122, reproduced against `9c442cf48e`.

## What Changed

- Offer upgrade on probe-capable Daytona snapshots and immutable sandbox
images. Perform the public environment probe only after a click. Save
after fresh adapter discovery confirms support.
- Resolve the actual computer for explicit, instance-default, and hidden
managed environments. Preserve pending edits and reject stale probe
results.
- Ignore Claude `maxTurnsPerRun`, `chrome`, `warmHandleIdleMs`, and
`acpWarmHandleIdleMs`. Return structured warnings from create, hire, and
update. Show warnings in Runtime and after a save.
- Keep validation for commands, credentials, filesystem, network, and
permission settings.
- Retain the legacy turn limit in the existing live conversion fixture.
Update regression tests, upgrade stories, and capability maps.

## Verification

- Red: the old route returns HTTP 422 for the saved turn limit; the old
form hides the Daytona upgrade notice.
- Green: 417 focused server and form tests pass. A further 188 tests
pass after the review fixes. Qualification coverage includes failed
probes, unsupported targets, changed settings, managed defaults, unsaved
environment variables, and forced Kubernetes targets.
- `pnpm -r typecheck` and `pnpm build` pass. Token gates, map checks,
map tests, and Storybook catalog checks pass.
- Real local Claude Opus 5.5 conversion and task pass, with the
downloaded artifact checked against seeded source bytes, SHA-256, and
Git commit.
- Real browser upgrade and full Claude Opus 5.5 task on a disposable
named Daytona snapshot pass at `b81cec7d8c`. The saved agent retains its
model, high effort, credentials, timeout, and grace settings while
dropping the turn limit with a visible warning. Exactly one successful
run completed the task. The downloaded artifact matched independently
seeded source bytes, SHA-256, and Git commit; the source was unchanged,
no interactions remained pending, and the delivery link survived a
browser reload. The snapshot used current runtime assets built from
public source. The supplied Daytona account could not access the
original staging snapshot, so this verifies an equivalent local fixture
rather than that exact snapshot. Disposable test resources were cleaned
up.
- Earlier live attempts remain recorded: an image-based sandbox creation
failed, and the first named-snapshot probe returned failure with
unresolved provisional cleanup identity. Later named-snapshot probing
and the task succeeded; the initial creation failures are not attributed
to this PR or declared resolved. A separate attempt using the Oct 18
cached runtime failed the current provider-pack compatibility check;
rebuilding the runtime from matching public source removed that
mismatch. Owned resources were identified and cleaned up, with
diagnostic databases retained.
- 54 checks passed at `b81cec7d8c`, with no failed checks; Greptile and
Paperclip Review both scored 5/5, with both review threads resolved.
Master advanced during the live proof, so the branch was rebased with
both sides of additive import/test conflicts retained. On the rebased
head `2b74222b94`, 472 focused tests, UI typecheck, and UI build pass.
All required CI gates pass; Greptile and Paperclip Review both score 5/5
on this head, with no unresolved review threads. The PR is mergeable.
The serial local `pnpm test:run` was stopped after the CI test lanes
passed; that local run is not claimed as a pass.

## Risks

- An explicit upgrade can allocate a temporary probe sandbox and take
several minutes. Probe failures leave the agent on its existing runner.
- Ignored options no longer enforce a turn cap, Chrome integration, or
legacy idle-time tuning. The UI warns about each active ignored option.
- Unsafe or ambiguous execution settings still fail validation. This
change does not weaken environment qualification or runtime artifact
checks.

## Model Used

OpenAI Codex, GPT-6, with reasoning, code execution, and browser tools.
The exact deployment 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 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 07:59:18 -07:00
e0d90339bf fix(runner): make task-capable plugin environments Runner-only (#17380)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - An environment plugin can run Paperclip Runner tasks through a
`driver: "plugin"` environment.
> - Core lets only the `paperclip_runner` adapter use a plugin
environment.
> - A Claude agent cannot get onto the Runner there. Runner selection
needs a reported platform for Claude, and a plugin target reports none.
> - The adapter Test route also checks the driver against the requested
harness before it resolves the runner.
> - This pull request makes task-capable plugin environments Runner-only
and checks the Test driver after runner selection.
> - The benefit is that Claude and Codex agents can use a Runner task
environment, and the UI cannot produce a legacy agent there.

## Linked Issues or Issue Description

Refs #17029. Refs #16978.

**What happened?**

A Claude Code agent with a plugin environment that runs Runner tasks
fails the connection test. The error is: `Environment driver "plugin" is
not allowed here. Allowed drivers: local, ssh, sandbox`. The Runner
selector in Advanced shows Paperclip Runner as unavailable, so the user
cannot fix the agent in the form.

**Expected behavior**

A Claude or Codex agent on that environment uses Paperclip Runner. The
connection test passes the driver check. Legacy is not offered, because
a legacy adapter cannot run on a plugin environment.

**Steps to reproduce**

1. Install an environment plugin whose driver declares `supportsTasks:
true`.
2. Create a plugin environment for that driver.
3. Open an agent with the Claude Code harness and select that
environment.
4. Click Test. The test fails with the driver error above.

**Agent adapter(s) involved**

Claude Code, Codex (through Paperclip Runner).

**Additional context**

Two gates caused the failure:

- `agentRunnerAvailability` requires a platform for `claude_local`. A
plugin target is `{ driver: "plugin" }`, so Claude resolves to Legacy.
- The Test route ran `assertAdapterTestEnvironmentForCompany` with the
URL adapter type before `resolveNewAgentRunnerForCompany`. The plugin
driver is allowed only for `paperclip_runner`, so the check failed
before selection could change the adapter.

## What Changed

- Runner target resolution marks a plugin environment as `runnerTasks`
when its plugin manifest declares `supportsTasks` for the driver key and
has the `environment.drivers.register` capability. The check reads the
manifest only. Run admission still verifies a ready plugin and a live
worker.
- `agentRunnerAvailability` returns Paperclip Runner as the only runner
for a `runnerTasks` target. It skips the platform check, because the
plugin provisions the host and launches its own pinned Runner. Harnesses
that the Runner does not support keep the Legacy result.
- The adapter Test route runs the company-binding check first, as
before. It runs the driver check after runner selection, with the
resolved adapter type. The driver check still runs before secret
resolution, leases, and the adapter probe.
- A saved adapter that cannot run on the requested environment no longer
keeps its saved execution in the Test route. It re-resolves its runner.
- `assertAdapterTestEnvironmentBinding` is a new helper that holds the
binding half of the guard. `assertAdapterTestEnvironmentForCompany`
keeps its behavior and calls it.
- The agent form switches a Legacy runner choice to Paperclip Runner
when the selected environment offers no Legacy runner. The test and the
save then send the Runner choice.
- `docs/specs/agent-config-ui.md` records the Runner-only rule and the
Run test order.

## Verification

- `pnpm --filter @paperclipai/server exec tsc --noEmit` passes.
- `pnpm --filter @paperclipai/ui exec tsc -b` passes.
- Server suites pass: `agent-runner-selection.test.ts`,
`agent-test-environment-routes.test.ts`,
`agent-permissions-routes.test.ts`,
`environment-selection-route-guards.test.ts`,
`agent-harness-verification.test.ts`,
`plugin-runner-task.integration.test.ts`, `adapter-routes.test.ts`,
`adapter-auth-signal-routes.test.ts`,
`agent-adapter-validation-routes.test.ts`,
`agent-hire-ai-connections.test.ts`.
- UI suites pass: `AgentConfigForm.render.test.tsx` and
`NewAgent.test.tsx`.
- New tests cover these cases:
- A task-capable plugin target offers only Paperclip Runner for Codex
and Claude.
  - Claude saves as `paperclip_runner` with ACPX on that target.
- A driver without `supportsTasks`, a different driver key, a missing
capability, an unknown plugin, or a malformed config keeps the existing
plugin target.
  - The Test route checks the driver against the resolved adapter.
- The Test route still rejects a plugin environment for a legacy
adapter, before any secret resolution.
- A saved adapter re-resolves only when it cannot run on the requested
environment.
- The form switches a saved or new Legacy choice to Paperclip Runner on
a Runner-only environment.
- I ran the new route and form tests against the old code. They fail
without the change.
- The full server `typecheck` script did not complete locally. Its
Runner vendor step needs `cargo`, which this machine does not have. CI
runs the full script.
- I did not run a live plugin environment end to end.

## Risks

- Behavior change: Codex on a task-capable plugin environment now offers
only Paperclip Runner. Before, the selector also showed Legacy, but Core
rejected a legacy save on that environment. No working setup loses an
option.
- The `runnerTasks` decision reads the plugin manifest. If the plugin is
down, the agent still selects the Runner, and the run fails at admission
with the existing plugin error.
- The adapter auth-signal route still checks the driver with the
requested harness. This PR does not change that route.
- An explicit Legacy save through the API on a Runner-only environment
still fails with the existing driver error. The UI no longer offers that
choice.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`) wrote the change and the tests in
Claude Code, with shell, file editing, and local test runs.
- Claude Fable 5.1 (`claude-fable-5-1`) did the earlier diagnosis in the
same session.
- The session does not expose 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
- [ ] 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: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 15:21:09 -07:00
DottaandPaperclip 4d90634f74 feat(connections): add 1Password service-account connector (#17249)
## Thinking Path

> - Paperclip lets people manage AI agents and govern their access to
outside services.
> - Apps connections keep provider credentials in the instance vault and
mediate every action through grants, policies, and audit.
> - Agents currently have no Apps connection for reading or managing
1Password items with an operator-supplied service-account token.
> - 1Password supports this through its official SDK; its documentation
MCP server does not expose vault operations.
> - This pull request adds a one-field service-account connection and
registers eight reviewed SDK actions through the existing
native-provider catalog.
> - Operators can select vault permissions in 1Password and agent/action
access in Paperclip without installing a CLI or handing durable
credentials to agents.

## Linked Issues or Issue Description

Related: #16144 adds 1Password as Paperclip's secret-storage backend.
This PR adds the separate Apps/tool-access flow with a per-connection
credential; it does not change secret providers or use a server-wide
ambient token.

**Subsystem affected**
Apps catalog, native tool-provider registry, and shared connection
setup.

**Problem or motivation**
People need to paste their own `OP_SERVICE_ACCOUNT_TOKEN`, find official
service-account setup instructions, and authorize agents to use the
selected vaults through ordinary Paperclip governance.

**Proposed solution**
Add `1password/service-account`, with a password field labeled **Paste
your 1Password Service Account token** and a link to [1Password's
creation
instructions](https://www.1password.dev/service-accounts/get-started#create-a-service-account).
Use the pinned official `@1password/sdk` 0.5.0 for vault/item listing,
item and secret-reference reads, and item create/update/archive/delete.

**Alternatives considered**
A remote MCP card would not provide vault access. A local CLI or a
third-party MCP package adds installation and credential surfaces that
the official SDK avoids.

## What Changed

- Added the source and generated catalog definition, permission review,
official light/dark artwork, documentation, and capability-map
references.
- Added a provider-owned SDK bridge with strict schemas, account-domain
validation, contract hashes, fixed errors, bounded output, and
disposable workers with cancellation/deadlines.
- Registered the provider through master's native-provider catalog;
existing setup, health, discovery, gateway, policy, and audit owners
remain in place.
- Labeled the single password field **Paste your 1Password Service
Account token**. The shared formatter preserves explicit credential
prompts; ordinary key labels retain their existing presentation.
- Added credential-ownership, gateway read/write, policy/revocation,
worker, setup UI, and interactive Storybook coverage.

## Verification

- Final review follow-up: added two deterministic worker-entry tests for
nested exact-token redaction and oversized-output rejection. Removing
each guard caused exactly its regression test to fail. The focused
provider suite passed **15 tests**, and the official server typecheck
passed after rebuilding stale workspace SDK artifacts. Current head
`569cb7f9bd57db791fb13a6034ce69bf50878cb1` passed the full [CI
run](https://github.com/paperclipai/paperclip/actions/runs/40016166260),
including typecheck, build, unit/integration tests, and all eight
browser shards. The required `ci / verify` and `ci / e2e` gates passed.
[Greptile](https://github.com/paperclipai/paperclip/pull/17249#issuecomment-6353731805)
and [Paperclip
Review](https://github.com/paperclipai/paperclip/pull/17249#issuecomment-6372165895)
each rated this exact head **5/5**, with no open findings. Paperclip
Review completed with a neutral check because its scoped reviewer could
not inspect CI; the full CI result was verified separately. Other
neutral checks and intentionally skipped Storybook jobs contain no
actionable findings.
- CI recovery on the same commit: the first attempt lost six jobs. Five
logged simultaneous runner shutdowns at 18:49 UTC on 2026-10-23; the
sixth stopped logging before a test result and its root cause was not
established. No assertion failure appeared in the retrieved logs. All
six jobs and the aggregate gates passed one failed-job retry. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/40005754936).
- Copy follow-up: the catalog, provider, and setup UI suites passed
**275 tests**. The governed gateway lifecycle passed **3 tests** (one
live-only test skipped), including create, update, archive, and delete.
UI token gates and map checks passed. The branch was rebased onto
`9c442cf48e` to resolve additive catalog conflicts while retaining the
Vercel and Supabase entries. The existing live write proof below remains
applicable; this follow-up changes presentation only.
- Five affected suites, including the existing Daytona consumer, passed
**290 tests** (one opt-in live test skipped in fixture mode). Full `pnpm
-r typecheck` and `pnpm build` passed. The local broad-suite attempt
could not complete because PostgreSQL semaphore exhaustion prevented a
competing integration suite from starting; the complete affected-file
retry passed after disposable-process cleanup. The prior commit
`f208a8aff6dc28859cc3f343497e18d85f124579` passed the complete CI
matrix. All CI build, typecheck, test, and browser gates also passed on
the earlier commit `9e2f3d3140368a08da43b004b2e8d3a0f4c0fa4d`. The
separate Paperclip Review reported a worker-result regression-test gap
on that head; the follow-up above addresses it. Its review thread is
resolved, and both fresh current-head reviews are clean as recorded
above.
- Token gates, module boundaries, brand validation, map checks, and
Storybook catalog checks passed.
- Direct SDK create/archive/delete and rejected-call coverage passed (13
provider tests); the Storybook Permissions/Test play completed
successfully in Chromium. Server and UI typechecks passed after those
fixes. Greptile passed prior commit
`9e2f3d3140368a08da43b004b2e8d3a0f4c0fa4d` at **5/5**. Both reviewers
also passed the worker-test follow-up at **5/5** as recorded above.
- Live 1Password proof on 2026-10-22: connect, eight-action discovery,
vault listing through an actual run-scoped gateway, refresh, reconnect
preserving identity, another read, removal, and denial through the
retained session passed. Credential absence was asserted in
responses/audit; an exact-token scan of inspected logs and changed files
passed.
- Real browser: Connectors → 1Password → token entry → personal access
limited to one disposable agent → completion → Permissions → Test
`onepassword_list_vaults` succeeded. The disposable connection was
removed afterward.
- Compiled-worker smoke initially exposed inherited Node launch flags.
Workers now use explicit empty `execArgv`; the compiled worker then
authenticated successfully and listed one vault.
- Live write proof on **2026-10-23**: the replacement Keychain token
passed all eight actions through the actual run-scoped gateway for both
personal and shared credentials. The test created, listed, read,
updated, resolved a secret from, archived, and deleted two synthetic
items. Both were absent from subsequent item lists. Refresh/reconnect,
identity preservation, removal, retained-session denial, and credential
absence passed. The live suite passed **3 tests** (one fixture-only test
skipped) in 116.65 seconds. The expanded fixture suite passed **3
tests** (one live-only test skipped); the 13 provider tests and server
typecheck passed. An exact-token scan passed over 64 source/log files.
- Failure history: the original token denied creation on 2026-10-22 and
created no item. The first 2026-10-23 attempt stopped before provider
calls because host PostgreSQL semaphore limits prevented test-database
startup. A temporary ten-connection test profile allowed the complete
retry to pass without changing shared services or host limits. A new
delete-result assertion also exposed an outdated fixture response
(`success` instead of `deleted`); the fixture was corrected and the
complete fixture suite passed.

Official contract sources: [service
accounts](https://www.1password.dev/service-accounts/get-started),
[SDKs](https://www.1password.dev/sdks), [item
management](https://www.1password.dev/sdks/manage-items), [official
JavaScript SDK](https://github.com/1Password/onepassword-sdk-js).

## Risks

- Authorized item/secret reads intentionally return secret values to the
agent and ordinary tool-result history. Select trusted agents and use
restricted service-account vaults; the connection token itself is
redacted.
- New connections retain existing Paperclip action defaults, including
Allowed writes/destructive actions for selected agents. 1Password still
enforces the token's permissions.
- Service-account access cannot be changed in place. Create a
replacement account and reconnect to change vault permissions; read-only
keys can connect but cannot write.
- SDK authentication happens per action in a disposable worker. Calls
have a 30-second maximum; cancellation stops local work, while a
mutation already accepted by 1Password can still finish. Writes are
never automatically retried.
- Additive dependency and catalog change; no database migration.
Disable/remove the connection to withdraw access, or remove the provider
from catalog visibility for rollback.

## Model Used

OpenAI Codex, based on GPT-6, with code editing, shell/browser tools,
and live provider verification. A more specific runtime model ID and
context-window limit 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-23 13:27:33 -07:00
73526559b5 fix(ui): reload once when a lazy chunk or its CSS fails to load (#17349)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The board UI loads each page as a lazy chunk. Vite adds a preload
step that also loads the CSS of the chunk.
> - Staging error monitoring reported `Unable to preload CSS for
…/assets/issue-detail-CIbQo9zW.css`. The same file name comes from the
current build, so the CSS did not change. One request for the file
failed for a short time.
> - Vite rejects only the first import that asks for a failed file.
Later imports skip that file. On a task page, the first import is the
task-page prefetch, which ignores errors. The page then shows without
its CSS. On other pages that share the CSS, such as Agents, the lazy
route rejects and the route error boundary shows the error.
> - Neither case recovers without a manual reload. This is a routine
retry that the app can do safely, so the app must do it.
> - This pull request reloads the page one time when a chunk or its CSS
fails to load. A loop guard limits this to one reload in five minutes.
> - The benefit is that a stale tab after a deploy, or one failed asset
request, recovers without an error page, without missing styles, and
without error-monitoring noise. An asset that stays broken still shows
the error and still sends a report.

## Linked Issues or Issue Description

**What happened?**
A board page showed "This page hit an error" with `Unable to preload CSS
for <origin>/assets/issue-detail-<hash>.css`. On a task page, the same
failure gave no error message, but the page showed without its
stylesheet.

**Steps to reproduce**
1. Build the UI and start the server.
2. Make the first request for `/assets/issue-detail-*.css` fail. The new
Playwright spec does this with `page.route(...).abort("failed")`.
3. Open `/<prefix>/agents`. The route error boundary shows "Unable to
preload CSS".
4. Open `/<prefix>/issues/<id>`. The task shows, but the browser does
not request the task CSS again. The page has no task-page CSS.

**Expected behavior**
The app recovers from a chunk or CSS load failure without user action.
If the failure continues, the app shows the error one time, with no
reload loop.

**Environment**
Hosted staging browser. The local build of current `master` reproduces
it.

I searched open and closed PRs for `preload`, `preloadError`, and `stale
chunk`. I found no related PR.

## What Changed

- `ui/src/lib/chunk-load-recovery.ts` (new): `isChunkLoadError` matches
the Vite CSS preload error and the dynamic import errors from Chromium,
Firefox, and WebKit. `reloadForChunkLoadError` reloads one time. A
`sessionStorage` marker blocks a second reload for five minutes. After
the first reload, later chunk errors in the same document are part of
that reload, so they return "reloading" and do not show an error.
Without `sessionStorage`, the function does not reload, because it
cannot guard against a loop. `startChunkLoadRecovery` listens for
`vite:preloadError`. It does not cancel the event, so the import still
rejects as before.
- `ui/src/main.tsx`: Starts the listener before the first render. The
listener covers every import, including the task-page prefetch that
ignores errors.
- `RouteErrorBoundary` and `AppErrorBoundary`: While a recovery reload
runs, they show a loading state. They do not show the error page and do
not report to Sentry. Other errors work as before.
- Tests: Vitest unit tests for the helper and both boundaries. A new
Playwright spec, `tests/e2e/chunk-load-recovery.spec.ts`, runs against
the real server and the built UI.

## Verification

- `pnpm --filter @paperclipai/ui exec vitest run
src/lib/chunk-load-recovery.test.ts
src/components/RouteErrorBoundary.test.tsx
src/components/AppErrorBoundary.test.tsx`: 21 tests pass.
- Full UI Vitest suite: 793 files, 9,075 tests pass.
- `pnpm --filter @paperclipai/ui typecheck` passes. `node
scripts/check-token-gates.mjs` is clean. `node scripts/check-maps.mjs`
passes.
- `npx playwright test --config tests/e2e/playwright.config.ts
chunk-load-recovery.spec.ts`: 3 tests pass.
- Task page with one failed CSS request: one reload, the CSS loads, and
the task shows.
- Agents page with one failed CSS request: one reload, the CSS loads,
and the page shows with no error page.
- CSS that always fails: one reload, then the error page shows. There is
no second reload.
- Red proof: I ran the same spec with the `ui/src` changes removed
(current `master` UI code). Both recovery tests fail. On Agents, the
route error boundary shows `Unable to preload CSS for
http://127.0.0.1:3199/assets/issue-detail-CIbQo9zW.css`. On the task
page, the CSS is never requested again.
- A failure I found and fixed during the work: my first version changed
only the error boundaries. The task-page e2e case failed with that
version, because the prefetch received the error and the boundary never
saw it. The `vite:preloadError` listener fixes that case. All results
above are from the final commit.
- The spec blocks service workers, because Playwright page routes cannot
see requests that a service worker sends. With a worker, a failed
network request for an asset that is not cached also gives
`Response.error()`. Thus the preload error is the same.

## Risks

- A page can reload while a user is on it. This occurs only after a
chunk or CSS load failure, and at most one time in five minutes per tab
session. Without this change, that page already shows an error or shows
without styles. Composer drafts use browser storage, so a reload keeps
them.
- A failure that recovers no longer sends a Sentry event. A failure that
continues after the reload still sends one, so a broken deploy stays
visible.
- The error patterns match browser and Vite message prefixes. If a
browser changes its message, that browser goes back to the current
behavior: the error page and a report.
- No API, schema, or server changes.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`) by Anthropic, run as a Paperclip
agent through Claude Code with tool use (shell, file edits, Playwright,
and Vitest).

## 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>
Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
2026-10-23 12:06:38 -07:00
93d26eb84e feat(ui): link routine-created tasks back to their source routine (#16471)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Routines create tasks on a schedule. Each task records its source in
`originKind = "routine_execution"` and `originId = <routine id>`.
> - The issue Properties card shows Relationships such as Parent. It
does not show the routine that created the task.
> - An operator who reads a routine-created task cannot go to the
routine from the task. They must find the routine by hand.
> - This pull request adds a "Routine" row under Relationships, below
Parent. The row links to the source routine.
> - The benefit is a direct path from a routine-created task to the
routine that made it.

## Linked Issues or Issue Description

Refs #9727. That PR adds a general provenance model and an "Origin"
chip. It also links routine executions to the routine. It is much larger
(DB migration, server, plugin SDK). It has merge conflicts and no
updates since August. This PR is a small UI-only change with no schema
or API change. If #9727 merges later, the two rows can be merged into
one.

**Is your feature request related to a problem?**
A task that a routine creates has no visible link back to that routine
in the Properties card.

**Describe the solution you'd like**
Show a "Routine" row under Relationships for routine-created tasks. The
row shows the routine title and links to `/routines/:id`.

**Describe alternatives you've considered**
A generic "Origin" row for all origin kinds (the #9727 approach). That
needs new server data for most kinds. A routine link needs only data
that the issue already has.

## What Changed

- Add `ui/src/components/issue-properties/routine-origin-row.tsx`
(`RoutineOriginRow`). It reads the routine with the same
`queryKeys.routines.detail` query as the routine page, so the cache is
shared.
- Show the row in `IssueProperties.tsx` after Parent, only when
`originKind === "routine_execution"` and `originId` is set (+5 lines).
The new component is in its own file because `IssueProperties.tsx`
already has more than 3,000 lines.
- States:
- Routine found: an outline chip with the repeat icon and the routine
title. The chip links to the routine page.
- Routine still loading, routine deleted (404), or any other lookup
error: no row. The card never shows an empty Routine field.
  - Task not created by a routine: no row. No routine request is sent.
- Add 4 tests in `IssueProperties.test.tsx`: routine found, routine
loading, routine deleted, and task not created by a routine.

## Verification

- `pnpm --filter @paperclipai/ui exec vitest run
src/components/IssueProperties.test.tsx`: 94/94 pass.
- `vitest run src/pages/IssueDetail.test.tsx
src/components/TaskSidePanel.test.tsx` (other surfaces that render the
panel): 195/195 pass.
- `node scripts/check-token-gates.mjs`: all gates clean.
- `tsc --noEmit` in `ui`: no errors in the changed files. Other errors
came from workspace packages that were not built locally
(`@paperclipai/plugin-sdk/ui`, generated storybook catalog JSON). This
change does not touch them.
- Manual check: open a task that a routine created. Find the "Routine"
row under Parent. Click it. The routine page opens.
- Not run locally: full `pnpm -r typecheck`, `pnpm test:run`, `pnpm
build`, and a browser check. CI runs these.

## Risks

- Low risk. The change is UI-only and additive. It has no schema, API,
or contract change.
- Each routine-created task view sends one extra `GET /routines/:id`
request. The routine page uses the same cache key, so the response is
often cached already.
- The row appears only after the routine request finishes. On a cold
cache, it shows up a moment after the rest of the card.
- If the routine is deleted or the user cannot read it, the task shows
no Routine row. The task still records `originKind`/`originId`.

> 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 (shell, file edit, test execution). Standard 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
- [ ] 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: Devin Foley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:20:58 -07:00
DottaandPaperclip 3bd709df8b Operationalize Product E2E accounting, tracing, and scheduling (#17009)
## Thinking Path

> - Paperclip manages agents and the work they perform.
> - Product E2E tests exercise real agents, tools, setup and cleanup.
> - Repeated runs need retained costs and traces, including failed
attempts.
> - A passing retry must not hide earlier spending or feedback.
> - Recurring work also needs admission limits, private reports and
failure detection.
> - This change supplies those controls while keeping paid activation
behind existing gates.

## Linked Issues or Issue Description

Refs #16996 and #17158. This is the consolidated landing of the reviewed
eval operations stack: #17019, #17024, #17025, #17027, #17030, #17033,
#17035, #17038, #17043, #17044, #17048, #17050, #17051, #17092, #17096,
#17100, #17107, #17109, #17112, #17115, #17117, #17121, #17123, #17127,
#17130, #17133, #17134, #17137, #17140, #17143, #17154. The repository
permits squash merges only. A local rehearsal showed that squashing each
slice into master causes repeated conflicts in dependent slices. This PR
preserves their commits and lands their combined implementation in one
reviewed integration. Superseded slices will close after this merge.

## What Changed

- Retain every attempt's cost receipt, including setup, failures,
interruptions and retries. Separate reported amounts, estimates, missing
costs and reserved capacity in reports and dashboards.
- Add bounded request admission, exact model pricecards, gateway error
accounting, cache policy and reconciliation evidence. Refuse unsupported
routes and requests that cannot fit the allowance.
- Integrate Braintrust gateway traces and OTLP correlation, with secret
filtering and experiment imports. Record phase timing, including setup,
feedback capture and cleanup.
- Collect complaint and suggestion evidence after each attempt,
including recovery after failures. Retain explicit review dispositions
independently from the product grade.
- Add gated daily and weekly selections, measured forecasts,
setup/readiness checks, wall-time limits and retained monitor
notifications. Include declared non-model overhead in admission while
reporting the existing subscription separately.
- Keep recurring history private, bound uploads and retention, and use
isolated archive environments. Keep public publication an explicit
operation. Report and publication jobs install only the committed
lockfile, with scripts disabled and isolated stores; stale pins fail
closed.
- Integrate current master, preserve its Product E2E journey billing and
privacy checks, and test that shared setup receipts do not double-count
estimated agent usage. Preserve upstream fixture repairs.

## Verification

- Complete integration baseline
`0649a5ce7544ab20825c2183d2f421157db49f24` includes master
`a3e1d915a7110a4e115b46396a3f79e6dfb4d05e` and every original stack head
as ancestors.
- On that integration baseline, `pnpm test:e2e:runner:unit`: 4,012
Vitest tests passed, two skipped, across 193 files; all 137 Node
source-contract tests passed.
- Focused billing and Product E2E journey contract checks: 24 tests
passed. They cover estimates, unknown receipts, single-owner setup
costs, browser-only execution and private publication guards.
- Monitor and workflow wiring: all 96 Node tests passed. `node
scripts/check-token-gates.mjs`: all gates clean.
- `pnpm test:e2e:runner:typecheck` passes after the standard Runner
TypeScript build refreshed local declarations. The first attempt
rejected the new master `runner_prepared_launch` union member because
this checkout retained an older generated declaration; the source union
already contained that member.
- Current head `492b0708a1c531a023d9ac10f0f3dc6383cc1754` removes
dependency re-resolution from archive-authorized reporting jobs after
the security scan flagged it. All 15 workflow-security tests pass after
updating the old two-install assertion.
- Hosted [CI run
39965460180](https://github.com/paperclipai/paperclip/actions/runs/39965460180)
passes on the current repaired head, including typecheck, build, general
tests, Runner checks, browser shards and canary dry run. Greptile is 5/5
on this exact head with no unresolved threads. The security scan passes
after the fixed lockfile-resolution thread was resolved.
- Paperclip Review returned a terminal neutral check but an incomplete
0-file assessment on the repaired head: its platform blocked both diff
responses as prompt-injection content. This is not a successful code
review. No bypass or fabricated pass was attempted; current-head
Greptile, security and hosted CI are independent gates.
- No paid test, reservation release or recurring-run activation
accompanies this landing. Live route qualification and invoice
reconciliation remain separate evidence.

<details>
<summary>Retained earlier validation failures</summary>

Earlier broad local runs had two 15-second test timeouts (CLI poll
cadence and Retry validation), one embedded-database setup timeout, and
later PostgreSQL semaphore exhaustion. The exact timed-out tests passed
separately without larger timeouts; the broad-run causes were not
established. Those local failures remain distinct from subsequent hosted
CI results. The independent #17158 fix records its Muse fixture
collision, its UUID correction and hosted verification. Local Muse
execution was also blocked by macOS embedded-PostgreSQL startup. No
historical failure is treated as a successful paid qualification.

</details>

## Risks

- Admission is a local control, not a provider invoice cap. Missing
provider receipts or resource charges retain unknown amounts and holds;
estimates do not become billed dollars.
- The bounded path admits only documented local suites and provider
routes. Ordinary legacy or separate Runner protocol campaigns have
different controls. Merging this code does not qualify additional
routes.
- Recurrence still needs the existing enable gates and current
qualification/allowance evidence. Archive permissions and resources must
match the documented private-environment contract.
- Legacy reports may lack complete attempt or phase evidence. Reports
preserve that limitation and do not infer zero usage from missing data.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools and code
execution. The exact deployment variant 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 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 (targeted checks;
full-suite host limitation disclosed 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-23 07:18:37 -07:00
DottaandPaperclip fbaf3c6ed2 feat(onboarding): connect a custom AI gateway (#17253)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A person must connect an AI account when they set up the first
agent.
> - The existing connection form supports custom Responses and Messages
gateways.
> - First-agent onboarding does not expose that form or its saved model
list.
> - A person who uses a custom gateway cannot complete this setup
through the normal controls.
> - This pull request adds the existing gateway form to onboarding and
requires a model before Connect.
> - The person can save the account first, then choose Connect to test
the environment and hire the agent.

## Linked Issues or Issue Description

Refs #14104. This addresses the missing custom endpoint option during
first-agent onboarding.
Refs #15103. That issue also covers other adapters and the separate New
Agent wizard.

Related source review:

- Refs #15884. That proposal adds a Local LLM source, changes
private-network HTTP validation, and uses OpenCode. This change uses
existing gateway routing and preserves the explicit environment test
before hire.
- Refs #14006. That proposal adds new providers and connection methods.
This change uses the existing OpenAI and Anthropic managed connection
contracts.

**What existing behavior does this improve?**

The API-key step of first-agent onboarding for Codex and Claude.

**Current behavior**

The wizard accepts a direct provider key but does not expose custom
gateway setup or the saved gateway model list.

**Proposed behavior**

Choose Use a custom gateway. Save its URL, key, and models through the
existing connection form. Select a saved model. Choose Connect to run
the normal environment test and hire the agent with the managed
connection binding.

**Reason and benefit**

People can complete onboarding with an existing custom gateway. They can
save the connection before any agent test starts.

**Breaking changes**

No API, database, or routing schema changes. The new path applies to
Codex and Claude API-key setup. Existing direct-key setup remains
available.

## What Changed

- Add a small onboarding dialog that reuses `AiProviderSetup` for
Responses or Messages gateway connections.
- Let the shared setup form use Save connection as its submit label in
this dialog.
- Bind the saved account to the current company and adapter. Clear its
selection when the person changes companies or chooses another API key.
- Load the saved connection's models. Require a model before Connect can
test the environment and hire the agent.
- Show a loading state, a visible error, and Retry loading connection
when the saved connection lookup fails. Reuse the shared lookup cache
and preserve the model hook contract for existing consumers.
- Cover saving, model selection, delegated account use, secret exclusion
from drafts and hire payloads, and Cmd+Enter in the gateway dialog.

## Verification

- Focused UI verification: `pnpm --filter @paperclipai/ui exec vitest
run src/components/OnboardingWizard.test.tsx
src/components/ai-connections/AiProviderSetup.test.tsx` — 187 tests
passed across two files.
- The first focused attempt had one test-only failure because its
fixture lacked `TooltipProvider`. The fixture now supplies that
provider. The complete focused run then passed all 187 tests.
- The new test confirms that saving the connection and pressing
Cmd+Enter in its dialog do not call the adapter test or hire API.
Connect remains disabled until model selection. Connect then uses the
selected model and managed connection for both test and hire.
- Rebased onto `origin/master` at
`042051904d368f5514e287e5ca8e404dc8f78a0d`. The two focused UI files
passed all 187 tests again on the rebased tree.
- UI typecheck passed on the rebased tree. The first attempt found
missing generated Plugin SDK declarations in the fresh worktree. `node
scripts/ensure-plugin-build-deps.mjs` built the local shared and SDK
artifacts. The Storybook catalog check and `tsc -b` then passed.
- Reused installed third-party packages from the unchanged lockfile.
Worktree-local workspace links pointed at the rebased source. No older
workspace source was substituted.
- The full token gate checks and `git diff --check` passed in this
isolated worktree.
- An earlier wider local repository run failed in a chat-channel test.
That failure was not investigated in this isolated UI follow-up and
remains part of the verification history. The complete CI suite for this
PR later passed on the reviewed commit. Deployed gateway acceptance has
not been run.
- Review follow-up: reproduced the failed saved-connection refresh
before the fix. The new test failed because the page did not show the
lookup error. The page now shows the error and Retry loading connection.
Connect stays disabled until lookup and model selection succeed.
- The new failure-and-retry test uses separate response objects so cache
mutation cannot hide a failed refresh. It also proves that save and
retry do not probe or hire an agent.
- The expanded regression initially needed a corrected mock return type.
After that correction, all 199 tests passed across OnboardingWizard,
AiProviderSetup, and useConnectionModels. UI typecheck, all token gate
commands, and `git diff --check` passed.
- The review fix is pushed at
`12b4e9cb8528ba44af377315ba39fe3fbccae7bd`. All 53 active CI and
security checks passed on that exact head. Two Storybook checks were
skipped. Greptile completed with 5/5, and there are no unresolved review
threads. The earlier local chat-channel failure remains recorded above.
- No live Cloud gateway campaign or candidate deployment has been
completed for this product change.

## Risks

- Gateway setup adds a nested dialog inside onboarding. Its key events
must not submit the parent wizard. The Cmd+Enter regression test covers
this boundary.
- A saved connection can offer no model list. That state permits an
explicit model ID and still requires selection before Connect.
- Saving a connection proves that it was stored. The normal Connect
action remains responsible for runtime validation. A successful mocked
UI test does not prove gateway reachability from a deployed runtime.
- `ROADMAP.md` already includes personal and shared AI accounts and
multi-model teams. This is a scoped extension of those capabilities. It
does not add a provider, a protocol, or wider URL access.

## Model Used

OpenAI Codex, GPT-6 family. The exact deployment model ID and context
window are not exposed in this session. The agent used reasoning, tool
use, code editing, and local test execution. No unverified model ID or
context size is claimed.

## 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
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] 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 06:26:39 -07:00
Devin FoleyandPaperclip c5ca29dbef fix(claude): prepare compatible sandbox runtimes during onboarding (#17259)
## Thinking Path

> - Paperclip connects agent accounts and prepares their execution
environments.
> - A managed sandbox image can outlive the model defaults shipped by
the app.
> - Claude setup skipped installation whenever a CLI was already on
PATH.
> - The selected model then failed its minimum-version check after
sign-in succeeded.
> - This pull request prepares a compatible private CLI before testing
or running it.
> - Cloud onboarding also stops asking customers to run inaccessible
shell commands.

## Linked Issues or Issue Description

**What happened?**

A new managed Cloud stack completed Claude subscription sign-in. Its
environment test then failed because the snapshot contained Claude Code
2.1.263, while the selected `claude-opus-5-5` model requires 2.1.280.
The screen displayed Manual debug commands that a hosted customer cannot
run.

**Expected behavior**

Paperclip prepares its managed runtime before testing the selected
account. A stale image CLI does not require the customer to upgrade a
server package. Failed preparation still blocks hiring. Cloud does not
display manual shell debugging.

**Steps to reproduce**

1. Start a managed sandbox with Claude Code 2.1.263 on PATH.
2. Connect a Claude subscription and select `claude-opus-5-5` on the CLI
lane.
3. Connect the agent. Installation is skipped because the command
exists, then the version gate blocks the hello test.

**Paperclip version or commit**

Source baseline: `6204239cfc8c3be79fc185cf3f468ebaa0ab1e3e`.

**Deployment mode**

Authenticated managed Cloud with a Daytona named snapshot. The
correction also applies to the default CLI in other managed sandbox
transports.

Related work: Refs #14993 sets model/runtime requirements; Refs #15993
changes native defaults on qualified targets. Neither prepares an
outdated default sandbox CLI on this path. Searches found no open
duplicate.

## What Changed

- Check the actual default CLI against the selected model's existing
minimum version.
- When a sandbox's default command is outdated, install the exact
required npm package into a private versioned workspace prefix. Reuse a
compatible private installation. Keep the image's global CLI intact.
- Verify the private executable and use that same command for the
account hello test and normal CLI runs, with matching command metadata.
Probe effort support after preparing that executable so the chosen
effort is retained. Keep the model, account, engine and permissions
unchanged.
- Return safe preparation checks to environment tests and normal run
logs, distinguishing installation failure causes without returning raw
installer output or credential-bearing URLs.
- Exclude provider and Paperclip credentials from the installer
environment. Preserve the existing failing version gate if installation
or verification cannot succeed. Local, SSH and explicit custom commands
remain operator-managed.
- Hide Manual debug and legacy operator check hints on Cloud and while
deployment metadata is unknown; preserve check messages and details.
Retain self-hosted help and the detailed failed checks. Cloud copy asks
for a retry instead of asking the customer to repair the environment.
- Add subprocess-backed runtime controls, an account-probe regression
and mounted Cloud/self-hosted wizard controls. Update development
guidance and the affected capability maps.

## Verification

- Passed all Claude source suites and the server Claude execution suite
on head `c941ae44c22d8dafec0df033a129e39ce4ebd966`: **412 passed**, one
existing opt-in test skipped. These include the new command/effort
ordering, safe installer diagnostics, environment forwarding and run-log
regressions.
- On final head `0ecae0e9304f495a57524158b3700b8e9bc21cb8`, passed **208
tests** across all 174 mounted onboarding wizard tests and 34 Claude
execution tests. The failure fixture includes the real command-bearing
hint, and execution asserts both metadata command fields agree.
- Passed `pnpm -r typecheck`, `pnpm build`, `pnpm check:token-gates`,
`node scripts/check-maps.mjs` and `git diff --check`. Full typecheck and
build were repeated successfully on final head
`0ecae0e9304f495a57524158b3700b8e9bc21cb8`. [Latest-head
CI](https://github.com/paperclipai/paperclip/actions/runs/39879208694)
is green: 54 checks passed and two skipped, including browser E2E and
serialized database suites.
- The new runtime controls execute real subprocesses with a controlled
installer. They cover an old CLI, an already compatible CLI, failed or
ineffective installation, local/custom commands, and an unknown version.
The probe regression asserts that the hello call uses the private
executable.
- A separate non-root local subprocess check installed the real npm
`@anthropic-ai/claude-code@2.1.280` package. Its private command
reported 2.1.280, the simulated image CLI remained 2.1.263, and a second
preparation reused the private copy. This ran on macOS ARM64. It did not
use a provider account, send a model prompt, or prove live Daytona
behavior.
- Attempted `pnpm test:run`. Embedded PostgreSQL initialization failed
after five attempts on this Mac with `Postgres init script exited with
code null`. The unchanged native-session database cases then failed.
Stopped only that full-suite process tree after recording the repeated
startup failure. No full local-suite pass is claimed; Linux CI must
cover those tests.
- The first new subprocess fixture had a quoting syntax error. It was
corrected before the passing focused runs. The one-off real-package
script first required an ESM extension correction, then passed. Logs
retain both attempts. A new execution assertion initially inspected the
final sandbox cleanup shell instead of the launched command; it now
checks execution metadata. A broader directory selection also picked up
generated `dist` tests whose Markdown fixtures are not copied by the
build (two ENOENT failures). The explicit source-suite run above passes;
no generated-test pass is claimed.
- Apex review: **5/5**, reviewed final head
`0ecae0e9304f495a57524158b3700b8e9bc21cb8`, all five earlier findings
addressed and resolved, no new findings.
- Merge, deployment and a fresh live Cloud subscription test are still
required. No customer account or production runtime was changed by this
branch.

## Risks

- An outdated sandbox needs npm registry access and up to 120 seconds
for one bounded installation attempt. A failed or unverified install
continues to block execution.
- The versioned package uses sandbox workspace storage. Compatible
cached copies avoid repeat installation within that workspace. Existing
runtime cleanup and sandbox lifecycle still apply.
- The compatible version comes from the adapter's existing model-version
contract. This does not add a model fallback or change the selected
execution engine.
- No schema, credential, permission, workflow or lockfile change.

## Model Used

OpenAI Codex, based on GPT-6, assisted with implementation and
verification. The exact serving model ID and context-window limit are
not exposed in this session. Capabilities used: code editing, shell
execution, API inspection and 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
- [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 18:44:53 -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
Dotta 46760cc588 fix(chat): honor dismissal for all composer requests (#17218)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task conversations show requests in the feed and above the message
composer.
> - Earlier fixes kept dismissed questions in history, but excluded
completion reviews and other request kinds.
> - Closing those forms left a pending badge, and the server could still
demand a response.
> - This pull request saves human dismissal and removes the request from
composer reminders and ordinary completion gates.
> - People can continue the conversation and reopen the request from
history.

## Linked Issues or Issue Description

Related work: #15229 and #15392.

**What happened?**

Dismissing a completion review closed its form but left it counted as
pending. It could return after reload, block a retry, or cause the agent
to demand another response. Raw runtime requests could also lose their
only usable control when dismissed.

**Expected behavior**

Dismissal leaves an accessible request in the feed and clears the
composer form and pending count. It persists after reload. It does not
submit an answer, approve an action, or wake the agent.

**Steps to reproduce**

1. Open a task with a pending completion review or another composer
request.
2. Dismiss the request, then reload the task.
3. Check that the composer stays clear and the feed entry can reopen the
request.

## What Changed

- Add nullable dismissal fields and a human-only dismissal endpoint with
company, private-task access, resolver, and locked review-policy checks.
- Persist saved-request dismissal on the server. Keep browser
persistence for raw runtime requests and existing question dismissals.
- Keep confirmations, choices, item verdicts, suggested tasks, and
runtime requests accessible in the feed.
- Exclude dismissed ordinary requests from completion and retry gates.
Tell agents not to repeat deferred requests.
- Preserve tool, secret, connection, plan, company-policy, and
configured review authorization gates. Expire deferred non-question
requests when their task completes.
- Preserve the selected form when another dismissal finishes saving.
Keep reopened reviews visible through delayed comment refreshes.
- Add a completion-review Storybook test drive and update design, API,
database, and capability documentation.

## Verification

- `pnpm -r typecheck`: passed. The final UI changes also passed the UI
typecheck.
- `pnpm build`: passed. The final UI changes also passed the UI
production build.
- Focused UI and transcript tests: 550 passed across nine files after
merging the current base branch.
- Focused database, completion, and prompt tests: 105 passed across
three files, including two review-policy regressions that failed before
the fix. The tests reject a review requester excluded by current policy,
preserve the pending gate on denial, and permit an independent reviewer
to defer the request.
- Route regression suite: 81 passed, including denial before reading or
mutating a private-task request.
- `pnpm check:token-gates`: passed.
- Map and Storybook structural checks: passed; 30 map/catalog script
tests passed.
- Browser: used the production task-thread components in the
completion-review fixture. Dismissed, reloaded, reopened from the feed,
and dismissed again. No pending badge or composer takeover remained.
Story callbacks simulate API saves; separate server tests cover
persistence and permissions.
- `pnpm test:run`: stopped after the general-server group reported one
failure in `workspace-runtime.test.ts`: "returns a bounded structured
conflict and exposes only same-company workspace references". The same
test passed in isolation (1 passed, 178 skipped). The cause of the
full-suite failure is not established. The full PR CI suite subsequently
passed on e243cbb001; its two authorization review findings are fixed in
9e1b4478b3. Fresh [full
CI](https://github.com/paperclipai/paperclip/actions/runs/39871944846)
passes on 9e1b4478b3, including the previously failing server and
browser shards. All 54 executed checks passed; two optional Storybook
deployment/visual jobs were skipped. The legacy security status also
passed. Fresh Greptile review is 5/5, the security scan passes, and no
review threads remain open. This full CI run settles the merge gate; the
earlier local workspace-suite failure remains recorded above because its
cause was not established.
- Additional verification: the original failing browser journey passed
locally after the delayed-refresh fix. The expanded page-reload case
also passes on 9e1b4478b3 (52.7s): dismiss, reload, reopen, approve, and
receive the actual tool failure in the continuing task. It exposed a
fixture reading an accepted request before tool execution finished; the
fixture now waits for a stored execution result. The first reload
attempt stopped on a still-loading page at the default five-second
assertion; the reload now uses the suite’s navigation allowance. A
controlled server-restart run timed out waiting for server health before
the UI assertions. Local route-suite runs timed out during concurrent
module loading; sequential imports passed all 81 tests, including the
privacy regression.
- Initial verification failures: a missing SDK build and a story fixture
type error were fixed. PostgreSQL bootstrap then failed because the host
had exhausted its semaphore allowance. After explicit operator approval,
64 verified abandoned PostgreSQL semaphore sets were reclaimed; no live
process was stopped. The database regressions then passed. The
raw-runtime regression exposed a missing feed control; the
implementation now preserves that entry and the regression passes.

## Risks

- Apply the additive database migration before the new server code. It
adds two nullable columns and does not change existing decisions.
- A dismissal is shared task attention state. Only a human with task
read access and current resolver/review authority can persist it. Review
policy is checked under the task lock. The operation is idempotent and
records the dismissing user.
- Raw runtime dismissal remains specific to a browser. Saved interaction
dismissal persists across browsers.
- A deferred review is not an approval. Tests retain protected-action
and configured review gates.
- The browser walkthrough uses a fixture. This branch has not been
deployed to a live instance.

## Model Used

OpenAI Codex, GPT-6, with code execution and browser tools. The exact
backend 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 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
2026-10-22 18:37:36 -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
TonioandClaude Fable 5.1 def4726bea feat(ui): add the artifact directions lab with the MVP V1 kit (#17213)
## 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 in the task thread, in the right panel's
Artifacts tab and on the Artifacts page
> - The three surfaces grew one at a time. Their artifact presentation
is dated and does not match
> - A redesign needs a side-by-side comparison of several directions on
the real chrome, in both themes, with hover states, before any product
code changes
> - This pull request adds a backend-free design lab under
`ui/src/artifact-directions`: the shipped presentation as the baseline,
four exploratory directions, and the MVP V1 kit drawn from the PCLP-Core
mocks
> - The benefit is a shareable, capturable reference for the artifact
redesign that touches no product code path

## Linked Issues or Issue Description

No public issue exists. This section follows the feature request
template.

**Subsystem affected**

The web UI (`ui/`): the task thread, the right panel's Artifacts tab and
the Artifacts page. The change is a design lab beside the app, not a
change to those surfaces.

**Problem or motivation**

The three artifact surfaces are being redesigned. Designers must compare
candidate directions on the real chrome, in dark and light, with hover
states, and share a link. No harness for that exists. Figma mocks do not
show the real chrome or the themes.

**Proposed solution**

A separate Vite entry (`ui/artifact-directions.html`) renders static
mocks of the three surfaces. A "kit" supplies the artifact components
for each surface. Kits: Today (the shipped components fed with
fixtures), four directions (1.Solid, 2.Tint, 3.Tactile, 4.Hybrid) and
5.MVP V1 built from the Figma mocks. A toolbar switches kit, surface,
theme and hover animation. The state lives in the URL, so any view can
be linked and captured.

**Alternatives considered**

Figma mocks only: no real chrome, no themes, no hover. Storybook stories
only: no page-level composition and no shareable static build. The lab
keeps two Storybook stories as a secondary view.

**Roadmap alignment**

The lab supports the "Artifacts & Work Products" theme in `ROADMAP.md`.
It is a design reference. It is not a product feature and it does not
ship in the app bundle.

**Additional context**

The lab builds with its own config
(`ui/vite.artifact-directions.config.mjs`). The app's `vite build` does
not include it. A build of this branch is live at
https://paperclip-artifact-directions.vercel.app. That preview also
carries two surfaces that are not in this pull request (a media preview
overlay and a panel closeup); they are parked on a separate branch.

## What Changed

- Add the lab entry, its Vite config and the shell:
`ui/artifact-directions.html`, `ui/vite.artifact-directions.config.mjs`,
`ui/src/artifact-directions/` (static frames for the thread, the panel
and the Artifacts page, a `fetch` stub for the lab's own page, fixtures,
the kit contract, URL state, a sticky two-row toolbar).
- Add the Today kit: the shipped artifact components, fed with the lab's
fixtures.
- Add four directions, each with its own `tokens.css` scoped to
`[data-direction]`: 1.Solid, 2.Tint, 3.Tactile, 4.Hybrid.
- Add the 5.MVP V1 kit from the PCLP-Core mocks: Artifacts page stacks
and single tiles, the right panel's row list, thread rows grouped inline
when one message produced several, a hover animation (the backing pages
turn 5°, the artwork rises 6px), light-mode values, Paper Mono for the
task pill.
- Set Paper Mono for every monospace run in the lab (`lab.css`), from
the face and `--font-paper-mono` that `index.css` declares.
- Add two Storybook stories under `design-proposals`
(`artifact-directions-compare`, `artifact-directions-hybrid`), annotated
for the Storybook catalog as proposed prototypes on fixtures, and a
capture script (`shot.cjs`).
- Add two `.claude/launch.json` entries: the lab's dev server and its
static preview.
- Add Vitest coverage for the lab's logic: URL state, the API stub, the
kit's kind treatment, type labels and media kinds, its date labels,
print fitting and the thread's inline grouping (six files).

## Verification

- Run `cd ui && npx vitest run src/artifact-directions`. The six lab
test files pass (31 tests).
- Run `cd ui && npx tsc -p tsconfig.json --noEmit`. The output is clean
apart from the five pre-existing `PluginOrganizationSwitcher` errors.
- Run `node scripts/check-token-gates.mjs`, `node
scripts/sync-agent-palette-tokens.mjs --check` and `node
scripts/sync-cliplab-character.mjs --check`. All gates are clean. The
lab directory is outside the token-gated paths; its tokens are
lab-local.
- Start the lab: `cd ui && npx vite --config
vite.artifact-directions.config.mjs --port 5180`. Open
`http://localhost:5180/`. The page lands on 5.MVP V1's Overview in dark
mode with animation on. Switch kit, surface and theme in the toolbar;
the URL follows.
- Open `http://localhost:5180/?d=d5-v1-mvp&s=gallery` and hover a stack:
the two backing pages turn and the first page rises. Open `?s=thread`
and `?s=panel` for the rows.
- Build the lab: `cd ui && ARTIFACT_DIRECTIONS_OUT_DIR=/tmp/artifact-lab
npx vite build --config vite.artifact-directions.config.mjs`.
- Headless checks ran against the dev server during the work: toolbar
labels, defaults and keys; thread and panel row geometry (58px rows, 8px
and 12px gaps); the hover animation (5° turn, 6px rise, one easing
curve); pill fills per theme; Paper Mono resolution on every monospace
run. The measured values are in the kit's doc comments.
- Run `node scripts/storybook-catalog.mjs --check` (the check `ui
typecheck` runs first): the catalog accepts both stories.
- Not run: the repo-wide `pnpm -r typecheck` (it needs the Rust
toolchain for `paperclip-runner`) and `pnpm build`. The change adds
files under `ui/src/artifact-directions` and
`ui/storybook/stories/design-proposals` and edits `.claude/launch.json`;
it changes no shipped module. CI runs the full Vitest suite.

## Risks

- Low risk for the product. The app bundle does not include the lab. The
lab's `fetch` stub installs only on the lab's own page.
- Storybook gains two stories; the Storybook build includes them.

## 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 measurements and captures, the Figma MCP server to read the
mocks) and image input for mock screenshots. 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 (none found for "artifact directions lab", "artifacts
redesign", "artifacts tab design")
- [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 lab's Vitest files,
the UI typecheck and the token gates; CI runs the full suite)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes (no
product behaviour or command changed; the lab documents itself in
`kit.ts` and the frames)
- [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 10:38:12 -07:00
DottaandPaperclip 25f2d05282 fix(ui): remove the provider trace run button (#17211)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The agent header provides actions to assign work and start runs.
> - A second run button starts a run with raw provider tracing.
> - Agent configuration already has a switch for raw tracing on future
runs.
> - This pull request removes the extra run button and its unused code.
> - The header keeps one normal run action and the saved tracing status.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The action buttons in the agent detail header.

**Current behavior**

Administrators see Run now and Run with provider trace next to each
other.

**Proposed behavior**

Remove Run with provider trace from the header. Use Capture raw provider
traces in the configuration Debugging section to enable tracing for
future runs.

**Reason and benefit**

Keep the normal run action clear. Put the tracing setting with the other
agent settings.

**Breaking changes**

The separate trace button is removed. The tracing configuration, trace
API, and run inspector actions stay available.

## What Changed

- Remove the trace button, its property, and its mutation.
- Remove the property from the agent detail page.
- Update tests for normal runs with saved tracing on and off.
- Check normal actions for Codex, Dot, and Muse.
- Document the tracing setting in the feature map.

## Verification

- Passed: 178 focused UI tests across AgentActionButtons,
AgentDetail.accounting, RunnerInspector, AgentConfigForm, and
AgentConfigForm.render.
- Passed: pnpm check:token-gates.
- Passed: node scripts/check-maps.mjs.
- Passed: git diff --check.
- Passed: [PR CI
workflow](https://github.com/paperclipai/paperclip/actions/runs/39796866659),
including the required verify and e2e gates.
- Passed: Greptile 5/5 with no open review threads.
- Two optional job badges still say running. Their test, cleanup, and
final job steps passed. The parent workflow completed with success.
- The broad local checks could not complete with the installed
dependencies. The full typecheck and build require smol-toml. The UI
checks also require @spekoai/client and the plugin SDK UI build. The
full test run was stopped after many suites could not load. The PR
workflow and both required gates passed for the current head.
- To inspect the UI, open an agent. Confirm there is one Run now action.
Enable Capture raw provider traces under configuration, Debugging. Save
the change. Confirm the header shows Raw tracing on and still has one
run action.

## Risks

- Low risk. This removes one UI action and its unused code.
- Administrators use the saved Debugging setting for tracing future
runs.
- No API, database, or permission changes.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, tool use, and code
execution. The exact serving model ID and context window are not exposed
in this run.

## 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 10:02:51 -05:00
TonioandPaperclip 043f2514e6 fix(ui): keep task tabs steady when switching views (#17068)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - A task side panel contains properties, artifacts, and document
views.
> - These views share one row of tabs.
> - Selecting Artifacts adds an upload control beside the row.
> - That control reduces the space available to the tabs and changes
their widths.
> - This pull request reserves the upload control space while the
Artifacts tab is open.
> - Switching views now keeps the tab widths and positions stable.

## Linked Issues or Issue Description

Refs #14949. This fixes a layout shift observed after that PR merged.

**What happened?**

In a narrow task panel, tabs shrink when Artifacts is selected. They
expand when another tab is selected. The upload control enters and
leaves the header during selection.

**Expected behavior**

Tab selection must not change the space available to the tab row. Tabs
must keep equal widths while the panel width and open tabs remain
unchanged.

**Steps to reproduce**

1. Open Properties, Artifacts, and a document or attachment in a task
side panel.
2. Make the side panel narrow enough for tabs to compress.
3. Switch between Artifacts and the other tabs.
4. Observe the tab widths and positions as the upload control appears
and disappears.

## What Changed

- Keep an upload control slot in the header while an upload-capable
Artifacts tab is open.
- Hide the control and make it inert when another tab is active. Remove
the slot when Artifacts is closed. Agent conversations do not reserve
upload space.
- Add a component regression test for selection, focus exclusion, and
closing the Artifacts tab.
- Add a constrained production-panel Storybook case with assertions for
equal widths, stable widths across selections, and upload-control
visibility.

## Verification

- The focused TaskSidePanel and SidePanelTabs suites passed: 52 tests.
- UI typecheck, UI build, and token gates passed after replaying the fix
onto current master.
- The Storybook catalog check and all 28 map/catalog tests passed.
- The browser ran `html-artifacts-03-task-journey--stable-tab-widths`
successfully. All three tabs measured 71.328125px before and after
selecting Properties, the report, and Artifacts.
- Review the Stable Tab Widths story under HTML artifacts / 03 Task
journey. The fixture mounts the production task panel. Upload requests
are outside its scope.
- Full repository typecheck, tests, and build were not rerun locally.
This machine has no Cargo, and an earlier broad test run hit unrelated
server workspace/runtime failures. Full PR CI passed on commit
`019e324c0eca815f90d9797194e768fb48cb46b6`.

- All 55 successful PR checks are green on the latest head, with no
pending or failing checks. The failed end-to-end shard passed on one
rerun after a transient database lock timeout during test cleanup; no
code changes were needed for the rerun. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/39557963507).

## Risks

- A blank upload-control space remains when Artifacts is open but
inactive. This keeps the tab row stable.
- Hidden controls use both visibility and inert state to exclude them
from keyboard navigation and accessibility exposure.
- No API, database, upload permission, or saved-tab format changes.

## Model Used

- OpenAI Codex, GPT-6. The runtime did not expose a more specific model
ID or context window. Used reasoning, code execution, and browser
inspection.

## 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-21 22:21:42 -07:00
DottaandPaperclip 734c265339 Default new Pi agents to Paperclip Runner (#17142)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Users choose a harness during agent setup.
> - Claude, Codex, and OpenCode already receive their qualified Runner
default.
> - Pi has a qualified native integration but new Pi agents still use
the direct adapter.
> - This change gives new Pi agents the native default on supported
targets.
> - Saved agents keep their runner and compatible settings. Legacy
remains available in Advanced.

## Linked Issues or Issue Description

Refs #17120, #14921, #14922, #14923, #14924, and #14956. Related generic
default work: #15422. This PR is the separate Pi follow-up to the merged
OpenCode change.

**Current behavior**

Choosing Pi for a new agent saves the direct Pi adapter. The native Pi
integration remains behind the generic experimental flag.

**Proposed behavior**

Default new Pi agents to ACPX Pi on macOS ARM64/x64 and GNU/Linux x64
with supported glibc. Keep unsupported targets and explicit Legacy
selections on the direct adapter. Require an explicit provider/model
before test or hire. Permit model-free inactive setup drafts.

**Reason and benefit**

Users choose Pi once and receive its qualified runner. Saved agents
retain their identity and settings. Conversions reject unsupported
legacy thinking and launch settings instead of dropping them.

## What Changed

- Add Pi to the shared platform/default contract and server creation
selection.
- Admit native Pi without the generic experimental flag.
- Preserve provider models, credentials, workspace settings, exact
thinking, and saved native policies.
- Add Pi runner controls, branding, setup resume, onboarding, built-in
configuration, and import handling.
- Add managed Pi OpenRouter routing and matching native provider API-key
accounts. Keep subscription and custom gateway exclusions. Clear
alternate credentials and reject custom Pi provider overrides.
- Keep Pi draft models empty instead of applying Claude's default model.
- Verify setup against the pinned Pi runtime. For native Pi on the
official OpenRouter route, reverify the API key live without requiring a
global Legacy Pi CLI.
- Match Pi’s bounded controller close window to its native snapshot
cleanup and lifetime verification, preserving explicit caller deadlines
and the mandatory drain/suspension proof.
- Bind Pi sidecars to the package that owns the pinned native assets,
including source and vendored server layouts. Other providers retain
their existing package authority.
- Keep protocol-owned finish/block tools out of the ACPX forwarded
catalog. The trusted bridge installs these tools itself; the complete
Rust authorization catalog and terminal receipt ledger remain intact.
This fixes actual Pi session startup and applies to other ACPX
consumers.
- Advance Copilot’s shared-source attestation to v58 because it pins the
shared files touched by Pi. Preserve immutable v57 bytes and historical
decoding; Pi’s own release identity is unchanged.
- Add regression coverage and update the paired maps and developer
documentation.

## Verification

- Passed: full repository typecheck and full production build on final
head 656d304783, including the generated attestation repair.
- Passed: focused shared/server/UI suites covering default selection,
platform fallback, conversion preservation, inactive drafts, managed
account compatibility, credential isolation, OpenRouter routing/model
IDs, exact thinking controls, and saved-account selection. Relevant
batches include 375 server/conversion tests, 267 account/routing tests,
and 110 UI setup/account tests.
- Passed: 179 attestation, historical-profile, qualified-profile, and
native-execution contract tests after CI identified stale Copilot source
hashes. The identity generator check passes; the only delta after the
passing Pi browser run is this Copilot attestation/history repair.
- Passed: 145 managed-account tests, including actual service
preparation and API-key adoption/rejection for native Pi without the
Legacy CLI; 6 pinned-installation probe tests.
- Red then green: an actual task failed session.open because its
54-operation catalog included the bridge-owned terminal tools. The
regression with those tools failed before the filter; all 399 Rust
library tests pass after it. The full product retry exposed an
additional package-authority mismatch. Four authority tests failed
before that repair; 11 authority checks and 14 installation/asset checks
pass afterward. Direct real Pi session initialization with the corrected
package root and catalog succeeds. No model prompt was sent by that
diagnostic.
- Red then green: real Pi posted Hello from Pi but its controller closed
before native cleanup could finish. The cleanup-budget test failed with
the old default and passes with the bounded Pi window. All 46 selected
suspension, drain, and package-authority tests pass after building their
native fixture.
- Passed: token gates, paired map checks, Rust formatting, and git diff
--check.
- Passed real browser acceptance on macOS ARM64, generic native runner
flag disabled, source a433748a12 (Pi code unchanged afterward): the UI
selects Paperclip Runner by default, retains Pi and the selected
model/account, and verifies the pinned runtime plus live OpenRouter key.
A fresh UI-created task, assigned to the UI-created native Pi agent,
posted exactly `Hello from Pi` and reached Done without retry or
restart. The native run and workspace finalization succeeded; the
response and Done persisted after Reload.
- Evidence: 8 preserved browser attempts, including the final passing
18-step journey with all screenshots. Prior failures remain recorded.
The earlier failed checkpoint run recovered on server restart; that
recovery is separate from the fresh final task’s clean success.
- Preserved browser failures: missing account control/inherited Claude
draft model; incompatible managed-account/model-prefix handling; generic
npm probe for Pi; Legacy CLI hello check; duplicate terminal tools and
wrong provider-package authority at actual native session.open; a real
Hello from Pi comment followed by premature checkpoint cleanup timeout.
Each failure has retained screenshots/logs and a corresponding focused
repair. The fresh final task proves these repairs end to end.
- The exact Runner Vitest shard was also run locally after the
attestation fix: the stale-hash failure is gone; 1,833 tests passed, 10
skipped, and two Codex retained-control settlement scenarios failed with
`native_cleanup_maintenance_unproven` during terminal ACK/suspension
replay. Both scenarios passed in an isolated rerun (2/2), and the same
19-test file passed in the preceding Linux CI run. The precise
full-shard timing cause is not established. These Codex scenarios are
outside the changed Pi paths; the original local failures are retained;
no complete local Runner-shard pass is claimed. The corresponding Runner
shard now passes on the final head in hosted Linux CI. All 60 final-head
check runs are now terminal and clean (55 successful, 1 neutral, 4
skipped), and the legacy Snyk status is successful.
- Local full repository tests were attempted but not completed:
provisioning briefly confused a workspace symlink, then a later run was
stopped before browser-driven repairs. No full local-suite pass is
claimed. Final-head hosted CI is green and fresh Greptile review is 5/5
with all review threads resolved; earlier jobs canceled by runner
shutdown are not counted as a pass.

## Risks

- Pi cleanup has a finite 45-second default window, accounting for the
native 30-second snapshot cleanup and 5-second lifetime fence. Other
providers and explicit caller deadlines retain their prior behavior.
- Pi requires explicit operator setup with `paperclipai runtime setup
pi` on the execution host. This PR does not add automatic downloads.
- Linux ARM64, Windows, musl, and unqualified targets retain Legacy.
- Legacy thinking levels minimal, medium, and xhigh cannot be translated
exactly. Native max thinking, warm lifecycle, or restricted permissions
cannot be dropped during a return to Legacy.
- Copilot’s bound profile advances to v58 with exact current launch
admission; v57 remains decodable for recovery. No historical identity is
rewritten.
- Existing agents and immutable run descriptors are not migrated. Cloud
Pi availability is unchanged.

## Model Used

OpenAI GPT-6 through Codex with reasoning, code editing, command
execution, and browser use. The exact serving 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 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-21 17:10:00 -05:00
DottaandPaperclip 92cfd701c3 feat: add governed Braintrust app connections (#17141)
Add hosted US and EU Braintrust OAuth and API-key connections through the existing governed MCP system.

Keep reviewed tool risks and catalog review policy in connector modules and a narrow registry. Preserve credential ownership, operator decisions, regional setup and changed-tool quarantine. Include official artwork, setup guidance, focused regressions and sanitized qualification evidence.

US OAuth has bounded live read/write, gateway, reconnect and cleanup proof. Remaining account-method and token-lifecycle qualification gaps are documented.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-21 16:19:58 -05:00
DottaandPaperclip 0f15f82b19 feat: offer existing Claude and Codex agents a runner upgrade (#17122)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Each agent stores its harness, model, account and runtime
configuration.
> - New Claude and Codex agents now use Paperclip Runner on qualified
targets.
> - Existing agents keep their legacy runner and need a clear upgrade
action.
> - The existing configuration API already translates settings and
records revisions.
> - This pull request adds an explicit upgrade action that uses that
API.
> - Operators can retain supported settings and correct rejected
settings in place.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Existing Claude and Codex agent configuration. Related defaults: #15683
and #15993.

**Current behavior**

Existing agents retain their legacy runner. The operator must find the
runner selector in Advanced to change it.

**Proposed behavior**

Show Upgrade runner when Paperclip Runner is the qualified default for
the saved environment. One click saves pending edits and requests the
existing server conversion. Show any rejected settings without changing
saved configuration.

**Reason and benefit**

Operators can adopt the current runner while retaining their harness,
model, account bindings, instructions and history. Unsupported settings
remain visible and editable.

**Breaking changes**

None. Visiting configuration and saving unrelated changes do not upgrade
an agent. The server API, authorization and conversion rules are
unchanged.

## What Changed

- Add an upgrade notice, pending state, saved result and retry feedback
to the production configuration form.
- Include pending profile, runtime and environment-variable edits in the
upgrade request.
- Bind asynchronous upgrade feedback and save receipts to their original
agent. Navigating away cannot show success on another agent or redirect
back.
- Keep the notice absent for native agents, other harnesses, unavailable
targets and failed discovery.
- Add configuration/API regressions and database session-reset checks
for Claude and Codex.
- Add 13 production-page Storybook states with browser checks in both
themes and on mobile.
- Update the product contract and feature/access maps.

## Verification

- Configuration form and original-agent save receipts: 135 tests passed.
Existing agent route/rename helpers also pass.
- Runner selection, configuration API and database migration
regressions: 220 tests passed.
- Storybook browser checks: 26 passed. Interactive cases wait for
Storybook's visible Pass report. Static cases check the rendered
production form. These use simulated HTTP boundaries.
- Full typecheck, build, map checks and token gates passed on the
current head. Storybook build and public preview verification passed.
- Published fixture preview:
https://storybook.paperclip.page/storybook/branches/codex~2Fagent-runner-upgrade/?path=/story/agents-runner-upgrade--legacy-codex
- All 58 current-head PR checks passed, including the full test shards,
browser suites, build and aggregate gates. The duplicate local pnpm
test:run was stopped after 34 minutes once the same-head full CI suite
passed; it had not finished its general-server phase. No local
full-suite pass is claimed.
- Real disposable local test drive: Codex used gpt-5.4 and Claude used
claude-sonnet-4-6. Both completed one task on Legacy, upgraded through
the browser button, and completed another task on Paperclip Runner with
the same model and API credentials. Independent file checks confirmed
saved instructions and environment bindings before and after conversion.
- Reopened both configurations and compared identity, model, credential
references, instruction hashes, working directories, run policies and
configuration revisions.
- A Claude Chrome setting produced a field-specific rejection. The saved
agent stayed Legacy. Clearing Chrome in the form and clicking Upgrade
runner saved the pending correction and completed conversion.

## Risks

- The existing translator rejects settings that the new runner cannot
honor. The notice shows that error and leaves the form available for
correction.
- Converted agents start fresh sessions. Prior runs remain available.
- Real task execution was checked on local macOS with API credentials.
SSH, sandbox targets and subscription credentials were not exercised in
this change.
- Storybook responses simulate persistence. The real test drive and
database tests provide separate persistence evidence.

## Model Used

- OpenAI GPT-6 through Codex. The exact serving variant and
context-window size were not exposed in this session. Used reasoning,
code editing, shell tools and browser interaction. No 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
- [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-21 15:13:42 -05:00
DottaandPaperclip 39e44a9d9b Default new OpenCode agents to Paperclip Runner (#17120)
Default new OpenCode agents to Paperclip Runner on qualified macOS and Linux x64 targets. Preserve saved runner choices, explicit Legacy selection, and unsupported-target fallback. Pi remains a separate change.

Verified the complete browser path with a real OpenRouter connection: create the new agent, assign a task, observe its response and Done status, and reload to confirm persistence. CI passes and Greptile is 5/5 with no unresolved findings.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-21 15:09:15 -05:00
DottaandPaperclip 0a5f1546ee feat(cases): add reusable prompt workflows (#17114)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Cases keep facts, documents, and one primary task across agent
handoffs.
> - Each case currently needs its own procedure text.
> - Agents need to reuse procedures and move cases between them without
replacing the task.
> - This change adds company workflow definitions with a name and
Markdown prompt.
> - Existing handoff and document transactions preserve authority,
revisions, and recovery.
> - Cases remain behind `experimental.enableCases`.

## Linked Issues or Issue Description

Refs #16959. Related proposal: #3951 uses task graphs and a visual
editor. This change extends existing Cases with prompt definitions and
keeps its current handoff model.

**Problem or motivation**

Agents cannot share a reusable procedure across cases or inspect a
case's movement between procedures.

**Proposed solution**

Add name-and-prompt workflow definitions. Adopt a prompt into the
primary task's revisioned workflow document through a handoff. Keep
phases as free text.

**Alternatives considered**

Defer graphs, workflow versions, run entities, role schemas, authoring
screens, and Spec Kit integration.

**Roadmap alignment**

This extends the existing Cases experiment and same-task review flow. It
adds no work queue or new execution engine. The maintainer approved this
scope in the implementation plan.

## What Changed

- Add company-scoped definition storage, shared request schemas, REST
routes, and four optional Cases tools.
- Accept a workflow ID at kickoff. Agent handoffs can adopt, refresh,
preserve, or detach a workflow.
- Capture prompt text and the document base revision at acceptance.
Apply workflow, phase, and document revision together after outgoing
execution settles.
- Hold conflicting document edits for recovery. Preserve cancellation,
replay, and restart behavior.
- Show current workflow names and captured transition names/phases in
Work, history, and Audit.
- Update instructions, API/tool contracts, capability maps, and the
isolated workflow journey.
- Pin bounded workflow prompt reads to a content fingerprint;
continuation conflicts on edits and can restart safely.
- Remove experimental Cases/workflow/Mermaid guidance from the always-on
native prompt. Extract runtime-context prompt strings into a
CODEOWNERS-protected constants file while preserving the public imports.
- Refresh Copilot’s pinned source identity to v57, including the
extracted prompt file and retaining historical identities.

## Verification

Local checks: repository `pnpm -r typecheck` and `pnpm build` pass on
the prompt-extraction tree (`88222d45d8`). Full repository coverage
previously completed through the supported isolated shard groups (1,082
general server suites, 161 serialized suites, and all three workspace
groups). The earlier default serial run was interrupted and remains
incomplete. The first sharded run retained the failures described below;
targeted corrections and separate limited-concurrency reruns pass. All
CI jobs, security checks, and the 5/5 Greptile review passed on
`fc1bd79c28`. Fresh CI and review are pending for the prompt extraction
in `88222d45d8`. Focused verification passes: real-database handoff
recovery and reuse; 2,002 native-tool/API contract checks; 144 Runner
catalog/discovery checks; 27 Runner context/coverage checks; 37
case/Audit UI checks; and Product E2E oracle calibration. Token gates,
migration safety/numbering, module boundaries, capability maps, and
generated tool/Storybook catalogs pass. The final route/context
corrections pass 49 API/native-tool tests, 90 real-database handoff
tests, and server typecheck; 142 Copilot installation/sidecar tests pass
with the refreshed identity.

Greptile’s first review found that successive prompt pages could mix
definitions after an edit. The fix returns a content fingerprint,
requires it for continuation, and rejects edits with 409. Strict
live/catalog schemas pass (171 Runner checks). The 2,005 API/OpenAPI
tests pass; the initial native regression caught compression’s weak ETag
prefix, and all 23 native integration tests pass after handling it. The
regression covers same-length edits and a four-byte restart window. No
stored version fields or entities were added.

The prompt extraction passes all 462 checks across six focused suites,
including persisted-context recovery and provider transport. The first
local transport attempt lacked the required debug Runner binaries (102
failures, retained); after building the normal prerequisites, all 283
tests in that suite pass without source or assertion changes. Existing
saved snapshots retain their recorded prompt text, and new executions
use core-only prompt v7. The extracted prompt source is now covered by
both CODEOWNERS and Copilot’s source fingerprint.

Live-provider evidence is separate from those simulated checks: the
isolated API-key campaign `reusable-workflows-api-final-2026-10-21`
passed with local code matching `a1d73b4652`. Four actual Codex API runs
read the adopted task documents, moved one case A → B → A on the same
task, completed normally, and passed all nine durable checks. Browser
assertions verified the current workflow/phase, historical names/phases,
five handoff records including terminal completion, and the completed
original task. Cleanup passed. The local report remains under
`tests/runner-e2e/results/reusable-workflows-api-final-2026-10-21/`; no
credentials or screenshots are committed.

CI initially caught an omitted route-inventory entry and a stale pinned
instruction-source hash; both are corrected and separately verified.
Local serialized coverage also recorded an unrelated environment-route
socket disconnect and activity-route timeout; their separate 11-test and
17-test suites passed without code or timeout changes. An unchanged
chunked-webhook check also passed its separate four-test rerun. The
initial adapter/database workspace groups hit time and resource limits
under default worker counts; complete reruns with `VITEST_MAX_WORKERS=2`
pass, including all 55 database files and 211 tests. The UI/CLI groups
passed 837 files and 9,442 tests in the original run. Original failures
remain retained and are not regraded.

Earlier failed live campaigns remain unchanged: subscription HTTP 429
before agent execution; an obsolete exact-four-row oracle that rejected
the valid terminal fifth row; and a chat-marker expectation that did not
account for the existing explicit-comment presentation policy. The final
fixture requires terminal completion and places the marker in its
authoritative comment. Positive/negative oracle tests and the fresh live
campaign pass.

## Risks

- The additive migration adds a table and nullable case/handoff fields.
Existing rows keep null workflow metadata; no assignments are inferred.
- Adoption can wait on an intervening task-document edit. Recovery must
cancel the old intent and accept a new one after readback.
- Shared definition edits affect future adoptions. Existing case copies
keep their revisions.
- The feature remains experimental. This PR does not merge or deploy the
change.
- Live acceptance covers native Codex before the prompt extraction; this
cleanup has contract/transport verification rather than a new
live-provider campaign. The refreshed Copilot identity has static
compatibility evidence, not new live-provider qualification.

## Model Used

OpenAI Codex, configured model ID `gpt-6-astra`, xhigh reasoning. Used
terminal execution, file editing, and tool calls. The active
context-window size 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
- [ ] 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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-21 15:00:12 -05:00
Devin Foley a1e2173ceb feat(apps): add Ditto connection (#16472)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents reach external services through the Apps catalog. Each
catalog entry is a reviewed `AppDefinition` that connects a provider's
hosted MCP server to Paperclip's shared vault, grants, policies,
gateway, and audit trail.
> - Ditto (`dittowords.com`) is a single source of truth for product
copy. Its hosted MCP server lets agents read style guide rules, search
and reuse approved text, and create, edit, translate and delete text,
components, variants and style guides.
> - Ditto is not in the catalog. Operators must use the generic "Connect
your own MCP server" flow. That flow has no branding, no guidance about
Ditto's `token` API-key scheme, and no warning about permanent deletes.
> - The generic risk classifier also reads several Ditto mutations as
reads: `translate_*` replaces variant text, and `link_*` and `unlink_*`
replace developer IDs.
> - This pull request adds the Ditto definition, its artwork, the
research and permission-review ledger rows, documentation, deterministic
tests, and one reviewed risk-classification rule.
> - The benefit is a branded, governed Ditto connection with browser
sign-in, an API-key option that uses the correct header, and correct
risk levels for every documented tool.

## Linked Issues or Issue Description

**Problem or motivation**

Product and engineering teams use Ditto to keep UI copy consistent. They
want their Paperclip agents to follow the Ditto style guide and reuse
approved strings when they write code. Ditto is not in the Apps catalog.
Operators must paste the MCP URL into the generic remote-MCP flow. That
flow gives no branding and no method guidance. It also does not tell the
operator that Ditto API keys use `Authorization: token <key>`, not
`Bearer`, and it does not warn that delete tools are permanent. The
generic classifier also marks five Ditto mutations as reads, so the
Permissions screen shows them with the wrong risk level.

**Proposed solution**

Add a catalog-only Ditto connection built from the connector playbook.
Browser sign-in uses dynamic client registration on Ditto's Auth0
authorization server and requests the reviewed scopes `openid`,
`profile`, `email` and `offline_access`. An optional method sends a
customer-created workspace API key with the `token` scheme. Both methods
share one `write` capability profile, so the delete and link warning
shows before sign-in. Add a reviewed `ditto` rule to `classifyRisk`:
`list_*`, `get_*` and `search_*` tools, `suggest_edit`, and tools that
Ditto marks read-only are reads; `delete_*` tools are destructive; all
other tools are writes.

**Alternatives considered**

A plugin was not needed because no custom UI, tables, workers, or
webhooks are involved. Requesting no scopes was not chosen, because
Auth0 issues a refresh token only for `offline_access`, so the
connection would expire with its first access token. Ditto's separate
documentation MCP server (`developer.dittowords.com/mcp`) was not added,
because it only searches Ditto's public docs.

**Roadmap alignment**

This extends the existing self-serve remote-MCP connection catalog and
does not overlap planned core work.

## What Changed

- Added the `ditto` provider to `scripts/ingest-app-definitions.mjs`
(category `content`, `token` API-key placement, guidance, warnings,
shared capability profile, description) and regenerated
`packages/shared/src/app-definitions/ditto.json` and the generated
registry.
- Added the Ditto row to the self-serve MCP research ledger with
`dcr_or_api_key` auth and risk tier S4, because the normal tool catalog
includes permanent deletes. Widened `SelfServeMcpResearchEntry.wave` to
include `4`, which existing entries already use.
- Added permission reviews for `ditto/mcp-oauth` (explicit scopes
`openid`, `profile`, `email`, `offline_access`) and `ditto/mcp-api-key`
(provider key), with evidence links.
- Added a reviewed `ditto` rule to `classifyRisk` in
`server/src/services/tool-access.ts`.
- Added Ditto's mark (`ui/public/brands/apps/ditto.png`, the avatar of
Ditto's official GitHub organization) and the brand manifest entry.
- Added gallery copy for the Ditto card.
- Added `doc/connections/DITTO.md` (sign-in sequence diagram, provider
and Paperclip endpoints including `/api/tools/oauth/callback`, scopes,
administrator setup, capabilities and policy, manifest, brand
provenance, validation hook) and linked it from the connections README
and the permission audit.
- Tests: Ditto definition shape, store visibility and artwork, URL
recognition, reviewed scopes, `token` header projection with the key
kept out of connection config, risk classification of every read-looking
Ditto mutation, the connect form's sign-in default, the warning before
sign-in, API-key gating, and the pinned catalog counts.

## Verification

- `pnpm exec vitest run packages/shared/src/app-definitions.test.ts
packages/shared/src/app-definitions-url.test.ts
ui/src/pages/apps/AppsConnect.test.tsx ui/src/pages/apps/Browse.test.tsx
ui/src/lib/app-brand-assets.test.ts
ui/src/pages/apps/AppLogo.brand-assets.test.tsx
server/src/__tests__/tool-access-service.test.ts` — 765 passed.
- `node scripts/check-app-brand-assets.mjs` and `node --test
scripts/app-brand-validation.test.mjs` — passed.
- `pnpm --filter @paperclipai/shared typecheck`, `pnpm --filter
@paperclipai/server typecheck`, `pnpm --filter @paperclipai/ui
typecheck` — clean.
- Manual: on a local instance, open Apps → Browse and confirm the Ditto
card and icon. Open `/apps/connect?source=ditto` and confirm that
sign-in is the default, that the warning shows before sign-in, and that
the API-key method is under Advanced.
- Live metadata probe: an unauthenticated `initialize` on
`https://api.dittowords.com/v2/mcp` returns 401 with
`resource_metadata`. The protected-resource and authorization-server
documents return the recorded endpoints. Dynamic client registration
succeeds, and the authorize endpoint redirects to Ditto's sign-in page
with the reviewed scopes and the `resource` parameter.
- Each of the 41 documented tool names was run through `classifyRisk`
with and without the new rule. Without the rule, `translate_text_items`,
`translate_library_components`, `link_figma_nodes_to_text_item`,
`link_text_items_to_component` and `unlink_text_items_from_component`
were reads.

## Risks

- Low risk to existing providers: the catalog change is additive, and
the new `classifyRisk` branch runs only for the `ditto` source template.
- Ditto delete tools are permanent, and linking a text item to a
component replaces its developer ID. Both methods warn the operator
before connecting, and the API-key helper text tells operators to set
delete and link actions to Ask first.
- Ditto API keys are not scoped, reach the whole workspace, and act as
the user who created them. Paperclip cannot narrow an issued key.
- The permission-review ledger records live proof for both methods as
not run. The lifecycle checklist in `doc/connections/DITTO.md` still
needs a documented pass with a Ditto workspace, including confirmation
that Auth0 issues a refresh token that `/v2/mcp` accepts.

> 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 (`claude-opus-5-5`, 1M context) in Claude Code, with
tool use (shell, file editing, web research).

## 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
2026-10-21 11:29:48 -07:00
Nicky LeachandPaperclip 42715d459f Support authenticated WebSocket routes and agent views in plugins (#17111)
## Thinking Path

> - Paperclip manages agents and their work.
> - Plugins provide optional views and connect to external runtimes.
> - A live runtime view needs a binary browser connection.
> - The current plugin API supports JSON routes but cannot proxy that
connection.
> - Agent detail tabs are declared in the plugin contract but are not
mounted on agent pages.
> - This PR completes those two host capabilities and keeps upstream
credentials on the server.

## Linked Issues or Issue Description

**Subsystem affected**

Plugin scoped API routes and agent detail views.

**Problem or motivation**

Plugins cannot expose a binary or text stream through a browser session
without exposing an upstream credential or adding a separate browser
gateway. Agent-scoped detail contributions also have no mount on the
agent page.

**Proposed solution**

Allow declared board GET routes to select a server-only WSS upstream.
Run upgrades through the existing HTTP authentication pipeline and
trusted Origin check. Add agent company resolution with the existing
`agent:read` decision. Mount contributed detail views in agent
navigation.

**Alternatives considered**

A separately hosted viewer needs its own browser credentials and
cross-origin policy. JSON or SSE transport adds encoding and buffering
to a binary protocol.

**Roadmap alignment**

This extends the existing plugin API and detail-tab contract. It adds no
desktop provider to Core. I checked ROADMAP.md and searched related open
PRs; I found no equivalent transport and agent view change.

## What Changed

- Add declared WebSocket routes requiring board authentication, GET, and
`http.outbound`. Reject body-based company resolution because browser
upgrades cannot send a body.
- Keep worker-selected upstream URLs and headers out of browser JSON
responses. Strip browser cookies and Origin. Preserve binary frames and
socket backpressure.
- Close both sockets on disconnect or worker shutdown. Reauthorize on
reconnect after a five-minute connection lifetime. Preserve HTTP
idle-work accounting for the stream lifetime.
- Resolve agent scope through `agent:read` and mount generic agent
plugin detail views, with current agent/view breadcrumbs and browser
titles.

## Verification

- Final head `9d8d269040acf9dc7bb65524876406af522dacb5`: CI passes
(including Runner Rust, build, and browser E2E); Greptile 5/5; no
unresolved review threads; no merge conflicts. Verified 2026-10-21.
- Core server TypeScript check: `node node_modules/typescript/bin/tsc -p
server/tsconfig.json --noEmit`.
- Focused server suites: 17 passing tests
(`server/src/__tests__/plugin-scoped-api-routes.test.ts` and
`server/src/http/server.test.ts`), including arbitrary build-output and
metrics channels with real local text and binary WebSocket round trips,
disconnect cleanup, denied actors and origins, credential exclusion,
agent-read denial, and cross-company 404 equivalence. The test replaces
TLS with local HTTP while retaining the real upgrade and binary stream.
- UI suites: 9 passing tests for independent Insights and Notes
contributions, removed contributions, built-in route preservation,
sidebar links, direct plugin entry and heading updates after tab
navigation. These contributions do not require the WebSocket transport.
- Shared validator suite: 42 passing tests, including rejecting
body-based WebSocket resolution while retaining ordinary HTTP body
resolution and accepting query/entity scopes.
- UI token gates pass.
- UI TypeScript check: `node ../scripts/storybook-catalog.mjs` then `tsc
-b`.
- Shared and plugin SDK builds pass.
- Full Runner build reached its unrelated Rust step and stopped because
cargo is unavailable. Runner TypeScript build was run separately. No
live remote VM was used.

## Risks

- This adds a browser ingress path for trusted installed plugins. The
plugin must select its upstream from a trusted binding. HTTP requests
cannot retrieve the upstream descriptor.
- Membership or binding changes are rechecked on reconnect. Connections
last at most five minutes, and worker shutdown is checked every five
seconds.
- Initial CI caught a missing cross-company 404 guard and an old test
that assumed exactly one upgrade listener. Both were corrected.
Greptile's body-resolution and stale-heading findings are fixed with
regression coverage; latest-head CI passes and Greptile scored 5/5 with
no unresolved findings.
- No schema migration. Rollback restores the previous Core image;
plugins using this transport must be disabled or rolled back first.

## Model Used

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

## Checklist

- [x] Thinking path and issue description included
- [x] Model described
- [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] No internal issues, private links, or runtime credentials included
- [x] Descriptive branch name
- [x] Focused tests and relevant typechecks run
- [x] Tests and documentation updated
- [x] Risks documented
- [x] All CI gates green
- [x] Greptile 5/5 with no unresolved findings
- [x] I will address review findings before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-21 10:10:00 -07:00
DottaandPaperclip 3ce8d976a9 Add experimental Paperclip Notebook MCP connection (#16984)
## Thinking Path

> - Paperclip connects agents to external tools through saved accounts
and per-action permissions.
> - Notebook exposes artifact management through an ordinary remote MCP
server with OAuth.
> - A private pilot needs a hidden, default-off catalog and execution
gate.
> - Local file publishing belongs to Notebook, which can accept bounded
file bytes through ordinary MCP tools.
> - Paperclip therefore needs the connector registration and generic
availability checks, with no file-transfer architecture.

## Linked Issues or Issue Description

**Subsystem affected**

Apps catalog, experimental feature metadata, connection setup, and
connector availability.

**Problem or motivation**

Users need to connect Notebook as their Cloud account, assign its tools
to agents, and retain Paperclip's normal Allowed / Ask first / Off
rules. The private pilot must remain hidden until an operator enables
it. Notebook should own its upload protocol and local publishing script.

**Proposed solution**

Register a personal remote MCP OAuth connection at Notebook's canonical
endpoint. Reuse existing OAuth discovery, credential storage, refresh,
reconnect, and removal. Enforce availability through generic catalog
feature metadata and saved application identity. Keep Notebook's
standalone uploader in its own service repository; it calls the ordinary
gateway and receives no saved OAuth credential.

**Alternatives considered**

A gallery-only filter permits retained tools and deep links while
disabled. A shared workspace publisher and private upload-ticket
transport add runtime behavior that a normal MCP connector does not
require. Notebook can receive file bytes directly through its own tools
instead.

**Roadmap alignment**

This extends Connected Apps and supports Artifacts and Work Products.
ROADMAP.md and related PRs were checked. This PR is standalone on
master. The separate OAuth lifecycle and file-transfer proposals (#17085
and #17086) are closed and are not dependencies.

## What Changed

- Register Notebook's personal MCP OAuth method, canonical endpoint,
scopes, catalog metadata, and branding.
- Declare managed `enablePaperclipNotebook` with false defaults and no
user-facing settings toggle or staging opt-in.
- Use generic availability metadata for gallery/setup, retained
connection identity, OAuth completion, health, tool/context discovery,
and dispatch. Resources/prompts recheck before credentials, including
retained handles. Removal remains available while disabled.
- Resolve catalog application identity from the saved application key,
so editable connection labels cannot bypass the hidden gate.
- Select a method's sole supported credential kind when no kind is
supplied.
- Keep UI changes to metadata-driven availability and existing
setup/reconnect controls.
- Document Notebook's service-owned upload script, inline publication,
ordinary action policies, and credential behavior.
- Add ordinary MCP OAuth, assignment, action-policy, disabled-state,
settings, and catalog tests.

No workspace contribution registry, private transfer endpoint, native
publisher, Runner file-reader change, or Paperclip CLI upload command is
included. The entire native-runtime and CLI trees match master. Upload
code lives in `paperclip-cloud/notebook/`.

## Verification

Source head: `65ef741e4f476c67425b57d2fb2d6d4c00e99b06`, directly on
master `53732c811bb69655eb43d3d12f2063ae4ca5ad67`. The diff is 42 files.
Shared execution changes only enforce generic catalog availability; tool
access also resolves saved application identity and the sole supported
credential kind. Neither module contains Notebook upload logic.

- Catalog/shared/settings/UI suites: 592 tests passed across 12 files.
Shared/server/UI typechecks passed using installed compilers.
- Fresh real PostgreSQL generic MCP suite: 84/84 passed at final source;
server typecheck and module boundaries pass. Coverage includes personal
OAuth, ordinary refresh/reconnect, assignments, Allowed / Ask first /
Off, hidden feature enforcement, and local credential removal. Four new
resources/prompts cases failed against the prior code and pass after
filtering saved application identity and rechecking before credentials.
They prove missing/relabelled setup markers and stale eligibility cannot
dispatch or read secrets while disabled; an ordinary provider remains
available with the flag off.
- The full tool-access service suite passed 463/464 cases. One unchanged
Google Workspace `slides.write` case timed out at 15 seconds; it passed
on one isolated retry without source or timeout changes. Its exact test
block matches master. The cause is not established; final-head CI must
qualify the complete suite.
- Maps, module boundaries, token gates, and whitespace checks passed.
Byte comparisons confirm the former transfer/runtime/CLI surfaces match
master.
- Fresh exact-head Greptile is 5/5 with zero unresolved findings after
an exhaustive feedback audit. Current-head CI workflow
[39625691137](https://github.com/paperclipai/paperclip/actions/runs/39625691137)
succeeded, including both required checks (`ci / verify`, `ci / e2e`),
Build, and browser E2E. Supplementary security/advisory scan status is
recorded in the PR Checks panel and qualification receipt; prior-head
scans are not counted. The superseded `4bd7af9b2e` completed CI
successfully, but Greptile found the valid resources/prompts
availability gap described above. It was fixed, replied to, and
resolved; earlier-head results do not qualify this revision.

Preserved environment failures: the first socket-restricted UI/route run
had 93 listener setup failures, and the same 93 cases passed with
local-socket access. The package-manager launcher could not fetch its
signature metadata; installed compilers passed without dependency or
configuration changes. The full service timeout and isolated retry
remain recorded separately. The superseded `585e870e73` CI also failed
an unchanged agent-chat project-plan revision assertion after task
creation; the complete spec and relevant runtime sources match master,
and a same-master prior run passed. Its cause is not established. Logs
are preserved; no test or timeout was weakened and no old-head rerun was
requested. The subsequent heads run full CI independently; no prior-head
pass substitutes for current qualification.

The Notebook uploader requires a separate service release. This public
PR adds no uploader runtime to Paperclip and claims no newly deployed
browser/agent acceptance. The Notebook-owned upload path is qualified
separately. Code-owner review remains required before merge.

## Risks

- The feature flag gates the curated connector; it does not create a
Notebook service-side team allowlist or block arbitrary standard MCP
URLs.
- Publishing, sharing, and deletion retain the existing assignment and
action-policy boundaries.
- The hidden feature must be checked for retained tools and saved
identity, including when connection labels change.
- Disconnect removes local credentials. It does not revoke the remote
Notebook authorization; the owner can revoke it in Notebook.
- Ordinary refresh uses the existing client. A lost response after
refresh-token rotation can require reconnect.
- The standalone Notebook script and its bounded upload tools must ship
together in the Notebook service before that documented convenience path
is available.
- No database schema, workflow, lockfile, shared transfer, or Runner
change is included. No merge, deployment, or rollout is performed by
this update.

## Model Used

OpenAI GPT-6 in Codex, with reasoning, repository inspection, code
execution, and tool use. 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-10-21 11:07:18 -05:00
Nicky LeachandPaperclip 79b2bf78dd Create agent records when onboarding names are submitted (#17005)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Core onboarding selects an agent and connects its provider account.
> - The current flow creates the agent record after authentication.
> - Setup needs a stable agent identity as soon as the user submits its
name.
> - This PR saves a paused setup record on name submission and finishes
the hire on that same record.
> - The existing sandbox authentication and approval paths continue to
apply.

## Linked Issues or Issue Description

**Subsystem affected**

Core agent lifecycle, shared validators, and onboarding UI.

**Current behavior**

Onboarding creates the database record at the final hire step. Earlier
authentication and saved setup have no agent record.

**Proposed behavior**

Create a paused agent with a setup hold when the user submits its name.
Do this before adapter selection or authentication. Update that same
record after adapter selection. Reuse its ID on retries and saved setup.
Finish that record through the existing hire path.

**Reason and benefit**

Give setup a stable identity without coupling this refactor to computer
provisioning or a new execution backend.

**Breaking changes**

Incomplete setup now leaves an inactive agent record. Existing clients
can still create and hire agents without the new optional fields. The
sandbox authentication flow and API key support remain in place.

**Additional context**

Requested Core-only refactor. Related work: #15422 changes runner
defaults. This PR preserves those choices. No duplicate early-record
refactor was found in the issue and PR search.

## What Changed

- Save the agent when the user submits its name in both onboarding entry
points. Use a provisional adapter until the user chooses one. Reopen
name-only drafts at adapter selection.
- Add retry-safe setup creation and same-record hire completion. Keep
approval checks at final hire.
- Save and restore setup configuration in both onboarding entry points.
Show Finish setup for paused setup agents.
- Restrict setup changes to authorized board users. Block generic resume
until setup finishes.
- Add lifecycle, authorization, connection, and UI coverage. Update the
specification and feature maps.

## Verification

- Latest focused server run: 126 lifecycle and AI-connection tests
passed after the Apex fixes. An earlier broader run passed 301
lifecycle, instruction, adapter-validation, and AI-connection tests.
Earlier authentication, retry, cross-company, and direct-create
regressions also passed.
- Name-save verification: 336 tests across the wizard, naming dialog,
New agent, action-button, and wizard-step suites passed. Coverage
includes retry identity, repeated submission, closing during a save,
saved-model restoration, and a disabled process adapter.
- Shared, server, and UI TypeScript checks passed. The latest UI package
check and direct server TypeScript check passed. The server package
preparation command could not finish locally because Cargo is
unavailable; full build preparation runs in CI. Map checks, token gates,
and `git diff --check` passed; each pushed diff was scanned for
credentials and PII.
- All six onboarding browser tests passed together with installed Chrome
against a fresh throwaway instance after the Apex fixes. They include
numbered duplicate names, first-time Copilot without a connected
account, and Grok’s saved model. They verify early persistence in both
entry points, closing and reopening a name-only draft, same-record
adapter selection, sandbox sign-in, login reload, and failed-connection
gating. Provider responses are simulated; Core persistence is real.
- Regression coverage includes incomplete Copilot creation versus final
validation, Kimi settings through redacted responses, stale local
drafts, company switches during creation, saved environments, and
provider changes with personal/shared old bindings.
- Apex found five name-only setup gaps: numbered names, early Copilot
account validation, the Grok model default, same-name draft ownership,
and provisional runner restoration. The fixes preserve server names,
defer implicit account binding until hire, set Grok’s model, avoid
name-based reuse of unfinished records, and restore Auto for pending
adapter choices. UI, database, and browser regressions cover these
cases.
- Standard Greptile found a Grok provider mismatch in the new adapter
save. The save now uses ACPX with the Grok profile. Both the 129-test
dialog/setup run and a real-API browser regression passed after the fix.
The first browser attempt stopped on an ambiguous empty-roster button
selector; it now scopes the click to the toolbar.
- Moving the save point exposed a saved-model reset and timing
assumptions in the same-name and portal fixtures. The source choice now
preserves the restored model, and tests cover same-name recovery without
a second hire.
- Initial CI exposed direct-create compatibility, concurrent setup
effects, fixture assumptions, and a missing-fields assumption in the
provider-validation guard. These were fixed and verified locally. Review
findings were addressed with authorization, recovery,
credential-persistence, and restored-configuration regressions.
- The final desktop capture passed after host resource cleanup. A repeat
first failed before Core started because macOS had exhausted
shared-memory IDs. Standalone PostgreSQL initialization reproduced the
same error. Releasing only unattached control segments from this task’s
stopped test databases allowed the unchanged revision to pass. No Core
or system setting changed.
- Local database tests required port access outside the sandbox. Missing
declared development dependencies were supplied outside the branch. No
live provider sign-in was tested locally.
- [Full monorepo
CI](https://github.com/paperclipai/paperclip/actions/runs/39522434236)
is green on `82b82fec189a172a885d4dd565ae2f4a18c73efc`. Standard
Greptile scored 5/5 with zero new comments (check `118969424903`). The
subsequent Apex review also scored 5/5 with zero new comments (check
`118972866331`) on that same commit. All review threads are resolved.
- The separate Superagent Security scan returned neutral/inconclusive
because its pinned merge-base checkout failed or timed out. GitHub
returned 404 for check and suite rerun requests. This is not a
successful security scan; the CI workflow and other security checks
passed.

## Risks

- Users can leave inactive setup records behind, including after name
submission alone. These records cannot run until hire completes.
- Setup completion touches hiring and approval boundaries. Tests cover
retries, company isolation, creator permissions, and approval snapshots.
- An uncertain credential-save result retains its new secret reference
for retry. A confirmed client rejection removes only credentials staged
by that attempt.
- No schema migration or VM provisioning change is required.
Agent-computer integration is out of scope.

## Model Used

OpenAI Codex, based on GPT-6, with repository search, code editing, and
tool execution. The exact deployment ID 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] Apex Greptile is also 5/5 on the same commit as standard review
and green CI
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 18:08:57 -07:00
DottaandPaperclip d33b40a5c3 fix: recover saved work and provide reliable task Retry (#16965)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The control plane must retain work when an execution or workspace
export fails.
> - Retained-workspace holds can leave saved input waiting with no
usable Retry action.
> - Users cannot verify process ownership or repair provider
allocations.
> - This pull request gives system recovery a durable budget and gives
each deliberate Retry a durable intent.
> - Safe recovery can preserve files, settle an accepted result, or
prepare an independent workspace.
> - One task state keeps infrastructure diagnostics out of the ordinary
conversation while preserving real permission and approval gates.

## Linked Issues or Issue Description

**What happened?**

A task with a retained workspace can show recovery, failed-run and
saved-message warnings at the same time. Historical runs without native
workspace descriptors cannot use the native restore path. Old recovery
metadata can prevent a new attempt even when an independent workspace
would be safe.

**Expected behavior**

Paperclip owns bounded infrastructure retries and file preservation. A
user can request another attempt with ordinary Retry. Thinking appears
immediately. The service preserves completed effects and current user
controls. It does not claim that starting fresh recovered the old files.

**Steps to reproduce**

1. Retain a failed run and its workspace after export or process-stop
failure.
2. Save a follow-up while the recovery hold is active.
3. Open the task and try to continue without infrastructure credentials
or operator certification.

Refs #16906, #16835, #16883. This extends their recovery and receipt
contracts. Related work: #16962 and #16963.

## What Changed

- Add task-level Retry with company-scoped authorization, all-status
idempotency and durable admission before physical work. Keep exact-run
Retry compatible.
- Add typed recovery phases, finite persisted backoff, historical
adoption and durable local failure diagnostics.
- Preserve native workspaces or verified historical snapshots. Admit an
independent fresh workspace only after execution containment. Keep
old-source preservation and cleanup obligations separate.
- Carry completed publication and API receipts forward. Fence uncertain
mutation retries across replacement runs. Preserve connected-chat
identity and authorization.
- Re-enter normal dispatch for saved input. Reuse accepted results
through the existing finalizer.
- Use one task interruption projection across the thread, composer and
task list. Show optimistic Thinking, ordinary Retry and genuine user
gates.
- Add PostgreSQL, filesystem, API, browser-fixture and controlled
provider coverage. Document the behavior and update the feature/access
maps.

## Verification

- All GitHub Actions CI jobs pass on
`6d8c6d27d50586d8548b31d03b47f6d73a0ee11d`: typecheck, all
server/chat/workspace and serialized suites, Runner checks, eight
browser shards, canary and build. The required merge gate passes.
- Greptile reviewed the final commit at 5/5, with no actionable findings
or unresolved review threads. Its two earlier P1 findings are fixed.
- Full recursive typecheck and build pass locally on the final commit.
All 16 task Retry cases pass against isolated real PostgreSQL. The
unrelated-success case and both stale Retry cases fail on the previous
code and pass after the fix.
- The corrected gateway fixture passes its uncertain-mutation and
independent-read case. Four real HTTP API cases pass for definite
403/422 rejection, completed-effect reuse, and uncertain-effect fences
across deliberate and automatic retries. These focused gateway/API
checks used a temporary database lifecycle harness on an existing
healthy local PostgreSQL process. The standard repository helper is
unchanged.
- Earlier qualification covers 291 task UI cases, saved-file copyback
and ancestry, current Agent Chat ownership races, nine chat Retry API
browser cases, and six assembled browser recovery fixtures. A real
API/PostgreSQL/native-runner journey showed Thinking in 25 ms despite a
delayed response, admitted one successor in a separate workspace,
retained original files, and survived reload.
- The controlled Daytona test interrupts export, joins the controller,
restarts it in a separate process, and verifies one agent start, one
external sentinel operation, retained file contents and no premature
cleanup. It does not establish abrupt-kill or live LLM/GitHub
acceptance.
- The full local `pnpm test:run` was attempted and was not green: an
OAuth row-lock timing assertion failed, and a later suite exhausted
macOS PostgreSQL semaphores. The ten OAuth timing cases passed on rerun
against a separate database. Later embedded database initialization
failures remain recorded; the final CI matrix passes.
- Security scanning passed on production-code commit
`63953edf069b111c6becc3144dffa6deb52f68b5`. Its only successor changes
one test-fixture identity line. The final scan is neutral/inconclusive
because its pinned merge-base checkout failed or timed out. Both rerun
API requests returned 404, so no fresh successful scan is claimed.
Socket and Snyk checks pass on the final head.
- The optional Paperclip Review remains queued behind an earlier run in
workspace finalization. Its prior completed assessment was incomplete
because a comparison tool was blocked by the platform filter. It is not
counted as a completed code review. GitHub does not require this check
for merge.
- Hosted acceptance remains pending deployment. Local and CI results do
not establish recovery of a hosted task or its retained files.

## Risks

- Recovery changes span admission, physical ownership and dispatch.
Incorrect evidence could permit overlapping work. Existing physical
locks and authoritative stop requirements remain in place.
- The migration adds concurrent indexes. It requires the existing
top-level migration runner and retries incomplete index creation safely.
- A fresh attempt can complete while old-source preservation remains
unresolved. The service retains that obligation and does not report
those files as recovered.
- Unknown tool mutations remain blocked until their authoritative
receipt owner resolves them. Generic upstream tools have no universal
result-query protocol.
- Recovery and diagnostics stay inside the stack. No Cloud incident
endpoint, notification worker or new outbound reporting channel is
included.

## Model Used

OpenAI Codex, GPT-6 family. The runtime does not expose a more specific
model version or context-window size. The model used reasoning, shell
execution, source editing and browser tools. No model subagents were
used for this implementation.

## 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; the full
local run limitation is documented 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-20 19:58:53 -05:00
DottaandPaperclip b11010b0d4 Simplify failure banners and show only the latest error (#16982)
Remove dashed failure dividers and show only the latest adjacent run or recovery error. Preserve permitted retries, pending state and unrelated notice boundaries. Add production-component Storybook examples and browser regression coverage.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-20 14:29:39 -05:00
DottaandPaperclip 505e1a5582 feat(cases): add persistent workflows with same-task agent handoffs (#16959)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - An agent workflow needs persistent facts and a safe way to transfer
work.
> - Creating a task for each phase splits the objective, discussion,
workspace, and review policy.
> - A case can retain the facts while one primary task moves between
agents.
> - Transfers must survive process failure and preserve private access,
budgets, and completion gates.
> - This pull request adds durable case handoffs, native case tools, and
read-only case pages.
> - Prompts describe the workflow. Existing task controls decide when
work can run and finish.

## Linked Issues or Issue Description

**Problem or motivation**

Prompt-driven agent teams need a persistent record that can move through
triage, implementation, verification, and correction. Ordinary
reassignment does not provide a durable instruction, safe release
barrier, or recoverable delivery receipt for an agent handing off its
own running task.

**Proposed solution**

Extend standalone cases with one primary task, a descriptive phase,
retained access sources, and a handoff ledger. Apply assignments after
source execution and workspace settlement. Deliver each transfer through
the existing durable wake queue. Provide `create_case`, `read_case`,
`update_case`, and `handoff_case` in the native runner. Creation
requires kickoff and explicit workflow text. An explicit handoff to
`done` closes the case when normal task completion is accepted.

**Alternatives considered**

Do not add a workflow engine, filesystem queue, configured state graph,
or one task per phase. The workflow document combines transition prose
with an optional Mermaid `stateDiagram-v2` map. The server does not
execute the diagram. The Pipelines experiment removed on master stays
removed.

**Roadmap alignment**

This extends Agent Reviews and Approvals, Enforced Outcomes, Bounded Run
Recovery, and Activity Log attribution. Existing approval, review,
budget, privacy, workspace, and responsible-user rules remain
authoritative.

Related work: [ordinary handoff wake
recovery](https://github.com/paperclipai/paperclip/pull/15019). This
feature adds a separate persisted case-handoff receipt and release
barrier.

## What Changed

- Add case routing fields, retained access sources, durable handoff
history, delivery leases, and replay-safe migrations.
- Keep the same primary task across agent phases. Preserve each
returning agent's own session and the task's workspace.
- Fence outgoing mutations, wait for provider and workspace release, and
recover delivery without duplicate task comments or runs. Recheck
current assignment permissions as the original caller before applying a
delayed transfer. Scope a run Stop to that run’s own handoff intents, so
repeated old Stop requests preserve newer work. Cancelling terminal
intent without a source run also requires fenced current task ownership,
including native retries and preparation with an old checkout. For Cloud
callers, revalidate current stack membership with an uncached Cloud RPC
and derive owner elevation from the current managed setting.
- Keep case reads, documents, assets, Audit, and live events inside
retained task/project permissions.
- Add native case creation/read/update/handoff tools. Store required
workflow text and initial documents on the first task. Page oversized
case facts and referenced document bodies through the dedicated tool
with bounded UTF-8 JSON, current routing versions, snapshot conflicts,
and current source authorization on every page.
- Add read-only case lists and detail pages, task-style list controls,
compact dotted field tables, linked handoff tasks, and case filters in
Audit.
- Add native/legacy integration tests, migration/restart tests, browser
coverage, and bounded live receipt fixtures. Extend the trusted sandbox
condition to cover the new subscription fixture profile.
- Hide obsolete paused-agent warnings on completed or cancelled task
threads.
- Synchronize the company-switch settings test with React effects after
a CI failure. Preserve its security assertions and production remount
behavior.

## Verification

The branch directly includes master `9ef434fe79`. The required `ci /
verify` and `ci / e2e` gates pass on head `765fccd67c`. [Current-head
CI](https://github.com/paperclipai/paperclip/actions/runs/39464348614)
passes typecheck, build, tests, and all eight browser shards. Security
checks pass. [Greptile gives this exact head
5/5](https://github.com/paperclipai/paperclip/pull/16959#issuecomment-6291156549),
with no unresolved review threads. The optional Paperclip Review check
remains queued because its assigned agent is paused. It is not a
required branch check. No check result was overridden.

Local workspace typecheck and build pass after the master merge, along
with database migration checks, token gates, map checks, Storybook
catalog checks, and the Copilot profile identity check. Standard builds
refresh Runner vendor output. Focused checks pass 2,008
API/paging/context tests and 7 strict case protocol tests. The final
commit changes one test fixture only; its ten tests, UI typecheck, and
token gates pass. No production source changed in that commit.

On current head `765fccd67c`, all **194 critical workflow tests**
executed and passed with no skipped tests in those files:

- 38 Stop/ownership tests, including board completion intent, native
retries, stale Stop, and preparation with an old checkout.
- 2 actual legacy process/HTTP handoff tests, including scratch failure,
a closed-stdio child that continues writing, and recovery through a
fresh worker after the process group stops.
- 5 migration tests, including SQL column metadata, preserved null
authority context, and all six prior-numbering receipts.
- 3 process-settlement and 5 scratch tests.
- 88 handoff-service, 18 heartbeat handoff, and 21 native case-tool
integration tests.
- 7 bounded case/document-read projection tests and 7 strict
protocol-contract tests.

The current CI checkout was `fed65d49`, merging `765fccd67c` into master
`9ef434fe79`. Its new document regressions reconstruct exact
Unicode/escaped bodies and revisions through real native authority and
authenticated HTTP with generic API tools disabled. They cover
case-owned, primary-task, and linked-task documents; routing on every
page; stale document snapshots; access loss and unlinking;
unrelated/foreign/private sources; system documents; and quarantined
content. Active-task document tools retain their existing behavior.
These are current-head test results from the first CI attempt; the
browser-only retry did not rerun these suites.

The full `64fdd3403f` CI failed one separate settings test: after a
company switch, it observed an unsettled API-key draft. The production
component and test were unchanged from prior green source. Production
switches remount both keyed settings layers; the test directly reused an
unkeyed view and used a timer tick instead of waiting for React effects.
The final commit replaces that fixture synchronization with React `act`.
The exact secret-clearing assertions and all timeouts remain unchanged.
The original assertion failure remains recorded; no unchanged retry was
used. The narrow unchanged baseline and fixed fixture each pass 10
tests.

The upstream result-paging merge preserves case capture namespaces and
current asset privacy. Its API integration suite executed 39 of 41 tests
successfully, with two skipped; the optional assigned-result PRP
integration test was skipped. Neither skipped suite is counted in the
194 critical tests or as live provider proof.

All 361 upstream migration entries and SQL bodies remain unchanged. Six
case migrations follow master as 0363–0368 with identical SQL hashes.
Official Drizzle generators produced the combined metadata and five
retained snapshots. Generation reports no schema changes, and the
snapshot drift test passes. The earlier `ce361ae5d0` CI passed on
attempt 1, including its then-current 179 critical tests. Fresh review
later identified unusable document references with generic API tools
disabled; the bounded document reads and ten additional authenticated
HTTP tests address that finding.

The full local `pnpm test:run` attempt was cancelled after this Mac
exhausted PostgreSQL semaphore capacity; it is **not** counted as a
pass. Later database attempts also stopped before assertions or skipped,
including one sandbox socket denial. Two original stale-Stop regressions
did reproduce the bug against the old source. A REST serialization
assertion passed after two preserved database-startup failures. No test
timeout was increased. All 194 assertions listed above executed and
passed in current-head CI. The complete 385-file, 3,963-test UI shard
also passed after the fixture repair.

A configured-provider receipt workflow passed 13 backend checks across
triage → implementation → verification → correction → done, using one
task and four work runs. The saved receipt is revision 2 with total 6
USD; case and task both closed. The original canonical attempt remains
failed because its browser assertion confused the terminal destination
with completed-task tooltips. The corrected full browser verifier passed
on the same retained database and original runs, with no additional
provider calls. The last clean-build browser readback is on
`6a86c54a53`; later changes affect recovery, authorization, bounded
reads, and settlement. Accounted work cost is a $1.010574 rate-card
estimate; provider billing and setup-probe usage are unavailable.

Copilot profile 49 passed the unchanged seven-fixture private protocol
pack (46/46 checks, no retries) and the product file-edit canary after
master's completion-replay change. All 60 bound implementation hashes
remain unchanged on the current source. Historical profile-47/48
identities and results remain intact. See the [profile-49 compatibility
record](https://github.com/paperclipai/paperclip/blob/codex/persistent-case-handoffs/doc/plans/2026-10-20-copilot-completion-recovery-compatibility-v49.json).
This is bounded compatibility evidence, not a fresh full matrix,
installed-package product test, or Daytona rollout.

Preserved CI failures and retries:

- On `20662930ac`, Slack managed setup failed a five-second success
assertion after reload. Its test/application path was unchanged from a
prior green head. One unchanged-source retry passed all 25 tests in that
shard; no source or timeout changed.
- On `9402b4f17a`, two CI workers received shutdown signals at 15:24:19
UTC. Neither log had an assertion failure before interruption. One
unchanged-source retry of each passed all Runner static checks and all
32 tests in browser shard 6; both aggregates passed. The next head,
`7b4374edaf`, passed all CI without retries.
- On `295f289b5a`, serialized shard 9 timed out during its first
device-login test, then the next test found an active login lease.
Direct login/test paths were unchanged from a prior green head. Cold
import plus a timed-out async body using the next test's mutable
actor/store is the supported fixture-race explanation; no request trace
proves that sequence. The original failure remains recorded. One
unchanged-source retry passed all 294 tests in 19 files, including all
41 device-login tests. No login source or timeout changed. The
subsequent `ce361ae5d0` CI passed without retries.
- On `64fdd3403f`, one company-switch settings assertion observed an
unsettled draft. The final test-only commit uses React `act` without
changing assertions, timeouts, or production code. On `765fccd67c`, all
ten settings tests and the complete 385-file, 3,963-test UI shard
passed.
- On `765fccd67c`, browser shard 3 completed the split-handoff
assertions, then cleanup received HTTP 500 from run cancellation after a
one-second PostgreSQL row-lock timeout. The extra chat run was reporting
completed work while teardown began. Cleanup stopped before restoring a
global experiment flag, causing a later assertion to fail. Relevant
production and test paths are unchanged from an earlier green commit.
Stop's lock order is consistent, and no nested self-lock was found; the
exact PostgreSQL blocker was not recorded. One unchanged-shard retry
passed. The original failure, trace, and downstream flag failure remain
recorded. No Stop implementation, cleanup assertion, or timeout changed.
The retry supports intermittent cleanup contention; it does not identify
the original blocking transaction.


## Risks

- Local process transfers require host-owned PID/group absence. Missing
or uncertain termination evidence keeps delivery pending, independently
of scratch setup.
- Handoff admission and task cancellation share execution ownership. New
regression tests cover temporary holds, late source writes, and
uncertain provider termination.
- Retained private sources use an intersection of existing permissions.
This intentionally fails closed when a source is missing or an existing
task cannot preserve that boundary.
- Migrations add tables and indexes. They preserve master history and
can replay over prior feature installs. Migration 0368 adds nullable
internal authorization provenance with no default or authority backfill.
Historical transfers still awaiting release without this context fail
closed; an operator must cancel them and request a new handoff.
- Delayed Cloud handoffs depend on the current Cloud membership RPC. An
unavailable, ambiguous, expired, or mismatched response holds the
handoff for retry; it does not reuse cached authority or grant access.
- Bounded reads reload and reauthorize the selected projection per page.
Underlying work grows with the data size and number of pages. Changed
data or routing requires restarting from offset zero without the old
snapshot.
- Phase names and workflow diagrams remain advisory. They do not satisfy
review or approval gates.
- This is a large, cross-cutting PR. The maintainer requested one PR for
the whole feature; the commits separate data, runtime, UI, and
qualification work.

## Model Used

OpenAI Codex, GPT-6 family, with tool use, code execution, and delegated
code review. The exact deployment model ID and context-window size were
not exposed in the session. Live fixture agents used the explicitly
configured provider model recorded in their test evidence.

## 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-20 12:46:14 -05:00
DottaandPaperclip 8ee851a0d8 fix(ui): keep runner turns stable through startup and completion (#16989)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task chat shows each agent turn from message submission through
completion.
> - Run admission can publish adapter metadata before native runtime
metadata.
> - The UI changed layouts during that gap and removed the agent
identity.
> - Completion reports can also arrive before the provider writes its
final reply.
> - The event reader treated those reports as final replies and then
replaced them.
> - This pull request keeps the runner layout stable and delays report
fallbacks until the final history fetch completes.
> - Readers see one provider reply, while report-only runs keep a useful
answer.

## Linked Issues or Issue Description

**What happened?**

Sending a task message briefly replaced the runner avatar, name, and
Thinking row with a generic Working row. At completion, a full report
summary appeared as the answer. A shorter provider reply then replaced
it while streaming.

**Expected behavior**

Keep the runner identity and header spacing stable during admission.
Stream the provider's final reply once. Use a report summary as a
fallback only after the run ends and its final history fetch completes
without a provider reply.

**Steps to reproduce**

1. Send a message to a native Paperclip Runner agent.
2. Observe the initial run record before native runtime metadata
arrives.
3. Let the agent call its completion tool before writing its final
response.
4. Observe the report summary, final response stream, and saved reply
handoff.

**Paperclip version or commit**

Reproduced from source at `6b804bfeba`. The event-reader behavior was
also present in earlier revisions.

**Deployment mode**

Self-hosted server. Local component tests and browser fixtures reproduce
the UI transitions.

Related work: Refs #12617, which added native runner turns to task chat.
The duplicate search found no open PR for this specific defect.

## What Changed

- Keep Paperclip Runner turns in the runner layout while runtime
metadata resolves. Use the same header spacing for queued and running
states.
- Keep structured reports as report entries. Do not create synthetic
provider final messages from them.
- Track successful event fetches for each run status. Permit a terminal
report fallback after the final fetch, or when the transcript contains
its terminal receipt.
- Preserve report-only answers and saved reply deduplication.
- Add desktop and mobile regressions for streamed replies, late final
events, report-only runs, pagination, and fetch failures. Delay
missing-answer notices until terminal history is ready. Document the
presentation rules in `DESIGN.md`.

## Verification

- Passed all 8,750 UI tests across 769 files. This includes 456 focused
tests for the thread, runner turn, native projection, native transcript
hook, transcript adapter, and boundary fixtures.
- The six completion regressions fail against the old native event
reader and pass with the fix. Three empty-history regressions fail
before the review fix and pass afterward. The startup regressions also
fail against the old layout condition.
- Passed UI TypeScript checking with `node
node_modules/typescript/bin/tsc -b ui/tsconfig.json`.
- Passed the UI production build with `cd ui && node
node_modules/vite/bin/vite.js build`.
- Passed `pnpm check:token-gates`, `git diff --check`, and the Storybook
catalog generator.
- Browser check: mounted the production turn with native event snapshots
at desktop and 390-pixel mobile widths. The report stayed hidden while
running. The actual reply stayed unchanged at completion. The
report-only fallback appeared after completion. The identity row kept
the same position and size. No browser errors or horizontal overflow
occurred. The temporary fixture was removed.
- Passed `pnpm -r typecheck` and `pnpm build`. Initial attempts failed
with `COPILOT_INSTALLATION_INVALID`. Reinstalling the generated Copilot
assets resolved that local packaging failure without source changes.
- The full repository test run was attempted locally and stopped after
repeated embedded PostgreSQL bootstrap failures in server suites. The
complete UI suite passes independently. In CI, serialized shard 5/9 had
one 15-second timeout in the unchanged `agent-live-run-routes.test.ts`
history-limit case; its other 387 tests passed. All five history-limit
variants pass locally. The single CI job retry passed. The original
timeout cause is not established.

## Risks

- Report-only answers appear later because the UI waits for terminal
history. Failed event fetches keep that fallback pending until a retry
succeeds; provider replies remain visible.
- Historical replies and accepted response-wake behavior retain their
existing resolution rules. The focused tests cover these paths.
- The change does not alter provider execution, completion authority,
database schema, or run timing.

## Model Used

OpenAI GPT-6 through Codex. The exact serving model ID and context
window are not exposed in this session. Used reasoning, code execution,
and browser inspection.

## 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-20 12:45:47 -05:00