paseo-profiles · git:20260910.b4b94b9 · 2026-09-10 · sha256 af71987945127478
paseo-profiles git:20260910.b4b94b9A
Immutable. This exact content is served forever at /api/v1/blob/af71987945127478.
--- name: paseo-profiles description: Copy paseo agent profiles (Architect, Engineer, Reviewer, Writer…) from one machine to another by merging them into the target's ~/.paseo/config.json, over ssh, idempotently. Use when the user wants to export/import/sync/clone paseo agent profiles between hosts, set up paseo agent profiles on a new or freshly installed machine, or roll the same profile set across a fleet. paseo itself has no profile export/import command — `paseo agent` manages running agents, not profile templates. --- # paseo-profiles Move **agent profiles** — the templates that pair a name, provider, model, mode, and thinking level (“Software Engineer” = claude / claude-opus-5 / bypassPermissions / xhigh) — between machines. paseo has no command for this. The profiles are a JSON array at `daemon.agentProfiles` in `~/.paseo/config.json`, and the only supported way to create one is by hand in the Desktop UI. ## Why not just scp config.json That same file holds **host-specific** settings: `daemon.listen`, `daemon.relay.enabled`, `daemon.cors`, and any password hash written by `paseo daemon set-password`. Copying the file wholesale flips those on the target. `~/.paseo/server-id` and `cli-client-id` are per-host identity and must never be copied either. So this is a **key-scoped merge**, not a file copy. ## Usage One command does the whole round trip: ```bash ~/.claude/skills/paseo-profiles/scripts/paseo-profiles.py push dev-server-frank-lume ``` Multiple hosts are just more arguments; one host failing doesn't abort the rest. ```bash paseo-profiles.py push host-a host-b host-c --dry-run # report only, write nothing ``` Always offer `--dry-run` first when the target already has profiles of its own. The halves are also usable separately, for an air-gapped or reviewed transfer: ```bash paseo-profiles.py export -o profiles.json # on the source paseo-profiles.py import profiles.json # on the target (also reads stdin) ``` Other flags: `--config PATH` (default `~/.paseo/config.json`), `--no-reload`. `paseo-profiles.py selftest` checks the merge logic. ## What it carries | Key path | How | |---|---| | `daemon.agentProfiles` | merged element-wise | | `daemon.mcp.injectIntoAgents` | scalar overwrite | | `daemon.browserTools.enabled` | scalar overwrite | | `agents.providers.omp.enabled` | scalar overwrite | Every other key in the target is read, left alone, and written back verbatim. ## Merge rules Per incoming profile: **id match** → replace in place; else **name match** under a different id → replace that slot, incoming id wins (importing “Software Engineer” must not leave two of them); else **append**. Profiles only the target has are never deleted. Re-running is a no-op — it prints `no changes` and skips the write and reload entirely. ## Safety Backs up to `config.json.bak-<UTC>` before the first write, writes via a temp file at mode `0600` then `os.replace` (atomic; the file holds secrets on some hosts). A missing target config is created rather than treated as an error. ## Gotchas - **`paseo` is not on the non-interactive ssh PATH on every host.** `ssh host 'paseo …'` can fail with *not found* while `ssh host 'zsh -lc paseo'` works. Use the absolute path — `/opt/homebrew/bin/paseo` on Apple Silicon. The script resolves this itself. - **A stopped daemon is fine.** Reload is best-effort; a stopped daemon reads the config at next start, and the script says so instead of failing. - After writing, it reads `paseo daemon reload --json` and reports honestly: it tells you to run `paseo daemon restart` if paseo lists a synced path under `restartRequiredPaths`, and warns if one shows up under `overrideControlledPaths` (the edit would be ignored). - Profiles land regardless of whether the target has that provider installed. A Codex profile on a host without Codex shows as unavailable — a gap on that host, not a transfer failure. - `push` stages the script at `/tmp/paseo-profiles-$(id -u).py` on the remote and runs it with `python3`, so the target needs python3 on its ssh PATH (macOS with CLT or mise: yes).