Commit Graph
2006 Commits
Author SHA1 Message Date
Dotta bc1220336d feat(runner): add experimental two-way OpenAI Dot provider 2026-10-03 00:32:25 -05:00
Dotta cd4739aa9c Prototype two-way Dot runner bridge over MCP Events 2026-10-02 15:17:00 -05:00
Dotta 45d17c4b15 Merge commit 'a88448f77' into codex/dot-events-prototype
* commit 'a88448f77': (21 commits)
  Use canonical settings defaults in MCP stories
  Add assistant connection Storybook coverage
  docs: record experimental MCP settings evaluation evidence
  fix(mcp): preserve event retries when access is disabled
  feat(mcp): enable assistant connections through experimental settings
  fix(mcp): include events at the subscription start boundary
  fix(mcp): preserve nullable checkout responses in event logging
  docs: record paid MCP Events qualification and rollout limits
  fix(mcp): release inactive monitor quotas before admission
  fix(mcp): retain changes during callback verification
  test(mcp): cover event lifetime bounds and late activity commits
  feat(mcp): deliver task events to subscribed assistants
  Preserve mention icons with Lucide 1.45 and clarify local evidence paths
  Record paid qualification and direct connection rollout steps
  Keep completed connections outside pending OAuth quotas
  Close OAuth admission abuse paths and verify API and eval contracts
  Bound unauthenticated MCP registrations across replicas
  Keep OAuth callback credentials out of browser eval diagnostics
  Reconcile assistant MCP with current schema and runner contracts
  test(mcp): add paid assistant workflow evaluations
  ...

# Conflicts:
#	packages/paperclip-runner/docs/capability-contract.md
#	packages/paperclip-runner/generated/capability/capabilities.yaml
#	packages/paperclip-runner/generated/capability/capability-contract.md
#	packages/paperclip-runner/spec/capability/capabilities.yaml
#	server/package.json
2026-10-02 14:49:21 -05:00
DottaandPaperclip d034ba7491 fix(interactions): derive question storage from canonical forms (#14946)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents request human input through durable issue interactions.
> - A question form has a canonical presentation and a compatibility
storage format.
> - The creation API required agents to write both formats.
> - Tool guidance told agents to split text and choice questions across
those formats.
> - This pull request accepts one complete canonical form and derives
storage fields on the server.
> - The benefit is a complete question card with stable answer and retry
behavior.

## Linked Issues or Issue Description

Related work: Refs #13630 and #14430. PR #13630 addresses the display of
historical partial forms. This change fixes creation and keeps the check
that rejects conflicting new forms.

**What happened?**

A question save supplied three compatibility questions and one canonical
text question. The API correctly rejected the incomplete canonical form.
The Runner's tool description encouraged this split. Sending only a
complete canonical form also failed because the API required
compatibility questions.

**Expected behavior**

An agent sends one complete `payload.questionSet` with every text and
choice question. Paperclip derives `payload.questions` for storage and
answer compatibility. Existing legacy requests remain valid. Explicitly
conflicting dual forms remain invalid.

**Steps to reproduce**

1. Call `paperclip_request_human_input` with `interactionKind:
"questions"`.
2. Send `payload: { version: 1, questionSet: ... }` with a required text
question and a required choice question.
3. The old API rejects the missing compatibility questions. With this
change, it stores both questions and preserves the canonical form.
4. Retry with the same idempotency key. Confirm that only one
interaction exists.
5. Submit both answers. Confirm that the normal resolver and
continuation rules apply.

**Paperclip version or commit**

The branch is based on `cf8ad63c8`. The problem affects the native
Runner and the interaction creation API.

**Deployment mode**

Server deployment with the native Paperclip Runner. Integration tests
use the real interaction service and an embedded test database.

## What Changed

- Add one shared canonical-to-storage projection. Reuse it for native
harness question requests.
- Accept canonical-only question creation at the shared validator and
server boundary.
- Export the input type and update the plugin SDK and its RPC contract.
- Advertise a typed, complete question form in the live and scenario
tool schemas.
- Enforce canonical text and custom-answer constraints before ordinary
or native resolution. Preserve harmless display whitespace.
- Run regex matching in isolated workers with a deadline and resource
limits. Both answer paths await the result before persistence. Saved
native delivery uses the validated answer without taking another worker
slot.
- Update agent guidance and generated Runner contracts.
- Test mixed forms, option-ID collisions, retries, answers, legacy
requests, and conflicting forms.

## Verification

- Interaction service, HTTP route, native bridge, and Runner authority
suites: 221 tests passed after correcting an obsolete tool-description
assertion.
- Shared validator, plugin SDK, CLI, and UI compatibility suites: 67
tests passed.
- Runner core tool-contract suite: 20 tests passed. AJV validates live
and scenario schemas.
- Final review regressions: 172 shared, service, native bridge, and
authority tests passed. These cover text length, pattern, numeric
limits, whitespace, custom option IDs, and historical pending cards.
- Runner session suites: 67 tests passed. Published example tests: 4
tests passed.
- Server typecheck and the shared/server builds passed after the
compatibility fixes.
- Final delivery verification: 35 response-delivery tests passed. The
native delivery regression proves saved answers do not enter pattern
workers; server typecheck and build passed.
- Pattern security and answer-flow verification: 205 tests passed after
repairing the child fixture loader. These cover pathological matching,
event-loop responsiveness, worker concurrency, slot cleanup, HTTP
routes, native delivery, and the full helper in a child process.
- `pnpm -r typecheck` passed on the bounded-worker revision.
- `pnpm build` passed on the bounded-worker revision.
- All 55 GitHub checks passed on `fe457af`; four optional jobs were
skipped. An unchanged Cursor adapter test timed out once in CI, passed
locally, and passed on one failed-job rerun.
- Reviewers can send the canonical-only mixed form above and verify that
the saved interaction contains both canonical and compatibility
questions.

## Risks

- The creation API accepts a new input shape. Stored rows and answer
contracts keep the existing shape.
- The shared projection must preserve synthetic free-text option IDs.
Collision and native round-trip tests cover this behavior.
- Historical partial rows remain readable. New conflicting dual forms,
including written-answer mismatches, remain rejected.
- Existing pending cards retain the written-answer paths offered by
their stored options. Canonical text constraints still apply.
- Ordinary answers now enforce declared canonical constraints before
persistence. Invalid answers leave the card pending.
- Regex validation has a one-second deadline and a four-worker capacity
limit. A complex pattern or capacity error leaves the card pending with
a validation error.
- No database migration or change to company authorization is required.

## Model Used

- OpenAI GPT-6 through Codex. The session exposes the GPT-6 model
family; its exact runtime model identifier and context window size are
not exposed. 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 `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-02 14:21:11 -05:00
dependabot[bot] 8fd3cf74ea build(deps): bump @grpc/grpc-js from 1.14.4 to 1.14.5 (#14786)
Bumps [@grpc/grpc-js](https://github.com/grpc/grpc-node) from 1.14.4 to
1.14.5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/grpc/grpc-node/releases">@​grpc/grpc-js's
releases</a>.</em></p>
<blockquote>
<h2><code>@​grpc/grpc-js</code> 1.14.5</h2>
<ul>
<li>Fix a bug that caused clients to automatically transmit excessive
error details to clients by default (<a
href="https://github.com/grpc/grpc-node/security/advisories/GHSA-f596-whhp-79r4">advisory
GHSA-f596-whhp-79r4</a>)</li>
<li>Fix a bug that caused <code>getAuthContext</code> to return
unverified certificates as though they were verified in some
configurations (<a
href="https://github.com/grpc/grpc-node/security/advisories/GHSA-m9gg-hp2v-232j">advisory
GHSA-m9gg-hp2v-232j</a>)</li>
<li>Fix a bug that could cause stale call data to accumulate if a
channel failed to connect for a long period of time (<a
href="https://redirect.github.com/grpc/grpc-node/issues/3078">#3078</a>)</li>
<li>Fix a bug that could cause call status to be reported with expected
fields missing (<a
href="https://redirect.github.com/grpc/grpc-node/issues/3079">#3079</a>)</li>
<li>Avoid redundant end() calls on completed HTTP/2 streams (<a
href="https://redirect.github.com/grpc/grpc-node/issues/3082">#3082</a>
contributed by <a
href="https://github.com/olavloite"><code>@​olavloite</code></a>)</li>
<li>Unify call numbers and avoid disabled trace allocations (<a
href="https://redirect.github.com/grpc/grpc-node/issues/3084">#3084</a>
contributed by <a
href="https://github.com/olavloite"><code>@​olavloite</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/grpc/grpc-node/commit/56567d9604b4e45cdca0d2e3c2a60ac227ee659d"><code>56567d9</code></a>
Merge pull request <a
href="https://redirect.github.com/grpc/grpc-node/issues/3086">#3086</a>
from murgatroid99/grpc-js_1.14.5</li>
<li><a
href="https://github.com/grpc/grpc-node/commit/748ae86f7bb8af4a8d917d6fcf01c7a4c070f0a4"><code>748ae86</code></a>
Merge pull request <a
href="https://redirect.github.com/grpc/grpc-node/issues/3088">#3088</a>
from murgatroid99/grpc-js_perf_improvement_backport</li>
<li><a
href="https://github.com/grpc/grpc-node/commit/526702d8ed335a99960878aea19cf6748f6d2314"><code>526702d</code></a>
test(grpc-js): fix type errors in client stream lifecycle tests</li>
<li><a
href="https://github.com/grpc/grpc-node/commit/26a8d3d7d919098ded374b1c246d113161d69eb1"><code>26a8d3d</code></a>
fix(grpc-js): avoid redundant end() calls on completed HTTP/2
streams</li>
<li><a
href="https://github.com/grpc/grpc-node/commit/152eebdcd5bbb1548b7779d14e0f5046784c21c1"><code>152eebd</code></a>
chore(grpc-js): unify call numbers and avoid disabled trace
allocations</li>
<li><a
href="https://github.com/grpc/grpc-node/commit/c5ae75026d7f07d24ab1bbd76cb84d78ab3a4a8d"><code>c5ae750</code></a>
grpc-js(-xds): Increment version numbers (1.14.x)</li>
<li><a
href="https://github.com/grpc/grpc-node/commit/735a09a4f967400667fbbeda54584437e1bcf721"><code>735a09a</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/grpc/grpc-node/commit/af9b1401fbf72d7cbe8b569c8df45cb4d4905e24"><code>af9b140</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/grpc/grpc-node/commit/45ac33e74312ccd34cd7015147b36ef21b12b6c3"><code>45ac33e</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/grpc/grpc-node/commit/9df49e3ca3ea20f8626f62339d703d7284ed13e9"><code>9df49e3</code></a>
Merge pull request <a
href="https://redirect.github.com/grpc/grpc-node/issues/3081">#3081</a>
from murgatroid99/grpc-js-xds_weighted_target_fix_ba...</li>
<li>Additional commits viewable in <a
href="https://github.com/grpc/grpc-node/compare/@grpc/grpc-js@1.14.4...@grpc/grpc-js@1.14.5">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-02 12:19:48 -07:00
DottaandPaperclip 9786f6df56 fix(runner): preserve credential content in document saves (#14937)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Runner sends authorized tool calls to the control plane.
> - Agents use these calls to save plans and instruction files.
> - The Runner used diagnostic secret detection to reject execution
arguments.
> - Ordinary credential-related prose could reject a document save
before persistence.
> - This pull request forwards the original arguments and leaves
credential policy to the provider harness.
> - The benefit is reliable saves with useful diagnostic records.

## Linked Issues or Issue Description

Related foundation: Refs #12415 and #14430. No duplicate save-policy fix
was found.

**What happened?**

A `write_document` call failed before the server saved its plan. The
Runner reported `semantic tool input contains credential material;
refusing to execute altered arguments`. The detector also masked
ordinary phrases such as `secret manager` and `credential handling` in
diagnostics. Both TypeScript dispatchers had equivalent execution gates.
One dispatcher also rewrote structured approval and question payloads
before execution.

**Expected behavior**

Paperclip forwards authorized arguments unchanged. The provider harness
decides credential-content policy. Log and audit redaction does not
reject or rewrite save input.

**Steps to reproduce**

1. Send an authorized `write_document` call with a plan that discusses
credential handling.
2. Include an intentional credential value in the body to exercise
harness-owned policy.
3. The old Runner rejects the call. With this change, the document
service stores the exact body.
4. Diagnostic records still mask explicit credential values. Qualified
credential fields, short bearer values, opaque diagnostic pairs, and
valid encoded JSON token headers have regression coverage.

**Paperclip version or commit**

Reproduced at `c46e41e81c03cd3c8b64cf993615b604d7fe8c62`. The branch is
based on current `master`.

**Deployment mode**

Server deployment with the native Paperclip Runner. Local regression
tests use the real document service and an embedded test database.

## What Changed

- Remove credential-content vetoes from Rust admission and both
TypeScript semantic dispatchers.
- Preserve original structured approval and question arguments during
execution.
- Keep transport bounds, schema checks, authorization, idempotency, and
audit masking.
- Require explicit credential syntax or recognized formats for
diagnostic masking. Preserve ordinary prose, metadata, and dotted
identifiers.
- Test exact document persistence, replay, nested argument identities,
and masked audit copies.
- Remove obsolete retry guidance and document harness-owned credential
policy.

## Verification

- `cargo test --manifest-path
packages/paperclip-runner/runner/Cargo.toml --locked -p
paperclip-runner-core --lib --test acpx_event_payload --test
acpx_provider_state --test acpx_provider_turns`: 355 tests passed.
- Focused server and adapter tests: 189 tests passed after rebase. These
include the real document save and the complete tool-gateway suite.
- Semantic dispatcher and conformance tests: 34 tests passed.
- Diagnostic redaction and MCP tests: 46 tests passed, including all six
review examples.
- `pnpm -r typecheck` and `pnpm build` passed on the repaired branch.
- The broad local root suite was interrupted after database fixture
setup failures. The focused database suites passed. CI runs the complete
configured test lanes.

## Risks

- Authorized tool arguments can intentionally contain credentials. The
harness must enforce its content policy.
- Diagnostic detection is narrower. Explicit assignments, credential
fields, and recognized credential formats remain masked.
- The change does not add a database migration or change company
authorization.

## Model Used

- OpenAI GPT-6 through Codex. The session exposes the GPT-6 model
family; its exact runtime model identifier and context window size are
not exposed. 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 `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-02 14:19:41 -05:00
DottaandPaperclip 839cac1343 fix: request supported offline access for generic MCP OAuth (#14950)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents use external MCP tools through the governed gateway.
> - Remote MCP connections can use OAuth access tokens that expire.
> - Some providers issue refresh tokens only after an offline-access
request and consent.
> - Resource scopes hid that identity-provider capability in the generic
connection flow.
> - This pull request requests supported offline access and tests expiry
through a local MCP server.
> - The benefit is continued tool access without another sign-in when
the provider permits refresh.

## Linked Issues or Issue Description

Related PR: #13447 addresses the same OAuth symptom together with
managed Codex configuration. This PR focuses on generic MCP OAuth. It
also covers consent, explicit scope overrides, legacy reconnects, exact
scope persistence, and real HTTP expiry tests.

**What happened?**

A generic MCP resource can advertise only its tool scopes. Its OAuth
server can separately advertise `offline_access`. Paperclip selected the
resource scopes and omitted the offline-access request. A provider could
then issue an access token without a refresh token. Tool access stopped
after the access token expired.

**Expected behavior**

Paperclip adds advertised offline access to the selected tool scopes
when the OAuth server does not exclude refresh tokens. It requests
consent and stores the scopes sent in the authorization request.
Existing connections can discover this capability when the user
reconnects. Providers without this capability keep their existing scope
behavior.

**Steps to reproduce**

1. Run `node scripts/mcp-fixtures/servers/oauth-refresh-fixture.mjs`
from the repository root.
2. Add its MCP URL as a generic connection on a local Paperclip
instance.
3. Approve the test consent page and call `read_status`.
4. Let the two-minute access token expire and call the tool again.
5. Before this fix, the connection needs another sign-in. With this fix,
the call refreshes the token and succeeds.

**Paperclip version or commit**

The integration regression reproduced the missing-refresh-token failure
on the parent of this PR's fix. The same test passes with the fix.

**Deployment mode**

Local development. Automated tests use a loopback HTTP MCP/OAuth server
and a disposable PostgreSQL database.

## What Changed

- Track offline-access capability separately from MCP tool scopes.
- Add supported offline access and consent for generic connections.
- Preserve the actual requested scopes through callback completion and
reconnect.
- Discover the capability for older connections with cached OAuth
endpoints.
- Add a reusable MCP/OAuth fixture with PKCE, token expiry, resource
binding, and refresh-token rotation.
- Test shared and personal gateway calls through two refresh rotations.
Cover scope selection, unsupported refresh, and legacy reconnects.
- Document the behavior and local test commands.

## Verification

- The two real HTTP expiry tests failed before the fix with
`oauth_refresh_missing` after the first token expired.
- Tests passed on the current head: 76 generic MCP regressions, all 365
tool-access service tests, and 4 fixture controls.
- Full workspace `pnpm -r typecheck` and `pnpm build` passed. Server
TypeScript checks also passed after the review fixes.
- All remote checks passed on
`d22909bb34e9d54478c0002077c498ffe105932d`. Greptile gave 5/5 with both
previous findings resolved. The complete local `pnpm test:run` is still
running.
- Run `node --test
scripts/mcp-fixtures/servers/oauth-refresh-fixture.test.mjs` for the
standalone provider controls.
- Run `pnpm exec vitest run
server/src/__tests__/generic-mcp-connection.test.ts` for the Paperclip
integration tests.

## Risks

- Users can see a consent prompt when a generic provider supports
offline access.
- The provider can still decline to issue a refresh token. Access works
until expiry, then the user must reconnect.
- A provider that advertises offline access but rejects the scope
produces an OAuth error. This PR does not add an automatic retry without
that scope.
- Existing grants without refresh tokens need another sign-in. The fix
does not change them in place.
- Curated Apps keep their reviewed scope and authorization-parameter
allowlists. No database migration is required.
- This simulation verifies the suspected failure. The reported internal
MCP server has not been tested.

## Model Used

- OpenAI Codex, based on GPT-6, with reasoning, tool use, and code
execution. The runtime did not expose a more specific model ID or
context-window size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-02 14:13:59 -05:00
DottaandPaperclip 7a52dcdc74 fix: repair MCP validation and cancelled execution recovery (#14951)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The tool gateway gives agents access to connected services. Recovery
controls what happens when a run stops.
> - Generated tool names can exceed the provider limit after the MCP
client adds its prefix.
> - The same invalid definition can fail each automatic retry. A
cancelled run can also hold saved messages without showing its cause.
> - This pull request bounds tool names, stops configuration retries,
and retains cancellation evidence.
> - It shows the stopped run and admits saved input only after the
existing safety checks pass.
> - The benefit is a clear recovery path that preserves operator Stop
and prevents duplicate message delivery.

## Linked Issues or Issue Description

**What happened?**

A long connected MCP tool name makes the provider reject the entire
request. Automatic recovery repeats the invalid request. Separately,
unexpected legacy cancellations can leave saved input behind a recovery
hold. The notice does not identify the stopped run or its cause.

**Expected behavior**

Complete MCP names fit the provider limit. Tool-definition errors
require configuration repair. Cancelled runs retain their source and
reason. The recovery notice shows the cause and saved-message count.
Verified unexpected cancellations can start a fresh turn through the
existing admission checks.

**Steps to reproduce**

1. Assign an App gallery connection with a long application key and tool
name to a Claude agent.
2. Start a run. The provider rejects a name over 128 characters,
including its MCP prefix.
3. For cancellation recovery, stop a legacy provider turn without an
operator Stop request and send a user message while the recovery hold is
active.
4. Inspect the recovery notice and the deferred message queue.

**Paperclip version or commit**

Rebased onto master at `cf8ad63c806685bfd7c48e3ed4a919d61a7c55f1`.

**Deployment mode**

Hosted or self-hosted server with legacy Claude or Codex execution.

Related public work:

- Refs #14017. That PR caps name segments. This PR preserves existing
short names and uses stable hash aliases for long complete names. It
also covers classification and recovery.
- Refs #4510. That PR adds a cancellation-source column. This PR records
bounded evidence in the existing run result, without a migration.
- Refs #12552 and #4506. Those PRs suppress recovery after operator
cancellation. This PR preserves operator intent and uses the existing
continuation gates.

## What Changed

- Bound gateway names with the full provider prefix in the 128-character
budget. Retain the original upstream tool name for dispatch and
permissions.
- Classify invalid tool definitions as configuration failures before
diagnostic redaction. Stop automatic retries and continuation attempts
for that error code.
- Persist cancellation source, expectedness, initiator, reason, and
time. Preserve recorded Stop intent when adapter results arrive. Report
unexpected started cancellations with closed diagnostic labels.
- Show the run cause, saved-message count, and Inspect run link. Offer
Continue for eligible unexpected cancellations. Require verified
provider stop, empty tool inventory, ownership, and the existing pause,
budget, approval, and dependency gates. Use the existing queue for
single delivery.
- Add regression coverage and update the execution, MCP gateway, and
run-log documentation.

## Verification

- `pnpm -r typecheck` and `pnpm build` passed.
- `pnpm check:token-gates` passed.
- Ran `pnpm test:run` and completed its workspace and serialized groups.
Initial resource and timing failures passed on isolated reruns. All 149
serialized route suites passed.
- Reran the changed server, adapter, and UI suites after the rebase.
Coverage includes long-name upstream dispatch, configuration retry
suppression, cancellation evidence retention, privacy labels, oversized
run projection, and concurrent saved-message delivery.
- `pnpm test:e2e tests/e2e/legacy-failure-continuation.spec.ts` passed
all six browser scenarios. The recovery notice shows the run cause and
inspection link, and each recovery entry point reaches one new response.
- Added database-backed checks for active, removed, paused, unavailable,
and disabled chat connections. The final continuation and
recovery-notice suites passed 167 tests. Externally bound chats hide
board Continue and show a usable next action.
- All 55 GitHub checks passed on
`42afbf1371dcaeb72646e3d8f65c19ff7cddf8de`. Two unrelated Storybook jobs
were skipped by their normal conditions. Greptile reviewed that commit
at 5/5 with no findings and no open review threads.

## Risks

- Long tool names change to aliases. Existing short names stay
compatible. The original connection and upstream name remain the
dispatch authority.
- Invalid tool definitions no longer get automatic retries. An operator
must repair the configuration before a new attempt.
- Continuation changes apply only to positively identified unexpected
legacy cancellations with complete empty tool inventory. Operator Stop,
unknown historical cancellations, outstanding tools, and unverified
provider termination keep their holds.
- No database migration. The added projection fields are optional.
Cancellation reason and initiator IDs remain local run evidence; Sentry
receives only closed source and initiator-type labels and expectedness.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, repository editing, shell
execution, and GitHub tool use. The runtime does not expose the exact
model variant 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-02 13:47:59 -05:00
DottaandPaperclip 7d59de6113 feat(connections): probe provider usage limits on demand (#14936)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Connections store the AI accounts used by legacy and native runners.
> - Subscription accounts can reach session, weekly, model, or paid
usage limits.
> - Operators need to read these limits for a specific stored account
before making a routing decision.
> - This pull request adds an on-demand usage probe to the connection
service and account detail.
> - The result preserves provider limits, reset times, paid usage, and
unknown values for later consumers.

## Linked Issues or Issue Description

**Subsystem affected**

Shared contracts, the connection service and API, and the account detail
UI.

**Problem or motivation**

Managed AI accounts lack a common operation to read their current usage
limits. A local harness probe can read a different login from the
account selected for an agent.

**Proposed solution**

Add `aiConnectionService.probeUsage()` and a board-only connection usage
endpoint. Probe the selected credential grant on request. Support Codex,
Claude, and Grok subscriptions, plus OpenRouter API key limits.

**Alternatives considered**

Harness-specific automatic polling would couple the read to execution
and can read ambient credentials. This change uses the managed
connection credential and leaves scheduling and admission decisions to
later work.

**Roadmap alignment**

This extends the existing Personal & Shared AI Accounts capability. It
adds no routing or quota enforcement. Related: Refs #14459 for managed
OpenAI quota reads; Refs #14781 and Refs #13379 for downstream pacing
and budget work. This operation reads one requested account across all
three subscription providers.

## What Changed

- Add typed usage snapshots and a probe capability flag to managed AI
connections.
- Normalize Codex, Claude, Grok, and OpenRouter responses. Keep model
scopes, provider admission, reset periods, and paid allowances separate.
Preserve unknown values.
- Enforce company membership, credential audience, grant identity, and
connection lifecycle before reading the stored secret.
- Add a board-only `GET
/api/companies/:companyId/ai-connections/:connectionId/usage` endpoint
with `no-store` responses.
- Add manual **Check usage** and **Refresh** actions to account details.
Show compact usage bars, resets, admission and overage status; remove
repeated descriptions and account-default copy. Clear previous results
during a new request or error.
- Add Storybook previews using the production account components for all
four providers, initial checks, loading, and permission errors.
- Add provider, authorization, runner selection, API, and UI coverage.
Document provider sources and live qualification.

## Verification

- Initial provider, authorization, selection, API, and UI validation
passed (96 focused tests): `pnpm exec vitest run
server/src/services/ai-connection-usage.test.ts
server/src/__tests__/ai-connections.test.ts
ui/src/components/ai-connections/AiConnectionUsagePanel.test.tsx
server/src/__tests__/openapi-routes.test.ts`.
- `pnpm -r typecheck` passes for the initial implementation. After
simplifying the UI, 9 usage-panel and date-helper tests, UI typecheck,
token gates, and Storybook build pass. The initial feature module
boundary check also passed.
- Real Codex, Claude, and Grok credentials were saved to encrypted
disposable connections. The actual usage HTTP route returned 200 with
`status: ok`. Legacy and native runner selection checks passed. The
tests started no model turn and exchanged no refresh token. The
disposable databases and vaults were removed.
- Live Claude responses added structured scoped limits. Live Grok
responses omitted included-plan usage. Tests now cover both shapes and
preserve the Grok omission as unknown.
- The full workspace build passes. A full local test run hit a heartbeat
feedback timeout. That case passes in isolation. The duplicate local run
was stopped after all remote checks passed. The Slack ordering and
OpenCode transport CI flakes also pass in isolation and on the CI rerun.


- Current head: `ff3d479029a1c4248190323e221b2803cfb0d79d`. All 54
active checks pass. Two Storybook checks are intentionally skipped by
the workflow. Greptile is 5/5 with no unresolved review findings; the
branch is mergeable.

## Risks

- Subscription usage endpoints can change. Credentials can lack
usage-read permission. The probe returns explicit errors without fresh
limits in these cases.
- A successful probe can contain partial data. Missing utilization or
admission remains unknown. An enabled paid-usage switch does not prove a
funded balance.
- This change adds no migration. It does not change runner admission or
automatic provider selection. Provider requests use fixed endpoints,
disabled redirects, bounded response sizes, and a 15-second deadline.

## Model Used

OpenAI Codex, GPT-6, with reasoning, file editing, shell execution, and
HTTP tools. The session does not expose the exact runtime model variant
or context window size. Real provider credentials were used only for the
authorized live checks.

## 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-02 11:47:14 -05:00
dependabot[bot] cf8ad63c80 build(deps-dev): bump tsx from 4.23.12 to 4.23.15 (#12965)
Bumps [tsx](https://github.com/privatenumber/tsx) from 4.23.12 to
4.23.15.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/privatenumber/tsx/releases">tsx's
releases</a>.</em></p>
<blockquote>
<h2>v4.23.15</h2>
<h2><a
href="https://github.com/privatenumber/tsx/compare/v4.23.14...v4.23.15">4.23.15</a>
(2026-09-20)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>exclude bare builtins from namespace inheritance (<a
href="https://github.com/privatenumber/tsx/commit/38e158857e50bca311be7c232a5057e5a2e5347a">38e1588</a>)</li>
<li>expose require.cache and require.extensions to tsImport CommonJS
modules (<a
href="https://github.com/privatenumber/tsx/commit/2da34075afaed43e2b7fd0aca5fbebaaf337ff3a">2da3407</a>)</li>
<li>make namespaced register() overloads portable for declaration emit
(<a
href="https://github.com/privatenumber/tsx/commit/562c434a5c8695e74327bbeb51cfeb9b86fc7e15">562c434</a>)</li>
</ul>
<hr />
<p>This release is also available on:</p>
<ul>
<li><a href="https://www.npmjs.com/package/tsx/v/4.23.15"><code>npm
package (@​latest dist-tag)</code></a></li>
</ul>
<h2>v4.23.14</h2>
<h2><a
href="https://github.com/privatenumber/tsx/compare/v4.23.13...v4.23.14">4.23.14</a>
(2026-09-20)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>restore the CJS bridge namespace for Node 24 require(esm) under
tsImport() (<a
href="https://redirect.github.com/privatenumber/tsx/issues/802">#802</a>)
(<a
href="https://github.com/privatenumber/tsx/commit/6e5236b065738d3687a06396d064774cfede390f">6e5236b</a>)</li>
</ul>
<hr />
<p>This release is also available on:</p>
<ul>
<li><a href="https://www.npmjs.com/package/tsx/v/4.23.14"><code>npm
package (@​latest dist-tag)</code></a></li>
</ul>
<h2>v4.23.13</h2>
<h2><a
href="https://github.com/privatenumber/tsx/compare/v4.23.12...v4.23.13">4.23.13</a>
(2026-08-30)</h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong>cache:</strong> bound shared transform cache memory (<a
href="https://redirect.github.com/privatenumber/tsx/issues/835">#835</a>)
(<a
href="https://github.com/privatenumber/tsx/commit/28e1f12d04cd2afe1db17f8555b14fe5fb567c6e">28e1f12</a>)</li>
</ul>
<hr />
<p>This release is also available on:</p>
<ul>
<li><a href="https://www.npmjs.com/package/tsx/v/4.23.13"><code>npm
package (@​latest dist-tag)</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/privatenumber/tsx/commit/ca66105a17a2a4c6503fe3a12b5b9ec408286011"><code>ca66105</code></a>
test: fix drive-less file URLs in ESM resolver fixtures</li>
<li><a
href="https://github.com/privatenumber/tsx/commit/2da34075afaed43e2b7fd0aca5fbebaaf337ff3a"><code>2da3407</code></a>
fix: expose require.cache and require.extensions to tsImport CommonJS
modules</li>
<li><a
href="https://github.com/privatenumber/tsx/commit/38e158857e50bca311be7c232a5057e5a2e5347a"><code>38e1588</code></a>
fix: exclude bare builtins from namespace inheritance</li>
<li><a
href="https://github.com/privatenumber/tsx/commit/562c434a5c8695e74327bbeb51cfeb9b86fc7e15"><code>562c434</code></a>
fix: make namespaced register() overloads portable for declaration
emit</li>
<li><a
href="https://github.com/privatenumber/tsx/commit/edfb1f05a3f40b879a41a03a0801c2abd3a3ecf9"><code>edfb1f0</code></a>
build: upgrade pkgroll and externalize CJS loader reference</li>
<li><a
href="https://github.com/privatenumber/tsx/commit/70e78284837c859f09b96cd10cd71d007aa4b795"><code>70e7828</code></a>
test: upgrade tinyspy for disposable API</li>
<li><a
href="https://github.com/privatenumber/tsx/commit/9ed2022dfa9ea1be9511fe6abcde8110c25055a7"><code>9ed2022</code></a>
ci: avoid duplicate release notifications</li>
<li><a
href="https://github.com/privatenumber/tsx/commit/872e77ffc5e96ca5c4727e74c0694debcb26219b"><code>872e77f</code></a>
refactor: use disposables for cleanup</li>
<li><a
href="https://github.com/privatenumber/tsx/commit/6e5236b065738d3687a06396d064774cfede390f"><code>6e5236b</code></a>
fix: restore the CJS bridge namespace for Node 24 require(esm) under
tsImport...</li>
<li><a
href="https://github.com/privatenumber/tsx/commit/28e1f12d04cd2afe1db17f8555b14fe5fb567c6e"><code>28e1f12</code></a>
fix(cache): bound shared transform cache memory (<a
href="https://redirect.github.com/privatenumber/tsx/issues/835">#835</a>)</li>
<li>See full diff in <a
href="https://github.com/privatenumber/tsx/compare/v4.23.12...v4.23.15">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-02 08:39:37 -07:00
DottaandPaperclip a75c50f79f Merge current MCP foundation
* codex/paperclip-public-mcp:
  test(shared): make the worktree port registry lock suite deterministic (#12798)
  fix(adapter-utils): make the directory merge lock crash test deterministic (#14881)
  feat(connections): make AgentMail a default connection with inline setup (#14772)
  fix(chat): hide ignored provider information (#14929)
  build(deps): bump aws-actions/configure-aws-credentials from 6.2.3 to 6.3.0 (#12966)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-02 10:34:18 -05:00
DottaandPaperclip 65cc11e0f5 Merge current master and retain both evaluation catalog additions
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-02 10:34:16 -05:00
DottaandPaperclip 6c1a75da49 feat(connections): make AgentMail a default connection with inline setup (#14772)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Connections give agents access to external services.
> - AgentMail needs both a saved key and an inbox assigned to the agent.
> - Chat requests offered a setup link instead of an inline card and
could treat a saved key as complete.
> - Inbox setup also hid address conflicts behind a generic server error
and a separate review step.
> - This pull request makes AgentMail a default connection, adds the
inline card, reduces setup to two steps, and shows conflicts beside the
address.
> - Shared native dropdown styles also give every caret a consistent
inset.

## Linked Issues or Issue Description

**What happened?**

AgentMail requests in chat did not show a usable inline connection card.
Manual setup required extra screens, ignored saved account keys, and
could trap new-address setup in a locked inbox dropdown. Agent selectors
omitted the avatar from the selected value. A taken address could
produce an HTTP 403 from AgentMail and appear as an internal server
error. Native dropdown arrows also touched the right edge of their
fields.

**Expected behavior**

Make AgentMail available as a default connection. Ask for the API key
inline, with a direct link to its provider page. Default human access to
the company and agent access to the requesting agent. Resume the agent
only after an assigned inbox is active. Manual setup should ask for an
agent and email address, then finish. Address checks should run as the
user types. Taken addresses should show clickable alternatives. A domain
dropdown beside the name should prefer a verified custom domain. Setup
should suggest authorized saved AgentMail keys and show agent avatars in
the picker and selected value.

**Steps to reproduce**

1. Ask an agent to connect AgentMail when it has no assigned inbox.
2. Check that an inline API-key card appears and links to the provider's
API-key page.
3. Open AgentMail setup, choose an agent, and request an address that is
already taken.
4. Correct the inline error, refresh, and finish setup with the same
request ID.
5. Inspect native dropdown carets in light, dark, disabled, and
right-to-left states.

Uses the bounded provider-error parser merged in #14768. Related work:
#13256 introduced AgentMail; #14725 expanded connection search.

## What Changed

- Stop recurring email queries for tasks that have no email thread.
Share the query between the thread provider and activity view. Keep
email-task updates and invalidation-based discovery.
- Make AgentMail available without the experimental chat setting. Keep
the catalog, setup and management routes, agent Channels tab, task email
feed, receiving worker, and agent tools available by default. Other
experimental chat providers stay gated.

- Make the email address and copy icon a single clickable action with
the shared Copied! confirmation. Add View inbox linking directly to the
matching AgentMail console inbox, with the address encoded as one URL
path segment.

- Reorganize inbox Settings around the copyable email address, usage
instructions, and receiving status. Move reconnect credentials into a
disclosure and separate the Disconnect action. Add production Settings
stories for active, paused, unassigned-address, revoked, webhook,
long-address, mobile, and reconnect states. Show repair controls when
the inbox has an error. Keep usage instructions tied to an active inbox
with an address.

- Add AgentMail channel intents and an inline key field with the direct
API-key URL.
- Keep setup and retry state tied to the interaction. Require an active
inbox for completion. Preserve company and agent access checks.
- Reduce manual setup to agent selection and email selection. Put the
domain dropdown beside the address and default to a verified custom
domain. Preserve explicit choices across reloads. Keep receiving
settings under Advanced options.
- Check the initial address and edits after a 350 ms pause. Abort
superseded requests and ignore stale responses. Show clickable
suggestions and retain known creation conflicts across reloads.
- Add a company-scoped, manager-only address check using the saved
credential. Search the visible inbox list instead of fetching an
uncreated inbox: live AgentMail retains negative lookups that can break
subsequent access-key creation. Unlisted addresses remain unknown;
creation is authoritative.
- Suggest labeled saved AgentMail keys in both manual setup and the
inline card. Filter by company, provider, active credential, and
current-user grants on the server. Prefer an account key and preserve
the selected key or an explicit new-key choice across refresh. Use
verified scope metadata and bounded concurrent checks for legacy keys.
Never return secret values.
- Catch an inbox-only key before the email step. Allow its existing
inbox only after an explicit choice. Recover old locked drafts at the
key picker. Save the replacement key before retiring an empty draft,
then use a new setup URL so refresh preserves the switched account; stop
if cleanup fails. Preserve already allocated addresses and their
original accounts.
- Use the shared AgentSelect in email setup. Show the canonical agent
avatar in each option and the selected value, including other consumers
of the shared component. Add regression coverage for legacy and current
Lucide agent-mention icon formats.
- Start each catalog Add connection with a fresh setup identity. Honor
Finish setup's exact draft/account/address instead of resuming an
unrelated browser draft. Return Cancel and Done to Connectors and Email
settings to the inbox. Group the task/thread explanation in a How it
Works card.
- Route AgentMail catalog removal through the email inbox control API,
including unfinished drafts. Refresh both the catalog and inbox views.
- Render each inbox management tab separately. Access uses the saved
account grants and agent controls; Conversations and Activity use the
shared persisted email feed. Activity lifecycle actions use the email
API. Reconnect returns to inbox Settings. Conversation failures show a
retry instead of a false empty state. Email delivery recovery stays in
the task.
- Map documented provider address conflicts to a field error. Preserve
actionable messages for other failures.
- Preserve non-secret draft fields across refresh, scoped to the
requested agent. Never save API keys in browser storage. Resume partial
inbox creation with the original agent, address, and request ID.
- Show an already-created address with explicit retry and new-address
recovery instead of locked inputs. Preserve the original inbox and
resumable draft when choosing another address. Distinguish runtime-key
404 errors and log safe provider status/operation/code.
- Apply final agent access once within email setup authorization for a
new account whose original installs are unchanged. Preserve later
permission edits and reused account installs. Support in-place retry of
progress loading.
- Let a failed inline setup change keys after retiring an empty draft.
Persist its replacement setup identity without storing secrets. Recover
a server-saved account when refresh interrupts the save response, while
preserving intentional account changes.
- Render the production setup in Storybook and add error, recovery, and
mobile states.
- Inset native select carets in shared CSS. Preserve custom icons,
listboxes, keyboard behavior, and forced-color controls.
- Add browser regression coverage and an AgentMail Product E2E case with
persisted-state and rendered-card evidence.

## Verification

- Full `pnpm -r typecheck`, `pnpm build`, `pnpm check:token-gates`, and
`git diff --check` passed after the default-availability change.
- All 485 focused tests passed. These cover setup, management, catalog
and route gates, connection intents, email authorization, Cursor
execution, and the OpenAPI contract. All 39 email integration tests run
with the experimental chat setting off.
- The shared polling change passed four behavioral tests, UI typecheck
and build, and token gates.
- `tests/e2e/agentmail.spec.ts` passed with the actual server setting
off. This full-stack browser test uses simulated provider responses. It
covers catalog entry, saved keys, editable address and domain controls,
creation, conflicts, retry, all management tabs, clipboard feedback, the
provider link, and task email rendering.
- In the live local browser, Add connection reached the editable email
step with the saved account key. The verified custom domain was selected
by default. Both domain choices worked. The existing inbox Settings page
remained available. Both active inboxes completed new mail checks with
the setting off. No new provider inbox or email message was created for
this pass.
- Earlier live provider acceptance covered creation on a verified custom
domain, Finish connecting on the reported draft, successful mail checks
after refresh, and catalog removal of disposable draft and active
connections. Clicking the email address copied the exact address and
showed Copied!. View inbox opened the same inbox in AgentMail’s console.
No email messages were sent.
- Production setup and Settings Storybook builds and interactions
passed. Settings states include active, paused, unassigned, revoked,
webhook, long-address, mobile, and reconnect. Receiving and
revoked-access stories had zero accessibility violations.
- Full local `pnpm test:run` on an earlier revision completed with
14,709 passing, 87 skipped, and four transient failures. All four failed
cases passed in focused reruns without product changes. That serial full
local command was not repeated after each follow-up. The latest-head
full CI suite is the final test gate.
- CI found an obsolete browser assertion that hid every channel when the
flag was off. Updated it to keep AgentMail and the Channels surface
visible while preserving the GitHub chat route gates. All 11 provider
browser tests passed locally after scoping the Channels selector to the
agent sidebar. Two initial local attempts stopped at temporary Postgres
initialization. The passing run used a separate disposable database on
the existing local Postgres server; it was removed after the test.
- Updated the remaining sidebar and aggregator discovery assertions for
default AgentMail availability. Ordinary task fixtures now return no
email thread. All 128 sidebar/task-page tests and all 42 aggregator
tests passed locally.
- Latest head `b42bb4cd5cc9f2d01a99ab8026832d5a956ea85f`: full CI
passed, with 54 successful checks including Snyk and two intentional
Storybook skips. The CI run is
https://github.com/paperclipai/paperclip/actions/runs/37020833647. A
fresh Greptile review scored 5/5 with no unresolved threads. Live model
evaluations and inbound/outbound email delivery were not run.

## Risks

- AgentMail no longer needs experimental opt-in. Setup still requires a
human to connect an account and assign an inbox. Inline setup creates an
inbox after a human submits a new or saved key. Company access, agent
access, inbox assignment, and completion checks remain enforced.
- AgentMail read APIs cannot prove global address availability. The
visible-list check is bounded to 100 entries and cannot see inboxes
outside the key’s scope. The UI reports this limitation, suggests
alternatives without claiming they are free, and keeps final creation
conflicts inline. Lookup outages show an error without preventing the
authoritative creation attempt.
- Native select CSS affects the whole app. Custom-icon selects and
multi-row lists are excluded. Forced-color mode keeps the browser caret.
- Saved-key discovery uses stored verified scope metadata and checks
authorized legacy credentials concurrently within a shared three-second
deadline. Provider outages mark legacy choices unavailable; users can
still enter another key. Final use rechecks authorization and provider
access.
- No database migration or transport default change. Live connection
remains the default.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-02 10:01:15 -05:00
DottaandPaperclip 12b3f10e9a fix(mcp): preserve event retries when access is disabled
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-02 09:51:38 -05:00
DottaandPaperclip ae37308eab Merge updated public MCP foundation
* codex/paperclip-public-mcp: (33 commits)
  fix(connections): repair stale AI defaults from agent settings (#14916)
  fix(runner): preserve stock Codex base instructions (#14920)
  fix(heartbeat): validate native MCP gateway ownership (#14914)
  fix(tool-access): enforce stored grant restrictions (#14915)
  fix(tool-gateway): bound MCP discovery memory and concurrency (#14864)
  build(deps): bump react-i18next from 17.0.12 to 17.0.15 (#12970)
  build(deps): bump @assistant-ui/react from 0.15.21 to 0.15.22 (#12971)
  build(deps-dev): bump @storybook/addon-docs from 10.5.10 to 10.6.0 (#12972)
  fix(daytona): recover output from stalled log streams (#14889)
  docs(release): canonicalize stable notes for v2026.1001.0 (#14890)
  build(deps): bump i18next from 26.4.0 to 26.4.2 (#12973)
  build(deps): bump react-router-dom from 7.18.2 to 7.18.4 (#12974)
  Retry transient failures in dashboard reads (#14873)
  build(deps-dev): bump agentmail from 0.5.20 to 0.5.31 (#12975)
  fix(company-skills): approve managed-checkout project dirs for local skill import (#10329)
  docs(release): align 2026.921.0-beta.1 stable notes header with v2026.1001.0 (#14882)
  build(deps-dev): bump @storybook/addon-a11y from 10.5.10 to 10.6.0 (#12976)
  build(deps-dev): bump storybook from 10.5.10 to 10.6.0 (#12984)
  build(deps): bump lucide-react from 1.45.0 to 1.48.0 (#12985)
  build(deps): bump @anthropic-ai/sdk from 0.121.0 to 0.129.0 (#13386)
  ...

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-02 09:41:00 -05:00
DottaandPaperclip b4714d5b0b Merge master and regenerate the MCP migration
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-02 09:40:55 -05:00
DottaandPaperclip 7a5f597e84 feat(mcp): enable assistant connections through experimental settings
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-02 09:32:06 -05:00
DottaandPaperclip e00d10d5d5 fix(connections): repair stale AI defaults from agent settings (#14916)
## Thinking Path

> - Paperclip manages AI agents and controls the credentials used for
their work.
> - Managed AI connections resolve each responsible user's provider
default.
> - Agent settings created another account but kept the old default
selected.
> - A rejected provider test left the old account marked as connected.
> - Claude ACP reported a typed login failure as a generic
terminal-access error.
> - This pull request repairs the selected account or selects the new
login explicitly.
> - Agents can save and run with the repaired credential, and failed
logins request sign-in.

## Linked Issues or Issue Description

- Fixes #14831.
- Refs #13867. Environment failures remain separate from
credential-health failures.

## What Changed

- Add an agent-settings action to reconnect an unavailable personal
default in place. Keep its connection, grant, default, and agent access.
- State that a new account becomes the user's provider default. Select
its returned grant before changing the agent binding. Keep the actual
sign-in method.
- Show default-update errors and allow retry without another provider
login.
- Show the agent-access choice. Connection managers start with
company-wide access for their own tasks. Other members start with access
for the current agent.
- Use the server's connection-manager permission in the shared list
response. This includes members with a custom management grant.
- Mark credentials as needing attention after an explicit login
rejection in Test or Save. This includes API-key 401 and 403 responses.
Network, quota, and server failures keep the credential health
unchanged.
- Reuse the credential-generation check so an old failure cannot
invalidate a newer reconnect.
- Route Claude's typed provider `access` failure to the existing
login-recovery flow. Replace its generic terminal-access fallback with a
sign-in message.
- Add regression tests and update the AI Connections documentation.

## Verification

- Red: the UI tests failed on the missing reconnect action, unused
returned grant, missing access choice, and lost default-update error.
The server tests failed because rejected credentials stayed connected.
The real ACP fixture returned `acpx_turn_failed` for typed login
failures.
- Green: 156 tests passed across the AI connection, hiring, agent field,
and New Agent suites. All 37 environment-route tests passed. The Claude
ACP authentication fixtures also passed.
- `pnpm check:token-gates` passed.
- `pnpm -r typecheck` passed.
- `pnpm build` passed.
- The full local `pnpm test:run` passed 707 files and 14,503 tests, then
exited with an agent-conversation timeout and embedded PostgreSQL
startup failures in unchanged suites. The isolated conversation and
migration tests passed on rerun. Later local test groups did not run
after this failure.
- [All CI gates
passed](https://github.com/paperclipai/paperclip/actions/runs/37012669356)
on commit `38513dfe2`. This includes the full test matrix, browser
tests, typecheck, build, Runner checks, and canary dry run.
- Greptile reviewed commit `38513dfe2` and returned 5/5 with no open
findings.
- The regression tests use a real embedded database and a real ACP
fixture process. Live provider sign-in requires a valid account and was
not run.

## Risks

- Connecting a new account from agent settings changes the user's
provider default. The dialog states this before sign-in.
- The displayed access choice can allow all company agents to use the
account for its owner's tasks. Reconnect keeps the existing access.
Server permissions still control installs.
- Claude's typed `access` category maps to the provider's
`auth_required` signal. Tool and workspace request failures retain their
existing classification.
- No database migration or provider credential format changes are
required.

## Model Used

- OpenAI GPT-6 through Codex. The exact served model identifier and
context window are not exposed in this session. Capabilities used:
reasoning, repository tools, code editing, and command execution.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-02 08:57:52 -05:00
DottaandPaperclip c46e41e81c fix(heartbeat): validate native MCP gateway ownership (#14914)
## Thinking Path

> - Paperclip lets people manage agents and govern their tool access.
> - Native runs receive an immutable MCP tool assignment for one agent.
> - The gateway must enforce that owner when it authenticates a run
token.
> - Older gateway rows stored the owner only in metadata.
> - This change validates the gateway and profile, binds new rows, and
repairs valid older rows on reuse.
> - It also delivers each native assignment once.
> - Other agents cannot use the assignment, and explicit shared gateways
keep their configured scope.

## Linked Issues or Issue Description

Builds on #14012 by @busla (Jón Levy). That PR adds agent binding and
seven regressions. This PR carries that fix onto current master and adds
legacy authentication, profile validation, and duplicate-delivery
coverage. Related: #14864 improves discovery memory use.

**What happened?**
Native gateway creation stored an owner in metadata but left `agentId`
null. Authentication could therefore accept another agent's run token.
Managed discovery could also deliver historical native assignments
again.

**Expected behavior**
A native assignment accepts only its owner's run token. The gateway and
profile must refer to the same immutable assignment. The current
assignment enters the run configuration once.

**Steps to reproduce**
1. Run the database fixtures in `heartbeat-runtime-mcp-servers.test.ts`
on the baseline.
2. Create a native assignment and inspect its stored gateway owner.
3. Authenticate with another agent's run token, then inspect legacy
reuse and managed delivery.
4. The baseline fails six ownership and delivery cases. The fix passes
all twelve cases.

**Paperclip version or commit**
The red baseline is `f2e0f1963`. This PR is based on `cad26c6bf`, which
includes the merged discovery fix.

**Deployment mode**
Native Paperclip Runner execution and managed Codex MCP delivery.
Reproduction uses isolated database and HTTP fixtures.

## What Changed

- Store the agent owner and agent context on new native gateways.
- Validate profile and gateway assignment metadata before reuse or token
creation.
- Bind valid legacy rows with a company-scoped, null-owner update and
validate the result.
- Reject mismatched run tokens before legacy repair.
- Identify native assignments by gateway metadata, the reserved profile
key, or profile source. Reject missing or malformed provenance,
including JSON null.
- Exclude historical native assignments from managed gateway delivery.
Keep their rows for existing runs.
- Add twelve database and HTTP regressions and document the runtime
contract.

## Verification

- Red baseline: six regressions fail and four controls pass before the
initial fix. Two additional regressions reproduce metadata-loss
admission and a JSON-null TypeError before the review fix.
- All twelve ownership regressions pass on the final code, including
owner admission, cross-agent rejection, metadata loss, JSON-null HTTP
401, and explicit shared-gateway admission. Policy, listing-memory, and
discovery HTTP coverage also passes.
- Full workspace typecheck and build pass locally. Server typecheck and
compilation pass again after the review fix. The final ownership and
grant patches pass 42 combined database and HTTP regressions.
- [Full
CI](https://github.com/paperclipai/paperclip/actions/runs/37011383657)
passes for `626a08ae66361cf586105877e24d806b1a7a9c20`: all 54 checks
succeed; two optional Storybook checks skip. This includes full
typecheck, build, all test shards, all eight E2E shards, runner
verification, and the canary dry run.
- Greptile scores that exact head 5/5. No review threads remain
unresolved.

## Risks

Invalid historical native gateway or profile metadata now rejects
authentication. Valid unbound rows are repaired only when their owner
reuses the assignment. Conflicting owners are never overwritten.
Historical rows are retained for existing runs. Explicit shared gateways
use ordinary profiles and keep their configured scopes. The reserved
native profile namespace remains agent-owned even when gateway metadata
is cleared. No schema or dependency changes are included.

## Model Used

Original fix and seven regressions in #14012: Anthropic Claude Opus 5.5,
`claude-opus-5-5`, 1M context, as reported by @busla. Extensions and
verification: OpenAI Codex (GPT-6), with reasoning, repository
inspection, code execution, and tests. This session does not expose the
exact serving model identifier or context window.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-02 08:22:33 -05:00
DottaandPaperclip 483dbc8890 fix(tool-access): enforce stored grant restrictions (#14915)
## Thinking Path

> - Paperclip governs the tools that agents can discover and call.
> - Stored grants can limit access to a tool, connection, or
application.
> - The grant matcher must enforce every restriction in that scope.
> - A nonmatching allow list fell through to a policy selector matcher
that ignores allow.
> - This change requires an explicit allow match and validates
additional selectors.
> - Malformed and unknown restrictions deny access.
> - Discovery and execution now enforce the same stored grant limits.

## Linked Issues or Issue Description

Related: #14864 adds the shared database and HTTP discovery fixture used
here. Searched existing public PRs for tool grant scope fixes. No
duplicate scope-validation fix was found.

**What happened?**
A stored grant with a nonmatching `scope.allow` could authorize a tool.
Empty or malformed allow lists, unknown selectors, and combined
mismatching selectors could also authorize access. The fallback policy
matcher does not validate stored grant JSON.

**Expected behavior**
An explicit allow list must match the requested tool, connection, or
application. Every additional selector must also match. Unknown or
malformed restrictions must deny access. Existing null and empty-object
scopes keep their broad grant behavior.

**Steps to reproduce**
1. Run `tool-grant-scope.test.ts` on the baseline.
2. Create a deny profile and a grant that names another tool.
3. Attempt discovery or a call for the tool outside the grant.
4. The baseline authorizes access. The fix denies it.

**Paperclip version or commit**
The red baseline is `f2e0f1963`. This PR is based on `cad26c6bf`, which
includes the merged discovery fix.

**Deployment mode**
The company-scoped MCP gateway. Reproduction uses isolated database
fixtures and a deterministic HTTP provider.

## What Changed

- Require an explicit allow entry to match the gateway or upstream tool
name, connection, or application.
- Apply all additional selectors after the allow match.
- Reject unknown selectors, invalid value types, empty restrictions, and
non-object scopes.
- Preserve null and empty-object scope compatibility.
- Add sixteen regressions, including discovery, successful execution,
and revocation through the HTTP gateway.
- Document stored grant scope behavior.

## Verification

- Red baseline: seven restricted-scope cases and three malformed-root
cases fail. HTTP discovery also exposes tools outside the grant.
- All 16 grant regressions and 35 adjacent policy tests pass locally.
The HTTP test excludes an ungranted tool from discovery, returns 403 for
its call, and verifies that no provider call occurs. It also checks
successful execution and later revocation.
- Server typecheck passes. The final ownership and grant patches also
pass 42 combined database and HTTP regressions.
- [Full
CI](https://github.com/paperclipai/paperclip/actions/runs/37011177989)
passes for `803fa9440111742672c94c4471e5b98f15dd3b97`: all 54 checks
succeed; two optional Storybook checks skip. This includes full
typecheck, build, all test shards, all eight E2E shards, runner
verification, and the canary dry run.
- Greptile scores that exact head 5/5. No review threads remain
unresolved.

## Risks

Stored scopes with unknown keys or malformed restrictions now deny
access. Operators must correct those grants before they can authorize
tools. Null and empty-object scopes keep their previous broad behavior.
There are no schema, dependency, or API changes.

## Model Used

OpenAI Codex (GPT-6), with reasoning, repository inspection, code
execution, database regressions, and HTTP tests. This session does not
expose the exact serving model identifier or context window.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-02 08:21:40 -05:00
cad26c6bfb fix(tool-gateway): bound MCP discovery memory and concurrency (#14864)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents discover governed tools through the MCP gateway.
> - A listing repeated policy and full run-row reads for each catalog
tool.
> - Parallel listings multiplied those allocations during run startup.
> - One 900-tool baseline listing used 11,489 queries and about 1.7 GiB
of extra heap in a fixture.
> - This pull request shares reads within a listing and bounds whole
listings across the process.
> - The benefit is lower discovery memory use while execution still
checks current policy.

## Linked Issues or Issue Description

Refs #13115. Its on-demand target change affects the same listing loop.

**What happened?**

MCP discovery repeated roughly 13 reads per tool. Full run snapshots and
repeated connection configurations caused large allocations. Per-listing
bounds alone did not limit concurrent listings across gateways.

**Expected behavior**

Discovery reads shared inputs once per listing. The process bounds
active and queued listings. Catalog payload size and policy evaluation
still grow with the catalog. Tool execution checks current access rules.

**Steps to reproduce**

Create a company with a remote MCP connection, 900 catalog tools, large
schemas, and a large run snapshot. Send concurrent tools/list requests
using a run-bound gateway token. Run the committed benchmark for a
deterministic reproduction.

**Paperclip version or commit**

Baseline: f2e0f19630. Measured on Node
26.4.0 on macOS.

## What Changed

- Keep Michael Nguyen's per-listing policy cache, scalar policy reads,
16-decision bound, and catalog/connection split under repeatable read.
- Admit two whole listings per process and queue at most 32. Return 503
with tool_discovery_busy when full.
- Propagate disconnects to discovery. Stop scheduling new reads and
drain started reads before freeing the slot.
- Project context IDs in gateway authentication and GitHub runtime
discovery. Avoid loading task descriptions and results.
- Keep discovery audit counts and a SHA-256 digest instead of the full
name list. Retain access and activity audit records.
- Sweep expired named gateway tokens at startup and on the existing
scheduler. Delete at most 500 per pass. Add an idempotent expiry-index
migration. Resolve audit token references atomically so cleanup cannot
break admitted requests.
- Return GET 405 with Allow: POST on stateless MCP gateway and
runtime-tools endpoints. Keep runtime-tools authentication.
- Add red-green regressions, HTTP concurrency and policy-revocation
coverage, and browser approval assertions.
- Commit the benchmark harness, raw results, and resource-bound
documentation.

## Verification

- Baseline listing regressions failed with 722 queries for 50 tools and
6,422 for 500. The connection-row duplication regression also failed.
- Follow-up regressions failed before the fixes for full snapshot reads,
abandoned listings, full name-list audits, and expired tokens.
- Listing and scheduler tests: 14 pass. Existing gateway/policy suites
passed after preserving the cleanup return contract.
- Two HTTP journeys pass: initialize, GET/SSE rejection, 16 concurrent
500-tool listings, provider call, policy revocation, and denied retry.
Token cleanup during provider dispatch also completes successfully and
blocks subsequent requests.
- pnpm test:e2e tests/e2e/mcp-user-stories.spec.ts --grep
'@mcp-runnable': 8 pass. The approval journey clicks Allow once in the
browser. Review screenshots wait for loaded content.
- pnpm -r typecheck: passes. pnpm build: passes.
- The general server group completed with 14,755 passes and 18 failures.
The 17 startup mock failures were fixed; all 21 startup tests pass on
rerun. The one Discord timing failure passed on the unchanged baseline
and on rerun (74 tests). UI and CLI groups pass 7,632 tests. Shared and
skill groups pass 853 tests. The remaining database and adapter groups
pass 3,010 tests with one worker after a macOS shared-memory limit
interrupted a parallel run. All 149 serialized route files pass (2,762
tests).
- At 900 tools, one listing falls from 11,489 to 36 queries and from
about 1.7 GiB to 37 MiB of extra heap. Sixteen concurrent listings used
169–187 MiB of extra heap. Four connections used 39 queries per listing.
- Latest-head verification: 54 successful checks and two expected skips
on 5c0793090c. Fresh Greptile review: 5/5
with no unresolved threads.
- Reproduce with server/scripts/benchmark-tool-gateway-listing.ts. See
doc/mcp-discovery-performance.md and
doc/benchmarks/2026-10-01-mcp-discovery.json.

## Risks

- The process-wide FIFO queue can increase discovery latency. Excess
callers must retry 503 responses.
- Cancellation applies to discovery. Started database reads finish
before their slot is released.
- Audit consumers must use visibleToolCount and visibleToolsHash instead
of visibleTools.
- The expiry index can briefly lock the token table during migration.
Sweeps preserve unexpired and non-expiring tokens.
- Measurements use isolated fixtures and deterministic providers. They
do not establish a production heap limit or affected installation count.
Rate-limit reads remain uncached.

## Model Used

- Original listing optimization: Anthropic Claude Opus 5.5
(claude-opus-5-5), Claude Code, extended thinking and tool use, as
recorded by the original author.
- Follow-up fixes and verification: OpenAI Codex, GPT-6, with shell
execution, file edits, database fixtures, and browser tests. The exact
serving model ID and context window are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with Fixes / Closes /
Refs OR (b) described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [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: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dotta <bippadotta@protonmail.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-02 07:45:27 -05:00
Devin FoleyandPaperclip 4a999089ef Retry transient failures in dashboard reads (#14873)
## Thinking Path

> - Paperclip shows company activity in the dashboard.
> - The dashboard reads company, task, approval, and cost data.
> - A pooled database connection can close during one of these reads.
> - The driver must reject ambiguous statements because writes may have
committed.
> - These four dashboard queries are known to be read-only.
> - This change retries only the failed read and preserves completed
work.

## Linked Issues or Issue Description

Refs #14773, which correctly removed automatic replay of ambiguous
database statements. Searched existing database and dashboard PRs.
Related #8780 changes pool recycling and logging; #13925 adds dashboard
consistency coverage. Neither provides these per-query retries.

**What happened?**

A dashboard request returns a server error when its company lookup, task
count, approval count, or monthly spend query loses its database
connection. Drizzle wraps the driver's connection error in `cause`.

**Expected behavior**

A transient connection failure gets a bounded retry of the specific
read. Completed reads and budget processing are not replayed. Persistent
outages and non-connection errors still fail the request.

**Steps to reproduce**

Inject a typed `CONNECTION_CLOSED` error into one of these reads. Then
allow the next query to succeed. Before this change, the dashboard
request fails immediately.

## What Changed

- Apply independent retries to the company lookup, task counts, pending
approval count, and monthly spend query. Each callback rebuilds its own
query with the same company scope.
- Extract the existing authentication retry helper as
`retryIdempotentDatabaseOperation`. Preserve authentication behavior and
its existing exports.
- Retain the existing limit of three total attempts with 50 ms and 100
ms pauses. Match typed connection codes through the error cause chain.
- Test later-read failures, unchanged query parameters, retry
exhaustion, missing companies, and errors that must not retry. Document
the boundary.

## Verification

- Final focused dashboard, authentication, and real database wire
suites: 38 tests passed. Six initial recovery regressions failed before
the implementation.
- `pnpm -r typecheck`: passed on the final source.
- Independent review: no actionable findings. The reviewer separately
passed all 38 focused tests and checked the code allowlist, attempt
bounds, pauses, and final error identity.
- `pnpm test:run`: the general-server group completed with 14,738 tests
passed, 13 failed, and 87 skipped. All 13 failures match the previously
reproduced clean-base macOS skill-cache failures. The two test files and
their implementations are unchanged from that baseline. The runner
exited after this group, so the remaining local workspace and serialized
groups did not run. All corresponding Linux CI groups passed on this
commit.
- `pnpm build`: passed on the final source.
- Full CI: 53 successful checks and 2 skips on `6a113529c0`. Greptile:
5/5 on that commit, with no review threads or remaining findings.
- Merge compatibility with master `f2e0f19630`, including #14866: no
conflicts. The five reviewed files are unchanged in the resulting merge
tree.

## Risks

A persistent outage adds at most two retries per covered query. Each
connection attempt retains the configured driver timeout. The change
does not repair the underlying network or database failure. Agent
counts, run-activity queries, and the budget workflow stay outside these
retry boundaries. General database statements and disconnected
transactions are not replayed. There is no schema or authorization
change.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository inspection, code
editing, and test execution. The runtime does not expose a more specific
serving 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 and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (38 focused tests; the full
local run has the baseline limitation documented above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-01 19:23:47 -07:00
427e048405 fix(company-skills): approve managed-checkout project dirs for local skill import (#10329)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Company skills can be imported into a company from a local folder;
`companySkillService.importFromSource` guards this with
`assertLocalImportSourceAllowed`, which only permits import sources
inside an approved set of roots (managed skills root + registered
project-workspace cwds), realpath-resolved and `${root}${sep}`-anchored
to prevent path traversal/escape
> - A project can exist as a `managed_checkout` (server-managed clone)
with **no registered `project_workspaces` row** — its `primaryWorkspace`
is `null` and `workspaces` is `[]`, so its only real on-disk location is
the server-derived `codebase.managedFolder`
> - Because `configuredRoots` was built solely from the managed skills
root and `workspaces[].cwd`, a `managed_checkout` project's
`managedFolder` was never an approved root, so importing a skill from
that project's own folder was rejected with
`skill_workspace_boundary_denied`
> - This PR adds each project's server-derived `codebase.managedFolder`
to `configuredRoots` so in-place skill imports from managed-checkout
projects are allowed
> - The benefit is that managed-checkout projects can re-import their
own skills in place, without weakening the traversal/escape protections
(the new roots are server-derived and matched exactly like the existing
ones)

## Linked Issues or Issue Description

No public GitHub issue. Describing in-PR (bug):

**What's wrong:** `assertLocalImportSourceAllowed` denies a legitimate
local skill import (`skill_workspace_boundary_denied`) for any project
that is a `managed_checkout` with no registered workspace row.

**Repro:** Create/import a company skill from a `managed_checkout`
project's own folder (`codebase.managedFolder/.agents/skills/<skill>`).
The import is rejected even though the source is inside the project's
server-managed checkout.

**Expected:** The import from a managed-checkout project's own
`managedFolder` subtree should be allowed, while paths outside that
subtree remain denied.

Related context (already merged): #9564 introduced the open-by-default
skill policy / this import boundary. This PR does not change that
boundary's matching logic — it only adds a missing, server-derived
approved root.

## What Changed

- `server/src/services/company-skills.ts`: add
`...projectRows.map((project) => project.codebase.managedFolder)` to
`configuredRoots` in `assertLocalImportSourceAllowed`. `managedFolder`
is server-derived (`resolveManagedProjectWorkspaceDir(companyId,
projectId)` → instance root + sanitized ids); it is
`fs.realpath`-resolved and `${root}${sep}`-prefix matched exactly like
every existing root. `managedFolder` is used rather than
`effectiveLocalFolder` because the latter can fall through to a
user-registered `localFolder`, which is already covered by the
registered workspace cwds.
- `server/src/__tests__/company-skill-import-boundary.test.ts`: add a
regression test — a managed-checkout project's `managedFolder/<skill>`
import is **allowed**, and a **prefix-adjacent sibling** (`managedFolder
+ "-evil"`) stays **denied**.

## Verification

- `cd server && ./node_modules/.bin/vitest run
src/__tests__/company-skill-import-boundary.test.ts` → **2/2 pass**
(embedded-Postgres suite). Covers both the new allow case and the
prefix-adjacent deny case, alongside the existing out-of-tree /
symlink-escape / non-file-scheme rejections.

## Risks

Low risk. The change only **adds** approved roots; it does not alter the
realpath + `${root}${sep}`-anchored matching that closes
traversal/prefix-adjacency escapes. The added roots are fully
server-derived from the instance root + sanitized company/project ids
(same trust class as the existing `resolveManagedSkillsRoot`) — no value
derived from the import `source` argument reaches them. Sanitization
(`[^a-zA-Z0-9._-]+ → -`) prevents separator/level injection, and the
only user-influenced segment (repo name) is normalized via `new
URL(...)`. The regression test's prefix-adjacent (`-evil`) case asserts
the escape class stays closed.

## Model Used

Claude Opus 4.8 (`claude-opus-4-8`), extended thinking + tool use (code
execution, git). Implementation and security review were produced with
Claude; this integration/PR was prepared with `claude-opus-4-8`.

## 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
- [ ] I have updated relevant documentation to reflect my changes (N/A —
internal boundary fix, no user-facing docs)
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green (CI in progress)
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
(pending review)
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: brandonburr <brandonburr@gmail.com>
2026-10-01 17:34:51 -07:00
dependabot[bot] 2a36e915ef build(deps): bump @vercel/connect from 0.6.1 to 2.3.3 (#13390)
Bumps
[@vercel/connect](https://github.com/vercel/vercel/tree/HEAD/packages/connect)
from 0.6.1 to 2.3.3.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vercel/vercel/blob/main/packages/connect/CHANGELOG.md">@​vercel/connect's
changelog</a>.</em></p>
<blockquote>
<h1><code>@​vercel/connect</code></h1>
<h2>2.0.2</h2>
<h3>Patch Changes</h3>
<ul>
<li>c028593: Update the Core SDK documentation to show how to start an
authorization request.</li>
</ul>
<h2>2.0.1</h2>
<h3>Patch Changes</h3>
<ul>
<li>2ecb357: <code>connectGitHubCredentials</code> now resolves the
GitHub App slug from the connector's metadata and exposes it as
<code>appSlug</code> on the returned credentials, so eve's
<code>githubChannel</code> can derive its invocation token
(<code>botName</code>) without extra configuration.</li>
</ul>
<h2>2.0.0</h2>
<h3>Major Changes</h3>
<ul>
<li>42938f9: Make Eve connector provisioning opt-in with
<code>autoProvision: true</code>. When enabled, try token and
authorization requests before provisioning, then provision and retry
once only when the connector is missing or not linked to the
project.</li>
</ul>
<h2>1.1.0</h2>
<h3>Minor Changes</h3>
<ul>
<li>b9fab7c: Add Sendblue credential helpers for Eve-native channels and
the Chat SDK adapter, including Connect trigger-forwarded webhook
verification for Chat SDK users.</li>
</ul>
<h2>1.0.0</h2>
<h3>Major Changes</h3>
<ul>
<li>9b55136: Default omitted scopes to <code>['*']</code> in token and
authorization requests.</li>
</ul>
<h3>Minor Changes</h3>
<ul>
<li>4199902: Send Vercel API requests to the region from
<code>VERCEL_REGION</code>, with a <code>region</code> option to
override it.</li>
</ul>
<h2>0.9.0</h2>
<h3>Minor Changes</h3>
<ul>
<li>46a5aaa: Add Linq helpers for Eve and Chat SDK applications.
<code>connectLinqCredentials</code> resolves an app-scoped Linq API key,
and <code>connectLinqAdapter</code> adds trusted Connect OIDC
verification for trigger-forwarded Linq webhooks while retaining the
provider signing secret within Connect.</li>
</ul>
<h2>0.8.1</h2>
<h3>Patch Changes</h3>
<ul>
<li><code>@​vercel/oidc</code><a
href="https://github.com/3"><code>@​3</code></a>.8.5</li>
</ul>
<h2>0.8.0</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/vercel/vercel/commits/@now/next@2.3.3/packages/connect">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-01 14:44:00 -07:00
Devin FoleyandPaperclip f2e0f19630 Defer agent directory cleanup until stop proof is available (#14866)
## Thinking Path

> - Paperclip manages agents and their persistent files.
> - Each run owns a temporary agent directory and a save receipt.
> - Cleanup needs independent proof that the owning process stopped.
> - A cleanup call without that proof currently waits for the directory
lock anyway.
> - A second lock failure can prevent environment release after the run
already reported a failed save.
> - This change skips cleanup that has no authority and retries
unavailable remote copies after exact destruction proof.
> - The save failure stays visible. Existing lock owners remain
protected.

## Linked Issues or Issue Description

Related work: Refs #14787 (lock diagnostics), #14695 (warm instruction
ownership), #9667 (stale lock proposal), and #9872 (control-plane
ownership proposal). I checked open PRs and issues. This change leaves
the shared filesystem lock protocol in place and does not duplicate the
warm-retention work in #14695.

**What happened?**

Heartbeat cleanup records an explicit unavailable instruction-save
warning, then calls directory release before releasing the environment
lease. Release can wait for a lock even though the copy has no
process-stop proof and cannot be removed. That secondary timeout
prevents the following lease-release step. If destruction proof arrives
later, the unavailable copy is excluded from both recovery queries.

**Expected behavior**

Skip a release that cannot remove anything. Preserve the failed-save
receipt and candidate fields. Once exact remote destruction is recorded,
recover remote cleanup without running a provider command. Unavailable
local copies retain their potentially uncollected edits even if local
stop proof arrives later. A blocked cleanup must not prevent cleanup for
other agents.

**Steps to reproduce**

1. Prepare an agent directory, report its save unavailable, and leave
process-stop proof absent.
2. Hold the shared directory lock and call release. Before this change,
release waits and fails although removal is not authorized.
3. Record destruction of the copy's exact remote lease. Before this
change, neither recovery sweep selects the unavailable copy.

**Paperclip version or commit**

Reproduced against `efc2e6810e9bc0dc8cb412b0e7647c0db9821caa`.

**Deployment mode**

Local and remote execution with persistent agent directories. Tests use
an isolated embedded PostgreSQL database and fixture transports.

## What Changed

- Re-read receipts and skip release before lock acquisition when stop
proof is absent, the copy is superseded, or cleanup is complete. Keep
the same checks inside the lock.
- Recover unavailable remote copies only after exact destruction proof.
Preserve their unavailable state, errors, candidate hash, and candidate
bytes. Keep unavailable local copies and their uncollected edits
unchanged.
- Store destruction-only cleanup authority with the stop proof. Later
cleanup honors it after a lost database response or restart, including
when a transport remains cached.
- Defer failed or unproven cleanup with bounded batches and a retry
delay. Keep failed cleanup visible in logs and its receipt.
- Serialize preparation of an existing run with cleanup. Fresh run
preparation keeps its existing admission path.
- Cover held locks, receipt scope, delayed proof, batch fairness, lost
update responses, cached transports, and concurrent same-run preparation
with database regressions.

## Verification

- Focused directory, legacy instruction-copy, shared lock, and bounded
diagnostic suites: 169 tests passed across four files.
- `pnpm -r typecheck`: passed on the final source.
- `pnpm build`: passed on the final source.
- Completed all selected local `pnpm test:run` groups: 733 general
server suites, 149 serialized suites, and 14 workspace projects. There
are 13 known macOS `EACCES` failures in the unchanged runtime skill
cache tests. Their exact signatures match earlier clean-base results,
and the cache source and test blobs match both that base and this PR
base (existing fix: #14290). One CLI import test timed out under
concurrent load; its full file passed separately (17 tests). Broad
coverage began before the review corrections; the final source has the
focused 169-test run, typecheck, and build. This is a local verification
limit, not a passing full local suite.
- `git diff --check` and local Gitleaks plus private-identifier/PII diff
scans passed.
- Independent review of the final source found no remaining actionable
issue. Its 17 targeted tests cover crash recovery, cached transports,
same-run preparation, real local edit preservation, proof scope, and
batch fairness. The main focused run also covers contained scheduling
failures.
- Final commit `35a24085f7`: Greptile 5/5 with no recommendations and
zero unresolved review threads.
- Final commit `35a24085f7`: all 53 checks passed, including Canary Dry
Run and the security scan; two visual checks were intentionally skipped.
The workspace shard passed on retry after GitHub reported that its first
runner lost communication. An earlier Canary runner shut down after the
release dry run passed. Neither interruption recorded an application
assertion failure; the exact final-head checks are now green.

## Risks

- This repairs cleanup ordering and recovery eligibility. It does not
repair an ambiguous legacy lock owner or restore unsaved files. Actual
collection still fails visibly when its lock cannot be acquired.
- An unavailable remote copy is recovered only after exact destruction
proof. A stopped but retained environment stays protected; recovery does
not execute a command that could restart it.
- Unavailable local copies with later stop proof still retain
potentially uncollected edits. A general local recollection or
reclamation policy remains outside this change.
- Existing-run preparation now waits for the same lock as cleanup. The
fresh-run path is unchanged.
- The cleanup mode is stored in the existing private receipt JSON. No
schema migration or public API change is required.
- No deployment, task replay, or runtime lock deletion was performed.

## Model Used

OpenAI GPT-6 (Codex), with reasoning, repository tools, and test
execution. The runtime does not expose a more specific model suffix 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
#` 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 references)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id
- [ ] 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-01 14:28:47 -07:00
DottaandPaperclip 4039d4f06b fix(auth): allow scoped low-trust work and owner-chat instruction edits (#14870)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Low-trust agents must work within their assigned scope.
> - Task creation currently rejects these agents before checking
assignment permission or scope.
> - Persistent instruction saves also reject direct requests from
authorized chat owners.
> - This PR checks the requested action and its recorded authority
instead of denying all such work.
> - Agents can organize permitted work and follow their owner's
instruction-edit requests while outside work stays restricted.

## Linked Issues or Issue Description

**What happened?**

Low-trust agents cannot create self-assigned tasks or subtasks, even
within their allowed scope. An authorized user also cannot ask an agent
in their own Agent Chat to update its managed `AGENTS.md`. Agent-folder
collection can hide the permission rejection behind a generic save
failure.

**Expected behavior**

Allow task creation when assignment permissions and project or root-task
scope permit it. Allow instruction self-edits during authenticated
owner-chat execution, subject to the user's current edit permission.
Outside tasks, subtasks, connector messages, and peer agents do not
inherit that instruction authority. Explain the actual denial when a
save fails.

**Steps to reproduce**

1. Configure an active agent with `low_trust_review` and a project or
root-task boundary.
2. Ask it to create an in-scope task assigned to itself, or a subtask of
its own task.
3. As a user with permission to configure that agent, ask it in your
Agent Chat to update its managed `AGENTS.md`.
4. Observe blanket permission denials rather than action-specific
checks.

**Paperclip version or commit**

Rebased onto master at `8ec4b84e1`. This is a core authorization change,
independent of adapter choice.

**Deployment mode**

Authenticated server. Regression coverage uses the server services, HTTP
routes, native tool authority, and embedded PostgreSQL.

Related work: #14775 adds human-directed task execution. #13599 concerns
instruction-path configuration; this PR leaves that configuration
restricted. #11988 proposes separate active-review instruction
protection. #10693 reports unclear authorization denials on a different
API surface.

## What Changed

- Apply task-assignment checks to both HTTP creation routes and native
task creation, including unassigned work. Preserve low-trust policy and
source attribution on the created task and its initial plan.
- Allow self-assigned decomposition within the permitted project or
root-task tree. Resolve workspace-derived project scope before
authorization, and reauthorize existing tasks before duplicate detection
returns them. Keep cross-project and peer-assignment checks.
- Derive instruction self-edit authority from the accepted run identity
and authenticated owner-message wake. Recheck current permissions at
save time. Bind retries to the same request and chat session.
- Reject inherited instruction authority from outside tasks, subtasks,
plugins, connectors, stale sessions, cancelled runs, and peer edits.
- Surface permission errors in instruction and agent-folder save
receipts. Tell chat agents to explain the rejected action and the
specific restriction.
- Update the low-trust policy and implementation documentation.

## Verification

- All 297 tests in 11 focused server suites pass after the rebase. These
cover owner-chat saves, private copies, warm agent directories, reset
and retry boundaries, permission revocation, task creation routes, and
native tool authority.
- After review fixes, all 126 tests in the four affected
authorization/chat suites pass. Workspace scope regressions and 146
existing creation/ownership/workspace-route tests also pass.
- The final duplicate-task and CI fixes pass all 39 tests across
chat-project tools, duplicate creation, environment-selection guards,
and assignee-invokability routes. The duplicate-task test reproduced an
unauthorized response before the fix and verifies denial plus permitted
reuse afterward.
- `pnpm --filter @paperclipai/server typecheck` passes after rebasing;
`pnpm --filter @paperclipai/server exec tsc --noEmit` also passes after
the review fixes.
- `git diff --check origin/master...HEAD` passes.
- Final head `7e73270b86748792649e4ae6fbc6879f73b42b73`: all 54 checks
passed, with two expected skips and no pending or failed checks. This
includes builds, typechecking, the full test matrix, end-to-end tests,
runner verification, the canary dry run, and security scans.
- Greptile is 5/5 on that exact head, with no unresolved review threads.
This change has not been deployed to staging.

## Risks

This changes authorization behavior. The instruction exception must not
become an inherited task permission. The check uses server-owned
execution records, requires the agent's own chat and instructions, and
keeps normal protected-change and responsible-user checks. Saves fail
closed when current provenance or permission is missing. Owner chat
grants a turn-scoped capability; the server does not classify the
message intent or require approval of the exact new file bytes. Prompt
injection within an authorized owner-chat turn remains a model-level
risk. This is the requested owner-chat trust boundary, without a new
per-edit confirmation flow. No database migration or broad trust-preset
change is required.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-01 15:42:40 -05:00
dependabot[bot] 793a98cd8c chore(deps): bump open from 11.0.1 to 11.0.4 (#13473)
Bumps [open](https://github.com/sindresorhus/open) from 11.0.1 to
11.0.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/sindresorhus/open/releases">open's
releases</a>.</em></p>
<blockquote>
<h2>v11.0.4</h2>
<ul>
<li>Fix <code>browser</code>/<code>browserPrivate</code> not detecting
Safari or Brave as the default browser 6ae6196</li>
</ul>
<hr />
<p><a
href="https://github.com/sindresorhus/open/compare/v11.0.3...v11.0.4">https://github.com/sindresorhus/open/compare/v11.0.3...v11.0.4</a></p>
<h2>v11.0.3</h2>
<ul>
<li>Fix Windows launches being killed when the parent process exits
734b821</li>
</ul>
<hr />
<p><a
href="https://github.com/sindresorhus/open/compare/v11.0.2...v11.0.3">https://github.com/sindresorhus/open/compare/v11.0.2...v11.0.3</a></p>
<h2>v11.0.2</h2>
<ul>
<li>Update dependencies  6f006ad</li>
</ul>
<hr />
<p><a
href="https://github.com/sindresorhus/open/compare/v11.0.1...v11.0.2">https://github.com/sindresorhus/open/compare/v11.0.1...v11.0.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/sindresorhus/open/commit/41511103abd932225b605b8e7f9e565cc180b1b6"><code>4151110</code></a>
11.0.4</li>
<li><a
href="https://github.com/sindresorhus/open/commit/6ae6196fa199cbc5eb4af007efd52e675c53b590"><code>6ae6196</code></a>
Fix <code>browser</code>/<code>browserPrivate</code> not detecting
Safari or Brave as the default b...</li>
<li><a
href="https://github.com/sindresorhus/open/commit/81deafb72a29ea16b2c3bdd30cdaf294aaa11d77"><code>81deafb</code></a>
11.0.3</li>
<li><a
href="https://github.com/sindresorhus/open/commit/734b821c36ee959dc11e380c3202770969347274"><code>734b821</code></a>
Fix Windows launches being killed when the parent process exits</li>
<li><a
href="https://github.com/sindresorhus/open/commit/ccf1fd644de3dfc9448438e185037eceb2d5d3d7"><code>ccf1fd6</code></a>
11.0.2</li>
<li><a
href="https://github.com/sindresorhus/open/commit/52d2d62d6f02f023720f4ca5a2f73bf050ae3ee7"><code>52d2d62</code></a>
Use <code>hasOwn</code> (<a
href="https://redirect.github.com/sindresorhus/open/issues/372">#372</a>)</li>
<li><a
href="https://github.com/sindresorhus/open/commit/6f006ad1a80950ff0dd9eb7e3252634153e3ef12"><code>6f006ad</code></a>
Update dependencies</li>
<li>See full diff in <a
href="https://github.com/sindresorhus/open/compare/v11.0.1...v11.0.4">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-01 13:00:29 -07:00
DottaandPaperclip 8ec4b84e1c fix(chat): resume messages after failed runs without duplicate delivery (#14857)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A user can send a new message after a native run fails.
> - The server checks that the old execution has stopped before it
starts a fresh turn.
> - A failed run can retain a result accepted before checkpoint or
cleanup failed.
> - The continuation gate treated that saved result as active recovery
and held the new message forever.
> - This pull request removes that false liveness signal while retaining
controller, process, environment, and authorization checks.
> - Live staging then exposed a second defect: chat admission created a
successor without consuming the original deferred receipt, so completion
delivered the message again.
> - Consume that exact receipt atomically with admission, while
preserving separate turns for later chat messages.

## Linked Issues or Issue Description

**What happened?**

A new user message stayed in the queue with `controller_settling` after
the previous run had reached `terminal_failure`. The old coordinator had
no lease owner but still had a `resultId`. Its remote environment had a
verified stop receipt.

**Expected behavior**

Start one fresh turn after execution has stopped and normal admission
checks pass. Preserve the failed run and its accepted result as history.

**Steps to reproduce**

1. Accept a native result, then fail checkpoint or cleanup and exhaust
recovery.
2. Retain the result ID on the terminal failure record and stop the
execution environment.
3. Send a new user message. Before this fix, it waits forever for the
finished controller.

**Paperclip version or commit**

Reproduced in a database-backed regression test on `26900655b`.

**Deployment mode**

Server with a native runner and remote sandbox. Local process stop
checks also apply.

Related: https://github.com/paperclipai/paperclip/pull/14775. Searched
existing PRs for retained-result continuation fixes; no duplicate found.

## What Changed

- Remove the retained-result veto for terminal failures.
- Keep controller ownership, successor, process, environment cleanup,
pending decision, and ordinary admission checks.
- Add regressions for retained results, active execution, missing stop
evidence, and delayed remote cleanup.
- Atomically consume the resumed receipt in agent chat, even though chat
does not coalesce other queued messages.
- Reproduce completion-time duplicate promotion, race cleanup against
periodic recovery, and prove a subsequent chat message keeps its own
turn.
- Document that a saved result does not make a terminal failure active.
- Keep exhausted workspace export on its separate repair path, tested
through the production finalizer.

## Verification

- Red: retained-result admission failed with `controller_settling`
before the original fix. The new chat-specific regression then
reproduced duplicate promotion when the first reply finished.
- Green: 406 tests across native continuation, workspace-export
recovery, and the wake-queue module passed on `cbc531cc0`.
- The chat regressions exercise real Postgres transactions, simultaneous
recovery callbacks, successful completion, the production queue-drain
use case, and repeated drain attempts. A distinct follow-up remains a
separate turn.
- `pnpm -r typecheck` and `pnpm build` passed on `cbc531cc0`.
- The earlier full local test run encountered a timeout and follow-on
failure in unchanged AI connection-adoption tests; all 50 tests passed
on isolated rerun. That local run was stopped after the full CI test
matrix passed on the earlier head.
- All 54 CI checks passed on `cbc531cc0` (2 skipped), including the full
test matrix and browser shards. One unchanged interaction-route test
returned HTTP 500 on its first CI attempt; its full 84-test file passed
locally, and the failed shard passed on one targeted rerun.
- Greptile reviewed `cbc531cc0`: 5/5, no unresolved findings.
- Live staging first verified that the original saved message resumes
and receives a successful response; that test exposed the duplicate now
covered above.
- Deployed exact commit `cbc531cc0410e1ef6e8811c6c5c014c3528351ed` to
the affected staging workspace; deployment verification, health,
authentication, and startup recovery passed.
- Submitted a fresh message through the browser. The agent replied in 39
seconds; server records show exactly one successful run, native phase
`committed`, no error, and an empty queue. A later check more than a
minute after completion found no duplicate run.

## Risks

The change affects admission after native execution failure and
consumption of a resumed deferred receipt. A fresh turn must never
overlap the prior execution, and consuming one chat receipt must not
absorb later messages. Tests retain the controller, process, and
remote-stop guards. This change does not migrate data, apply an old
result, or reset the old retry budget.

## Model Used

OpenAI Codex (GPT-6). The exact runtime model identifier and context
window are not exposed in this session. Used reasoning, repository
inspection, code execution, database-backed tests, and browser
inspection.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-01 14:43:02 -05:00
dependabot[bot] 8f7baf2f72 chore(deps): bump @aws-sdk/client-s3 from 3.1122.0 to 3.1141.0 (#13475)
Bumps
[@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-s3)
from 3.1122.0 to 3.1141.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/aws/aws-sdk-js-v3/releases">@​aws-sdk/client-s3's
releases</a>.</em></p>
<blockquote>
<h2>v3.1141.0</h2>
<h4>3.1141.0(2026-09-25)</h4>
<h5>Chores</h5>
<ul>
<li><strong>codegen:</strong> smithy-aws-typescript-codegen 0.54.0 (<a
href="https://redirect.github.com/aws/aws-sdk-js-v3/pull/8314">#8314</a>)
(<a
href="https://github.com/aws/aws-sdk-js-v3/commit/ad80ce3ebaf394679aabc6e26b2dcd023ce8e010">ad80ce3e</a>)</li>
</ul>
<h5>New Features</h5>
<ul>
<li><strong>client-connect:</strong> Agent Privacy During Hold is a new
privacy capability for Amazon Connect Voice that prevents agent audio
from being captured in call recordings or Contact Lens conversational
analytics during hold. When enabled, agents are automatically muted on
entering hold and unmuted on resuming the contact (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/03527f9ea153365c1e3654ac6d3f3e064d06b5d0">03527f9e</a>)</li>
<li><strong>client-qconnect:</strong> Release shapes for the proactive
agentic recommendations and the multi-knowledge base search features.
Increases the maximum length of QuickResponseContent. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/e008332b0b70c55d22dfca8a9c2317b67d06a5f3">e008332b</a>)</li>
<li><strong>client-bedrock-agent:</strong> Adds support for calling VPC
configuration API's in Bedrock. These configurations allow the use of On
Prem connectors in Bedrock Managed Knowledge bases (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/18524dc69cf36ebbb8bc7bc33e0bce6311dcdb23">18524dc6</a>)</li>
<li><strong>client-mediaconnect:</strong> This release adds support for
RTMP push router outputs in AWS Elemental MediaConnect. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/5bd8d80bbca2c1c2545521b03d741b46fccd09b4">5bd8d80b</a>)</li>
<li><strong>client-securityagent:</strong> This release adds the
ListActorMessages operation, which returns the multi-factor
authentication messages received at an actor's server-generated email
address (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/10e53d506db74c48b09b94d9b9387b84dd40ed58">10e53d50</a>)</li>
<li><strong>client-arc-region-switch:</strong> Adds a service quota
checker to Region switch to verify quota parity between your primary and
standby Region, and automatically submit quota limit increases. Adds an
optional EC2 Auto Scaling and ECS setting that waits for instances or
tasks in the scaled-up Region to be healthy in target groups. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/cca33e380a8985e23a0e3fbb420577aab4b60ac7">cca33e38</a>)</li>
<li><strong>client-bedrock-agentcore-control:</strong> Amazon Bedrock
AgentCore Payments now supports credential rotation for payment
connectors, letting you rotate API and wallet secrets for Quick Create
payment auths from the console. This release also adds Type and Creation
type columns to the payment managers views. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/adca591f07c448603de2876faaf7914cad441436">adca591f</a>)</li>
<li><strong>client-neptune-graph:</strong> Add GraphIdentifier filter
for ListImportTasks (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/9b9aea9b553ba84f006f95da5d8ffd5381cc8a17">9b9aea9b</a>)</li>
<li><strong>client-rekognition:</strong> This release adds support for
Feedback and Metadata in the GetFaceLivenessSessionResults response.
Feedback returns codes explaining why a Face Liveness check produced its
result. Metadata includes the client SDK type. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/0831c361bb69d44357ff57360db39afdbb149337">0831c361</a>)</li>
<li><strong>client-glue:</strong> add support for table level federation
(<a
href="https://github.com/aws/aws-sdk-js-v3/commit/a44458b77853cbb25a9fcb362b0a275d7dc1c69b">a44458b7</a>)</li>
<li><strong>client-wellarchitected:</strong> This change releases the
Well-Architected Agent, a generative AI service that analyzes a
customer's AWS environment and delivers personalized, prioritized
recommendations across cost, security, performance, and resilience. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/d0656586067f70b8d50000300f04512dd089df96">d0656586</a>)</li>
</ul>
<hr />
<p>For list of updated packages, view
<strong>updated-packages.md</strong> in
<strong>assets-3.1141.0.zip</strong></p>
<h2>v3.1140.0</h2>
<h4>3.1140.0(2026-09-24)</h4>
<h5>Documentation Changes</h5>
<ul>
<li><strong>client-route53resolver:</strong> Documentation updates for
Route 53 Resolver. Clarifies which Outpost Resolver operations apply to
first-generation AWS Outposts and that Resolver is managed automatically
on second-generation Outposts. Adds Local Network Interface subnet
compatibility notes for Resolver endpoints. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/b4432abaaaf19bf4ac5d4d2b09bcc83e4d5440a0">b4432aba</a>)</li>
<li><strong>client-iot:</strong> Fixed ListV2LoggingLevels and
DeleteV2LoggingLevel documentation to include all supported target-types
(<a
href="https://github.com/aws/aws-sdk-js-v3/commit/4dcf76d527e0c1fe76d64cb8ea444ce62d64135b">4dcf76d5</a>)</li>
</ul>
<h5>New Features</h5>
<ul>
<li><strong>clients:</strong> update client endpoints as of 2026-09-24
(<a
href="https://github.com/aws/aws-sdk-js-v3/commit/29a8566cb4c6eeb0cc554f4ae9bf985160556523">29a8566c</a>)</li>
<li><strong>client-eventbridgev2:</strong> Introducing Amazon
EventBridge enhanced Custom event bus, a new shareable event bus for
organizational-scale event-driven applications feature ordered delivery,
deduplication, open event formats, and cross-account bus sharing. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/69fbe6a22fd7810332b0b0356803a0eee3f563cf">69fbe6a2</a>)</li>
<li><strong>client-datazone:</strong> Amazon DataZone now supports the
TOOLING blueprint category on CreateEnvironmentBlueprint,
UpdateEnvironmentBlueprint, GetEnvironmentBlueprint, and
ListEnvironmentBlueprints, for custom tooling blueprints.
CreateConnection now accepts roleArn in iamProperties. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/591cd6f5a7b714427cbe87b36b13357d560d48ea">591cd6f5</a>)</li>
<li><strong>client-elasticache:</strong> Added tagging support for
ElastiCache Global DataStore. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/0fa9da5946312f09942dad6f711885855f0d0b8e">0fa9da59</a>)</li>
<li><strong>client-marketplace-discovery:</strong> AWS Marketplace
Discovery API now supports localized responses and SigV4a request
signing. It returns new fulfillment details, including AMI architecture,
EBS volume and security group information, SaaS quick-launch status, and
SageMaker input and output MIME types. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/510673e376bbc578d318308136ecb5a841416bc3">510673e3</a>)</li>
<li><strong>client-redshift-data:</strong> Updates to the ListDatabases
and WorkgroupName validation (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/218c24e106efe1ad64658984123af6634fc7278d">218c24e1</a>)</li>
<li><strong>client-securityagent:</strong> Added support for Confluence
export, enabling customers to publish security findings to Confluence
pages. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/81408527778af52f0c604a4eaca440f445082f78">81408527</a>)</li>
<li><strong>client-cloudwatch:</strong> This release adds Create, Get,
Update, and DeleteResourceMetricsConfiguration to enable detailed metric
collection for an AWS resource, and adds UpdateOTelEnrichment plus
include and exclude filters on StartOTelEnrichment so you can choose
which metric namespaces CloudWatch enriches. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/765cc1ce8f95a4f62d83dc07b81a927d74e09b52">765cc1ce</a>)</li>
<li><strong>client-eventbridge:</strong> Adds a ManagedBy field to the
DescribeEventBus and ListEventBuses responses, identifying the AWS
service that created an event bus on your behalf. (<a
href="https://github.com/aws/aws-sdk-js-v3/commit/28a639b27585c85376a4b5db528c31efb80e874d">28a639b2</a>)</li>
</ul>
<h5>Tests</h5>
<ul>
<li><strong>undici-http-handler:</strong> update bidi stream e2e test to
nova-2-sonic model (<a
href="https://redirect.github.com/aws/aws-sdk-js-v3/pull/8313">#8313</a>)
(<a
href="https://github.com/aws/aws-sdk-js-v3/commit/d9a37d9d318f2ef7f5bcf6286bf3c7b475e4175b">d9a37d9d</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-s3/CHANGELOG.md">@​aws-sdk/client-s3's
changelog</a>.</em></p>
<blockquote>
<h1><a
href="https://github.com/aws/aws-sdk-js-v3/compare/v3.1140.0...v3.1141.0">3.1141.0</a>
(2026-09-25)</h1>
<p><strong>Note:</strong> Version bump only for package
<code>@​aws-sdk/client-s3</code></p>
<h1><a
href="https://github.com/aws/aws-sdk-js-v3/compare/v3.1139.0...v3.1140.0">3.1140.0</a>
(2026-09-24)</h1>
<p><strong>Note:</strong> Version bump only for package
<code>@​aws-sdk/client-s3</code></p>
<h1><a
href="https://github.com/aws/aws-sdk-js-v3/compare/v3.1138.0...v3.1139.0">3.1139.0</a>
(2026-09-23)</h1>
<p><strong>Note:</strong> Version bump only for package
<code>@​aws-sdk/client-s3</code></p>
<h1><a
href="https://github.com/aws/aws-sdk-js-v3/compare/v3.1137.0...v3.1138.0">3.1138.0</a>
(2026-09-22)</h1>
<p><strong>Note:</strong> Version bump only for package
<code>@​aws-sdk/client-s3</code></p>
<h1><a
href="https://github.com/aws/aws-sdk-js-v3/compare/v3.1136.0...v3.1137.0">3.1137.0</a>
(2026-09-21)</h1>
<p><strong>Note:</strong> Version bump only for package
<code>@​aws-sdk/client-s3</code></p>
<h1><a
href="https://github.com/aws/aws-sdk-js-v3/compare/v3.1135.0...v3.1136.0">3.1136.0</a>
(2026-09-18)</h1>
<p><strong>Note:</strong> Version bump only for package
<code>@​aws-sdk/client-s3</code></p>
<h1><a
href="https://github.com/aws/aws-sdk-js-v3/compare/v3.1134.0...v3.1135.0">3.1135.0</a>
(2026-09-17)</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/aws/aws-sdk-js-v3/commit/5bc8d9a96936723ac90d721e0c5a2bff7ee8520d"><code>5bc8d9a</code></a>
Publish v3.1141.0</li>
<li><a
href="https://github.com/aws/aws-sdk-js-v3/commit/6050a3813c26795562b5ada8b0d9ea498eb9f8a1"><code>6050a38</code></a>
Publish v3.1140.0</li>
<li><a
href="https://github.com/aws/aws-sdk-js-v3/commit/03d54a858f80012bbc60046a77242223e8dfd9d9"><code>03d54a8</code></a>
Publish v3.1139.0</li>
<li><a
href="https://github.com/aws/aws-sdk-js-v3/commit/c68e50e4a6e0469a20c2894fe8a29c140553ebb8"><code>c68e50e</code></a>
Publish v3.1138.0</li>
<li><a
href="https://github.com/aws/aws-sdk-js-v3/commit/9a104768684e8f22d4373fcc5d910711e62676d6"><code>9a10476</code></a>
chore(codegen): sync for MetricsRecorder support and core error/retry
fixes (...</li>
<li><a
href="https://github.com/aws/aws-sdk-js-v3/commit/6b432472f9bdf5437319b9186f706e3af5c9a748"><code>6b43247</code></a>
Publish v3.1137.0</li>
<li><a
href="https://github.com/aws/aws-sdk-js-v3/commit/d6b94db8f4a00cc452dbe0aacb247e8ece3897ea"><code>d6b94db</code></a>
Publish v3.1136.0</li>
<li><a
href="https://github.com/aws/aws-sdk-js-v3/commit/2d5f18d08aa373d95692d83cb3d60a6a79248fae"><code>2d5f18d</code></a>
Publish v3.1135.0</li>
<li><a
href="https://github.com/aws/aws-sdk-js-v3/commit/0d6310bf6979ddbf737a7e15cfd8d0e7cec07063"><code>0d6310b</code></a>
Publish v3.1134.0</li>
<li><a
href="https://github.com/aws/aws-sdk-js-v3/commit/615a1ca4661ec0e4cb34b8da89fe60c2419b94d0"><code>615a1ca</code></a>
Publish v3.1133.0</li>
<li>Additional commits viewable in <a
href="https://github.com/aws/aws-sdk-js-v3/commits/v3.1141.0/clients/client-s3">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-01 11:13:22 -07:00
DottaandPaperclip 6aa0962d4f fix(mcp): include events at the subscription start boundary
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 12:44:13 -05:00
DottaandPaperclip a140d533a6 fix(mcp): preserve nullable checkout responses in event logging
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 12:41:54 -05:00
DottaandPaperclip 5aa2a6e3ae fix(mcp): release inactive monitor quotas before admission
Reclaim expired and stopped subscriptions while serializing admission. Include checkout/release status changes and suppress unchanged status writes. Cover retained quota, retry limits, late commits and native transitions.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 12:32:02 -05:00
DottaandPaperclip 93056b8ede fix(mcp): retain changes during callback verification
Bound temporary eval tunnel setup retries before provider calls and record their outcomes. Keep production callback validation unchanged.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 12:24:15 -05:00
DottaandPaperclip efc2e6810e fix: show each task once in dashboard agent cards (#14847)
## Thinking Path

> - Paperclip helps people manage AI agents and their tasks.
> - The dashboard shows recent agent activity in compact cards.
> - Those cards use run records, so two runs for one task can create
duplicate task cards.
> - An operator needs to see each task once when scanning the dashboard.
> - This pull request selects one run per linked task before it applies
the card limit.
> - The live runs page still shows each run for run inspection.

## Linked Issues or Issue Description

**What happened?**

The dashboard showed the same task in two agent cards when that task had
both an active run and a completed run.

**Expected behavior**

The dashboard should show a linked task at most once. It should keep the
active run card when one is present.

**Steps to reproduce**

1. Start an agent run for a task that already has a completed run.
2. Open the company dashboard.
3. Observe two cards linked to the same task.

**Paperclip version or commit**

Reproduced on the pre-change master at `8b4aa0692`.

**Deployment mode**

Local dev, built from source. The bug is in the core dashboard UI and
does not depend on an agent adapter or database mode.

## What Changed

- Select distinct linked tasks from capped active and recent run samples
before applying the dashboard card limit.
- Keep separate cards for runs without a linked task.
- Preserve the dashboard's count of additional distinct cards behind the
live-runs link.
- Add UI and embedded Postgres regression tests for duplicate runs and
document the dashboard rule.
- Give the existing multi-request cross-tenant authorization test enough
time on loaded CI runners.

## Verification

- `pnpm --filter @paperclipai/ui exec vitest run
src/components/ActiveAgentsPanel.test.tsx`
- `pnpm --filter @paperclipai/ui exec vitest run
src/api/heartbeats.test.ts`
- `pnpm exec vitest run server/src/__tests__/dashboard-service.test.ts
server/src/__tests__/agent-live-run-routes.test.ts`
- `pnpm exec vitest run
server/src/__tests__/agent-cross-tenant-authz-routes.test.ts`
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm --filter @paperclipai/server typecheck`
- `pnpm --filter @paperclipai/ui build`
- `pnpm -r typecheck`
- `pnpm build`
- `pnpm check:token-gates`
- Review the dashboard with an active and a completed run on the same
task. Confirm that it shows one card. Open Live agent runs to inspect
both run records.

## Risks

- A very high volume of recent runs for one task can fill the capped
sample and leave older tasks off the dashboard. The Live runs page
remains available for full run inspection.
- The dashboard may fetch up to 50 distinct run representatives to
preserve its overflow count. The default run API response and persisted
data are unchanged.

> 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-6. The runtime does not expose the exact model ID or
context window size to this task. The model used reasoning, tool calls,
and code execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [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-01 12:18:35 -05:00
DottaandPaperclip fed6d7bab8 test(mcp): cover event lifetime bounds and late activity commits
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 12:17:49 -05:00
DottaandPaperclip 56f6c416af Merge master and retain the shared Lucide compatibility fix
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 12:16:01 -05:00
DottaandPaperclip 716dacc9fa feat(mcp): deliver task events to subscribed assistants
Add MCP 2.0 discovery and signed durable task subscriptions alongside legacy tool calls. Recheck tenant and Cloud authority before delivery and exercise webhook-driven result retrieval in the paid Product E2E suite.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 12:15:40 -05:00
Devin FoleyandPaperclip 6f2ce27ca7 fix(workspaces): prepare checkouts without a local seed config (#14810)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task preparation can create an isolated Git worktree and run its
setup script.
> - The Paperclip repository setup script also prepares a seeded
development instance.
> - A server configured through environment variables can have no local
seed config.
> - This stops ordinary task preparation before the agent starts.
> - This pull request prepares checkout dependencies when no seed source
exists, while preserving errors for invalid sources and existing
development instances.
> - Tasks can start without creating or claiming a seeded development
runtime.

## Linked Issues or Issue Description

**What happened?**

A task with the Paperclip repository fails during setup when the host
has no repository-local or default instance config. The automatic
worktree provisioner requires a seed source even when the task only
needs the checkout.

**Expected behavior**

A plain checkout should prepare its dependencies without a local
development database. A missing custom source, invalid source path, or
existing development instance with a missing source should still fail.
Starting a seeded runtime must still require a valid source.

**Steps to reproduce**

1. Run an environment-configured Paperclip server without a local
instance config.
2. Add the Paperclip repository to a project.
3. Start a task that uses an isolated Git worktree without a custom
provision command.
4. Observe the setup error before agent execution.

**Paperclip version or commit**

Reproduced against `0d3e7bf6ac` with a real script subprocess and
workspace realization regression.

**Deployment mode**

Environment-configured server with external PostgreSQL.

**Additional context**

Searched open and closed GitHub PRs and issues. Related work: Refs
#14795 (seed-source diagnostics) and Refs #11733 (source validation).
This change keeps source validation and seed-readiness checks in place.

## What Changed

- Permit dependency setup when the default seed config is absent
(including the Docker image config path) and the worktree has no
development-instance state.
- Keep missing custom configs, invalid paths, and lost sources for
existing instances as errors.
- Create no config, environment file, or seed manifest for a plain
checkout.
- Keep dependency install failures visible and allow normal instance
setup once a source becomes available.
- Cover the setup script, seed-runtime refusal, and automatic server
worktree realization.
- Document the difference between checkout preparation and
seeded-runtime readiness.

## Verification

- Regression tests failed before the fix for absent-source checkout
preparation and dependency setup.
- `bash -n scripts/provision-worktree.sh`
- `node --test scripts/__tests__/provision-worktree-self-heal.test.mjs`
— 34 passed; 1 existing flock-dependent test skipped on macOS.
- Server regression — 2 passed, covering an unset config and the Docker
image default path.
- `pnpm build` — passed.
- `pnpm -r typecheck` — passed.
- All CI checks passed, including the full test shards, build,
typecheck, browser tests, and canary dry run.
- The first local `pnpm test:run` encountered two chat-test failures
because skill discovery selected an unrelated parent directory. Both
tests pass at the PR commit in a clean temporary checkout. The full
local run was not completed; the redundant clean run was stopped after
the complete CI suite passed.
- `git diff --check` and added-line secrets/PII scan passed.
- Greptile: 5/5, no comments. The branch has no merge conflicts.
- No live tenant deployment or task retry was performed.

## Risks

- A new checkout with no implicit seed config now completes dependency
setup. It has no seeded development instance. A runtime request still
fails until a valid source exists.
- Existing instances and custom source paths retain their failure
behavior. The script does not synthesize a source from environment
credentials or copy a live database.
- No schema, API, or task-setting changes. Revert the commit to restore
the previous setup behavior.

## Model Used

OpenAI Codex (GPT-6), with tool-assisted analysis, code edits, and local
tests. The runtime did not expose a verified model variant 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-01 10:00:25 -07:00
DottaandPaperclip 6395cae072 fix(runner): ship provider pack in the standard Docker image (#14854)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Remote OpenCode and ACPX runs need a provider pack from the
application build.
> - Cloud now builds its application image from the standard production
image.
> - The provider pack was added only to the legacy cloud image target.
> - The standard image therefore cannot supply the pack to downstream
Cloud images.
> - This pull request adds the pack to the production image and lets the
cloud target inherit it.
> - Remote runs can then use the pack that matches the application
source commit.

## Linked Issues or Issue Description

Refs #13827. Refs #14024.

The standard production image does not include the remote provider pack.
Downstream Cloud images inherit that omission. Remote OpenCode and ACPX
runs fail with `runner_remote_provider_artifact_incompatible` and ask
for `PAPERCLIP_RUNNER_REMOTE_PROVIDER_PACK_PATH`.

## What Changed

- Build and copy the provider pack into the standard production image.
- Set the pack path and check that an unprivileged user can read its
artifacts and execute Node.
- Let the legacy cloud target inherit the pack from production.
- Add regression checks for production packaging and cloud inheritance.
- Document stamped image behavior and the default pack path.

## Verification

- The 12 focused Docker stamp and provider-pack reuse tests pass on
commit `4a11f8d52aead55f85527c8e82c6d7f2644ce0da`.
- The new packaging regression failed against the old Dockerfile and
passed with the fix.
- On the current commit, `pnpm build` and `pnpm -r typecheck` pass. All
seven standard-image contract tests also pass.
- The current-head CI build, typecheck, test, browser, and native Runner
checks passed. The local full suite hit one chat-channel assertion
failure; that exact test passed in isolation. The remaining local run
was stopped after CI completed to avoid duplicating its full suite. An
earlier run on the pre-rebase base had a heartbeat comment batching
timeout; the external chat wait integration suite passed all 142 tests
in isolation.
- [The stamped preview image build
passed](https://github.com/paperclipai/paperclip/actions/runs/36885002850/job/110446106393),
including the production-stage provider pack build, copy, and
unprivileged artifact readability/executable check. Publication,
compatibility validation, and deployment of this exact commit to a
staging QA instance passed.
- Reproduced the exact missing-pack error on an existing staging image
with Paperclip Runner, ACPX, and Claude in a remote Daytona computer.
The legacy Claude adapter succeeds with the same account and computer.
After deploying this commit, the same native task succeeded: it computed
`5050` with a real remote shell command, wrote a proof file, read it
back in a separate call, uploaded the file as a deliverable, and
completed the task. The uploaded file contents and Done state persisted
after a page reload. The run trace confirms Paperclip Runner, ACPX, and
Claude. The first run took 2m 59s, including approximately 97s of remote
artifact preparation. A second native run read the unchanged file from
the prior run and completed successfully. Its startup took about 120s;
this verifies repeated execution and file persistence, not fast
provider-pack reuse.

## Risks

- Stamped standard images now include the provider pack and its build
cost. A pack build failure now fails the production image build.
- Unstamped local builds still skip pack generation. Setting the path
alone does not create a pack.
- No database, provider authentication, or runner verification rules
change.

## Model Used

OpenAI Codex, GPT-6. The exact serving model identifier and context
window are not exposed in this session. Capabilities used: repository
inspection, code editing, shell verification, and browser 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
- [ ] 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-01 11:07:50 -05:00
DottaandPaperclip d17bdce7a9 Keep completed connections outside pending OAuth quotas
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 11:00:25 -05:00
DottaandPaperclip fb7946a4b8 Close OAuth admission abuse paths and verify API and eval contracts
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 10:27:00 -05:00
DottaandPaperclip 4ac374103f fix(connections): repair Asana MCP and add shared-app sign-in (#14756)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Connections let agents use provider tools through the permission
gateway.
> - Asana provides an official remote MCP server, but its v2 server
requires a registered MCP OAuth app.
> - Setup can discover retired v1 endpoints and send a callback that
differs from the displayed URL.
> - This pull request repairs custom app setup and adds sign-in through
Paperclip's shared app.
> - Users can choose their own app without enrolling with Paperclip
Cloud.
> - Agents can use Asana tools after the user connects their account and
sets action permissions.

## Linked Issues or Issue Description

Related: #14739 supplies the personal credential repair used by resumed
Asana setup. No duplicate Asana authentication PR was found.

**What happened?**

Asana setup failed even with a user-created app. Root discovery metadata
still points at v1. MCP v2 uses the Asana OAuth issuer and requires an
MCP app with a client secret. Local setup also displayed a localhost
callback while an Origin header could make authorization use a numeric
loopback callback.

**Expected behavior**

Sign in with Paperclip's app when its broker profile is available. Keep
custom MCP app setup available without Cloud enrollment. Use the correct
issuer, callback, client credentials, and resource throughout setup.

**Steps to reproduce**

1. Open Asana in the connection catalog.
2. Supply an Asana MCP app's client ID and secret.
3. Start OAuth on a local instance opened with a numeric loopback
address, or resume a draft that cached v1 metadata.
4. Observe the wrong discovery endpoint or callback mismatch.

**Paperclip version or commit**

Reproduced from b54b2dc35c. Rebased onto
master at `0829d94af` after the single-screen setup change in #14811.

**Deployment mode**

Local development from source. The managed path also supports enrolled
self-hosted instances.

## What Changed

- Add the `asana.mcp` managed profile and the default Sign in with Asana
method.
- Use Asana's reviewed v2 protected-resource metadata before cached
endpoints.
- Require a custom MCP app's client secret and retain saved credentials
during setup or reconnect. Repair only the known Asana v1
issuer/resource binding, retaining company and callback checks.
- Expose a boolean for the acting user's saved client secret. The form
offers secret reuse only when that user has an active grant with the
required reference.
- Let users select their own app from the enrollment and
shared-app-unavailable screens, or from Advanced on the single-screen
setup page.
- Canonicalize HTTP loopback callbacks even when the request includes an
Origin header.
- Extend signed broker claims and provider URL validation for Asana.
Require refresh credentials on managed authorization.
- Document setup, distribution, and shared-app rollout requirements.
- Resolve permission-profile name collisions when finishing another
account. The live staging test found this after renaming the first Asana
connection; OAuth succeeded but profile finalization failed.

## Verification

- Final live staging proof used app commit
`c6053157c4e42ac017727117b754ae77fa5c45fa` and the real Cloud broker at
`767b63835170f664542afd0df99a76615e204b62`. In the embedded browser,
default shared sign-in required no client credentials, returned through
the central Cloud callback to the tenant, and discovered 39 actions. Get
me succeeded through the gateway as the selected QA agent (2.1 seconds).
The custom-app connection also returned a real result on this final
build (0.9 seconds).
- Retried the shared draft that failed during the first staging test. It
completed after the profile-name fix, retained the selected agent, and
kept the existing custom connection intact. Two database regressions
reproduced the collision before the fix and passed afterward. The
updated transaction rollback test also passes.
- Shared reconnect returned to the same staging connection with 39
actions. Earlier staging checks verified the custom-app fallback when
the shared profile was unavailable, saved-secret reuse on reconnect, and
Off blocking the action test. Allowed was restored after that check.
- Local live-provider checks also repaired a saved Asana v1
issuer/resource binding without reentering the secret and verified that
numeric-loopback setup uses the displayed localhost callback. Expiring
the local managed access-token timestamp triggered a real Asana refresh
and a successful Get me call. These early local broker tests used
enrollment/authentication and storage fixtures; the final staging proof
used deployed Cloud identity and persistent storage.
- The new production app is registered and configured, but production
sign-in has not been deployed or verified. Live provider revocation was
not run because the existing staging test app is shared with other
connections.

- After rebasing onto the single-screen setup flow, full `pnpm -r
typecheck`, `pnpm build`, and `pnpm check:token-gates` pass. Focused
verification passes 365 service and 36 broker-client tests. Broader
checks pass all 833 shared-package tests and all 530 connector-page
tests. The shared suite uses `TMPDIR=/private/tmp` to avoid macOS
temporary-directory symlinks in its canonical-path tests. The UI tests
verify the shared-app default and switching to a custom app with its
required client secret.
- Embedded-browser smoke on the current rebased build verified the
shared sign-in default, Advanced → custom app (client ID and secret
required), and switching back to Paperclip. Both existing Asana
connections remained connected after restart. No new provider
authorization was performed during this smoke.
- The full local `pnpm test:run` was interrupted when the execution
session restarted. Before interruption, it reported one runtime-slot
restart test failure. That test passed on an isolated retry after
clearing two unused PostgreSQL shared-memory segments. The full local
suite did not complete; CI must pass on the current head before merge.
- All 52 CI and security checks pass on
`9318fd4e9b616cdc3de12f40cdb9bd32d865af4c` (CI run `36882064080`),
including all eight browser shards, nine serialized-server shards,
build, typecheck, and canary dry run. Two optional Storybook checks were
skipped. Greptile review 4 reports 5/5 on this exact commit, with all
review threads resolved. Its updated summary identifies the current SHA;
this comment-triggered review did not publish a separate GitHub check
run.
- Provider revocation is unit-tested in the companion broker. Live
provider revocation was not run because the existing test app is shared
with other connections.

## Risks

- The shared Paperclip Asana MCP app has been registered with its
production callback and Any workspace distribution. Its secret is
provisioned in the production secret store, and the runtime client ID
and secret reference are configured. The production profile is enabled
in the saved deployment configuration. The companion broker has merged
and passed staging deployment; production sign-in still requires a
production deployment and live verification. Custom setup remains
available.
- Asana MCP uses the provider's fixed `default` grant. Paperclip action
policies limit agent tool use; they do not narrow provider consent.
- The callback correction affects HTTP loopback OAuth flows. Public
HTTPS callbacks retain their existing behavior.
- Reviewed discovery URLs now override stale cached endpoints. Tests
cover the Asana v1-to-v2 repair.
- No schema migration. Connection removal retains the existing
local-only revocation behavior.

## Model Used

OpenAI GPT-6 through Codex, with code execution, browser testing, and
GitHub tooling. The exact model variant and context window are not
exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-01 10:24:44 -05:00
DottaandPaperclip 826de9e6c2 Bound unauthenticated MCP registrations across replicas
Serialize registration quotas in PostgreSQL, cap retained clients, and expire unused clients and authorization requests. Preserve consented clients, grants, receipts, and audit history. Concurrent replica and active-grant retention tests pass.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 10:12:09 -05:00
DottaandPaperclip 0ea494cdaa feat(mcp): connect external assistants as company members
Add opt-in user OAuth, scoped first-party MCP tools, durable mutation receipts, consent UI, and vendor workflow packages. Preserve normal scheduling and human attribution.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-01 10:12:09 -05:00
dependabot[bot]andPriya Raman 8b4aa06920 build(deps): bump multer from 2.2.0 to 2.4.0 (#14493)
Bumps [multer](https://github.com/expressjs/multer) from 2.2.0 to 2.4.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/expressjs/multer/releases">multer's
releases</a>.</em></p>
<blockquote>
<h2>v2.4.0</h2>
<h2>Highlights</h2>
<p><strong>multer finally supports Google Cloud Functions and Firebase
🎉</strong></p>
<p>These platforms read the request body before your code runs, so
multer's classic <code>req.pipe(busboy)</code> received nothing: empty
<code>req.body</code>, empty <code>req.files</code>, and nearly a decade
of duplicated issues.</p>
<p>The new <code>streamHandler</code> option closes that gap: you decide
how the body reaches the parser, so the pre-read <code>rawBody</code>
just works (see image).</p>
<pre lang="js"><code>const multer = require('multer')
<p>const upload = multer({<br />
storage: multer.memoryStorage(),<br />
streamHandler: (req, busboy) =&gt; {<br />
// Cloud Functions / Firebase expose the pre-read body here<br />
if (req.rawBody) busboy.end(req.rawBody)<br />
else req.pipe(busboy)<br />
}<br />
})</p>
<p>app.post('/upload', upload.single('file'), (req, res) =&gt; {<br />
res.json({ name: req.file.originalname, size: req.file.size })<br />
})<br />
</code></pre></p>
<p>This landed thanks to community PRs going back to 2017; their authors
are credited as co-authors in the release.</p>
<h2>Important: Security</h2>
<ul>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-88932">CVE-2026-88932</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-3pph-fpjx-jg34">GHSA-3pph-fpjx-jg34</a>)</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>docs: remove README translations by <a
href="https://github.com/UlisesGascon"><code>@​UlisesGascon</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1463">expressjs/multer#1463</a></li>
<li>ci: add macOS to the test matrix by <a
href="https://github.com/kilisamemarisaaa"><code>@​kilisamemarisaaa</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1464">expressjs/multer#1464</a></li>
<li>feat. improve wording for LIMIT_UNEXPECTED_FILE error code by <a
href="https://github.com/flashbag"><code>@​flashbag</code></a> in <a
href="https://redirect.github.com/expressjs/multer/pull/426">expressjs/multer#426</a></li>
<li>feat: add filename to file errors by <a
href="https://github.com/UjjwalKumar239"><code>@​UjjwalKumar239</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1416">expressjs/multer#1416</a></li>
<li>refactor: remove concat-stream dependency by <a
href="https://github.com/Phillip9587"><code>@​Phillip9587</code></a> in
<a
href="https://redirect.github.com/expressjs/multer/pull/1356">expressjs/multer#1356</a></li>
<li>fix: reject non-integer fileSize limits by <a
href="https://github.com/abhu85"><code>@​abhu85</code></a> in <a
href="https://redirect.github.com/expressjs/multer/pull/1395">expressjs/multer#1395</a></li>
<li>fix: allow exactly limits.parts parts by <a
href="https://github.com/deepakganesh78"><code>@​deepakganesh78</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1446">expressjs/multer#1446</a></li>
<li>fix: do not consume maxCount for files skipped by fileFilter by <a
href="https://github.com/Sagargupta16"><code>@​Sagargupta16</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1426">expressjs/multer#1426</a></li>
<li>fix: validate all limits at construction time by <a
href="https://github.com/ShubhamOulkar"><code>@​ShubhamOulkar</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1335">expressjs/multer#1335</a></li>
<li>test: cover storage engine _removeFile invocation semantics by <a
href="https://github.com/kilisamemarisaaa"><code>@​kilisamemarisaaa</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1460">expressjs/multer#1460</a></li>
<li>feat: accept a function for limits by <a
href="https://github.com/hossein-zare"><code>@​hossein-zare</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1133">expressjs/multer#1133</a></li>
<li>fix: add flush option to disk storage to fsync files before
completion by <a
href="https://github.com/kilisamemarisaaa"><code>@​kilisamemarisaaa</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1458">expressjs/multer#1458</a></li>
<li>feat: expose busboy defCharset, highWaterMark and fileHwm options by
<a
href="https://github.com/UlisesGascon"><code>@​UlisesGascon</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1465">expressjs/multer#1465</a></li>
<li>docs: describe the file stream contract for storage engines by <a
href="https://github.com/UlisesGascon"><code>@​UlisesGascon</code></a>
in <a
href="https://redirect.github.com/expressjs/multer/pull/1468">expressjs/multer#1468</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/expressjs/multer/blob/main/CHANGELOG.md">multer's
changelog</a>.</em></p>
<blockquote>
<h2>2.4.0</h2>
<ul>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-88932">CVE-2026-88932</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-3pph-fpjx-jg34">GHSA-3pph-fpjx-jg34</a>)</li>
<li>Add <code>filename</code> to <code>LIMIT_FILE_SIZE</code> and
<code>LIMIT_UNEXPECTED_FILE</code> errors (<a
href="https://redirect.github.com/expressjs/multer/pull/1416">#1416</a>)</li>
<li>Accept a function for <code>limits</code>, called with the request,
to set limits per request (<a
href="https://redirect.github.com/expressjs/multer/pull/1133">#1133</a>)</li>
<li>Add opt-in <code>flush</code> option to <code>DiskStorage</code> to
fsync files before the callback runs (<a
href="https://redirect.github.com/expressjs/multer/pull/1458">#1458</a>)</li>
<li>Expose busboy's <code>defCharset</code>, <code>highWaterMark</code>
and <code>fileHwm</code> options (<a
href="https://redirect.github.com/expressjs/multer/pull/1465">#1465</a>)</li>
<li>Add <code>streamHandler</code> option to feed busboy from
pre-consumed bodies (Google Cloud Functions, Firebase) (<a
href="https://redirect.github.com/expressjs/multer/pull/1466">#1466</a>)</li>
<li>Allow <code>multer.diskStorage()</code> to be called without options
(<a
href="https://redirect.github.com/expressjs/multer/pull/1471">#1471</a>)</li>
<li>Decode WHATWG-escaped characters (<code>%0A</code>,
<code>%0D</code>, <code>%22</code>) in field names, matching
<code>file.originalname</code> since 2.3.0: <code>req.body</code> keys,
<code>file.fieldname</code> and <code>err.field</code> now carry the
real name. If you matched the escaped spelling as a workaround, use the
real name now (<a
href="https://redirect.github.com/expressjs/multer/pull/1473">#1473</a>)</li>
<li>Report the decoded filename in <code>err.filename</code> on
<code>LIMIT_FILE_SIZE</code> errors, matching
<code>file.originalname</code> (<a
href="https://redirect.github.com/expressjs/multer/pull/1478">#1478</a>)</li>
<li>Reject non-integer or negative <code>limits</code> values at
construction time; a float limit silently disabled the check (<a
href="https://redirect.github.com/expressjs/multer/pull/1395">#1395</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1335">#1335</a>)</li>
<li>Accept requests with exactly <code>limits.parts</code> parts;
<code>LIMIT_PART_COUNT</code> now fires only when the limit is exceeded.
If you set <code>parts</code> one higher to work around this, you can
drop the extra one (<a
href="https://redirect.github.com/expressjs/multer/pull/1446">#1446</a>)</li>
<li>Files skipped by <code>fileFilter</code> no longer count towards
<code>maxCount</code> (<a
href="https://redirect.github.com/expressjs/multer/pull/1426">#1426</a>)</li>
<li>Change the <code>LIMIT_UNEXPECTED_FILE</code> message to
&quot;Unexpected file field&quot; (<a
href="https://redirect.github.com/expressjs/multer/pull/426">#426</a>)</li>
<li>Remove the <code>concat-stream</code> dependency (<a
href="https://redirect.github.com/expressjs/multer/pull/1356">#1356</a>)</li>
<li>Docs: add JSDoc to the public API and document the storage engine
stream contract (<a
href="https://redirect.github.com/expressjs/multer/pull/1467">#1467</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1468">#1468</a>)</li>
<li>Docs: add FormData upload examples (<a
href="https://redirect.github.com/expressjs/multer/pull/896">#896</a>)</li>
<li>Docs: remove the translated READMEs (<a
href="https://redirect.github.com/expressjs/multer/pull/1463">#1463</a>)</li>
<li>Internal: run the test suite on macOS (<a
href="https://redirect.github.com/expressjs/multer/pull/1464">#1464</a>)</li>
</ul>
<h2>2.3.0</h2>
<ul>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-77078">CVE-2026-77078</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-wc9g-mqfw-jrwm">GHSA-wc9g-mqfw-jrwm</a>)</li>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-77037">CVE-2026-77037</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-qfvm-cv95-jqjf">GHSA-qfvm-cv95-jqjf</a>)</li>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-77063">CVE-2026-77063</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-qvfw-j98x-7q72">GHSA-qvfw-j98x-7q72</a>)</li>
<li>Fix <a
href="https://www.cve.org/CVERecord?id=CVE-2026-82333">CVE-2026-82333</a>
(<a
href="https://github.com/expressjs/multer/security/advisories/GHSA-535w-7cp7-47q4">GHSA-535w-7cp7-47q4</a>)</li>
<li>Add <code>MulterError</code> codes <code>INVALID_FIELD_NAME</code>
and <code>STREAM_DESTROYED</code></li>
<li>Add opt-in <code>limits.fieldArrayIndexLimit</code> to bound numeric
array indexes in field names (<a
href="https://redirect.github.com/expressjs/multer/pull/1438">#1438</a>)</li>
<li>Accept files whose size is exactly <code>limits.fileSize</code> (<a
href="https://redirect.github.com/expressjs/multer/pull/1407">#1407</a>)</li>
<li>Preserve the caller's async context (<code>AsyncLocalStorage</code>)
when calling <code>next()</code> (<a
href="https://redirect.github.com/expressjs/multer/pull/1124">#1124</a>)</li>
<li>Decode WHATWG-escaped characters (<code>%0A</code>,
<code>%0D</code>, <code>%22</code>) in <code>file.originalname</code>
(<a
href="https://redirect.github.com/expressjs/multer/pull/1421">#1421</a>)</li>
<li>Do not crash when <code>fileFilter</code> invokes its callback more
than once (<a
href="https://redirect.github.com/expressjs/multer/pull/1427">#1427</a>)</li>
<li>Use a fallback message for <code>MulterError</code> codes without a
mapping (<a
href="https://redirect.github.com/expressjs/multer/pull/1448">#1448</a>)</li>
<li>Docs: clarify <code>preservePath</code> and <code>parts</code>, use
<code>crypto.randomBytes</code> in the <code>DiskStorage</code> example
(<a
href="https://redirect.github.com/expressjs/multer/pull/1414">#1414</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1430">#1430</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1436">#1436</a>)</li>
<li>Docs: add Indonesian, Japanese and Tamil translations and refresh
all translations from the current README (<a
href="https://redirect.github.com/expressjs/multer/pull/1431">#1431</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1354">#1354</a>,
<a
href="https://redirect.github.com/expressjs/multer/pull/1462">#1462</a>)</li>
<li>Internal: run the test suite on Windows (<a
href="https://redirect.github.com/expressjs/multer/pull/1334">#1334</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/expressjs/multer/commit/35979e5afbb814bdb4b750ce028b125eb84c53af"><code>35979e5</code></a>
2.4.0 (<a
href="https://redirect.github.com/expressjs/multer/issues/1469">#1469</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/b888532fe2e10ceb13da44286448cb2bb4ce9720"><code>b888532</code></a>
chore(deps): bump github/codeql-action/upload-sarif to 4.37.9 (<a
href="https://redirect.github.com/expressjs/multer/issues/1474">#1474</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/e6bcd7db69315714fb9a38b1cd1e0f582cbce65a"><code>e6bcd7d</code></a>
chore(deps): bump github/codeql-action/analyze from 4.37.4 to 4.37.9 (<a
href="https://redirect.github.com/expressjs/multer/issues/1475">#1475</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/00dec43b394c5bfaf4efb6d0fe8467bad05525ed"><code>00dec43</code></a>
chore(deps): bump github/codeql-action/init from 4.37.4 to 4.37.9 (<a
href="https://redirect.github.com/expressjs/multer/issues/1476">#1476</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/8d5c3b72e430e7edaa2749e96dcb75bf18d84733"><code>8d5c3b7</code></a>
feat: allow diskStorage without options (<a
href="https://redirect.github.com/expressjs/multer/issues/1471">#1471</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/02f6e8265b6bf6b6921a819db3b84276efa03ed2"><code>02f6e82</code></a>
fix: report the decoded filename on LIMIT_FILE_SIZE (<a
href="https://redirect.github.com/expressjs/multer/issues/1478">#1478</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/bc3f72d5edaa19b993771348e3fb47b366316a88"><code>bc3f72d</code></a>
fix: decode escaped field names, not just filenames (<a
href="https://redirect.github.com/expressjs/multer/issues/1473">#1473</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/2661325ba8ca2a72b7fb554b63d2df51da9290c4"><code>2661325</code></a>
docs: add JSDoc to the public API (<a
href="https://redirect.github.com/expressjs/multer/issues/1467">#1467</a>)</li>
<li><a
href="https://github.com/expressjs/multer/commit/53337f9713619ef3381ee6b4e541f926dbaac305"><code>53337f9</code></a>
fix: remove late-completing uploads aborted before the engine names
them</li>
<li><a
href="https://github.com/expressjs/multer/commit/7f2c9ab5f35c0478a7b3bb0f5e1af9b536780132"><code>7f2c9ab</code></a>
feat: add streamHandler option to feed busboy from pre-consumed bodies
(<a
href="https://redirect.github.com/expressjs/multer/issues/1466">#1466</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/expressjs/multer/compare/v2.2.0...v2.4.0">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for multer since your current version.</p>
</details>
<br />

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Priya Raman <noreply@paperclip.ing>
2026-10-01 15:00:48 +00:00
DottaandPaperclip 0829d94af2 fix(auth): derive low-trust human direction from existing execution records (#14775)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Low-trust review contains work that may include hostile input.
> - Its default intake boundary currently blocks direct human chat and
tasks outside that boundary.
> - Human direction should authorize the assigned work while preserving
containment.
> - Existing conversations and execution requests already identify
direct human instructions.
> - This pull request derives exact-task authority from those records
and the current assignee.
> - The agent can perform that work without gaining access to unrelated
tasks or privileged tools.

## Linked Issues or Issue Description

**What happened?**

A low-trust agent with a project boundary rejects its owner's direct
Agent Chat before provider execution. Human-assigned tasks outside that
project fail the same check.

**Expected behavior**

An authorized human can talk to the agent or assign it a task. The exact
task runs with its existing sandbox, credential, and tool restrictions.

**Steps to reproduce**

1. Enable Agent Chat and isolated workspaces. Configure a sandbox agent
with low-trust review scoped to an intake project.
2. Send the agent a direct board chat message, or assign it a
projectless task.
3. Observe `low_trust_boundary_mismatch` before execution.

Related: #14766 adds private task directories for repo-free low-trust
execution. It is now merged into master and included in the branch base,
so CI and staging verify the combined behavior.

## What Changed

- Derive owner-chat access from existing conversation identity.
- Derive exact-task access from the existing human requester and
server-owned request origin, including coalesced requests. Plugin and
external sender attribution do not authorize work.
- Follow existing `retryOfRunId` database links for automatic
continuations, checking company, agent, and task throughout; cancelled
ancestors cannot grant authority.
- Require a live run and current assignment. Preserve sandbox,
credential, privileged-tool, responsible-user, and quarantined-output
checks.
- Retain board backlog assignments in existing request records without
starting execution. Reassignment cancels old human requests in the
common service transaction, including plugin writes; late settlement
cannot revive them.
- Add real database and HTTP coverage for request provenance, retry
ancestry, cancelled runs, concurrent reassignment, spoofing, and
containment. Document the rule.
- Preserve legacy board assignment requests through their existing
source, reason, and human requester.
- Use the existing wrapped-error helper for concurrent chat-question
idempotency; a deterministic race test reproduces the CI failure before
the fix and passes after it.
- No new schema, migrations, or user-identity fields. Existing requester
columns hold attribution.

## Verification

- Passed the focused database, policy-retention, HTTP, and reassignment
tests locally. The HTTP test creates a task through the real board route
and checks the resulting persisted wakeup before exercising agent reads,
comments, mutations, and review handoff.
- Database tests hold a reassignment transaction open to verify coherent
authorization before and after commit, with a two-connection pool. They
cover retries, coalesced requests, cancelled ancestry, invalid
cross-company/agent/task links, cycles, and forged attribution.
- Full local `pnpm -r typecheck` and `pnpm build` passed on the final
commit (`d107c26df`). [Latest-head
CI](https://github.com/paperclipai/paperclip/actions/runs/36815589542)
passed: 54 successful checks, two expected skips, including all eight
browser-test shards. Greptile is 5/5 on this exact commit with no
unresolved threads. Local tests were targeted; the full test suite ran
through CI’s test matrix.
- The revised HTTP suite passed all 13 tests; database authorization
tests passed all 11, including legacy compatibility and late watchdog
settlement; the backlog route contract passed all 3 tests. Another 102
tests covering durable chat admission, wake queues, and Cursor execution
passed.
- All 90 interaction-service tests passed with both create calls
deliberately held until their optimistic reads complete, forcing
duplicate-key recovery. That forced race failed before switching to the
shared wrapped-error helper.
- Previous staging proof covered owner chat and projectless task
persistence. The simplified revision has not been redeployed; that
earlier proof is not claimed for the new implementation.

## Risks

- This is an authorization change: only the live run's exact task
qualifies, and normal responsible-user restrictions still apply.
- Existing request and retry records are authoritative. Merely naming a
responsible/originating user or an external connector sender does not
qualify.
- Reassignment invalidates existing human request records
transactionally. A cancelled run or request cannot regain authority when
the task is assigned back.
- Ordinary task exceptions require server-owned origin or the legacy
board assignment source/reason/actor combination. Existing owner chats
use conversation identity.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-01 09:45:18 -05:00
467125fafb feat(connections): one-screen connector setup with stated defaults (#14811)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents use Connections (the Apps catalog) to act in services like
Notion, GitHub, Google Workspace and Railway
> - Each connector asked the user to answer setup questions before it
went to the provider. Most of the questions already had the correct
answer selected
> - ROADMAP.md lists "simpler setup" for Apps and Connections as ongoing
work. This change continues that work
> - This pull request removes the questions that Paperclip can answer
itself. It states the defaults in one line and moves the choices behind
"Change" and onto the Permissions tab
> - The benefit is that most connectors take one click in Paperclip and
then the provider's own consent screen

## Linked Issues or Issue Description

No public issue exists. This is the description, from the enhancement
template.

**What existing behavior does this improve?**
The setup flow for tool connectors in the Apps catalog.

**Subsystem affected**
Apps and Connections: `ui/src/features/connections`,
`ui/src/pages/apps`, the `packages/shared` app definitions, and the
OAuth routes in `server/src/routes/tool-access.ts`.

**Current behavior**
Every connector opened with an Access step. The step asked who can use
the connection and which agents get it, and both answers were already
selected. 18 connectors also asked "How do you want to connect?" when
Paperclip could rank the methods. The Google apps and Postman also asked
"What should Paperclip be able to do?" before sign-in. The four gateway
connectors (Zapier, Arcade, Composio, Executor) used a separate two-step
wizard. Asana was pinned to a customer-owned OAuth app, so the user had
to register an app in Asana's developer console. The "Set all" control
on the Permissions tab changed only one action. After the user approved
access, Railway's consent page showed "you can close this window" and
did not return to Paperclip.

**Proposed behavior**
One screen per connector, with one primary button. The screen states the
defaults in one sentence, for example "Connects for everyone in your
organization, available to all agents". A "Change" link opens one
Advanced panel. When the provider's metadata allows dynamic client
registration, Paperclip registers a client itself. Connecting lands on
the Permissions tab. On that tab, "Set all" changes every action in the
group.

**Reason and benefit**
The user makes fewer decisions before the connection exists. Most
choices are easier to make after the connection, on the Permissions tab,
where a change has an immediate effect.

**Breaking changes**
None. No schema or API change. Existing connections keep their settings.

## What Changed

- **No Access step.** `ConnectionSetupFlow` no longer has the Access
step. The flow shows the resolved default above the primary button and
on the completion screen. The access controls moved into one Advanced
panel. The panel opens automatically only when a setting in it is
required.
- **A default method for every app.** The flow always picks the ranked
default method. Alternate methods are in the Advanced panel. The Google
and Postman capability choice is not asked before sign-in. The
write-capable method is the default.
- **Gateway connectors.** `RemoteMcpProductionSetup` (Zapier, Arcade,
Composio, Executor) no longer has its own Access step. Its commit path
and the main commit path use one helper, `askFirstCatalogEntryIdsFor`,
for server-suggested defaults.
- **Dynamic registration from live metadata.**
`canRegisterOAuthClientDynamically` now allows registration when the
provider advertises a registration endpoint, even if the catalog entry
lists only customer-owned clients. The Asana and Linear definitions and
catalog text match live probes. Asana issues clients for loopback
callbacks only, so a hosted deployment still needs an Asana app.
- **Connection setup states.** New
`packages/shared/src/connection-setup-state.ts` sorts each method into
`instant`, `authorize`, `paste` or `register`. The gallery card verb
("Connect" or "Add key") comes from this resolver and the instance's
ownership availability.
- **Generic MCP.** The generic path no longer asks "Does it need a key?"
first. A credential challenge from the server shows the key field.
- **Permissions tab.** Each action row shows its risk level. Each group
has a "Set all" control. The control sends one change for the whole
group. Before, each row's save started from the same render, so the
saves overwrote each other. The Zapier/Arcade/Composio/Executor setup
screen had the same defect.
- **OAuth callback interstitial.** A cross-site browser navigation to
`/api/tools/oauth/callback` gets a small same-origin "Finishing your
connection…" page. That page repeats the request, and the repeat does
the code exchange. Railway's consent page replaces itself after about
two seconds, and the code exchange plus tool discovery takes longer than
that. The interstitial uses only a meta refresh, because the OAuth code
is single-use. Requests without `Sec-Fetch-Site: cross-site` take the
old path.
- **Linear registers through its MCP server.** Linear pins the console
endpoints at `linear.app`. Pinned endpoints now replace discovery only
when the method cannot register, or when the connection has an
operator-entered client. So a Linear connection now finds the
registration endpoint at `mcp.linear.app`.
- **Own-OAuth-app recovery stays on the one-click screen.** When the
method also accepts a customer-owned client, the client fields are in
the Advanced panel. The panel opens after a failed sign-in. "Try again"
resumes the draft with the operator's client.
- **E2E specs** follow the one-screen flow. The Access-step clicks are
removed, the specs open **Change** before they pick agents, and they
expect GitHub's **Add key** verb.
- **Default permissions do not change.** New connections still allow
every action. The user can set actions to Ask first or Off on the
Permissions tab.

## Verification

- `cd ui && npx vitest run src/pages/apps src/features/connections
--no-file-parallelism`
- `cd packages/shared && npx vitest run src/app-definitions.test.ts
src/connection-setup-state.test.ts`
- `cd server && npx vitest run src/__tests__/tool-access-service.test.ts
src/__tests__/remote-mcp-connectors.test.ts`
- `pnpm check:token-gates`
- New tests:
- `PermissionsPanel.group.test.tsx` checks that "Set all" sends one
change for the whole group. It fails on the old code.
  - `action-permissions.test.ts` checks the group update.
  - `connection-setup-state.test.ts` checks the four setup states.
- A server test checks that a cross-site callback gets the interstitial
and does not use the OAuth state, and that the same-origin repeat
completes the connection.
- Manual check on a hosted staging deployment. GitHub, Google Drive,
Composio, Notion, PostHog and Railway each connected from one screen and
returned to the Permissions tab. On Railway, "Set all" changed all 65
write actions, and the change remained after a reload.
- Visual changes: snapshot baselines are intentionally not updated. See
the `doc/design/DECISION-SHEET.md` entry "Per-change snapshot
verification demoted to dormant (Jul 13 2026)".

## Risks

- **Fewer confirmation clicks.** Organization-wide access is the
default, and the user does not confirm it on a separate step. This was
already the preselected answer. The flow shows the default before the
user clicks and again after the connection.
- **Google write scope.** Google apps now request the write-capable
scope by default. A narrower scope needs a new sign-in.
- **Dynamic registration from live metadata.** A provider can advertise
registration and then reject a redirect URI. Asana rejects hosted
callbacks, for example. In that case registration fails, and the
customer-owned client path remains available for recovery.
- **Callback interstitial.** The OAuth callback adds one same-origin
step for cross-site browser navigations. Browsers without `Sec-Fetch-*`
headers use the old direct path.
- Chat and bot connectors (Discord, Telegram, Microsoft Teams, iMessage)
do not change.

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

## Model Used

- Claude Opus 5.5 (Anthropic), model ID `claude-opus-5-5`, used through
Claude Code with tool use (shell, file editing, browser automation) and
extended thinking. It wrote the code, the tests and this description. A
human product owner directed the work and tested it by hand.

## 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: scotttong <squadbot000@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:13:47 -07:00
Devin FoleyandPaperclip 4b9a6000f7 Add bounded evidence for directory lock timeouts (#14787)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent files use directory locks during collection and cleanup.
> - A lock timeout can fail finalization after the model turn completes.
> - The timeout currently identifies no owner state or waiting
operation.
> - This pull request adds bounded evidence to the existing run failure
report.
> - Operators can distinguish a known local holder from a possible old
lock without changing lock safety.

## Linked Issues or Issue Description

**What happened?**

A directory lock timeout does not distinguish active local work from an
owner record left by an earlier process. The stored execution stage can
also precede the cleanup operation that failed.

**Expected behavior**

The failure report should identify the waiting operation and expose
bounded ownership clues. It must preserve the timeout and keep unknown
ownership protected.

**Steps to reproduce**

Hold a directory merge lock while a second caller reaches its
acquisition deadline. The regression tests exercise a live holder and an
older owner record with a live PID.

Related: #9667 proposes stale-lock recovery under a single-server
assumption. This change only adds evidence and does not adopt that
assumption. #14575 and #14665 add other run failure diagnostics.

## What Changed

- Record lock owner state, capped age and wait duration, same-process
and process-age comparisons, and whether this module holds the lock.
- Label agent-directory release, collection, checkpoint, and warm
handoff timeouts with a fixed operation code.
- Validate each field before the existing event-local Sentry report
accepts it. Exclude owner records, PIDs, paths, and absolute timestamps.
- Limit the extra diagnostic owner read to 100 ms with best-effort
abort; malformed JSON is `invalid` and unreadable owner records remain
`unknown`.
- Document the diagnostic limits and verify that contenders never
reclaim protected locks.

## Verification

- Focused lock, diagnostic, real Sentry SDK, and database-backed
agent-directory tests: 126 passed, including stalled-read and
malformed/missing/unreadable-owner regression coverage.
- Final revision `0691613dcc`: all 54 reported checks successful, with
two intentionally skipped Storybook checks. Greptile: 5/5, zero
unresolved review threads; no merge conflicts.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- `pnpm test:run`: complete suite coverage ran with the existing
repository shard flags: four general-server shards, four serialized
shards, two general-workspaces-a shards, and general-workspaces-b. The
full run is not green because of the base failures below.
- The broad run found 13 failures in the unchanged macOS skill-cache
tests. All 13 reproduce on the clean base revision. Open PR #14290
covers that existing failure.
- Two unchanged CLI archive tests hit their five-second limits during
the broad run; all 17 tests in that file pass on recheck. A CLI auth
socket error also cleared on recheck (19 tests), and its full serialized
shard passed on rerun.

## Risks

This is a diagnostic change, not a stale-lock fix. Owner observations
can race with release. Wall-clock shifts can affect the age comparison.
A local-holder flag covers only this module instance. None of these
fields authorizes reclamation or proves a file save. Lock acquisition,
release, retries, task status, and recovery guards retain their current
behavior. No schema change or deployment action is required.

## Model Used

OpenAI Codex, based on GPT-6, with code execution and repository tools.
The exact model build and context window were not exposed to this agent.

## 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 (focused checks pass;
existing base failures are documented above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 18:35:12 -07:00
DottaandPaperclip f7e36ba3e2 fix: isolate repository-free low-trust tasks in private directories (#14766)
## Thinking Path

> - Paperclip manages work by agents within company boundaries.
> - Email tasks can run under the low-trust review preset.
> - These tasks must use an isolated workspace and a sandbox.
> - The default workspace strategy assumed that the project had a Git
repository.
> - A project without a configured workspace failed before the agent
could start.
> - This change gives each such task a private directory and keeps the
sandbox requirement.

## Linked Issues or Issue Description

**What happened?**
An inbound email assigned to a low-trust agent failed with
`git_worktree_base_not_git_checkout` when its boundary project had no
configured workspace. Setup had accepted the project and sandbox.

**Expected behavior**
The agent can process email without a repository. Its workspace stays
isolated from other tasks and the shared agent home.

**Steps to reproduce**
1. Select a low-trust agent with an active sandbox and a project
boundary.
2. Leave the project without a configured workspace.
3. Receive an email through AgentMail.
4. Observe that startup fails before provider work starts.

**Paperclip version or commit**
Reproduced against `5edf55d73`.

**Deployment mode**
Hosted staging with sandbox execution.

Related: #13256 added email tasks. #13636 fixed default isolation for
projects without workspaces; the explicit isolation used by low-trust
tasks still needed this path.

## What Changed

- Select private task directories for low-trust sandbox tasks with no
configured workspace or explicit workspace strategy.
- Keep each directory scoped to its company and task. Retain files
across turns and reassignment and reject symlink paths and mismatched
workspace reuse.
- Preserve Git validation for configured workspaces and explicit
strategies, plus the existing authorization and remote gates for
referenced projects.
- Add a startup regression and directory isolation tests. Document the
supported repository-free path.

## Verification

- The startup regression failed before the fix with the same Git
validation error.
- 260 targeted email, workspace policy, heartbeat, referenced-project
and directory tests pass.
- Full `pnpm -r typecheck` and `pnpm build` pass on the latest commit.
- All CI checks, including the complete sharded test suite and canary
dry run, pass on `b4ccd9802b09b2e95499df72d48b4a3906b8c328`.
- The final commit also passes the same server shard locally: 60 files,
1,024 passed / 6 skipped tests. The earlier all-groups local run was
interrupted during follow-up edits; complete-suite verification comes
from CI on the final commit.
- Deployed the reviewed commit to staging and independently verified the
full serving SHA. Two real Codex runs in Daytona succeeded and finalized
the same private company/task workspace. The first wrote a 35-byte
marker; the second read the existing file without modifying it and
returned the independently verified SHA-256
`ce3bbeb44d07ca6822826d3a5945752a38d30b356d10829f3159a191e5aa92a6`.
- Live runtime caveat: Codex reported a nested `bwrap` loopback
permission error and used its configured escalated execution inside
Daytona. The outer Daytona sandbox remained active for both runs.
- The startup regression uses a real database, production trust checks,
workspace persistence, sandbox lease acquisition and realization, and a
fake provider. It checks reassignment and allows only an authorized
referenced project.
- The transfer regression runs production archive/sync-back/merge code
against distinct filesystem roots: create output in one sandbox, restore
it, then read and update it in a fresh sandbox. The provider I/O is
emulated; live staging verification is separate.

## Risks

- The new default applies only to low-trust sandbox tasks without
workspace configuration. Standard agents and explicit Git strategies
keep their existing behavior.
- Task directories retain work across turns and consume instance
storage. The change does not migrate or copy existing shared files.
- No database migration or credential changes are required.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 18:06:07 -05:00
Devin FoleyandPaperclip 3bbb8d0f69 Add bounded AgentMail failure diagnostics (#14768)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - AgentMail connections create inboxes and handle email tasks.
> - A failed provider request currently records only its HTTP status.
> - The same 403 can mean a permission denial, a resource limit, or
another provider restriction.
> - This pull request records a fixed operation name and a documented,
allowlisted error code.
> - Operators can distinguish these failures without exposing provider
payloads or changing retry behavior.

## Linked Issues or Issue Description

**What happened?**

An AgentMail inbox creation failure reports only `AgentMail request
failed (403)`. The response body is deliberately excluded because it can
contain private mail or credentials. That also discards the provider
code needed to identify the cause.

**Expected behavior**

Keep the HTTP failure visible with a fixed operation name and a safe
provider code. Never copy arbitrary error text, resource identifiers,
suggested fixes, or URLs into diagnostics.

**Steps to reproduce**

1. Make an inbox creation request through `agentmailApi` with a fake
provider returning HTTP 403 and `code: "missing_permission"`.
2. Observe that the old error lacks the operation and provider code.
3. With this change, verify the error includes `operation=create_inbox,
code=missing_permission`, preserves status 403, and excludes all other
response fields.

Related work: #13256 introduced the AgentMail connection. The provider
documents stable codes in its [error
reference](https://docs.agentmail.to/errors).

## What Changed

- Add a fixed method/route-to-operation map and an allowlist of
documented provider codes.
- Read at most 8 KiB for diagnostics, with a one-second deadline. Cancel
unread bodies and preserve the HTTP error if reading or parsing fails.
- Keep the existing error prefix, status, retry delay, and failure
handling.
- Add regression coverage and document the diagnostic limits.

## Verification

- `pnpm exec vitest run server/src/__tests__/agentmail-api.test.ts` — 44
tests passed.
- `pnpm build` — passed.
- `pnpm -r typecheck` — passed before the review correction. Final `pnpm
--filter @paperclipai/server exec tsc --noEmit` also passed.
- Full local `pnpm test:run` did not finish successfully; three
company-skills-service failures were observed outside the changed
module. The final-head CI server suites passed. The remaining
workspaces-b CI retry covers an unrelated HTTP/2 port collision.
- The diff passed a scan for configured secrets, private deployment
references, and non-fixture email addresses.

## Risks

- A failed request can now wait up to one extra second while reading its
diagnostic code.
- New, missing, malformed, or oversized provider codes report `unknown`.
A future provider code needs an explicit allowlist update.
- This is a diagnostics change. It does not establish or repair the
cause of an existing provider denial.
- No schema, credential policy, or retry behavior changes.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have 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 at 20853e31abacf53a32f1a63467ee208a719bbf00; the
locked-body finding is fixed and its thread resolved
- [x] I will address all Greptile and reviewer comments before
requesting merge


Final verification (September 30): all final-head GitHub checks pass at
`20853e31abacf53a32f1a63467ee208a719bbf00`, including the targeted
workspaces-b rerun after the unrelated EADDRINUSE failure. Greptile
scored 5/5 on this head and no review threads remain unresolved. The
branch is mergeable. The local full-suite run did not yield a passing
completion; CI completed successfully across all suites. This public PR
remains open for maintainer merge.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 15:29:15 -07:00