joulebox

Agentic Go and Python (experimental)

Pay for the work, not for the lease.

For humans

last — ms — Jsession — J · $0.20/kJ
:w write · :wq / ZZ write+close · :q close · :fmt gofmt · Ctrl-S write

Not asciinema. Live.

For agents




Reaching the network

SID=$(curl -sS -X POST "$ORIGIN/v1/session" | jq -r .id)
# the session's answer also has "allow": ["example.com"]
jq -Rs --arg sid "$SID" '{session:$sid,op:"W",path:"get.go",data:.}' <<'EOF' \
  | curl -sS --fail-with-body "$ORIGIN/v1/fs" --json @-
package main
import "io"
import "net/http"
func main() {
	resp, err := http.Get("https://example.com/")
	if err != nil { println(err.Error()); return }
	b, _ := io.ReadAll(resp.Body)
	resp.Body.Close()
	println(resp.Status)
	println(string(b))
}
EOF
curl -sS --fail-with-body "$ORIGIN/v1/exec" \
  --json '{"session":"'"$SID"'","line":"go run get.go"}' | jq -r .stdout

A program reaches the network only through the proxy: https only, port 443, host names, not IP literals. A response is at most 1 MiB, the exchange at most 2 seconds, and at most 3 redirects.

An anonymous session's list is the box's, today example.com, and allow in the request is ignored. POST /v1/session answers with "allow", the list that session got. A session of your own hosts needs a key: Authorization: Bearer <secret> and {"allow":["api.example.org"]}, at most 16 hosts. A wrong key is 401. More than 16 hosts is 400. Keys are issued by hand for now.

A refusal names its rule: proxy: host not allowed (not on the list, before DNS), proxy: address refused (the name is metadata, or a DNS answer is not a public address; nothing is dialed), proxy: scheme not allowed (not https), proxy: bad request (an IP literal, or a malformed URL), proxy: too many redirects, proxy: timeout, proxy: too large, proxy: budget exhausted, proxy: unavailable, proxy: no egress (this session has no list).

What a run costs

A line's energy is CPU time × 2 W, at $0.20/kJ. The Graviton has no energy counter.