3.0 KiB
Example: Web server / API
The distinguishing concern for servers is lifecycle: an agent needs to
start the server in the background, verify it's up, interact with it, then
cleanly shut it down. A foreground npm start that blocks the shell is
useless to an agent.
Structure to follow
A good server run skill has:
- Prerequisites & setup — same as any project.
- Run — the background-launch pattern (below), not a blocking command.
- Verify — a
curlor similar that confirms the server is actually up. - Stop — how to cleanly terminate the background process.
If the background-launch + readiness-poll + smoke-curl sequence is more
than a couple of lines, put it in a smoke.sh inside the skill directory
and have SKILL.md say "run the smoke script." One command, exit code
tells you if the server is healthy.
Background-launch pattern
Don't write:
npm start
That blocks. Instead, show how to launch in the background, wait for readiness, and find the PID later:
npm start &> /tmp/server.log & SERVER_PID=$! # Wait for the server to come up (adjust timeout/port as needed) for i in {1..30}; do curl -sf http://localhost:3000/health > /dev/null && break sleep 1 done
Then the verification step:
curl http://localhost:3000/health # → {"status":"ok"}
And stopping:
kill $SERVER_PID # or, if you've lost the PID: pkill -f "node.*server.js"
Details worth documenting
- Which port. Make it explicit and say how to override it (
PORT=4000 npm start). - What "ready" looks like. A specific log line or a health endpoint to hit.
- Required env vars. Database URL, API keys, etc. — with a template
.envif the list is long. - Hot reload vs production mode. If they differ meaningfully, say which to use and when.
- Dependent services. If the server needs Redis/Postgres/etc., either
point at a docker-compose that brings them up, or include the
docker runcommand directly.
Example snippet
Here's what a Run section for a typical Node API might look like:
Run
Start the dev server in the background:
npm run dev &> /tmp/api.log &The server listens on port 3000. Wait for it to be ready, then verify:
for i in {1..20}; do curl -sf http://localhost:3000/health && break sleep 0.5 done curl http://localhost:3000/health # → {"status":"ok","version":"1.2.3"}Logs are at
/tmp/api.log. Stop with:pkill -f "tsx watch src/index.ts"Environment
Variable Required Default Notes DATABASE_URLYes — Postgres connection string PORTNo 3000LOG_LEVELNo infodebug/info/warn/error