One Python file · one import at startup (six installable) · any OpenAI-compatible endpoint — llama.cpp, vLLM, SGLang, Ollama, or a cloud API.
Runs on the machine it manages: you send a task, it uses real tools (shell, execute_code,
edit_file, fetch_url, …), narrates its work, keeps state in plain files beside itself.
| With a self-hosted model, the cost is | tinycmdr |
|---|---|
| 15–30K tokens of harness boilerplate re-prefilled every uncached turn | ~4.1K-token fixed prompt on a clean unpack (est_tokens; the endpoint read ~3.5K in September) — tinycmdr status prints this install's |
| a volatile prefix that invalidates the KV cache every request | static prefix, volatile context tail-anchored |
| a looping or stuck model wedging your inference slot | loop guard, per-run scan budget, stall watchdog, supervised restart |
| "the UI" requiring a hosted service or an open LAN port | built-in browser page, token-gated, loopback by default — or CLI, --once, Mattermost/Telegram |
| no way to hand files back and forth | page uploads (drag-drop/paste) and downloads for files the agent offers |
| upgrade procedures per version | one update command from every version; host files never overwritten |
| infrastructure sprawl | no database, no container, no daemon: one process, plain files |
| secrets leaking into prompts | tokens live in .env only; config.json never holds one |
| Door | For |
|---|---|
| Page (default) | live cards, file upload/download, conversation rail, tasks/jobs/log/inventory, and a channel per cohort below — browser, phone on your LAN |
Terminal (--app, --cli) |
ops on the box |
| Chat (Mattermost / Telegram) | steering from anywhere; uploads both ways |
--once "…" |
scripts |
One process serves whichever are configured; same sessions, notes, skills, model switches.
The page can command more than the box it runs on. Give it cohorts — other tinycmdr boxes — and it grows a rail section (one row per cohort), a tab per engaged cohort, and a channel that streams that box's work line by line, exactly like a local run:
// the hub: config.json
"agent": {
"a2a_remotes": {
"storage": {"url": "http://storage.lan:8790", "token_env": "COHORT_STORAGE_TOKEN"},
"workshop": {"url": "http://100.101.2.3:8790", "token_env": "COHORT_WORKSHOP_TOKEN"}
}
}// each cohort: config.json (its own page needs nothing else)
"web": {"a2a": true, "a2a_policy": "read_only"}The hub relays server-to-server over the agent-to-agent protocol; token_env names a variable in
the hub's .env holding that cohort's page token — copy the cohort's TINYCMDR_WEB_TOKEN value
into the hub's .env under the name you chose (never into config.json), and orders and channels
only ever name a configured cohort. The rail's ADD COHORT does that setup for you — a name, the
cohort's URL and its page token, probed before anything is written — and the config.json block
above is the same thing by hand. Keep one token per box, so a lost or retired one rotates alone
(tinycmdr token set TINYCMDR_WEB_TOKEN on that box, then the hub's .env). a2a_policy: "read_only" lets a cohort answer with reads while refusing every write and command that arrives
over A2A; its own page keeps full tools. Address cohorts on a private network (the LAN, or a
Tailscale/WireGuard overlay) — this one link is plain HTTP with a bearer token, and a public
address is warned about at startup.
Windows — PowerShell, no administrator rights:
irm https://github.com/trappsquid/tinycmdr/releases/latest/download/install.ps1 | iexLinux and macOS — one line; it asks a few questions and writes nothing until you confirm:
curl -fsSL https://github.com/trappsquid/tinycmdr/releases/latest/download/install.sh | bashNeeds Python 3.10–3.12 (on macOS, --install-python fetches one for you). Only a Linux system install and a
macOS install with sudo ask for root.
| OS | download | then |
|---|---|---|
| Windows | tinycmdr-win.zip |
double-click INSTALL-WINDOWS.cmd |
| Linux | tinycmdr-linux.tar.gz |
sudo bash install/install-tinycmdr.sh |
| macOS | tinycmdr-macos.zip |
bash install/install-tinycmdr-macos.sh |
Stable names always point at the newest build. SHA256SUMS covers all eight published files
(checksummed, not signed — it catches corruption, not a replaced release):
base=https://github.com/trappsquid/tinycmdr/releases/latest/download
curl -fsSLO $base/tinycmdr-linux.tar.gz && curl -fsSLO $base/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing # macOS: shasum -a 256 -c SHA256SUMSUnattended installs, every switch, a second install on one host
Linux. --mode user|system, --yes; a run with no terminal never asks. macOS has one
kind of install — a per-user launchd agent, --no-launchd to skip it — so it takes --yes and
has no --mode. Every question has a switch: --mattermost-url, --allowed-user,
--telegram-token, --telegram-ids, --model-base-url, --model, --web-host, --web-port,
--web-token, --no-web, --no-path.
A second install on one host needs its own identity: TINYCMDR_SERVICE=tinycmdr-work … on
Linux, --label com.tinycmdr.work on macOS, -TaskName on Windows.
Windows — INSTALL-WINDOWS.cmd asks the same questions when run bare:
-InstallDir <folder> somewhere other than %USERPROFILE%\tinycmdr
-TaskName <name> the autostart entry this install owns
-NoPath leave the user PATH alone
-SkipTask files only: no autostart
-VerifyOnly report on an existing install, change nothing
-Uninstall [-Force] stop it, remove the folder and the autostart entry
-AsService boot-start task instead of a logon shortcut (elevated shell)
-TelegramToken <t> a Telegram bot token
-TelegramIds <ids> your numeric Telegram id(s)
-AddEndpoint <spec> another endpoint, repeatable: "<base_url>;<model>;<alias>;<key>"
-AddSearch <spec> another web-search provider, repeatable:
"<url>;<kind>;<label>;<key>" - kind defaults from the host
(anysearch, else searxng); a key is optional
-WebHost <addr> page bind: 127.0.0.1 (default) or 0.0.0.0
-WebPort <p> page port (default 8790)
-NoWeb install without the page
-NonInteractive ask nothing
Mac day-to-day notes: install/README-macos.md.
tinycmdr setup # once: endpoint, chat gateways, search consent
tinycmdr # the page, opens in your browser (the default door)
tinycmdr cli # the console alone: this folder, inline cards, no page
tinycmdr --app # the full-screen session alone, no page
tinycmdr --once "…" # one task, then exit
tinycmdr --no-web # the page off for this run (the lanes/service only)Keys (session): Enter send · ↑/↓ line, PgUp/PgDn page, Ctrl-Home/Ctrl-End ends ·
Ctrl-C stop run / quit idle · Ctrl-D/Ctrl-Q/Esc quit · Ctrl-Y copy newest item (again:
walk back) · Ctrl-B copy transcript. Wheel scroll: TINYCMDR_APP_MOUSE=1.
Page: token-gated always (TINYCMDR_WEB_TOKEN in .env; the installer mints one, and so does
the first start of a host that has none — an install that upgraded into the page). tinycmdr setup
asks the three things nobody can infer: loopback or LAN, the port, and the token (Enter keeps the
host's own or mints one; a token you bring replaces it — --web-token <t> does the same at
install). Loopback by default; 0.0.0.0 puts it on your network — token in cleartext there, so
trust the network. Rotate/reprint:
tinycmdr token set TINYCMDR_WEB_TOKEN # empty value mints a fresh one, prints the link
tinycmdr web # print the tokenized link (checks the page answers first; opens a browser when there is one)Chat: whichever token you configure runs that lane; both → one process serves both.
tinycmdr <verb> in a shell, /tinycmdr <verb> in the session and in chat:
| Verb | Does |
|---|---|
status |
version, folder, model, endpoint, context, log, instance |
doctor |
check this install, name what is wrong (exit 1) |
health |
one line + exit code, no network |
model |
picker; model setup wizard; model endpoint [<url>] read/fix; model use/add/remove |
logs [n] · version · proc |
log tail, version, process + lock state |
update |
fetch the published build (update <file|zip|folder> by hand) |
clean · token · config get|set <dotted.key> |
folder junk, secrets, config.json |
restart |
through this host's own door (launchd, systemd, Task Scheduler) |
/stop in the session/chat |
cancel the run now |
| a plain message mid-run | steer: folded in at the next step |
| Drop this | Get this |
|---|---|
skills/<name>/SKILL.md (YAML frontmatter: name + description; optional globs:, always: true, and hide: true for operator-only, then the runbook) |
live next message; one prompt-index line, read in full only when relevant; an operator-only runbook opens only when the operator names it |
tools/<name>.py or <name>.tool.json |
callable next call; listed by name and shelf, descriptions one find_tools call away |
create_tool |
the agent writes its own |
Flat as it grows: ~5.7 characters of tool index per tool at 80 tools.
tinycmdr update # fetch the published build (verified against SHA256SUMS)
tinycmdr restart # start running it (chat restarts itself)Never overwrites config.json, .env, soul.md, notes, tools/, skills/, theme.toml.
A missing theme.toml or soul.md is recreated from the shipped default
(theme.default.toml, soul.example.md) on start; an edited one is never touched.
An old or broken install updates with the same command (the launcher falls back to the published
update.sh / update.ps1).
| OS | Command |
|---|---|
| Windows | UNINSTALL-WINDOWS.cmd (double-click it in the install folder), or INSTALL-WINDOWS.cmd -Uninstall -Force (+ -InstallDir <folder> if not default) |
| Linux | sudo bash ~/tinycmdr/install/install-tinycmdr.sh --uninstall (+ --mode user) |
| macOS | UNINSTALL-MACOS.command, or bash ~/tinycmdr/install/uninstall-tinycmdr-macos.sh --uninstall |
Your Mattermost bot token is not touched; revoke it in Profile → Security → Personal Access Tokens.
This repository is the runtime - tinycmdr.py, the installers, the examples and the assets.
Development happens in trappsquid/tinycmdr-dev,
which carries the full history, the release tooling and the suites that grade it; from this
checkout python3 tinycmdr.py doctor is the check you have, and tinycmdr doctor on an installed
box is the same command.
What it is, measured — surface, budgets, failure handling, comparisons:
docs/tinycmdr-what-it-is.md.
The GUI tool's host notes (TCC grants and the stale case, Windows/Linux pitfalls, image routing):
docs/computer-use.md.
This repository is the install surface: it starts at the tree released as v1.0.87, and its
release carries the artifacts. The project's full history, its tags, its development tree and the
note explaining the 2026-10-07 sanitisation of that history live in
trappsquid/tinycmdr-dev — including how to check
that the sanitisation did not touch shipped code (the v1.0.87 archives are byte-identical to the
ones published before it). Releases are unsigned.
MIT. Free and open source for personal and enterprise hardware.