dev.config.json
Last updated April 7, 2026
kb-dev service definitions — ports, commands, dependencies, health checks, groups.
.kb/dev.config.json is the service catalog consumed by kb-dev, the Go binary that manages local development processes. Every long-running daemon in a KB Labs deployment (REST API, workflow daemon, marketplace, gateway, state daemon, Studio, etc.) plus its infrastructure dependencies (Qdrant, Redis, Docker containers) is declared here.
This is not the platform config. kb.config.json tells the platform which adapters to load; dev.config.json tells kb-dev which processes to start, how to health-check them, and what they depend on. They're separate files with separate schemas.
The reference file in this repo is .kb/dev.config.json — read it alongside this page for a real example.
Top-level shape
interface DevConfig {
version: string; // schema version — '1.0.0' today
name: string; // display name of the environment
description?: string;
groups: Record<string, string[]>; // group name → list of service IDs
services: Record<string, ServiceDef>; // service ID → service definition
}Groups
Groups exist so you can start related services in one command: kb-dev start infra boots everything tagged infra, kb-dev start backend boots all backend services. A service can belong to exactly one group; the group name is also declared on the service itself as service.group.
Typical groups (from the reference config):
{
"groups": {
"infra": ["qdrant", "redis", "state-daemon"],
"backend": ["workflow", "rest", "marketplace", "gateway"],
"ui": ["studio"],
"ui-web": ["kb-web", "kb-docs", "kb-app"],
"local": ["host-agent"],
"execution": ["runtime-server"]
}
}The rule of thumb is:
infra— stateful infrastructure that platform services depend on (vector DB, cache, state daemon).backend— HTTP daemons that serve the platform API.ui— the main Studio app.ui-web— marketing and docs sites.local— daemons meant to run on end-user machines (host agent).execution— container-mode execution backends.
Names are arbitrary — you can add your own groups and kb-dev will pick them up.
Service definition
interface ServiceDef {
name: string; // human-readable display name
description?: string;
group: string; // must match a group key
type: 'node' | 'docker'; // how to run it
command: string; // shell command to start it
stopCommand?: string; // shell command to stop it (for docker containers)
healthCheck: string; // URL for http check, or shell command
port: number; // TCP port it listens on
url?: string; // full URL (display + quick-open in CLI)
optional?: boolean; // kb-dev start won't fail if this one can't start
dependsOn?: string[]; // service IDs that must start first
env?: Record<string, string>; // env vars passed to the process
container?: string; // for docker: the container name
api?: { // display metadata
docs?: string; // URL of OpenAPI spec or docs
endpoints?: string[]; // list of example endpoints
};
}The definition is deliberately flat — no nesting, no inheritance. kb-dev reads it literally and treats each entry as an independent process.
type
Two types today:
'node'— a plain Node.js process.kb-devruns thecommandas a subprocess, captures stdout/stderr, tracks the PID, and probeshealthCheck.'docker'— a Docker container.kb-devruns thecommand(typicallydocker-compose up -d <name>) and usescontainerto track the container by name instead of by PID.
The distinction matters because lifecycle management differs: Node processes are killed by PID via kb-dev stop, containers are stopped via docker stop (or whatever stopCommand specifies).
command
The shell command to start the service. Multi-line commands are allowed — use && or ; to chain operations. Common patterns:
Node service built and ready:
"command": "node ./platform/kb-labs-rest-api/apps/rest-api/dist/index.js"The path is relative to the workspace root. kb-dev always runs commands with the workspace root as CWD, so you don't need to cd around.
Dev mode via pnpm filter:
"command": "cd platform/kb-labs-studio && pnpm --filter kb-labs-studio-app dev"Use this for services you want hot-reload on. Studio is the canonical example.
Docker container with cleanup:
"command": "docker stop qdrant 2>/dev/null || true && docker rm qdrant 2>/dev/null || true && docker-compose -f deploy/docker/docker-compose.yml up -d qdrant"The || true suppresses errors when the container doesn't exist yet — first-run safety.
healthCheck
How kb-dev decides the service is ready.
HTTP URL — kb-dev polls until it gets a 2xx response:
"healthCheck": "http://localhost:5050/api/v1/health"Shell command — kb-dev runs the command; exit code 0 means healthy:
"healthCheck": "redis-cli ping"Both forms are supported; the choice depends on the service. Most HTTP daemons expose /health (or /api/v1/health for the REST API); infrastructure like Redis or Postgres uses shell commands (redis-cli ping, pg_isready).
The health check runs on start (to know when the service is ready) and periodically afterwards (to catch crashes and trigger restarts if watchdog mode is enabled).
dependsOn
List of service IDs that must be healthy before this one starts. Forms a DAG — kb-dev topologically sorts the graph and starts services in order.
{
"rest": {
"dependsOn": ["workflow"]
},
"workflow": {
"dependsOn": ["state-daemon"]
},
"state-daemon": {
"dependsOn": ["redis"]
}
}When you run kb-dev start rest, kb-dev walks the dependency chain (rest → workflow → state-daemon → redis) and starts them bottom-up, waiting for each to pass its health check before moving on.
A dependsOn target that's optional doesn't block startup if it fails — kb-dev logs a warning and continues.
env
Environment variables passed to the subprocess. Values can reference other env vars (${KB_STATE_DAEMON_PORT}), but resolution happens in the shell, not inside kb-dev.
{
"state-daemon": {
"env": {
"KB_STATE_DAEMON_PORT": "7777",
"KB_STATE_DAEMON_HOST": "localhost"
}
}
}These are merged with the process env that kb-dev itself was started with — don't repeat PATH or HOME unless you need to override them.
optional
When true, kb-dev treats a start failure as a warning instead of an error. Used for services that aren't strictly required in every dev setup:
{
"redis": {
"optional": true,
"group": "infra"
}
}If Redis fails to start, kb-dev start infra still succeeds and continues to the next service. Downstream services can still depend on an optional — they'll start successfully if the optional dependency is missing, but their health check may reveal runtime errors later.
api (display metadata)
Optional block with links and endpoints shown in kb-dev status and the CLI's service-info view. Purely cosmetic — doesn't affect runtime.
{
"api": {
"docs": "http://localhost:5050/openapi.json",
"endpoints": [
"GET /api/v1/health",
"GET /api/v1/routes",
"POST /api/v1/workflows/runs"
]
}
}Use it to document the most useful endpoints and link to OpenAPI specs. It's the fastest way to give a new developer "here's where to look" context when they run kb-dev status.
Full example
A minimal entry for a typical platform service:
{
"rest": {
"name": "REST API",
"description": "Main platform REST API",
"group": "backend",
"type": "node",
"command": "node ./platform/kb-labs-rest-api/apps/rest-api/dist/index.js",
"healthCheck": "http://localhost:5050/api/v1/health",
"port": 5050,
"url": "http://localhost:5050",
"dependsOn": ["workflow"],
"api": {
"docs": "http://localhost:5050/openapi.json",
"endpoints": [
"GET /api/v1/health",
"GET /api/v1/routes",
"POST /api/v1/workflows/runs"
]
}
}
}A Docker infrastructure service:
{
"qdrant": {
"name": "Qdrant Vector DB",
"description": "Vector database for Mind RAG search",
"group": "infra",
"type": "docker",
"container": "qdrant",
"command": "docker stop qdrant 2>/dev/null || true && docker rm qdrant 2>/dev/null || true && docker-compose -f deploy/docker/docker-compose.yml up -d qdrant",
"stopCommand": "docker stop qdrant",
"healthCheck": "http://localhost:6333/",
"port": 6333,
"url": "http://localhost:6333"
}
}Adding a new service
- Pick a group. Usually one that already exists; make a new one only if nothing fits.
- Pick a port. Make sure it doesn't collide with other services. The convention is backend on 4000–8000, UI on 3000s.
- Add an entry to
dev.config.jsonwith the required fields (name,group,type,command,healthCheck,port). - Update the group's list to include your new service ID.
- Add
dependsOnif your service needs another service to be healthy first. - Run
kb-dev start <your-service>to verify it boots.
If the service is a platform daemon, it should also have a ServiceManifest (kb.service/1) in its source — that manifest is what lets kb-dev know how to install and update it when the service is published to npm. See Services → Overview for the relationship between ServiceManifest and dev.config.json.
kb-dev commands that read this file
Everything in kb-dev reads dev.config.json:
| Command | Uses |
|---|---|
kb-dev start [service|group] | services, groups, dependsOn |
kb-dev stop [service|group] | services, stopCommand, container |
kb-dev restart [service] | all of the above |
kb-dev status | services, healthCheck, port, url, api |
kb-dev logs [service] | services (to know what process to tail) |
kb-dev ensure [service] | services, dependsOn, healthCheck — idempotent start |
kb-dev ready [service] | services, healthCheck — block until healthy |
kb-dev doctor | services — check env, ports, dependencies |
None of them modify the file. To change the environment, edit dev.config.json and re-run the command.
Gotchas
cwdis always the workspace root. Don't rely on relative paths that assume you're inside a sub-directory; prefix withcdif you need to.- Commands run in a shell. Use
&&and|| truefor chaining, but be aware that this isn't a cross-platform shell — the dev config assumes Unix-style shells. Windows users need WSL or similar. - Port collisions are silent. If two services declare the same
port,kb-devwon't warn you at startup — it'll just fail health-checking the second one. Runkb-dev doctorto detect collisions explicitly. - Docker cleanup is your responsibility.
stopCommandruns when you saykb-dev stop, but ifkb-devcrashes mid-run, you may end up with orphaned containers.docker ps -aand manual cleanup. dev.config.jsonis not versioned by plugins. Plugin services need to be added manually. Future versions may auto-generate the file fromServiceManifestdeclarations at install time.
What to read next
- Services → Overview — how
ServiceManifestanddev.config.jsonrelate. - Configuration → kb.config.json — the platform config, distinct from this file.
- Configuration → Environment Variables — what the platform reads from env.