Highlights
- Agents are private by default, and every run is authorized. A
privateagent (the new default) runs only for its owner or an instance admin — anyone else gets a404indistinguishable from a missing agent. API keys now carry enforced operation and resource scopes (agent:run/agent:push, optionally pinned to specific agents), operators choose who may attest a version (SKRUN_VERIFICATION_POLICY), and an agent's owner can attach their own LLM key to it, encrypted at rest. - Run untrusted skills in a throwaway sandbox. Each
POST /runcan execute in its own short-lived machine with an egress allowlist enforced at the network layer, built from a multi-runtime image you can pull directly —ghcr.io/skrun-dev/skrun-runtime, carrying Python 3.12, Node 22, Go, Rust, Ruby and Java. The first backend is Fly.io (SKRUN_RUNTIME=flyio); operators using it can keep machines warm ahead of demand withSKRUN_RUNNER_POOL_SIZE, and each run reports a per-phase startup breakdown. - Self-host in one command, dashboard included.
infra/docker-compose.ymlbrings up API + Postgres + MinIO + Caddy at production parity, and the published image now serves the operator dashboard at/dashboard— previously it was API-only and the console had to be hosted separately. - Postgres, without a vendor.
DATABASE_URLtakes any standard Postgres ≥ 14. Migrations apply automatically on boot, serialised by an advisory lock so rolling deploys don't race. SQLite remains the zero-config local default. - A credential only travels to an endpoint its owner chose. An
agent.yamlmay declaremodel.base_url, so the server no longer sends its own key there, and it refuses yourX-LLM-API-Keyunless you name the destination yourself withX-LLM-Base-URL. Both relaxations are explicit operator opt-ins, off by default. - Hardening, four internal audit cycles' worth. Request forgery is blocked on the resolved IP rather than the hostname, sandbox egress is contained on IPv6 as well as IPv4, the runner control RPC is authenticated per run, bundles are integrity-checked on download,
max_costis enforced rather than merely logged, and 16 outstanding high-severity advisories are down to none.
Known issue
The boot error message names the wrong Supabase pooler port. When the api-server starts without DATABASE_URL, the error it prints suggests the "Supabase pooler URL on port 6543". That is transaction mode, and it silently breaks the pg_advisory_lock the migrations runner takes to serialise concurrent boots. Use the Session Pooler on port 5432, as the Migration section below says — the documentation is right, the message is wrong. Corrected after this release; the fix is not in the 1.0.0 artifacts.
Breaking
- Agents are private by default and
POST /runis run-authorized. Any authenticated caller could previously run any verified agent in any namespace. Existing agents migrate toprivateon upgrade; thepublicset-path is disabled in this release. - The server's own LLM key is no longer sent to an agent-declared
model.base_url. Opt in withSKRUN_ALLOW_SERVER_KEY_CUSTOM_BASE_URL=trueonly where every agent on the instance is yours. - A caller-supplied
X-LLM-API-Keyis refused when the agent declares amodel.base_urlyou did not name. SendX-LLM-Base-URLto state the endpoint your key belongs to. - The Docker Compose stack has no default credentials.
POSTGRES_PASSWORD,S3_ACCESS_KEY_IDandS3_SECRET_ACCESS_KEYmust be set — the stack refuses to start otherwise. DATABASE_URLtakes apostgres://URI, not a Supabase HTTPS project URL. The API validates the prefix at boot and refuses a stale value.
Migration
This is a security upgrade as much as a feature release. The Breaking section above describes behaviour that 0.8.0 and earlier still exhibit; upgrading is how you leave it behind.
- Node 22+ is now the floor.
- Set
POSTGRES_PASSWORD,S3_ACCESS_KEY_IDandS3_SECRET_ACCESS_KEYbefore bringing the Compose stack up — see.env.example. - Move
DATABASE_URLto a standard connection string. On Supabase use the Session Pooler on port 5432: transaction mode on port 6543 breaks the advisory lock the migrations runner relies on. - If you point a model at Ollama or another local endpoint, set
SKRUN_ALLOW_LOCAL_MODEL_HOSTS=true— private and loopback addresses are refused by default. - Callers sending their own key to an agent they do not own must add
X-LLM-Base-URL.
Stats
- 1836 unit + integration tests pass (was 1222 at v0.8.0)
- 140 E2E in-memory, plus the live multi-provider suite
- Four internal security audit cycles closed; 16 high-severity advisories down to zero
- OpenAPI 3.1 spec at 1.0.0
Install
npx @skrun-dev/cli@1.0.0 --version
# or
npm i -g @skrun-dev/cli@1.0.0Full changelog: CHANGELOG.md