## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - People rate agent comments and documents to capture feedback. > - Feedback bundles remove credentials and personal information before export. > - The feedback scanner treats ordinary dotted text as JWTs and authentication terms as bearer tokens. > - This pull request checks encoded JWT headers and preserves known authentication terms. > - The benefit is readable feedback context with credential masking kept in place. ## Linked Issues or Issue Description Refs #12309 for the related dotted-identifier false-positive report. This PR fixes the separate feedback scanner. It does not close every case in that report. Related PR: #14318 adds fine-grained GitHub token coverage. It addresses a separate credential form and is not duplicated here. **What happened?** Feedback exports replace `api.openai.com`, dotted filenames, and public schema IDs with a JWT placeholder. They also replace the words after `bearer` in phrases such as “bearer tokens.” Five-part encrypted JWTs are only partly masked. **Expected behavior** Keep public identifiers and authentication terms readable. Mask complete credential tokens. Count only text replacements in the redaction summary. **Steps to reproduce** 1. Pass `api.openai.com` or `Use bearer tokens.` to `sanitizeFeedbackText`. 2. Check that the original text is returned and the redaction counts stay empty. 3. Pass a signed JWT or an encrypted JWT to the same function. 4. Check that the full token is replaced and one JWT replacement is counted. **Paperclip version or commit** Reproduced in the feedback scanner on master at `5e8e992df2b3d71f82091b7bbf29fd482854d9f5`. **Deployment mode** Built from source. The defect is in the shared feedback export service and does not depend on deployment mode. ## What Changed - Use the existing JWT header predicate in the feedback scanner. - Match complete three-part and five-part tokens, including direct-encryption tokens with an empty key segment. Accept short token segments in the predicate. - Preserve the closed set of authentication terms already used by the general scanner, including terms inside closing prose delimiters. - Count only replacements that change the text. - Add tests for readable context, credential masking, nested values, and redaction counts. - Document feedback text redaction. ## Verification - Focused redaction and feedback service tests: 89 tests pass across five suites. - `pnpm --filter @paperclipai/adapter-utils typecheck` passes. Full local typecheck, tests, and build were attempted. The kernel killed compiler and test processes at the sandbox memory limit of 4 GB. Serial retries and a capped Node heap still could not complete the server compiler. CI runs the full repository checks. - `git diff --check` passes. - Latest commit `0eb8d3fb4257bb79e67fab615a8299ef69230ad8`: **55 checks passed**, including full typecheck, tests, build, and E2E; two optional Storybook checks were skipped. [CI evidence](https://github.com/paperclipai/paperclip/actions/runs/38407932875). Both Greptile findings have regression tests and fixes. [Greptile gives this commit 5/5](https://github.com/paperclipai/paperclip/pull/16168#issuecomment-6146917423), with both review threads resolved. ## Risks - This changes the feedback export matching rules. Public dotted text no longer triggers credential masking by shape alone. - Explicit credential assignments, provider keys, structured secret fields, email addresses, and phone numbers remain masked. Tests cover these cases. - Existing feedback snapshots are not rewritten. No schema change or migration is needed. - The encoded-header check remains a heuristic. It is not a full JWT validator. ## Model Used OpenAI Codex, GPT-6, with reasoning, tool use, and code execution. The runtime identifies the model as GPT-6. It does not expose the exact provider deployment ID or context window size. The earlier patch and this PR preparation were AI-assisted. ## 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>
@paperclipai/adapter-utils
Shared utilities for Paperclip adapters: process spawning, environment injection, sandbox/SSH transport, workspace sync, and the round-trip helpers that move code between the local execution-workspace cwd and wherever the agent actually runs.
For the adapter-author guide see
docs/adapters/creating-an-adapter.md
and the in-repo notes at packages/adapters/AUTHORING.md.
Sandbox bridge deadlines
Command-managed bridge control operations (queue reads, input delivery, setup, and cleanup) have a host-enforced deadline of at most 30 seconds per shell command. A shorter configured timeout still applies. These operations cannot inherit the agent run's hours-long lifetime or wait forever on a provider that ignores its timeout. Long-lived agent session commands keep their own limits.
A control timeout reports a transport failure. It does not prove that the remote command stopped and does not replay an uncertain write. The process session closes failed input delivery and uses its existing shutdown path; normal execution settlement must still verify termination.
No-remote-git contract
The local execution-workspace cwd is the only persistence boundary across runs. No adapter may depend on a git remote for cross-run state.
Adapters that run the agent on a different host should use the SSH round-trip
helpers in src/ssh.ts:
prepareWorkspaceForSshExecution({ spec, localDir, remoteDir })— bundles the local cwd (tracked files, dirty edits, untracked additions, and the git history needed to reconstruct it) toremoteDirbefore the run starts. Runs with nogit remoteconfigured.restoreWorkspaceFromSshExecution({ spec, localDir, remoteDir, ... })— syncs the remote cwd back intolocalDirafter the run, including any new commits the agent created. Also runs with nogit remoteconfigured.
prepareRemoteManagedRuntime in
src/remote-managed-runtime.ts wraps both
calls for adapters that want a per-run remote workspace and an automatic
restoreWorkspace() finally hook.
The invariant is pinned by the no-remote-git contract case in
src/ssh-fixture.test.ts, which asserts that a
remote-only commit propagates to the local worktree through the
prepare → restore round-trip with no git remote configured at any point. Do
not regress that test.