Headless Agent Quickstart
Write your first agent.yaml, pick an isolation class, run it, watch its logs / traces / cost, then terminate it — end to end in about 15 minutes. The four worked demos in examples/headless-agents/ are the reference; this page builds the smallest one from scratch.
Prerequisites
Have the runtime services running. From the repo root, in separate terminals:
make dev-infra # Postgres + Redis + MinIO
make run-runtime-manager # runtime-manager on :50054
make run-scheduler # scheduler on :50055 / :8085
make run-api-runtime # control-plane wired to the scheduler, :8080Docker on the host is enough for the trusted and standard classes. You also need an API token exported as LANTERN_API_TOKEN for the REST calls below.
1. Write the spec
An agent.yaml declares the image, the isolation class, limits, and any egress / secrets. Here is the minimal one — a first-party script that only writes to stdout, so it picks trusted and asks for no network:
apiVersion: lantern.dev/v1
kind: AgentSpec
metadata:
name: hello
labels:
owner: lantern-team
spec:
image_digest: lantern/demos/hello@sha256:0000...0001
isolation: trusted # first-party, no package loading
limits:
vcpu: "100m" # 0.1 vCPU
memory: "64Mi"
timeout: 30s
scratch_size: "16Mi"
network: none # stdout only, no egress
secrets: []
egress_rules: []
idempotent: trueimage_digest is pinned by digest, not a tag — the runtime runs exactly the bytes you signed. Choosing the isolation class is the one decision that matters most; the isolation classes guide is the decision tree.2. Pick the isolation class
Rule of thumb: first-party signed code → trusted, your own code, default → standard, loads internet packages or drives a browser → untrusted, adversarial input → hostile. Demo 02 (web-scraper) uses untrusted precisely because it pulls requests + beautifulsoup4 from PyPI. Full tree in Isolation classes.
3. Run it
The CLI schedules the spec and tails the logs:
lantern run examples/headless-agents/01-hello/agent.yaml \
--input '{"name": "Ada"}'Or POST the spec directly to the control plane:
curl -X POST http://localhost:8080/v1/runtime/schedule \
-H "Authorization: Bearer $LANTERN_API_TOKEN" \
-H "Content-Type: application/json" \
-d @examples/headless-agents/01-hello/spec.jsonThe response carries a vm_id. If you are over your per-tenant quota the call returns HTTP 402 instead of scheduling.
4. Watch logs, traces & cost
Stream the harness log lines over SSE:
curl -N http://localhost:8080/v1/runtime/vms/<vm_id>/logs \
-H "Authorization: Bearer $LANTERN_API_TOKEN"Inspect the instance and its recent audit events:
curl http://localhost:8080/v1/runtime/vms/<vm_id> \
-H "Authorization: Bearer $LANTERN_API_TOKEN"Or open localhost:3001/runtime — the dashboard shows the live instance, its log stream, resource usage, and lets you exec in for debugging. If you have an OTel collector wired (Observability) you get one trace per spawn with token + cost telemetry; aggregate counters are at GET /v1/runtime/metrics.
5. Terminate
A clean-exiting workload is torn down automatically. To drain and stop one early:
curl -X DELETE "http://localhost:8080/v1/runtime/vms/<vm_id>?grace=30s" \
-H "Authorization: Bearer $LANTERN_API_TOKEN"The instance drains for the grace period, the manager tears down the pod, and the scheduler marks its state terminated.
What's next
- Isolation classes — pick the right boundary for the workload
- Durable execution — what happens when a node dies mid-run
- Identity & secrets — vend a real secret into the workload (demo 02)
- Observability — wire an OTel collector and read the trace