Shell + jobs API

Run shell commands programmatically with cancellation, timeouts, and SSE streaming.

Endpoints

EndpointPurpose
POST /api/shell/runExecute a shell command, stream stdout/stderr as SSE.
POST /api/shell/testAuto-detect and run the project's test framework.
POST /api/shell/suggestLLM-powered command suggestion for a goal.
GET /api/shell/jobsList in-flight shell jobs.
POST /api/shell/cancel/<job_id>Cancel a running job.
GET /api/shell/recentList recent commands (for re-run).

Run a command

POST /api/shell/run
{
  "cmd": "pytest -k test_auth",
  "cwd": "<workspace-relative path, defaults to root>",
  "timeout": 300
}

Returns text/event-stream with frames:

data: {"type":"stdout","line":"…"}
data: {"type":"stderr","line":"…"}
data: {"type":"exit","code":0}

Hard timeout 300 seconds. Long-running processes (dev servers) should use the terminal PTY instead.

Friendly detector

shell_friendly_detector reads package.json scripts, Makefile targets, .env keys, and common CLI conventions to surface "things you probably want to run":

  • "Run tests" → pytest or npm test or cargo test
  • "Start dev server" → npm run dev or flask run or cargo run
  • "Lint" → eslint . or ruff check .
  • "Build" → npm run build or make build or cargo build

These appear as buttons in the terminal panel and as palette commands.

Test runner

POST /api/shell/test auto-detects the framework (pytest, jest, mocha, vitest, go test, cargo test) and runs it. Output is parsed for pass/fail counts.

Suggest

POST /api/shell/suggest:

{ "goal": "find all unused imports" }

Returns:

{ "command": "ruff check . --select=F401", "explanation": "..." }

The user always confirms before running.

Free-port substitution

Shell command templates can use $FREE_PORT. When KrowForge spawns the process, it scans for an open port and substitutes it. Useful for:

npm run dev -- --port $FREE_PORT

The chosen port is logged so you can navigate to http://localhost:<port>.

Job listing & cancel

GET /api/shell/jobs returns active jobs:

[{ "job_id": "j_…", "cmd": "pytest", "started_at": "…", "pid": 12345 }]

POST /api/shell/cancel/j_… sends SIGTERM, waits 3 s, then SIGKILL.

Recent

GET /api/shell/recent returns the last 50 commands (per workspace). Used by the terminal's "↑ Recent" picker.