Distributing Perfetto skills to OSS coding agents

Authors: @LalitMaganti

Status: Draft

Problem

RFC-0025 section 3 sets out the broad direction for AI integration outside the Perfetto UI: ship Perfetto-flavoured skills 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 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:

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:

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:

ToolInstall command
Claude Code/plugin marketplace add google/perfetto@ext/agents
Gemini CLIgemini extensions install https://github.com/google/perfetto --ref ext/agents
Codexcodex plugin marketplace add google/perfetto --ref ext/agents
OpenCodeadd "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, 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.