Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f51fd2d
chore: configure the engineering skills for this repository
sleeyax Oct 11, 2026
a412c0c
docs(catppuccin-theme): rewrite the README to the new template
sleeyax Oct 11, 2026
337444d
docs: trim the root README
sleeyax Oct 11, 2026
27c9994
docs(discord-rich-presence): rewrite the README to the new template
sleeyax Oct 11, 2026
8588ba6
docs(claude-tty-acp): cut the README down to what users need
sleeyax Oct 11, 2026
82f70ae
docs(guided-review): rewrite the README around what a reviewer does
sleeyax Oct 11, 2026
748381a
docs(claude-tty): rewrite the README to the new template
sleeyax Oct 11, 2026
0730c78
docs: cut every CLAUDE.md down to the traps an agent cannot find out
sleeyax Oct 11, 2026
8e0109c
docs: restructure the root README
sleeyax Oct 11, 2026
91ad887
docs: add installing from source to the root README
sleeyax Oct 11, 2026
94153bd
docs: point the from-source build step at the manifest
sleeyax Oct 11, 2026
ad6a7b2
docs: list the from-source update steps
sleeyax Oct 11, 2026
58dbf42
docs: explain the plugin registries in the root README
sleeyax Oct 11, 2026
a22b1a8
docs: trim the release section to what a contributor needs
sleeyax Oct 11, 2026
b829a25
docs: write the release section as prose
sleeyax Oct 11, 2026
b2d7afa
docs: state the general install notes before the install methods
sleeyax Oct 11, 2026
bff57fc
docs: reword the installation notes and registry names
sleeyax Oct 11, 2026
659b19c
docs: explain how to cut a major release
sleeyax Oct 11, 2026
0da11ea
docs: group the version rules into one paragraph
sleeyax Oct 11, 2026
6b8daf2
docs: give every README the same installation section
sleeyax Oct 11, 2026
2f20cf2
docs(guided-review): say only one of gh or glab is required
sleeyax Oct 11, 2026
01d761f
docs: give every README the same development section
sleeyax Oct 11, 2026
cedda7e
docs(guided-review): restore the forge caveats the rewrite cut
sleeyax Oct 11, 2026
8d2539f
docs(guided-review): keep the rule for recording read fixtures
sleeyax Oct 11, 2026
3b6c53c
docs(claude-tty-acp): restore the context mtime rationale and fix the…
sleeyax Oct 11, 2026
2e89488
docs: fix the root CLAUDE.md claims about entries, skills and glossaries
sleeyax Oct 11, 2026
455f7e6
docs: say what each installation method updates to
sleeyax Oct 11, 2026
034c035
docs(catppuccin-theme): say a registry install needs Paseo 0.11
sleeyax Oct 11, 2026
7733699
docs(discord-rich-presence): describe the socket lookup the plugin ac…
sleeyax Oct 11, 2026
d68fc24
docs(claude-tty): list every untyped contract with the adapter
sleeyax Oct 11, 2026
e72ed38
chore: drop the setup instructions left in the agent docs
sleeyax Oct 11, 2026
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
87 changes: 70 additions & 17 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,96 @@
# Working in this workspace

A pnpm workspace of paseo plugins, one per directory under `plugins/`.
Each package is a plugin directory in its own right: paseo is installed against `plugins/<name>`, and `paseo-plugin.json` and the runtime entries sit at that package's root because the loader stats exactly those names.
Since Paseo 0.8 those entries are `index.client.tsx` and `index.server.ts`, either or both, and every other module lives under `client/`, `server/`, or `shared/`, which is what decides the bundle it joins.
A pnpm workspace of Paseo plugins under `plugins/`, and the apps they run under `apps/`.
Paseo installs a plugin against its package directory, so `paseo-plugin.json` and the runtime entries sit at the package root, where the loader looks for them.
The entries are `index.client.tsx` (or `index.client.ts`) and `index.server.ts`, either or both.
Every other module lives under `client/`, `server/` or `shared/`, and that directory decides which bundle it joins.

Dependencies belong to the package that uses them, not the root, because the daemon's esbuild resolves from the plugin directory.
`pnpm typecheck` and `pnpm test` at the root fan out to every package; the package-level scripts are the ones to run while working on a single plugin.

Paseo documents the plugin contract at `public-docs/plugins/reference.md` in `getpaseo/paseo`: which modules each runtime may import, the settings store, the theme tokens, the host UI components, and the CLI.
`providers.md` beside it covers ACP providers, `publishing.md` npm distribution, and `migration.md` the runtime-entry migration.
Paseo documents the plugin contract at `public-docs/plugins/reference.md` in `getpaseo/paseo`, with `providers.md`, `publishing.md` and `migration.md` beside it.
Read it before inferring a rule from a failed build.
Each package carries its own CLAUDE.md, which records only what that reference does not.

A package's CLAUDE.md holds only what an agent cannot find out from the code, `git log` or that reference: the traps that break something when you don't know them.
Decisions with a real trade-off go in an ADR instead (see **Domain docs** below).

## Plugin READMEs

Every plugin's README follows the same template, so a new plugin starts from this and drops only the sections marked optional:
A README is for someone installing and using the plugin.
Internals, rationale and history stay out of it.
A change updates the section it belongs to rather than appending a paragraph, and leaves out what the UI already tells the user.
Write short, plain sentences, one per line.

Every plugin's README follows this template; sections marked optional are dropped when there is nothing to put in them:

```md
````md
# plugin name

<short description>
<one or two sentences on what it does for the user>

## Screenshots
## Screenshots (optional)

## Installation

<paseo plugin add sleeyax/<name> for a plugin in the Paseo registry, else paseo plugin add github:sleeyax/paseo-plugins:plugins/<name>, plus the update note; a plugin that needs a built artefact from this repo documents the absolute-path form instead>
Requires:

- Paseo <version> or newer
- <anything else the daemon's host needs>

```sh
paseo plugin add github:sleeyax/paseo-plugins:plugins/<name>
```

Also available as `sleeyax/<name>` on [Paseo Community Plugins](https://paseo.sh/plugins) and on [Paseo Cafe](https://paseo.cafe/plugins/<name>).
<only when the plugin is listed there>

<optional extra instructions>
Update with `paseo plugin update <name>`.
To install from source, see the [root README](../../README.md#from-source).

## Settings
<plugin-specific notes, if any>

## Usage

<one ### per thing a user does with it, written as how to do it>

## Settings (optional)

<a table of setting, default, and what it does>

## Troubleshooting (optional)

<only the problems whose fix the message itself does not give>

## Development

<instructions for developers>
For development instructions, see the [root README](../../README.md#development).

<anything else this package needs, if any>

Design decisions are in [docs/adr](docs/adr).
<only when the package has ADRs>

## License and attributions (optional)
```
````

## Repository skills

The repository's own skills live in `skills/`.
`.claude/skills/` and `.agents/skills/` hold one symlink per skill into it, so a new skill goes in `skills/` with a link in each, or only one harness sees it.

## Agent skills

### Issue tracker

Issues live in GitHub Issues on sleeyax/paseo-plugins, managed with the `gh` CLI.
See `docs/agents/issue-tracker.md`.

### Triage labels

The five default triage labels, each label string equal to its role name.
See `docs/agents/triage-labels.md`.

### Domain docs

Where a plugin's settings file lives is documented once in the root README, not per plugin.
Multi-context: each plugin and app is its own context whose decisions go in its own `docs/adr/`, and `docs/adr/` at the root holds workspace-wide decisions.
No glossary exists yet; `/domain-modeling` creates `GLOSSARY-MAP.md` and a context's `GLOSSARY.md` once terms get settled.
See `docs/agents/domain.md`.
132 changes: 82 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,79 +1,111 @@
# Paseo plugins and apps

Extensions for [Paseo](https://github.com/getpaseo/paseo), organized in a pnpm workspace.
My plugins for [Paseo](https://github.com/getpaseo/paseo).

| App | Description |
| --- | --- |
| [Claude TTY ACP](apps/claude-tty-acp) | Run genuine interactive Claude Code sessions in Paseo's native agent view. |

| Plugin | Description |
| --- | --- |
| [Discord Rich Presence](plugins/discord-rich-presence) | Show your current Paseo activity on Discord. |
| [Catppuccin theme](plugins/catppuccin-theme) | Add all four Catppuccin flavours as app themes. |
| [Claude TTY](plugins/claude-tty) | Offer the Claude TTY ACP adapter as a Paseo provider, and manage it on the daemon host. |
| [Guided Review](plugins/guided-review) | Show a trunk-first guide to a pull request or merge request, and build your draft review alongside it. |
## Overview

Each app and plugin has its own README with installation, settings, and development details.
| Plugin | Description |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| [Discord Rich Presence](plugins/discord-rich-presence) | Show your current Paseo activity on Discord. |
| [Catppuccin theme](plugins/catppuccin-theme) | Add all four Catppuccin flavours as app themes. |
| [Claude TTY](plugins/claude-tty) | Offer the Claude TTY ACP adapter as a Paseo provider, and manage it on the daemon host. |
| [Guided Review](plugins/guided-review) | Show a trunk-first guide to a pull request or merge request, and build your draft review alongside it. |

## Local development
| ACP | Description |
| ------------------------------------- | -------------------------------------------------------------------------- |
| [Claude TTY ACP](apps/claude-tty-acp) | Run genuine interactive Claude Code sessions in Paseo's native agent view. |

Install dependencies and check every package from the repository root:
## Installation

```sh
pnpm install
pnpm typecheck
pnpm test
```
Check each plugin's README for the Paseo version and anything else it may depend on.
A plugin installed from GitHub or a registry can be updated with `paseo plugin update <id>`.
From GitHub that installs the latest commit on `main`, and from a registry the revision the registry last approved.

Enable Paseo plugins, then install each plugin by its directory in this repository:
### From GitHub (recommended)

```sh
paseo plugin add github:sleeyax/paseo-plugins:plugins/discord-rich-presence
paseo plugin ls
```

Paseo clones the repository itself and tracks the default branch, so `paseo plugin update <id>` keeps an installation current and `paseo plugin update <id> --check` previews what it would install. Plugins published to the [Paseo plugin registry](https://paseo.sh/plugins) also install by their registry ID, which their READMEs give.
### From a registry

Two plugins ask something of the host: `claude-tty` runs an adapter that has to be built, and `guided-review` bundles Paseo's syntax highlighter, an npm dependency. Installing and updating either runs the `build` commands in its manifest, so both need `pnpm` on the daemon's `PATH`; `claude-tty` can instead take a path to an adapter built elsewhere, in its own **Adapter executable** setting.
Some plugins are also listed in a plugin registry:

To work on a plugin, install it from the working copy instead. A directory installation runs no `build`, so build what it needs first:
- [Paseo Community Plugins](https://paseo.sh/plugins): install by the registry ID the plugin's README gives, such as `paseo plugin add sleeyax/discord-rich-presence`.
It needs Paseo 0.11 or newer.
- [Paseo Cafe](https://paseo.cafe): copy the install command from the plugin's page.

```sh
paseo plugin add "/absolute/path/to/paseo-plugins/plugins/discord-rich-presence"
```
### From source

To run changes of your own, install from a clone instead:

1. Clone this repository and install its dependencies:

```sh
git clone https://github.com/sleeyax/paseo-plugins.git
cd paseo-plugins
pnpm install
```

2. Run the `build` commands in the plugin's `paseo-plugin.json` from its directory, if it has any.

3. Install the plugin from the clone:

After making changes, run `paseo plugin reload <id>`. Paseo does not hot-reload plugins, and reloading is the compile check for the client and server bundles built from `index.client.tsx` and `index.server.ts`.
```sh
paseo plugin add "/absolute/path/to/paseo-plugins/plugins/discord-rich-presence"
```

## Releasing a plugin
To update:

A plugin's `version` in its own `package.json` is its update identity: [Paseo Cafe](https://github.com/paseo-cafe/paseo-cafe) compares it against the installed copy's, and only a higher version offers an update.
Until it moves, installations stay on the old code however many commits land here.
- Run `git pull`
- Repeat the build steps
- Run `paseo plugin reload <id>`.

[release-please](https://github.com/googleapis/release-please) does the bumping, from the conventional commits on `main`: a `feat` takes a minor, a `fix` takes a patch, and a `chore` or `docs` releases nothing.
It keeps a single release pull request open and adds to it as more commits land, so a release can cover one pull request or a batch of them.
Merging it is the release: the new versions and each package's `CHANGELOG.md` are written, tagged, and published as GitHub releases.
Nothing reaches npm, since every package here is private.
Alternatively, run the `update-plugins` [skill](#skills). It does all the update steps above for every plugin installed from the clone.

Which package a commit bumps comes from the files it touches rather than its scope, so keep a change inside the plugin it belongs to.
`claude-tty` and the `claude-tty-acp` adapter it runs are versioned together, because a change to the adapter changes what the plugin ships.
## Development

## Skills
Install the plugin you are working on [from source](#from-source), then:

`skills/` holds agent skills for working on this repository, in the [Agent Skills](https://agentskills.io) format, so any harness that reads them can use them.
`.claude/skills/` and `.agents/skills/` are symlinks into it — the first is where Claude Code looks, the second is where Codex, Cursor, OpenCode and GitHub Copilot do — and editing the file under `skills/` updates every harness at once.
1. After each change, reload the plugin, and read its logs if something broke:

| Skill | Description |
| --- | --- |
| `update-plugins` | Rebuild the apps and reload the plugins this host has installed from this checkout. |
```sh
paseo plugin reload <name>
paseo plugin logs <name>
```

2. Typecheck and test the package you are working on:

```sh
pnpm --filter @paseo-plugins/<name> typecheck
pnpm --filter @paseo-plugins/<name> test
```

Or every package at once, from the repository root:

```sh
pnpm typecheck
pnpm test
```

`<name>` is the package's directory name, which is also its plugin ID.

Each plugin's README has anything else specific to it in its own Development section.

### Skills

This repository comes with its own set of local skills to aid in development:

| Skill | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `update-plugins` | Rebuild the apps and reload the plugins this host has installed from this checkout. |
| `adopt-paseo-release` | Review the Paseo releases since the last review and file an issue with what the plugins should adopt. Runs only when invoked by name: `/adopt-paseo-release` in Claude Code, `$adopt-paseo-release` in Codex. |

Working in this repository needs no installation; the symlinks are committed. To use a skill from another checkout, install it by name:
### Releasing a plugin

```sh
npx skills add sleeyax/paseo-plugins --skill update-plugins
```
Releases are automatic, so there is no version to bump or changelog to write by hand.
[release-please](https://github.com/googleapis/release-please) reads the conventional commits on `main` and keeps a release pull request open; merging it releases.

## Plugin settings
A `feat` releases a minor version, a `fix` a patch version, and `chore` or `docs` nothing. A breaking change, marked with `!` after the type (`feat!: ...`) or a `BREAKING CHANGE:` footer, releases a major version. To release a specific version instead, add a `Release-As: 1.0.0` footer to the commit.

Plugins keep their settings in `$PASEO_HOME/plugin-settings/<plugin-id>/`, managed by Paseo and removed with the plugin.
Versions from before Paseo 0.9 used `${XDG_CACHE_HOME:-~/.cache}/paseo-plugins/<plugin-id>/` instead; each plugin's README says whether it carries those settings over.
The package a commit releases is the one whose files it touches, so try to keep each commit inside one package.
43 changes: 43 additions & 0 deletions apps/claude-tty-acp/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Working on the adapter

Read the ADRs in `docs/adr/` first: they explain why the adapter types into a PTY, reads the transcript and relies on hooks.

## stdout is the ACP stream

The server speaks ACP as newline-delimited JSON on stdout, so any other byte written there corrupts the connection.
Log with `writeLog` from `src/log.ts`, which writes to stderr and to the log file under the state directory.
The daemon drops stderr, so the file is the only record of a session.

## How a write is cut up decides what Claude reads

Claude reads several characters that arrive together as pasted text, not as keys.
Send each control key as its own write with a gap after it, as the Ctrl-U clear does, or Claude inserts them as literal characters.
A large write goes the other way: the terminal can hand it over in several reads, and a paste's opening sequence cut between two of them reaches Claude as text.
So pastes go in batches that each end on a whole piece, see `PASTE_WRITE_BYTES`.

## The client has no session until the response

Paseo drops any session update for a session ID it has not been given yet.
Anything sent from `session/new` or `session/load` (commands, a replayed history) goes out after the handler returns, which is why both use `setImmediate`.

## Paseo reads "busy" from the open turn only

ACP has no other busy signal, so every turn must end through a hook or an explicit release.
A prompt Claude never took fires no hook, so it must fail the prompt rather than return; otherwise the session reads busy forever and is never suspended.
Paseo cancels before every mid-turn message and gives the cancelled `session/prompt` 2 seconds to answer, so anything added to the cancel path has to fit inside that budget.

## Cards Paseo must not answer use only reject kinds

Paseo's automatic permission modes accept an `allow_*` option without showing a card.
A card for a decision that must come from a person (startup consent, Claude's own dialogs) offers every option with a `reject_*` kind and tells them apart by `optionId`.

## A failed tool call carries an error

A `tool_call_update` with `status: "failed"` must carry a non-null `rawOutput`.
Paseo's timeline schema requires an error on failed items, and one item without it makes the client refuse the agent's whole history.

## Claude's terminal UI is measured, not specified

Readiness, dialog detection and the input-box echo match what Claude Code draws, measured against the versions named in the code comments.
A Claude Code release can break them without any change here.
The log records every dialog transition with its screen; turn those screens into test fixtures before changing a parser.
Loading
Loading