mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-12 18:06:11 +02:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Server shutdown must stop agent execution and preserve its files. > - Legacy adapters export workspace and instruction changes during settlement. > - Shutdown released their sandbox leases before this export finished. > - The provider closed command access, so the later Git export failed. > - This change stops an owned adapter through its cancellation control and waits for settlement before release. > - A bounded timeout retains the exact sandbox source behind the existing repair gate. ## Linked Issues or Issue Description **What happened?** A server restart interrupted a remote legacy run. Shutdown began releasing its sandbox lease while the adapter was still stopping its provider and restoring files. The sandbox provider closed command admission. The adapter's later Git export failed with `workspaceRestoreFailure: restore_failed`, leaving the task held for workspace repair. **Expected behavior** Shutdown keeps the exact lease available through provider stop, instruction collection, and workspace restore. Cleanup follows adapter settlement. A restore that exceeds the bounded deadline keeps its exact source for repair before later execution. **Steps to reproduce** 1. Start an owned legacy adapter with a sandbox workspace. 2. Send SIGTERM to the server while the adapter is active. 3. Delay adapter settlement until after the shutdown terminal write. 4. On the base branch, shutdown releases the lease without cancelling or joining the adapter. Its later export can encounter closed provider admission. Related: #14311 defines the provider-stop boundary for file collection. #15042 closes run admission during shutdown. This fix orders sandbox release after the adapter's existing file settlement. ## What Changed - Cancel each owned legacy adapter and join all affected runs within one shared 30-second window. - Commit a durable fence on the exact sandbox before exposing interruption. Other cleanup workers defer while export is pending. - Permit the exact aborted owner's stop-only request so shutdown does not block provider termination. - Reload current execution evidence after settlement. Release leases even when the adapter's ordinary terminal write wins the shutdown race. - Claim the current fence before recording timeout retention. An old snapshot cannot create a repair hold after successful settlement. - Recover fenced sources after controller loss, including released stop receipts. Block reuse or destruction of the physical allocation while file recovery is required, including direct resume and destroy calls with historical lease snapshots. Convert failed ordinary cleanup into stop-only recovery after its existing attempt settles. - Allow 90 seconds for shutdown in shipped Compose services. Preserve native runner restart ownership and unregistered process behavior. - Add database regressions for restore order, timeout, concurrent cancellation, another cleanup worker, controller loss, stale snapshots, stop-only settlement, and completion races. Document the shutdown order. ## Verification - The original ordering regression failed on the base implementation. - Latest recovery and environment runtime suites: 190 tests passed. The other four focused suites passed 136 tests, covering run control, shutdown, file repair, server startup, and environment runtime. - Server typecheck passed. Full `pnpm -r typecheck` and `pnpm build` passed on the latest head. - `pnpm test:run` was run locally. Its general-server group passed 18,559 tests and failed seven, with one unhandled error. The long run started before the review fixes, then loaded newer regression cases against older transformed modules. The current focused suites pass in a fresh process. The damaged-prior-epoch native-session-resume failure also reproduces on unchanged base commitde9ab8e7e0. An isolated rerun of the Google Workspace connection case passed. Later full-run groups did not run because general-server stopped on failure. - The prior CI startup import failure is fixed: expiry loads the terminal recorder only when it needs to pin recovery. Its focused startup suite passes. - Apex reviewed commitc564320b16at 5/5. All review threads are resolved. All latest-head CI gates passed. The branch has no merge conflicts. ## Risks Owned legacy adapters share a 30-second shutdown window. The wait is bounded. Timeout cleanup uses the existing stop-and-retain and workspace repair paths. A timeout can require manual file verification even if a late restore succeeds. No database migration or API change is needed. ## Model Used OpenAI GPT-6 through Codex, with repository inspection, code editing, shell execution, and test tools. The session identifies the model family as GPT-6. It does not expose a more specific runtime model ID 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 (focused suites; full local limitations are listed above) - [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>
47 lines
2.0 KiB
YAML
47 lines
2.0 KiB
YAML
# Quickstart: single-container Paperclip with embedded database.
|
|
# Copy this file and set the required env vars before running.
|
|
#
|
|
# cd docker
|
|
# export BETTER_AUTH_SECRET="$(openssl rand -hex 32)"
|
|
# export ANTHROPIC_API_KEY="sk-ant-..."
|
|
# docker compose -f docker-compose.quickstart.yml up --build
|
|
#
|
|
services:
|
|
paperclip:
|
|
build:
|
|
context: ..
|
|
dockerfile: Dockerfile
|
|
# Ceiling on processes. The image makes tini PID 1 so orphaned agent
|
|
# descendants are reaped instead of piling up as zombies; this is the
|
|
# backstop if something leaks anyway — the container hits its own limit and
|
|
# dies visibly rather than starving the host of pids.
|
|
pids_limit: 2048
|
|
# Includes the shared 30s adapter-settlement window and final cleanup.
|
|
stop_grace_period: 90s
|
|
ports:
|
|
- "${PAPERCLIP_PORT:-3100}:3100"
|
|
environment:
|
|
HOST: "0.0.0.0"
|
|
PAPERCLIP_HOME: "/paperclip"
|
|
|
|
# ── LLM provider keys (at least one is needed for agents to work) ──
|
|
OPENAI_API_KEY: "${OPENAI_API_KEY:-}"
|
|
ANTHROPIC_API_KEY: "${ANTHROPIC_API_KEY:-}"
|
|
|
|
# ── Deployment settings ──
|
|
# "authenticated" requires login, "local_trusted" skips auth
|
|
PAPERCLIP_DEPLOYMENT_MODE: "authenticated"
|
|
# "private" = LAN only, "public" = internet-facing (use with TLS)
|
|
PAPERCLIP_DEPLOYMENT_EXPOSURE: "private"
|
|
# Base URL users will access the UI at
|
|
PAPERCLIP_PUBLIC_URL: "${PAPERCLIP_PUBLIC_URL:-http://localhost:3100}"
|
|
# Extra hostnames the instance accepts beyond the public URL host
|
|
# (LAN or Tailscale aliases), comma-separated; empty means none
|
|
PAPERCLIP_ALLOWED_HOSTNAMES: "${PAPERCLIP_ALLOWED_HOSTNAMES:-}"
|
|
|
|
# ── Required secret for session signing (generate with: openssl rand -hex 32) ──
|
|
BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET:?BETTER_AUTH_SECRET must be set}"
|
|
volumes:
|
|
# Persistent data directory (database, agent workspaces, uploads)
|
|
- "${PAPERCLIP_DATA_DIR:-../data/docker-paperclip}:/paperclip"
|