Configuration
The tarjan.yaml schema — repos, tools, services.
name: myproduct
version: dev # named, reusable workspace (omit for a fresh one per run)
workspaceRoot: ~/tarjan/myproduct # workspaces are materialised under here
requires: # tools that must exist before starting
- name: git # no `services:` → baseline, always checked
- name: docker
optional: true # warn instead of fail if missing
services: [postgres] # checked only when postgres is in the selection
- name: node
minVersion: "20"
mise: node@20 # versioned runtime via mise (with --install)
services: [api]
repos: # cloned into the workspace
- name: api
url: https://github.com/your-org/api.git
branch: main
services: # started in dependency order
- name: postgres
docker: { image: postgres:16, ports: ["5432:5432"], env: { POSTGRES_PASSWORD: dev } }
health: { tcp: "localhost:5432" }
- name: api
workdir: api
setup: ["npm install"] # one-shot, runs once per workspace
setupCheck: "test -d node_modules" # setup counts as done only if this passes
command: "npm run dev"
env: { DATABASE_URL: "postgres://postgres:dev@localhost:5432/postgres" }
dependsOn: [postgres]
health: { http: "http://localhost:8080/health" }
restart: on-failure
watch: { paths: ["src"] }
workspace: { vscode: true }Workspaces & versions
With no version:, each tarjan up materialises a fresh, timestamped
workspace under workspaceRoot (e.g. ~/tarjan/myproduct/20260628-150405/)
— every run starts from a clean slate and old runs stay around for reference.
Set a top-level version: (or pass tarjan up --version <label>, which
overrides it per run) to use a named, reusable workspace at
<workspaceRoot>/<name>-<version> instead. Repeated up runs of the same
version reuse the directory: already-cloned repos and finished setup steps
are skipped, so it comes back fast. tarjan pull <version> updates that
workspace's checkouts in place, and --workspace <dir> still overrides
everything with an explicit path.
Different versions give you parallel environments side by side — e.g.
--version feat-a and --version feat-b are independent checkouts you can keep
on different branches. They coexist on disk, but only one can run at a
time: services publish fixed host ports shared by every workspace, so a second
running environment collides with the first ("address already in use"). Stop
one (Ctrl+C or tarjan down) before starting the other — reuse makes the
switch quick.
Required tools
Each requires entry declares a tool: name (looked up on PATH),
minVersion, versionCommand, installHint, optional, and an install
provider — mise (versioned runtimes), package (OS package managers), or a
bespoke install command — run only with --install.
A tool may also list the services that need it. A tool with no services is
a baseline, checked on every run; one that names services is checked only
when at least one of them is in the run's selection — so a partial
tarjan up web skips toolchains it won't use, and tarjan doctor <service>
reports just what that service needs.
Service fields
| Field | Meaning |
|---|---|
name | Unique service name. |
kind | service (default) or job (run-to-completion). |
workdir | Working directory inside the workspace (usually a cloned repo). |
setup | One-shot commands run once per workspace before first start. |
setupCheck | Command that verifies setup succeeded; setup is recorded as done only when it exits 0, and a later run re-checks and re-runs setup if it now fails. Guards against a setup command that exits 0 without producing what it should (e.g. npm install printing "up to date" while a downloaded binary is missing). |
command | Long-running command (ignored when docker is set). |
docker | Run as a container: image, ports, env, volumes, args. |
external | A cloud/remote dependency tarjan only health-probes. |
env / envFile | Inline variables / .env files (files load before inline). |
dependsOn | Services that must be healthy (or, for jobs, complete) first. |
health | Readiness probe: tcp, http, or command (+ timeout, interval). |
restart | Crash policy: no (default), on-failure, or always. |
maxRestarts | Cap on automatic restarts (default 5; 0 = unlimited). |
watch | Live-restart on file change: paths + debounce. |
optional | Failure → warning instead of aborting the whole up. |
profiles | Gate the service to specific --profile groups. |
remote | Run on a named SSH target from remotes: — see Remote targets. |
Profiles & selective start
A service or repo with no profiles is always included; one with
profiles is included only when a matching profile is active (--profile), it's
named in --only, or it's pulled in as a dependency.
tarjan up # always-on services only
tarjan up --profile frontend # + the frontend profile
tarjan up --only web # web + its dependenciesEnv files & secrets
A global envFile applies to every service; a per-service envFile applies to
one. Precedence, lowest to highest: process env, global env files, service env
files, inline env. Commit a .env.example and git-ignore the real .env*.