patchbay v0.2.0
Added
-
ngrok (
network) — the agent's authentication, read fromngrok.ymlat
the v3 platform location, the legacy~/.ngrok2one, or$NGROK_CONFIG.
One profile: the authenticated agent. Namedtunnels:are forwarding rules on
that one account, not identities, so they are reported as a count and a list
inmeta.pb verify ngrokrunsngrok config checkand, when anapi_key
is configured, asks the ngrok API whether it is live — through the key vault's
own HTTP seam, so the check is testable without the network. Neither the
authtoken nor the api_key is ever reported, not even as a last4. -
cloudflared (
network) — Cloudflare Tunnel origin certificates, and which
one is in force. Profiles are the certificates, because that is the identity
dimension: with two*.pemfiles on disk, every command usescert.pem
unlessTUNNEL_ORIGIN_CERTor--origincertnames the other, and nothing on
the machine tells you which. That silent-wrong-account trap gets its own note.
Tunnel credentials are read for their ids and account tags only —
TunnelSecrethas no field to deserialize into — andcert.pemis never
parsed at all, since it carries a private key.config.yml(or
$TUNNEL_CONFIG) contributes the tunnel name and ingress-rule count. -
A registered Cloudflare API token now puts a caveat on the
wranglerrow:
it is a different credential from wrangler's OAuth login, with different
reach, whichwrangler logoutdoes not revoke andwrangler whoamicannot
see. -
Grafana key verification —
pb key verifyand the MCPverify_keynow
understand--provider grafana, asking{endpoint}/api/organd reporting the
org the token belongs to. Grafana tokens are only meaningful against the
instance that issued them, soKeyEntrygains an optionalendpoint
(pb key add --endpoint https://<you>.grafana.net, and the same field on the
MCPstore_key); akeys.jsonwritten before it existed keeps parsing, and
keys without one never grow the field. Agrafanakey deliberately maps to no
probe — there is no Grafana CLI for it to sit beside. -
Machine migration —
pb exportpacks the logins that survive a machine
move into oneage-encrypted.pbxbundle: the portable credential files,
optionally the key vault (--keys, off by default), a secret-free
manifest.json, and a generatedSETUP.mdthat tells a machine with no
patchbay on it how to install one.pb importputs it back, backing up
anything it would replace to<path>.patchbay-bak, and--dry-runprints the
whole plan without writing a byte. Running an import twice produces the same
machine. -
A portability policy per tool (
patchbay_core::migrate::policy). Every
probe declaresPortable,DeviceBoundorPointerOnlywith the reason in
the table —gh's token is in the keychain,tailscale's node key is this
device,ssh's private keys are never touched. A probe added without a policy
fails the test suite. Files are collected and restored throughPathson both
machines independently, so an override on either side is honoured. -
pb plan,pb status --diff <manifest>, and theplan_setup/
mark_setup_doneMCP tools — the gap list, re-derived from the machine in
front of you rather than copied out of the manifest. Each item carries whether
patchbay can close it itself, the exact command, and whether that command
opens a browser.mark_setup_donere-probes rather than believing the agent
that claims it ran something. -
Cloud-sync destinations (iCloud Drive, Dropbox, Google Drive, OneDrive, Box,
pCloud) are refused without--force, with the reason: copying credential
files is the technique sessions get hijacked with, and a bundle in a sync
folder hands a service the whole set. -
No secret value leaves the encrypted payload — not into the manifest,
SETUP.md, a log line, an error,--jsonor an MCP response. Decryption is
in memory only: there is no staging directory, and each file goes straight to
its destination through a temp file in that destination's own directory. -
pb use infisical <email>— the Infisical CLI'suser switchis an
arrow-key picker with no non-interactive form, so patchbay makes the same
change itself: it repointsloggedInUserEmailandLoggedInUserDomainat one
of the accounts already inloggedInUsers. Switching to an email that has
never logged in is refused with the list of ones that have. No credential
moves — every user's JWT stays in the vault backend, so the switch is followed
by a note to runinfisical login statusif the JWT's freshness matters. -
MCP client management — one board for the MCP servers registered across
the AI clients on this machine: Claude Code (~/.claude.json, user and
project scopes), Claude Desktop, Cursor, Codex CLI (config.toml), Windsurf
and VS Code.patchbay_core::mcp_clientsreads all six formats into one
model and writes three of the operations back. -
pb mcp—pb mcp list(the server × client matrix, or--json),
pb mcp add <client> <name>,pb mcp copy <name> --from … --to …(translates
between the JSON and TOML dialects),pb mcp rm <client> <name>. -
MCP tools —
list_mcp_clients,add_mcp_server,copy_mcp_server,
remove_mcp_server, so an agent that just set a server up can register it in
every client the user has. -
Write safety for other tools' config files: a rolling
<path>.patchbay-bak
backup before every change, atomic temp-file-and-rename writes, and
parse-modify-serialize so unknown keys, JSON key order and TOML comments all
survive. Claude Code's project scopes are read and labelled but never written. -
The board reports
env_keys,header_keysand an argument count — never
values, since those fields routinely hold API keys. Acopydoes carry values
(a server that cannot authenticate is useless) and names what travelled.
Changed
patchbay_core::utilnow owns the write-safety machinery MCP client
management introduced —backup,write_atomicand a new
serialize_json_preserving_style— so every probe that edits another tool's
config gets the same rolling.patchbay-bak, the same atomic rename and the
same house style on the way out. The style part is not cosmetic: the Infisical
CLI writes one compact line with": "separators, and re-serializing it
serde_json's way would rewrite every byte of the file for a one-field change.
Fixed
-
kubectl — a
~/.kube/configthat is a directory of per-cluster
kubeconfigs (a common layout, and one kubectl itself chokes on) is now
scanned instead of reported as zero contexts. The*.yaml/*.ymlfiles
directly inside it are merged first-file-wins, each context records the file
it came from, files that are not kubeconfigs are skipped by name, and the
note now spells out theexport KUBECONFIG=…that makes a shell agree.
Because every file carries its owncurrent-context, no active context is
reported unless exactly one file defines contexts. -
15 new probes, taking the board from 8 tools to 23:
vercel,firebase,
neon,docker,tailscale,ssh,stripe,supabase,flyctl,
doctl,npm,op,ollama,huggingface,claude. -
Four new categories —
containers,network,payments,ai. The
panel's sidebar picks them up from the JSON. -
Custom config paths. Every probe honours the environment variable its own
CLI honours, and patchbay gained an optional~/.config/patchbay/config.toml
with a[paths]table for the case where there is no shell environment to
inherit (the panel launched from Finder) or the state lives on another
volume. Precedence is tool variable →[paths]→ platform default, and an
override in effect is named in the tool'snotes. See "Custom paths" in the
README.
Fixed
ghandrclonenow honourXDG_CONFIG_HOME, as those CLIs do.gcloud
deliberately still does not, because it does not either.
Full Changelog: v0.1.0...v0.2.0