## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Each task must have an isolated workspace that its agent can read. > - Older project checkouts can contain worktrees for restricted tasks. > - The source access check correctly rejects these shared checkouts. > - A fresh task then fails even when its agent can clone the project remote. > - This pull request gives fresh default tasks a separate clone of the same remote. > - The task can start while the restricted task files remain protected. ## Linked Issues or Issue Description **What happened?** Fresh tasks fail with `Task workspace access is no longer available` when their default project checkout contains a restricted task worktree. The caller has access to the new task and its remote repository. The shared local Git source is unsafe to copy. **Expected behavior** Use a separate clone of the same authorized remote for a fresh default task. Keep source access checks and responsible-user Git credentials in force. **Steps to reproduce** 1. Put a restricted task worktree inside a project checkout. 2. Assign a new default task to an agent that cannot read the restricted task. 3. Start the new task. The current source check fails before workspace creation. 4. With this fix, the task uses a separate remote source. The restricted files are absent. Later runs reuse the same owned source. Related work: Refs #15749, Refs #15528. This change keeps their source retention and workspace ownership checks. ## What Changed - Add a remote source path scoped to the company and task. - Clone through the run’s Git connection after the shared source fails its access check. - Reject reused workspaces, explicit selections, pinned branches, local sources, credential-bearing URLs, and symlink paths. - Check source access again before publishing the workspace. - Resolve later runs from the verified recorded source. Ignore leftover clones that the saved workspace does not own. - Record provenance for new implicit Git defaults. Read the current task binding before fallback. Preserve explicit, inherited and ambiguous legacy checkout choices. - Keep the effective task strategy during startup validation of matching implicit defaults. Preserve the existing explicit-selection write check. - Add regression coverage and document the fallback. ## Verification - Merged master `c8efdbfba43` and resolved both rounds of catalog/index conflicts. All upstream suites, classifications, source references and story IDs are preserved. Both fix branches combine cleanly in either merge order, with no catalog fingerprint drift. - Passed locally: 313 focused source-isolation, preparation, task-creation, binding and trust tests before the final startup fix. The final fix passes all 100 source-trust, task-binding and environment-selection tests. Earlier workspace-resolution and persisted-source suites also passed. - Real-Git regressions cover all three review findings. Reconstruction ignores an unrecorded clone and preserves unpublished commits/files. Explicit and parent-inherited checkout IDs without typed selections retain their denial and branch tips without cloning or acquiring an environment. A protected-project heartbeat completes and resumes using the task’s Git strategy with read access. Explicit selection still requires writes, and a mismatched default is rejected. - Passed: the complete Storybook catalog check with no drift errors, feature and agent map structure checks, and all 17 catalog/index script tests. The generated index counts match the merged catalog. The current upstream verification-route inventory remains unchanged. The catalog contains all 262 authored suites and 2,481 story IDs. - Passed: full workspace typecheck and build after the final guard changes, on latest head `79d2adadcb6d3d7a04b9943a91bdb8b0b6abea6d`. - Latest head `79d2adadcb6d3d7a04b9943a91bdb8b0b6abea6d`: complete CI passed (54 successful checks, two intentional skips), including the full general/serialized suites and all eight browser shards. Fresh Greptile Apex review is 5/5 on this same commit, with no unresolved findings or recommendations. The full local test command was attempted earlier without a complete aggregate result; the complete suite result is from CI. - Manual check: configure a shared project checkout with a restricted task worktree. Admit a fresh default task using the authorized remote. Confirm separate Git storage and no restricted local branch or file. Reuse, close and reopen the task workspace. Confirm that explicit, literal branch and low-trust selections retain the denied source. ## Risks - A clean remote clone excludes unpublished local work. The fallback applies only to fresh default tasks and rejects existing workspace or branch selections. - A private remote can fail to clone when the responsible user lacks Git credentials. The run then reports the failure; access checks are not bypassed. - Older untyped checkout bindings cannot prove default provenance. They keep the source denial instead of silently dropping unpublished work. - New implicit Git defaults use the existing workspace-intent contract. The source directory uses existing instance storage. No schema migration is required. ## Model Used OpenAI GPT-6, model ID `gpt-6`, through Codex. Used reasoning, repository inspection, code editing, terminal tools, and test execution. The API session does not expose an exact 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>
5.9 KiB
Project source repositories
The Create project dialog accepts a name and optional GitHub repository selections.
It uses the same RepositoryEditor as project Configuration. Description remains
editable in Configuration. Status, goal links, and target dates remain supported by
the API but are omitted from creation; Status and Goals are omitted from Configuration.
Old Overview URLs and saved Overview preferences redirect to Configuration.
API and persistence
GET /api/companies/:companyId/project-repositoriesreturnsrepositories,connectionCount, andfailedConnectionCount. Repository IDs are GitHub's stable numeric IDs represented as strings. Results are deduplicated across accessible grants and sorted by full name. Connection labels are display provenance only.POST /api/companies/:companyId/projectsaccepts optionalrepositoryIds. The server resolves new selections through the caller's authorized GitHub grants before creating the project and all repository workspaces in a transaction. The existingworkspaceinput remains supported; it cannot be combined withrepositoryIds.PUT /api/projects/:id/repositoriesaccepts the selectedrepositoryIdsarray. Accessible retained IDs refresh their canonical name and URL after renames or transfers; unavailable retained IDs keep their saved metadata. Replacement is transactional. Existing selections may be retained or removed even if their GitHub connection becomes unavailable. New identities require current access. Legacy URL workspaces are preserved, and matching legacy URLs are adopted without creating a duplicate workspace. Local/remote workspace locations survive detaching their repository.
No schema migration is required. Selected repositories are normal project workspaces
with metadata.githubRepositoryId. Existing manual repoUrl workspaces remain
editable through Configuration and the workspace API. One workspace remains primary.
Tasks materialize the other distinct repositories as editable checkouts inside their
workspace, including when no local folders are configured. Local execution and sandbox
staging use the same layout; sandbox restore preserves each repository's Git history.
See Project Repository Checkouts for paths,
ignore rules, and reuse behavior. Responsible-user credential rules still apply.
A repository selection never delegates credentials.
Fresh tasks using the default repository workspace can clone the same authorized remote into a company- and task-scoped source directory when an existing project checkout contains another task's restricted workspace. The clone uses the run's Git connection and keeps separate Git metadata. Source access checks still apply before the task workspace is published. Low-trust review runs cannot use this persistent clone fallback. This fallback does not copy unpublished local changes or replace reused workspaces, explicit workspace selections, pinned branches, or repositories that only exist on the local filesystem. Configured branch templates must derive the branch from the task identifier, ID, title, or slug. Literal or task-independent templates retain the source denial, so a fresh clone cannot replace a selected local branch with a new empty branch. New implicit Git workspace defaults record their project-source provenance. An untyped checkout binding from an older task is ambiguous and keeps the denial, including explicit checkout IDs and inherited parent sources. Admission rechecks the current binding rather than inferring a default from the selected checkout ID. Startup validation of these recorded defaults keeps the task's effective workspace strategy. It does not substitute the agent's shared strategy or grant project writes. Workspace close and reopen use the recorded isolated source. Both operations verify its company, task, repository URL, and separate Git storage before use.
Discovery and setup
The server checks company membership, grant ownership/status, and organization-grant
audiences before loading provider metadata. Connection managers receive no bypass to
another person's personal repositories. Managed GitHub grants refresh installation
access; PAT connections use paginated /user/repos. Provider failures are reported
without exposing provider error bodies or credential material. Successful connections
remain selectable when another connection fails.
ConnectionSetupFlow owns provider setup in both Apps and project dialogs. Task
intents retain their existing callback protocol. Standalone dialogs verify the saved
connection through the API after the sign-in popup returns to the instance. Project
name and repository drafts stay mounted across setup and cancellation.
UI review and verification
Proposals/Project repos contains the reviewed states, including loading, failure,
empty search, disconnected GitHub, multiple repos, legacy URLs, forty selections,
mobile, and short viewports. The configuration story composes the production page
properties through an explicit repositories slot. Story setup and saves use fixtures.
- Shared visual control:
ui/src/components/RepositoryEditor.tsx. - Data and error handling:
ProjectRepositoryInput.tsx. - Configuration persistence and legacy editing:
ProjectRepositories.tsxandLegacyProjectRepository.tsx. - Production dialog:
NewProjectDialog.tsx. - Server tests:
project-repositories.test.tsandproject-repositories-persistence.test.ts. - Browser acceptance:
tests/e2e/project-repositories.spec.ts.
The browser suite uses a real temporary server and database. It verifies creation, forty persisted repos, mobile scrolling, removal/save/reload, legacy URL editing, and rejection without a partial project. Provider discovery is simulated in the picker rejection test. GitHub network and popup behavior use deterministic fixtures in integration/component tests; the suite does not authorize a real GitHub account.