blob: 80fa56692bebb6836f6f2565d43b67abffb95865 [file] [view] [edit]
# Distributing Perfetto skills to OSS coding agents
**Authors:** @LalitMaganti
**Status:** Draft
## Problem
[RFC-0025](./0025-ai-in-perfetto.md) section 3 sets out the broad direction
for AI integration outside the Perfetto UI: ship Perfetto-flavoured
[skills](https://agentskills.io/home) so that any OSS coding agent
(Claude Code, Gemini CLI, OpenAI Codex, OpenCode) can drive
`trace_processor` to load, query and reason about traces. The seed commit
[39c023b](https://github.com/google/perfetto/commit/39c023b2575616e2bb81c7357cf670f89780404e)
landed the first three skills in `ai/skills/` and established the
authoring conventions.
This RFC pins down the packaging, distribution and update story.
Today, a user who wants Perfetto's skills inside their agent has to clone
`google/perfetto`, install `trace_processor` separately, and copy
`ai/skills/*` into the right location for each agent. They then have to
remember to repeat that work whenever we ship changes. Concrete
problems:
1. There is no first-class install path for any of the major agents.
2. Skills and the `trace_processor` binary are acquired through
different channels, so users have to do two installs and keep both
versions in sync themselves.
3. Once installed, skills snapshot at copy time and rot as
`trace_processor` evolves.
4. A user who has never heard of "Perfetto skills" has no entry point:
no marketplace listing, no docs page, no install snippet to paste.
This RFC proposes a single packaging mechanism, tied to the existing
Perfetto release process, that addresses all four for the four agents
that matter today while leaving room for the long tail.
## Decision
Pending. The body proposes the following:
* Source of truth lives in `main`, under `ai/skills/` and
`ai/extensions/<agent>/`.
* The Perfetto release pipeline produces a dedicated `ext/agents`
branch on each release. The branch carries a pristine, root-level
layout that every supported agent's install command can fetch
directly via git ref pinning. OpenCode reads the same content via
its `skills.urls` config.
* The branch bundles the `trace_processor` Python wrapper
(`tools/trace_processor`) so users do not need a separate
`trace_processor` install step.
* Four officially supported install lines, one per agent, documented
on the Perfetto docs site under an AI integration page.
* A fallback install script lives alongside our other release scripts
and copies the bundled skills and the `trace_processor` script into
a user-chosen path. This is the install path for any agent we do not
officially support (Cursor, Continue, homegrown agents).
* The existing `trace_processor` CLI plus skills cover the workflow.
We do not ship an MCP server or a binary plugin, and we do not add
an `install-skills` subcommand to `trace_processor`.
* Slash commands per agent are deferred. v1 is skills-only.
* Marketplace submissions wait until the integration has been stable
through at least one release cycle.
## Design
### Source-of-truth layout in `main`
Skills are already at `ai/skills/`. We add per-agent extension manifests
alongside, in their own subdirectories:
```text
ai/
├── skills/ # canonical skill content
│ ├── perfetto-infra-querying-traces/SKILL.md
│ ├── perfetto-infra-getting-trace-processor/SKILL.md
│ ├── perfetto-workflow-android-heap-dump/SKILL.md
│ └── ...
└── extensions/
├── claude-code/
│ ├── plugin.json # packaged into .claude-plugin/
│ └── marketplace.json # packaged into .claude-plugin/
├── gemini-cli/
│ └── gemini-extension.json # at branch root
└── codex/
├── plugin.json # packaged into .codex-plugin/
└── marketplace.json # packaged into .agents/plugins/
```
Each manifest holds the minimum the agent's loader requires: name,
version, the list of skills, and (when we choose to ship them later)
slash commands. There is no per-agent skill content. All four agents
use the agentskills.io `SKILL.md` format, so a single canonical
`skills/` tree serves all of them.
A skill's SKILL.md frontmatter can declare which install targets it
applies to. The release pipeline reads this and includes or excludes
the skill per target. The motivating case is
`perfetto-infra-getting-trace-processor`: it is needed for the
fallback installer (where users may want to set up `trace_processor`
manually) but redundant for the native extensions (which bundle the
script).
### The `ext/agents` release branch
`ext/agents` is produced by the Perfetto release pipeline alongside
the `trace_processor` binary release. Each commit to it corresponds
1:1 with a Perfetto release tag, and the manifest `version` fields all
carry that tag. Treat it as a release artefact, not as a working
branch.
Its root is shaped to satisfy every agent's discovery contract at the
same time:
```text
ext/agents (branch root)
├── gemini-extension.json # Gemini reads from root
├── .claude-plugin/
│ ├── plugin.json
│ └── marketplace.json # Claude marketplace entrypoint
├── .codex-plugin/
│ └── plugin.json
├── .agents/plugins/
│ └── marketplace.json # Codex marketplace entrypoint
├── bin/
│ └── trace_processor # bundled Python wrapper
└── skills/ # shared, agentskills.io layout
├── index.json # OpenCode skills.urls manifest
├── perfetto-infra-querying-traces/SKILL.md
├── perfetto-workflow-android-heap-dump/SKILL.md
└── ...
```
The branch carries only the extension surface. There is no `src/`,
`docs/` or `tools/` content. A user installing the extension pulls a
few tens of kilobytes rather than the full `google/perfetto` tree.
The four manifest filenames are namespace-distinct, so each tool only
sees its own. Skills live in one shared `skills/` tree because all four
tools agree on `<root>/skills/<slug>/SKILL.md` and respect the
agentskills.io frontmatter; nothing is duplicated.
### Coupling to the release process
`ext/agents` is part of the release artefact set, not built from `main`
directly. The whole point of this coupling is that the
`trace_processor` binary, the bundled wrapper script and the skills
move together: when users update one, they update everything. Doc and
skill state on `main` does not surprise installed users mid-cycle.
The release pipeline assembles the branch from `main` at the release
tag, copies in the manifests, skills (filtered by target), and the
`trace_processor` wrapper, sets every manifest's `version` field to
the release tag, and commits. A separate linter step in regular `main`
CI validates each manifest against its tool's schema so we catch
broken JSON before it reaches the release pipeline.
Every commit on `ext/agents` records the SHA of the `main` commit it
was built from, in a small metadata file at the branch root. The
fallback install script is regenerated at the same release tag and
embeds that same SHA. When the script runs, it walks `ext/agents`
history (via a single GitHub API call) to find the commit whose
recorded SHA matches the embedded one, and downloads that commit's
tarball. This makes installs deterministic across release boundaries:
a user who saves the script locally and reruns it later gets the same
bundle they would have gotten on the day it was published, even if
newer releases have landed in the meantime.
### Per-agent install commands
These five lines are the entire user-facing install surface:
| Tool | Install command |
| :----------------------------------- | :----------------------------------------------------------------------------------------------------------- |
| Claude Code | `/plugin marketplace add google/perfetto@ext/agents` |
| Gemini CLI | `gemini extensions install https://github.com/google/perfetto --ref ext/agents` |
| Codex | `codex plugin marketplace add google/perfetto --ref ext/agents` |
| OpenCode | add `"skills": { "urls": ["https://raw.githubusercontent.com/google/perfetto/ext/agents/skills/index.json"] }` to `opencode.json` |
| Other agents (Cursor, Continue, ...) | `curl -fsSL https://get.perfetto.dev/agents-install.sh \| bash -s -- --target <path>` |
Each tool's native update path applies for the first four. Claude
`/plugin update`, Gemini `extensions update`, the Codex marketplace
refresh, OpenCode's startup URL re-fetch. The release pipeline pushes
to `ext/agents`; users get the changes through the channel they
already know. The fallback script's update path is to re-run the same
command, which overwrites the target directory.
### Bundling `trace_processor`
The release pipeline vendors the auto-generated
`tools/trace_processor` Python wrapper into `ext/agents/bin/`. Users
who install the extension also get the script, so there is no
separate `trace_processor` install step.
The exact mechanism each native extension uses to expose the wrapper
to its skills (relative path from plugin root, declared `bin` in the
manifest, install-time `PATH` entry) is settled per-agent during
manifest authoring.
### Fallback installer
The installer script lives in `tools/` in `main`, alongside our other
end-user scripts, and is served from `get.perfetto.dev` the same way.
It downloads the `ext/agents` tarball at the latest release tag (or
the ref passed via `--ref`), extracts `skills/` and
`bin/trace_processor` into the path passed via `--target`, and prints
a `PATH` hint.
The script is the install path for any agent without a native
extension. It is also the recommended path for users who want a single
on-disk source of truth regardless of agent, including OpenCode users
who want the bundled wrapper rather than installing `trace_processor`
separately (`--target ~/.config/opencode/`).
### Extension store / marketplace submissions
Each of the three plugin-style agents has, or is in the process of
establishing, a public extension index (Gemini CLI's
[extensions index](https://github.com/google-gemini/gemini-cli/tree/main/extensions),
Claude Code's `code.claude.com/plugins`, the upcoming Codex public
index). We submit Perfetto's extension to each once it has been live
in `ext/agents` for at least one release cycle. The submission for
each is a small, tool-specific PR; it is not on the critical path for
the docs page or for v1 install support.
OpenCode has no marketplace surface (plugins are discovered via npm),
so no submission is required.
### Documentation
A new page on the Perfetto docs site carries the five install lines,
a one-line summary of each shipped skill, and a pointer to
`ai/skills/README.md` for teams who want to author or contribute their
own. It also documents the project-scope variant for each install
path, for teams who want to check skills into a shared repo
(`.claude/skills/`, `.opencode/skills/`, etc.) so every developer on
the team gets the same baseline.
The page links back to this RFC and to RFC-0025.
### Out of scope
Several adjacent topics come up in the same conversation but belong in
their own RFCs or follow-ups:
* Long-running session hardening in `trace_processor` (idle-timeout,
optional parent-PID watch, stdin-EOF detection). The querying skill
already teaches the `--httpd` background pattern and agents handle
the process lifecycle through their existing background-shell
tooling. Cleanup robustness is a `trace_processor` work-item, not a
packaging one.
* Team-authored skills via extension servers. RFC-0025 §4 covers
this. The packaging mechanism here would extend naturally because a
team's extension server can publish its own `index.json` and a
team's local config can list multiple `skills.urls`. The server-side
API is separate work.
* Slash commands per agent (`/perfetto-load`,
`/perfetto-investigate-jank`, ...). Cheap, discoverable, easy to
add later once we know which workflows users repeatedly type in
natural language. Skills-only in v1.
* A first-class OpenCode npm plugin. Useful only if we want a custom
`perfetto_query` tool or auto-spawn hooks. Deferred until there is
evidence skills alone are insufficient.
* An MCP server. See Alternatives.
## Alternatives considered
### A. `trace_processor ai install-skills` subcommand
Bundle the skills into the binary and ship a subcommand that copies
them into the user's agent skill directories.
Pros: Works fully offline. Skill version equals the binary version.
Cons: Snapshots at install time; users have to re-run after every
release. Encodes the agent skill-directory layout into
`trace_processor`, which leaks packaging concerns into the analysis
engine. Each new agent we want to support requires a code change.
### B. Subdirectory installs (no branch)
Use Codex's `--sparse` and Claude's `git-subdir` source format to
install directly out of `main`'s `ai/extensions/<tool>/`
subdirectories.
Pros: No release-pipeline branch building.
Cons: Gemini CLI does not support subdirectory installs for extensions
(only its standalone `gemini skills install` does), so this approach
cannot cover all four tools. Forces every install to clone the full
`google/perfetto` history, which is hundreds of megabytes for a few
KB of extension content. Couples installed state to whatever happens
to be on `main` at the moment of install rather than to a release.
### C. First-class MCP server
Ship a `trace_processor mcp` mode (or a separate `perfetto-mcp`
binary) that exposes the existing RPC as MCP tools, and have each
extension declare it as an MCP server in the agent's config.
Pros: MCP is a recognisable install ritual. Typed tool surface. Server
holds agent state. The server process is cleaned up automatically when
the agent dies (via stdio EOF).
Cons: Buys little over skills plus a CLI binary in practice. The
`trace_processor` CLI is well-shaped, agents construct shell
invocations reliably from a skill, and the long-running `--httpd` mode
already covers iterative querying. An MCP layer is duplicate plumbing.
The cleanup advantage MCP enjoys is a property of stdio child
processes, not of the protocol; we can get the same property for
`trace_processor` via a small `--exit-on-stdin-eof` or
`--idle-timeout` change without adopting MCP.
### D. Custom OpenCode npm plugin
Publish `@perfetto/opencode-plugin` to npm and rely on it for the
OpenCode install path.
Pros: Matches OpenCode's documented plugin install ritual. Lets us
register custom tools and hooks alongside the skills.
Cons: OpenCode's plugin API cannot register skill paths at runtime;
the only first-class skill-distribution mechanism is `skills.urls`,
which we already use. An npm package adds a release artefact and a
publishing pipeline for what would, in v1, be a strictly worse
skill-discovery experience than the URL approach. Worth revisiting if
real users ask for the tool/hook surface.
## Open questions
* OpenCode `skills.urls` cache invalidation behaviour needs a
prototype. Confirm that pushes to `ext/agents` propagate to users on
the next session start and that the cache does not pin a stale copy
indefinitely.
* The exact mechanism each native extension uses to expose the
bundled `trace_processor` wrapper to skills (relative path from
plugin root, declared `bin` in the manifest, install-time `PATH`
entry) needs to be settled per-agent during manifest authoring.
* Claude Code marketplace ref pinning is documented but lacks an
official non-default-branch example. Prototype the
`google/perfetto@ext/agents` install upfront, before the release
pipeline work, to confirm the contract.