brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
fleetRuns commands on the developer's other machines over SSH and enrolls or removes machines from the Harness fleet; inventory and public keys live in the private agents repo, never private keys. Use when an agent needs a shell on another machine to run a command, read a log, check a build, or restart a service. Not for GUI verification (computer-use) or config…
Independent GitHub snapshot · Automated classification · Original documentation governs
Every machine the developer owns is reachable as ssh <alias> once it is enrolled.
Plain OpenSSH does the work: the private agents repo tracks an ssh/config fragment
and one public key per machine, and each machine includes the fragment and
authorizes those keys.
$repo/ssh/config Host blocks: alias, HostName, User, IdentityFile. No secrets.
$repo/ssh/keys/<alias>.pub one public key per enrolled machine
~/.ssh/id_ed25519_fleet this machine's private key — never leaves the machine
~/.ssh/config starts with `Include <repo>/ssh/config`
~/.ssh/authorized_keys a `# harness:fleet` block rewritten from ssh/keys
Trust boundary. Anyone who can push to the agents repo can add a key that every
machine authorizes on its next authorize run. That is the same trust the repo
already holds through tracked settings.json hooks; keep the repo private.
harness="${CLAUDE_PLUGIN_ROOT:-$(ls -d "$HOME"/.claude/plugins/cache/*/harness/*/ 2>/dev/null | sort -V | tail -1)}"; harness="${harness%/}"
"$harness/scripts/fleet-hosts.sh"
Pick the alias from that list, then:
ssh -o BatchMode=yes <alias> 'zsh -l -s' <<'EOF'
uptime
EOF
BatchMode=yes. A password or host-key prompt then fails fast instead
of hanging the agent.zsh -l -s with a quoted heredoc for anything beyond one word. A non-login
shell on macOS lacks Homebrew's PATH, and the heredoc avoids nested quoting.tailscale status for that name. Report "offline"
and stop. Do not retry in a loop.Remote commands run with the session's permission mode, and this skill does not
widen it. Read-only commands (status, logs, ls, git status, builds that write
only to their own output) may run as the task needs. Ask the user before
anything that changes remote state outside the task's scope: installing or
removing software, deleting files, kill/launchctl, reboots, git push, or
editing another machine's config. sudo needs a password that BatchMode cannot
supply. Hand that command to the user. Never configure passwordless sudo.
SSH gives a shell, not the screen. To prove behavior visually on another machine,
use harness:delegate or ask the user.
Run once per machine, on that machine. It needs macOS Remote Login (System Settings
› General › Sharing) or sshd enabled for other machines to reach it, and a
network path to the others (for example, Tailscale MagicDNS names).
Inventory. If $repo/ssh/config has no block for this machine, add one and
show it to the user:
Host studio
HostName studio.example-tailnet.ts.net
User alice
IdentityFile ~/.ssh/id_ed25519_fleet
IdentitiesOnly yes
ConnectTimeout 8
Use ~ rather than an absolute home path; harness:sync's portability lint
rejects /Users/<name>.
Key. If ~/.ssh/id_ed25519_fleet is absent, generate it. Agents need a
key they can use without anyone present, so tell the user it has no
passphrase and is protected by file mode and disk encryption. If they prefer
a passphrase, they create the key themselves and load it with
ssh-add --apple-use-keychain.
repo="${AGENTS_REPO:-$HOME/.agents}"; alias=<this machine's Host alias>
[ -f ~/.ssh/id_ed25519_fleet ] || ssh-keygen -q -t ed25519 -N '' -C "$USER@$alias fleet" -f ~/.ssh/id_ed25519_fleet
mkdir -p "$repo/ssh/keys" && cp ~/.ssh/id_ed25519_fleet.pub "$repo/ssh/keys/$alias.pub"
Include the inventory from ~/.ssh/config:
harness="${CLAUDE_PLUGIN_ROOT:-$(ls -d "$HOME"/.claude/plugins/cache/*/harness/*/ 2>/dev/null | sort -V | tail -1)}"; harness="${harness%/}"
"$harness/scripts/fleet-include.sh"
OpenSSH applies an Include placed after a Host or Match line only to that
block, so the script prepends the line unless it already precedes the first one.
It refuses a symlinked config, because the rename would replace the link. In
that case, tell the user to add the line to the top of the link's target.
Authorize every key in the repo, including the one just added:
harness="${CLAUDE_PLUGIN_ROOT:-$(ls -d "$HOME"/.claude/plugins/cache/*/harness/*/ 2>/dev/null | sort -V | tail -1)}"; harness="${harness%/}"
"$harness/scripts/fleet-authorize.sh"
The script rewrites only the marked block. It rejects any key file that is
not exactly one plain public-key line, including lines with command= and
other options, and then leaves authorized_keys unchanged.
Commit with /harness:sync, which commits and pushes the repo.
Propagate (next section) from any machine that can already reach the others. Until then, the other machines do not accept the new key.
The first two machines need one bootstrap visit: enroll each one at its own keyboard or over VNC. Every later machine is enrolled locally and then propagated from any enrolled machine.
After a key is added or removed, pull the repo on every reachable machine and re-run authorize there. The script is streamed over stdin, so the target does not need this plugin installed.
harness="${CLAUDE_PLUGIN_ROOT:-$(ls -d "$HOME"/.claude/plugins/cache/*/harness/*/ 2>/dev/null | sort -V | tail -1)}"; harness="${harness%/}"
hosts="$("$harness/scripts/fleet-hosts.sh")" || exit 1
failed=0
for h in $hosts; do
out="$(ssh -o BatchMode=yes "$h" 'git -C "${AGENTS_REPO:-$HOME/.agents}" pull -q --ff-only && bash -s' \
< "$harness/scripts/fleet-authorize.sh" 2>&1)" && rc=0 || rc=$?
case "$rc" in 0) r=ok ;; 255) r="unreachable or refused" ;; *) r=FAILED ;; esac
[ "$rc" -eq 0 ] || failed=1
printf '== %s: %s (exit %s) %s\n' "$h" "$r" "$rc" "$(printf '%s\n' "$out" | tail -1)"
done
exit "$failed"
Report each host's line verbatim. The run exits 1 unless every host succeeded,
because any host not updated may still hold a revoked key. unreachable or refused (ssh exit 255) means the connection failed; that host picks up the change
the next time propagate reaches it. FAILED means the pull or authorize failed on
a reachable host and needs attention there.
Delete its Host block and ssh/keys/<alias>.pub, commit with /harness:sync, then
propagate. Its key leaves every reachable machine's authorized_keys. Tell the user
that machines propagate cannot reach still accept the key until they are reached.