Commit Graph
126 Commits
Author SHA1 Message Date
DottaandPaperclip 92b238137b Connect and configure GitHub Copilot through Apps (#15705)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Apps and AI Connections store credentials and govern access to agent
runtimes.
> - Users need a supported saved-token connection and config values that
survive save and reopen.
> - The release must preserve saved-token access and task lifecycle
guarantees.
> - This pull request will connect Copilot through the normal Apps and
AI Connections path.
> - The benefit is a reviewable part of the Copilot production release.

## Linked Issues or Issue Description

Refs #15701 and #15703. Supersedes setup work in #15562. Base: #15703.
Next: #15706.

## What Changed

- Require configuration update authority before Copilot
credential-bearing model discovery; default to the saved environment and
preserve explicit selection for editors.

- Keep Copilot discovery passive during reconnect reconciliation;
refresh on explicit opening, account/environment changes and reconnect.

- Add GitHub AI token connections with encrypted storage, ownership,
grants and audit logging.
- Keep repository access separate from Copilot runtime authentication.
- Probe the selected environment without sending a model prompt and
preserve authenticated model selection through save/reopen.
- Keep fresh execution admission consistent with normal Copilot setup;
persist task model choices without changing provider or permission
policy.
- Refresh authenticated models after reconnecting the same saved Copilot
account, including recovery from a previous authentication error.
- Apply the additive provider-default constraint migration through the
normal generated migration workflow.

## Verification

Runtime #15701 is merged at `d855e550ad8d2a267312983f26457aabf5393c3a`.
History #15703 is merged at `df80616d98119cbf5abd40549794d9980a5fabf6`.
Remaining source
[`42bcbd61299655f7e37aabe6bb5f19bba770ad1d`](https://github.com/paperclipai/paperclip/commit/42bcbd61299655f7e37aabe6bb5f19bba770ad1d)
contains the four-file authorization repair. The remaining PR trees
preserve six nonoverlapping files from the newer public mainline
managed-settings fix and the CI-owned lockfile. No unrelated provider is
enabled.

The security finding is repaired: existing-agent discovery requires
`agent_config:update` before connection selection or token resolution.
The saved environment is the default. Authorized editors can select a
prospective environment. Both denied board-viewer and agent-reader
regressions fail on the original source. All49 route tests and server
typecheck pass with the fix. Denied requests perform no connection
selection, credential resolution or probe. Current-head security scans
pass on both remaining PRs; the repaired thread is resolved.

Copilot CLI1.0.88 and profile47 retain digest
`sha256:55044aa235e88b3fe36ec8a556ee1e3382590870aab907e4462ef7d64af49cea`.
The [qualification
record](https://github.com/paperclipai/paperclip/blob/42bcbd61299655f7e37aabe6bb5f19bba770ad1d/doc/plans/2026-10-20-copilot-qualification-v47.json)
reports20/20 Product cells,154 assertions and7/7 protocol cases,46
assertions against frozen normal installed source
`c2616370800f5f6df45246b0890ba35a7cd2faab`. The exact qualification
model is `gpt-5.6-luna`. Every passing Product case confirms cleanup.
Original failures remain recorded; automatic behavior retries are
disabled. The route-only authorization repair changes no bound
runtime/profile bytes and does not relabel the frozen campaign.

The ordinary installed remote journey passed saved-token selection,
model discovery, normal UI save/reopen, metadata-only Test, completed
task, accepted receipt and exact19-byte browser download. An open model
catalog caused no additional discovery requests during117seconds. Actual
installed runtime smokes passed on macOS ARM64, macOS x64 under Rosetta
and native Linux x64 on Daytona. Raw token browser entry was not
exercised; encrypted connection creation used the normal API.

The first Daytona file attempt timed out during delayed semantic
dispatch; its precise stalled layer remains unresolved. Independent
ordinary remote delivery and the other19 Product cells passed before one
instrumented recheck passed8/8 with unchanged source,prompt,assertions
and deadlines. No causal latency repair is claimed.

Before the authorization repair, all four final PR heads passed required
verify/E2E and fresh Greptile5/5 reviews with zero unresolved threads.
Current-head CI/review is running for the two repaired heads. Local
focused checks retain129 connection,59 runner,72 shared-eval and88
recovery/workspace passes, plus migration safety and token gates. The
additive Copilot migration is361; released master history is preserved.

[Cloud normal-package
run39414239704](https://github.com/paperclipai/paperclip/actions/runs/39414239704)
builds the pre-security source4f3f. All four native producers and Linux
package assembly pass; the final clean installed consumers are
finishing. All18 retained archives match their hashes;37,863 regular
files contain zero selected credentials. That package does not contain
the later route repair. The actual final published package must include
it and pass the local/Daytona live canaries. The frozen Daytona image
remains published and independently verified. No separate full-image
scan is claimed. Docker builds run in the cloud.

**Remaining:** current-head CI/review, setup and qualification merges,
final publication, and ordinary local/Daytona canaries against the
actual shipped package. The user explicitly authorizes the maintainer
review override; CI remains a merge gate. No production deployment is
claimed. Provider USD remains unknown and GitHub-attributed.

## Risks

Bad credentials, missing entitlement, runtime installation and
unavailable models must remain distinct failures. A connection must not
adopt ambient credentials. The constraint migration changes accepted
provider values, with no credential-storage migration.

Current-master NewAgent fixture extraction is retained. Copilot cases
use that shared support and test both passive discovery and explicit
reconnect under the same setup lifecycle.

The onboarding retry regression shares the component suite’s
saved-connection, authenticated-model, draft, agent-list, hire and
render lifecycle fixtures. Keeping it beside the existing onboarding
failures makes adoption versus duplicate hire observable under the same
lifecycle; this is the concrete cohesion reason for the existing large
test file.

## Model Used

OpenAI Codex, based on GPT-6. The exact serving model ID and context
window are not exposed in this task. Used for code changes, review and
tool-assisted verification.

## 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-20 07:02:22 -05:00
DottaandPaperclip 45b67f1d93 feat: default new Apple Silicon Claude agents to Paperclip Runner (#15993)
## Thinking Path

> - Paperclip lets users choose an agent harness and account.
> - The server resolves the runner for new agents.
> - Claude still needs the same ordinary native-default journey as
Codex.
> - Existing agents must retain their runner, model and account.
> - This PR defaults new Apple Silicon Claude agents to Paperclip Runner
with Opus 5.5.
> - Users can connect and work without a runner override.

## Linked Issues or Issue Description

Refs #15683. This PR depends on #15994 and precedes #15997. Related
scope: #15422, #13978 and #15224.

## What Changed

- Resolve new Apple Silicon Claude agents to `paperclip_runner`,
`provider: acpx`, `acpxAgent: claude`. Keep explicit Legacy, models,
provider routing and saved execution.
- Use `claude-opus-5-5` for ordinary Claude defaults and retain explicit
overrides.
- Reuse existing API-key/subscription connections, credential storage
and checks. Generalize the shared Advanced runner control with Claude
branding.
- Carry configured effort into the shared v9 contract. Preserve
compatible permissions, instructions, skills, timeouts and session
behavior. Require Legacy for unsupported settings.
- Qualify a new immutable managed Claude target at explicit Connect
through the existing permission-gated probe. Use fresh scoped discovery
for test and hire. Discard stale results and require an explicit Connect
after settings change.
- Retain merged Codex onboarding recovery, auth preparation,
import/effort corrections and Grok Bot gates.
- Check the Claude first-task wizard's saved default directly. Update
configuration/runtime documentation and exact Opus 5.5 accounting.

- Align hire fixtures with the merged host-environment restriction.
Native agent-authenticated hires cannot inject host env settings; both
creation endpoints verify that no extra agent is saved.

## Verification

- Updated onto master `9179d8dcc3e908c217fde4f63c9d08ccf8132eeb` through
#15994. Native input v9 carries effort while preserving v7 home modes
and v8 Muse. Codex defaults remain unchanged.
- Focused local verification passed 285 server tests, 323 UI tests, 124
setup/registry tests, and two v9 permission-pin transport cases. Direct
server/UI TypeScript checks passed. An initial 30-second hook timeout
was resolved by serial verification with a longer hook budget: all 122
credential/permission cases and 232 snapshot/environment cases pass.
Direct server TypeScript checking also passes.
- Ordinary web creation with the experiment disabled saved native
Claude, Opus 5.5 and High effort without runner/model overrides. The
actual product task and follow-up both succeeded on integrated source
`b2c9fe43f9cd3bc5dd9d22552da0148845ba71a4` with the cloud-built daemon
from `04e0202ca81387b17cbe7fd094a8338648356fe9`. The final master
reconciliation also changes shared runtime source. Historical proof
retains its source identity; a final-source cloud qualification is
running before refreshing the preview daemon.
- Both actual browser downloads were checked: v1 has three sections/six
checkboxes (451 bytes); v2 preserves the original body and adds two
Rollback checks (612 bytes). The original attachment stayed
byte-identical. The follow-up records session resume and the same
provider session. Total estimated API usage: $0.518432800, with no
pending/unpriced usage in the successful fixture.
- Fixed the live-discovered setup incompatibility: native API-key
validation no longer depends on the global Legacy Claude CLI. The
existing provider endpoint verifies the key without a paid prompt;
subscription/custom routing probes remain intact.
- Fixed security review's native-hire credential redirection:
agent-supplied URLs, proxy/launch settings and other host environment
controls are rejected before inheritance. Native credential references
remain supported and partial edits use the saved harness. Added
create/hire/update regression coverage.
- Current-head cloud CI is green. All three stack PRs have fresh
Greptile 5/5 reviews and zero unresolved review threads. Required
typecheck, test and build gates ran in cloud CI; Docker work stayed
remote. Earlier failed checks remain in their original runs.
- Docker and native release builds ran in cloud infrastructure. An
inadvertent local Rust prerequisite was stopped; no local Docker build
was run.

- The final master merge preserves task-loading, permission,
skill-retention and OpenRouter changes. Pi uses a fresh combined profile
27, preserving both historical profile-24 declarations; Copilot remains
profile 22. Focused protocol checks passed 155 cases (one skipped), the
updated Pi attestation check passed 18 (one skipped), and 91
evaluation/catalog checks passed.

- Latest-application manual continuation passed in 37.942 seconds on
`695e5c005a85bddc8711d3fcddcaf6b7e1fb64d0`, with High effort, native
Opus 5.5, Anthropic API attribution, the same resumed Claude session, an
independently checked 635-byte file and persisted Done status. It uses
the earlier verified Mac daemon; the preceding-source package
qualification passed at `dca62c7aeb4b45f0dd91a8e18d386a16a2658ef8`. That
package run predates the small TypeScript startup fix and is not
relabeled as qualification for it.
- Upgrade limitation: changed compiled sidecar identity rejected old
durable launch state and recovery hit session-open bounds before
eventually resuming. That attempt was operator-cancelled and retained;
the successful manual continuation does not qualify seamless upgrades.

- Local latency profile, Opus 5.5/High unchanged: three alternating
real-ACP loopback samples per variant reduce median provider-ready time
from 5.081s to 4.034s. The matched real API task startup improves from
5.533s to 4.348s, but total reply time changes from 17.933s to 20.221s
because agent work varies. This establishes a startup saving of about
one second, not a consistent total-reply speedup. A real candidate
follow-up passed in 20.146s and resumed the same saved session. The
loopback fixture makes no external model requests; failed initial probes
remain retained.
- The startup change passes 107 focused runtime/effort/lease tests, 53
profile checks (one skipped), TypeScript checking and the
TypeScript-only runtime build. Native hire fixture checks pass 70 tests;
their first local run retained a socket-hangup failure and stale
OpenCode expectation, both accounted for before the passing rerun.
Broader required checks run in cloud CI.

## Risks

- Missing packages, authentication rejection, unsupported settings and
unavailable models must fail explicitly. Existing agents retain saved
execution; explicit runner changes use existing revision/session
invalidation.
- Subscription follow-up remains unverified; remaining live acceptance
uses API keys per human steering. Historical accounting holds and the
separate $50 ceiling remain intact.
- The subscription acceptance limit remains explicit for review. No
Claude database migration is introduced.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, code
execution and browser testing. 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
- [ ] Focused local tests and final cloud verification 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-19 13:58:52 -05:00
DottaandPaperclip fa50cab568 perf(ui): speed task loading without shifting the conversation (#16849)
## Thinking Path

> - Paperclip's board should open a task quickly while keeping its
conversation and composer stable.
> - The browser currently downloads unrelated screens and unopened
dialog implementations before task content appears.
> - Splitting routes alone creates many shared requests and did not
improve measured cold loading.
> - This change groups the startup and task dependency trees, preloads
the task chunk, and defers optional routes and dialogs.
> - Existing coordinated history reveal stays intact so late data does
not insert content above the reader.
> - Hidden routes must not overwrite saved scroll positions with
zero-height geometry.
> - Repeated browser measurements and delayed-response tests establish
the result independently of bundle-file size.

## Linked Issues or Issue Description

Refs #14758. Related prior work: #10463 and #14727.

**What existing behavior does this improve?**

Cold task-page opening downloads and evaluates code for other screens
and globally mounted, unopened dialogs. A direct task link should reach
its saved conversation sooner without moving already-visible messages or
the composer.

**Subsystem affected**

Board UI startup, route boundaries, dialog loading, task scroll
restoration, and the issue-detail performance harness.

**Proposed behavior**

Load optional screens and dialogs when needed, keep startup requests
bounded, and preload the task route. Preserve the current history reveal
policy. Keep the shell mounted during route loading and preserve the
reader's position when a route is temporarily hidden.

**Additional context**

The older bundle-splitting attempt in #10463 is still open from August.
This implementation targets current master and deliberately preserves
today's editor, composer, and transcript reveal behavior. It does not
implement the alternative transcript-row design discussed in #14758.
ROADMAP.md does not describe overlapping startup-bundle work.

## What Changed

- Lazy-load board routes, standalone screens, the legacy layout,
onboarding, and unopened create dialogs.
- Keep activated dialogs mounted across close/reopen to retain their
existing draft lifecycle.
- Group startup and issue dependencies and preload the emitted issue
chunk from the production HTML.
- Contain route loading within the shell and retain existing chunk-error
recovery.
- Contain dialog import failures locally, support cancellation, and keep
setup dismissed after a late download. Warm the task module from task
lists and keep the small chat redirect eager.
- Wait for task-creation dialog fields in the browser fixture before
filling an explicit title.
- Ignore zero-height scroll geometry while a route is hidden.
- Reuse the same persisted performance fixture between builds, record
actual network spans, and distinguish concealed loading content from the
ready thread in browser assertions.

## Verification

- Production UI build and UI TypeScript check passed.
- Recovery follow-up: 74 focused UI tests passed; the cancellation
change passed 23 focused tests plus all 131 onboarding tests (the latter
with a 15-second per-test timeout on the contended local host).
- Setup cancellation was reproduced against the prior production build
and verified fixed after releasing the held real wizard download.
- 91 focused UI tests passed; the final route registrations were checked
again after making standalone screens lazy (33 routing tests passed).
- All eight real-browser layout scenarios passed: delayed comments, late
media, properties changes, growing drafts, older history, Back
navigation, deep links, desktop/mobile same-task links, request
failure/retry, and stalled native/log reads.
- Browser walkthrough: read a populated task, submit one reply, refresh,
navigate to Projects, and return. The reply persisted once and the
normal composer remained usable.
- Token design gates passed. The separate repository-wide publish-token
scan fails on pre-existing references to the local maintainer username
in unchanged files; this change adds none.
- Production-build measurements use the same persisted task, local
API/database, fresh browser contexts for cold opens, and five samples
per scenario/profile. These measurements do not establish deployed
staging latency.
- Final head `076466816a`, consecutive before/after production builds:
five samples per scenario/profile, same saved task and server. Cold Fast
4G/4x CPU content paint: **5,775 → 4,248 ms (26%)**; issue API server
timing was 23 ms in both sets. Warm Fast 4G: 989 → 971 ms. JavaScript
transferred before content: **2,596 → 1,722 KiB (34%)**.
- Unthrottled cold content paint: 1,306 → 676 ms; warm: 269 → 224 ms.
These local timings vary with host load. Earlier measurements showed
about 20% cold improvement, and a contended intermediate run had
substantially higher API latency; those runs are retained in the local
evidence. The final matched pair meets the proposed 25% target, but it
does not establish a guaranteed 25% improvement across environments.
- All four browser scenarios that failed on the first CI run passed
locally after the readiness fixes; the subsequent CI run passed all
eight browser shards.
- Fault-injection browser checks: delayed route loading preserves shell
geometry; a failed route recovers through Back; cancelled or failed
dialog loading preserves an unsent reply; Back dismisses pending setup
and contains its late failure.

- Final head `076466816a`: all CI gates green (55 successful checks, no
pending or failed checks); Greptile 5/5 with no actionable findings and
all review threads resolved.

## Risks

- Dynamic chunks add a loading state on first entry to optional screens
and dialogs. Route failures use the existing error boundary. Optional
dialog failures are dismissible without unmounting the board; retrying a
rejected import requires a reload.
- The task preload prioritizes the primary board journey, including when
another screen is opened first.
- Chunk grouping should be revisited when the dependency graph changes;
bundle size alone does not establish a speedup.
- No API, authorization, migration, editor semantics, or
transcript-reveal policy changes.

## Model Used

OpenAI Codex, GPT-6, with reasoning, repository tools, code execution,
and browser verification. The runtime does not expose a more precise
model identifier 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-19 10:16:23 -05:00
DottaandPaperclip adb69e8f09 feat: default new Codex agents to Paperclip Runner on Linux and macOS (#15683)
## Thinking Path

> - Paperclip is the open source control plane for agent companies.
> - People choose a harness when creating an agent.
> - The server should resolve that harness to a qualified runner.
> - Codex is the first harness in the staged default rollout.
> - Saved agents must retain their execution choices.
> - New Codex agents therefore use Paperclip Runner on qualified
macOS/Linux targets, with an explicit Legacy override.

## Linked Issues or Issue Description

Refs #16028, #15555, #15673, #15422, #15631, #15926, #15932, #16149.

The runtime/install prerequisite and release repair are merged. This
slice owns Codex creation, setup, configuration and preservation. Other
harness defaults remain unchanged. It adds no database migration;
incoming master migrations, required maps and regression coverage are
retained.

## What Changed

- Resolve `runner: auto | paperclip | legacy` at the common creation
boundary across onboarding, API/CLI, hires, built-ins, plugins and
imports. Freeze pending hires and export resolved execution choices.
- Preserve existing runners on upgrades, unrelated edits and import
updates, including compatible accounts, workspace settings, Codex effort
and intentional clears.
- Use the underlying harness picker and branding; put the runner
override in Advanced. Use the shared dropdown and update
production-component stories and creation contracts.
- Support qualified Apple Silicon, Intel Mac, Linux x64 and Linux ARM64.
Linux requires GNU libc 2.39+. Disabled, external, unsupported and
unqualified combinations retain their applicable Legacy execution.
- Test the selected runtime/account/model/environment. Ordinary Connect
probes eligible immutable managed targets and refreshes scoped
discovery. Creation/discovery do not provision. Auth, dependency,
incompatible-setting and cleanup failures remain actionable without
changing runners.
- Keep setup probes read-only, preserve local/SSH isolation and resolve
packaged assets before staging credentials. Bound cleanup reads by the
remaining absolute deadline; physically close every owned ingress socket
before endpoint release. Unconfirmed cleanup retains recovery state.
- Preserve validated completed-onboarding callbacks through startup
recovery. First file-producing work belongs to the child task and uses
the existing dependency/block handoff and task-scoped registration.
- Reuse existing E2E fixtures, artifact checks, reporting and controls.
Keep Docker/Cargo/native compilation remote. Paperclip tarballs contain
no Codex payloads; official optional npm platform dependencies remain.

## Verification

Current tested head: `1c03a8815672d82c264a9b08d4ea1984e8fae107`.
**Merge-ready: required CI, fresh review, package qualification, Mac
core acceptance and Test task/follow-up acceptance pass.** The existing
attachment and native-continuity oracles independently verify both Test
downloads, run attribution and unchanged native/provider/workspace
identities. The maintainer authorized a code-owner-review exception for
this PR only. The first Test setup failure and normal Board
completion-review friction are retained below. Actual post-merge
packages and private Cloud distribution remain separate qualification
gates.

- [Current
CI](https://github.com/paperclipai/paperclip/actions/runs/38564241625):
all 48 ordinary jobs and required verify/E2E pass. Attempt 1 retained
six simultaneous host-shutdown cancellations. One failed-only retry
passes those six lanes and two aggregates, preserving 40 successes.
Actual integration checkout `53104c1` combines this head with master
`c80`; it is not relabeled as the branch tree. Fresh exact-head Greptile
5/5, 30 resolved threads, no actionable findings.
- [Exact-source package
qualification](https://github.com/paperclipai/paperclip/actions/runs/38565287239):
nine applicable jobs pass, nine conditional jobs skip. Four remote
native producers; Linux x64 clean install; Intel Mac, Apple Silicon and
Linux ARM64 native startup/physical cleanup controls. All 18
tarballs/four daemon source/hash/manifest bindings and 343 migrations
through 0344 verify. No Codex payload is packed. These hosted tarballs
are not a published npm canary.
- Normal Apple Silicon installation and credential-free native
startup/cleanup pass using the packaged daemon, with no source build or
provider turn. Fresh installed DB initialization passes. Upgrade
651a→1c03 preserves all three complete execution configs, accounts, ten
recorded run profiles, paused budgets, active incidents, cost summaries
and two historical unpriced events. Historical recovery state is
retained.
- Cleanup regressions: four delayed-read baseline failures become 15
passing deadline/authority controls. No-acknowledgement and prior-error
socket ownership regressions become 12 passing controls. Direct
runtime/server types, maps: 35 areas / 176 IDs, diff checks and
independent reviews pass. Permission/auth/reconnect policy and the
10-second setup budget remain intact.
- Existing source coverage includes creation/selection/imports, pending
approvals, recovery, account/lifecycle handling, mounted forms,
dropdowns and E2E support. Full typechecks/tests/build/token and
applicable Storybook checks pass in the recorded current CI; no
duplicate suite or weakened grader.
- Literal 9546 live Mac proof: ordinary Auto Codex onboarding, useful
document, real completed-child callback/reply, seven successful native
runs, manual follow-up and independently downloaded1,101-byte child
file. Existing Legacy title edit/reload preserves execution; two real
Legacy runs produce independently checked15/34-byte files. These remain
historical source records.
- Current literal 1c03 Mac core acceptance passes independent checks:
ordinary Auto native Codex onboarding without runner override; only
timeout 180 seconds/concurrency 1 saved; six successful native runs and
six serialized turns (maximum overlap 1); both same-task continuity
checks and five mechanical callback checks; actual rendered parent reply
and exact child downloads. The useful handoff advances from revision 1
to 2. Both files are 48 bytes, SHA-256
`8b742bd4e8123a7c078f0a8d9f3449fbfa8a320d7d90be641a2818db3c53d92c` and
`f42db9774fa06e804ab7d596fc8b922a2b638921c418b87d0111151d290a6afe`;
exactly one byte changes and old history remains. The agent is paused
with zero active runs/errors. Both artifact work products have
`isPrimary=false`, and descriptive titles fail a stricter title-helper
assumption; these retained results are scoped editorial follow-up, not
new merge gates. Six source-bound screenshots are uploaded and verified
in the private primary QA report.
- [Literal 9546 managed
proof](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-38485488621-1/index.html):
original 19 assertions and completed judge pass, four native turns,
child-bound240-byte file and session/workspace continuity. Checkout
reports a verified generated target-lock mutation; full final porcelain
was not retained. Signed execution-image identity remains separate from
Core source.
- Actual 651a Test deployment succeeds on one owned/pinned target. One
ordinary Auto API-key Connect then fails native cleanup before hire.
Controller turn/drain/suspend completion and service-recorded
environment cleanup are observed; they do not certify physical deletion
or native authority retirement. Failure/recovery/unknown holds are
retained. No Legacy switch or unchanged paid retry. The two source
repairs above require actual treatment.
- [Current immutable Core
preview](https://github.com/paperclipai/paperclip/actions/runs/38570365725)
and matching DB/shared artifacts pass. One owned, pinned Test target
serves exact `1c03`; identical migration history correctly skips the
migrator. Ordinary Auto Codex Connect succeeds and hires native; saved
native selection and QA bounds survive reload. The initial child
preparation attempt fails before provider work, with actual stdout
identifying `renewal_deadline`; its trigger remains unknown and the
failure is retained. Normal Board **Try again** and **Resume** recover
the child to Done, producing a browser-verified 44-byte file, SHA-256
`0a8458b1efcc2d7a0d815689458c4caab039a46c7c7a3e5805de6bc8b1a96ecc`. The
actual parent callback reports the completed child document/file. The
existing validator requires a parent-owned attachment, so recovery
enters normal Review; after byte checking, normal **Approve completion**
reaches parent Done. No forced status or duplicate parent file is used.
The validator is unchanged from integrated and current master.
Autonomous initial callback-to-Done is not proven. The same-child
follow-up completes document revision 2 and publishes a second
independently downloaded 44-byte file, SHA-256
`22022257300fae762784632d08d3bbe0bab61e2ce81f91864a14dcd7aa464591`; only
the revision digit changes. The unchanged existing native-continuity and
attachment oracles pass. All ten recorded runs are terminal: nine native
successes and the retained pre-provider setup failure. The QA agent is
paused with zero active runs. The pre-existing parent evidence scope
mismatch is a separate follow-up, with ordinary completion review
exercised rather than a forced status or relaxed validation. This
unsigned Core preview remains distinct from post-merge private Cloud
composition.

## Risks

- Saved agents are not migrated. Explicit runner changes use normal
configuration/session rules; historical runs retain their recorded
execution.
- Native readiness depends on verified assets and server-owned target
qualification. A Legacy probe, HTTP200 or successful account save cannot
prove native readiness.
- Recovery exceptions remain restricted to validated
completed-onboarding reports; process-loss, ownership and terminal-state
safeguards remain active. Unexecuted live journeys stay open.
- Linux ARM paid tasks, Windows, Alpine and 32-bit ARM remain deferred.
Cold Cargo cache misses are recorded; no warm-cache speedup is claimed.
- Historical invoices/physical cleanup remain unconfirmed and held.
After merge, exact published npm canary, signed standard image/migrator,
private composition and serving/live acceptance still require
qualification. Production deployment/default promotion is not
authorized.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tools, code execution and
parallel agents. Exact serving snapshot 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 available 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 linked public issues or PRs above
- [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 the stated focused 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 risks
- [x] All Paperclip CI gates are green on the current candidate
- [x] Greptile is 5/5 with no open findings on the current candidate
- [x] I will address all reviewer comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 11:33:02 -05:00
DottaandPaperclip 9f7057e122 feat(connections): configure custom model providers across agent harnesses (#14970)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents use a harness, a model, and a credential to run tasks.
> - Connections already store credentials and control who can use them.
> - Custom providers also need an endpoint and a supported API format.
> - A per-agent endpoint would duplicate credentials and access rules.
> - This pull request stores routing on the connection and projects it
into the harness.
> - Isolated credentials and protocol checks keep the selected
connection authoritative.

## Linked Issues or Issue Description

Refs #37, #13083, #14104, #14565, #12692.

#14016 is a reference only. This PR has its own schema, vault
persistence, routing validation, runtime projection, and tests. None of
the five commits in #14016 is an ancestor of this branch. We do not
depend on or plan to merge it. #14967 addresses task-pinned account
pools. #14422 addresses another provider integration.

This is the first of two linked PRs. Merge this connection change before
#15341, which refines agent setup and adds the qualification harness.
The split keeps each review below 100 changed files. Provider catalog
entries have usable setup forms in this PR. Local browser subscription
sign-in is included.

## What Changed

- Store non-secret routing metadata on AI connections. Vault provider
API keys, including Bedrock bearer API keys. Reject general AWS access
keys.
- Enforce company, owner, human audience, agent access, connection
status, and protocol checks before resolving credentials. Keep reconnect
destinations immutable and retain connection identity during key
rotation.
- Project OpenRouter and compatible custom endpoints into Codex, Claude,
OpenCode, and local Hermes. Carry these settings through both legacy and
native runner transports. Clear conflicting host credentials and redact
keys from diagnostics.
- Preserve older OpenRouter accounts and native personal defaults. Add
Google API-key accounts and migration `0306` for the two
provider-default constraints.
- Run local Claude and Codex subscription sign-in behind the existing
browser sign-in card. Use private attempt homes and owner-bound
completion instead of a copied terminal command.
- Seed isolated Gemini authentication and preserve OpenCode workspace
permissions. Keep the selected connection authoritative. The independent
Gemini and Grok workflow fixes are in #15341.
- Keep native OpenCode custom gateway keys in a runner-owned
selected-model proxy; the harness config contains only a session-scoped
capability. Honor runtime outgoing proxy and certificate settings.
Preserve streamed responses and revoke the proxy on close or startup
failure.
- Allow ordinary members to connect native personal accounts before an
agent exists.
- Repair routed accounts from task cards using the saved provider
destination, protocol, model aliases, and connection identity.
- Add provider catalog definitions, model discovery, pinned logos, and
complete native and routed setup forms. Allow a personal routed
connection before a new agent exists. Keep endpoint authentication keys
out of Hermes terminal children.
- Recover cancelled or restarted browser sign-in with a clear restart
action. Support no-auth endpoints without a vault credential. Add
isolation and recovery regressions and runtime documentation.

## Verification

- Updated with `origin/master` at `22a3ea341`. Migration `0306` follows
the new master migration and passes migration and snapshot checks.
- The integrated connection regressions passed 152 tests and 50 native
OpenCode driver tests, including key-free child-shell configuration
reads, authenticated/no-auth forwarding, streaming, model/path
restrictions, cancellation, outgoing proxy routing, and NO_PROXY bypass.
Provider setup has 14 passing tests. The pinned real OpenCode 1.18.34
executable also completed a turn through the proxy against a local
synthetic provider; the reusable key was absent from its config. A
second real-executable smoke passed with an HTTPS CONNECT proxy and
runtime-specific synthetic certificate trust. Certificate-file and
certificate-directory regressions pass.
- Task-card repair passed 48 tests, including OpenRouter, Bedrock, and
custom gateway reconnect cases. UI typecheck and token gates passed.
- The prior core regression set passed 133 tests across new-agent setup,
provider forms, browser sign-in, routing projection, and connection
authorization. Token gates and UI typecheck passed.
- Full workspace typecheck and production build passed again after the
latest integration and credential-proxy fix. The merged deterministic
runner E2E suite passed 1,400 Vitest tests and 128 Node tests.
- Full workspace typecheck passed on the prior linked combined
implementation. Production build, Storybook build, 1,316 browser-harness
Vitest tests, and 128 Node tests passed. Head `9d964c8d9` includes the
latest master integration and regenerated migration. This exact head
passed 54 remote checks with four expected skips and Greptile 5/5; no
review threads remain open. An unchanged server fixture had a random
six-character issue-prefix collision on its first attempt. All 245 tests
passed locally and the single CI retry passed.
- A provider-free terminal check used the cited supported Hermes source
and dummy keys. Gateway and OpenRouter terminal children could not read
the selected key.
- The broad local Vitest attempt passed 15,442 tests but was not green.
It had an embedded-Postgres startup failure, an HTTP logger timeout, an
origin socket error, and a browser cancellation wait timeout. The
cancellation wait was corrected. The relevant connection tests and the
full origin test file passed separately. Latest-head CI must pass before
merge.
- Prior credential-backed acceptance exercised task creation, tool use,
artifact delivery, completion, and context-dependent follow-up. Claude
legacy and native runners passed Bedrock with `us-east-1` and
`us.anthropic.claude-sonnet-4-6`.
- Historical local qualification retained 43 passing API/gateway cells
out of 46. Those attempts span earlier builds. They do not qualify this
exact commit or staging. All subscription combinations and staging
remain unqualified.
- Verify native subscription and API-key setup. Connect a regular
provider catalog row. Verify an incompatible harness and a changed
reconnect URL are rejected. Use #15341 for the complete browser
campaign.

## Risks

- Migration `0306` changes two check constraints. It preserves rows and
is safe to reapply. It takes normal constraint-change locks.
- Credential projection touches several harnesses. CLI upgrades can
change provider configuration and session behavior.
- The native OpenCode proxy adds a loopback hop, pins requests to the
selected model, limits request bodies to 16 MiB, rejects redirects, and
expires at session close. It prevents reusable keys in the child
configuration; it is not an OS isolation boundary against a process
debugger running as the same user.
- Custom endpoints must be reachable from the agent environment. Saving
a connection does not prove connectivity. Bedrock keys require rotation
before expiry.
- Gemini CLI 0.58.0 has an upstream ACP new-file error conversion
defect. Provider overloads and an unresolved follow-up timeout also
affect live Gemini qualification. We have not patched the installed CLI
or marked those cases as passing.
- OpenClaw Gateway, Hermes Gateway, Claude Managed, AWS AgentCore,
Process, HTTP, and legacy ACPX local are excluded. Vertex, ambient AWS
identity, arbitrary auth headers, and custom routing for other harnesses
are excluded.
- These PRs do not establish production or staging qualification for
every provider and login method.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, code
execution, and browser testing. The exact deployment 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
#` / `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-06 13:29:03 -05:00
86b7ee992c feat(onboarding): ClipLab sleepy-to-wake hero and step hand-offs (#13629)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents have a persistent visual identity (#13171): a ClipLab
character in one of 17 palettes, rendered as cached PNGs in lists and as
a live character in larger placements.
> - The onboarding wizard is where a person meets that identity first,
and it showed a stock ClipLab expression on the previous engine while
the rest of the app would show a different character on a newer one.
> - The wizard's steps also cut from one screen to the next, so the arc
read as separate pages rather than one walk.
> - This pull request puts one character on one engine everywhere, gives
the wizard's hero the studio's sleepy → wink → idle sequence on Review,
and hands the steps over inside one presence.
> - The benefit is that what wakes on Review is exactly what the agent
looks like on the dashboard afterwards, and the walk to it reads as one
screen changing.

## Linked Issues or Issue Description

Refs #13171, now merged into master. This PR contains the onboarding and
ClipLab update on top of that foundation. Original feature work by
@tonio-alucema; merge preparation preserves the original commits.

**Problem or motivation**

The onboarding hero and the app's avatars were two different characters
on two different ClipLab engines. Steps 1 → 4 of the wizard cut between
screens, and the wizard mounted cold when a cloud-managed workspace
arrived from Cloud's naming screen.

**Proposed solution**

Vendor ClipLab v0.2.0 as the shared engine and render one
studio-exported character from it in every palette, for every pose and
size. Play the export's one-shot wake on Review with the palette fading
in over the gray dormant loop. Hand steps over inside one presence so
the footer slides instead of jumping, and play the arrival half of that
hand-off when the wizard opens directly on the agent step.

**Alternatives considered**

Exporting mp4/webm loops per size: no cursor following, no clean alpha,
and the palette "colour in" is a runtime blend. Minting a `cap-v2`
character version: nothing had shipped `cap-v1`, so the artwork is
regenerated in place instead of migrated. Keeping the separately
vendored runtime bundle for the hero: two engines and two characters in
one app.

## What Changed

- `packages/shared/src/cliplab`: re-vendored from ClipLab v0.2.0
(`987b6db0`) with the Paperclip adaptations replayed (optional graphics
backend for the Node SVG snapshot path, supersampled live textures,
character framing, deterministic SVG id prefixes); new upstream
`particles.ts`.
- `packages/shared/src/cliplab/character.ts`: the studio export,
mirrored from `ui/src/assets/cliplab/onboarding.character.json` by
`scripts/sync-cliplab-character.mjs` (drift caught by
`check:token-gates`). `characterDefinition` builds every palette from
it; the resting portrait is its idle beat.
- `OnboardingCharacter`: gray `sleepy` loop through the agent and
connect steps; on Review the one-shot sleepy → wink → idle plays on two
lock-step canvases while the palette fades in, then the `idle` loop.
Body-follows the pointer, page-scoped. 160px in the wizard.
- `OnboardingWizard`: steps 1 → 2 → 3 → 4 hand over inside one
`AnimatePresence` (departing content fades and gives its room back;
arriving content opens its room then fills); the hero has a room that
opens on the walk into the agent step; opening directly on the agent
step plays the arrival half; the self-hosted naming step uses the arc's
label and field.
- Motion vocabulary in `onboarding-motion.ts` (`stepContentMotion`,
`ledeMotion`, `heroRoomMotion`, `heroRoomArrival`, `titleSwapMotion`).
- Storybook: `Onboarding / Character` (Wake Up), `Onboarding / Agent
arc` walkable from the naming step plus `Arrive From Cloud`; the
companies fixture answers the wizard's create call with a company.
- Uses the shared runtime for onboarding; `doc/agent-personas.md`
documents the shared character.
- Releases both onboarding canvases after partial startup or transition
failure. Registers each canvas before seeking so synchronous render
errors can release it. Six component tests cover these failures and
palette changes before or during wake.
- Refreshes both sleeping canvases when the palette changes, including a
palette change in the same render as wake.
- Moves choreography values into the CSS token layer and preserves the
shared motion catalog drift check across the imported stylesheet.
- Repairs the static Storybook avatar route and uses accessible heading
names/current button labels in the wizard play functions.
- Closes the lazy avatar worker pool during application shutdown.

## Verification

- Merge-preparation checks: `pnpm -r typecheck`, `pnpm build`, `pnpm
build-storybook`, and `pnpm check:token-gates` pass. The final UI
typecheck and 123 focused onboarding, lifecycle, and token catalog tests
pass. All 55 checks on final head
`b4f5e201a1564083d163abc6f93f5b3da06ccefd` pass, including the full
sharded test suite, runner verification, and all eight browser shards
([CI
run](https://github.com/paperclipai/paperclip/actions/runs/35445430535)).
The duplicate monolithic local `pnpm test:run` was stopped after CI
completed; it is not claimed as a separate completed local run.
- Chromium walkthrough: palette change, wake, return to sleep, WebGL
failure fallback, Review step hand-offs and cloud arrival pass with
normal and reduced motion; no browser errors. The signoff happy-path
browser test also passes against a disposable instance.
- The final CI run confirms the catalog fix and a passing signoff
browser shard. The earlier signoff failure was a heartbeat-run
availability timeout; the focused local reproduction and final CI passed
without signoff code changes.
- Original author verification:
- `pnpm check:token-gates` (includes the new character sync check);
shared, server avatar/persona (17) and UI onboarding/persona (137)
suites pass; `pnpm build-storybook` packages all 3,564 avatar PNGs
through the worker pipeline.
- Storybook: `Agents / Personas` Sizes, Expressions and Palettes render
the studio character at every size and pose; `Onboarding / Character →
Wake Up` plays the wake on the shared engine; `Onboarding / Agent arc`
walks 1 → 4 with the hand-offs, and `Arrive From Cloud` plays the
arrival (measured: content room 6 → 65px over 320ms, fade to 1.0 by
~560ms, footer travel continuous).
- The original author walked the agent → connect → review flow and wake
after a real sign-in on staging.
- Not done here: the Linux Storybook visual baselines
(`tests/storybook-visual/agent-personas.spec.ts`) need re-baselining for
the new engine, hero size and naming-step changes.

## Risks

- Every avatar's pixels change (new engine, new character) under the
unchanged `cap-v1` name. Stacks that rendered avatars on the previous
engine keep those PNGs in their cache
(`generated-agent-avatars/cap-v1/...`, served immutable) until cleared;
only the two pinned staging stacks ever did.
- The one-shot handoff to the idle loop is timed from the sequence's
authored duration (the engine reports completion by continuing into idle
itself); presentation only, nothing in the wizard's state waits on it.
- Reduced motion skips the wake and the hand-offs; jsdom is treated the
same way, so the wizard tests see the next step's content immediately.
- The committed export differs from the studio by one animation (Loop
off, leading idle step removed); a re-export without that fix would play
a 5.6s idle before the wake.

## Model Used

Original feature: Anthropic Claude Fable 5.1 (`claude-fable-5-1`) in
Claude Code, with shell, browser, and file tools. The original context
window was not recorded.

Merge preparation and lifecycle regression fixes: OpenAI GPT-6 in Codex,
with reasoning, shell execution, file editing, GitHub CLI, and automated
tests. The session does not expose an exact runtime 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

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

---------

Co-authored-by: Dotta <bippadotta@protonmail.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 08:30:14 -05:00
1ef3b08714 feat(ui): integrate agent personas across the app (#13171)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A stable agent persona is useful only when the same identity appears
across the app.
> - Lists, task messages, selectors, and activity feeds need inexpensive
static avatars.
> - Onboarding and agent headers need a larger character with
expressions and pointer tracking.
> - This pull request connects the persona foundation to those existing
views and preserves onboarding draft assignments.
> - Full-page stories and Linux checks make the placements and
performance contract reviewable.

## Linked Issues or Issue Description

**Problem or motivation**

Agents need a stable visual identity in lists, tasks, onboarding, and
configuration. External tools also need an image URL for that identity.

**Proposed solution**

Assign each agent a permanent palette from a fixed ClipLab character
library. Store the assignment on the agent. Render and cache preset PNG
URLs on demand. Use static images in dense views and one animated
character in larger placements.

**Alternatives considered**

A generated image bundle requires a separate asset build. A live
renderer in every avatar adds unnecessary work in large lists. Arbitrary
uploaded images do not provide the requested shared character system.

**Roadmap alignment**

This improves agent identity across existing control-plane views. It
preserves agent permissions, company boundaries, and status labels.
ROADMAP.md has no separate ClipLab persona milestone.

Related approaches: #2422 adds configurable image URLs and DiceBear
generation; #5578 adds optional uploaded avatars. This work uses a
fixed, versioned character library and preset URLs.

## What Changed

- Replace agent icons with static persona images across lists, the
sidebar, org charts, tasks, comments, selectors, activity, and dashboard
views.
- Put one animated character in the agent header. Let it follow the
pointer across the page, with reduced-motion and touch fallbacks.
- Add larger padded characters to agent creation. Keep the palette
stable across draft refreshes and connection retries, then reveal it
after success.
- Pass appearance through shared projections rather than fetching each
agent separately.
- Add real full-page Storybook examples for the agent list, overview,
task, dashboard, new-agent dialog, and connection page.
- Add Linux screenshot, clipping, density, and 500-avatar performance
checks.

## Verification

- `pnpm -r typecheck`, `pnpm build`, and token gates pass on the rebased
tree. Persona lifecycle tests pass.
- The rebased feature passes 38 Linux screenshot/performance checks,
including both display densities, corner pointer positions, and the
no-WebGL/no-live-download contract for 500 avatars.
- The final Linux persona suite passes all 38 visual, lifecycle,
density, and full-page checks using the standard Storybook configuration
and real on-demand avatar endpoint.
- Final local focused verification: 45 avatar/native-recovery tests
pass; UI identity/routine tests, typecheck/build, token gates, and
Storybook build pass.
- Current-head CI passes: full workspace/server tests, all serialized
server groups, typecheck/release checks, build, canary validation, and
end-to-end shards. The build passed after retrying a native-runner
concurrency-test failure; its three targeted cases also pass locally.
- Manual inspection covered stable identities in the app, header
placement, full-page mouse tracking, onboarding size, and task/dashboard
placements.


### Screenshots

Linux captures use synthetic Storybook fixtures. Full-page captures use
reduced motion. The live character, mouse tracking, and disposal are
checked separately.

<details>
<summary>Agent overview with the character in its header</summary>

<img
src="https://raw.githubusercontent.com/paperclipai/paperclip/8c68f42b268ada22b67d79d0fe1bb0a2f84ec25c/screenshots/full-page-agent-overview.png"
width="900" alt="Agent overview with the character in its header" />

</details>
<details>
<summary>Task messages and assignee identity</summary>

<img
src="https://raw.githubusercontent.com/paperclipai/paperclip/8c68f42b268ada22b67d79d0fe1bb0a2f84ec25c/screenshots/full-page-task.png"
width="900" alt="Task messages and assignee identity" />

</details>
<details>
<summary>Larger onboarding character with room for expressions</summary>

<img
src="https://raw.githubusercontent.com/paperclipai/paperclip/8c68f42b268ada22b67d79d0fe1bb0a2f84ec25c/screenshots/full-page-meet-your-next-agent.png"
width="900" alt="Larger onboarding character with room for expressions"
/>

</details>
<details>
<summary>Dashboard agent activity</summary>

<img
src="https://raw.githubusercontent.com/paperclipai/paperclip/8c68f42b268ada22b67d79d0fe1bb0a2f84ec25c/screenshots/full-page-company-dashboard.png"
width="900" alt="Dashboard agent activity" />

</details>

## Risks

- This PR depends on #13170, the persona foundation. Merge the
foundation first, then retarget this PR to master.
- Many placements change from icons to character silhouettes. Human
avatars and authoritative agent status labels retain their existing
behavior.
- Only one character can render live per view. Reduced motion,
hidden/offscreen content, touch input, and renderer failures use the
defined fallbacks.
- The full-page stories use fixture data. They do not contact a real
company or complete real provider sign-in.

## Model Used

OpenAI Codex, GPT-6 family. The exact model identifier and context
window are not exposed in this session. Used code editing, shell
execution, browser inspection, and Linux visual testing.

## 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>
Co-authored-by: Tonio <tonework@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 07:57:53 -05:00
DottaandPaperclip 669bd0e7a9 fix(ui): show progress and verify subscriptions during onboarding (#13499)
Automatically verify detected Claude and Codex subscriptions during initial onboarding. Show connection progress, support retries, and ignore stale results after navigation. Prefer the personal default subscription while preserving the later create-agent chooser.

Allow Enter to advance from the agent name field. Add regression tests and production-component Storybook coverage.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-15 17:39:25 -05:00
DottaandPaperclip e704e1c9ae fix: keep AI subscription locks safe through transaction pooling (#13347)
## Thinking Path

> - Paperclip manages AI agents and their credentials.
> - AI Connections must preserve account ownership from login through
execution.
> - A subscription environment check can pass and leave a session
advisory lock on a pooled database backend.
> - The next execution then reports that the subscription is busy.
> - Onboarding can also lose its completion callback when the connection
list refreshes before the login poll.
> - This change keeps each credential lease in one transaction and keeps
the login controller mounted until completion.

## Linked Issues or Issue Description

Refs: #13247, #13248, #13344.

**What happened?**

A real hosted subscription login saved successfully and passed its
environment check. The first task then failed with an AI connection busy
error. A connection-list update could also leave onboarding on
Connecting.

**Expected behavior**

A completed environment check releases its credential lease. A saved
login completes onboarding without another sign-in.

**Steps to reproduce**

1. Run Paperclip with a transaction-pooling PostgreSQL proxy.
2. Connect a Claude subscription through onboarding and reuse it for an
agent.
3. Start a task after its environment check succeeds.
4. For the UI race, refresh the managed connection list before the login
completion poll.

## What Changed

- Hold the grant lock inside one transaction. Roll back on cleanup or
failed acquisition.
- Disable the lease transaction's idle timeout so long provider
executions retain the lock.
- Keep the onboarding login controller mounted while its authorization
URL is active; restore saved-account retry if later agent creation
fails.
- Add lock-lifetime and Claude/Codex completion-order regressions.
- Document the pooling requirement.

## Verification

- 104 focused connection and onboarding tests passed.
- Workspace typecheck, production build, Storybook build, and token
gates passed.
- All 34 latest-head checks are terminal: 32 passed and two Storybook
workflows skipped by their normal filters. CI covers all
server/workspace/serialized test shards, browser tests, typecheck,
build, runner verification, and canary packaging. The additional local
full-suite run is still in progress.
- Real browser sign-ins saved Claude and OpenAI subscriptions on both
new and existing staging stacks. On the patched new stack, both
providers completed tasks and immediate repeat executions with the same
saved accounts. Read-only database inspection confirmed live
transaction-scoped locks and no remaining locks after completion. On the
final deployed head, both shared accounts on the existing stack also
completed actual tasks. Both personal accounts passed a fresh
environment check followed immediately by execution after a deployment
restart.

## Risks

- Each active subscription reserves one database connection and holds an
otherwise idle transaction until cleanup. This is required to pin the
backend through a transaction pool.
- Old session locks from earlier versions may need operator cleanup
after active runs drain. This change does not bypass existing locks.
- No database migration, credential routing, or legacy authentication
change.

## Model Used

OpenAI GPT-6 in Codex, with code execution and browser tools. The exact
deployment model ID and context-window size are not exposed to this
task.

## 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-09-12 19:05:18 -05:00
DottaandPaperclip b2acc674be fix: enable isolated subscription login on authenticated self-hosted instances (#13344)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - AI Connections store reusable provider credentials with company and
owner boundaries.
> - Self-hosted instances can require board authentication while running
agents on the local server.
> - The login UI treated those instances as unsupported and displayed
instructions without a command.
> - Removing that restriction must not expose the server operator's
existing CLI account.
> - This pull request enables owner-scoped login attempts and reuses the
existing login UI.
> - Users can connect Codex and Claude subscriptions on an authenticated
self-hosted instance.

## Linked Issues or Issue Description

**What happened?**

On an authenticated self-hosted instance, OpenAI subscription setup
displayed terminal instructions with no command and a disabled Connect
button. Claude also could not complete the local connection flow.

**Expected behavior**

An authorized board user can prepare an isolated sign-in attempt, sign
in on the server, and save the verified account as a Connection. This
must not import another user's or the operator's ambient credentials.

**Steps to reproduce**

Run Paperclip in authenticated mode with a local environment. Open
Connections, choose OpenAI or Anthropic, and select Subscription. The
previous UI never enabled local login preparation.

Related: #13247, #13248, and #10751. This fix preserves the restriction
on remote access to the operator's ambient Claude login.

## What Changed

- Allow company-authorized users to create, check, cancel, and complete
their own isolated local login attempts.
- Keep ambient Claude credential import restricted to the local
operator.
- Support isolated Claude credential files without falling back to the
host account or mutating process-wide environment variables.
- Use Codex device authorization so sign-in does not depend on a browser
callback to the remote server's localhost.
- Gate server-host login on authenticated public deployments unless a
trusted runtime host is configured. Publish the capability through
health so setup shows supported alternatives.
- Read isolated Claude credential files through bounded,
descriptor-bound opens with ownership, permission, and symlink checks.
Try the alternate filename after malformed JSON.
- Reuse shared login instructions and lifecycle hooks in onboarding,
agent setup, and Connections. Show health-query failures explicitly.
- Document authenticated self-hosted behavior and add authorization,
isolation, lifecycle, and UI regression tests.

## Verification

- Passed 71 focused tests across connection routes, credential
isolation, legacy compatibility, the shared login hook, and agent setup.
- Passed 89 onboarding regression tests.
- Passed `pnpm -r typecheck`, `pnpm build`, Storybook build, and `pnpm
check:token-gates`.
- Completed real Codex device authorization and Claude browser
authorization on an authenticated Linux self-hosted instance. Both
accounts were detected automatically and saved as Connected. Both
completed attempt directories were removed.
- These live checks cover login, credential validation, and connection
creation. They do not establish a new model execution or long-running
refresh result.
- Review follow-up: 68 focused checks passed after rerunning one route
socket error; the full route/health rerun passed all 49 tests. The
70-test onboarding suite also passed. Final workspace typecheck,
production build, and Storybook build passed again.
- The broad local run exposed an instance-name assumption in two new
assertions. The fixture now uses an explicit non-default instance, and
all 32 connection tests passed with a different inherited instance name.
The superseded broad run was stopped; this is not a claim that the full
local suite completed. Full CI results will be recorded before merge.

## Risks

- The server must have the provider CLI installed. Users still run the
displayed command on the server that hosts Paperclip.
- Authorization checks must keep login attempts scoped to the company,
owner, provider, and reconnect target. Regression tests cover cross-user
and cross-company access.
- Existing local-trusted Claude behavior stays available. Authenticated
remote users cannot use its ambient import path.
- No database migration, dependency change, agent binding change, or
provider routing change is included.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code execution, and browser
tools. The runtime does not expose a more specific model version 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
- [ ] 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-09-12 23:06:55 +00:00
DottaandPaperclip 8d6232e7b0 feat: reuse provider sign-in across AI connection workflows (#13248)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Users connect provider accounts during onboarding and agent setup.
> - They should reuse and manage those accounts through the existing
Connectors interface.
> - A second login wizard would diverge from the established provider
workflows.
> - This pull request composes the existing sign-in components into
Connections and agent configuration.
> - Users can select accounts without changing their agent's harness or
model.

## Linked Issues or Issue Description

**Problem or motivation**
AI credentials are configured separately from Connections. Agents cannot
consistently reuse a responsible user's account or a permitted shared
account.

**Proposed solution**
Manage AI accounts with the existing Connections grants and permissions.
Keep model and harness selection independent from credential selection.
Preserve legacy authentication until validated adoption.

**Alternatives considered**
A separate credential registry would duplicate ownership and access
policy. Automatic fallback would risk using the wrong account.

**Roadmap alignment**
This extends the shipped Apps, multi-user, secrets, and agent-runtime
capabilities. The maintainer requested the feature and reviewed the UI.
Related groundwork: #11899 (connection permissions), #10910 (connection
wizard), #11692 (Claude subscription profiles), and #11854 (Codex
account rotation).

## What Changed

- Add compact AI-account management to the existing Connectors pages.
- Reuse AgentProviderConnection, AdapterLoginPanel, AdapterLoginChrome,
and authentication controllers.
- Add the shared connection picker to agent setup/settings and task
requests.
- Preserve onboarding's sequence and reuse existing accounts.
- Add local-login recovery, retry, cancellation, and React StrictMode
handling.
- Add interactive Storybook scenarios, design-guide examples, and app
acceptance checks.

This is part 2 of the AI Connections change. The runtime foundation in
#13247 is merged. This PR now targets master.

## Verification

- Updated against master `47ded8bf9`, including the landed runtime
foundation and upstream task-search changes.
- Full workspace typecheck, production build, Storybook build, and token
gates passed on the integrated branch. Final local-login changes passed
59 focused tests; new-agent and inbox regression suites passed 63 tests.
- Browser checks verified automatic local Claude account detection,
resumable Codex login commands, retry, focus restoration, and
desktop/phone layouts. Commands create their isolated directory before
invoking the CLI.
- All CI test, browser, build, packaging, and runner jobs passed on
final head `dd17d3211931dd70aaa6ea619d83a7f9966dd18e`. The fresh
Greptile review is 5/5, the security scan passed, and there are no
unresolved review threads. The final CI aggregate gates passed.
- Local general-server coverage passed 11,804 tests; three
port-collision failures passed in an isolated 25-test rerun. All 6,111
UI tests passed. CLI coverage passed 484 tests; its remaining doctor
test requires port 3199, which is occupied by an unrelated report server
on this Mac. The complete CLI suite passed in CI.
- Live browser testing verified Codex API-key reconnect inside a task
card on desktop and phone. Real provider runs resumed and completed with
unchanged connection/grant identity and agent routing.
- Tested opening, cancelling, reopening, and completing connection
creation. A regression confirms Connect another account cannot submit
the new-agent form or copy provider keys into agent settings.
- Added shared inline repair, automatic local sign-in checks, and
responsive connection dialogs. Standalone Daytona installation ignores
workspace configuration and suppresses dependency scripts. Its
standalone build also passed with CI's exact pnpm 9.15.4.
- Destructive live tests are excluded by default. Explicit opt-in, local
deployment checks, and matching disposable fixture identities are
required before any mutation.

## Risks

- Local Codex/Grok creation requires the connection-specific terminal
login command.
- Browser sign-in uses the existing supported-environment controllers.
- This update verifies live local Claude detection and Codex API-key
task repair. New subscription authorization/refresh and
independent-human/native-runner isolation were not reverified in this
update.
- No agent automatically adopts managed Connections.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-12 16:51:26 -05:00
Tonio f70accd3a4 fix(onboarding): answer the Claude paste at once, and show the code as dots (#13193)
The Claude card's button only moved to Connecting once the login was stored - a submit, a status poll and a completion read after the paste - so for about a second the customer had done their part and the button still read Waiting for code. The panel now reports the submit as it starts (onCodeSubmitted) and the step shows Connecting from that moment.

That could not simply move the phase earlier: the two-second hold started when Connecting did, so it would have hired whether or not a credential existed. The hire now waits for both the stored login and two seconds of Connecting counted from the paste. onSubmitFailed gives the button back when a submitted code does not become a stored login, the field locks while a code is out, and Cmd+Enter no longer hires mid-connect.

Reports that land after Back are ignored. The panel stays mounted through Back's exit, so a late failure reopened the card being left, and a late success hired a customer who had backed away. The second predates this change; its test fails the same way against master.

The authorization code shows as dots. The OpenAI card is untouched.
2026-09-10 19:52:31 -07:00
DottaandPaperclip e9828f8bf4 fix: reuse saved model connections during agent setup (#13161)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent setup connects each agent to a model provider.
> - The organization can already hold subscription logins and API keys.
> - The simplified setup flow did not consistently offer those saved
credentials.
> - This pull request restores reuse and selects a saved connection by
default.
> - Agents keep secret references, so reuse does not copy or rotate
credentials.

## Linked Issues or Issue Description

Related change: #13011. Searched public issues and PRs; no duplicate fix
found.

**What happened?**

Onboarding and new-agent setup could ask for a new API key or sign-in
despite an existing saved connection. A general environment auth signal
could also be mistaken for the owner's saved Claude subscription.

**Expected behavior**

Offer saved credentials from the selected organization. Default to a
saved subscription when one exists. Otherwise select a saved API key.
Keep the option to enter a new key or sign in to another account.

**Steps to reproduce**

1. Save a Claude or OpenAI API key, or complete a supported subscription
login.
2. Add another agent with the same provider.
3. Open the provider connection step.
4. Check whether the saved credential is available and selected.

**Paperclip version or commit**

Reproduced on 5cb4f061d after #13011. This branch is rebased onto
current master.

**Deployment mode**

Built from source. Tested in an isolated local test drive with embedded
storage and board access.

## What Changed

- Add a shared saved-credential lookup and picker for active personal
and organization keys.
- Reuse saved Claude subscriptions and saved Codex account homes. Select
an existing connection by default.
- Preserve secret references through connection tests and agent
creation, including the native Claude and Codex runner setup paths.
- Store newly entered onboarding keys separately. Do not rotate another
agent's key.
- Keep explicit choices during metadata refresh. Prevent refreshes from
remounting an active login panel.
- Add integration tests and production-component Storybook stories.
Document connection reuse.

## Verification

- All 5,628 UI tests passed before rebase.
- Twenty targeted server credential tests passed.
- UI typecheck, UI build, token gates, and diff whitespace checks
passed.
- Browser walkthroughs covered onboarding and new-agent setup, saved
keys, saved subscription fixtures, and new sign-in screens.
- Live Claude and Codex API-key probes succeeded. Created both agents
and confirmed that each retained its saved-secret reference. Both secret
versions remained unchanged. Codex passed after one retry.
- Live subscription authentication was not repeated. Subscription flows
use fixture browser tests and integration tests.
- After rebase and the cache fix, all 109 focused onboarding and
agent-creation tests passed.
- Full repository `pnpm build` and `pnpm -r typecheck` passed.
- The full local test attempt encountered timeouts and embedded
PostgreSQL startup failures under parallel load. All four affected
suites passed in isolation: 20 tests, with no code changes. The complete
CI matrix passed, including all workspace, general server, serialized
server, browser end-to-end, build, typecheck, and canary dry-run checks.
- Greptile reviewed commit d53ddf6b82:
5/5, successful check, no review threads.

## Risks

- The default connection mode changes when saved credentials exist. A
saved subscription takes priority over saved API keys; personal keys
appear before organization keys.
- A listed credential can be expired or unavailable in the selected
environment. The existing connection test still checks it.
- No database migration or API contract change is required.

## Model Used

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

## 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-09-10 12:57:53 -05:00
5acf56658b feat(onboarding): first task opens as a chat with a chief of staff (#13068)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Onboarding ends by handing a new user to their first agent on a
seeded first task
> - Today the wizard asks for a mission up front, the UI composes what
the agent is told, and the agent starts running before the user says
anything
> - New users get a cold, ticket-shaped start, and nobody can edit the
agent's brief or persona without a code change
> - This pull request makes the first task a short chat: a four-step
wizard, a chief-of-staff persona, a greeting plus a two-option opening
card, server-owned markdown texts, and no run until the user answers
> - It also gives question cards one consistent action row (Cancel /
Skip / Next), makes agent hires idempotent within a run, and turns the
Paperclip Runner flag on by default for self-hosted instances
> - The benefit is a first run the user steers, with texts a board
operator can edit as markdown

## Linked Issues or Issue Description

No public GitHub issue exists for this change. The feature request
fields follow.

Related PRs and issues:

- Refs #11043 — an earlier draft of the first-task onboarding
experience. This PR supersedes it.
- Refs #11280 — a report about the onboarding first-task route test.
This PR extends that test file.

### Subsystem affected

Onboarding wizard, the seeded first task and its texts, task-chat
question cards, agent hiring, and the instance experimental settings.

### Problem or motivation

The onboarding wizard collects a mission through two extra steps and a
questionnaire. The UI then composes the first agent's instructions and
the first task description from those answers. The first task wakes the
agent at once, so the agent runs and posts before the user types a word.
Board operators cannot change the greeting, the brief, or the persona
without editing TypeScript. Question cards in chat behave differently
per adapter, and a single-select pick submits on click. A misread hire
response could create a duplicate agent that the creating agent cannot
remove.

### Proposed solution

Reduce the wizard to four steps and stop the UI from authoring agent
texts. Move the greeting, the brief, the chief-of-staff persona, and the
opening question into markdown and JSON files that the server loads at
runtime. Seed the persona onto the first agent through an explicit hire
marker. Do not wake the first task until the user answers the opening
card or types. Give every question card the same Cancel / Skip / Next
actions. Add an experimental toggle that switches the single-task
proposal between one confirmation card and a plan document with a
checkbox card. Make agent hires idempotent within a run.

### Alternatives considered

- Keep the mission questionnaire and feed it into the brief. Rejected:
the agent asks better questions in chat, and the wizard gets shorter.
- Keep the first task open-ended with a plain composer. Rejected: a
two-option card gives the user a clear first move.
- Derive the plan-document behaviour from the user's intent only.
Rejected in favour of an explicit experimental toggle so operators can
choose.
- Key the "pick does not submit" behaviour off the presence of a submit
label. Rejected: several adapters set a submit label on single-select
cards, and their cards would change behaviour.

### Roadmap alignment

`ROADMAP.md` lists no planned core work on onboarding or the first task.
This change refines the existing flow and does not duplicate planned
work.

## What Changed

- Wizard: four steps (Name your organization, Create your first agent,
Connect a model, Review). The front door and both mission steps are
removed with their state and saved-progress keys. The UI no longer
composes the first agent's instructions or the first task description.
- Server-owned texts: the greeting, the brief with two proposal
variants, the chief-of-staff persona, the opening question, and a README
live in `server/src/onboarding-assets/first-task/` and load at runtime.
The create route stores the assembled brief and ignores any client
description.
- Persona seed: an `onboardingFirstAgent` marker on the hire lets the
server seed the chief-of-staff persona over the first agent's entry
file. Board-authored hires only. The persona tells the agent the hire
response shape and to list agents before it acts on an unclear result.
- No auto-run: the first task does not queue an assignment wake. The
stranded-assignment reconciler leaves it idle until a user comment or an
answered card exists.
- Opening card: the server seeds an `ask_user_questions` card right
after the greeting with two options: "Interview me and propose a plan
and an agent team to execute it." and "I have a task in mind" with free
text. Answering wakes the agent.
- Experimental toggle `enableFirstTaskPlanProposal` (default off): the
single-task proposal is one confirmation card, or a plan document plus a
checkbox card when on.
- Question cards: every `ask_user_questions` card renders Cancel, Skip,
and Next (the submit label on the last question). Skip hides on required
questions. Picking an option no longer advances or submits by itself.
- Wizard guards: the dashboard's agentless offer ignores a cached empty
agent list while a refetch is in flight. The hire step adopts an agent
that already carries the typed name instead of hiring "Name 2".
- Agent hires are idempotent within a run: a retry of the identical
request under the same run id returns the existing agent with `200` and
`idempotent: true`. The fingerprint covers the whole validated request,
so a corrected payload is a new hire. Lookup, create, and activity
record run under one lock per company and run, so overlapping retries
cannot both create.
- The Paperclip Runner experimental flag defaults to on for self-hosted
instances. Cloud keeps its declared default: a managed instance whose
tenant row and managed overlay omit the flag resolves it to off.
- Question cards: a send that finds an earlier required answer missing
returns to that question with a message instead of failing silently.
- The two onboarding e2e specs follow the new wizard: the front door and
growth intake shots are gone, and the planning-mode spec dismisses the
opening card before it reads the composer.
- Docs: `docs/board-operator/editing-first-task-texts.md` explains how
to edit the texts and the toggle.

## Verification

Commands, run from the repo root:

```
pnpm -r --filter './packages/*' --filter '!@paperclipai/paperclip-runner' build
pnpm --filter ./packages/shared typecheck
pnpm --filter ./ui typecheck
pnpm --filter ./server exec tsc --noEmit
pnpm check:token-gates
pnpm --filter ./ui exec vitest run OnboardingWizard onboarding QuestionForm InteractionCard ProtocolCard TaskChatComposer Dashboard feature
PAPERCLIP_IN_WORKTREE=false pnpm --filter ./server exec vitest run onboarding-first-task heartbeat-process-recovery agent-hire-idempotency instance-settings agent-skills-routes issue-onboarding onboarding-greeting --testTimeout=90000
```

Results on this branch:

- Typecheck is clean for shared, ui, and server.
- Token gates: 4 of 4 clean.
- UI: 344 tests pass across 23 files.
- Server: all suites pass. The first test in `agent-skills-routes` has
its own 10 s cap and needs about 15 s on my laptop for the app cold
start. It passes with a longer cap. This PR does not change that cap.

Manual steps on a dev instance:

1. Open `/onboarding`. Confirm four steps: Name your organization,
Create your first agent, Connect a model, Review.
2. Finish the wizard. Confirm the first task shows the chief-of-staff
greeting and the opening card with two options. Confirm no run starts.
3. Pick "Interview me…". Confirm no run starts. Press Continue. Confirm
a run starts and an interview card of 3–4 questions arrives.
4. On a fresh organization, pick "I have a task in mind", type a task,
and press Continue. Confirm a proposal arrives as one confirmation card.
5. Turn on Settings → Experimental → "First task: propose with a plan
document" and repeat step 4. Confirm a plan document and a checkbox card
arrive.
6. Visit the dashboard after the hire. Confirm the wizard does not
reopen and one agent exists.
7. Open any question card. Confirm Cancel returns the plain composer
with the card still pending, Skip advances an optional question, and
Next moves to the next question.

Design reference with flow diagrams, chat mock-ups, and live captures:
https://pages.paperclip.ing/first-task-flow/proposed/

## Risks

- `pnpm dev` now builds the runner daemon because the Paperclip Runner
flag is on by default. Developers without a Rust toolchain must set
`PAPERCLIP_RUNNER_BINARY` or turn the flag off. Self-hosted instances
that never set the flag now let qualified agents use the runner.
- The wizard drops the mission steps and their saved-progress keys. A
user who is mid-wizard on an older build restarts at step 1 after an
upgrade. Existing organizations are not touched.
- The first task no longer runs on its own. A user who neither answers
the card nor types sees no agent activity. This is intended.
- The persona seed applies only to hires that carry the marker from the
wizard. API hires are unchanged.
- Hire idempotency is scoped to one run id and to the exact request.
Retries across runs, or with a changed payload, still create a second
agent. The lock is per server process, which matches how an instance
serves its API.
- Single-select question cards no longer submit on pick. Users of
adapters that relied on that behaviour now press Next.
- No database migrations.

> 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) through Claude Code. `claude-fable-5-1` with
extended thinking, tool use, and code execution wrote most commits.
`claude-opus-4-8` wrote the toggle, texts, wizard, and idempotency
commits, as the `Co-Authored-By` trailers show.

## 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>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 20:19:14 -07:00
Tonio ae03465ad4 fix(onboarding): drop the sign-in card's Cancel, and resume after Back (#12958)
The card carried a Cancel beside its instruction, directly above the step's own Back. Two ways out of one screen is one too many.

Removing it was only safe if returning genuinely resumed the running session, and writing the test for that disproved the premise: coming back started a second login rather than adopting the first, which the server's per-owner lease rejects. Cancel was not duplicative — it was the only way out of a login the customer could no longer reach.

The cause was the cache. The active-session read is a useQuery with no staleTime, so on the second mount it answered instantly from the first mount's cached null: isFetched was true, the resume effect concluded there was nothing to adopt, and autoStart began a new login while the refetch was still in flight. Both panels did it, and it was pre-existing on master. Both reads now refuse the cache, so the resume works and the removal is safe because of it.

Removing the button also stranded the chain behind it: handleCancel in both panels, the onCancel prop on AdapterLoginPanel, and the wizard's wiring. The panel chrome's own Cancel is untouched.

An abandoned login is collected on a five-minute timer (DEVICE_LOGIN_TIMEOUT_MS) with the reaper as the restart-safe backstop, and the lease is keyed on adapterType, so a source switch does not contend. Both covered by tests.
2026-09-07 00:20:31 -07:00
Tonio be407f3456 fix(onboarding): hide the probe's diagnostics while the hire is in flight (#12902)
After a successful sign-in, a block of amber diagnostics flashed up and vanished as the step advanced. They are the identity and target INFO checks every environment test reports: they make the result a warn without blocking anything, and the step rendered any non-pass result, so they owned the screen for the window between the probe returning and setStep(5).

Gated on loading rather than the connect phase. A blocking result stops the hire and handleGiveHeartbeat clears loading in the finally after its early return, so a genuine block still shows its checks while a hire in flight shows none.

The button needed no change: step 4 forces the footer's loading to false and takes its label from connectCta, which reads Connecting for that whole window.
2026-09-05 10:08:28 -07:00
Nicky LeachandPaperclip 60469a08e0 feat(agent-login): resume an active login session and permit concurrent login terminals (#12861)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent authentication uses server sessions, plugin workers, and
browser login panels.
> - A page reload loses an active login session, and one worker permits
only one login terminal.
> - These limits cause lost work and prevent two owners from logging in
through one worker.
> - This pull request lets the browser resume active sessions and lets
workers serve concurrent login terminals.
> - The benefit is reliable login recovery with a bounded process-wide
route limit.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

It improves agent credential login recovery and concurrent login
terminal handling.

**Subsystem affected**

Cross-cutting (multiple of the above).

**Current behavior**

A page reload loses the active login session. A shared plugin worker
rejects a second login terminal.

**Proposed behavior**

The browser reads and resumes the owner's active session. A worker
supports multiple login terminal routes under a process-wide ceiling.

**Reason and benefit**

Owners keep login progress after a reload. Two owners can log in through
one worker without removing the route limit.

**Breaking changes**

None. The change adds owner-scoped read routes and changes login
terminal concurrency.

## What Changed

- Replace the single worker login route with maps keyed by host route
and worker session identifiers.
- Add a process-wide login route ceiling and release each reserved slot
on every exit path.
- Add owner-scoped active-session reads with consistent negative
responses and private cache control.
- Keep the device-login prompt while the session has an active public
status.
- Add a durable setup-token cancel fallback for a lost in-memory
session.
- Resume active sessions when the agent configuration or onboarding
panel mounts.
- Remove routine unmount cancellation and keep explicit Cancel behavior.

## Verification

- `pnpm --filter @paperclip/server test` — server route, service, and
plugin-worker-manager suites.
- `pnpm --filter @paperclip/plugin-sdk test` — worker RPC host suite.
- `cd ui && npx vitest run
src/components/AgentConfigForm.render.test.tsx
src/components/OnboardingWizard.test.tsx`.
- `cd ui && npx tsc -b`.
- `tests/e2e/onboarding.spec.ts` — reload during login.
- CI must pass on this pull request.

## Risks

The change affects agent authentication and the sandbox-to-host
boundary. Route cleanup must release every reserved slot. Owner checks
must prevent cross-owner session access. Tests cover route cleanup,
owner scope, reload recovery, and concurrent worker routes.

## Model Used

Codex, OpenAI GPT-5, tool use and code review support. The
implementation author owns the exact model details for the code changes.

## 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 with the relevant issue-template
fields
- [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
- [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 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-09-05 10:03:13 -07:00
Tonio a7ed22e3dd refactor(onboarding): reconcile the arc column's width comment with its width (#12875)
The shell carried two comments arguing opposite things: the older made the case for a 64px inset and said 40px was too wide, the newer made the case for the 40px the code uses. The older one had also drifted from the code independently - it described 68px sides and a 424px column while the file used --sz-64px, a 432px column.

One comment now: 40px sides, a 480px column, the measure the connect sequence is drawn to and which the arc shares. The earlier objection is kept and marked untested, with a note that if step 1 or step 3 reads loose the fix belongs in those steps' content rather than the shared shell.

Comment-only; no behaviour change.
2026-09-05 00:32:48 -07:00
Tonio f2349990cc feat(onboarding): the connect step's sign-in as one continuous sequence (#12863)
Picking a source starts the sign-in: the row collapses to the answer, the card opens where the credential link was, and the footer button walks Sign in -> Waiting for code -> Connecting before the step advances. Back unwinds it a beat at a time.

Nothing mounts to change layout - the card and the link are always rendered and their heights animate, with inert holding the a11y line - because a mount changes the page in one frame and no easing can smooth a step already taken.

Review fixes in the same branch: the displayed-code panel now reports its prompt upward (the OpenAI path could not leave the loading beat without it), the two-second hold is a cancellable beat rather than a dropped timer, unwinding a sequence that never opened a card no longer starts a login to cancel it, and the key field regains focus-on-open.
2026-09-04 17:48:16 -07:00
Tonio 1a74719309 feat(onboarding): the connect step signs in from its own button (#12801)
Connect starts the sign-in; the card that appears is the sign-in rather
than an offer of one; success advances to Review rather than reporting
itself. The two logins end in different places and the button says which:
Claude submits a code back here, so it spins on "Connecting"; OpenAI
finishes in another tab, so it stays a still, disabled Next until the
poll lands.

AdapterLoginPanel grows autoStart / onCancel / onConnected / chrome
rather than a second implementation — the session start, both polls, the
server deadline, the one-shot completion read and the unmount release are
the parts onboarding needs unchanged. Every prop is off by default, so
the agent form and the new-agent page render what they did before.

Claude's code auto-submits on the paste, not on every change:
isValidBrowserCode accepts any printable ASCII from one character up, so
a value-driven submit fired on the first keystroke of anyone who typed.

Also orders the OpenAI card and the settings displayed-code panel
code-above-link, with the instruction worded to match, and releases the
displayed-code session on unmount so an abandoned login stops holding the
one-per-owner reservation.
2026-09-03 21:45:45 -07:00
Tonio 9ef3b087c1 feat(onboarding): round-4 corrections to the connect and agent steps (#12796)
Reads the connect and agent steps from the design's own values through the
Figma MCP rather than measuring an export, which corrected the arc column
inset (433px content, 64px inset — `--sz-68px` goes with the mismeasurement
it was minted for) and restored the selected tile's border alongside its
fill.

Round-4 items: sources named for the provider you sign in with, OpenAI's
mark inlined so it can take `currentColor` on a light tile, monochrome
autofill via `box-shadow` (Chrome ignores `background-color`), and the
agent step's placeholder.

Also wires `MODEL_SOURCE_NAMES`, which was added for the rename and never
read — the tiles kept passing the display registry's label, so the step
still showed "Claude Code" and "Codex" under a heading asking which
provider you are signing in to. Covered by a test that fails on the
unwired version.
2026-09-03 20:52:31 -07:00
DottaandPaperclip 8c89340444 fix(onboarding): preserve draft through company refetch (#12735)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Onboarding creates an organization in the browser.
> - The browser keeps onboarding drafts for the same origin.
> - A new data directory does not clear that browser data.
> - The organization create request refreshes the company list.
> - The old gate unmounted the live wizard during that refresh.
> - This pull request keeps the wizard mounted after its first draft
check.
> - The customer can continue to the agent step after the organization
is created.

## Linked Issues or Issue Description

No matching public issue was found. Related earlier fix: Refs #12667.

**What happened?**

A local canary install could create an organization through the API and
then return the browser to an empty organization-name screen.

**Expected behavior**

The wizard must continue to the agent step after it creates the
organization.

**Steps to reproduce**

1. Keep a Paperclip onboarding draft in the browser.
2. Run npx paperclipai@canary onboard with a new data directory.
3. Open /onboarding.
4. Enter an organization name and select Continue.

**Paperclip version or commit**

2026.902.0-canary.7. The fix is based on current master.

**Deployment mode**

Local trusted mode through the Paperclip CLI.

**Install method**

npx package install.

**Agent adapter(s) involved**

Not adapter-specific.

**Database mode**

Embedded PostgreSQL.

## What Changed

- Keep the onboarding wizard mounted after its first successful draft
ownership check.
- Keep a failed ownership check retryable, so a later verified fetch
restores the saved draft.
- Add component, source E2E, and published-canary coverage for the
retained-draft refetch case.

## Verification

- Confirmed that the new canary scenario fails against
2026.902.0-canary.7 before this fix.
- pnpm exec vitest run ui/src/components/OnboardingWizard.test.tsx
- PAPERCLIP_E2E_PORT=3245 pnpm exec playwright test --config
tests/e2e/playwright.config.ts tests/e2e/onboarding.spec.ts
--reporter=line
- pnpm --filter @paperclipai/ui typecheck
- pnpm check:token-gates

## Risks

Low risk. The initial ownership check still waits for a fresh company
list. A later successful retry can restore a retained draft. Later
background refetches preserve live wizard state.

## Model Used

OpenAI Codex, GPT-5. Reasoning, tool use, code editing, terminal
execution, and browser testing were used. The execution environment does
not expose a 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 described the issue in-PR following the bug issue template
- [x] I have not referenced internal or 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 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-09-02 16:50:15 -05:00
TonioandClaude Fable 5 141c5b1340 feat(onboarding): Figma pass over the tenant arc (#12726)
Takes the four tenant onboarding steps to the design, and makes the model
choice explicit.

**Nothing is preselected on the connect step.** It arrived with a source
already chosen, which made the row read as a confirmation rather than a
question and let a customer pass the step having touched none of it. The
step now opens unanswered and cannot advance until a source is selected in
the visible row.

Two defects fell out of that, both found by Greptile in review:

- A saved draft can name an adapter the row does not show — one the registry
  dropped, or one in the advanced list. The gate asked `sourcePicked`, which
  only means "a draft named something", so Next stayed live on a step that
  had visibly asked nothing and would hire against the hidden name. It now
  asks `sourceSelected`, read off the visible row, and the snap that replaces
  an unofferable adapter clears the pick rather than presenting its
  replacement as chosen.
- Cmd+Enter bypassed that gate entirely, because the condition was written
  out twice and drifted. Both paths now ask one predicate.

Also: selection is a fill rather than a border; the input canvas opens only
for a chosen source; the close control is gone from every step (nothing
downstream of the connect step works until a model is connected); the arc
draws to the design's 424px column with a filled 44px name field; the CTA
reads "Next" through the arc and "Get started" at the end; the login spinner
reads "Preparing..."; the OAuth panels number their fields and show the URL
above the code.

Storybook: the arc stories waited for a button named "Connect" and had been
silently rendering the wrong step since the CTA was renamed. They now wait on
the destination heading. Three e2e specs had the same fault and now select a
source before advancing.

One test was removed rather than replaced — `hydrates again when the same
company comes back through onboarding` drove the close control, and three
substitutes each passed against a wizard with the behaviour deleted. The
reason is recorded where it stood.

Known and not fixed here: SidebarCompanyMenu opens the wizard at step 1 for
"create a new organization", and with no exit an existing user who changes
their mind is trapped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 12:19:15 -07:00
TonioandClaude Fable 5 889f5853f9 Onboarding: count the whole walk on a cloud tenant (#12706)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - A cloud customer meets it as one walk that crosses two applications:
Cloud names the organization, then hands off to the tenant for the
agent, the model and the review
> - The tenant's progress strip counted only its own three steps, so the
count restarted at the crossing — four dots on the naming screen, then
three beginning again at one
> - The strip that spans the whole walk already existed and simply was
not chosen on that path, which made the walk read as two products rather
than one
> - This pull request picks the four-step strip when the run came from
Cloud, so the count runs 1, 2, 3, 4 straight through
> - The benefit is that the hand-off stops announcing itself

## Linked Issues or Issue Description

**What existing behavior does this improve?**
The onboarding progress strip on a cloud tenant. It restarted its count
at the hand-off from Cloud, so a customer went from "1 of 4" to "1 of 3"
mid-walk.

**Subsystem affected**
Tenant onboarding wizard — `ui/src/components/OnboardingWizard.tsx`.

**Current behavior**
`showsAgentArcStepper` is `isAgentArcStep && entryStep >= 3`. Every run
entering on the agent step gets the three-step strip, including a cloud
tenant whose organization was named one screen earlier in Cloud.

**Proposed behavior**
A cloud tenant gets the four-step strip, positioned 2, 3 and 4. A
self-hosted run entering on the same step keeps three.

**Reason and benefit**
The count describes the walk the customer is on rather than the half of
it this application happens to render.

**Breaking changes**
None. No API or schema change; the self-hosted path is unchanged.

## What Changed

- Adds `enteredFromCloud`, read from `enableManagedSandboxOnly` — the
cloud-tenant shape the connect step already resolves its login
environment through.
- Excludes that case from `showsAgentArcStepper`, so it falls to the
existing four-step strip. `ONBOARDING_STEP_LABELS` and
`onboardingStepPositionFor` already produce 2, 3 and 4; neither needed
changing.
- Widens the experimental-settings query from step 4 to steps 3–5, so
the strip can read it on every step of the arc.
- Adds tests for both strip lengths.

## Verification

- `pnpm vitest run src/components src/adapters storybook` in `ui/` —
2309 tests pass.
- `pnpm typecheck` in `ui/` — clean.
- Storybook, `Onboarding/Agent arc`: its fixture is cloud-shaped, so the
three steps now announce "Step 2 of 4", "Step 3 of 4" and "Step 4 of 4"
with four dots.
- The two new tests fail without the change — the cloud case reports
`expected 'Step 1 of 3' to be 'Step 2 of 4'`.

## Risks

- **The two runs entering on the agent step are genuinely different, and
only one signal separates them.** A cloud tenant walked a naming screen
in Cloud; a self-hosted company with no agents walked nothing before
this. Getting it backwards would either restart the count or credit a
step nobody walked. Both directions are now tested, which they were not
before — the suite covered `agentArcStepFor` but nothing asserted which
strip renders.
- `enableManagedSandboxOnly` is being read as a proxy for "came from
Cloud". It is the same signal the connect step already trusts for its
environment, so this does not introduce a new dependency, but it is
inference rather than a fact passed at the hand-off. If the step count
ever needs to vary, Cloud should seed the position explicitly instead.
- The widened query means the value can be unresolved on first paint,
and the strip briefly renders three dots before settling to four. The
query key is shared and usually already cached, so this is rare rather
than routine — worth watching on staging, and the fix if it shows is to
hold the strip until the value resolves.
- Cosmetic only. Nothing here changes which steps run, what they
collect, or where the walk goes.

## Model Used

Claude Opus 5 (`claude-opus-5`), via Claude Code with extended thinking,
tool use, and browser-driven verification of the rendered strip.

## Checklist

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

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

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-09-01 18:06:38 -07:00
TonioandClaude Opus 5 42c6f8a424 Onboarding: model source tiles, one input canvas, and Storybook coverage for the agent arc (#12613)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - New customers meet it through onboarding, whose last three steps run
inside the tenant: create an agent, connect a model, review
> - The connect step is the one that decides whether the agent can run
at all, and it had drifted — three contributors changed it in parallel,
and its visual language no longer matched the rest of the flow
> - It also could not be looked at without a provisioned stack, so
defects in it were only found by walking a real signup, and the review
step behind it could not be reached at all when it failed
> - This pull request brings the visual work onto the sign-in behaviour
that already shipped, and adds Storybook coverage for all three steps
> - The benefit is that the step is easier to read, and that it can now
be inspected and driven before it ships rather than after

## Linked Issues or Issue Description

**What existing behavior does this improve?**
The onboarding connect-a-model step. It presented the model choice as a
dropdown plus an "Advanced settings" disclosure, and put each credential
type in a different place, so the controls below moved whenever the
choice changed.

**Subsystem affected**
Tenant onboarding wizard (`ui/src/components/OnboardingWizard.tsx`) and
its Storybook coverage.

**Current behavior**
The step offered every registered adapter through a disclosure.
Credential entry appeared in a different shape per source. None of the
three agent-arc steps could be rendered outside a provisioned cloud
stack, so the sign-in panel and the review step were only reachable by
walking a real signup.

**Proposed behavior**
Two brand tiles for the recommended sources, a link that switches
between subscription and API-key credentials, and one canvas that holds
whichever input the current choice needs. Storybook stories mount the
real wizard against fixtures and walk it forward, so every step and its
states can be inspected locally.

**Reason and benefit**
The step reads as one decision rather than three scattered ones, and its
furniture stays still while the choice changes. The stories mean a
regression in it is visible before release instead of during a signup.

**Breaking changes**
No API or schema change. One behavioural narrowing, described under
Risks.

## What Changed

- Replaces the adapter dropdown and "Advanced settings" disclosure with
`ModelSourceTiles` — brand tiles for Claude Code and Codex.
- Adds `CredentialModeLink`, a text toggle between subscription sign-in
and API keys, replacing the disclosure.
- Adds `ConnectInputCanvas`: one surface that holds the sign-in panel or
the API-key field and resizes between them, so the Connect button below
does not move.
- Keeps the existing sign-in behaviour unchanged. `AgentConfigForm`
changes are presentation only — the provider name in the title, the CTA
wording, and `space-y` to `gap`. No change to the login mutations,
queries, or session handling.
- Restores the sleep marks on the dormant agent for the two steps before
the hire.
- Adds Storybook stories for all three agent-arc steps, with fixtures
for the environments, auth signal, both adapters' login flows, and the
hire.
- Copy: names the provider being signed in to ("Sign in to
Anthropic"/"Sign in to OpenAI"), and drops "Clippy" from the agent-name
helper text.

## Verification

- `pnpm vitest run src/components storybook` in `ui/` — 139 tests over
the touched suites, 1986 across `src/components`.
- `pnpm typecheck` in `ui/` — clean.
- Storybook, `Onboarding/Agent arc`: walk each story. Step 1 has no Back
button, steps 2 and 3 do.
- The sign-in gate: on `Connect a model`, press Connect without signing
in. It holds on step 2 and reports "No working authentication was
found." On `Review`, which fixtures an authenticated signal, Connect
reaches the review step.
- Both providers' login flows: press Sign in on the Claude tile for the
authorization URL and browser-code field, and on the Codex tile for the
device URL and code.
- The Claude sign-in was also walked end to end on a staging tenant,
including the OAuth redirect and pasting the code back.

## Risks

- **Onboarding now offers two model sources instead of every registered
adapter.** `ModelSourceTiles` is fed the `recommended` set, which is
`claude_local` and `codex_local`; Gemini, Cursor, Grok, Kimi, OpenCode
and Paperclip Runner are no longer selectable *during onboarding*. This
is deliberate. The full list is unchanged in agent settings, which is
where an adapter can still be switched after the agent exists, and
adding a source back is one `recommended: true` in
`adapter-display-registry.ts`. Flagging it because it is the one
behavioural narrowing here and it is not visible from the diffstat.
- The API key entered on this step is held in component state and
deliberately never written to the onboarding draft, because that draft
is `localStorage`. A customer who leaves mid-step re-enters the key;
that is the intended trade.
- Storybook-only risk: the fixtures now answer the environment test from
the story's auth state. If a future change moves the hire's gate off the
`adapter_auth_missing` check code, the stories would keep passing while
the product regressed. The gate is asserted in the adapter packages' own
tests, not here.
- Motion changes are low risk and reversible: the input canvas animates
its contents only, and its container was deliberately left unanimated
after an animated wrapper clipped the sign-in panel.

## Model Used

Claude Opus 5 (`claude-opus-5`), via Claude Code with extended thinking,
tool use, and browser-driven verification of the Storybook stories.

## Checklist

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

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

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 09:57:46 -07:00
DottaandPaperclip dda4dff645 fix(onboarding): restore browser launch and gate canaries (#12667)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The onboarding command starts the local server and opens the
first-run wizard.
> - Interactive onboarding stopped opening the browser by default.
> - Organization creation could also succeed in the API while the wizard
stayed on the name step.
> - The npm canary workflow did not prove that the published package
could complete this path.
> - This pull request repairs the startup and organization transitions
and adds an exact-version canary smoke gate.
> - The benefit is a quickstart that works for users and is tested after
each canary publish.

## Linked Issues or Issue Description

Related: #12557 covers a separate final-route onboarding handoff.

**What happened?**

Interactive `paperclipai onboard` runs did not open the onboarding page.
The organization API request could succeed while a same-company context
update caused the wizard to stay on the organization step. The canary
release lane did not test the exact published npm package through this
path.

**Expected behavior**

Interactive onboarding must open the browser once. A successful
organization request must advance to the first-agent step when the
surrounding context adopts the same organization. Each published canary
must install in a clean environment and reach the model connection step.

**Steps to reproduce**

1. Run `npx paperclipai@canary onboard --data-dir "$(mktemp -d
/tmp/paperclip-canary.XXXXXX)"` in an interactive terminal.
2. Enter an organization name while the company context refreshes from
the create response.
3. Observe that the browser does not open or that the wizard can remain
on the organization step after the API creates it.
4. Inspect the canary release lane and observe that no post-publish
onboarding test runs against the exact npm version.

**Paperclip version or commit**

The issue reproduced with `2026.901.0-canary.8` and the source state
before this pull request.

**Deployment mode**

Local trusted quickstart with embedded PostgreSQL. The install source
can be npm or a source checkout.

## What Changed

- Open the browser once for interactive foreground onboarding.
- Preserve explicit browser opt-outs and restore the prior environment
value after startup.
- Accept a same-company context update after organization creation and
reject a different-company takeover with an explicit error.
- Export the exact canary version from the publish job.
- Install and test that exact npm version in a clean Playwright smoke
job through the "Connect a model" step.
- Upload server logs, traces, screenshots, and the Playwright report
when the canary smoke fails.
- Document the interactive default and headless opt-outs.

## Verification

- `pnpm exec vitest run cli/src/__tests__/onboard.test.ts
ui/src/components/OnboardingWizard.step.test.tsx --reporter=dot` passes
with 37 tests.
- `node --test scripts/__tests__/release-verify-workflow.test.mjs`
passes with 9 tests.
- `pnpm exec playwright test --config tests/e2e/playwright.config.ts
tests/e2e/onboarding.spec.ts` passes with 2 tests.
- `PAPERCLIPAI_VERSION=2026.901.0-canary.8 pnpm run
test:canary-onboarding-smoke` passes against the published npm package.
- `pnpm check:token-gates` passes.
- `pnpm -r typecheck` passes.
- `pnpm build` passes.
- A fresh interactive source run opens the browser and reaches "Connect
a model" after organization and agent naming.

## Risks

- Low risk. Automatic browser opening only applies to interactive
foreground onboarding.
- `PAPERCLIP_NO_BROWSER=1` and `PAPERCLIP_OPEN_ON_LISTEN=false` keep
headless runs silent.
- A different organization context still blocks the pending create
transition.
- The canary package is immutable before the smoke runs. A smoke failure
leaves the package published but makes the release workflow red.
- This change does not modify REST APIs, database schemas, or shared
data types.

> 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

- OpenAI Codex based on GPT-5. The runtime does not expose the exact
deployment snapshot or context-window size. The model used reasoning,
browser automation, repository tools, shell commands, code editing, 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-09-01 10:10:30 -05:00
Dotta 1955b0e2d8 Gate Paperclip Runner setup behind an experimental flag (#12656)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent adapters control how Paperclip starts and resumes an agent
runtime.
> - Paperclip Runner is an experimental Rust runtime and must stay
opt-in.
> - The server already rejected new runner selections when the flag was
off.
> - Some setup and onboarding views did not enforce the same boundary.
> - This pull request exposes the existing flag and applies it to every
new setup path.
> - The benefit is a safe rollout with unchanged legacy onboarding and
recoverable existing native runs.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

This improves experimental adapter selection in Settings, onboarding,
new-agent setup, invite setup, and company import.

**Subsystem affected**

Cross-cutting: the React UI and the server onboarding seed service.

**Current behavior**

The server defaulted Paperclip Runner to off, but Settings did not
expose the flag. First-run onboarding could show the runner after
opt-in. A direct new-agent URL and some setup pickers could also reveal
native runner configuration before the availability check completed.

**Proposed behavior**

Settings has a default-off Paperclip Runner toggle. Explicit agent
configuration shows the runner only after the server reports that the
flag is enabled. First-run and invite onboarding always use legacy
adapters. Existing native agents and runs remain readable and
recoverable.

**Reason and benefit**

This keeps the experimental runtime out of normal onboarding. It also
gives administrators one clear opt-in before users can create a native
runner agent.

**Breaking changes**

None. Legacy adapter selection and execution stay unchanged. Existing
native records remain available.

## What Changed

- Added the Paperclip Runner opt-in to Experimental Settings.
- Refreshed adapter availability after the setting changes.
- Kept UI and server-seeded onboarding on legacy adapters.
- Made native runner choices fail closed in new-agent, invite, and
import setup.
- Preserved edit and recovery behavior for existing native agents and
runs.
- Added focused regression tests for flag-off and flag-on behavior.

## Verification

- GitHub Actions will run the repository test, typecheck, build, and
policy gates.
- Focused tests cover Settings, onboarding, agent creation, invite
setup, import setup, and server-seeded onboarding.
- No local test suite was run, per the maintainer request to use GitHub
Actions for verification.
- `git diff --check` passes.

## Risks

Low risk. The change narrows new adapter selection only. The server
remains the final enforcement point. Existing native records do not
depend on the current flag value for read or recovery behavior.

> 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

OpenAI Codex, GPT-5, with reasoning, tool use, and code execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [ ] 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
- [ ] 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-09-01 05:57:40 -05:00
DottaandPaperclip fcb2e99e8f feat(apps): expand the self-serve connection catalog (#12344)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A useful app store needs accurate and selectable provider
definitions.
> - Local brand assets now cover the expanded provider set.
> - Provider methods differ in transport, authentication, ownership, and
required scope.
> - This pull request expands the catalog and encodes those provider
contracts.
> - The benefit is a larger self-serve store with explicit setup
choices.

## Linked Issues or Issue Description

Refs #11965

This is stack 6 of 11. It depends on stack 5 and replaces another
reviewable part of #11965.

## What Changed

- Add and update provider definitions for the self-serve catalog.
- Add Google Workspace connection methods and capability profiles.
- Add catalog generation, ingestion, URL matching, and contract tests.
- Update legacy key tests to use a provider that still uses header
credentials.

## Verification

- `pnpm --filter @paperclipai/server typecheck`
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/tool-access-service.test.ts`
- Result: 164 tests passed.
- `pnpm build`

## Risks

- An incorrect provider definition can offer the wrong setup method.
- Contract tests verify transport, authentication, and provider URL
behavior.
- The change does not add a database migration.

> I checked `ROADMAP.md`. This stack continues the existing app
connection work from #11965 and does not duplicate another planned item.

## Model Used

OpenAI Codex, GPT-5. The runtime model ID and context window were not
exposed. The model used reasoning, tool use, and code execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Refs #` or (b)
described the issue in this pull request
- [x] I have not referenced internal or 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 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-08-29 12:08:34 -05:00
Nicky LeachandPaperclip d9449e636e feat(onboarding): sign in to an agent provider during onboarding (#12440)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - New organizations create their first agent through the onboarding
wizard
> - The wizard does not show provider sign-in when a host credential is
absent or unknown
> - The create step also gives unclear feedback when the provider needs
authentication
> - This pull request adds a safe auth signal and a provider sign-in
step for sandbox drivers
> - The benefit is a clearer onboarding path with no token or account
data in the signal

## Linked Issues or Issue Description

**Subsystem affected**

Cross-cutting (server API, shared types, and UI)

**Problem or motivation**

The onboarding wizard can fail when the selected provider needs
authentication. It does not tell the person how to complete sign-in.

**Proposed solution**

Add a status-only provider auth signal. Show the sign-in panel for
sandbox drivers when the signal says `absent` or `unknown`. Apply a
stored Claude login to the new agent and block creation when the adapter
test reports missing authentication.

**Alternatives considered**

The wizard could hide the sign-in panel when the signal read fails. This
would hide a needed action, so this pull request shows the panel when
the signal is unknown.

**Roadmap alignment**

The change supports the roadmap goal for scoped and audited credential
bindings.

**Additional context**

The auth signal returns only `present`, `absent`, or `unknown`. It never
returns a token, identifier, or account name.

## What Changed

- Add `GET /api/companies/:companyId/adapters/:type/auth-signal` with
company and permission checks.
- Add shared auth-signal types and the UI query path.
- Apply a stored Claude login by reference without reading its token.
- Show the provider sign-in panel only for sandbox drivers with
interactive terminal support.
- Block agent creation when the provider test reports missing
authentication.
- Add route, wizard, and end-to-end test coverage.

## Verification

- `pnpm --filter @paperclipai/server test adapter-auth-signal-routes`
passes 50 tests.
- `pnpm --filter @paperclipai/ui test OnboardingWizard` passes 69 tests.
- `pnpm --filter @paperclipai/ui exec tsc --noEmit` exits with code 0.
- The `e2e_shards` lane runs `tests/e2e/onboarding.spec.ts`.

## Risks

The route reads a host-local readiness signal. It returns `unknown` on
read errors and never exposes credential data. The UI may add a sign-in
step when the signal is unavailable.

## Model Used

OpenAI Codex, GPT-5, extended reasoning, tool use, and code execution.
The exact context window was not provided.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run 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-08-28 10:20:37 -07:00
scotttong 4d82f5eaea copy: unify user-facing "company" wording to "organization" (#12243) 2026-08-27 01:04:55 -07:00
TonioandClaude Opus 5 eb86fcd498 The agent, drawn as itself (#12274)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - A new customer's first session ends in the tenant's agent arc:
create an agent, connect a model, review
> - Walking it turned up questions the arc had no business asking — a
role picker using a vocabulary the customer has not been given, a model
picker asking them to judge models they have not met — and chrome
restating what they had just watched happen
> - Each one costs a first-session customer attention at the exact
moment they are deciding what this product is
> - This pull request cuts the arc to what it must ask, and draws the
agent as itself so the arc has a visible subject
> - The benefit is three steps that each ask one thing, ending on an
agent that is visibly ready

## Linked Issues or Issue Description

No public issue exists. The changes come from walking the sign-up arc
end to end.

**What happened:**
The agent step asks for a role from a fixed enum before asking for a
name. The model step shows two "Recommended" badges (on both options),
an "Adapter type" eyebrow, and a model picker. The review step lists a
three-row checklist of work the customer just performed. The progress
strip is a full-width segmented bar.

**Expected behavior:**
The agent step asks for a name. The model step offers the two harnesses
and hides the rest behind advanced settings. The review step says the
agent is ready. The strip counts three discrete steps.

**Steps to reproduce:**
1. Sign up and enter the tenant wizard on the agent arc.
2. Observe the role select above the optional name field.
3. Continue to the model step: both options carry a "Recommended" badge,
and a model picker sits below.
4. Continue to review: a checklist restates the organization name,
agent, and model.

**Additional context:**
The brand pill assets (`pill-1-dormant.svg`, `pill-1-alive.svg`) are
transcribed verbatim into a component rather than approximated. The role
removal exposed a latent silent-failure path — see Risks.

## What Changed

- `PillGuy` renders the brand pill in two states; the arc holds one
instance, dormant through create and connect, alive on review.
- The agent step asks for a name only. The name is required; the role
picker is gone.
- `DEFAULT_AGENT_ROLE` (`general`) backs every onboarding hire, and
`agentRole` now defaults to it rather than empty.
- The model step drops both "Recommended" badges, the "Adapter type"
eyebrow, and the model picker; "More Agent Adapter Types" becomes
"Advanced settings"; the sub-line becomes "Paperclip works with your
existing subscription or API keys."
- The review step drops its checklist; the heading becomes "Let's get
started..." with "[name] is ready to work!".
- The progress strip renders three left-aligned dots at the previous
gap.
- Five e2e specs and both wizard unit suites migrate off
`#onboarding-agent-role`.

## Verification

Run the tenant suite:

```
cd ui && npx vitest run
```

- 4398 tests pass across 474 files; `npx tsc --noEmit` clean.
- Walked live in a local instance: agent step (dots, dormant pill, name
placeholder), model step (no badges/eyebrow/picker, "Advanced
settings"), review (pill alive, new copy, no checklist).
- The retargeted role test asserts the hire payload carries `role:
"general"` and the typed name — it is the test that catches the silent
failure below.

## Risks

- **A latent silent failure, now closed.** `handleGiveHeartbeat` returns
early when `agentRole` is empty. With the picker removed and no default,
Connect would have hired nobody and shown no error. The default closes
it; the guard stays for any future path that clears the role.
- **Behavioral change:** every onboarding hire is filed as `general`
rather than a chosen role. The role remains editable in the app.
- **Behavioral change:** the model is no longer chosen during
onboarding. Every adapter offered here resolves its own default in
`buildAdapterConfig`, and the model is changeable later.
- **Assets:** the pill carries its own gradient fills and does not
follow the theme. That is deliberate — the agent looks like itself on
either ground.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id
- [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
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:39:55 -07:00
TonioandClaude Opus 5 88a0f885e8 Brand lockup, no idle env-check card, no Mission row (#12074)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - New customers meet the product through an onboarding arc that ends
in the tenant wizard
> - A staging walk of that arc found three rough edges: an ad-hoc icon
standing in for the brand, an environment-check card that narrates a
probe the flow already runs on its own, and a review checklist that
still lists a Mission the arc stopped asking for
> - Each one makes the product look less finished than it is at the
exact moment a customer decides what it is
> - This pull request renders the brand lockup, hides the idle
environment-check card while keeping the probe and its failure surface,
and drops the Mission row
> - The benefit is a first-session arc that reads as one product, with
no controls for questions nobody was asked

## Linked Issues or Issue Description

No public issue exists. The changes come from walking the sign-up arc on
a staging fleet.

**What happened:**
The model step shows an "Adapter environment check" card with a "Test
now" button even though pressing Connect runs the same probe and blocks
a failing hire. The review step lists "Mission" in its checklist
although onboarding no longer asks for one. The auth page renders a
sparkles icon beside the word "Paperclip" instead of the brand lockup.

**Expected behavior:**
The model step shows the check only when a probe has found something to
fix. The review checklist lists only what onboarding set up. The brand
renders as the lockup asset used across surfaces.

**Actual behavior:**
An idle card narrates a probe that runs regardless. A permanent
unchecked row marks a question nobody was asked. The brand is a generic
icon plus text.

**Steps to reproduce:**
1. Sign up on a staging fleet and enter the tenant wizard.
2. On "Create your first agent", choose a role and press Next: the model
step shows the "Adapter environment check" card before anything has been
probed.
3. Continue to Review: the checklist lists "Mission" as a permanently
unchecked row.

**Additional context:**
The Mission row outlived the removal of the mission step (#11935). The
environment probe itself still runs on Connect and blocks a failing
hire; only its idle card is at issue. The brand lockup lands across all
three surfaces in the same round — paperclip-cloud#270 and
paperclip-id#58 carry the other halves.

## What Changed

- `PaperclipLockup` renders the brand asset (mark + wordmark, one
geometry, `fill="currentColor"`); the auth page uses it in place of the
sparkles icon.
- The adapter environment check's idle card (explainer + "Test now") no
longer renders. The probe still runs on Connect and still blocks a
failing hire.
- The check's failure content still renders when a probe has found
something — the blocking error points the customer at "the reported
checks", so they stay visible.
- Connect retries a cached failed probe instead of reusing it. With
"Test now" gone, Connect is the only retry, and a stale fail would lock
out a machine the customer has since fixed.
- The review checklist drops its "Mission" row.

## Verification

Run the tenant suite:

```
cd ui && npx vitest run
```

- 4365 tests pass across 471 files; `npx tsc --noEmit` is clean.
- New test drives the wizard to the model step and asserts the
environment-check card is absent, anchored on "Connect a model" so an
unrendered step cannot pass as an absence.
- The review assertions anchor on the remaining rows ("Organization
name", "Agent created", "Model connected").

## Risks

- **Behavioral change:** a cached *failed* probe is re-run on Connect
instead of reused. Pass and warn results are still cached. This only
affects the retry path that "Test now" used to serve.
- **Hidden, not removed:** the environment check machinery is intact;
only the idle card is gone. A failing probe still blocks the hire and
still shows its checks.
- **Brand:** the wordmark now ships inside an SVG; its accessible name
carries the text. Screen readers announce "Paperclip" as before.

## Model Used

Claude Fable 5 (`claude-fable-5`) via Claude Code, with tool use and
code execution; earlier rounds on this branch's predecessor used Claude
Opus 5 (`claude-opus-5`).

## 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
- [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
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 01:35:15 -07:00
TonioandClaude Opus 5 3ff636bc48 Drop the mission step from the wizard arc (#11935)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - New customers arrive through an onboarding arc that spans Paperclip
Cloud and the tenant app
> - Cloud's naming screen stopped asking for the company mission, but
the tenant wizard still decided its first step by asking whether the
company had one
> - Every Cloud-created company therefore looked mission-less on
arrival, so every walk detoured through a "Define your mission" screen
the design had already removed
> - This pull request removes that step from the arc, and makes step 1
create the company itself
> - The benefit is a shorter arc that matches the design, and a
three-step progress strip that now counts the steps that exist

## Linked Issues or Issue Description

No public issue exists. The problem was found by walking staging end to
end.

**What happened:**
A new customer signs in, names their organization, and waits for it to
build. The tenant wizard then asks "Define your mission" before it asks
for the first agent. Cloud no longer collects a mission, so this screen
appears for every new customer.

**Expected behavior:**
The wizard asks for the first agent, the model, and a review. The
progress strip counts three steps.

**Actual behavior:**
The wizard asks for the mission first. The progress strip counts five
segments, because the run does not enter on the agent arc.

**Additional context:**
Three merged pull requests built the mission-based step choice this
change removes: #11352, #11416 and #11429. The mission is now collected
later, inside the tenant app, so onboarding does not ask for it at all.

## What Changed

- `onboardingStepForCompany` always returns the agent step. The
`companyHasMission` parameter is removed, because it cannot change the
answer.
- `resolveRouteOnboardingOptions` no longer accepts `companyHasMission`.
- The dashboard no longer waits for the goal lookup before it opens the
wizard. That wait only chose a step, and the step is now fixed.
- Step 1 creates the company in a new `handleCreateCompany`. Company
creation used to sit at the end of `handleConfirmMission`.
- No company goal is written during onboarding.
- The three-step strip now shows on the agent, model and review steps,
because every Cloud-first run enters on the arc.
- The full-length bar drops its second segment. No run can fill it.
- The grow path keeps its step 2 questionnaire. Only the create path
skips ahead.
- Back from the agent step goes to the screen the run came from.
- Four end-to-end specs no longer drive the wizard through the mission
step.

## Verification

Run the tenant test suite:

```
cd ui && npx vitest run
```

- 4356 tests pass. 471 files pass.
- `npx tsc --noEmit` reports no errors.
- Fault injection: forcing `skipsMissionStep` to `true` fails the grow
questionnaire test. Removing the Back rule fails the Back test. Both
tests fail on the exact defect they guard.
- The three-step strip is asserted by an existing test. It checks `Step
1 of 3` and `aria-label="Create your first agent"`.

Manual check on staging after the paired Cloud change:

1. Open a new incognito window.
2. Sign in with a new account.
3. Name the organization.
4. Confirm the wizard shows "Create your first agent" and "Step 1 of 3".

## Risks

- **Behavioral change.** Onboarding no longer writes a company goal. An
agent hired during onboarding starts without a seeded mission. This is
intended. The mission moves to the tenant app.
- **Dead code.** `ONBOARDING_MISSION_STEP` and the mission screen stay
in the codebase, but nothing in the app opens them. They wait for the
surface that collects the mission later.
- **Grow path.** The grow path is unchanged, but it shares step 2 with
the removed screen. New tests cover it.
- **Superseded work.** #11352, #11416 and #11429 tuned the mission-based
step choice. This change removes the branch they tuned.

## Model Used

Claude Opus 5 (`claude-opus-5`), extended thinking, with tool use and
code execution through Claude Code.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id
- [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
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 02:28:45 -07:00
TonioandClaude Opus 5 3d366ba15f Rebuild the onboarding agent arc on the prototype's step design (#11905)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The onboarding wizard in `ui/` hires that first agent. It runs three
steps: create the agent, connect a model, and review
> - A standalone prototype holds the agreed design for these steps.
#10786 ported that prototype, but #11067 reverted it in full because the
port deleted `OnboardingWizard.tsx` while four pull requests were
editing that file
> - Those four pull requests have since merged. The revert said the port
can "re-land incrementally", and this is that re-land
> - This pull request takes the presentational layer from the prototype
only. It keeps master's wizard as the source of behaviour, so the eight
onboarding fixes merged since the revert stay in place
> - The benefit is that the three agent steps match the agreed design,
and no merged fix is lost to get there

## Linked Issues or Issue Description

Refs #10786 — the first attempt to land this design.
Refs #11067 — the revert that asked for it to re-land in smaller steps.

No public issue exists for the re-land. The problem is described below.

**Subsystem affected**

The `ui` package. The change touches the onboarding wizard, the agent
capsule,
and one Storybook story. It adds four small presentational components
under
`ui/src/components/onboarding/`.

**Current behavior**

The wizard's agent steps do not match the prototype. Each step shows a
small
heading beside an icon, above a form. The agent capsule sits below that
heading and does not animate. The agent gets a name but no role, so
every
first agent is created as `ceo`.

The wizard also shows a five-segment progress bar on these steps. A
walker who
enters on the agent step cannot reach the first two segments, so two of
the
five can never be filled.

**Proposed behavior**

The three steps use the prototype's card, its centred display heading,
and its
footer. One capsule sits above the heading and stays mounted across all
three
steps, so it reads as one object being built rather than three screens
that
each show their own.

A three-segment strip counts these steps for a walker who enters on
them. The
full-length bar stays for a walker who starts at step one, so that count
never
restarts partway.

The agent step gains a role. The options come from the agent role enum,
not
from the prototype's mock list.

**Reason and benefit**

The design is agreed and already built once. Re-landing it
presentation-first
keeps the behaviour that master gained after the revert.

Sourcing roles from the enum matters. The prototype offers "Coder",
which is
not a valid role — the enum uses `engineer` — so a walker who picked it
would
fail validation at hire time.

**Breaking changes**

None. The wizard keeps its routes, its draft format, and its hire call.
The
draft gains one optional field, `agentRole`. A draft saved before this
change
loads without it and falls back to the default.

## What Changed

- Add `ui/src/components/onboarding/`: `Stepper`, `OnboardingCard`,
`OnboardingHeading`, `FooterNav`, `AgentPreview`, and shared motion
constants
- Rebuild wizard steps 3–5 on those parts: one card, the capsule above a
  centred heading, and one footer
- Hold one `AgentCapsule` across the three steps. It springs in once,
then
  morphs from dashed slot to traced outline to filled
- Add `strokeDraw` to `AgentCapsule`. It traces the outline instead of
  cross-fading it. The dashed layer holds until the trace ends
- Add a role select to the agent step. Choosing a role fills the name,
unless
  the walker typed one
- Show one progress indicator per run, not two
- Label strip segments by destination, not by number
- Add `motion` to the `ui` package
- Add a Storybook story for the strip and the capsule states

## Verification

Run the tests:

```
pnpm --filter @paperclipai/ui exec vitest run
pnpm --filter @paperclipai/ui exec tsc -p tsconfig.json --noEmit
```

4235 tests pass. The typecheck is clean.

To see the steps, start the app and open `/<PREFIX>/onboarding` for a
company
that has a company-level goal. The wizard opens on the agent step. Step
three
requires a hire.

Three absence assertions were checked by fault injection. Each one fails
when
the old behaviour returns:

- put the step counter back, and the "shows no step counter" test fails
- default `strokeDraw` to true, and the cross-fade test fails
- restore the timer gate on the strip, and the indicator test fails

## Risks

Low to medium.

`motion` is one new dependency in `ui`. #11067 gave dependency weight as
one
of three reasons to revert #10786, so this branch carries the smallest
set
that works. `motion` drives the step transitions and the capsule
choreography,
and three files import it.

An earlier revision of this branch also added `three` and
`@types/three`. Both
are removed. They existed for the 3D backdrop, which belongs to the auth
and
welcome screens rather than to these three steps, so nothing on this
branch
imported them.

The role select changes what the wizard sends. Before this change every
first
agent was hired as `ceo`. Now the walker chooses. The values come from
the
enum, so the server accepts all of them.

Steps 1 and 2 keep the older design. They do not run on the Cloud-first
path,
where the company already exists.

## Model Used

Claude Opus 5 (`claude-opus-5`), with extended thinking, tool use, and
code
execution. Used for the code, the tests, and this description.

## 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: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 16:41:53 -07:00
Nicky LeachandPaperclip 5bc6031f79 fix(server,ui,claude-local): verify auth on the adapter Test lane and enforce managed-sandbox tenant binding (#11810)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Adapter Test checks whether an agent adapter can run with its
configured environment, and every local-driver adapter (Claude, Codex,
Gemini, OpenCode, Pi, Cursor, etc.) shares this Test route and its UI
resolution logic
> - The Claude ACP Test lane could report pass without checking local or
remote authentication, and the shared Test route and UI had gaps in
environment binding, probe safety, and managed-sandbox resolution that
affect every adapter that uses the Test button, not only Claude
> - This pull request verifies authentication on every Claude ACP
target, and closes the shared Test-route/UI gaps: tenant-binding on the
route, a managed-sandbox-only redirect that matches the real run path,
and a three-tier environment resolution in the UI
> - The benefit is a truthful Test result with safer probe execution and
tenant isolation, for Claude specifically and for every other local
adapter that shares this Test surface

## Linked Issues or Issue Description

**What happened?**

The Claude ACP Test lane returned `status: "pass"` without checking
authentication for some local and non-sandbox targets. Separately, the
shared `/companies/:companyId/adapters/:type/test-environment` route —
used by every local-driver adapter, not only Claude — accepted a foreign
environment id, and its UI resolution did not mirror the server's
managed-sandbox-only redirect.

**Expected behavior**

The Test lane checks the resolved credential and hello probe for every
Claude ACP target. The shared adapter Test route rejects a foreign
environment before it reveals environment details or starts a lease, for
any adapter type. The Test's environment resolution (UI and server)
matches the real run's three-tier resolution, including the
managed-sandbox-only redirect.

**Steps to reproduce**

1. Run the Claude ACP Test lane against a local target without a valid
credential.
2. Run the adapter Test route with an environment id from another
company (any adapter type).
3. Observe the pass result on step 1, or the missing tenant-binding
rejection on step 2.

**Paperclip version or commit**

`933749e01f74e82ce5d315c071be534d04e01158`

**Deployment mode**

Local dev (`pnpm dev`) and server route tests.

**Agent adapter(s) involved**

Claude Code directly (the ACP auth-verification work). The
tenant-binding guard, managed-sandbox-only redirect, and UI three-tier
resolution apply to the shared adapter Test route and affect every
local-driver adapter (Codex, Gemini, OpenCode, Pi, Cursor, etc.), not
only Claude — see "What Changed" below for the split between Claude-only
and shared changes.

**Database mode**

Not database-related.

**Access context**

Both board and agent paths use the affected Test surface, for every
local-driver adapter.

**Additional context**

Two commits that were previously bundled into this PR — a
`plugin-worker-manager` duplex-channel frame-bound fix and a
`workspace-runtime` exit-persist crash fix — are unrelated to the
adapter Test lane and have been split out into their own PRs: #11860 and
#11861.

## What Changed

Claude-only (`packages/adapters/claude-local`):

- Verify `CLAUDE_CODE_OAUTH_TOKEN` and run the hello probe for every
Claude ACP target.
- Keep `adapter_auth_missing` sandbox-only and report missing
non-sandbox credentials as a warning.
- Add a deny-by-default probe environment builder for the ACP and CLI
local probes.
- Log only fixed probe context and allowlisted classifications.
- Seed the host OAuth token into the hello probe environment.

Shared, cross-adapter (`server/src/routes/agents.ts`,
`ui/src/lib/adapter-test-environment.ts`,
`ui/src/components/AgentConfigForm.tsx`,
`ui/src/components/OnboardingWizard.tsx`):

- Add a company-binding guard and a binding assertion for the generic
`/companies/:companyId/adapters/:type/test-environment` route, so a
foreign-company environment id is rejected before any secret resolution
or sandbox lease, for every adapter type.
- Resolve all three server environment tiers (agent default, instance
default, local default) in the UI, and add the managed-sandbox-only
redirect so the Test probes the same target a real run would use.
- Enforce onboarding Test results: block hire on a failed environment
test.

- Add regression tests for authentication, tenant binding, probe safety,
diagnostics, and UI resolution.

## Verification

- Adapter suites pass for the Claude local server probe, remote, ACP,
auth, probe environment, and config paths.
- Server route tests pass, including the five tenant-binding cases.
- UI adapter Test environment resolver tests pass for all three
resolution tiers.
- Adapter package `tsc --noEmit` exits 0.
- Full CI must pass on this pull request.

## Risks

The probe environment now denies caller variables by default. A required
variable that is not on the allowlist could stop a probe from starting.
The route now rejects foreign environment ids with a fixed 403 response.
The managed-sandbox-only redirect changes where the Test (and the login
affordance) probes for every local-driver adapter under that policy, not
only Claude — operators running other local adapters under
managed-sandbox-only will see their Test target move from local to the
managed sandbox, matching what real runs already do. The change limits
secret and diagnostic exposure.

## Model Used

Original implementation: OpenAI Codex, GPT-5; exact context window not
exposed in that run; tool use and code execution.

This revision (commit split and title/description correction): Claude,
Sonnet 5 (claude-sonnet-5). The original title and description described
this PR as Claude-only; review found it also changes the shared adapter
Test route and UI resolution used by every local-driver adapter, and
carried two unrelated server fixes. Claude split those two commits into
#11860 and #11861 via `git rebase --onto` (verified byte-identical to
the original tree minus those commits) and rewrote this description to
reflect the actual scope. No functional code in this PR was authored by
Claude.

## 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-08-21 11:30:49 -07:00
233c12f029 feat: add kimi-local adapter for Kimi Code CLI (CLI + ACP engines) (#9967)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Local agent adapters (`claude_local`, `gemini_local`, `grok_local`,
…) are the integration surface that lets Paperclip run coding CLIs on
the host machine
> - The Kimi Code CLI (`kimi`, Moonshot AI) has a documented
non-interactive mode, `kimi -p --output-format stream-json` with session
resume via `kimi -r`, but Paperclip has no built-in adapter for it
> - So Kimi users (especially Kimi membership / OAuth subscribers)
cannot onboard their CLI to Paperclip agent teams
> - This pull request adds a complete built-in `kimi_local` adapter
(both execution engines, session management, instructions + skills
delivery, thinking-effort control, environment test, UI and CLI modules,
docs) following the established `gemini_local`/`grok_local` package
pattern
> - Kimi Code ships an ACP server (`kimi acp`), so the adapter runs on
Paperclip's shared acpx engine by default (streaming transcript with
live tool status, like `claude_local`/`gemini_local`) and falls back to
a headless CLI lane (`kimi -p --output-format stream-json`) when ACP
prerequisites are unavailable
> - The benefit is that Kimi Code becomes a first-class Paperclip agent
lane: selectable in the UI, resumable across heartbeats, with the same
operating context (instruction bundle, skills, effort) and streaming
transcript the other local adapters get

## Linked Issues or Issue Description

- Supersedes #9880 (same branch; expanded from the CLI-only lane into a
complete adapter with the default ACP engine lane, control-plane skill
install, and live transcript wiring)
- Refs #9879 (adapter request for Kimi Code CLI, filed with this PR)
- Refs #163 (original Kimi support request)

Duplicate/related prior PRs, per the dedup search (both appear stale: no
updates or maintainer review since May 2026, and both target an older
Kimi CLI interface; calling them out for reviewer context per
CONTRIBUTING.md):

- Refs #6276 (`feat: add kimi-local adapter`): targets an older
array-based content format (`{type: think}`/`{type: text}` blocks), not
the current documented stream-json schema
- Refs #5202 (`feat(adapter): add Kimi CLI local adapter with Wire
protocol support`): builds on a `--wire` JSON-RPC interface that current
Kimi Code CLI (0.27.0) no longer documents; the current documented
headless interface is `-p --output-format stream-json`

This PR is a fresh implementation against current master and the
currently documented/verified Kimi CLI behavior (see Verification).
Happy to fold in anything useful from the earlier attempts if a reviewer
prefers.

## What Changed

- **New adapter package** `packages/adapters/kimi-local`
(`@paperclipai/adapter-kimi-local`), modeled on
`gemini-local`/`grok-local`:
- `src/server/execute.ts`: spawns `kimi -p <prompt> --output-format
stream-json` (argv array, no shell), `-m <model>` only when configured,
`-r <sessionId>` when the stored session cwd matches the run cwd,
automatic fresh-session retry on unrecoverable-session errors,
headless-safe env (`CI=1`, `NO_COLOR=1`, `KIMI_CODE_NO_AUTO_UPDATE=1`,
`TERM=dumb`; user-configured values win), full remote (ssh/sandbox)
execution lane with runtime install via `@moonshot-ai/kimi-code`
- **Instruction bundle delivery**: the prompt path directive now names
the sibling instruction files (`./HEARTBEAT.md`, `./SOUL.md`,
`./TOOLS.md`) alongside the prepended entry file, and local runs pass
`--add-dir <instructions-dir>` so Kimi can actually open them (matching
`claude_local`). Without this, only the entry file reached Kimi and
agents improvised the operating workflow that `HEARTBEAT.md` documents
- **Thinking effort**: a configured `effort` is forwarded as the
`KIMI_MODEL_THINKING_EFFORT` operational override (Kimi has no
per-invocation effort flag). It is only sent for models that advertise
`support_efforts` (currently `kimi-code/k3`) to avoid provider
rejections, and `medium` maps to `high` since Kimi has no medium tier
(`low`/`high`/`max` pass through)
- **Skills delivery**: desired Paperclip skills are delivered via Kimi's
`--skills-dir` flag from a dedicated per-run directory (a local
snapshot, or the synced snapshot on remote targets), so skills load
reliably and in isolation. Paperclip never overwrites the shared
`$KIMI_CODE_HOME/skills` home, so skills installed by the operator or
other agents are left intact. `--skills-dir` is only passed when at
least one skill is desired, so unconfigured agents keep Kimi's default
skill discovery
- **Live run status**: the adapter now forwards each streamed
stream-json line to `onEvent` (assistant `content` as an assistant
snippet, `tool_calls` as tool-name events), which drives the
issue-thread activity indicator (`currentToolName` /
`lastAssistantSnippet` / `lastEventAt`). Previously the adapter only
wrote the raw run log, so the issue thread showed a stale "no output for
N s" line with no tool or reasoning context while Kimi worked. Tool
results are omitted so the last meaningful "Using X" / snippet is not
overwritten by a generic label
- `src/server/parse.ts`: parses the verified Kimi stream-json event
shapes (`assistant` text, `assistant.tool_calls` with JSON-string
arguments, `tool` results, trailing `meta.session.resume_hint` for
session-id capture) plus failure classifiers (`kimi_auth_required`,
transient network, unrecoverable session). A signaled exit (null exit
code, not a timeout) is now reported as a failure rather than coalesced
to success, and the error message names the terminating signal
- `src/server/skills.ts`: lists/syncs Paperclip skills for the adapter's
skill-management surface
- `src/server/test.ts`: environment test covering CLI resolution + `kimi
--version`, cwd check, auth detection (OAuth credential dirs, keyed
`[providers.*]` in config.toml, or the `KIMI_MODEL_NAME` +
`KIMI_MODEL_API_KEY` env pair), and a live hello probe
- `src/ui/` (stdout-line parser for transcripts, config builder) and
`src/cli/` (stream event formatter) modules
- Root metadata: three managed model aliases
(`kimi-code/kimi-for-coding`, `kimi-code/kimi-for-coding-highspeed`,
`kimi-code/k3`), effort-capable-model metadata (`EFFORT_CAPABLE_MODELS`,
effort mapping helpers), `agentConfigurationDoc`
- Tests: 101 tests across parse, execute (args building, resume gating,
retry, auth error code, timeout, signaled-exit failure, effort
forwarding/gating/mapping, `--add-dir` instructions directive,
`--skills-dir` gating, `onEvent` runtime-event forwarding), ACP engine
(engine resolution, acpx config build, node-version gate), ACP
transcript delegation, environment test, UI parse/build-config
- **ACP engine lane (default)** (`src/server/acp.ts` + shared
`adapter-utils/acpx-engine`): Kimi Code ships an ACP server (`kimi
acp`), so `kimi_local` now runs on Paperclip's shared acpx engine by
default, matching `claude_local`/`codex_local`/`gemini_local`. The
issue-thread transcript streams live (assistant text deltas, tool calls
with a `pending`->`completed` status lifecycle) instead of the CLI
lane's bursty complete-message output. Registered `kimi_local -> "kimi"`
in `ACPX_ADAPTER_AGENT_IDS` and resolved the built-in agent command to
`kimi acp`; `execute.ts` dispatches to the ACP executor first with an
automatic CLI fallback when ACP prerequisites fail (`engine=acp`
requires ACP, `engine=cli` pins the headless lane); `index.ts` falls
back to the shared acpx session codec; the UI/CLI delegate `acpx.*`
events to the shared acpx transcript parser and event formatter. The
headless CLI lane (above) remains as the fallback
- **Registration** (one entry each, mirroring existing adapters): server
adapter registry + `BUILTIN_ADAPTER_TYPES`, `AGENT_ADAPTER_TYPES`
(shared), UI adapter registry + display registry (`Kimi Code`, Moon
icon) + capabilities defaults, CLI adapter registry, `Dockerfile`
(package copy + `npm install --global @moonshot-ai/kimi-code@latest`),
`vitest.config.ts` workspace, `scripts/release-package-manifest.json`
- **Behavioral sets** mirroring `gemini_local` (Kimi resumes sessions
the same way): `GIT_SENSITIVE_LOCAL_ADAPTER_TYPES`,
`SESSIONED_LOCAL_ADAPTERS` (heartbeat + recovery),
`REMOTE_MANAGED_ADAPTERS`, ssh/sandbox execution-target allow-lists,
`ADAPTER_DEFAULT_RULES_BY_TYPE` (`timeoutSec: 0`, `graceSec: 15`), and
`LEGACY_SESSIONED_ADAPTER_TYPES` + `ADAPTER_SESSION_MANAGEMENT` in
adapter-utils
- **UI touch-points**: New Agent default-model branch, AgentConfigForm
command map (`kimi_local: "kimi"`) + model defaults + a Kimi-specific
thinking-effort option list (`Low`/`High`/`Max`, reflecting Kimi's tiers
rather than borrowing Claude's), OnboardingWizard (command map, model
default, `kimi login` / `KIMI_MODEL_NAME + KIMI_MODEL_API_KEY` auth
hints, manual-debug command line), InviteLanding enabled adapters
- **Control-plane skill install** (`cli/src/commands/client/agent.ts`):
`paperclipai agent local-cli` seeded the Paperclip control-plane skills
into `~/.codex/skills` and `~/.claude/skills` so Codex/Claude agents
auto-discover the API reference every run. Kimi had no equivalent
target, so `kimi_local` agents began each session without the
control-plane skill and rediscovered routes (e.g. the company-scoped
`POST /api/companies/{companyId}/issues`) by trial and error. Added
`~/.kimi-code/skills` (honoring `KIMI_CODE_HOME`) as a third install
target for parity. Independent of the per-run `--skills-dir` delivery,
which only applies to explicitly configured skills.
- **Docs**: `docs/adapters/kimi-local.md` (prerequisites, auth options,
config fields including `effort`, session resume, instruction bundle,
skills delivery, control-plane skill install) + a row in
`docs/adapters/overview.md`

Out of scope (deliberately): model profiles, built-in agent
`allowedAdapterTypes` additions.

## Verification\n\nCurrent-master rebase verification (OpenAI Codex,
2026-08-03): 13 focused files / 231 tests pass; adapter-utils, server,
UI, CLI, and Kimi adapter typechecks pass; full repository build and UI
token gates pass. The branch is conflict-free against master at head
`1249df117c5e12e5771b9a570a6340866450619e`.\n\nAutomated (all from repo
root, pnpm 9.15.4, Node 22):

- `vitest run packages/adapters/kimi-local`: 89/89 pass (includes
coverage for the instruction `--add-dir` directive, effort
forwarding/gating/mapping, `--skills-dir` gating, the signaled-exit
failure path, and `onEvent` runtime-event forwarding with cross-chunk
line buffering)
- `vitest run server/src/__tests__/adapter-registry.test.ts
server/src/__tests__/adapter-routes.test.ts
server/src/services/heartbeat-stop-metadata.test.ts
ui/src/adapters/adapter-display-registry.test.ts`: 37/37 pass
- `vitest run cli/src/__tests__/skills.test.ts`: 13/13 pass (the
control-plane skill install target follows the existing Codex/Claude
install path, whose symlink logic is unchanged)
- `vitest run packages/shared`: 307/307 pass; `vitest run
packages/adapter-utils`: pass except one pre-existing, unrelated failure
(`mcp-isolation.integration.test.ts` requires Claude CLI ≥ 2.1.207; host
has 2.1.185, fails identically on unmodified master)
- `pnpm --filter @paperclipai/adapter-kimi-local typecheck|build`, plus
typecheck of `server`, `ui`, `cli`, `adapter-utils`: all clean
- `pnpm install --frozen-lockfile`: passes (the PR diff itself contains
no lockfile changes, per repo policy; verified against a locally
regenerated lockfile)
- `node scripts/check-no-git-push.mjs` and `node
scripts/check-forbidden-tokens.mjs`: pass
- CI note: the `policy` job's release-bootstrap step is expected to stay
red until a maintainer bootstraps the first npm publish of
`@paperclipai/adapter-kimi-local`; see the CI Note for Maintainers
comment. All other contributor-actionable checks are green.

Manual end-to-end (real Kimi CLI 0.27.0, OAuth login, dev server on an
isolated instance):

1. Server `GET /api/adapters` lists `kimi_local` as builtin with correct
capability flags; models endpoint returns the three Kimi models
2. `POST .../adapters/kimi_local/test-environment`: all checks pass,
including a live `kimi -p` hello probe
3. Created a `kimi_local` agent and invoked two heartbeats: run 1
spawned `kimi -p ... --output-format stream-json`, Kimi used its `Read`
tool, produced the expected answer, and the session id was captured from
the `session.resume_hint` meta event; run 2 resumed the **same** Kimi
session (`sessionIdBefore == sessionIdAfter`) via `-r`
4. UI: adapter appears in the New Agent dropdown; selecting it shows the
Kimi command placeholder, the three models, and the Kimi config fields;
the run transcript renders Kimi tool calls via the adapter's stdout
parser

The instruction-bundle, thinking-effort, and `--skills-dir` changes
landed after the manual run above. They are covered by the unit tests
listed under Automated, and the Kimi CLI flags they rely on
(`--add-dir`, `--skills-dir`, `KIMI_MODEL_THINKING_EFFORT`) were
confirmed against the installed Kimi Code CLI 0.27.0 (`kimi --help`,
config-file thinking-effort docs).

Screenshots (assets branch on the fork, not part of the diff):

![Kimi Code in the Add a new agent runtime
picker](https://raw.githubusercontent.com/hawikk/paperclip/assets/kimi-local-pr-screenshots/shots/00-kimicode.png)

![Adapter dropdown with Kimi
Code](https://raw.githubusercontent.com/hawikk/paperclip/assets/kimi-local-pr-screenshots/shots/01-adapter-dropdown-kimi.png)

![Kimi adapter selected: command, model, config
fields](https://raw.githubusercontent.com/hawikk/paperclip/assets/kimi-local-pr-screenshots/shots/02-kimi-adapter-selected.png)

![Kimi models in the model
dropdown](https://raw.githubusercontent.com/hawikk/paperclip/assets/kimi-local-pr-screenshots/shots/03-kimi-model-dropdown.png)

![Successful resumed heartbeat run (kimi_local invocation + parsed
transcript)](https://raw.githubusercontent.com/hawikk/paperclip/assets/kimi-local-pr-screenshots/shots/04-successful-resumed-run.png)

![Agents list showing the Kimi Code
label](https://raw.githubusercontent.com/hawikk/paperclip/assets/kimi-local-pr-screenshots/shots/05-agents-list.png)

## Risks

- Low risk to existing behavior: the change is additive, one new
workspace package plus single-entry registrations alongside existing
adapters; no existing adapter code paths are modified.
- The adapter invokes the locally installed `kimi` CLI; like other local
adapters, run behavior depends on the host's Kimi version. The parser is
written against the documented/verified 0.27.0 stream-json schema and
degrades gracefully (malformed lines are skipped, failures surface as
run errors).
- `--skills-dir` overrides Kimi's auto-discovery of user and project
skills for the run. This is intentional (paperclip-managed agents get a
reproducible, isolated skill set), and it is only passed when at least
one Paperclip skill is desired, so unconfigured agents keep default
discovery.
- Thinking effort is only forwarded to models that advertise
`support_efforts` (currently `kimi-code/k3`); `EFFORT_CAPABLE_MODELS`
must be extended when more Kimi models gain support, otherwise a
configured effort is silently ignored for them.
- `Dockerfile` now installs `@moonshot-ai/kimi-code@latest` globally
alongside the other agent CLIs, so image size increases slightly.
- Maintainer action needed for the npm bootstrap gate: the `policy`
job's release-bootstrap step fails until the first npm publish of
`@paperclipai/adapter-kimi-local` (the gate from #5146 that every new
adapter package has passed through). Enrollment with `publishFromCi:
true` is required by the manifest validator (dropping the entry,
`false`, or `private` are all rejected), so this is intentionally left
to a maintainer. Remaining CI lanes are expected to run once it is done.

## Model Used\n\n- **Current-master rebase, conflict adaptation, and
registry-parity coverage:** OpenAI, **GPT-5 Codex** (Codex agent; exact
serving model ID and context-window size were not exposed to the
runtime), with repository, shell, Git, and GitHub tooling. It preserved
Hawik’s commit authorship, reconciled ACPX and environment-capability
changes, added current registry tests, and ran the verification
above.\n- **Adapter implementation and initial review:** Moonshot AI,
**Kimi K3 Coding** (latest), via **Kimi Code CLI v0.27.0**
(`kimi-code/k3` alias, 1M-token context window, thinking mode, agentic
tool use). The CLI agent explored the repo, wrote the adapter
implementation (delegated to a coder sub-agent of the same model), ran
tests, and drafted the first version of this PR body. A second
model-driven review pass (read-only, same model) audited the diff for
security/correctness before submission; its findings (shell-quoting
hardening, auth-detection false positive, session-compaction
registration, test gaps) were fixed and are included.
- **Harness-context fixes and review responses:** Anthropic, **Claude
Opus 4.8** (`claude-opus-4-8`) via Claude Code. Diagnosed from run logs
that Kimi received only the entry instructions file (not the
`HEARTBEAT.md`/`SOUL.md`/`TOOLS.md` bundle) and that `effort` was never
wired, then implemented the instruction `--add-dir` delivery,
`KIMI_MODEL_THINKING_EFFORT` forwarding, and `--skills-dir` skill
delivery, added the accompanying tests and docs, and addressed the
automated review comments (preserving external skills on remote sync,
treating a signaled exit as a failure). Also extended the `paperclipai
agent local-cli` installer to seed the control-plane skills into
`~/.kimi-code/skills` for Codex/Claude parity, wired `onEvent` runtime
events so the issue-thread activity indicator reflects Kimi's tool and
reasoning output live, and built the ACP engine lane (`kimi acp` via the
shared acpx engine, default) so the transcript streams with live tool
status like the other ACP adapters. The Kimi CLI flags, subcommand, and
env var relied on here were verified against the installed Kimi Code CLI
0.27.0.
- All CLI behaviors claimed here (`-p`, `--output-format stream-json`,
`-r` resume, event shapes, `--add-dir`, `--skills-dir`,
`KIMI_MODEL_THINKING_EFFORT`) were verified empirically against the
installed Kimi CLI, not assumed.

## 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 *(only the release-bootstrap step
remains red, pending the maintainer npm publish described in Risks)*
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
*(will address all Greptile comments as they arrive)*
- [x] I will address all Greptile and reviewer comments before
requesting merge





---

## Maintainer Addendum (2026-08-20)

The shared acpx-engine and issue-chat changes (run-summary segmentation,
placeholder tool-event coalescing,
`ISSUE_CHAT_TRANSCRIPT_MAX_VISIBLE_ENTRIES` 30 → 400, live-reasoning UI)
have been **extracted to #11761** so the cross-adapter behavior changes
review and revert independently — both commits there preserve @hawikk's
authorship. This PR is now the kimi-specific adapter only (60 files,
+3,793/−8, essentially pure addition); the only shared-engine touch left
is the `kimi acp` command resolution. `publishFromCi` is `true` — the
package name is bootstrapped on npm.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Dotta <bippadotta@protonmail.com>
Co-authored-by: Devin Foley <devin@paperclip.ing>
2026-08-20 12:06:33 -07:00
TonioandClaude Opus 5 6d0adbfb5d refactor(ui): retire the shared-cache reasoning the account key made obsolete (#11507)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Three places in the UI turn the company list into an authorization
verdict: the invite landing page, the onboarding draft gate, and company
auto-selection
> - Each grew a defense when one `["companies"]` cache entry answered
for every account, and each documented that hazard at length
> - #11488 keyed the entry by account, so the hazard those comments
describe can no longer happen
> - The comments stayed, and a comment that describes a trap that no
longer exists is how the next reader removes a mechanism that is still
holding something up
> - This pull request replaces that reasoning with what the mechanisms
actually do now, and removes the one condition that genuinely went dead
> - The benefit is that the next person to simplify these gates has
accurate reasons to work from

## Linked Issues or Issue Description

No public issue exists. Follow-up to #11488, #11430 and #11417. The
problem follows.

**What happened?**

The three gates were written against a shared, account-less company
cache. #11488 keyed that entry by account, which made the documented
hazard impossible — but the documentation stayed. Each gate now carries
a long explanation of a cross-account leak that the key prevents, while
the mechanism it explains is in fact still required for a different and
unrelated reason.

That is a maintenance hazard in a specific direction: a reader who
checks the comment against the code concludes the mechanism is obsolete,
removes it, and reintroduces a failure the comment never mentioned.

**Expected behavior**

The reasoning next to each gate describes why the gate is there now.

**Steps to reproduce**

Read the comment above `ownershipDecidable` in `OnboardingWizard.tsx`
against `master`. It justifies `isSuccess` on the grounds that "after an
account switch the retained value is the previous account's list", which
the account-keyed entry makes impossible.

**Paperclip version or commit**

`master` at `0817fbad9`.

## What Changed

- `ui/src/pages/InviteLanding.tsx` — dropped the
`Boolean(sessionQuery.data)` conjunct from `membershipListIsCurrent`;
rewrote the comment.
- `ui/src/components/OnboardingWizard.tsx` — replaced the shared-cache
explanation above the ownership gate with the reason the gate still
exists.
- `ui/src/hooks/useSignOut.ts` — corrected the sweep's rationale, which
cited the company list as its example of data the next account could
read.

### The one dead condition

`membershipListIsCurrent` tested `Boolean(sessionQuery.data) &&
companiesQuery.isFetchedAfterMount`. The first term cannot be false when
the second is true: the query is `enabled` only while a session exists,
so the flag cannot be set without one. The lapsed-session case it looked
like it covered is covered by the keying instead — the observer re-keys
to the anonymous entry and holds no data to leak.

Tests pass with it removed, but that only shows no test distinguishes
it, which is why the reasoning above is recorded in the code rather than
left for the next reader to redo.

### What is deliberately kept

Each gate turned out to be load-bearing for a reason that has nothing to
do with accounts:

- **InviteLanding** still waits for a list fetched this mount. A pending
query reads as an empty list, which reads as "not a member", which
auto-accepts an invite the customer may already hold.
- **OnboardingWizard** still forces a fetch with `staleTime: 0`. A
cached list is the right account's but can be thirty seconds old, so a
company created moments ago in another tab is missing from it — and
missing reads as "you do not own this", which *deletes* the draft rather
than withholding it.
- **CompanyProvider** still clears the live selection on an account
change. That is component state and does not change key with the query.

Removing them as redundant is the mistake the stale comments invited;
this change is what makes that argument harder to make by accident.

## Verification

- `pnpm tsc -b` in `ui`: clean.
- `InviteLanding.test.tsx`, `OnboardingWizard.test.tsx`,
`CompanyContext.test.tsx`, `useSignOut.test.tsx`,
`companies-query.test.ts`: **67 passed**, run twice.

No behaviour change is claimed and none is intended: the only
non-comment edit is the removal of a condition that cannot alter the
expression's value.

**Not done:** no browser run. Nothing here is observable at runtime.

## Risks

Low. Comments, plus one condition shown to be unreachable-false.

The risk that remains is a documentation risk in the other direction: if
the keying is ever reverted or bypassed, these comments will understate
what the gates protect against. They name #11488 so that connection is
findable.

**This does not close the class.** Account-scoped entries other than the
list — `["companies", id]`, stats, and the rest — still survive an
account change that skips the sign-out button. That is unclaimed work,
and larger than this.

## Model Used

Claude Opus 5 (`claude-opus-5`), through Claude Code. Extended thinking
enabled. Tool use enabled: file read and edit, shell for typecheck and
test runs.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] 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 <noreply@anthropic.com>
2026-08-16 22:34:55 -07:00
TonioandClaude Opus 5 327f59cac2 refactor(ui): key the company list by account (#11488)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Which companies a person belongs to is an authorization fact the
server owns, and the UI caches the answer for speed
> - It cached that answer under one `["companies"]` key with no account
attached, while `main.tsx` sets `staleTime: 30_000` for every query
> - So for thirty seconds after an account change, one person's list
answered questions asked about another, arriving with no loading state
and no error
> - Three separate consumers each grew their own defense against this,
and each was a place to forget one
> - This pull request keys the entry by account, so a list belonging to
someone else is not distrusted but unreachable
> - The benefit is that the protection stops depending on every future
consumer remembering to defend itself

## Linked Issues or Issue Description

No public issue exists. Refs #11380, #11382, #11417, #11430. The problem
follows.

**What happened?**

The company list lived in a single cache entry, `["companies"]`,
carrying no record of which account it was fetched for. Combined with
the app-wide 30s `staleTime`, any read within that window after an
account change returned the previous account's list — from cache, with
no request, no loading state and no error.

Every consumer that treats the list as an authorization fact had to know
this and defend itself:

- `InviteLanding` reads it to decide whether you already belong to the
inviting company (#11417).
- `OnboardingWizard` reads it to decide whether a saved draft belongs to
you (#11382, merged).
- `CompanyProvider` reads it to pick and persist your active company
(#11430).

All three defenses are correct. The problem is structural: the fourth
consumer has to invent a fourth one.

**Expected behavior**

A cached company list can only answer questions about the account it was
fetched for.

**Steps to reproduce**

1. On a self-hosted instance in `authenticated` mode, sign in as account
A, which belongs to company X.
2. Within thirty seconds, have account B become the session in that tab
— a second tab signing in, or A's session lapsing server-side.
3. Any consumer reading the company list receives A's list, and nothing
in the query result indicates it is not B's.

**Paperclip version or commit**

`master` at `ac91b7f3b`, which includes #11430.

## What Changed

- `ui/src/lib/queryKeys.ts` — `companies.list(userId)` replaces
`companies.all` as the list's entry. `companies.all` remains the prefix,
so it still matches for invalidation.
- `ui/src/api/companies-query.ts` — `companyListQueryOptions(userId)`
builds the keyed options; `useCompanyListQuery()` is the only observer
entry point and holds until the session settles, because the key cannot
be built before then; `fetchCompanyListForCurrentAccount(queryClient)`
covers imperative paths; `useAccountIdentity()` exposes the session
identity the key is built from.
- `ui/src/api/companies-query.ts` — the `/companies` detach moved into
the query function.
- `ui/src/context/CompanyContext.tsx` — drops the session-watching
refetch machinery the key now makes unnecessary (`removeQueries`, the
explicit replacement fetch, the awaiting gate). It still clears the live
selection on an account change, because that is component state and does
not change key with the query.
- `ui/src/pages/InviteLanding.tsx`,
`ui/src/components/OnboardingWizard.tsx` — read through the
account-aware API.
- Tests — the account-keyed guarantee, prefix invalidation still
reaching the list, the detach inside the query function, and updates
where suites seeded the old shared key.

### The existing defenses are deliberately left in place

The per-consumer gates in #11382, #11417 and #11430 are now belt and
braces. They are also what will catch this refactor if it is wrong
somewhere, so removing them in the same change that moves the foundation
would be the wrong order. Simplifying them is a follow-up, once this has
proven itself.

### Why `retry: 1` appears in CompanyProvider

An earlier measurement on #11430 found a retry on the replacement fetch
changed no outcome, because `removeQueries` made the observer rebind and
issue a second request for free. Keying by account removes that
mechanism and the free attempt with it. The retry now carries the
property the incidental refetch used to — a single blip during an
account change should not leave the customer with no companies until
they find "Try again". #11430's test for that property is unchanged and
still passes, which is how the gap was caught.

### A regression this went through, kept for the record

Gating the query on the session settling meant that while the account
was unknown the query was *disabled*, and a disabled query reports
`isLoading: false` with no data — which the provider defaults to an
empty list and reads as "asked, and owns nothing". That is the
destructive branch #11477 had just fixed, reached through a different
door: it would have cleared the customer's stored company on every cold
boot. #11477's test caught it during the rebase. `useCompanyListQuery`
now reports the wait for the account as part of the wait for the list.

### What this does not do

It does not scope the rest of the per-account cache. `["companies",
id]`, stats, and every other account-scoped entry still survive an
account change; that is the cache-lifetime work in #11380.

## Verification

- `pnpm vitest run` in `ui`: **4018 passed, 1 failed**.
- `pnpm tsc -b` in `ui`: clean.
- `companies-query.test.ts`: 6 passed. `CompanyContext.test.tsx`: 17
passed. `OnboardingWizard.test.tsx`: 13 passed.
`InviteLanding.test.tsx`: 13 passed.

The failure is the pre-existing timezone-dependent
`IssueProperties.test.tsx`, fixed by #11478.

Two behaviours are asserted rather than assumed, because the refactor is
only safe if they hold: that invalidating the `companies` prefix still
marks the account-keyed list stale (19 call sites depend on it), and
that the query function detaches the in-flight `/companies` request
before fetching.

**Not done:** no manual two-account run in a browser. The path needs two
accounts on an `authenticated` instance, which a local dev instance
cannot exercise.

## Risks

Moderate, and worth reading before approving.

**It touches `InviteLanding.tsx`, which #11417 also modifies**, so one
of the two will need a rebase — the conflict is mechanical (both change
how the same query is read).

This was #11481, which GitHub closed automatically when its base branch
(#11430's) was deleted on merge; reopening a pull request whose base
branch is gone is not permitted, so it continues here against `master`
with the same head and the same review already recorded on #11481.

**The list now waits for the session query.** The key cannot be built
before the account is known. In the app the session is already fetched
at boot by many components, so this is a dependency rather than an extra
request, but it does serialize: on a cold boot the list waits for the
session to land. Every test that renders a company-list consumer now
needs a session in the cache, which is why several suites gained a seed.

**A missing mock surfaces as a passing gate rather than an error.** The
detach inside the query function meant suites whose `companiesApi` mock
lacked `detachInflightList` had their query function throw, which read
as "decided" in the onboarding gate and mounted the wizard early. Fixed
in the affected suites; worth knowing as a failure mode.

## Model Used

Claude Opus 5 (`claude-opus-5`), through Claude Code. Extended thinking
enabled. Tool use enabled: file read and edit, shell for typecheck and
test runs.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] 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 <noreply@anthropic.com>
2026-08-16 21:23:56 -07:00
TonioandClaude Opus 5 38752c4e5e fix(ui): clear account-scoped query caches on sign-out (#11380)
Sign-out invalidated two query keys - the auth session and health - and left
everything else in the cache. `invalidateQueries` also keeps serving the old
data while it refetches, so it was insufficient even for the two it did touch.
The company list was never touched at all, which is how one account's
companies could still be in hand when the next account signed in.

The self-hosted path now resets every account-scoped entry. Scoping is an
allowlist of instance-scoped roots rather than a list of things to clear, so a
query key added later is account-scoped unless someone deliberately says
otherwise - forgetting this file fails closed.

`health` is the only exemption. It carries deployment mode, bootstrap state
and Cloud metadata, nothing account-scoped, and `useCloudInstance` observes it
with `enabled: false` and leaves the fetch to CloudAccessGate. Dropping the
entry would strand every such observer on `null` until the gate happened to
refetch, flipping Cloud instances into their self-hosted rendering mid
sign-out. It is refreshed in place instead.

`resetQueries` rather than `removeQueries`: removal empties the cache without
notifying the observers already subscribed, so a mounted `useQuery` keeps
returning its last result until an unrelated re-render rebuilds it.
CompanyProvider sits above the router and stays mounted across the whole
sign-out and sign-in cycle, so that is the common case here rather than a
corner one. Reset notifies them, so the old data leaves the cache and
everything reading it.

The cloud path is untouched: it is a top-level navigation, and the document
reload builds a new QueryClient with nothing left to clear.

This is the root cause behind the onboarding draft-ownership gate added in
#11382. That gate stays, and its comment now says why: this fix covers the
sign-out button, not the question. An account can change without it - a
session lapsing server-side, a second account signing in on a warm tab, a
caller supplying the company context from somewhere else - so the gate stays
independent rather than deferring to this.

ui typecheck clean; full ui suite 4014 pass, with only the timezone-dependent
IssueProperties failure already present on master.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 07:55:14 -07:00
6542ad1f4d fix(onboarding): carry an existing company's mission into the wizard (#11416)
Ports the substance of #11259, which predated the recent onboarding work and
was still open. One of the parts it solves is a regression #11352 introduced.

A company that already has its mission opens on the agent step, which is the
point of #11352. What that missed is that the mission field is filled only by
the step being skipped, and that the field is not decoration:
`composeCeoInstructions` seeds the lead agent's instructions from it, and the
Review checklist reads it. So every Cloud-seeded company hired its lead agent
with no Mission line at all, having been routed there precisely *because* it
had a mission. Before #11352 those companies dead-ended on the mission step; a
dead end became a quiet data loss, which is worse, because it completes.

`selectExistingCompanyMission` reads the company's own goal back into the shape
the mission field holds, and the wizard hydrates from it - only when the field
is empty, so a customer editing their mission is never overwritten by the
stored copy. The marker recording that hydration travels with the field it
describes, cleared wherever `companyGoal` is.

`isExistingCompanyMissionUnresolved` holds the hire while that read is
outstanding, counting an in-flight refetch over cached goals as unresolved.
That is the rule #11382 settled on a day earlier for a different consumer -
`isFetching`, not `isLoading`, because retained data is not an answer to the
question being asked now. #11259 had it first, on 11 August.

`canGoBackFromOnboardingStep` and `canJumpToOnboardingStep` bound how far back
a run can walk by the step it entered on. The Back button already applied that
rule inline; the progress bar applied only the "already completed" half, so a
run holding a company could still jump to step 1 - the step whose job is to
create one. The entry step is captured once, when the wizard opens, for the
same reason the step itself is.

`planMissionPersistence` came with them and turned out to be required rather
than tidying. Hydration sets `createdCompanyGoalId` from the company's existing
goal, and confirming the mission read that id as "already written" and skipped
the write, discarding the customer's edit. That skip was safe only while the id
could arrive one way - by writing. A goal in hand now means update it.

Each piece was checked by removing it and confirming a specific case fails.
The hydration case asserts on `saveInstructionsFile`'s content, the actual
consumer, rather than on the mission textarea, because the entry path never
renders that field and the navigation bound now prevents reaching it. One
caveat recorded rather than smoothed over: the reopen case fails only when
both marker-clears are removed, since `reset()` also clears the company id and
the next introduction routes through `clearCompanyScopedState`. They are kept
as one invariant rather than one guard plus a coincidence.

ui typecheck clean; full ui suite 4004 pass. Two failures remain, in
IssueProperties and StatusCards/format; both are date-dependent, both
reproduce on master with these changes stashed, and neither file is touched
here.

Co-Authored-By: Jannes Stubbemann <stubbi@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 01:42:03 -07:00
TonioandClaude Opus 5 484b1f626c fix(onboarding): verify draft ownership against a list fetched this session (#11382)
#11370 stopped onboarding restoring a saved draft when the company list had
*errored*. It still trusted the list when the list looked healthy — and the
wider door was exactly that. `main.tsx` sets `staleTime: 30_000` app-wide and
`Auth.tsx` invalidates rather than resets on sign-in, so `invalidateQueries`
keeps serving the previous account's companies with `isLoading` false and no
error at all. On a self-hosted instance, where sign-out does not reload the
page, signing in as a second account in the same warm tab could restore the
first account's draft. No request had to fail.

The wizard now judges ownership against a list it fetched for the current
session: its own `useQuery` on the shared key with `staleTime: 0`, gated so it
runs only when a parseable draft exists and adds no request otherwise.

Every clause of that gate earns its place, and each was verified by removing
it and watching a specific case fail:

- `isSuccess` ties the answer to this session. React Query retains the last
  good `data` when a refetch fails, so after an account switch the retained
  value is the previous account's list; a failed refetch flips status to error
  and this rejects it.
- The `unauthorized` check catches the opposite error. `companiesListQueryOptions`
  folds 401 and 403 into `{ companies: [], unauthorized: true }` rather than
  throwing, so an auth blip arrives as a *successful* empty list and would
  otherwise read as "this account owns nothing" and delete the draft.
- The mount gate keys on `isFetching`, not `isLoading`. `isLoading` is false
  whenever retained data exists, so a refetch over a warm cache mounted the
  wizard undecided — and with the wizard open, the persist effect overwrote
  the customer's own draft with defaults before the answer arrived. It still
  releases on failure, so the "Get Started" dead end stays fixed.
- An unreadable draft is judged, and cleared, before any of the above, and
  does not enable the query at all.

`isFetchedAfterMount` was in an earlier revision and is deliberately not here:
it is true after a failed refetch too, so it rejects nothing `isSuccess` has
not, and no test could distinguish it.

Worth recording how the first defect survived a check. I fault-injected it,
saw a test fail, and concluded the guard worked. It was failing for an
unrelated reason — the inner wizard mounted during the fetch and locked its
state initializers to defaults, so the draft could not appear whatever the
gate decided. Fixing the mount gate exposed the real behaviour. An injection
is only evidence if the failure it produces is the one being claimed.

This narrows onboarding only. The general fault is that a sign-out leaves
account-scoped caches in place, and account changes that skip the button —
a session lapsing server-side, a second account in a warm tab — reach the same
stale list. Tracked separately; this defence should not be removed as
redundant when that lands.

ui typecheck clean; full ui suite 3963 pass, with only the timezone-dependent
IssueProperties failure already present on master.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 22:59:41 -07:00
TonioandClaude Opus 5 35a9b98733 fix(ui): theme the onboarding wizard decorative panel instead of hardcoding dark (#11379)
The onboarding wizard's decorative right-hand panel, which holds the ASCII
paperclip illustration, hardcoded a near-black surface. `ThemeContext`
supports light and dark and follows `prefers-color-scheme`, so in light mode
a new customer met the product as a pale form beside a solid black rectangle
— on the one screen meant to introduce it. The glyphs inside already used
`text-muted-foreground`, so the panel was the only part ignoring the theme.

It now uses the paired `bg-muted` surface, which is defined in both themes
(`oklch(0.97 0 0)` light, `oklch(0.269 0 0)` dark), so the illustration reads
as ink on a surface either way and follows any future theme without another
fix.

The guard for it asserts the complete set of `bg-` classes on the panel is
`["bg-muted"]`, anchored to the `<AsciiArtAnimation />` wrapper rather than
scanning the file. Forbidding specific spellings is what failed here
originally: the first version checked `bg-[#rrggbb]` and silently stopped
guarding anything once master migrated the class to `bg-(--hex-1d1d1d)`.
Naming what is allowed cannot decay that way, and it catches named colours
like `bg-black` that no spelling list covered.

Lands the work from #8982 by @stubbi, whose two commits are included
unchanged with their authorship. The rebase and the guard are mine.

Tested: ui typecheck clean; both theme cases fail against four spellings of
the regression — `bg-(--hex-1d1d1d)`, `bg-[#1d1d1d]`, `bg-black`,
`bg-zinc-900` — where the original caught only one and my first widening
caught two. Full ui suite 3958 pass, with one timezone-dependent
IssueProperties failure present on master. All CI gates green; Greptile 5/5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 12:06:20 -07:00
TonioandClaude Opus 5 66515582e4 fix(onboarding): do not restore wizard state for a company the user does not own (#11370)
Onboarding persists a draft to `localStorage`, including `createdCompanyId`.
That key is scoped per browser origin, not per account, so a browser that has
already run onboarding hands the stored company id to the next session on the
same origin — whoever is signed in. Every downstream call then targets a
company that account may not own: goals, agents and issues are created there,
and requests fail with authorization errors.

`restoreOnboardingState` now returns a saved draft only when the signed-in
account owns the company it names. Otherwise the draft is discarded and the
stale blob removed.

The wizard splits into a gate and an inner component because the inner one
has ~20 `useState(saved?.x ?? default)` initializers, and an initializer runs
only on the first render. Mounting before the restored draft is final locks
every field to its default with no way back, so the gate waits for the
company list while it is loading.

Ownership is judged only against a list that actually answered. Any company
query error makes it undecidable, whatever the list contains — the companies
cache is not account-scoped and survives sign-out, so a failed refetch after
an account switch can leave the previous account's companies in hand, and
trusting a non-empty list there would hand one account's draft to the next.
Nothing is restored and nothing is deleted in that state; the next successful
load decides.

Judging the draft and mounting the wizard are separate questions. The gate
withholds the wizard only while the list is *loading*, never on error: the
companies query sets `retry: false`, and with no companies the dashboard
offers a "Get Started" button wired to onboarding, so blocking there would
make that button do nothing at all. Mounting costs the draft nothing, because
the persist effect is itself gated on the wizard being open.

All four draft-storage call sites — read, write, cleanup, reset — go through
one guarded helper. Storage access throws outright where a browser denies it,
and each site sits in a render, an effect or a close handler, so an escaping
exception took down something the customer was using.

Lands the work from #9900 by @stubbi, whose two commits are included
unchanged with their authorship. The rebase, the error-path handling and the
storage guards are mine.

Follow-up filed separately: sign-out should remove account-scoped cached data
rather than invalidating two keys. This change is defensive and protects
onboarding only.

Tested: ui typecheck clean; 73 pass across the seven onboarding suites; full
ui suite 3952 pass, with one timezone-dependent IssueProperties failure
present on master in a file this does not touch. All CI gates green;
Greptile 5/5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 11:08:48 -07:00
TonioandClaude Opus 5 bc0b5a1642 fix(ui): onboarding wizard keeps an invisible disabled adapter selected (#11371)
The wizard defaults `adapterType` to `claude_local`, and a saved draft can
name any adapter. The grid only renders adapters the server has enabled, so
on an instance where the held adapter is disabled nothing appears selected
while the wizard still holds it — and the first agent is hired on an adapter
the deployer turned off, which can never acquire a lease.

The selection now snaps to the first enabled, non-coming-soon adapter
whenever the held one is not visible, and adapter-specific model defaults
follow it.

The snap waits for the adapter registry to load. External adapter types are
registered into the UI registry only once the adapters query resolves, so
before that a saved external adapter is indistinguishable from a disabled
one — snapping on that transient list would replace the customer's choice
with a built-in and the persist effect would write it down. This gate fails
closed, unlike the fail-open gates in onboarding, because the directions of
harm are opposite: acting early silently rewrites a saved answer, while
waiting merely leaves the selection alone, which is the behaviour that
existed before the snap did.

The test file is named `OnboardingWizard.adapters.test.tsx` rather than
`OnboardingWizard.test.tsx`, which is the name #11370 uses for its restore
gate. Both merged cleanly onto master alone but collided with each other on
add/add, and nothing in either status showed it.

Lands the work from #9900's sibling, #9501, by @stubbi, whose commit is
included unchanged with their authorship. The rename and the registry gate
are mine.

Tested: ui typecheck clean; 51 pass across the adapter, hook, dialog,
config-form and wizard-step suites, including the other callers of the
adapter hook since that module changed. All CI gates green; Greptile 5/5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 10:27:59 -07:00
TonioandClaude Opus 5 d95340b0b8 feat(ui): send a company with no agent into onboarding, at the right step (#11352)
A company with no agent cannot do anything: no runs, no tasks, nothing to
show. The dashboard says so in a banner with a link, which asks the customer
to notice a problem the product can fix for them. It is worse for a company
created by Paperclip Cloud: Cloud creates the company before the tenant
boots, so the companyless redirect never runs, and the customer arrives on an
empty dashboard straight out of a signup flow that already asked for a
mission.

The dashboard now opens onboarding when the agent list has loaded and is
empty, and onboarding opens on the agent step when the company already has
its mission — read from the company-level goal the seed writes, under the
query key the launch path already uses, so it shares a cache entry rather
than adding a fetch.

The step is decided once. `initialStep` is derived from the company list and
the goal list, so it changes on any retry, refetch or cache invalidation. An
effect that took it as a dependency called `setStep` on every one of those
and moved a customer who was already mid-flow. Gating the input only narrowed
that window; it could not close it. The step now belongs to the request that
opened the wizard: the effect reads it through a ref and is keyed on the
wizard opening or the company changing. `createdCompanyIdRef` beside it
already used this pattern for the same reason.

That exposed a path nothing had ever taken. A company reached the mission
step only by creating itself on step 1, so opening an existing company there
found code that had never run: `companyName` is only typed on step 1, and
both ways forward require it, so the step could not be completed at all; and
confirming advanced without writing anything, so the mission the customer
typed was discarded. Both fixed, and the write now reconciles against the
goal list rather than adding a second company goal, since the mission lookup
fails open and can send a company that has one back to that step.

Company-scoped state now stays with its company. `clearCompanyScopedState`
runs when the route replaces a company and when it withdraws one — the same
event, and clearing half of it left a goal id that made the next company skip
a mission it had never given. `stillTheSameCompany` guards all five async
writes, after the server work rather than before it, so a company switch
mid-flight cannot hand the new company the old one's goal, project, issue or
agent, and cannot leave a hired agent without its instructions file. The
keyboard path honours `loading` like every button already did.
`claimOnboardingOffer` makes onboarding an offer that stays declined for the
visit.

Route ownership is now recorded whenever the route names a company, including
one the wizard already holds. This changes a documented rule deliberately:
without it a self-created company was never withdrawn, so `/onboarding` would
show "create a company" while still holding the previous one and write the
customer's new mission into it.

Tested at the seam, because every defect on this branch lived between a value
and its consumer and the predicate tests passed at every stage.
`OnboardingWizard.step.test.tsx` renders the real wizard against the real
resolver and the real mission hook across 18 cases, and each was
fault-injected against the code it replaces rather than trusted on a green
run. That caught a case that passed against the broken code, and a race in
one of the guards.

ui typecheck clean; full ui suite 3923 pass, with one timezone-dependent
IssueProperties failure present on this branch's base in a file this change
does not touch. All CI gates green; Greptile 5/5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 08:18:07 -07:00
aac6ce82e1 fix(ui): read the onboarding company prefix from the path, not the route match (#11351)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - New users meet the product through an onboarding wizard that creates
their company, their first agent, and a starter task
> - The wizard also serves an existing company, at
`/{PREFIX}/onboarding`, to add another agent to it
> - On that route the wizard ignores the company in the URL and opens at
"create a company" instead
> - It reads the prefix with `useParams()`, but it renders beside
`<Routes>` rather than inside it, so there is no route match to read
> - This pull request reads the prefix from the pathname, which is
available without a match
> - The benefit is that the URL a user follows decides what the wizard
asks them

## Linked Issues or Issue Description

No public issue exists for this. The problem follows.

**What happened?**

Open `/{PREFIX}/onboarding` for a company that already exists. The
wizard opens at step 1 and asks the user to create a company. The
company named in the URL is ignored.

**Expected behavior**

The wizard recognises the company in the URL and opens at step 2, so the
user adds an agent to that company instead of creating a second one.

**Steps to reproduce**

1. Create a company, so it has an issue prefix.
2. Go to `/{PREFIX}/onboarding`.
3. Read the first screen. It asks for a company name.

**Paperclip version or commit**

`master` at `5ca7b4c1f`.

**Deployment mode**

Any. This is client-side routing and does not depend on the server.

## What Changed

- `ui/src/lib/onboarding-route.ts` — adds
`companyPrefixFromOnboardingPath()`, which reads the prefix from the
pathname.
- `ui/src/components/OnboardingWizard.tsx` — uses that value when the
route match supplies none. One line, plus the import.
- `ui/src/lib/onboarding-route.test.ts` — six cases for the new
function.

`OnboardingWizard` renders beside `<Routes>` in `App.tsx`, so
`useParams()` returns nothing and `companyPrefix` was always
`undefined`. `resolveRouteOnboardingOptions` then took its no-prefix
branch every time. `useLocation()` needs only the router, not a match,
and the wizard already calls it.

The route match is still read first. If the wizard later moves inside
the route tree, this code does not need to change.

The new parser accepts the same shape as `isOnboardingPath()`: the
prefix is the first of exactly two segments. One test asserts the two
agree, because a disagreement would either open the wizard where no
company resolves, or resolve a company where onboarding is not served.

### Why the change is this small

Three pull requests are open against `OnboardingWizard.tsx` — #9900,
#9501 and #8982. A larger change there would collide with all three.
Almost all of this lands in `onboarding-route.ts`, a small file of pure
functions with existing tests.

## Verification

- `npx tsc --noEmit -p ui/tsconfig.json` — clean.
- `npx vitest run ui/src/lib/onboarding-route.test.ts` — 18 pass.
- `npx vitest run ui/src` — 3883 pass, 445 files.

One test shows the defect and the fix together. With `companyPrefix:
undefined`, which is what the wizard supplied before,
`resolveRouteOnboardingOptions` returns `{ initialStep: 1 }`. With the
parsed prefix it returns `{ initialStep: 2, companyId: "c1" }`.

**Pre-existing failures, unrelated:** `IssueProperties.test.tsx` and
`StatusCards/format.test.ts` fail on clean `origin/master` with these
changes stashed. Both look date-dependent.

**Not done:** no manual browser check. The behaviour is covered by unit
tests at the function boundary, and the wizard's own suite passes.

## Risks

Low. The route match is still preferred, so behaviour changes only where
`useParams()` gave nothing — which today is every render of this
component.

The parser returns a prefix only for a two-segment path ending in
`onboarding`, so no other route can start matching. An unknown prefix
already falls back to step 1 in `resolveRouteOnboardingOptions`, and
that path is unchanged.

To revert, remove the fallback in the wizard. The new function has no
other caller.

## Model Used

Claude Opus 5 (`claude-opus-5`), through Claude Code. Extended thinking
enabled. Tool use enabled: file read and edit, shell command execution
for typecheck and the test runs, and the GitHub CLI.

## 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
- [ ] 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: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-13 21:45:39 -07:00
scotttong 815e49bb7c feat: make chat-style tasks the default experience (#11101) 2026-08-11 09:06:21 -07:00
TonioandPaperclip 384e5f6178 revert(ui): back out onboarding port (#10786) (#11067)
This reverts commit 11e56654f8.

#10786 ported the onboarding flow from a standalone prototype and
repointed `/onboarding` at the new `CloudOnboardingFlow`, deleting the
existing `OnboardingWizard.tsx` in the process. The ported flow is not
ready to be the shipping onboarding experience: it landed as a single
large port rather than an incremental migration, it pulled `motion`,
`three` and `@types/three` onto the UI dependency list for prototype
visuals, and it deleted the wizard that four in-flight pull requests
(#9900, #9501, #8982 and one more) were building on — those went
CONFLICTING the moment the file disappeared.

Rather than keep the half-migrated state on master while that is sorted
out, back the port out whole and re-land it incrementally. This restores
`OnboardingWizard.tsx` and the previous versions of the four e2e specs,
drops the `onboarding-preview.html` Vite entry, the DesignGuide
onboarding section and the `data-viz-misc` storybook story, and removes
the three prototype dependencies from `ui/package.json`.

This is an exact mechanical inverse of the squash commit — 41 files,
+2089/-3647, no hand edits. Reverting this commit restores all 41 files
byte for byte, so the port is recoverable in full when it is ready.

`pnpm-lock.yaml` is deliberately not touched. #10786 never updated it;
bot commit 4683f26c9 (#11036) added the `motion`/`three` entries
afterwards, so the lockfile is now ahead of the manifest. CI owns
lockfile updates (`.github/workflows/pr.yml`) and the policy job
regenerates it from the changed manifest.

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-07 14:55:34 -07:00
TonioandClaude Opus 5 11e56654f8 feat(ui): port onboarding flow from prototype; add cloud + local variants (#10786)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - First-run onboarding is the subsystem that turns a brand-new install
into a working company: it creates the company, its goal, a lead agent,
and that agent's first task
> - The existing `OnboardingWizard` carried all of that wiring
correctly, but its UI had drifted from the current design direction, and
a separate design prototype (`paperclip-onboard`) existed as a
standalone visual mock with no backend
> - Porting the prototype's *logic* would have thrown away working,
well-tested backend orchestration; leaving the two apart meant the
design never shipped
> - Separately, cloud and local (self-hosted) installs need meaningfully
different first runs — local has no sign-in and must let the user pick a
locally-installed CLI adapter — so a single linear wizard could not
serve both
> - This pull request rebuilds the presentational layer from the
prototype on top of the existing backend orchestration, and splits it
into two thin flow containers over a shared core
> - The benefit is that the shipped onboarding matches the intended
design, cloud and local can diverge without duplicating logic, and each
can later ship to a different app version while sharing one set of step
components

## Linked Issues or Issue Description

No existing issue — describing inline (feature request).

**What problem does this solve?**
Onboarding is the first thing a new user sees, and the shipped wizard
had drifted from the current design. In parallel, cloud and local
installs need different first-run paths: local has no hosted sign-in,
and its agent runs on a CLI adapter installed on the user's machine,
which the cloud path never has to ask about. There was no way to express
that difference without either forking the whole wizard or bolting
conditionals onto a single linear flow.

**Proposed solution**
Extract the onboarding step views and shell into a shared core, then
compose two thin flow containers (cloud and local) over it. Keep all
backend orchestration in the existing `useOnboardingFlow` hook so no
working logic is rewritten.

**Alternatives considered**
- *Single flow with a `variant` prop* — most DRY, but the two flows are
intended to ship on different app versions, and a shared file would have
to be split later anyway.
- *Two fully independent copies* — simplest per-flow, but every shared
refinement (spacing, motion, copy) would have to be made twice and would
drift.

## What Changed

- **Shared core** under `ui/src/components/onboarding/`:
`OnboardingScaffold` owns the full-screen shell and the single
`AnimatePresence` step crossfade, so both flows transition identically;
step views (Start / Company / Agent / Task), `FooterNav`, `AgentPreview`
and the motion constants are extracted for reuse.
- **`CloudOnboardingFlow`** — `start → company → agent → task`; mounted
in the real app via `OnboardingWizardVariant`. Behaviour matches the
retired wizard, including `previewMock` and the existing-company ("add
an agent") entry point.
- **`LocalOnboardingFlow`** — skips sign-in and adds an optional email
ask (with a privacy assurance), a local model/adapter step that hires
with `requireEnvProbe: true`, and a "star us on GitHub" interstitial
before completing. **Harness-only for now** — the real app still mounts
the cloud flow.
- **Deleted `OnboardingWizard.tsx`** (1,786 lines); updated its
Storybook stories and the `OnboardingWizardVariant` test to the new
components.
- **Orbiting 3D paperclip backdrop** behind the auth and welcome screens
(`three`), code-split so it only downloads on those screens; honours
`prefers-reduced-motion` and disposes its GL context on unmount.
- **`motion`** added for step transitions and the agent-capsule
choreography.
- Visual values routed through design tokens per `DESIGN.md`; `Stepper`
generalized to take a step total (backward compatible); `/design-guide`
page and the component index updated.
- **Standalone preview harness** (`ui/onboarding-preview.html`) with
`?flow=` and `?step=` for backend-free review, wired as a second Vite
rollup input.
- **Adapter env probe bound to the adapter it ran against.**
`hireLeadAgent` reused `adapterEnvResult` for any adapter, so when a
hire failed and the user picked a *different* local adapter and retried,
the previous adapter's verdict satisfied the `requireEnvProbe` guard
while the hire posted the new adapter's config — hiring it unprobed. The
cache is now keyed on the adapter type plus the exact config posted to
the test endpoint, the config is built once and shared by probe and
hire, a failed probe clears the cache, and `clearAdapterEnvResult()`
(called on adapter change) stops the step displaying a stale verdict.
Cloud is unaffected — it hires with `requireEnvProbe: false`. Reported
by Greptile.
- **E2E specs re-pointed at the new flow.** Four specs still drove the
deleted wizard (`onboarding`, `conference-room-typing-intro`,
`planning-mode-visual-verification`, `nux-phase4-screenshots`) and
failed with `element(s) not found` on `"Name your company"` /
`input[placeholder="Acme Corp"]`. Rather than repeat the new drive
sequence four times, `tests/e2e/onboarding-flow.ts` adds one driver per
step (`startCloudOnboarding`, `completeCompanyStep`,
`completeAgentStep`, `completeTaskStep`, `completeCloudOnboarding`) and
the specs import it, so the next flow change touches a single file. Two
now-dead `**/test-environment` route stubs went with it — the cloud flow
hires with `requireEnvProbe: false`, so that probe never fires.

## Verification

- `pnpm --filter @paperclipai/ui typecheck` — clean.
- `npx vitest run` over the onboarding suites
(`OnboardingWizardVariant`, `AgentCapsule`, `onboarding-launch`,
`onboarding-goal`, `onboarding-route`, `onboarding-adapter-config`) — 33
tests pass.
- `pnpm --filter @paperclipai/ui build` — succeeds; the three.js chunk
splits out separately (522 kB raw / 133 kB gzip) rather than entering
the main bundle.
- Both flows driven end-to-end in the preview harness in `previewMock`
(no database writes), plus the cloud flow rendered in the real
authenticated app at `/onboarding` to confirm the mount swap.
- The four re-pointed e2e specs pass locally against the new flow.
- New `ui/src/hooks/useOnboardingFlow.test.tsx` — 4 cases pinning the
adapter-probe cache (switch-adapter retry, cold path, explicit clear,
and the cloud flow's `requireEnvProbe: false`). Verified non-vacuous:
the switch-adapter case fails against the pre-fix code.
- Rebased onto current `master`; `pnpm-lock.yaml` is deliberately
**not** committed — `.github/workflows/pr.yml` regenerates it when a
manifest changes and shares it with downstream jobs as the `pr-lockfile`
artifact.

## Risks

- **Deleting `OnboardingWizard.tsx` is the one change that alters
existing app behaviour.** The cloud flow is intended to be
behaviour-equivalent, and its entry points are covered by the updated
`OnboardingWizardVariant` test, but this is the area to review most
closely.
- **Conflict risk with open PRs that touch the old wizard**: #9900,
#9501, #8982 and #6636 all modify
`ui/src/components/OnboardingWizard.tsx`, which this PR removes.
Whichever lands second will need its change re-applied to the new step
components. Flagging so ordering can be decided deliberately.
- **New dependencies**: `motion` and `three` (+ `@types/three`). `three`
is large, so it is lazily imported and code-split — it does not affect
the main bundle. Both are MIT.
- The **local flow is not reachable in the app** yet (harness/canary
only), so it carries no runtime risk today; wiring it up is a follow-up.
- The auth screens remain **presentational only** — they are not wired
to real auth, unchanged from before this PR.
- **Pre-existing, not introduced here:** `OnboardingWizardVariant`
renders outside `<Routes>` in `App.tsx`, so its `useParams()` never
resolves `:companyPrefix` and `/{prefix}/onboarding` opens the welcome
screen instead of jumping to the agent step. `master` has the identical
structure, so this PR faithfully ports existing behaviour; the working
"add an agent" entry is the launcher card behind the overlay, which is
what the screenshot spec drives. Worth a separate fix.

## Model Used

Claude Opus 5 (`claude-opus-5`) via Claude Code, with extended thinking
and tool use (repo search/edit, local test + build execution, and
browser-driven visual verification of the rendered flows). Portions of
the session also ran on `claude-opus-4-8` and `claude-fable-5`.

## Checklist

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

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

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 23:35:05 -07:00
DottaandPaperclip a116713b9a feat(mcp) [split 6/8]: add Tools and Profiles UI foundation (#9561)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Governed MCP access spans contracts, runtime enforcement, adapters,
UI surfaces, and operator verification
> - The parity reference PR #9534 is too large for effective automated
or human review
> - The feature therefore needs a linear stack whose individual diffs
stay below the 100-file review limit
> - This pull request is split 6/8 and focuses on UI API, shared
components, and Tools/Profile surfaces
> - The benefit is a standalone, testable review boundary while
preserving byte-for-byte parity at the top of the stack

## Linked Issues or Issue Description

- Related parity reference: #9534
- Problem: Operators need typed clients and administration surfaces that
compile independently before navigation exposes them.
- Proposed solution: Adds UI APIs, hooks, libraries, shared components,
Tools/Profiles pages, and the plugin settings consumer required by the
new company-scoped API.
- Alternatives considered: keeping #9534 as one 403-file review, or
rewriting the feature to manufacture seams; both were rejected in favor
of path extraction plus compile-driven boundary moves.
- Roadmap alignment: this advances the existing governed MCP/tool-access
work already represented by #9534; it does not introduce a separate
roadmap initiative.
- Stack position: base branch is
`pap10341-split/05-runtime-integration`.
- Merge policy: merge bottom-up, in order, only after the complete
eight-PR stack has been reviewed and the top-of-stack parity gate
remains empty.
- Requested review: UXDesigner sanity pass on Tools/Profile surfaces;
Greptile on every PR.

## What Changed

- Adds UI APIs, hooks, libraries, shared components, Tools/Profiles
pages, and the plugin settings consumer required by the new
company-scoped API.
- Keeps this PR below 100 changed files and independently typecheckable.
- Preserves the final tree from #9534 when combined with the other seven
stack levels.

## Verification

- `pnpm typecheck`
- `pnpm check:token-gates` — all gates clean
- Focused UI Vitest run with `NODE_ENV=test` — 28 files, 183 tests
passed

## Risks

- Large dead-code UI additions can drift from activation routes; PR 7
supplies the registration layer and top-level parity catches omissions.
- Stack risk: merging out of order can expose incomplete layers;
mitigate by following the documented bottom-up merge policy.
- Parity risk: later edits to an intermediate branch can drift from
#9534; mitigate by re-running the empty top-of-stack diff before merge.

> 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

- OpenAI Codex, exact model ID `gpt-5.4`; runtime-managed context
window; medium reasoning with repository, shell, Git, GitHub CLI, and
code-execution tools enabled.

## 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] Internal references are omitted except the execution-plan link
explicitly required for this coordinated split stack
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] 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


## Stack Coordination

- Internal execution plan:
[PAP-13874](/PAP/issues/PAP-13874#document-plan)
- Parity reference: #9534
- Stack: #9556 → #9557 → #9558 → #9559 → #9560 → #9561 → #9562 → #9563
- Merge bottom-up only after full-stack review and an empty parity diff
at #9563.


## UI Evidence

QA captured these from the live Garden MCP split stack at 1440px and
verified clean rendering:

![Profiles
index](https://raw.githubusercontent.com/paperclipai/paperclip/ac72de3ec85feb14c5ec1ed0a3d39b29baa0abff/doc/screenshots/garden-mcp-split-stack/profiles-index.png)

![Profile
wizard](https://raw.githubusercontent.com/paperclipai/paperclip/ac72de3ec85feb14c5ec1ed0a3d39b29baa0abff/doc/screenshots/garden-mcp-split-stack/profile-wizard.png)


![Policies](https://raw.githubusercontent.com/paperclipai/paperclip/ac72de3ec85feb14c5ec1ed0a3d39b29baa0abff/doc/screenshots/garden-mcp-split-stack/policies.png)

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-14 15:31:12 -05:00