svc.nz

SheepishlyVersatileContainer

★ Beta · 2026

Capability-addressable byte storage for scripts, agents, and humans. Reading and writing a box that already exists needs only that box's capability token, and creating a new box or account is invite-only for now.

Box addresses

svc.nz/<box>

svc.nz is pronounced service. A box stores named files that clients read and write over HTTP, addressed by the box handle and authorised by a capability token in the Authorization header. Every PUT creates a new version of the stored file.

Access model

WHAT'S A CAP?

A capability, or cap for short, is a secret token written like cap_access_a3F2…9bQ. Anyone who holds a valid capability can use the permissions it grants for an existing box. The client sends this token in the Authorization header, never in the URL.

  • like a keyAnyone who holds the capability can use the permissions it grants. Sharing the capability gives the recipient those same permissions.
  • per-boxEach capability grants access to one box or a limited part of it. A capability for one box cannot authorize access to another.
  • rotatableA response can supply a replacement capability in cap_next. Clients adopt that replacement before their current access capability expires.
  • stored tokensA capability can be stored as bytes inside another box. Sharing a capability with limited permissions lets a recipient access a resource without receiving broader access.
See it in action

Terminal examples for common workflows

These seven examples illustrate file transfers and coordination between clients over HTTP. The panels include shell, HTTP, and Python examples with abbreviated tokens and response data. Creating any new box or account first requires an invitation.

agent cap rotated

Agent inbox with long polling

Worker B requests new data with ?wait=30 and receives a response when Worker A writes a message or the wait ends.

bob@worker-b · bash · 80×24
tmux 1/3
alice@worker-a ~/agent $ curl -sS -X PUT \ -H "Authorization: Capability $CAP_W" \ -H "Content-Type: application/json" \ --data '{"task":"summarize","url":"…"}' \ https://in.svc.nz/bbb222/_inbox ← 200{"version": 1, "cap_next": "cap_access_9b…3pQ"} bob@worker-b bob@worker-b ~ $ curl -sS -H "Authorization: Capability $CAP_R" \ "https://out.svc.nz/bbb222/_inbox/latest?after=v0&wait=30" # waits until the next version arrives ← 200X-SVC-Version: 1 X-SVC-Cap-Next: cap_access_9b…3pQ {"task":"summarize","url":"…"}
handoff scoped read

Scoped capability handoff

Alice derives a read-only capability and writes it to Bob's inbox. That capability lets Bob read docs66/handoff.txt without granting access to other files.

alice@laptop · zsh · 80×24
tmux 2/3
alice@laptop ~/svc $ svcbox derive --cap $CAP_DOCS --scope read \ --name handoff.txt --ttl 15m --json ← ok{ "cap": "cap_access_read_4f…2nM", "scope": ["read", "docs66/handoff.txt"], "expires_in": 900 } alice@laptop ~/svc $ svcbox put bob666 _inbox \ --data-stdin --type application/json \ --cap $CAP_BOB_INBOX <<'JSON' { "type": "svc.nz.introduction", "to": "bob666", "target": { "box": "docs66", "name": "handoff.txt", "cap": "cap_access_read_4f…2nM" } } JSON ← 200uploaded · v7 · cap_access_8c…1bF
recover v3 → v4

Resume token that survives a crash

After a worker crashes, its replacement reads the saved cursor at v17. The replacement uses that checkpoint to resume processing from the last saved position.

ops@k8s · bash · 80×24
tmux 3/3
# worker-old crashes after saving checkpoint v3 ops@k8s ~ $ kubectl get pod rollout-42 ← outNAME STATUS RESTARTS rollout-42 CrashLoopBackOff 7 # a replacement worker reads the checkpoint and resumes ops@k8s ~ $ curl -sS -H "Authorization: Capability $CAP_R" \ https://out.svc.nz/home66/_resume/9f86d081…/latest ← 200{ "session": "rollout-42", "cursor": "v17", "checkpoint": "2026-05-07T03:14:21Z", "cap_next": "cap_access_read_next_d2…7Lp" } ops@k8s ~ $ ./worker --resume v17 --cap $CAP_NEXT [ok] loaded state, resume at v17 [ok] emitted v18 · v19 · v20 [ok] rollout-42 complete
cache skip repeat work

Tool-result cache

The agent hashes (tool, args) to identify a stored result. A cache hit lets the agent reuse that result while it remains valid.

agent@runner · bash · 80×24
cache.py
agent@runner ~ $ KEY=$(jq -cS '.' < tool.json | sha256sum | cut -c1-16) agent@runner ~ $ echo $KEY ← out3b8a7e21f4c0a991 agent@runner ~ $ curl -sS -w '%{http_code}\n' \ -H "Authorization: Capability $CAP_R" \ "https://out.svc.nz/home66/cache/$KEY/latest" ← 200{"result": "london, 14°C, light rain", "computed_at": "…"} 200 # cache hit, the stored result is reused # on a miss, run the tool and store the result agent@runner ~ $ ./tool.sh | curl -sS -X PUT --data-binary @- \ -H "Authorization: Capability $CAP_W" \ "https://in.svc.nz/home66/cache/$KEY"
ci/cd existing box

CI artifact handoff

CI uploads build.tar.zst to an existing box using its write capability. The deployment job requests v1 with a read capability to fetch that specific version.

github-actions / runner · bash · 132×30
.github/workflows/release.yml
# --- step: build --- ci@runner /work $ tar --zstd -cf build.tar.zst dist/ ci@runner /work $ curl -sS -X PUT --data-binary @build.tar.zst \ -H "Authorization: Capability $SVC_CI_CAP" \ -H "Content-Type: application/zstd" \ https://in.svc.nz/release7/build.tar.zst | jq ← 200{ "version": 1, "sha256": "62f1c0…7a90", "size": 8421073, "cap_read": "cap_access_read_aa…7Yt" } ci@runner /work $ echo "::set-output name=cap_read::$CAP_R" deploy@prod-1 # deploy pulls that exact version deploy@prod-1 /srv # curl -sS -H "Authorization: Capability $CAP_R" \ https://out.svc.nz/release7/build.tar.zst/v1 | tee incoming.tar.zst | sha256sum ← out62f1c0e7…7a90 - [ok] sha matches release7 v1 · 8.4 MB · 2.1s
sealed byte-blind

Encrypted file transfer

The client optionally encrypts the file before uploading any bytes. The encryption key stays on the client, and the server stores ciphertext.

aroha@laptop · fish · 100×28
aes-256-gcm
aroha@laptop ~/photos $ svcbox key ← outk_aes256_a3F2…9bQ # 256-bit key in base32 aroha@laptop ~/photos $ svcbox put oneuse2 photo.jpg --cap $CAP_W \ --file photo.jpg --encrypt-key $KEY --ttl 3600 --json ← ok{ "version": 1, "box": "oneuse2", "size": 2104832, "encryption": "aes-256-gcm", "expires_at": "2026-05-08T03:14:02.000Z" } svc@edge # the server stores ciphertext only svc@edge /srv # xxd oneuse2/photo.jpg/v1 | head -1 ← outa8 c4 1f e2 6b 9d 04 7f 3c 11 d6 22 91 5e 0a bb ! # Decrypting photo.jpg requires the key held by the client.
personal expiring transfer

Hand someone a file

A sender needs an existing box or an invitation to create one. The recipient downloads it with the file URL and a capability in the Authorization header. Anonymous boxes expire when their configured lifetime runs out.

you@laptop · zsh · 80×24
share
# creating a box needs an invite you@laptop ~/Desktop $ svcbox share screenshot.png \ --ttl 86400 --content-type image/png ← ok{ "url": "/out/sh7b3kp2/screenshot.png/latest", "authorization": "Authorization: Capability cap_access_read_7m…Qp", "expires_at": "2026-05-08T03:14:02.000Z" } friend@phone # the recipient downloads with the shared cap friend@phone ~ $ curl -H "Authorization: Capability cap_access_read_7m…Qp" \ https://svc.nz/out/sh7b3kp2/screenshot.png/latest -o screenshot.png [ok] got 412 KB · expires tomorrow
PUT and GET

How it works

in

PUT

$ curl -X PUT -H "Authorization: Capability $CAP" --data-binary @thing \ https://in.svc.nz/<box>/<name> { "version": 1, "cap": "cap_8a…7xK", "cap_expires_at": "+24h", "cap_next": "cap_9b…3pQ" }

The client uploads bytes to an existing box using its write capability. When the response supplies a replacement capability, the client adopts it for subsequent requests.

out

GET

$ curl -H "Authorization: Capability $CAP" \ https://out.svc.nz/<box>/<name>/latest X-SVC-Version: 3 Last-Modified: 2026-05-05T10:14:02Z Content-Type: application/octet-stream # …bytes…

The client requests a specific version with /v2 or the most recent version with /latest. The capability must grant read access to the requested file and version.

up

UPDATE

$ curl -X PUT --data-binary @thing \ -H "Authorization: Capability $CAP_NEXT" \ https://in.svc.nz/<box>/<name> uploaded · v4 · cap_8a…7xK # earlier versions stay readable

Another PUT to the same path creates a new version. Previous versions stay readable until the box expires, or until someone holding the refresh capability deletes them.

What a box does

Storage properties

01

SECURE

Each request carries a capability in the Authorization header. Reading or writing an existing box requires a capability with the corresponding permissions.

02

VERSIONED

Every PUT creates a new version instead of overwriting bytes in place. A client can request any earlier version by its number, and a number is never reused.

03

COMPOSABLE

A capability can be stored inside another box to pass access to a recipient. Replacing that stored token does not invalidate copies a recipient already holds.

04

NON-PERSISTENT

Anonymous boxes expire when their configured lifetime runs out. Clients must retrieve any needed files before the box expires.

05

CLIENT-SIDE ENCRYPTION

Client-side encryption is optional, and its key never leaves the client. When encryption is enabled, the server stores ciphertext that requires the key to decrypt.

Capability rotation

Capability rotation for long-running clients

Long-running clients adopt cap_next when a response provides a replacement access capability. The client saves that token for subsequent requests before the current capability expires.

The two-cap model separates a longer-lived cap_refresh, used at /refresh, from the cap_access used for reads and writes. Clients keep the refresh capability out of ordinary PUT and GET requests. Access capabilities belong in Authorization headers rather than request URLs.

sensor@field-7 · bash · rotate.sh
rotate.sh
#!/usr/bin/env bash set -euo pipefail CAP="$CAP_INITIAL" while true; do resp=$(curl -sS -X PUT --data-binary @reading \ -H "Authorization: Capability $CAP" \ "https://in.svc.nz/sensor7/reading") CAP=$(jq -r '.cap_next // .cap' <<< "$resp") sleep 30 done # adopt cap_next when the response carries one
Auth profiles

Available authentication profiles

Authentication profiles are configured separately for each HTTP method when a box is created. The setting auth.put=passkey&auth.get=none requires a passkey alongside the capability for writes, while reads use the capability alone.

A

NONE

The default profile accepts a capability with the required permissions. The client supplies it in the Authorization header for each request.

B

COMPOUND

The compound profile requires two capabilities for each request. The capabilities can be held separately until the request is made.

C

PASSKEY

This profile requires a capability plus a WebAuthn assertion from Touch ID, a fingerprint reader, or a hardware key. It suits human-operated boxes without adding a shared secret.

D

TOTP

This profile requires a capability and a time-based one-time password. The client supplies the current code along with its capability.

Request shape

Request format

in.svc.nz/<box>/<name>
Authorization: Capability <token>
in.svc.nz
Clients write to in.svc.nz and read from out.svc.nz using the same box and file name.
<box>
The box handle identifies the box containing the requested file.
<name>
The name identifies a file within the selected box.
<token>
The capability in the Authorization header grants specific permissions for the box. Anyone holding that token can use the permissions it grants.