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 underapps/; 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.- A repository connection maps a Towbar environment to a branch.
- The API starts or signals a durable source workflow in Temporal.
- A worker activity calls the signed internal source-sync route.
- The API fetches one immutable commit from the configured Git provider.
manifest-v2.tsparsestowbar.ymlplus.towbar/apps,.towbar/resources, and.towbar/composefiles with strict schemas.reconciliation.tscompares the accepted manifest with the current inventory.- The API applies the result transactionally. Invalid input leaves the previous inventory and secret slots intact.
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.tsowns admission, immutable snapshots, execution context, secret resolution, and release commits.deployment.workflow.tsdefines the durable sequence and interruption recovery policy.activities/deployment.tsbridges Temporal to the signed internal API and deployment executor.deployment.tsperforms the remote candidate, health, promotion, rollback, and cleanup steps.ssh.tsenforces the SSH connection and trusted-host-key boundary.
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.
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 inpackages/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 underapps/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:- Start with
docker-compose.ymlto see the processes and private networks. - Read
manifest-v2.tsandreconciliation.tsto understand the Git contract. - Open
apps/towbar-api/src/app.tsandapps/towbar-api/src/routes/v1to trace HTTP boundaries. - Follow one workflow from
apps/towbar-worker/src/workflowsinto its matching activity. - Continue into
packages/towbar-deployerto see the remote-host behavior. - Review
packages/towbar-database/src/schema/index.tsto see what state persists. - Run the repository checks from
CONTRIBUTING.md.
