LanternDOCS

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, :8080

Docker 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: true
Note: image_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.json

The 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