devstate is an agent-first development loop supervisor. A project defines setup commands, finite checks, and long-running services in devstate.json; the CLI writes a compact line-oriented status file for agents to inspect.
npm install
npm run builddevstate status
devstate start
devstate check
devstate stopdevstate with no command prints a compact command list with the devstate version. devstate status launches the interactive setup assistant when devstate.json is missing and the terminal is interactive. It detects setup commands, lets you choose setup commands, checks, and services, adds .devstate to .gitignore, writes devstate.json, and can start the dev loop. When devstate.json exists, devstate status prints the current compact status text from .devstate/status.md. Invalid invocations print the same command list with an error.
devstate start exits if devstate.json is missing. Otherwise, it runs setup commands synchronously, starts or reuses the service graph, waits for services to become ready, kicks off configured checks in the background, and exits without printing status on success. Background checks update .devstate/status.* as they run and may show failed checks, but the start exit code is governed by setup and service startup.
devstate check requires an already-running supervisor. If a background check from start is still running, it waits for that run to finish, then runs the configured checks again synchronously so the result is fresh evidence from this command. It prints compact status text and exits from that fresh check result plus current service lifecycle state. If services are stopped, it prints a stopped message, does not run checks, and exits nonzero.
devstate stop stops the supervisor, services, and any active background check process group if they are running, writes a stopped status, and exits without printing status on success. It is idempotent.
The .devstate/ directory is generated state and should be ignored by git:
.devstate/status.md.devstate/status.json.devstate/logs/*.txt.devstate/control.json.devstate/control.sock
Commands are shell command strings:
{
"$schema": "https://unpkg.com/devstate/schema/v1.json",
"setup": {
"install": {
"cmd": "npm install"
}
},
"checks": {
"check": {
"cmd": "npm run check"
}
},
"services": {
"web": {
"cmd": "npm run dev",
"events": {
"url": { "log": "(https?://\\S+)" },
"ready": { "http": "$url" }
}
},
"test": {
"cmd": "npm run test -- --watch",
"events": {
"ready": { "log": "watching" }
}
}
}
}Checks are finite commands. Their pass/fail state comes only from process exit code.
Services are long-running environment processes. events.ready is a readiness gate for devstate start; it can be a log regex or an HTTP probe. events.url captures URLs from service logs and prints them as inline evidence. Watch-mode test services are not completion gates: use checks for finite completion evidence. events.run, events.pass, and events.fail are not supported.
Agents should read .devstate/status.md first. The file keeps the old name for compatibility, but the contents are plain text:
devstate fail at 2026-06-30T10:22:31Z
🟢 npm run check > .devstate/logs/check-check.txt (4.2s, exit 0)
🔴 npm run test > .devstate/logs/check-test.txt (1.1s, exit 1)
FAIL specs/foo.md
expected operation "bar" to exist
🕒 npm run dev > .devstate/logs/service-web.txt (4203s)
http://localhost:3000
The first line is devstate <state> at <utc timestamp>. States are:
ok: all configured checks pass and required services are running/readyfail: any check failed, any required service failed/crashed, setup failed, or readiness timed outrunning: services are running while checks are pending or runningstarting: setup/services/checks are initializingstopped: services are stoppedstale: supervisor/control state is stale
Command lines are compact:
- Checks:
<icon> <cmd> > <relative log path> (<duration>, exit <code>) - Running checks:
🕒 <cmd> > <relative log path> (<elapsed>) - Pending checks:
🕒 <cmd> > <relative log path> - Services:
🕒 <cmd> > <relative log path> (<uptime>) - Stopped services:
⏹️ <cmd> > <relative log path> - Failed services:
🔴 <cmd> > <relative log path> (<duration>, exit <code if known>)
Inline evidence is indented by two spaces. Passing checks avoid success noise. Failed checks/services include a bounded, ANSI-stripped excerpt. Services include captured URLs.
Full stdout/stderr for commands and services is preserved in .devstate/logs/*.txt.