Dev targets
A dev target is something you run yourself while developing: a local HMR web server, a debug build, a native app process you want running, a preview bundle. RepoOS can start, stop and restart each one for you and keep it running while you work, so you don't have to keep a terminal open for every process.
Dev targets are distinct from task previews. A preview is a temporary instance RepoOS starts from a task's worktree to show a change under review; it lives on the task. A dev target is what you start for your own development, in the project's root checkout, and it stays up until you stop it.
Declare the targets in the project's committed repoos.toml. Only commands declared there can ever run — nothing you type in the UI becomes a command, and no API request body can supply one. That is the whole trust boundary of the feature.
Fields
Every target has a name, a kind and a command; the rest are optional and depend on the kind:
| Field | Type | Required | Meaning |
|---|---|---|---|
name | string | yes | Stable identity. Unique within the project; the API, CLI and UI address the target by it. |
kind | server | artifact | process | yes | A server is a long-lived process with a URL. An artifact is a build that produces a file and exits. A process is a long-lived foreground process with no URL and no build artifact — a native macOS app, a daemon. |
command | string | yes | The shell command, run in the project's root checkout — never a task worktree. |
url | string | for server | The server's URL, e.g. http://localhost:5173. Shown as the open-URL link. |
port | number | no | The port used for {port}. With auto-pick on it is the preferred port (used when free); with auto-pick off it is the fixed port. |
autoPort | boolean | no | Auto-pick a free port for {port}. Default true. Set false to pin the target to port and let a clash fail. |
artifactPath | string | for artifact | Repo-relative path of the build output, e.g. dist/app-debug.apk. |
label | string | no | A human label shown in the UI. Defaults to name. |
healthCheck | table | no | When the target counts as healthy — see below. Not used for a process. |
Every row needs some way to be judged healthy: a server needs a url (and may add a healthCheck), an artifact needs an artifactPath, and a process is healthy while its process is alive — which is its health check. A server without a url is rejected with a pointer to kind = "process", and a process cannot carry a url, an artifactPath or a healthCheck.
The health check
A process that has spawned is not necessarily ready. A Vite server answers a moment after it starts; a build writes its output at the end. A health check tells RepoOS when to call a target ready instead of guessing:
healthCheck.url— a URL polled until it answers. Use it for aserver.healthCheck.file— a repo-relative file that must exist. Use it for anartifact.
Leave healthCheck out and a server is reported running as soon as its process is alive, and an artifact when its command exits successfully. A process has no health check: it is reported running as soon as its process is alive, and stays running while it lives. A target that never satisfies its health check is reported failed rather than running.
[[dev.targets]]
name = "web"
kind = "server"
command = "bun run dev"
url = "http://localhost:5173"
label = "Web app"
healthCheck.url = "http://localhost:5173/health"Examples
A local HMR web server that is ready when its app responds:
[[dev.targets]]
name = "web"
kind = "server"
command = "bun run dev"
url = "http://localhost:5173"
label = "Web app"
healthCheck.url = "http://localhost:5173/health"A local HMR web server whose port RepoOS chooses, so it never clashes with another app on the machine. Auto-pick a free port is on by default: {port} in the command, url and healthCheck is replaced with the same port, and the Dev page shows the real URL it bound:
[[dev.targets]]
name = "web"
kind = "server"
command = "bun run dev --port {port}"
url = "http://localhost:{port}"
label = "Web app"
healthCheck = { url = "http://localhost:{port}/health" }Set port to state a preferred port: RepoOS uses it when it is free and falls back to a free one when it is taken. Turn autoPort off to pin the target to a fixed port instead — a clash then fails with the plain-language summary that names the process holding the port, rather than being moved:
[[dev.targets]]
name = "web"
kind = "server"
command = "bun run dev --port {port}"
url = "http://localhost:{port}"
port = 5173
autoPort = false # use 5173 as-is; a clash fails with the summaryAuto-pick only ever picks a port — it never stops another process. Only a process RepoOS itself started can be stopped (the Stop action in the failure summary).
An Android debug build that produces an APK:
[[dev.targets]]
name = "apk"
kind = "artifact"
command = "./gradlew assembleDebug"
artifactPath = "app/build/outputs/apk/debug/app-debug.apk"
label = "Debug APK"
healthCheck.file = "app/build/outputs/apk/debug/app-debug.apk"A native macOS app that runs in the foreground with no URL and no build output — Divot's menu bar app:
[[dev.targets]]
name = "divot"
kind = "process"
command = "swift run --package-path macos divot"
label = "Divot bar"It is reported running while the process is alive; stop it from the Dev page or repoos dev divot stop, and Restart re-runs the command (which rebuilds and relaunches). Its last output lines are shown just like a server's.
Editing targets
Two ways to edit the list, both writing the same [[dev.targets]] rows:
- Settings → Advanced → Dev targets. Add, edit, reorder and remove rows in the UI. Validation errors appear inline as you type, and the change is written through the config API — never by hand. The same parser validates the list server-side, so the form can never save a row the loader would reject.
repoos.tomldirectly. Hand-write the[[dev.targets]]tables. A row the parser cannot use — a missingnameorcommand, an unknownkind, a duplicate name, or a conflicting field such as aurlon anartifact— is reported as a clear validation error (in Settings and on the Dev page) rather than silently dropped.
Running targets
Start, stop and restart a target from the Dev page, or from the CLI:
repoos dev list
repoos dev web start
repoos dev web stop
repoos dev web restart
repoos dev web status
repoos dev web logsA started target runs in the project's root checkout, detached from the server's own lifetime: it keeps running after you close the browser, and stops only when you ask, when the server stops, or when it crashes. Its state is one of running, stopped, starting or failed, and the last 2000 lines of its combined output are available in a scrollable panel. The panel opens six lines at a time and scrolls for the rest; it starts minimised after a clean run and opens automatically when the last run failed, so the error is visible. Your expand/collapse choice is remembered per target when you leave the page or reload. A running target also shows how long ago it started — "17 hours ago" beside its state — and hovering or focusing that time reveals the exact start timestamp. A started target's card carries a soft cyan glow — the same highlight an active remote runner shows while it runs checks — so a running target stands out from a stopped one at a glance.
When a target fails, the Dev page shows a plain-language summary above the log: what failed, the most likely cause, and how to fix it. A port already in use is detected from the output and, when it can, names the process holding the port — its PID and command — with a Stop action for a process RepoOS started. A {port} target avoids that entirely while auto-pick is on (the default); turn it off with autoPort = false when you need a fixed port. Enable the optional AI-written summary under Settings → Advanced → Dev failure summaries.
Missing dependencies
A target's cwd is its own project directory. If that directory has a package.json, it needs its own node_modules — a fresh task worktree has none, and an older install can predate a dependency added to package.json. Starting the target then fails with ERR_MODULE_NOT_FOUND even though the command itself is correct.
repoos doctor reports this as A dev or preview target is missing its installed dependencies and gives the exact fix, for example:
cd user-docs && bun installThe check is read-only — doctor never installs anything for you.
See also
- Configuration — the full
repoos.tomlreference, including the[[dev.targets]]keys. - CLI reference — the
repoos devcommands.