Paperclip

Paperclip makes interrupted heartbeats resumable by session ID

Paperclip proposes persisting the observed session ID during a run so process-loss recovery can resume the same work. Companion changes strip inherited systemd manager variables and move ACP lifecycle ownership into a typed coordinator ledger.

← Back to homeOriginal source ↗

paperclipai/paperclip PR #11585 is the inspected primary source: “fix(heartbeat): persist mid-run observed session id so a process-lost retry can resume.” The related records below were inspected as supporting context rather than independent confirmation.

The facts

- paperclipai/paperclip PR #11585 was created 2026-08-18T00:59:57Z and was open at inspection; its title is “fix(heartbeat): persist mid-run observed session id so a process-lost retry can resume.” - paperclipai/paperclip PR #11584 was created 2026-08-18T00:44:44Z and was open at inspection; its title is “fix: strip systemd service-manager env vars from spawned agent processes.” - paperclipai/paperclip PR #11576 was created 2026-08-18T00:06:45Z and was open at inspection; its title is “refactor(acpx-engine): coordinator-owned ACP run lifecycle with a typed resource ledger.” - The repository reported 78708 stars, 5131 open issues, default branch master, and last push 2026-08-18T00:55:47Z. - The latest tagged-release baseline checked was v2026.722.0 published 2026-07-22T23:05:41Z.

What changed

paperclipai/paperclip PR #11585 reports: Thinking Path - Paperclip is the open source app people use to manage AI agents for work - When an agent's underlying process is killed mid-run (OOM, cgroup sweep, kill -9), the server relies on an automatic process_lost retry to recover the run - That retry reads the last-known session id (sessionIdBefore) so the resumed run can pick up where it left off instead of starting a brand-new session - The session id was only ever persisted after the adapter returned an AdapterExecutionResult — a process that never returns one (because it was killed) leaves no session row behind - So every process_lost retry today resumes with sessionIdBefore: null, discarding all accumulated context, even though the underlying agent CLI (claude --resume ) can recover that context perfectly well - This PR adds an optional onSessionObserved adapter callback fired the moment the adapter learns its session id, while the process is still alive, and wires the server to persist the task session at that point instead of waiting for a terminal result - The benefit is a process_lost retry resumes the real prior conversation instead of losing it Linked Issues or Issue Description What happened?** When a run's agent process is killed (SIGKILL from a systemd cgroup sweep, OOM, or kill

paperclipai/paperclip PR #11584 reports: Problem Agent child processes spawned by runChildProcess inherit the paperclip server's systemd readiness socket (NOTIFY_SOCKET) and socket-activation vars (LISTEN_FDS/LISTEN_PID/LISTEN_FDNAMES), so an agent subprocess can reach the service's own readiness channel. Every boot then logs Got notification message from PID N, but reception only permitted for main PID M. Fix In runChildProcess (packages/adapter-utils/src/server-utils.ts), in the same block that already strips the Claude Code nesting-guard vars, strip NOTIFY_SOCKET / LISTEN_FDS / LISTEN_PID / LISTEN_FDNAMES from the merged** env (process.env + opts.env) after the merge — not just from the process.env side — since every local adapter builds opts.env as {...process.env,...env } and would otherwise re-leak these vars even after sanitizeInheritedPaperclipEnv strips PAPERCLIP_* keys from the process.env copy. This is a single chokepoint fix covering all local adapters (pi-local, claude-local, codex-local, cursor-local, gemini-local, opencode-local, copilot-local, acpx-local). Remote/sandbox execution targets bypass runChildProcess and are unaffected. Scope: env-strip only, per the linked issue. Does not include the systemd-cgroup escape work tracked separately (AGE-538). Testing New unit test in packages/adapter-utils/src/server-utils.test.ts: sets NOTIFY_SOCKET/LISTEN_FDS/LISTEN_PID/LISTEN_FDNAMES in **both** process.env and the caller's opts.env, spawns a child that echoes its own process.env as JSON, and asserts none of the four vars are present. Confirmed the test fails on unmodified master (red) and passes with the fix (green). On this

paperclipai/paperclip PR #11576 reports: Thinking Path - Paperclip is the open source app people use to manage AI agents for work - Agent adapters run agent sessions through the ACPX engine - The ACPX engine handled one run attempt as a long implicit procedure - That shape made resource ownership, cleanup order, and failure behavior hard to verify - This pull request gives the attempt a coordinator, a typed resource ledger, separate run sites, and explicit turn and settlement sequences - The benefit is clear ownership, one cleanup path, safer session reuse, and testable failure behavior Linked Issues or Issue Description What existing behavior does this improve?** The ACPX engine manages startup, turn execution, session reuse, and cleanup inside one large run procedure. Current behavior** The run procedure owns several resources through implicit control flow. Cleanup and session reuse behavior depend on lane-specific branches and error paths. Proposed behavior** The coordinator owns the run attempt. A typed ledger records six resources and their states. Host and sandbox run sites own lane-specific acquisition. Turn and settlement sequences expose typed outcomes. The engine emits allowlisted phase telemetry. Reason and benefit** Explicit ownership makes cleanup and failure behavior easier to inspect. The fault matrix and characterization tests protect the external result while the refactor reduces hidden control

Why it matters

Resume logic needs a durable identity and a single lifecycle owner. Otherwise recovery can fork work while inherited process state quietly changes its execution environment. The operator test is whether the system remains bounded and its receipts still describe the action after failure, retry or restart.

Current

The primary record was open when captured on 2026-08-18. The tagged-release baseline was v2026.722.0 published 2026-07-22T23:05:41Z. Repository metadata, full source bodies, current pull requests and issues, releases, Google News, Hacker News, Lobsters, Metamesh and the rendered ClawCharts row were inspected. ClawCharts selected the subject; it did not prove the claim.

Evidence

The primary URL is https://github.com/paperclipai/paperclip/pull/11585. Supporting records are https://github.com/paperclipai/paperclip/pull/11584 and https://github.com/paperclipai/paperclip/pull/11576. Source bodies, timestamps and states are preserved in the daily evidence bundle. Test counts and reproductions remain attributed to their authors unless identified as independently rerun.

Source boundary

Open work is described as open, closed work as closed, and operator reports as reports. A pull request is evidence of proposed or reviewed direction, not proof of a shipped release. Search residue, package mirrors and historically published source spines were excluded.

Operator take

Write session identity before externally visible progress, strip supervisor-only environment at spawn, and reconcile every ACP resource through one typed owner ledger. Preserve a before-state receipt, make the smallest reversible change, and verify the original failure independently.

Caveat

Public project records are mutable. Status, scope and evidence can change after publication. This brief records the inspected state and does not authorize changes to a reader’s deployment.

Source inspected; source state, environment and release boundary remain explicit.