Commit Graph
8 Commits
Author SHA1 Message Date
DottaandPaperclip 27fbdb2a74 perf(workspaces): reuse verified seeds across task branches (#18159)
## Thinking Path

> - Paperclip manages AI agents and their workspaces.
> - Remote runs stage a recoverable copy of the selected host workspace.
> - New tasks use separate workspace IDs and Git branches.
> - The verified seed cache currently treats those identities as
different content.
> - This causes repeated clones and seed verification when task files
and Git commits are identical.
> - This pull request shares immutable seed content within a company and
applies each task's branch to a private archive.
> - It also removes credential broker calls for two local Git snapshot
commands.

## Linked Issues or Issue Description

**What happened?**

New remote tasks rebuild the same Git seed under different workspace IDs
and branches. In a measured staging run, preparation took 29.7 seconds.
Git clone took 6.1 seconds and optional seed publication took 7.8
seconds. Publication overlapped the 4.4-second transfer, so those values
cannot be added. Local `diff-files` and `write-tree` commands also
request GitHub credentials.

**What did you expect?**

Reuse a verified seed when filesystem contents, Git HEAD, origin, and
nested repository layout match. Preserve each task's branch, recovery
archive, ignored files, and copyback behavior. Keep local snapshot
plumbing independent of GitHub credential capture.

**Steps to reproduce**

1. Configure a remote native environment and a Git project workspace.
2. Create two tasks from the same source commit with different task
branches and workspace IDs.
3. Inspect the workspace preparation spans. Both tasks currently clone
and publish the same seed content.

**Paperclip version and deployment mode**

Reproduced on Core `25f1070fbdabd96b26cdf199e624a77905f3ca37`, with a
managed remote sandbox and native Runner. The local comparison used a
public repository at a fixed commit with roughly 13,000 entries.

Refs #17886, #16398, #16399, #17357. The Git launcher extension builds
on Jamie Buchanan's work in #17886. The other PRs establish the seed
verification, recovery, and eviction contracts preserved here. A search
found no open PR for sharing these verified seeds across task branches.

## What Changed

- Use a company-scoped cache bucket for native host-current preparation.
Keep the existing bucket and company storage limits and eviction rules.
- Remove branch names from the shared generation identity. Keep file
contents, Git HEAD, origin, and nested layout in that identity. Keep the
default workspace-scoped identity unchanged for other callers.
- Store a detached Git archive in the shared cache. Copy it and append
the selected branch metadata before upload and private per-run
persistence. Existing durable-seed replay can read the private archive
without the new cache option.
- Forward the scope through the execution target and both
command-runtime paths.
- Treat `diff-files` and `write-tree` as local Git commands. Network
commands, unknown commands, and managed commit identity keep their
existing credential path.
- Test new workspace IDs, named and detached branches, nested
repositories, dirty and ignored files, symlinks, recovery, corrupt
caches, refused publication, and copyback.

## Verification

- Current head `6087bac274d50804d1b332646e43f3b8d41d798f`: 53 checks
passed, two optional checks skipped, Greptile 5/5, no unresolved review
threads. Linux CI passed.
- Adapter-utils TypeScript 7.0.2 typecheck passed.
- Server package typecheck passed, including its Runner and plugin build
prerequisites.
- 140 seed-cache, seed-reuse, and sandbox-runtime tests passed after
rebasing.
- 44 Git launcher and command-runtime tests passed after rebasing.
- 30 native workspace preparation, warm history, and
retention-configuration tests passed. All 56 retention tests also passed
(5.72 seconds) after repairing missing library aliases inside the
installed macOS Postgres package. That local dependency repair changed
no repository source. The earlier startup timeouts occurred before test
assertions.
- The new seed reuse regression failed before the change because the
second branch cloned again. It passes through the execution target and
both command-runtime paths after the change.
- Clean local preparation comparison: two alternating measured pairs,
with an existing verified company seed and new task branches. Baseline:
19.63 and 9.85 seconds. Shared cache: 5.18 and 4.80 seconds. Median:
14.74 to 4.99 seconds. Each baseline cloned and published; each
shared-cache run skipped both. Branch and file checks passed. The
complete comparison loop took 58 seconds.
- The comparison used real Git, archives, snapshot workers, and local
file transport. It used no model calls. It does not establish a complete
staging response time. The first generation still pays the cold
preparation cost.

## Risks

- A shared cache hit requires an identical generation that is still
present. The company bucket retains the existing 16-generation/1 GiB
bucket limit; busy companies may miss more often.
- The branch binding appends entries to a private tar archive. Tests
cover the host platform; Linux CI must also pass before merge.
- A cache miss, corruption, or capacity refusal must retain the private
recovery path. Existing tests exercise those cases.
- Git plumbing can still encounter repository-specific filters or
missing objects. This extends the existing local-command policy by two
commands; it does not grant network credentials to them.
- The latest measured real staging reply took 77.8 seconds. This change
targets a bounded part of that path and does not claim the
under-15-second response goal is met.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning and repository tools. The
session does not expose the exact model revision 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-29 09:19:23 -05:00
DottaandPaperclip 7d8d1fbc1d fix(adapter-utils): provide a default author for local commits (#18094)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/209/changes/paperclip/209
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents use managed launchers for Git and GitHub commands.
> - These launchers exclude host credentials and host Git identity.
> - A checkout without an author cannot save a local commit when managed
GitHub identity is absent.
> - A local author default belongs in the launcher that owns this
isolation.
> - This pull request supplies a private Paperclip default and preserves
explicit and managed identity selection.
> - Agents can save local work without manual author setup or extra
GitHub access.

## Linked Issues or Issue Description

**What happened?**

An ordinary `git commit` fails with `Author identity unknown` in a fresh
checkout without author settings or a usable managed GitHub identity. An
agent must set its own author to continue.

**Expected behavior**

The managed launcher supplies a default local author. Repository and
command settings override that default. A current managed identity
retains its existing precedence.

**Steps to reproduce**

Run the managed launcher in a fresh Git repository without author
settings or broker credentials. Add a file, then run `git commit -m
work`.

**Paperclip version or commit**

Reproduced at `063cfd43813cabf18417605fb9eefb9aacf95c8d` on Linux with
Node 25.9.0 and pnpm 9.15.4.

**Deployment mode**

Managed sandbox execution. The shared launcher also serves local and SSH
execution that selects managed access.

Related: #16662 changes precedence for a connected GitHub account. #8945
assigns identity to managed worktrees. This repair supplies the missing
anonymous launcher default and keeps the current managed precedence. It
does not require either change.

### Hypothesis and thesis for a fix

**Hypothesis:** The launcher removes inherited author variables and host
Git config. Without a broker identity or explicit repository settings,
it has no author. Four real-Git cases reproduce the reported error on
the base revision.

**Thesis for a fix:** Put `Paperclip <noreply@paperclip.ing>` in a
private Git config for each operation. Git treats it as global config,
so repository and command settings can override it. The existing broker
environment still takes precedence. Do not store a person's identity in
shared checkout config, where it could remain after steering or
revocation. The default grants no GitHub access.

## What Changed

- Write the default author to the existing private operation directory
with mode `0600`. Remove it when the operation exits.
- Point managed Git at this file while keeping host global/system
config, credentials and SSH identity excluded.
- Add real-Git regressions for missing, absent, unavailable and rejected
access. Preserve explicit overrides, identity changes and revocation
controls.
- Verify two shell commits through normal launcher staging and a commit
after anonymous heartbeat cleanup. Check saved files, commit metadata
and temporary config cleanup.
- Update identity documentation and the two run map recipes.

## Verification

- Red: the four new local-commit cases fail on the base launcher with
`Author identity unknown`.
- Green: all 80 focused tests pass in one run across
`github-launcher.test.ts`, `github-launcher-environment.test.ts`,
`heartbeat-github-launchers.test.ts` and `native-github-access.test.ts`
(23.31 seconds).
- A controlled filesystem failure first made the candidate discard valid
managed credentials. After the correction, the same real launcher
process retains them. Default-author file failure does not change
operation-directory readiness.
- Review found a second failure: a partial write can leave invalid Git
config. The real-process test failed before the repair with `fatal: bad
config line` from `git status`. The launcher now selects the default
file only after the write succeeds. Both write-failure cases retain
managed credentials, allow status, require identity when no default is
available, and save a commit with explicit identity. The test reads the
stored commit metadata with real Git.
- Real shells, generated launchers and Git create and inspect saved
commits. Sandbox transport and broker replies use controlled fixtures.
No live cloud rollout or GitHub write acceptance is claimed.
- The isolated test process excludes inherited task launcher paths, Git
config and broker authentication variables. An initial run exposed those
test-environment inputs; the isolated replay passed. The heartbeat
assertion now checks the private default file and its cleanup instead of
expecting `/dev/null`.
- Adapter-utils typecheck and build pass. Map validation and `git diff
--check` pass.
- Conflict repair on 2026-10-29: merged master
`fa5e70faf47ef2ca20bf2daf95b7503c94469b89` into the PR branch. Resolved
19 conflict paths by retaining master for unrelated files. All seven Git
identity files remain byte-for-byte equal to the reviewed fix. The final
diff is seven files, 145 additions and 15 deletions.
- At head `c501e3f28369d404c91082b89188dc150c9362a9`, all 80 focused
tests pass again (37.53 seconds). Adapter-utils typecheck and build
pass. Map validation and migration checks pass. The PR diff passes `git
diff --check`.
- Full workspace typecheck and build were attempted again. Both stop
because this sandbox has no Rust `cargo`. The duplicate full local
Vitest run was stopped after about five minutes without a final result
while full CI was running. The earlier full local attempt was stopped
without a final result. No local full-suite pass is claimed.
- GitHub now reports the PR as mergeable. All current-head checks have
completed. [Full CI run
40878973679](https://github.com/paperclipai/paperclip/actions/runs/40878973679)
passes, including typecheck, build, Rust, test shards and all eight E2E
shards. The exact-head check inventory has 54 successes, one neutral
Paperclip Review and two Storybook skips. Snyk passes. Greptile and
Paperclip each reviewed `c501e3f28369d404c91082b89188dc150c9362a9` at
5/5 with no actionable findings. All review threads are resolved. GitHub
reports the PR as clean and mergeable.
- The prior CI run had one failed E2E test: `a lost creation response
requires reload and cannot blindly replay commands`. Its YAML parser
received page text that starts with `Skip to Main Content`. The new run
passes E2E shard 7/8 and the full E2E gate. The prior failure remains
part of this record. A passing run does not establish the earlier
failure's cause. This change does not alter that test or the agent
configuration UI.

## Risks

- Commits without explicit or managed identity now use the generic
Paperclip author. Operators can still set repository or command
identity.
- `git config --global` writes to temporary operation config and does
not persist. The documentation states this behavior.
- If the private config directory cannot be prepared, commits still need
explicit identity. Existing redacted diagnostics and credential
isolation remain.
- One small synchronous file write is added to a directory the launcher
already creates. No new subprocess, network request, persistent identity
or authority cache is added.

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

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, shell execution and tool
use. The runtime does not expose the exact model ID or context window
size 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
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-29 08:56:12 -05:00
Jamie Buchanan 3339582810 fix(adapter-utils): stop asking the GitHub broker on every local git call (#17886)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent runs use `git` and `gh` through the managed GitHub launcher.
> - The launcher asks the broker for credentials before every `git` and
`gh` call. It also asks for local commands that do not use the network,
such as `git status`.
> - Each request runs a transaction and an UPDATE in the database. On a
busy install this gives hundreds of thousands of writes each day and
long COMMIT waits.
> - This pull request stops the request for local `git` commands and
writes the identity summary only when it changes.
> - The benefit is fewer broker requests and fewer database writes. The
credential rules do not change.

## Linked Issues or Issue Description

- Fixes #17879

## What Changed

- The managed `git` launcher does not ask the broker for local
subcommands (`status`, `diff`, `log`, `rev-parse`, `add`, `config`,
`branch`, `checkout` and others). It reads past global options such as
`-C` and `-c`. An unknown subcommand or option still asks. `commit` and
`var` still ask, because the managed author comes from the broker
answer.
- The launcher keeps no broker answer between invocations, so no GitHub
credential is written to a file. The suggestion in the issue to reuse
one answer per run is not part of this pull request, because the reused
answer would have to rest on disk.
- `resolveGitHubOperationCredentials` writes
`run_identity_contexts.github` only when the summary changes.
- `doc/execution-github-identity.md` describes the behavior.

## Verification

- New launcher tests run real `git` against a fake broker that counts
POSTs. A 12-command sequence (init, status, config, rev-parse, add,
diff, commit, log, branch, show, status, diff) made 12 POSTs before and
1 POST after. The one POST is `commit`.
- The same tests check that `var`, `remote`, `fetch`, an alias, and an
unknown option still ask, and that `git var GIT_AUTHOR_IDENT` returns
the managed author.
- A new test covers the unchanged-summary write.
- `vitest run` on the launcher, launcher environment, callback bridge,
github-operation-credentials, run-identity, heartbeat-github-launchers,
native-github-access, openapi-routes, run-trust-preset,
http-log-redaction, skill-source-github-access and chat-channels tests:
12 files, 1901 passed, 1 skipped.
- `vitest run --project @paperclipai/adapter-utils` on `src`: 1903
passed, 12 skipped, 1 failed. The failure is
`sandbox-callback-bridge.test.ts`, a file this PR does not change. It
passes alone (89 of 89, three runs).
- `tsc --noEmit` passes in `packages/adapter-utils` and in `server`.
- Three deliberate breakages each made a test fail: `var` back in the
local list, the broker always asked, and the summary write skip removed.
- Not run: the full server suite and `pnpm build` (the local machine has
no `cargo` for the runner binary).

## Risks

- In a partial clone or an LFS repository, a local command that must
fetch a missing object runs without a token.
- A `git` command that is not local (`commit`, `fetch`, `push`) and
every `gh` command still asks the broker once.
- No migration. No credential is stored at rest.

## Model Used

- Claude Sonnet 5.5 (`claude-sonnet-5-5`, Anthropic) through Claude
Code, with tool use (shell, file edits, test runs), wrote the code and
tests.
- Claude Opus 5.5 (`claude-opus-5-5`, Anthropic) through Claude Code
wrote the issue text and this description.
- A person asked for the change and submits it.

## Checklist

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

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents run `git` and `gh` through a managed launcher. The launcher
gets a GitHub credential from the Paperclip control plane
> - The launcher sends one request to the credential broker for each
command
> - If that request fails at the transport level, for example after a
10-second timeout, the launcher continues without managed credentials
> - So a slow or restarting control plane removes the managed GitHub
identity from that command. Some agents then use other GitHub identities
that do not have the necessary permissions
> - This pull request retries a failed broker request two more times,
with a short backoff, before the launcher gives up
> - The benefit is that a short control-plane delay does not remove the
managed identity from an agent's GitHub operation

## Linked Issues or Issue Description

Refs #14175. That pull request changes the same broker request loop for
a different failure: sandbox network denials. The pull request that
merges second must rebase.

**What happened**
A Codex agent ran `git` and `gh` through the managed launcher while the
control plane was under heavy memory pressure. Each command printed
`Paperclip: GitHub broker_transport_unavailable; continuing without
managed credentials.` The agent then tried to open the pull request
through a different GitHub integration. GitHub rejected the request with
`403 Resource not accessible by integration`.

**Expected behavior**
A short broker delay or a short transport failure must not remove the
managed GitHub identity from the command. The launcher must try the
broker again before it continues without credentials.

**Steps to reproduce**
1. Set `PAPERCLIP_GITHUB_BROKER_URL` to a closed port.
2. Start a broker on that port after about 300 ms.
3. Run `gh` through the launcher.
4. Before this change, the launcher prints
`broker_transport_unavailable` and runs `gh` without the managed token.

**Version or commit**
`4ac374103` on master. Commit `3166e93a7` has the same code.

**Deployment mode**
Local trusted instance that runs as a launchd service, with
`codex_local` agents.

## What Changed

- `packages/adapter-utils/src/github-launcher.ts`: the broker request
loop now catches transport errors and retries up to two more times,
after 0.5 s and then after 1 s. The loop reads the response body inside
the retry, so a failed or slow body read is also retried. Busy (409)
responses keep their own budget of 30 attempts, separate from transport
retries. After the third transport failure, the launcher prints
`broker_transport_unavailable` as before.
- `packages/adapter-utils/src/github-launcher.test.ts`: two new tests
make the broker fail the first request and answer the second. In one,
the connection drops before the response. In the other, the connection
drops in the middle of the body. Each test checks that `gh` gets the
managed token, that the broker receives exactly two requests, and that
no `broker_transport_unavailable` message appears.
- The existing `broker-offline` test now has a 15-second timeout,
because each command now retries twice before it falls back.

## Verification

- `npx vitest run packages/adapter-utils/src/github-launcher.test.ts`: 9
of 9 tests pass.
- The body-read test fails on the first commit of this pull request and
passes with the second commit.
- `pnpm --filter @paperclipai/adapter-utils typecheck`: passes.
- The existing `broker-offline` test confirms that the launcher still
falls back after the retries, and that local Git still works.

## Risks

- When the broker is unreachable, each `git` or `gh` command now waits
about 1.5 s more before it continues without credentials. When the
broker times out, the worst case is about 31.5 s instead of 10 s.
- The change only adds retries. It does not change which credentials the
launcher accepts or which environment variables it copies.
- #14175 changes the same loop. The pull request that merges second
needs a small rebase.

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

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), used through Claude
Code with tool use: shell commands, file edits and test runs. The model
wrote the change, the test and this description. The repository owner
approved the change before it was made.

## Checklist

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

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 12:57:41 -07:00
Devin FoleyandPaperclip 5442f2d869 fix: repair managed Git launchers in sandbox projects (#13588)
## Thinking Path

> - Paperclip runs agents in local and remote execution environments.
> - Managed GitHub launchers select credentials for each Git operation.
> - Remote launchers are written inside the project checkout as
extensionless CommonJS scripts.
> - An ES module project makes Node interpret those launchers as ESM, so
they crash before credential resolution.
> - When the launcher can start, empty identity variables also override
valid repository and command-line Git configuration.
> - This change gives the launchers their own CommonJS scope and clears
empty identity overrides while preserving managed credential isolation.

## Linked Issues or Issue Description

**What happened?**

In a repository with `"type": "module"`, the managed `git` and `gh`
launchers fail immediately with `ReferenceError: require is not defined
in ES module scope`. The launchers use CommonJS but inherited the
enclosing project's module type.

Sandbox agents also report empty `GIT_AUTHOR_NAME` and
`GIT_COMMITTER_NAME` variables and try to unset them for each command.
With no managed identity available, the Git launcher recreated those
empty values. `git commit` failed with `fatal: empty ident name`, even
with explicit `user.name` and `user.email` configuration.

**Expected behavior**

Managed `git` and `gh` start in both ES module and CommonJS projects.
Local commits with an explicitly configured identity work without manual
environment cleanup. Managed credentials and captured identity continue
to take precedence. Missing identity does not silently select the host
user's details.

**Steps to reproduce**

1. Create a sandbox project whose `package.json` contains `"type":
"module"`.
2. Stage the managed GitHub launchers and run `git --version` or `gh
--version`. Before this fix, the launcher fails at its first
`require()`.
3. In a CommonJS project with no available managed identity, configure
repository `user.name` and `user.email`, or supply them with `git -c`.
4. Run `git commit --allow-empty -m test`. Before this fix, both
identity configuration forms fail with empty identity.

**Paperclip version or commit**

Reproduced from master commit `165b10bd9`.

**Deployment mode**

Sandbox execution. The shared launcher is also used for managed local
and SSH execution.

Related work: #13094 introduced the local-operation fallback; #13053
changes launcher discovery on Windows. Neither fixes empty identity
overrides. Related identity work in #8945 and #8946 configures worktree
authorship and does not remove these environment overrides.

## What Changed

- Stage `package.json` with `"type": "commonjs"` in the launcher
directory before the Node scripts. Keep the project's package
configuration unchanged.
- Leave inherited author and committer variables unset in the real Git
process. When credentials are absent, require explicit Git identity
configuration with `user.useConfigOnly`.
- Clear empty identity merge overrides in staged shell profiles after
environment merging. Preserve nonempty captured identity values.
- Exercise real Git commits with repository and command-line identity,
broker failures, and managed-user switching. Verify startup in ES module
and CommonJS projects, shell cleanup, and captured identity
preservation.
- Document launcher module scope and local identity behavior in the
execution GitHub identity contract.

## Verification

- Confirmed both new local-commit regression cases fail before the fix
with `fatal: empty ident name`.
- Confirmed the new ES module project regression fails before the fix
with `require is not defined in ES module scope`.
- Focused launcher and shell tests: 28 passed.
- `pnpm exec vitest run --project @paperclipai/adapter-utils --exclude
'**/dist/**'`: 1,216 passed, 11 skipped across 58 files.
- `pnpm --filter @paperclipai/adapter-utils typecheck` and `pnpm
--filter @paperclipai/adapter-utils build`: passed.
- `pnpm -r typecheck` and `pnpm build`: attempted; both stop in the
unchanged native runner because Cargo is not installed on this machine.
- Full `pnpm test:run`: started locally; stopped the duplicate run after
the complete CI suite passed. No local full-suite success is claimed.
- CI on `99ea8050e`: all 53 checks passed (2 skipped), including full
tests, typecheck, build, native runner checks, and browser checks.
- Greptile reviewed `99ea8050e`: 5/5 with no findings or unresolved
comments. GitHub reports no merge conflicts with master.
- No live sandbox or GitHub push probe performed.

## Risks

- The new package scope is confined to the run-specific launcher
directory. It does not change the project's module type, launcher names,
or credential selection.
- Without a managed identity, an explicitly configured repository author
can now create local commits. GitHub access remains subject to the
existing credential broker. Global/system Git configuration, ambient
credentials, and SSH identity remain isolated.
- Managed identity still wins over repository settings. Missing local
identity still fails instead of guessing host details.
- New or resumed executions must stage the updated launcher and shell
profiles. Existing processes retain their prior files and environment
until refreshed. No database migration or sandbox image rebuild is
required.
- Revert this change to restore the prior behavior.

## Model Used

- OpenAI GPT-6 via Codex, with code inspection, implementation, and
local test execution. The hosted model variant and context window were
not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub references)
- [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 (the affected adapter-utils
package)
- [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-17 18:40:22 -07:00
DottaandPaperclip 82f662656a fix(runner): restore legacy Git access and independent networking (#13094)
## Thinking Path

> - Paperclip runs agents for people with different GitHub accounts.
> - Managed operations must use the intended person's eligible
connection.
> - A failed duplicate connection must not hide a healthy grant for the
same account.
> - Legacy hosts also need their existing Git configuration when managed
access is not configured.
> - Runner networking and local Git operations must not depend on GitHub
broker availability.
> - This pull request separates those policies and improves failure
diagnostics.

## Linked Issues or Issue Description

**What happened?** New runs always cleared host Git credentials and
installed managed launchers. Network permission depended on GitHub
environment variables. A launcher failure could stop even local `git
status`. A newer unhealthy duplicate could take precedence over a
healthy connection, and generic health errors were shown as reconnect
requirements.

**Expected behavior:** Use a healthy eligible managed connection for the
intended account. Preserve host authentication only for unconfigured
standard-trust local or SSH execution. Permit local Git during broker
failures and keep network permission independent of GitHub credentials.

**Steps to reproduce:** Configure healthy and unhealthy grants for one
GitHub account, dispatch an agent, and execute Git commands. Separately
run an unconfigured legacy host with existing GitHub CLI authentication.
Stop the broker and run local `git status`.

**Paperclip version or commit:** Master at 668110469. **Deployment
mode:** Self-hosted. **Installation method:** Git checkout. **Agent
adapters involved:** Native Codex runner and shared adapter execution
setup. **Database mode:** Existing instance database; no migration.
**Access context:** Responsible person's managed grant, or explicitly
unconfigured legacy host. **Node.js version:** 26.4.0 locally.
**Operating system:** macOS development and Linux execution hosts.

**Relevant logs or output:** Previously `GitHub credential context
unavailable` hid configuration, transport, and capability errors. New
diagnostics identify these categories without credential values.

**Additional context:** Refs #13005 and #13022. Dependency provisioning
is addressed separately in #13093.

## What Changed

- Prefer healthy eligible grants and retry credential acquisition once
for the same principal and account before starting an operation.
- Preserve host Git configuration only when managed access is
unconfigured on a standard-trust local or SSH target.
- Project authentication mode and validated Git metadata into native
runner boundaries; refresh resumed provider settings when modes change.
- Enable network access through an explicit standard-trust controller
decision, independently of GitHub. Omitted or restricted decisions stay
disabled; replace warm providers when that decision changes.
- Run local Git with cleared credentials when the managed broker fails,
with specific redacted diagnostics.
- Retry access-refresh conflicts once without treating concurrency as
expired authorization.
- Show retry instead of reconnect for transient GitHub health failures.
Add optional authorization and run-diagnostic fields without a database
migration.

## Verification

- All latest-head CI gates are green, including typecheck, general and
serialized suites, browser tests, canary, native runner verification,
and build. Greptile is 5/5 with no remaining findings; the security scan
passed.
- Full recursive typecheck and build passed. UI token gates passed.
- Full general server run: 7,110 passed, one transient socket hangup;
that file passed on retry. All remaining workspace groups passed,
including 5,552 UI and 478 CLI tests. The complete serialized rerun
passed all 144 suites / 2,179 tests after the initial isolated timeout
passed on retry.
- 195 final launcher and native session tests passed, including
host/managed transitions, local/remote warm network-policy changes,
broker rotation, and attempts to override validated controller
filesystem roots.
- GitHub gateway fallback, duplicate connection selection, refresh
conflicts, per-user reauthorization, and native transport/security
suites passed.
- Additional live native fixtures passed SSH public-key authentication
and a Git credential helper in fresh and resumed host-mode sessions. An
unwritable managed configuration directory preserved local Git (exit 0)
while GitHub CLI failed with `configuration_directory_unavailable` (exit
4). The temporary SSH listener and keys were removed.
- Applicable Rust suites passed except two timing failures under load;
each failed case passed in isolation. The final environment contract
test passed.
- Linux native runner acceptance passed in both managed and legacy host
modes: DNS, HTTPS, npm package download, fresh-worktree Git status,
authenticated GitHub user lookup, repository read, and a new run
continuing the same provider conversation. Managed broker outage
preserved local Git and rejected authenticated access without host
fallback.
- Matching Linux server/runner artifacts and the separate provisioning
repair are deployed to the development instance. A fresh UI-dispatched
task and a new run after a server restart both passed all six shell
checks through the live controller and credential broker. Both runs
selected the expected healthy connection/grant and retained the same
provider conversation. Neither connection was repaired or reconnected.

The sandbox roots are assigned from the validated execution-target probe
**after** ordinary bindings are merged. Regression coverage supplies
forged roots and verifies they cannot override the controller paths.
Networking is enabled only for an explicit
`PAPERCLIP_RUNNER_NETWORK_ACCESS=enabled` controller decision; omitted
values remain disabled.

## Risks

Unconfigured standard-trust local and SSH runs regain access to host Git
authentication resources. Managed, sandbox, plugin, and low-trust runs
do not gain this fallback. Revoked managed access never falls back to
another account. Deploy server and runner artifacts together;
already-started operations retain their captured identity. An
unauthenticated command can still fail when it requires GitHub access.

## Model Used

OpenAI GPT-6 through Codex, with code editing, shell execution, tests,
and browser inspection. The exact model variant and context-window size
are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-09 10:15:10 -05:00
DottaandPaperclip 297d8741f5 fix: resolve duplicate connections to the same GitHub account (#13022)
## Thinking Path

> - Paperclip lets people share agents while keeping GitHub access
personal.
> - Each managed Git or GitHub operation selects an eligible connection
grant.
> - Connecting the same GitHub account twice creates two grants.
> - The old resolver counted grants and rejected them as competing
identities.
> - Managed commands then ran anonymously and reported a misleading
login failure.
> - This change compares GitHub account IDs and selects one eligible
grant for the same account.
> - The benefit is reliable access after reconnecting, with clear
diagnostics for real failures.

## Linked Issues or Issue Description

Refs #13005.

**What happened?**

Two active connections owned by one Paperclip user pointed to the same
GitHub account. Managed Git refused both as ambiguous. The agent could
not push, although the account was connected and had repository access.

**Expected behavior**

Multiple grants for the same GitHub account resolve to one eligible
authorization. Different accounts remain ambiguous. Unavailable access
explains its cause without blocking unrelated work.

**Steps to reproduce**

1. Connect the same GitHub account twice for one Paperclip user and
allow the shared agent through both connection audiences.
2. Start an instruction as that user.
3. Run managed gh or git push. Before this fix, no credential is
provided.

## What Changed

- Compare stable GitHub account IDs when more than one eligible grant
exists. Never deduplicate by login alone.
- Prefer an available grant, then the newest authorization with a stable
ID tie-breaker. Refresh and webhook timestamps do not change the
selection.
- Keep the selected credential and connection policy together. Do not
combine permissions or fall back from a dedicated account to a personal
account.
- Print the redacted unavailable reason in managed command output.
Unrelated local operations still work anonymously.
- Add database and executable launcher regressions, and document
selection behavior.

## Verification

- Final `pnpm -r typecheck` and `pnpm build` passed.
- Fourteen operation credential integration tests passed, covering
duplicate personal/dedicated grants, incomplete credentials, distinct
accounts with the same login, missing identity metadata, revocation,
membership, connection audiences, and A → B → A steering. Existing Git
credential and gateway suites and both executable launcher tests also
passed.
- The local broad test run encountered three embedded-Postgres lifecycle
timeouts and stale modules from edits made during that run. A fresh
process rerun of all four affected suites passed all 35 tests. The full
Node 24 CI test matrix passed on the final commit.
- CI passed all 31 checks on `797973b30beb16ba5fa69ed281835e1ab812b449`
(Storybook visual regression was correctly skipped). An unrelated
Company Settings UI test failed once; the focused local reproduction and
rerun of its CI shard both passed without code changes.
- Fresh Greptile review of the final commit: 5/5, with no open findings.
Security checks passed.
- Live acceptance passed with both duplicate connections enabled:
managed `gh api user` returned the expected account, managed `git push`
succeeded, and the agent created #13023 and pushed its review fixes. No
host login or credential changes were used.
- Applied the final source/compiled patch to the affected instance with
backups, after confirming no runs were active. Restarted service health
and the final resolver selection were verified. The patch is an overlay
on the existing deployment; this PR supplies the upstream fix.

## Risks

The resolver selects one authorization for an already permitted GitHub
account. It does not combine repository permissions across connections.
If the selected authorization has narrower access, that operation can
still be denied by GitHub. Different provider account IDs and unknown
duplicate identities continue to fail closed. No schema, host
credential, or connection permission changes are included.

## Model Used

OpenAI GPT-6 through Codex assisted implementation and verification with
shell, database, and browser tools. The exact model variant and
context-window size are not exposed in this session.

## Checklist


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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-07 22:43:37 -05:00
DottaandPaperclip 1cc45086d3 feat: use the responsible person's GitHub for shared agent operations (#13005)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Several people can send instructions to the same agent and task.
> - A fixed GitHub token in the provider process can keep the first
person's access after another person's message is accepted.
> - Task ownership cannot select credentials for each accepted
instruction or preserve the identity of an operation already in
progress.
> - This pull request records ordered execution identity contexts and
resolves credentials when managed Git, gh, or GitHub tools start.
> - The benefit is automatic personal GitHub access for shared agents,
with durable continuation rules and no teammate credential fallback.

## Linked Issues or Issue Description

**Subsystem affected**

Cross-cutting: orchestration, connection grants, database, runtime
adapters, native runners, and run details.

**Problem or motivation**

A shared agent must use the person whose instructions it has accepted. A
queued message must retain its author. A retry or approval without new
instructions must retain the originating identity. GitHub must remain
optional for ordinary work.

**Proposed solution**

Persist execution identity separately from task ownership. Give new
processes a run-scoped broker capability and token-free managed
launchers. Capture identity at operation start. Keep an explicit
dedicated-agent grant as an override. Show redacted diagnostics in run
details.

**Alternatives considered**

Per-task ownership, fixed provider tokens, and mutable repository author
configuration do not handle accepted steering or concurrent operations.
A manual account-selection action would add unnecessary setup to each
turn.

**Roadmap alignment**

This completes the existing Multiple Human Users, MCP Tool Gateway &
Apps, Secrets Manager, and Self-healing Runs capabilities. The
implementation follows the maintainer-approved plan.

Related work: Refs #12843, Refs #12907. Existing proposals #4618 and
#8945 cover per-agent or per-worktree author configuration. This change
instead follows the accepted human instruction across runtime types.
Refs #11831 for governed personal connection delegation; this change
preserves connection audience checks and does not use standing
delegation as a personal credential fallback.

## What Changed

- Add durable, ordered identity contexts and active run references.
Preserve message authors through consolidation, steering, retries,
delegation, approvals, routines, and restart.
- Add an authenticated operation-time GitHub credential broker and
local/remote managed git and gh launchers. Keep personal tokens out of
the long-lived provider process.
- Resolve GitHub gateway and server-side Git operations through the same
responsible-person or dedicated-grant selection rules.
- Make absent and unavailable GitHub credentials non-blocking at generic
startup. Clear host and prior-person credentials. Keep anonymous Git
access where supported.
- Add run-detail identity history and the dedicated-account warning.
Keep task ownership and queue-versus-steer decisions unchanged.
- Preserve personal OAuth declarations through connection edits. Retain
exact selected grants in the gateway.
- Fix continuation races found during real acceptance: verify a warm
owner before credential rotation, and wait for bounded durable runner
suspension before the next run starts.
- Make migrations replay-safe. Retain identity through agent/run
deletion, remove it with its company, and clean terminal launcher
directories before releasing execution environments. Document
coordinated release and rollback.

## Verification

- Full workspace typecheck, build, and token gates passed. The complete
local suite passed in its normal test groups: 17,120 passing tests,
including all 143 serialized server suites. After integrating the newly
merged runner API work, full local typecheck and build passed again,
along with 890 focused integration tests. All 31 checks on the
integrated revision passed, including build, browser E2E, release
registry, canary dry run, typecheck, security and all test suites.
Greptile is 5/5 with all review threads resolved.
- Current focused checks passed: 142 native executor tests, 67 runtime
lifecycle tests, 9 durable identity tests, 75 credential/routine tests,
19 low-trust/resumption tests, and the executable migration replay test.
- Authenticated browser acceptance with two Paperclip users and two
GitHub accounts on one shared native agent passed. Real commits and
pushes followed A → B accepted steering → queued A continuation in the
same saved conversation. GitHub commit author and committer identities
matched all three operations. Both runs succeeded and task ownership
stayed unchanged.
- Real GitHub MCP calls switched from A to B after accepted steering. A
delegated subtask retained its originating identity across a server
restart.
- Disabling B's GitHub connection left ordinary work successful. Managed
gh was unauthenticated and the provider had no inherited GH_TOKEN or
GITHUB_TOKEN.
- The browser displayed run-detail diagnostics and the exact
dedicated-account warning. A final controller-restart check followed by
another-person continuation retained the conversation, selected the
correct GitHub login and Git author, and removed each terminal launcher
directory.
- Company-lifetime migration and all five previously failing CI suites
passed locally (167 tests). Same-token gateway A → B → A and six
broker/launcher boundary tests passed.
- Remote callback, launcher, sandbox, and runtime contract tests passed.
Both native and legacy Codex completed actual Daytona executions on the
integrated revision ([campaign
results](https://github.com/paperclipai/paperclip/actions/runs/34155056509)).
The remote package-manager shim staging regression also passed locally.

## Risks

- Deploy the migrations, server broker, launchers, and runner artifacts
together. Existing processes finish with their original contract. New
managed processes need the broker endpoint for GitHub operations.
- Finish or stop new managed executions before rolling application code
back. Keep the additive schema and identity history during rollback.
- Scripts that require a persistent raw GH_TOKEN must use managed git,
gh, or GitHub gateway tools. Run capabilities authorize code executing
within that run to acquire its current identity; this is not
hostile-code isolation within one execution principal. Managed commands
prevent automatic credential carryover; arbitrary code deliberately
copying a credential is outside that boundary.
- Uncertain steering acknowledgement deliberately holds new credential
acquisition until reconciliation. Already-started operations retain
their captured identity.
- GitHub private access and provider outages can still fail the specific
operation that needs them. Dedicated grant failure does not fall back to
personal access.

## Model Used

OpenAI GPT-6 through Codex assisted implementation, review, shell
execution, and browser acceptance. The exact model variant and
context-window size are not exposed in this session. Tool use included
TypeScript and Rust tests, database integration tests, GitHub CLI, and
authenticated browser control.

## 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-07 14:32:20 -05:00