Files
PaperClipAI/maps/feature-map/projects.md
T
Nicky LeachandPaperclip 98ce93dd4e Choose project storage from compatible environments (#20587)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Projects supply repository files to agent runs through core staging
or a storage plugin.
> - A storage plugin's default claim silently attached new projects even
when their agents used a different environment.
> - An environment name or driver type does not establish shared storage
access. The existing binding and task-driver contracts do.
> - This pull request groups creation choices by that contract and
selects storage from the creator's effective environment.
> - The benefit is a visible, validated choice and a clear error before
an incompatible managed workspace operation.

## Linked Issues or Issue Description

Fixes #20459.

Related: #20156 covers a separate provider-failure diagnostic. The PR
search found no other fix for #20459. ROADMAP.md has no duplicate
project-creation change.

## What Changed

- Show **Available in** when configured environments require different
project storage. Each option names the environments that can use the
same storage owner. Hide the selector when all choices are compatible.
- Derive compatibility from repository staging and managed binding
ownership. Local, SSH, and sandbox environments use core staging.
Managed storage requires a registered task driver from the same
installed storage plugin. Separate storage plugins remain incompatible.
Unknown plugin contracts and the fake sandbox are excluded.
- Follow the creating agent's environment, or the person's primary
agent, then the instance default and local fallback. Apply managed-only
and forced Kubernetes policy. The product has no separate user or
company environment-default field today.
- Add a company-authorized discovery endpoint and an optional creation
`environmentId`. Validate the choice again on save. Store the storage
owner without overriding agent run environments. Preserve explicit API
storage choices and existing project ownership.
- Keep the hidden repository-free private-task project independent of
environment availability. Submit the observed storage owner as
`expectedStorageProviderPluginId` so a changed contract fails at save
without setting a workspace policy. Instance task-isolation defaults
stay inherited.
- Reject an incompatible managed workspace before a provider operation.
Name the storage and selected environment in the error. Add regression
tests, API documentation, creation-story fixtures, and minimal
corrections to obsolete map text.

## Verification

- **102 tests passed across 7 files:** project environment integration,
installed storage policy, repository persistence, project environment
routes, project creation telemetry routes, OpenAPI, and
NewProjectDialog. Run with `node node_modules/vitest/vitest.mjs run
server/src/__tests__/project-environments.test.ts
server/src/__tests__/project-workspace-provider.integration.test.ts
server/src/__tests__/project-repositories-persistence.test.ts
server/src/__tests__/project-routes-env.test.ts
server/src/__tests__/project-goal-telemetry-routes.test.ts
server/src/__tests__/openapi-routes.test.ts
ui/src/components/NewProjectDialog.test.tsx --silent`.
- The review fixes cover both archived-default private-task cases and
changed-storage rejection. With both instance isolation flags enabled, a
new core repository project keeps a null policy and resolves to an
isolated Git worktree. The complete affected set passes all 102 tests.
- The CI query-error policy failure was fixed by using the shared query
view. The form and shared query-view suites pass **24 tests**, including
cached choices during a transient refetch failure. `node
scripts/check-query-error-rendering.mjs --enforce --summary` reports
zero findings.
- CI exposed stale SDK source hashes and heartbeat fixtures that paired
plugin storage with Local. Refreshed exactly four shared-source hashes
with the maintained generator (runtime pins unchanged). All **53 SDK
privacy/source-proof tests**, including real built SDK output, pass. All
**7 corrected managed-storage heartbeat scenarios** pass; the fixtures
declare the owning plugin's task environment and substitute transport at
the existing execution seam.
- Shared and UI TypeScript checks pass. The UI production build passes.
`pnpm check:token-gates`, `node scripts/check-maps.mjs`, `node
scripts/check-module-boundaries.mjs`, and diff checks pass.
- Tested UI states: compatible choices, incompatible groups, default
within a group, manual override, create failure, loading, discovery
failure and retry, and an unavailable default. Tests use the production
form and existing design tokens.
- The integration tests use real isolated PostgreSQL on macOS arm64 with
Node 26.12.0. They cover user/agent defaults, storage persistence,
policy restrictions, company and authentication denials, and rejection
before a provider call. Discovery uses saved configuration and makes no
worker or provider requests.
- Local verification limits: `pnpm -r typecheck` and `pnpm build` stop
in unchanged adapter-utils code because the installed ACPX types lack
`inheritProcessEnv`. A direct server check also finds an unchanged AI
SDK type-version mismatch. The existing heartbeat test `inherits the
instance default environment across companies while preserving explicit
agent overrides` times out at line 518 on both this change and
unmodified master with the same dependencies. The full `pnpm test:run`
attempt passed all six chat shards (1,948 tests), then the Git workspace
expiration suite reported 14 failures. I stopped that broad run. Two
sampled failures reproduce on unchanged master with the same
`unknown_worktree_git_files` refusal; the other expiration failures were
not independently compared. A later broad workspace-preparation run also
hit workspace validation failures and was stopped; the seven corrected
fixture scenarios pass independently. These limits do not establish a
full local suite pass. Hosted CI remains required.
- Initial missing-package and loopback-denial failures were resolved by
repairing isolated dependency links, building the SDK, and running
database tests with loopback access. No deployed or live-provider
execution is claimed.

## Risks

- Creation defaults now follow the effective environment. A plugin's
`defaultForProjects` claim alone no longer selects storage. This is the
intended behavior change.
- Compatibility covers repository project storage. It does not guarantee
arbitrary host paths, retained-workspace moves, adapter/image support,
credentials, or worker readiness. Matching provider configs cannot prove
a cross-plugin storage contract.
- A person's primary agent supplies the personal default because there
is no separate personal environment setting. An unavailable configured
default requires a valid explicit choice or a configuration repair.
- No migration runs. Existing projects keep their storage owner. This
change does not detach existing managed data or provide a storage
migration.
- Full local verification has the limits listed above. CI and standard
Greptile review are pending.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, tool use, and code
execution. The exact serving snapshot and context-window size were not
exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-10 17:38:31 +00:00

6.0 KiB
Raw Blame History

navigation
navigation
section sectionOrder order
Projects and execution 40 10

Projects and repositories

People group tasks into projects, attach goals and repositories, and configure the context and defaults used by project work.

Feature ID: projects.

Implementation: project list, project detail.

Agent access: companion.

Sub-features

  • lifecycle: projects/lifecycle — create, name, organize, and archive projects.
  • task-context: projects/task-context — inspect project tasks and create work in the selected project.
  • repositories: projects/repositories — configure repository/workspace sources and verify usable checkouts.
  • defaults: projects/defaults — maintain project instructions, environment, goal, and budget context where offered.
  • privacy: projects/privacy — create private projects, inspect access members, and manage their audience without publishing protected tasks.

How to get to it (user POV)

project-list

Open /projects, create a project, and enter its overview or Issues view.

repository-settings

Open /projects/:projectId/configuration and its repository/workspace settings. Workspace storage shows the saved provider or Core/local choice. Plugin-backed projects retain their storage owner.

project-access

Open /projects/:projectId/configuration, use Private project, and choose Manage access or View access according to your authority. Create a private project through the supported creation surface or API when needed for a fixture.

Driving it with Playwright and the Paperclip CLI

Preconditions: follow the baseline. Use a disposable project and a small repository you can access; record checkout and credential ownership.

project-list

Automated: projects UI and project detail are component tests.

Manual: Create a project, add a task from its view, and reload. Verify the task belongs to that project, list counts are plausible, and links preserve company scope. Archive only the disposable project and inspect list/task behavior.

repository-settings

Automated: provider defaults and API overrides and storage selection UI cover saved storage, explicit overrides, and configuration errors. These offline checks do not qualify live provider storage.

Automated: repository persistence and repository browser suite cover configured repository workflows.

Manual: Attach a small repository, save, and create a project task. Inspect the actual checkout/revision used by its run. Test an invalid repository and missing credentials without treating a saved URL as a working workspace.

project-access

Automated: Privacy production review covers persisted project audience changes, task inheritance, and actor intersections. Privacy controls covers UI controls and task-cache invalidation after membership removal. These tests do not prove both people’s live navigation.

Manual: As an ordinary authenticated project owner, create a private project and task. Add another company person and an eligible agent through Manage access, reload, and inspect their project discovery and task reads. The added person can view members but cannot change the audience. Remove them, reload their session, and retry direct project/task links. Confirm removing the owner is unavailable or rejected. Add a direct grant for one private task, then open the project to the company after inspecting the confirmation. Verify the project becomes discoverable, protected tasks remain private, and project-derived task access no longer substitutes for direct task access. Test the agent and its responsible person separately.

Sources: Project properties, access members, project routes, and authorization.

Gotchas

  • A private project’s member list is readable to an authorized project reader. Task access-grant inspection has a stricter management boundary.

  • /overview now selects Configuration, not a distinct overview page. Personal join/leave and star controls have their own persistence and should be checked when affected; Star/Unstar {project name} is the visible star action.

  • Project name slugs change on rename and have no historical alias lookup. Reopen a renamed project through its stable UUID route, wait for the current Configuration form, and record the newly normalized URL before reloading.

  • Project repository configuration and a provisioned execution workspace are different records.

  • See workspaces, goals, and budgets for those features.

  • Do not assume a deleted or archived project should erase its historical task evidence.

Automatic repository skills

Creating or attaching a GitHub repository enqueues skill import without another setup step. Check Skills → Sources and the installed library afterward. Ordinary edits to older projects do not adopt their repositories; explicit adoption belongs in Sources. Removing a repository retains installed skills and originating project access but stops its automatic tracking. Changing the ref does not retarget existing skill references.

Documentation scope: Projects and execution workspaces

Provider-specific provisioning, multi-repository/submodule edge cases, Git reconciliation variants, and all service exposure combinations require deeper recipes.