docs/guides/board-operator/execution-workspaces-and-runtime-services.md
This guide documents the intended runtime model for projects, execution workspaces, and issue runs in Paperclip.
Paperclip now presents this as a workspace-command model:
Services are long-running commands that stay supervised.Jobs are one-shot commands that run once and exit.You can define how to run a project on the project workspace itself.
Workspace commands can be controlled manually from the UI, and heartbeat runs also start services automatically.
ensureRuntimeServicesForRun (server/src/services/workspace-runtime.ts, called from server/src/services/heartbeat.ts) starts each service whose desired state resolves to running — which is the default when no explicit per-service desired state is set. A running service that matches an existing reuse key is reused rather than restarted.stopped/manual in the runtime config; those services stay UI-controlled.Execution workspaces isolate code and runtime state from the project primary workspace.
Issues are attached to execution workspace behavior, not to automatic runtime management.
running-desired runtime services for the duration of the run (see "Runtime control" above); it does not stop them when the run ends unless they are ephemeral and no other run holds a lease.Execution workspaces are durable until a human closes them.
Heartbeat resolves a workspace for the run (code location and session continuity) and also brings up that workspace's runtime services.
ensureRuntimeServicesForRun to start the workspace's running-desired runtime services, running the lazy runtime provision command first if one is configured and has not yet run (see "Lazy runtime provisioning" below).Some workspaces need heavy one-time setup — seeding a database, warming caches — before their runtime services can start. That work can be deferred to the first runtime-service start instead of running eagerly during workspace preparation.
workspace_runtime_provision operation on the execution workspace and surfaced on the workspace detail page:
A project workspace can be repo-only: a Repo URL with no local path. The server then
materializes a managed checkout on demand (git clone into a managed directory) and, for
isolated git_worktree runs, refreshes the base ref (git fetch) before preparing each
worktree. Both operations run on the server, outside any agent process — so agent-scoped
credential env bindings do not apply to them.
For private GitHub repositories, store a token as a company secret named one of
GITHUB_TOKEN, GH_TOKEN, or PAPERCLIP_GITHUB_TOKEN (checked in that order; Settings →
Secrets). The server resolves it per run and authenticates managed clones and base-ref
fetches with it. Details and caveats:
https://github.com/... repo URLs are authenticated this way. SSH URLs, GitHub
Enterprise hosts, and other providers keep ambient behavior (system git config/credential
helpers on the server host). URLs that embed their own credentials are never overridden.GITHUB_TOKEN or
GH_TOKEN variable in the server process environment (useful for self-hosted single-tenant
deployments), then to unauthenticated access — public repos keep working with no setup.GH_TOKEN/GITHUB_TOKEN bound at agent or project scope (see
deploy/secrets) so the token reaches the agent process env. The
same company secret can back both uses via a binding.Code state moves between runs through the local execution-workspace cwd alone — not through a git remote.
git remote configured.git push from runtime code, and must never assume a remote exists.workspace_finalize=failed on the execution workspace, which gates dependent issue wakes until the next successful finalize.The invariant is enforced by the "no-remote-git contract" case in packages/adapter-utils/src/ssh-fixture.test.ts, which asserts a remote-only commit reaches the local worktree with no remote configured at any point.
With the current implementation:
running-desired runtime services (via ensureRuntimeServicesForRun); services set to stopped/manual stay UI-controlled.