EnerBrain Agency· Documentation
Guides › Board Operator

Execution Workspaces And Runtime Services

How project runtime configuration, execution workspaces, and issue runs fit together

This guide documents the intended runtime model for projects, execution workspaces, and issue runs in EnerBrain Agency.

EnerBrain Agency now presents this as a workspace-command model:

Project runtime configuration

You can define how to run a project on the project workspace itself.

Runtime control: manual and heartbeat-driven

Workspace commands can be controlled manually from the UI, and heartbeat runs also start services automatically.

Execution workspace inheritance

Execution workspaces isolate code and runtime state from the project primary workspace.

Issues and execution workspaces

Issues are attached to execution workspace behavior, not to automatic runtime management.

Execution workspace lifecycle

Execution workspaces are durable until a human closes them.

Resolved workspace logic during heartbeat runs

Heartbeat resolves a workspace for the run (code location and session continuity) and also brings up that workspace's runtime services.

  1. Heartbeat resolves a base workspace for the run.
  2. EnerBrain Agency realizes the effective execution workspace, including creating or reusing a worktree when needed.
  3. EnerBrain Agency persists execution-workspace metadata such as paths, refs, and provisioning settings.
  4. Heartbeat passes the resolved code workspace to the agent run.
  5. Heartbeat calls 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).

Browser-reachable origins for OAuth QA

A managed service that runs EnerBrain Agency itself needs one canonical origin for Better Auth and tool OAuth callbacks. EnerBrain Agency resolves that origin in this order:

  1. Explicit service/runtime configuration such as PAPERCLIP_PUBLIC_URL or BETTER_AUTH_URL.
  2. An explicit instance auth public base URL.
  3. The managed service's rendered expose.urlTemplate, injected as a low-priority runtime fallback.

The exposed URL must describe the route the operator's browser actually uses. Non-loopback callbacks require HTTPS. Loopback HTTP such as http://127.0.0.1:45439 is supported for local browser QA. A non-loopback hostname rendered from workspace data must remain inside the stable domain suffix configured by expose.urlTemplate; branch names cannot replace that domain. Bind addresses, internal-only single-label names such as paperclip-dev, reserved/non-resolving names, and non-loopback HTTP origins fail service startup with configuration guidance instead of silently producing an unusable redirect URI.

Keep readiness and browser exposure separate when a proxy or tailnet route fronts the process:

{
  "name": "paperclip-dev",
  "command": "pnpm dev --bind lan",
  "port": { "type": "auto" },
  "readiness": {
    "type": "http",
    "urlTemplate": "http://127.0.0.1:{{port}}"
  },
  "expose": {
    "type": "url",
    "urlTemplate": "https://{{workspace.branchName}}.dev.example.com"
  }
}

Use a distinct reachable hostname (or other distinct origin) per isolated worktree. Do not point multiple worktree runtimes at the parent instance's origin. After startup, open the service URL in the same browser session used for QA and verify GET /api/tools/oauth/client-metadata; its redirect_uris entry should use that service origin and /api/tools/oauth/callback.

Lazy runtime provisioning

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.

Private repositories and repo-only project workspaces

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:

Cross-run persistence (no-remote-git contract)

Code state moves between runs through the local execution-workspace cwd alone — not through a git remote.

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.

Current implementation guarantees

With the current implementation: