TINY(1)General Commands ManualTINY(1)

NAME — tiny · credential-less Claude Code & Codex sessions on your own Kubernetes

HOLDS NO KEYS

No keys. No open ports. Your cluster.

An agent that reads issues and pulls dependencies will eventually be told what to do by someone who is not you. tiny runs the real Claude Code and Codex CLIs as pods on your own Kubernetes, holding nothing worth stealing: no git credentials, no cloud credentials, nothing listening on the pod, egress denied by default. Work leaves as a signed-off bundle a courier pushes. When it asks to do something risky, your answer runs as you — not as the agent. And the session keeps working after you close the lid.

SEED PACKET Nº 1GERMINATES IN SECONDS
$ brew install tiny-systems/tap/tiny
ANY CLUSTER · MIT LICENSED
THE FLEET SCREENprod/team-a
$ tiny
NAME STATE AGE CPU MEM WHAT
✳ checkout-bug needs you 2h 112m 840Mi May I force-push the fix? [y/N]
● api-fix running 6h 212m 1.1Gi migrating auth tests to vitest
└ ● api-db running 41m 907m 2.9Gi rewriting migrations in golang:1.26
● night-run running 11h 1m 301Mi ⏸ usage limit · resuming 5:20am
✓ readme done 2d
[enter] attach · [a] answer · [m] message · [b] broadcast to all · drop a file
FOR ONE HUMANno team required

Give your laptop a rest — run your Claude Code on your own cluster.

Close the lid

The session lives in the cluster, not on your machine. Mid-conversation locally? tiny handoff moves it there, uncommitted changes and transcript included. Close the lid; attach from any terminal later.

$

Your subscription, not a token bill

tiny runs the real CLI, so you sign in the way you do on your laptop: Claude Pro/Max or ChatGPT Plus, the same plan you already use. (Automated or customer-facing work should use a metered API key under the provider's terms.)

Rate limits become naps

When a session hits your plan's usage limit, its fleet row shows ⏸ resuming 5:20am, and it resumes then on its own.

It asks before it leaps

The fleet screen shows who is waiting on you. You can answer inline, message a session without attaching, or drop a file onto its row.

CONTAINMENTboth halves · a claim is worth what its exceptions are worth
CLOSEDNOT NEGOTIABLE

Repo credentials. The agent has none. Work leaves as a git bundle; a courier pushes it with a short-lived token the agent never sees. It cannot push, force-push or reach your other repos — the capability is absent, not restricted.

Cloud credentials. None in the pod, and 169.254.169.254 — the endpoint that hands out an instance’s IAM role — is blocked.

Inbound network. Nothing listens. No container port; the MCP sidecar binds 127.0.0.1. You reach a session through the Kubernetes API under your own RBAC, never through an open port.

Acting as the agent. Approving a question runs in your client with your credentials. That is why the web page can only read.

OPENSAID OUT LOUD

The model credential lives in the agent pod. Running the real vendor CLI requires it. Inherent, not an oversight.

HTTPS out, unless you narrow it. A NetworkPolicy matches addresses, not hostnames, so by default any host on 443 is reachable. Switch on the hostname allow-list and only named hosts are — though allow-listing github.com still means an agent can write to a gist.

The agent’s own tool calls. It runs with bypassPermissions. Asking is cooperative — nothing intercepts it. The boundary is the pod, the missing keys and the policy.

Detail: threat model · egress policy · the gate

OPTIONSthe machinery under both
--the-real-thing
Attaching puts you in the actual Claude Code CLI over a TTY: hotkeys, plan mode, skills, your .mcp.json. tiny does not wrap or proxy the agent, so new agent features work without us doing anything.
--survives-anything
The workspace is a persistent volume; the pod is disposable. Kubernetes replaces dead pods on its own, and the replacement resumes the transcript.
--image any:tag
golang:1.26, buildah, your own dev image: an init container injects the agent into whatever you name. You do not maintain a special image.
--humans-hold-the-gate
Dangerous moves park as Question objects until you answer. Your y approves and performs the action with your credentials, so the audit log names you rather than a service account.
--no-credentials
Pods store no deploy keys or tokens. Work leaves through the outbox, so a compromised agent cannot push or call GitHub. On a laptop, a bypass-mode agent has your SSH keys and browser sessions; here it has a workspace and a model token.
--no-control-plane
There is no operator or manager pod; the CLI and Kubernetes do the work. The namespace holds only the sessions you run and the add-ons you switched on.
--tmux-native
Every session lives in tmux. Attaching is a real tmux attach, with panes and scrollback, and detaching does not stop the agent.
--resources cpu,mem
Per-session requests and limits from the session spec. The fleet screen shows each session's own CPU and memory readings.
--drop-a-file
Drag a file onto a session’s row in the fleet screen and it lands in that workspace under /workspace/uploads/.
--agent claude|codex
Claude Code by default; --agent codex runs OpenAI’s Codex. The fleet screen, the gate and resume behave the same for both.
--model your-pick
Pin the model per session (claude --model / codex -m underneath). Also a field on the options form.
--broadcast
One message into every unfinished session's inbox: [b] on the fleet screen, or tiny broadcast from cron and CI.
NO SERVERMIT LICENSEDYOUR CLUSTER · YOUR KEYS
ADD-ONSone checkbox each · six today, and counting
[✓] registry-cacheZOT

Pull-through image cache in your namespace. golang:1.26 downloads once instead of once per session, which also keeps you under docker.io rate limits. An optional DaemonSet installs its CA on the nodes.

[✓] artifact-storeMINIO

S3-compatible store next to the sessions, for things too big for git: builds, screenshots, datasets.

[✓] github-runnerACTIONS

In-cluster Actions runner, so delivery jobs can reach the sessions. A labeled issue lands in an inbox in about five seconds.

[✓] web-pageREAD-ONLY

The fleet as a page, plus each session’s blast radius: files changed, lines, branch, and the files two sessions are both editing. Port-forward to reach it; it can only read.

[✓] egress-policyNETWORK

Default-deny networking for sessions: this namespace and http/https out, nothing else. Closes the cloud metadata endpoint and every other port. It does not stop exfiltration over 443 — and it only bites if your CNI enforces NetworkPolicy, which the screen tells you.

[✓] hostname allow-listEGRESS PROXY

All outbound traffic through a CONNECT proxy that filters by name, not address — the thing a NetworkPolicy cannot do. TLS is never terminated; the hostname is read before the tunnel opens. Closes the DNS channel too. Refusals name the host and get logged.

[ ] your-next-one
each add-on is a single toggle
in tiny settings
DEMONSTRATIONrecorded, not staged — pick a scene

Recorded against a real cluster, including the kubectl delete pod. Tapes in the repo.

FOR YOUR TEAMthe loop: issue in · PR out

Label an issue. Harvest a pull request.

1

Sow

File a GitHub issue and add the tiny label. That is the whole ceremony. Anyone on the team can do it from the GitHub UI.

2

Deliver

An Actions job on the in-cluster runner pipes the issue into the root session's inbox. It usually takes about five seconds.

3

Grow

The root session plans, spawns specialists in the right toolchains, and raises a when a decision needs a human. Overnight is fine; we test session recovery by killing pods mid-task.

4

Harvest

Agents hold no credentials. Finished branches leave as git bundles through the outbox, and a short-lived courier token opens the pull request and comments on your issue.

THE ENTIRE INTEGRATION.github/workflows/tiny.yml
on:
issues: { types: [labeled] }
jobs:
deliver:
if: github.event.label.name == 'tiny'
runs-on: [self-hosted, tiny]
steps:
- run: |
printf 'issue #%s: %s\n\n%s' "$N" "$TITLE" "$BODY" \
| tiny deliver root --ensure --repo "https://github.com/$REPO.git"
the task hand-off is a prompt piped into tiny deliver · full workflow in the docs

PROOF — this loop produced a real pull request in our demo repo: github.com/tiny-systems/seedling

FIELD NOTESthe blog
We can't stop the agent, so we emptied its pockets2026-09-16

A coding agent reads untrusted text for a living. Ours runs with permissions bypassed and holds no credentials at all. The reasoning, and the part we haven't solved.

Codex, day one2026-08-29

The second agent took an afternoon. The two bugs it surfaced were nowhere near the model.

The outbox: agents that hold no credentials at all2026-08-29

Job tokens die with their jobs and deploy keys sprawl, so our agents stopped pushing entirely.

all field notes →

MANUALthe docs — every page one static file

Install

One binary, one wizard, no pods until your first session.

$ brew install tiny-systems/tap/tiny
$ tiny setup     # cluster · runtime · claude token
$ tiny new "make the tests not lie"

tiny pins one cluster per machine, chosen with an arrow-key picker on every start — enter‑enter repeats yesterday's choice. Read the full manual →

SEE ALSOsupport the garden

Built in the open, watered by stars.

tiny is MIT-licensed. We are early, and stars are the main way people find small projects like this one — if you want this to keep growing, a star genuinely helps.

SUPPORT OUR WORK ★ Leave a star github.com/tiny-systems/tiny
Two little robot gardeners tending rows of potted seedlings — one watering a sprout, one carrying a branch