mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-08 01:57:31 +01:00
## Thinking Path > - Paperclip manages AI agents and their work. > - Storage plugins own remote task workspaces. > - Run completion currently requests the same inspection used for storage cleanup. > - That inspection can fetch remote refs and scan files after the agent has finished. > - Completion needs retained workspace identity and durable writes, not permission to delete files. > - This change adds an optional completion operation and keeps maintenance inspection separate. ## Linked Issues or Issue Description **What happened?** A successful plugin-backed run can fail during completion because the storage provider performs a slow remote-recoverability inspection. Dirty or unpublished output does not need a deletion-safety proof to remain valid task output. **Expected behavior** Completion verifies the assigned workspace and confirms durable writes through the provider. Cleanup still requires the existing full inspection. **Steps to reproduce** Run a task with plugin-owned storage whose inspection fetches remote refs. Let the agent finish, then observe completion waiting for the maintenance inspection. Related context: #16428 added finalization observability. The duplicate search found no existing PR for this provider contract. ## What Changed - Add optional `workspaceProvider.finalizationVersion: 1` and strict `finalize` / `finalized` schemas. - Pass original run and agent context through live completion and recovered completion. - Give the new operation a 30-second deadline and keep ownership checks and lifecycle serialization. - Retain the inspection fallback for providers without the capability. Keep maintenance inspection and removal unchanged. ## Verification - SDK build passed. - Targeted SDK and completion unit tests: 7 passed. - Added integration coverage for capability selection, legacy fallback, maintenance separation, and failure propagation. - Local integration setup timed out starting PostgreSQL; the integration suite passed in GitHub CI. - Full build/typecheck and broader tests passed in GitHub CI (55 successful checks, 2 skipped). Local checks remained targeted as requested. - Diff reviewed for secrets and operational identifiers. ## Risks The capability is opt-in. Providers must not advertise it until their completion implementation is available. An unavailable provider or failed durability barrier remains retryable. No schema or stored-binding migration is required. Test-file size exception: the provider integration suite grows from 973 to 1,002 lines. The 29-line case follows the same prepared binding through legacy completion, opted-in completion, and maintenance inspection using the existing single-connection database fixture. Keeping it there avoids a second embedded-Postgres lifecycle for one transition test. The completion helper unit tests are in a separate focused file. ## Model Used OpenAI GPT-6 Codex, with reasoning and code/test tools. ## 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>
162 lines
8.2 KiB
Markdown
162 lines
8.2 KiB
Markdown
# Plugin Runner execution
|
|
|
|
Core can run `paperclip_runner` tasks in a plugin environment.
|
|
The plugin owns the execution host and its files.
|
|
Core owns run identity, selected policy, assigned tools, and the PRP journal.
|
|
|
|
## Required hooks
|
|
|
|
Set `supportsTasks: true` on the environment driver.
|
|
Declare the `environment.drivers.register` capability.
|
|
Implement these hooks:
|
|
|
|
- `onEnvironmentAcquireLease`
|
|
- `onEnvironmentTask`
|
|
- `onEnvironmentReleaseLease`
|
|
- `onEnvironmentDestroyLease`
|
|
|
|
Task execution does not require `onEnvironmentExecute` or
|
|
`onEnvironmentRealizeWorkspace`. The task API has no shell command or file installation
|
|
operation. Use a separate workflow to install agent files. Providers that
|
|
advertise `workspaceFileReadVersion: 1` can return task output files through the
|
|
bounded `read_file` operation for attachments and deliverables.
|
|
|
|
Core supports per-turn workspace sessions with Codex, OpenCode, and ACPX.
|
|
OpenCode and ACPX require the existing qualified provider profiles.
|
|
Workspace-free providers and warm process retention are not supported here.
|
|
The plugin owns project workspace preparation. Core does not prepare or reuse
|
|
a Core Git worktree for a task-only environment.
|
|
For plugin-backed project storage, Core uses the workspace provider contract.
|
|
The storage plugin must also provide the selected execution environment.
|
|
Its declared workspace modes and strategies remain in effect.
|
|
Core passes the pinned workspace binding with each task operation.
|
|
Core rejects configured workspace services for task-only environments.
|
|
Fresh retries that import retained files are not supported for plugin storage.
|
|
An agent-owned workspace cannot move to another agent or environment.
|
|
Core also rejects reuse of a local workspace in a task-only environment.
|
|
Keep its original owner, or use the workspace storage provider contract.
|
|
|
|
## Prepare and launch
|
|
|
|
1. Return an opaque task ID from lease acquisition as `providerLeaseId`.
|
|
2. Return the installed Runner version and SHA-256 digest from `describe`.
|
|
3. Return `launchPreparationVersion: 1` from `describe`.
|
|
4. Handle `prepare` with the [launch preparation contract](../runner-launch-preparation.md).
|
|
5. Save the result under its configuration ID.
|
|
6. Handle `submit` with that ID in `preparedLaunchId`.
|
|
7. Return an authenticated WSS endpoint from `connection`.
|
|
|
|
Preparation must not start a process. It must preserve Core's provider, model,
|
|
policy, instructions, and resource assignment identities. Resolve assigned
|
|
resources to execution-host paths. Use `bindRunnerLaunchResources` and
|
|
`createRunnerProviderLaunch` when the built-in descriptor builder is suitable.
|
|
|
|
Core checks the returned requirements digest and descriptor before it registers
|
|
PRP or submits the task. A failed check does not enable a fallback launch.
|
|
Recovery within the same run must return the exact saved configuration.
|
|
|
|
The plugin supplies executable paths and the provider workspace in the
|
|
descriptor. It owns the process environment and account installation.
|
|
For example, a persistent computer can use these locations:
|
|
|
|
```text
|
|
HOME=/home/agent
|
|
AGENT_HOME=/home/agent/.agents
|
|
CODEX_HOME=/home/agent/.codex
|
|
instructions=/home/agent/.agents/AGENTS.md
|
|
skills=/home/agent/.agents/skills/<name>/SKILL.md
|
|
```
|
|
|
|
These are execution-host locations. Core does not copy the home for each run.
|
|
The plugin must declare `projectAuthCheckVersion: 1` for all native tasks.
|
|
Core requires `check_project_auth` to allow the exact prepared configuration
|
|
before it sends credentials. The plugin must reject conflicting project or
|
|
parent authentication settings. It must keep the checked configuration fixed
|
|
until submission. See [managed account validation](PLUGIN_ENVIRONMENT_TASKS.md#managed-account-validation).
|
|
|
|
Core sends authorized project IDs, the PRP identity, launch limits, and the
|
|
bootstrap ticket through `submit`. It does not send a process command.
|
|
The plugin must submit each task at most once. A lost reply requires status
|
|
reconciliation for the same task.
|
|
|
|
## Credentials and tools
|
|
|
|
Core can transfer a selected Codex account or a direct Claude credential.
|
|
Other managed routes fail closed until they have a typed credential contract.
|
|
Do not put credentials in task metadata, journals, logs, or errors.
|
|
|
|
Assigned MCP tools run through the Core gateway over PRP.
|
|
The gateway credentials stay on Core.
|
|
The plugin must preserve the MCP binding identity in the prepared context.
|
|
|
|
Core records credential writeback authority before dispatch.
|
|
After process termination, Core saves refreshed credentials before it completes
|
|
the task. A failed save retains the task grants for cleanup.
|
|
|
|
## Stop and recovery
|
|
|
|
A terminal phase does not prove process termination.
|
|
Return `executionStopped: true` only after the task and its descendants stop.
|
|
Return `sessionStateAvailable: true` only when the suspended state remains usable.
|
|
Keep retained state when Core completes the task.
|
|
Core checks managed plugin workspaces through their storage provider before
|
|
completion, including after a restart. Core does not inspect these folders locally.
|
|
If this check fails, Core defers the run and continues recovery for other runs.
|
|
Core keeps known branch and owner error codes with the repair instructions.
|
|
|
|
The task contract exposes two checkpoint operations:
|
|
|
|
- `read_state` returns the exact Runner durable state for the supplied identity.
|
|
- `archive_state` moves a suspended Runner authority checkpoint under the supplied
|
|
archive key. It returns the same state on retry. It keeps provider session files.
|
|
|
|
These operations do not accept paths. Core checks the active lease and retained
|
|
source task before it calls the plugin. The existing Runner transport validates
|
|
state identity and suspension before it rotates authority.
|
|
|
|
Core checks company, agent, environment, workspace, driver, and termination
|
|
receipts before it supplies `resumeFrom`. For same-run controller recovery, Core
|
|
first stops and releases the old task. A failed stop prevents replacement.
|
|
A new run prepares its current assignments. Provider compatibility checks remain
|
|
in the existing backends. Missing or incompatible retained state fails closed.
|
|
|
|
## Setup verification
|
|
|
|
Core creates a private probe lease with an expiry.
|
|
It runs the same describe, prepare, submit, and WSS/PRP path.
|
|
The probe checks provider authentication and the selected model with tools denied.
|
|
Core bounds Runner lifetime to the remaining probe time.
|
|
It then requires suspension, confirmed termination, and task cleanup.
|
|
For a new agent-owned computer, the saved-agent lifecycle runs verification
|
|
after it saves the agent. Core does not require a computer before this save.
|
|
|
|
## Verification
|
|
|
|
- [Lease and SDK RPC integration](../../server/src/__tests__/plugin-runner-task.integration.test.ts)
|
|
- [Real Runner setup and recovery](../../server/src/services/native-runtime/plugin-runner-probe.test.ts)
|
|
- [Task ownership and cancellation](../../server/src/services/native-runtime/plugin-runner-task.test.ts)
|
|
- [Credential transfer](../../server/src/services/native-runtime/plugin-runner-credentials.test.ts)
|
|
|
|
The Runner fixture uses a synthetic Codex provider and local sockets.
|
|
It does not qualify a deployed plugin, live account, or production WSS proxy.
|
|
|
|
## Workspace completion and maintenance
|
|
|
|
A storage provider can declare `workspaceProvider.finalizationVersion: 1`.
|
|
Core then sends `workspaceOperation` with `operation.kind: "finalize"`, the retained
|
|
binding, lifecycle generation, and originating `runId` and `agentId`. The operation
|
|
must verify workspace identity and make the run's retained writes durable before
|
|
returning `{ kind: "finalized", headSha, branchName }`. Git workspaces must still
|
|
report the assigned branch. Non-Git workspaces return null Git fields.
|
|
|
|
Completion permits dirty, untracked, ignored, and unpublished work. It does not
|
|
prove remote recoverability or authorize deletion. The provider chooses how to
|
|
meet this contract; Core does not prescribe a VM, filesystem, or Git layout.
|
|
Core gives completion a 30-second deadline. An unavailable execution host or an
|
|
unconfirmed durability barrier must fail retryably, never return success.
|
|
Recovery receives the original run and agent context.
|
|
|
|
The existing agent-independent `inspect` and `remove` operations continue to
|
|
protect storage maintenance. Providers that do not declare finalization version 1
|
|
retain the inspection-based completion path. No stored binding migration is required.
|