Pulse
Run c2j jobs on cloud compute or your own runners.
Pulse watches all repositories in a JobDB tenant, finds jobs that need an executor, acquires a JobDB lease for each selected job, and passes it to the container. It uses c2j's public Go library for discovery and tags each launch with its JobDB identity. The controller needs no separate c2j executable; executor images must contain c2j and the tools their recipes need.
Install · Quick start · Run in a container · Configuration · Providers · HTTP API
Install
npm
npm install --global @colony2/pulse
pulse version
Requires Node.js 22+, tar, enabled install scripts, and HTTPS access to GitHub Releases. The installer downloads the matching native executable and verifies the archive SHA-256 checksum.
Native executable
Download your platform's archive from GitHub Releases, verify it against checksums.txt, and put pulse on your PATH. Native executables need no Node.js. Archives also contain the optional Linux pulse-exec bridge for cloud providers. Docker needs only the Pulse executable.
Linux and macOS are supported on AMD64 and ARM64. Container images support Linux AMD64 and ARM64. The local Docker provider supports Linux servers and Docker Desktop on macOS, using Pulse's automatic Docker socket/context discovery.
Quick start
Start Docker Engine on Linux or Docker Desktop on macOS, then run:
pulse
No Pulse configuration file is required. Pulse uses the same tenant settings as c2j: C2J_JOBDB, then jobdb in the nearest .c2/config.yaml. You can also select a tenant explicitly:
pulse run --jobdb https://jobdb.example.com/acme
pulse check
pulse run --once
pulse version
Pulse discovers eligible c2j jobs across every repository in the tenant. Docker is the default provider, and jobs without an image/base request use the selector ubuntu-26*, resolving to a supported Ubuntu 26.04 base backed by ghcr.io/colony-2/base2:latest. Jobs without resource requirements have no CPU, memory, or scratch allocation, and Docker has no default container-count cap. Docker detects native and emulated execution support and prefers its daemon's native architecture on macOS and Linux. Explicit base selectors still constrain the architecture.
For Colony base images, Docker automatically retains uv, pnpm, and Nix dependencies in tenant-scoped volumes across jobs and restarts. No Nix daemon or manual cache setup is needed. See cache settings and image prerequisites.
check validates settings and initializes providers; it does not verify remote connectivity or launch permissions. run --once performs one discovery/submission pass. Both pulse and pulse run keep polling until SIGINT or SIGTERM and write JSON logs to stderr. Launched containers continue under their own lifetime controls.
For independently implemented Go providers, see the Go provider guide. Pulse uses the zero-dependency provider API; custom binaries can register implementations without plugins.
For custom providers or multiple tenants, use an optional configuration: remote runners, local Docker overrides, or cloud providers. Executor images must include c2j with run with-lease support; cloud images also need pulse-exec. Use a JobDB server containing commit 39ae1b444460 or later with available-route discovery and supplied-lease renewal support; upgrade the server alongside Pulse.
Run in a container
Use ghcr.io/colony-2/pulse. For simple deployments, pass the complete YAML in PULSE_CONFIG. Start with examples/container.yaml, fill in the settings, then run:
export PULSE_CONFIG="$(cat pulse.yaml)"
docker run --rm --init \
--read-only --tmpfs /tmp -p 8080:8080 \
-e PULSE_CONFIG -e PULSE_PROVIDER_TOKEN \
ghcr.io/colony-2/pulse:latest
The file is read on the host. In a deployment console, set PULSE_CONFIG directly to the YAML contents. Keep credentials in separate secret/environment settings or use the hosting platform's identity. For repeatable deployments, select a release tag such as :vX.Y.Z or an image digest.
The image is distroless, runs as UID/GID 65532:65532, and contains Pulse, its execution supervisor, and CA certificates. It includes native cloud authentication and needs no shell, Node.js, Git, cloud CLI, or separate c2j executable. Configure defaults.base with an environment selector. Legacy defaults.image plus defaults.platform remain supported for explicit OCI images.
For mounted YAML, pass the file path explicitly:
docker run --rm --init --read-only --tmpfs /tmp -p 8080:8080 \
--mount "type=bind,source=$PWD/pulse.yaml,target=/etc/pulse/pulse.yaml,readonly" \
-e PULSE_PROVIDER_TOKEN \
ghcr.io/colony-2/pulse:latest --config /etc/pulse/pulse.yaml
The mounted file must be readable by UID 65532. See configuration and Cloud Run deployment, cloud authentication, and Docker socket setup.
Configuration
Pulse optionally loads one YAML document, in order:
- Explicit
--config PATH. PULSE_CONFIGcontaining the YAML itself../pulse.yaml, if present.- Built-in defaults.
Sources are not merged. Empty or invalid inline configuration fails startup unless an explicit file was selected. Values are literal, without environment-placeholder expansion. Restart or redeploy to apply changes.
Tenant selection uses --jobdb, an explicit Pulse target's jobdb, C2J_JOBDB, then c2j project settings. Each target covers the whole tenant. Missing instance_id values are derived from the JobDB deployment URL. Remove obsolete cells settings when upgrading. Pulse requires an HTTP(S) JobDB tenant; c2j's embedded database cannot serve container workers.
Launch services have positive numeric priorities: 1 is preferred over 2. Equal-priority services rotate first choice for each batch. A provider can accept part of a batch and decline the rest for fallback.
targets:
- instance_id: production
jobdb: https://jobdb.example.com/acme
jobdb_token_env: JOBDB_TOKEN
launch_services:
- {name: runner_pool_a, priority: 1}
- {name: runner_pool_b, priority: 1}
- {name: cloud_overflow, priority: 2}
Define these service names under providers and supply JOBDB_TOKEN for authenticated JobDB discovery and lease acquisition. Pulse never passes this broad credential to the executor. Omit jobdb_token_env for an unauthenticated deployment. Provider authentication is configured separately.
When providers is omitted or empty, Pulse enables a local provider named docker. On Apple Silicon macOS with tart on PATH, it also enables tart using pulse-tart’s default two macOS and four Linux job VMs (4 vCPU / 8 GiB each; Linux includes Docker). Targets without launch_services prefer Docker at priority 1, then Tart at priority 2. Explicit provider maps remain authoritative. The default base is ubuntu-26*; select defaults.base: 'macos*' for macOS work. See Tart and Orchard configuration.
The default Docker pool uses the daemon’s CPU and memory capacity, with no container-count cap and 256 MiB accounting overhead per container. Start Docker Engine or Docker Desktop. Docker launches c2j directly and supplies its lease over native stdin, with no host mounts or helper installation. See Docker defaults and overrides.
c2j owns recipe and operation timeouts; Pulse imposes no execution timeout by default. Optional infrastructure caps must be configured explicitly and supported by the selected provider. Defaults are a 5-second poll interval, a 5-minute lease duration, 60-second provisioning-failure backoff, and batches of at most 100 jobs. Claims run with up to 8 concurrent calls and a 5-second claim window; configure these with claim_concurrency, claim_timeout, and batch_size. Pulse acquires the lease before submission and does not renew it; c2j renews the supplied lease on startup. Accepted or uncertain starts rely on lease expiry for recovery. Definite non-starts release the lease with backoff. In-memory cooldowns suppress failures only; JobDB ownership survives controller restarts. See configuration details and the complete examples.
Providers
| Provider | Type | Notes |
|---|---|---|
| Local Docker | docker | CPU, memory, and container-count budgets; no disk quotas. |
| Local Tart | tart | macOS and Linux ARM64 VMs, with Docker included on Linux guests and opt-in Docker on macOS; automatically enabled on Apple Silicon Macs with Tart installed. |
| Orchard | orchard | macOS and Linux ARM64 VMs; Linux includes Docker, macOS Docker is opt-in on a configured Orchard worker. |
| Remote runner service | remote | Batch submission with partial acceptance and capacity fallback. |
| Google Cloud Run Jobs | cloudrun | Native job execution and supported resource sizes. |
| AWS ECS Fargate | ecs | Standalone tasks with the execution supervisor. |
| Azure Container Apps Jobs | azurejobs | Manual jobs with native execution timeouts. |
In cloud environments, attach a service account, task/instance role, or managed/workload identity to the controller. Elsewhere, supply supported environment credentials or mounted credential files. See cloud authentication and provider operations for permissions, image requirements, capacity, and resource cleanup.
HTTP API
Continuous mode serves a public, unauthenticated, read-only API on :8080. PORT changes the default port; http.listen can override the address.
| GET endpoint | Returns |
|---|---|
/status | Version, uptime, and polling status. |
/config | Configuration with environment values and URL credentials redacted. |
/instances | Active instances across all configured providers. |
/providers/{provider}/instances | One page from a configured provider. |
/scheduler/cooldowns | Current cooldowns and in-flight attempts. |
/scheduler/round-robin | Priority tiers and next starting services. |
curl http://localhost:8080/status
curl 'http://localhost:8080/providers/runners/instances?page_size=100'
Lists include queued, starting, and running instances and exclude terminal instances; paused/stopping compute is included where supported. run --once, check, and version do not start the server. See HTTP API documentation for pagination and partial failures.
More documentation
- Configuration and container deployment
- Provider operations
- Implementing a remote provider
- Contributing and development
License
Local provider plugins
Use type: plugin to run a trusted, independently installed compute provider. Pulse starts and supervises the executable, delivers only its configuration, and preserves uncertain submission outcomes without replay. See installation and the public SDK and the separate-module reference provider.