Skip to main content
Towbar is a monorepo with a small control plane and an SSH-based deployment plane. The public repository contains the dashboard, API, workflow worker, deployment executor, database schema, installer, examples, and release checks. You can trace a request from the browser to the code that changes a server without relying on a separate hosted service.

Browse the source

Open the complete Apache-2.0 repository on GitHub.

Run the checks

See the local development, documentation, and verification commands.

Runtime topology

The dashboard and API share one origin. Caddy sends /v1/* requests to the API and everything else to the Next.js dashboard. PostgreSQL stores control-plane state. Temporal stores workflow history and schedules durable work. The worker performs side effects and reaches deployment servers over SSH. The Compose topology is declared in docker-compose.yml. The public routing rule is deliberately short and visible in infra/gateway/Caddyfile. Temporal and PostgreSQL stay on the private Compose network. A local installation publishes only the dashboard gateway on 127.0.0.1:4021.

Repository map

Towbar uses pnpm workspaces and Turborepo. Deployable processes live under apps/; reusable contracts and implementation boundaries live under packages/. This split keeps the dependency direction clear. The API owns authorization and database changes. Temporal workflows describe durable coordination. Activities perform network and filesystem work. The deployer knows how to change a remote host but has no database dependency. The dashboard uses HTTP contracts and never reads PostgreSQL directly.

How a repository becomes inventory

Towbar treats Git as the workload contract while keeping server credentials and secret values out of the repository.
  1. A repository connection maps a Towbar environment to a branch.
  2. The API starts or signals a durable source workflow in Temporal.
  3. A worker activity calls the signed internal source-sync route.
  4. The API fetches one immutable commit from the configured Git provider.
  5. manifest-v2.ts parses towbar.yml plus .towbar/apps, .towbar/resources, and .towbar/compose files with strict schemas.
  6. reconciliation.ts compares the accepted manifest with the current inventory.
  7. The API applies the result transactionally. Invalid input leaves the previous inventory and secret slots intact.
The parser resolves one environment at a time. Each environment therefore gets a digest derived from its branch and effective configuration, rather than from mutable dashboard form state.

Manifest implementation

Read the root manifest, entity discovery, strict YAML parsing, and environment resolution.

Example repository

See Dockerfile, image, static, Buildpacks, Railpack, Nixpacks, and Compose examples.

How a deployment runs

A deployment is a durable operation with an immutable snapshot. The API admits the request and records the snapshot before the worker touches a server. The important handoffs are visible in a small set of files:
  • areas/deployments/service.ts owns admission, immutable snapshots, execution context, secret resolution, and release commits.
  • deployment.workflow.ts defines the durable sequence and interruption recovery policy.
  • activities/deployment.ts bridges Temporal to the signed internal API and deployment executor.
  • deployment.ts performs the remote candidate, health, promotion, rollback, and cleanup steps.
  • ssh.ts enforces the SSH connection and trusted-host-key boundary.
Temporal retries coordination and recovery work. The main deployment activity does not blindly rerun a failed deployment. If execution stops near promotion, recovery asks PostgreSQL whether the release commit became durable before deciding to finish cleanup or remove the candidate. This prevents an uncertain network response from rolling back a release that was already recorded.

Public and internal API boundaries

apps/towbar-api/src/app.ts builds two Hono applications from the same middleware stack:
  • The public listener serves browser sessions, API keys, REST, MCP, authentication, and provider webhooks.
  • The internal listener serves worker callbacks and sensitive execution context on the private Compose network.
Worker requests to the internal listener carry an installation HMAC signature, timestamp, and nonce. The API checks the signature and replay window before returning deployment context or resolved credentials. Internal routes are not published by Caddy. Authorization rules live in packages/towbar-access/src/index.ts. The same permission vocabulary is used for browser sessions, personal API keys, team API keys, and system actors. Browser-only actions such as revealing a secret or opening a server terminal cannot be granted to automation keys.

State and secret boundaries

PostgreSQL stores workspace state, accepted inventory, deployment snapshots, encrypted secret values, audit events, and runtime observations. The schema is defined in packages/towbar-database/src/schema/index.ts, with reviewed SQL migrations under packages/towbar-database/drizzle. Secret names belong in Git. Secret values belong in Towbar. The API encrypts stored values with AES-256-GCM and binds each ciphertext to its workspace, owner, environment, stage, and record identity. The worker resolves plaintext only when execution starts. Plaintext stays out of manifest snapshots, Temporal arguments, workflow history, audit events, and deployment logs. Static control-plane credentials, including provider clients, notification destinations, and log drains, come from the installation environment. The API validates those settings at startup and the dashboard shows only complete integrations. OAuth grants and GitHub installation metadata are stored as workspace state because users create them through provider authorization flows.

Deployment-server boundary

Towbar does not install a general-purpose agent to deploy applications. The worker connects to registered Ubuntu servers through SSH, verifies the stored host identity, and invokes narrowly generated Docker and Caddy operations. The deployment executor uses candidate containers and health checks before switching traffic. A failed candidate leaves the previous healthy release serving traffic. The optional Scout Agent has a separate job. It collects bounded host and container measurements and sends them to the HTTPS Towbar origin. Its Go implementation is under apps/towbar-monitoring-agent. It is not part of deployment admission and cannot execute deployment commands.

Reliability and release evidence

The repository has several levels of verification: CI runs the required groups independently and uploads their logs as artifacts. Read tools/verification/README.md for the exact coverage and the distinction between fixture, emulator, disposable-host, and live-provider evidence.

A practical reading order

If you want to understand the implementation before running Towbar, follow this path:
  1. Start with docker-compose.yml to see the processes and private networks.
  2. Read manifest-v2.ts and reconciliation.ts to understand the Git contract.
  3. Open apps/towbar-api/src/app.ts and apps/towbar-api/src/routes/v1 to trace HTTP boundaries.
  4. Follow one workflow from apps/towbar-worker/src/workflows into its matching activity.
  5. Continue into packages/towbar-deployer to see the remote-host behavior.
  6. Review packages/towbar-database/src/schema/index.ts to see what state persists.
  7. Run the repository checks from CONTRIBUTING.md.
Continue with Your first deployment, or read the security model for the supported trust assumptions and reporting process.
Last modified on September 22, 2026