Per-Repo Dev Servers
Codumentor can launch, track, and stop long-running dev servers for the
repos it knows about — your Django/Node/etc. project, or Codumentor
itself during dogfooding. One declarative config, one CLI verb
(codumentor dev), one shared registry the admin panel lists and
operates on.
This page is for users editing their Codumentor config and developers
wiring .codumentor/ into their repo. The launcher is single-host and
single-user; multi-host scheduling is explicitly out of scope.
When to use this
- You want to "open" a repo and have its dev server come up alongside.
- You're iterating on Codumentor itself and need a clean preview per worktree, addressable by URL.
If your dev server is short-lived (one command, one terminal, you
Ctrl-C when done), you don't need this — just keep using your existing
workflow.
Configuration
Add a dev_server block under the existing per-repo project_setup
entry (or the top-level project_setup if you only have one repo):
project_setup:
setup_script: .codumentor/setup.sh # optional; already supported
watch: # optional; already supported
- requirements.txt
dev_server:
command: "python -m myapp serve --port ${PORT}"
health_path: "/health" # optional; GET expected to 2xx
open_url: "http://127.0.0.1:${PORT}/"
ready_timeout_seconds: 30 # optional; default 30
env: # optional extra env for the child
MYAPP_CONFIG: dev.yaml
Field reference
| Field | Required | Meaning |
|---|---|---|
command | yes | Shell-style command line. ${PORT} and any other ${VAR} references are substituted at spawn time. The child inherits the parent env plus PORT and the entries under env:. |
health_path | no | If set, the launcher polls GET http://127.0.0.1:${PORT}<health_path> until it returns 2xx (or the timeout elapses). Without it, TCP-accept is the only ready signal. |
open_url | no | The URL the admin panel links to. Defaults to http://127.0.0.1:${PORT}/. Templated the same way as command. |
ready_timeout_seconds | no | How long to wait for the server to become healthy before treating the launch as failed (default 30). |
env | no | Extra environment variables passed to the child process. Values are templated. |
${VAR} templating
The launcher uses Codumentor's regular ${VAR} substitution. It runs
twice:
- Load time: real env vars like
${HOME}are resolved when the config file is read.${PORT}is left literal because it isn't set in the parent environment yet. - Spawn time: a second pass over the
dev_serverblock withPORT=<allocated>injected.command,open_url, and the values underenv:are templated then.
So you can freely mix ${HOME}, ${VIRTUAL_ENV}, and ${PORT} in any
of those fields and they'll Just Work.
Port allocation
The launcher binds to :0, reads back the kernel-assigned port, and
closes before spawning. Cheap, no range exhaustion. Ports are not
stable across restarts — every launch gets a fresh port and a fresh
instance id.
CLI: codumentor dev
Four verbs. All of them respect the same --repo NAME semantics as
codumentor setup. If --repo is omitted, the launcher infers the repo
from your current working directory.
codumentor dev [--repo NAME] [--no-wait]
Allocate a port, ensure project_setup is current, spawn
dev_server.command, register the instance, wait for the
healthcheck. --no-wait skips the wait but still registers.
codumentor dev status [--json]
List running instances. Reconciles dead PIDs out first.
--json prints a machine-parseable payload that includes
orphan processes.
codumentor dev stop [--repo NAME | --id ID | --all]
SIGTERM the matched instances, wait, SIGKILL on timeout,
drop the registry entries. One of the three selectors is
required — there is no implicit default.
codumentor dev logs [--repo NAME | --id ID] [-f/--follow] [-n N]
Print or tail the log file an instance writes to. With -f,
streams new lines until interrupted or the server exits. -n
sets how many trailing lines to seed; -n 0 dumps the whole
file.
Logs and where they live
Stdout and stderr from the spawned server go to
~/.codumentor/dev-logs/<instance-id>.log. The file is append-only;
the launcher never rotates or truncates it. Each launch gets a fresh
id (and so a fresh file), so the on-disk footprint grows by one file
per launch.
codumentor dev logs -f is the usual way to look at output:
$ codumentor dev logs -f
==> /home/me/.codumentor/dev-logs/codumentor-main-58231-a1b2c3.log [id=codumentor-main-58231-a1b2c3, repo=Codumentor, pid=12345, port=58231] (following — Ctrl-C to stop)
INFO: Started server process [12345]
INFO: Uvicorn running on http://127.0.0.1:58231 (Press CTRL+C to quit)
…
The follow loop exits cleanly when the server's PID disappears — so a
logs -f against a crashed server returns instead of hanging.
Selecting an instance
When you only have one preview running, the CLI uses it. When you have
more than one, pick with either --repo NAME (any unique repo) or
--id ID (use dev status to list ids). The error message lists the
valid options.
The admin-panel widget
The admin page renders a "Dev-Server Previews" panel that lists running
instances with:
- Repo / Branch — what's running
- URL — clickable, opens the preview in a new tab
- Health — live PID + port probe, refreshed every 3 seconds
- Age — time since launch
- Stop — sends a SIGTERM via the same path as
codumentor dev stop
Below the table there are two optional sections:
- Orphan processes — live processes carrying our internal marker but missing from the registry (you can see this if the registry file was deleted while servers were still running). Listed with a manual
kill <pid>hint; the plugin deliberately never auto-kills.
Limits, soft caps, and resource pressure
Each preview is a full server process — venv, sqlite, whatever else
your app pulls in. The launcher emits a soft warning to stderr if you
go above 3 running instances. There's no hard limit; CI and scripted
callers are never blocked, just reminded.
Selfdev (Codumentor's own dev_server)
codumentor-selfdev.yaml ships with a working dev_server block so
you can dogfood the launcher on Codumentor itself:
project_setup:
dev_server:
command: "${VIRTUAL_ENV}/bin/codumentor -c codumentor-selfdev.yaml api --port ${PORT}"
health_path: "/health"
open_url: "http://127.0.0.1:${PORT}/"
scripts/setup-worktree.sh --dev builds a worktree (its own venv + UI
build) and execs codumentor dev against it. Combined with the admin
panel, you get one row per worktree, clickable URLs, and a single
place to stop them when you're done.
Troubleshooting
| Symptom | Likely cause |
|---|---|
No repo … has a dev_server.command | The config in use has no dev_server block, or you passed --repo for a repo that doesn't have one. |
| Health check fails after 30s | Increase ready_timeout_seconds, or check codumentor dev logs — the process may be failing to bind. |
dev status shows a dead instance | A reconcile pass on the next CLI invocation drops it; you can force one with codumentor dev status itself. |
Orphan process in dev status | A registry was deleted (or moved by changing CODUMENTOR_DEV_REGISTRY) while a child kept running. Kill the listed PID by hand — the plugin won't. |
See also
- Design doc — the full design, including phasing and what's deliberately out of scope.