Skip to content

~6 min readgrounded in apps/cli/src/cli.ts · apps/cli/src/config.ts · apps/cli/README.md · docs/CLI.md · docs/EVIDENCE.md

CLI: npx tiny-vercel·

The CLI lives in the repository at apps/cli and ships as the npm package tiny-vercel. It is tiny-tech — the program behind every laptop on the production account — with its 54 hard-coded tiny.technology references replaced by one setting: where your deployment is.

npx tiny-vercel init https://<your-app>.vercel.app
npx tiny-vercel login
npx tiny-vercel

Three commands: point, sign in, run. Until the package is on npm (an owner decision, D-013) use a checkout: npm ci --prefix apps/cli && node apps/cli/dist/cli.js ….

The one setting·

init fetches <url>/api/health. That endpoint is public on every tiny-vercel deployment and answers with the site's name and the worker origin it uses — the same value its own browser bundle already ships — so the CLI never has to be told about the worker separately:

$ npx tiny-vercel init https://tiny-vercel-scratch.vercel.app
Checking https://tiny-vercel-scratch.vercel.app/api/health …
✓ tiny-vercel at https://tiny-vercel-scratch.vercel.app · worker https://tiny-vercel-worker.cagatay.workers.dev
  saved to ~/.tiny/config.json

~/.tiny/config.json (mode 0600) holds api, worker and siteName. When more than one source names a deployment the CLI takes the first of:

Order Source When you would use it
1 --api <url> on the command line one-off commands against another deployment
2 TINY_API_URL CI, a daemon unit file, a second account on one machine (TINY_HOME moves the whole ~/.tiny)
3 ~/.tiny/config.json the normal case — written by init and by login
4 the origin recorded by an earlier login (credentials.json) or enrollment (device.json) upgrading a machine that never ran init
5 an interactive prompt first run in a terminal with nothing configured

Inside an MCP client there is no terminal to prompt, so a missing setting is an error whose text is the init command. TINY_WORKER_URL overrides the advertised worker if you ever need to.

What it does·

Face Start it with What you get
MCP server claude mcp add tiny -- npx -y tiny-vercel — or {"command":"npx","args":["-y","tiny-vercel"]} in any MCP client's config 30+ tiny_* tools: identity, cross-agent memory (tiny_learn / tiny_recall), DMs, your tinys, forged tools, scheduled jobs, wallet, use_device — all proxied to your app's /api/* with your token. tiny_login opens the browser when a token is missing.
Local agent npx tiny-vercel (TUI) · npx tiny-vercel repl · npx tiny-vercel "one question" A Strands agent running on this machine: shell, files, HTTP, screen control, Apple / Spotify / Google / WhatsApp / Telegram / Flipper / ADB, npm / PyPI / OpenAPI / MCP bridges, local memory, notifications, background loops, parallel sub-agents. Bring a model key (tiny-vercel onboard, or TINY_MODEL_* / OPENAI_API_KEY / Bedrock / Ollama) or let your deployment's /api/chat run the turns.
Device daemon npx tiny-vercel mesh · npx tiny-vercel daemon install (launchd / systemd --user) Heartbeats so this machine shows online on /devices; polls the relay mailbox so the web agent's use_device can run work here; joins the devduck-compatible LAN mesh; serves a control socket (tiny-vercel tray status) that the optional Swift menu bar in apps/cli/menubar speaks.
Account plumbing login · logout · whoami · devices · onboard · sync · connect [google\|spotify\|telegram\|whatsapp] The consent flow (browser approves, code returns on 127.0.0.1, exchanged for a 90-day token), model-provider and voice settings synced through your account, optional app connections stored locally with 0600 permissions.

login also enrolls the machine as a device in the same step, so the very first mesh already heartbeats.

How it reaches your deployment·

Everything credentialed goes to the web app as Authorization: Bearer <token> against app/api/* — 27 routes, listed in docs/CLI.md. Three public reads (/retrieve, /list, /tools/browse) go straight to the worker the app advertised, and the same origin is the only place use_device will fetch a device's screenshot from. Nothing else on the network is contacted; there is no telemetry.

Proven against the demo·

On 2026-09-15 the exact sequence above was run from a clean TINY_HOME against the live demo: init derived the worker, login completed the loopback code exchange and enrolled the Mac, the daemon's heartbeat showed it online with 18 declared capabilities, and a chat on the demo asking the agent to use_device made the Mac run cat on a file that existed nowhere else — the file's contents came back in the chat 22 seconds later. Timings, sizes (npm pack 425 kB) and the raw tool results are in docs/EVIDENCE.md.

Where things live on disk·

Path Mode Contents
~/.tiny/config.json 0600 the deployment (api, worker, siteName)
~/.tiny/credentials.json 0600 your 90-day token and login
~/.tiny/device.json 0600 this machine's device id and token
~/.tiny/model-config.json, integrations.json 0600 onboarded providers, connected apps
~/.tiny/tools/ — your own tools (.mjs exporting {name, description, handler}); use_tools reload picks up edits
~/.tiny/tray.sock 0600 the daemon's control socket

TINY_HOME relocates all of it. logout removes credentials and the device identity, nothing else.

Testing and packaging·

npm test --prefix apps/cli builds with tsc and runs 1,445 tests in about 17 s; none of them touch a real backend — the MCP smoke test starts a loopback stand-in deployment. swift test in apps/cli/menubar covers the menu bar. The CLI keeps its own package-lock.json because its TUI needs React 19 while the web app pins React 18 (D-012); root npm test and CI run it via --prefix.