Skip to content

patchbay v0.2.0

Choose a tag to compare

@github-actions github-actions released this 13 Aug 15:49
· 20 commits to main since this release

Added

  • ngrok (network) — the agent's authentication, read from ngrok.yml at
    the v3 platform location, the legacy ~/.ngrok2 one, or $NGROK_CONFIG.
    One profile: the authenticated agent. Named tunnels: are forwarding rules on
    that one account, not identities, so they are reported as a count and a list
    in meta. pb verify ngrok runs ngrok config check and, when an api_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 *.pem files on disk, every command uses cert.pem
    unless TUNNEL_ORIGIN_CERT or --origincert names 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 —
    TunnelSecret has no field to deserialize into — and cert.pem is 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 wrangler row:
    it is a different credential from wrangler's OAuth login, with different
    reach, which wrangler logout does not revoke and wrangler whoami cannot
    see.

  • Grafana key verificationpb key verify and the MCP verify_key now
    understand --provider grafana, asking {endpoint}/api/org and reporting the
    org the token belongs to. Grafana tokens are only meaningful against the
    instance that issued them, so KeyEntry gains an optional endpoint
    (pb key add --endpoint https://<you>.grafana.net, and the same field on the
    MCP store_key); a keys.json written before it existed keeps parsing, and
    keys without one never grow the field. A grafana key deliberately maps to no
    probe — there is no Grafana CLI for it to sit beside.

  • Machine migrationpb export packs the logins that survive a machine
    move into one age-encrypted .pbx bundle: the portable credential files,
    optionally the key vault (--keys, off by default), a secret-free
    manifest.json, and a generated SETUP.md that tells a machine with no
    patchbay on it how to install one. pb import puts it back, backing up
    anything it would replace to <path>.patchbay-bak, and --dry-run prints 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 declares Portable, DeviceBound or PointerOnly with 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 through Paths on both
    machines independently, so an override on either side is honoured.

  • pb plan, pb status --diff <manifest>, and the plan_setup /
    mark_setup_done MCP 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_done re-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, --json or 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's user switch is an
    arrow-key picker with no non-interactive form, so patchbay makes the same
    change itself: it repoints loggedInUserEmail and LoggedInUserDomain at one
    of the accounts already in loggedInUsers. 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 run infisical login status if 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_clients reads all six formats into one
    model and writes three of the operations back.

  • pb mcppb 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 toolslist_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_keys and an argument count — never
    values, since those fields routinely hold API keys. A copy does carry values
    (a server that cannot authenticate is useless) and names what travelled.

Changed

  • patchbay_core::util now owns the write-safety machinery MCP client
    management introduced — backup, write_atomic and 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/config that 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/*.yml files
    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 the export KUBECONFIG=… that makes a shell agree.
    Because every file carries its own current-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 categoriescontainers, 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's notes. See "Custom paths" in the
    README.

Fixed

  • gh and rclone now honour XDG_CONFIG_HOME, as those CLIs do. gcloud
    deliberately still does not, because it does not either.

Full Changelog: v0.1.0...v0.2.0