Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ An agent kit is a `hybrid/v1` mixin that:
| [`antigravity/`](antigravity/) | Agent | Pinned Google agy + private Gemini-to-Chat-Completions bridge | **Experimental** — real ARM64 CLI and isolated Paseo verified against synthetic provider; live gateway and x64 pending |
| [`opencode-go-provider/`](opencode-go-provider/) | Provider | OpenCode Go (`openai-compatible`) facts and a 19-model neutral catalog | **Preview** — blocked on the acq credential-binding addition |
| [`pi-coding-agent/`](pi-coding-agent/) | Agent | Pinned pi CLI + `~/.pi/agent/models.json` renderer | **Preview** — live verification pending acq PR 611 |
| [`personal/`](personal/) | Skill | The author's personal layer, dropped into `~/.agents/skills`: the `paseo-first-mate` skill and 27 vendored skills by [Matt Pocock](https://github.com/mattpocock/skills) (MIT, pinned commit; his code review is installed as `pocock-code-review`). See [`personal/NOTICE`](personal/NOTICE) for credits | Offline-verified; no live sandbox run |
| [`personal/`](personal/) | Skill + startup step | The author's personal layer, dropped into `~/.agents/skills`: the `paseo-first-mate` skill and 27 vendored skills by [Matt Pocock](https://github.com/mattpocock/skills) (MIT, pinned commit; his code review is installed as `pocock-code-review`). See [`personal/NOTICE`](personal/NOTICE) for credits. Also installs pinned Paseo plugins at startup (one background command, `github.com` egress; needs the paseo kit) | Offline-verified; plugin installer exercised against a real Paseo 0.12.0 daemon; no live `acq` run |

**Preview status.**

Expand Down
8 changes: 6 additions & 2 deletions personal/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@ An acq `hybrid/v1` skill kit. Start with [`README.md`](README.md).
- **Check your work:** `scripts/verify` (offline) and, from the repository root,
`python scripts/run-kit-tests.py personal`. Both need `python3`; `shellcheck` and `acq`
are used when installed.
- The kit has no `commands`, no `caps.network` and no `agent:` block on purpose. Every
payload is dropped at its final path; do not add a startup step to link or fetch.
- The kit has one `commands` entry on purpose: a background startup step that runs
`files/home/paseo-plugins-install.sh` (ADR 0003). Skills are dropped at their final path;
do not add a step to link or fetch them. It has no `agent:` block, and `caps.network`
lists `github.com` only. A new Paseo plugin is one `install_plugin ID git:owner/repo <40-hex>`
(or `npm:pkg <x.y.z>`) line in that script; the script refuses unpinned sources and
`scripts/verify` section 3d checks it. Read the plugin's source at the pin first.
80 changes: 74 additions & 6 deletions personal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ that holds the author's personal layer: the skills a coding agent should have in
every sandbox, applied last on top of the global kits.

It is an opt-in `--kit` mixin. It installs no agent, writes no provider
configuration, runs no commands, publishes no ports, and allow-lists no
network hosts.
configuration, and publishes no ports. It runs one background startup command that
installs Paseo plugins (see [Paseo plugins](#paseo-plugins)), and allow-lists one
network hosts, `github.com` and `registry.npmjs.org`, for that command.

## What it ships

Expand All @@ -26,9 +27,65 @@ network hosts.
`~/.agents/skills` is the cross-agent skills root that the supported agents scan,
so no per-agent linking is needed.

The payload is written at its final path by the kit's `files[]` records, which
is why the spec has no `commands`. Nothing can fail at startup beyond the file
drop itself.
The skills are written at their final path by the kit's `files[]` records, so they
need no command. The one startup command is the plugin installer below; it is
detached and always exits 0, so nothing it does can fail a sandbox create.

## Paseo plugins

At startup a background script, `~/paseo-plugins-install.sh`, installs the author's
Paseo plugins into the sandbox's Paseo daemon. It needs the separate
[`paseo` kit](https://github.com/GSA-TTS/agentic-coding-patterns/tree/main/integrations/isolation/acq-kits/paseo) applied too: that
kit starts the daemon this script talks to. Without it the script waits up to ten
minutes, logs that the daemon never answered, and installs nothing.

What it does, in order:

1. Takes a run lock (one installer at a time) and waits for `paseo plugin ls` to answer.
2. If the daemon's global `pluginsEnabled` switch is off, sets it with
`paseo daemon config set` under the paseo kit's `config.json` lock and runs
`paseo reload`. **Plugins are trusted, unsandboxed code**: a plugin's server code
can reach the sandbox's files, processes, credentials and network, and its client
code runs inside the Paseo app. Using this kit is the consent to turn the switch
on.
3. Installs each listed plugin that is not already installed, from a source pinned to
a full commit (`git:owner/repo` plus the SHA) or an exact npm version. It does not
use a bare registry id such as `xzthemeofsss/quote-notes`, which would install
whatever the registry points at that day. `scripts/verify` fails on an unpinned
entry. Each install is retried up to three times, waiting for the daemon in between,
because the paseo kit can restart the daemon while it pins the worktree root.

Log: `~/.local/state/paseo/paseo-plugins.log`. Check the result with `paseo plugin ls`.
Plugins live under the daemon's home, which is not persisted past the sandbox, so
each new sandbox installs them again.

| Plugin | Source | Pin (sha512s are recorded for reviewers; nothing checks them at install) | Notes |
| --- | --- | --- | --- |
| `quote-notes` ("Codex Style Annotations", 0.2.2) by xzthemeofsss | `git:xzthemeofsss/paseo-plugins` | `5ce92527c99a328b28775c7d745f324f2cc84309` | Client plus a one-line settings registration; no server handlers. Needs Paseo 0.11.4 or later. Disable the older `quote` plugin first if you add it. Some labels are in Chinese. |
| `skills` ("Skills", 0.4.0) by gpambrozio | `npm:@gpambrozio/paseo-skills` | `0.4.0` (sha512 `zMgP2U/vrRsLkKhoQICkN52+YoDy2WkkYymEDmruduKxf4Dq99Ct8Pk3xqJyAzijq2oprMFYLbj/wT6XepBLeA==`) | Lists the skills each agent session can use, renders each `SKILL.md`, and can invoke one. Reads the skill directories under `~/.claude`, `~/.codex` (or `$CODEX_HOME`) and `~/.agents`, and the project-level ones for the agent's working directory; writes nothing; no network or subprocess. Shows this kit's 28 skills in the Paseo UI. Needs Paseo 0.9 or later. |
| `mermaid` (0.5.0) by dutchakdev | `npm:paseo-plugin-mermaid` | `0.5.0` (sha512 `vNVNE1b0z7HJ1093jT1Cz/f3QYXFKg6yTfdqTHeFqaa9Ks437b0nrmQRdY/tWC9XDdXvgjWCCS1v9CsYYsCOhg==`) | Draws `mermaid` code blocks in chat as diagrams (flowcharts and sequence diagrams itself, other types through Paseo's Markdown on 0.13 or later), and opens `.mmd` files as diagrams. Runs only in the app: no server code, network or subprocess. Needs Paseo 0.11 or later. If you install Better Paseo, turn off its "Plugin markdown for replies" setting. |
| `beautiful-chat` (0.1.0) by ABorakati | `git:ABorakati/beautiful-chat` | `42b61d8301b5400a67821bbbfcf99fa8b681dc37` | Redraws chat timeline items (tool calls, reasoning, checklists, prompts, errors, replies) as typed, syntax-highlighted cards that follow the Paseo theme, with its own settings page and chat find. The code does not gate on provider, so it applies to every agent; only the OMP-specific parts (job and IRC envelopes) are provider specific. Its manifest runs `npm ci --include=dev` during install, so the daemon needs `npm` on its PATH and `registry.npmjs.org`. Its server spawns `xdg-open` for "reveal path", which does nothing useful in a headless sandbox. **Conflicts with `mermaid` by default, see below.** |

**Mermaid and Beautiful Chat: switch one setting off, once per browser.** Beautiful Chat's
**Assistant markdown** setting is on by default and takes assistant replies before Mermaid
sees them, so Mermaid blocks show as plain code. In the Paseo app open
**Settings, Plugins, Beautiful Chat** and turn **Assistant markdown** off; Paseo then draws
replies itself and Mermaid draws the diagrams. (Mermaid's own overview calls the
equivalent setting in a different plugin, Better Paseo, "Plugin markdown for replies";
Beautiful Chat's is named **Assistant markdown**.)

Beautiful Chat keeps its settings in the browser's `localStorage` under
`paseo/beautiful-chat/preferences/v1`, not on the daemon, so the kit cannot set this for
you. `localStorage` belongs to the page origin. It carries across sandboxes only if you
reach them through the same origin, such as the hosted app at `app.paseo.sh` or the desktop
app. A daemon-served web UI on a per-sandbox published port is a new origin each time and
needs the toggle again. On a native mobile client `localStorage` may not exist, in which
case the choice is not saved and the conflict returns; that is untested.

To add or change one, edit the `install_plugin` lines at the bottom of
`files/home/paseo-plugins-install.sh`, read the plugin's source, and run
`scripts/verify`. The reasoning is in
[`docs/decisions/0003`](docs/decisions/0003-install-paseo-plugins-at-startup.md).

## Matt Pocock's skills

Expand Down Expand Up @@ -162,7 +219,7 @@ empty state directory, that every vendored file still matches the sha256 in its
lock file, that the renamed skill is consistent everywhere, that no
credential-shaped string is shipped, and `acq kit validate` when available.
`shellcheck` runs when installed. There is no live sandbox check: the kit only
drops files, so a live run would exercise acq's file drop rather than this kit.
drops files and starts one plugin installer that needs the separate paseo kit, so a live run would exercise acq and that kit rather than this one. The installer itself is exercised against a real Paseo daemon in an isolated home; see ADR 0003.

## Security notes

Expand All @@ -172,6 +229,17 @@ drops files, so a live run would exercise acq's file drop rather than this kit.
run commands and push code. Everything is plain text you can read in this
directory; review the diff before pinning a new SHA, especially after
re-vendoring.
- **`github.com` and `registry.npmjs.org` are open to every agent in the sandbox.**
`caps.network` is sandbox-wide, not scoped to the installer, so any agent or plugin
there can also reach them (clones, gists, pushes, package fetches). The paseo kit
already allows the npm registry.
- **Plugins are code, not text.** A listed plugin runs unsandboxed. Review a plugin's
source at the exact commit before you add or move its pin, and check what it fetches
and writes. Some plugins run commands at install: `beautiful-chat` declares
`build: npm ci --include=dev`, which executes with the daemon's privileges and the sandbox's
registry access (npm lifecycle scripts of its dependencies included). Read a plugin's `paseo-plugin.json` `build` list as well as its code. The installer reaches only `github.com` and `registry.npmjs.org`
(and whatever the daemon's own allow-list permits); the egress allow-list is the only network control, and the
plugin runs inside it.
- **Agent-writable.** The files land under `/home/agent`, which the agent owns.
They are a convenience payload, not a trust anchor.

Expand Down
28 changes: 28 additions & 0 deletions personal/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,31 @@ agent owns it) and starts nothing.
The kit is applied from a pinned SHA. Push the change, pin the new SHA, and
create a new sandbox. Editing the files inside a running sandbox changes that
sandbox only.

## A Paseo plugin is not installed

- **Read the log.**

```bash
acq exec <sandbox> -- cat /home/agent/.local/state/paseo/paseo-plugins.log
acq exec <sandbox> -- paseo plugin ls
```

- **"daemon not reachable ... (is the paseo kit applied?)".** The installer talks to the
Paseo daemon that the separate `paseo` kit starts. Apply both kits. If the daemon was
slow, run `sh ~/paseo-plugins-install.sh` again; it skips what is already installed.
- **"could not lock config.json" or "could not set pluginsEnabled".** The paseo kit holds
a lock while it writes `config.json`. Run the installer again.
- **"another installer is running".** A run lock at
`~/.local/state/paseo/paseo-plugins.run.lock` is held, or was left by a killed run.
If no installer is running, remove that directory and run again. A killed run can
likewise leave `~/.paseo/.config-json.lock`, which the paseo kit also waits on.
- **A `git clone` fails.** The sandbox must allow `github.com`. This kit's `caps.network`
lists it; confirm the kit was applied and the egress policy did not drop it. Behind an
HTTPS-inspecting proxy, git needs the proxy CA in the system store; that path is untested.
- **The plugin installed but the UI does not show it.** Reload the browser tab. Client
plugins load in the app, not the daemon, and the app checks the plugin's
`requirements.paseo` range against its own version.
- **It is installed but you want a newer version.** Change the pin in
`files/home/paseo-plugins-install.sh`, run `scripts/verify`, and recreate the sandbox.
Plugins are installed at create time and are not updated in place.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Decision: ship the First Mate skill as a snapshot kit at its final path

**Status:** accepted (2026-10-29); the kit was later renamed `personal` and widened, see [0002](0002-personal-kit-and-vendored-pocock-skills.md)
**Status:** accepted (2026-10-29); the kit was later renamed `personal` and widened, see [0002](0002-personal-kit-and-vendored-pocock-skills.md). The files-only, no-commands, no-egress shape described below was relaxed by [0003](0003-install-paseo-plugins-at-startup.md)

## Context

Expand Down
100 changes: 100 additions & 0 deletions personal/docs/decisions/0003-install-paseo-plugins-at-startup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Decision: install Paseo plugins at sandbox startup, pinned, from the personal kit

**Status:** accepted (2026-11-07)

## Context

The author uses Paseo plugins in the Paseo web UI that the separate `paseo` kit runs
in the sandbox. A new sandbox starts with the daemon's `pluginsEnabled` switch unset
(treated as off) and no plugins configured, so each plugin had to be installed by hand
every time. [0001](0001-ship-the-first-mate-skill-as-a-snapshot-kit.md) and
[0002](0002-personal-kit-and-vendored-pocock-skills.md) kept this kit to files only: no
commands and no egress. A plugin install cannot be a file drop. The daemon owns its
plugin directory and config, and `paseo plugin install` needs a running daemon.

## Decision

1. **One startup command, in the background.** It runs
`~/paseo-plugins-install.sh` (a dropped file, mode 0755) detached, with the same
`user: "1000"` and `background: true` shape the paseo kit uses. The script waits up
to 600 seconds for the daemon (the paseo kit npm-installs the CLI first, which can be
slow behind a proxy), takes a run lock so two copies never install at once, then
installs, retrying each plugin up to three times because the paseo kit can restart
the daemon while it pins the worktree root. It always exits 0 and logs to
`~/.local/state/paseo/paseo-plugins.log`, so it cannot fail a sandbox create. This is
the kit's first `commands` block.

2. **The kit turns the global switch on.** If `pluginsEnabled` is not true, the script
runs `paseo daemon config set pluginsEnabled true` under the paseo kit's
`config.json` lock directory, then `paseo reload`. Plugins are trusted, unsandboxed
code: server code can reach the sandbox's files, processes, credentials and network,
and client code runs inside the app. The author gave explicit consent to enabling the
switch in every sandbox that uses this kit (2026-11-07). The blast radius is the
sandbox, which is already the security boundary.

3. **Pin every plugin to a full commit or exact version; do not install by registry
id.** `paseo plugin install xzthemeofsss/quote-notes` asks `plugins.paseo.sh` what to
install and takes the answer of the day. The script instead uses
`git:owner/repo` with `--ref <40-hex>` (or `npm:pkg@x.y.z`), which resolves nothing
remotely beyond the repository itself. The pin is the one the registry listed when it
was reviewed. The guard is in the script itself: `install_plugin` refuses, and logs,
anything but a git source with a lowercase 40-hex commit or an npm source with an
exact `x.y.z`. `scripts/verify` section 3d checks the guard is present, that no other
line calls `paseo plugin install`, and that every call is pinned. This also removes the dependency on `plugins.paseo.sh`,
which was not reachable from the development sandbox, so the registry route could
not be tested.

4. **Egress: `github.com` and `registry.npmjs.org`.** `github.com` is for `git clone` of
git-sourced plugins and `registry.npmjs.org` for npm-sourced ones. The paseo kit
already allows the npm registry; this kit lists it too rather than rely on another kit.
`caps.network` is sandbox-wide, so every other agent in the sandbox also reaches these
hosts. `scripts/verify` fails if an npm-sourced plugin is listed without the npm host.
The daemon installs npm plugins with `--ignore-scripts` (checked in its source).

5. **Idempotent and skip-if-present.** The script skips a plugin whose id is already
configured, so a second run, a daemon restart that re-runs startup, or a snapshot that
kept the plugin does not error or re-clone.

6. **Plugins with a `build` step are allowed, reviewed by hand.** `beautiful-chat`'s
manifest runs `npm ci --include=dev` on install, unsandboxed, so its dev dependencies
(React Native, TypeScript, about 360 packages) are fetched and their lifecycle scripts
may run. Reviewed at the pinned commit: every lockfile entry resolves from
`registry.npmjs.org` with an integrity hash, and the only package with an install
script is `fsevents` (macOS only, skipped on Linux). That is a point-in-time review of a
lockfile, not a guarantee. The kit cannot see a plugin's `build` list from the installer,
so `scripts/verify` does not check it; the README tells whoever bumps a pin to read it.

7. **No in-place updates.** Plugins install at create time, like provider input. To move
a pin, change the script and recreate the sandbox.

## What was tested

Against a real Paseo 0.12.0 daemon in an isolated `PASEO_HOME`, with real `git clone`s and
npm installs (the registry at `plugins.paseo.sh` was not used): starting with `pluginsEnabled`
unset, one run of the script set it, reloaded, and installed all four plugins. `paseo plugin
ls` reported each `running` at its pin: `quote-notes` and `beautiful-chat` at their commits,
`skills` 0.4.0 and `mermaid` 0.5.0 from npm (the lockfiles the daemon wrote carry the same
sha512s recorded in the README). `beautiful-chat`'s `npm ci` build took about 7 seconds. A
second run logged "already installed; skipped" for each. With no daemon it logged a clear
message after the wait and exited 0. The run-time guard refused a branch, a short SHA, an
uppercase SHA, an npm range or tag, a bare registry id, `git:` sources with extra path
segments or `@ref`, and `npm:github:` sources, all before calling `paseo`. A second
concurrent run exited at the run lock, and a TERM left no lock behind.

Not tested: a real `acq run` with the paseo kit on msb or sbx (no `acq` in the development
sandbox), the paseo kit's newer CLI pins (0.12.0 here), a daemon restart landing mid-install,
a build that outlasts the CLI's own install timeout, `git clone` behind an HTTPS-inspecting
proxy whose CA is not in the system store, and how any of the plugins look in a browser.

## Consequences

- The kit now depends on the paseo kit for the plugin step to do anything. Kits cannot
declare dependencies yet, so this is documented, and the script reports a missing
daemon instead of failing.
- The kit adds two egress hosts (`github.com`, `registry.npmjs.org`) and one background process that lives for a few seconds
to a few minutes after sandbox start.
- Updating a plugin is a code-review task: read the diff between pins, then bump.
- `scripts/verify` gains section 3d and also shellchecks the installer.
- `mermaid` and `beautiful-chat` conflict until Beautiful Chat's **Assistant markdown**
setting is switched off in each browser origin. That setting is client-side
`localStorage`, so the kit cannot apply it. Documented in the README.
Loading
Loading