Docs › Changelog
Changelog
What each version of Sparehand added, changed or fixed. Beta features (Crew, Studio, members, cloud machines, cloud AI providers) are listed with the rest; see requirements.md for what each needs.
0.1.0 — first release
Released: (date of the public release)
Running jobs
sparehand runsends a command to the least busy worker with room (memory, disk, job slots, CPU, GPU), syncs the git checkout with rsync, runs it in the same folder and passes the exit code through.run --get coverage,distcopies results back when the job ends. The job history steers a command to the machine that was fastest for it (SPAREHAND_HISTORY=0to switch off). Exit 255 means "run it locally";run --or-localdoes that for you.- A Windows (WSL2) worker's GPU bridge is measured (
lib/worker-gpu-probe.sh: a 256 MB copy to the card, with Studio's PyTorch, cached 10 minutes): under 1 GB/s it is degraded (after days up the path drops from about 8 GB/s to 0.1 until Windows restarts), sorun --gpupasses the machine over, status and the Machines tab say so, andsparehand set NAME heal autorestarts Windows there by itself when nobody uses it (ask, the default, gives a Restart Windows button;restart-at HH:MMa daily restart). The Activity tab logs the speed before and after. sparehand runner add WORKER OWNER/REPO(andlist,status,remove,start,stop; the dashboard's GitHub Actions… on a worker's card): a worker becomes a GitHub Actions self-hosted runner for a repository in one step. The registration token comes fromghon the hub or is pasted, and is kept nowhere. On Linux and WSL with Docker each job runs in a new container; on a Mac as your user, under a launchd agent. A runner's job takes one of the worker's job slots, waits while the worker is full or paused, and is stopped by the same watchdog as arunjob. A public repository is refused unless confirmed.removederegisters the runner at GitHub and leaves nothing on the worker;sparehand remove NAMEcovers it. See ci-runners.md.sparehand emulator start|list|stop|setup: Android emulators boot headless on the workers (a Linux or Windows one first, a Mac next, a cloud VM last) instead of the hub, each reached by adb here at a forwarded serial (127.0.0.1:15555…, forANDROID_SERIAL); exit 255 when none can.setupinstalls a JDK, the Android SDK, the emulator and a system image without sudo. An emulator counts as a job, stops after 30 minutes without adb use, and on a cloud VM within its daily cap. The dashboard lists them on each machine's card with a Stop button.- Workers on macOS, Linux and Windows (WSL2), plus Linux servers anywhere (by IP, domain name or Tailscale name).
- A watchdog stops a job when its worker runs low on memory, is paused, or its GPU gets busy; a job also stops on the worker when the hub's connection drops (Ctrl-C, an agent timing out).
- A job that fails with "command not found" (exit 127) on a worker exits 255, so it runs locally.
pause/resume(flag on the worker),disable/enable(flag on the hub, which a worker can't flip back),sparehand stop NAME PID.- Worker mode closes a worker's apps while it builds and reopens them when it is idle.
- Per-repository hooks, per-worker CPU limits, git worktree support,
.envfiles kept home. SPAREHAND_WAIT=SECONDSwaits for a free worker instead of running locally at once.- Workers below
SPAREHAND_MIN_DISK(5 GB) free disk get no jobs; run folders of deleted checkouts and folders unused for 30 days are cleaned up automatically, at most once a day. - On a Mac worker, swap only counts as used memory while macOS reports memory pressure.
Speed
- Split test runs:
sparehand run --split[=N]runs one suite in parts at the same time on this computer and the free workers (Jest, Vitest, Playwright via--shard, pytest by files, also through npm/pnpm/yarn/bun test). Parts are handed out as machines finish one, and a slow machine stops taking parts once the others would finish the rest sooner, so all end at about the same time. A 235-file Jest suite went from 2 min 33 s on one machine to 55 s on three. - Faster jobs: a short job's overhead went from about 6 s to 1.6 s (one shared SSH connection per worker, quicker CPU and GPU sampling, no waiting for the watchdog at the end).
- Dependencies shared between checkouts: workers keep installed
node_modulesper lockfile version, so a new checkout of the same project (such as a git worktree made by an AI agent) copies them instead of reinstalling.SPAREHAND_DEPS_CACHE=0switches it off.
Agents & tests
sparehand agent install [--project]adds a Claude Code hook that hands tests, typechecks and lint to the workers automatically; builds, installs, git and dev servers stay local, and your permission rules still apply.agent statusandagent uninstall.- A ready-made snippet for
CLAUDE.md/AGENTS.mdfor other agents, and a SwiftBar menu-bar plugin. sparehand crew "TASK" [--repo PATH] [--base BRANCH]starts a Crew task from the terminal (the repo defaults to this git checkout) and prints its id and dashboard link;crew list,crew show ID(plan, parts, the Master's summary) andcrew approve ID. It uses the dashboard's API on 127.0.0.1, so the dashboard has to be running.
Machines
- Pair with a code: one command on a new Mac, Linux or Windows machine installs what's missing, lets the hub's key in (limited to the hub's addresses) and shows a check code to confirm on the hub. The join script's checksum is verified, and so is the machine's SSH key.
sparehand addchecks a machine first;hostkey/trustaccept an SSH key only after you compare its fingerprint (a changed key for a known address is refused);doctor,setup-info,list,set NAME jobs|cpus|screen,remove.- Add a machine in the app: a guided flow for Mac, Linux, Windows PC and servers with the exact commands, a fingerprint check and lock-down steps. Servers get their own build user.
- Rename a worker, or the hub:
sparehand rename NAME NEW(rename hub NEW). - Wake and sleep: workers are woken with Wake-on-LAN when a job needs one, kept awake during long jobs, and can be put to sleep (
sparehand sleep NAME, or automatically afterSPAREHAND_SLEEP_IDLE_MINidle minutes on Mac and Linux, never while someone uses them). A machine that woke up on another adapter than its ssh alias points to (cable unplugged, Wi-Fi answers) is recognised:sparehand wakeand the automatic wake say which address answers and that the usual route is down, instead of "didn't wake up". Jobs still go through the alias. - Forwards:
sparehand forward NAME PORT [LOCAL-PORT]makes a service on a worker answer atlocalhoston the hub, through SSH, only for the hub.forward list|up|stop; the Mac app reconnects dropped ones. - File sharing:
sparehand files NAME on|off|open|browse|mkdirshares a folder of a worker and shows it in the hub's Finder under the machine's name, set up from the hub: an encrypted share only the hub can reach on Windows, File Sharing on a Mac, Samba on Linux. System folders can't be shared.
AI & GPU
- Cloud models with a free tier (docs/ai.md): the AI hub at
localhost:11434also reaches Groq, Cerebras, Gemini, OpenRouter's free models, Mistral, NVIDIA and SambaNova once you add a key (Local AI → Cloud providers…; kept in the Keychain), asprovider/model, through both the OpenAI and the Ollama API.auto(andauto:fast) answers from your machines first and goes to the cloud only when none can. Each provider's use is counted against its free limits and its rate-limit headers; one that answers 429, fails or refuses its key rests for a while andautomoves on. A model it answers 404 for (listed, but not for your key) is hidden for 7 days, until the provider's Test. Cloud answers are marked ☁; members never use them."aiEndpoints"adds any OpenAI-compatible server of your own,"aiCloud": falseturns it off. - The Anthropic Messages API on the AI hub (
/v1/messages, streaming, tool use, count_tokens):ANTHROPIC_BASE_URL=http://localhost:11434 ANTHROPIC_MODEL=auto clauderuns Claude Code on your own models, then the free cloud ones. A Claude model's name meansauto(a Haikuauto:fast). autokeeps a conversation on the model it first gave it to for 30 minutes, while that model can answer.fusion: a machine's model and two cloud ones answer the same question, and a judge writes one answer from theirs ("aiFusion"chooses the panel and the judge); also in the dashboard's chat.- More cloud providers: Cloudflare Workers AI (
ACCOUNT_ID:TOKEN), GitHub Models, Cohere and Hugging Face. Their picture, speech and transcription models answer at/v1/images/generations,/v1/audio/speechand/v1/audio/transcriptions. - The hub measures each cloud model's speed and reliability:
autoputs failing ones last andauto:fasttries the quickest first. It learns providers' limits from their answers' headers. Cloud providers… shows each provider's use over the last 14 days. "aiCloudCatalogUrl"fetches a newer provider list daily (never changing where a known provider is reached)."aiCache"answers repeated requests from memory,"aiCompress"trims empty space from long prompts, and"aiCloudMembers"lets members use cloud models on their credits.sparehand ai cloud [key|remove|test|models|catalog] [PROVIDER]manages the providers from the terminal.- The AI chat makes pictures: 🖼 next to Send, with Studio's ComfyUI (Z-Image Turbo or FLUX.2 [klein]) on a machine with an NVIDIA graphics card, or in the cloud: Cloudflare's FLUX.1 schnell (free daily allowance), Hugging Face's, or Gemini (paid, with Studio's key). Asked for a picture, a chat model would only describe one, so the chat offers 🖼 instead.
- Cloudflare's key is asked for as two things, the account ID and the API token, in two boxes (and two questions from
sparehand ai cloud key cloudflare); the account ID in use is shown. - xAI (Grok) joins the cloud providers, and Mistral, which no longer has a free API, is marked Paid like it: paid providers are labelled and never in
auto's lists unless you put them in"aiAuto". sparehand run --gpu(or a command matchingSPAREHAND_GPU_MATCH, such asollama,whisper,torchrun) goes only to a worker with an NVIDIA GPU, one GPU job at a time per GPU. Its own load never looks like gaming.- Machines in the cloud (docs/cloud-gpu.md): a cloud machine is a worker that Sparehand starts when a job finds no other machine free and stops after its idle minutes, with caps on hours a day and spend a month, and Start/Stop, the price and the cost so far on its card. Runpod, AWS and Azure: Add a machine → Cloud provider makes the machine for you, with a GPU or without (CPU machines for builds and tests): the credential once, into the hub's Keychain; the size and region from the provider's live catalog with price, Spot price and stock; disk, Spot, idle time, caps, Studio's picture and clip models when asked, and whether Studio may pick it by itself or only when a storyboard does (the default); then the volume or disk, the firewall rule that lets only the hub in, the tools and Node 22 on the machine and the pairing, step by step with a Stop.
sparehand cloud add NAME --runpod|--aws|--azure,cloud catalog,cloud key,cloud remove --deleteandcloud trustdo the same in the terminal; each provider is a small module underlib/cloud/. A Runpod worker's volume is the durable thing: by default a pod is made for each use (on the first GPU of its list with stock) and terminated when idle, so it always comes back and only the volume costs in between; or the pod is kept and stopped. A machine's address (and a pod's SSH port) changes with a start: the hub rewrites its~/.ssh/configblock and checks the machine's pinned SSH key. Google Cloud the same way, through the Compute Engine API (a service account key or gcloud's login; billing and the GPU and CPU quotas checked first, with a link to the quota page when one is 0, and a CPU VM allowed when only the GPU is blocked); the gcloud commands stay as the by-hand fallback. The picker shows every machine the provider's API returns, with a search box and filters (GPU or CPU, memory, region, price) and the recommended ones marked. Runpod, a pod per use (the default): the network volume stays, a pod is made for each use on the first machine of the worker's list with stock (Secure or Community Cloud) and terminated when idle, so a stopped pod stuck on a full host never holds the worker and only the volume costs in between; keep the pod stays as the other choice; Start now and Terminate now on the card; an existing pod or volume is taken over withcloud add --podor--volume-id(the old pod is left for its owner to terminate). The cards, Studio's tools and the Crew agents show each service's brand mark (listed in THIRD_PARTY_NOTICES.md). - More coding tools:
sparehand agent install TOOL|allconnects Claude Code, Gemini CLI, Cursor, GitHub Copilot CLI, Windsurf (Devin Local) and OpenCode by a hook that changes the command, Codex CLI and Kiro's CLI by a hook that refuses a heavy command and names the Sparehand command to run, and Cline by a note in its instructions (which depends on the model following it).agent statusshows per tool whether it is connected by hook or by note and the version its hook was checked against;agent test TOOLshows what the installed hook does with a heavy command and a light one without running anything;agent uninstallputs every file back exactly as it was. The formats and their sources are in docs/agent-hooks.md. Settings → AI Tools in the Mac app has a switch per tool. - Check and Wake on every machine card in the dashboard (
sparehand doctor/sparehand wake);doctornow tells a machine that refuses the hub's key (its address changed since pairing) from one that is off. A coding agent's hook caps waits so its command never times out; Bun's text lockfile and projects without a lockfile get their dependencies installed; ignored folders with non-ASCII names stay home; the hub keeps itself awake while a job runs. - Leave no trace:
sparehand remove NAME --clean(and "Remove and clean up…" in the app) undoes everything Sparehand put on a worker: file sharing, the AI model server, worker mode, its run folders and caches, and the hub's key; its own SSH server and tools stay. - Where the models go: each machine's models can live in a folder you choose (an external drive, a data disk): Models are kept in… · Change… in the library, or
sparehand ai folder NAME PATH. The models already downloaded move there and Ollama restarts withOLLAMA_MODELS. - The Helper: a Help button on every dashboard page (and ? in the menu bar, "Stuck? Ask the Helper" in setup) opens a guide that answers in plain words, in the user's language, from a local AI model on their own machines. It knows how the app is laid out, the docs, and what each machine is doing now, and offers the next step as buttons (Add a machine, Check a worker, Share files, Open the model library…) that the user presses; it never acts by itself. One click sets it up (the AI model server plus a small suggested model on the best machine, the hub included); until then it answers straight from the guide. The model is optional (a switch in the Helper, or
"helperModel": false), and it only answers about Sparehand. - Model library: the dashboard's Local AI card sets up the model server on a worker with one button, then offers a catalog of about 30 models grouped by use (chat, coding, reasoning, pictures, document search), each with a plain description and how well it runs on that machine (from its graphics memory and total memory, which the worker check now reports). Install with progress, stop, remove, or install any other Ollama model by name.
sparehand ai modelsshows the same in the terminal. - Chat: talk to your local models in the dashboard: answers stream in with formatting (lists, code), which machine answered and how fast, a Copy button, starter prompts, and a "Think first" switch (off by default, so thinking models answer much sooner).
- Saved chats, several at once: chats are saved on the hub (a private folder; every device sees the same ones;
"chatHistory": falsesaves none), listed by day with search, rename and delete; several can be open as tabs, each answering while you read another, and the tabs reopen next time. - Private chats: 🕶 Private in the chat: new chats aren't saved, and the chat, its attachments and its pictures are erased when its tab is closed, Private is turned off or the page is closed. Its pictures aren't kept on the hub, and one made on a machine keeps its words out of the command line and the job history (
comfy.py --prompt-file,--forget 1), with the worker's copy cleared. - Private Studio productions: 🕶 Private on the new production form: erased 10 minutes after its videos are downloaded, a day after it last changed, or on Erase, with its copies on your machines (
sparehand clean). Nothing goes into the brand kit or its folder, the descriptions never show in the job history, the Director (Claude Code) keeps no record, and notifications leave its title out. - Latest models, daily: the library's "New and popular on Ollama" section reads ollama.com once a day and offers each new model at the size that suits the machine.
- The hub runs models too:
sparehand ai install hub(its Ollama on 127.0.0.1:21433). - Local AI hub:
sparehand ai install NAMEputs Ollama on a worker (checksum verified, no admin password),ai pulldownloads models, andlocalhost:11434(Ollama API and OpenAI-compatible/v1) sends each request to a machine that has the model and isn't busy. A "Local AI" card in the dashboard shows machines, models and what's in memory. Alsoai update|rm|uninstall. - On gaming PCs, a busy GPU means someone is playing: no new jobs, and a running one moves elsewhere.
Dashboard & history
- Files: an upload of gigabytes no longer dies after 5 minutes, a download says its size, and one over the limit gets a 413 with the reason instead of a dropped connection. A stop (SIGTERM) writes the AI hub's use per provider and People's last-seen times first. A cloud provider whose key wasn't there at start (a locked Keychain) is looked at again a minute later. An app that leaves mid-answer no longer marks the AI machine unreachable. The chat search reads titles and first lines, not every saved chat.
- What's using it? on every machine card: the apps using the most memory (and their CPU), grouped by app, highlighted when memory or CPU is high. On a Mac it counts memory macOS compressed (the footprint Activity Monitor shows); on a Windows PC it lists the Windows apps first, then WSL's. Also
sparehand top [NAME]. Quit beside each app asks it to close (like ⌘Q or clicking X, so it can ask to save); one that doesn't close gets Force quit. Parts of macOS and Windows, other users' processes, Sparehand itself and WSL's keep-alive get no button (imagent and Photos analysis do: macOS starts them again, fresh). Every quit is in Activity. - Files tab: browse, download and upload each machine's shared folder from the dashboard, on any device; through the hub over SSH, confined to the folder (
sparehand files NAME ls|get|put|newdir). - A web app for phone or tablet (via
tailscale serve): machines, jobs, activity, history, screens (noVNC) and Claude Code sessions, plus Edit, Remove and Rename for workers, their shared folder, forwards and a GPU tag. - History: every run is recorded (machine, project, exit code, duration, wait, and why it ran on the hub when it did).
sparehand history [DAYS]and the History tab summarise jobs per machine, success rate, average time per project and work taken off the hub. - Work (optional): Jira and Azure DevOps items with a readiness check, and Start, which opens a plan-first Claude Code session for an item.
- The cloud as a spare machine: when every worker is busy, asleep or switched off, a new session's Run on offers Cloud: the hub starts a Claude Code cloud session (
claude --cloud) on a copy of the repository's GitHub remote, and you follow it on claude.ai or in the Claude app. Its work comes back as a branch, which Changes shows with each file's diff and Pull it in, which merges it into your branch. - Crew agents in the cloud: a Claude Code in the cloud agent (off until you add it, up to 10 parts at once) lets the Master hand parts to Claude Code cloud sessions as well as to agents on your own machines. Crew pushes the part's branch, starts a session with
claude --cloud(the brief, the agents' rules and a branch to push to), waits for that branch onorigin(with a time limit), fetches it into the part's branch, then checks, reviews and merges it as usual. A part sent back starts a new session with the Master's notes. The Crew tab shows each cloud part's claude.ai link and its state; cloud sessions can't be followed or answered from Crew. - The Advisor: Sparehand learns from its own mistakes. A Crew review that sends a part back, the Master's final review and the Director's layout fixes each leave a one-sentence lesson, kept per repository (or for Studio), and given back next time: to the Master's plans and reviews, every agent's brief, every storyboard, and Claude Code sessions started from the dashboard in that repository. The Master's final review, and the Advisor's reading of Sparehand's own records (jobs that ran on the hub and why, agents whose parts keep coming back, a failing final check, machines not set up for Studio, words the voice mishears), become recommendations for you, with a notification, Done and Dismiss. Apply with Crew starts a Crew task in the repository with the recommendation as its brief (the recommendation is done by itself when the task finishes well); Apply in a session starts a Claude Code session from the dashboard that applies it and asks before changing anything. An Advisor tab in the dashboard and
sparehand advisorin the terminal; lessons can be added and forgotten by hand."advisor": falseinapp.jsonturns it off. - Worker cards warn when disk is low; the dashboard server can follow the program that started it (
SPAREHAND_EXIT_WITH_PID).
Security
- Trust goes one way: the hub logs in to workers with keys, accepted only from the hub's addresses.
- Git-ignored files and
.envfiles are never copied to workers (unless you turn it on). - The
.gitfolder stays home (its config, hooks, other branches and stash): a worker gets the checked-out commit and its history as git bundles.addanddoctorwarn about a token in a remote URL. - What a worker sends back is untrusted: its status line is checked field by field (never evaluated), and files come back only into the checkout, never into
.git, Claude Code or editor settings or top-level dot-files, and never through a symlink. - The hub's key is installed with
permitopenlimited to the machine's own services, so forwards work but nothing else can be reached through it. - File shares accept only the hub; the dashboard listens on 127.0.0.1 only.
- The dashboard page comes with a strict Content-Security-Policy (this origin and the page's own scripts, by their hashes; never framed). An error nobody expected tells a member one sentence and the owner the real message; the log keeps the details.
- Crew's Master writes
AGENTS.mdfor a repository without one into the task's own folder, where the agents read it; it goes into your repository only when you tick Add it to the repository while approving the plan (shown as a diff). The folders next to a repository reach an agent's checkout only with Link the repositories next to it on (off by default; git repositories only, never for a repository in your home folder itself). - Tests (end to end over SSH, and the app's access rules) run in CI on every push.