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: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ jobs:
uv run ruff format --check src tests
uv run ruff check src tests
uvx --from actionlint-py==1.7.12.24 actionlint .github/workflows/*.yml
uvx --from skills-ref==0.1.1 agentskills validate skills/agent-plugins
uvx --from skills-ref==0.1.1 agentskills validate skills/package-agent-plugin
shellcheck scripts/*.sh

- name: Type-check
Expand Down
30 changes: 25 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@

The [Agent Plugins format](https://agent-plugins.org/) defines the directory: a manifest, [Agent Skills](https://agentskills.io/specification) for instructions and resources, [Model Context Protocol (MCP)](https://modelcontextprotocol.io/specification) server configuration for tools, and client extensions. This library packages that directory and makes it discoverable through Python metadata. Agent clients choose which components to activate.

## Read the bundled guidance

Run `agent-plugins` without arguments to read its own installed plugin:

```console
uvx agent-plugins
```

The output contains two version-matched skills. `agent-plugins` explains how to
read instructions from Python packages that already ship an Agent Plugin.
`package-agent-plugin` explains how to add Agent Plugin packaging to a Python
project.

## Package your plugin

Keep `plugin.json` and `skills/` beside your code. For a project using the [uv build backend](https://docs.astral.sh/uv/concepts/build-backend/), configure `pyproject.toml`:
Expand Down Expand Up @@ -56,20 +69,27 @@ Attachment updates the wheel in place. Pass `--output-dir` to preserve the input

## Inspect an installed plugin

Install `agent-plugins` in the environment you want to inspect. The package includes its own Agent Skill:
Load the complete version-matched guidance shipped by a package:

```console
pip install agent-plugins
uvx --with my-package agent-plugins read my-package
```

The first `my-package` tells uv which distribution to install. The second
identifies the installed Agent Plugin to read.

Use the Python API when the package is already installed in the current
environment:

```python
import agent_plugins as ap

plugin = ap.locate("agent-plugins")
skill = plugin.skill("agent-plugins")
consumer_skill = plugin.skill("agent-plugins")
packaging_skill = plugin.skill("package-agent-plugin")

print(skill.source)
print(skill.file("SKILL.md"))
print(consumer_skill.source)
print(packaging_skill.source)
```

Pass your library's distribution name to `locate()` to inspect its plugin. Use [`Plugin.from_project()`](https://peter-gy.github.io/agent-plugins/guide/inspect-project) to inspect the selected source files before building.
Expand Down
13 changes: 9 additions & 4 deletions development_docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ other source → supplied BuildPlan │ │ │
| `build/hatchling.py` | Public Hatchling adapter module |
| `_marker.py` | Encode and decode `agent_plugins.json` |
| `_discovery.py` | Resolve markers through `importlib.metadata` |
| `_files.py` | Own resolved roots, validated relative names, subtree inventories, and selected-file lookup |
| `_files.py` | Own resolved roots, validated relative names, single-pass immediate subtree inventories, and selected-file lookup |
| `_plugin.py` | Construct project-selected handles and compose named manifest, MCP, and skill access around one inventory |
| `_skill.py` | Expose exact skill source, checked selected files, native joins, and tree rendering |
| `_schema/manifest.py` | Dispatch and cache manifest validation |
Expand All @@ -62,7 +62,8 @@ other source → supplied BuildPlan │ │ │
| `_schema/skill.py` | Split UTF-8 `SKILL.md` source at exact delimiters |
| `_schema/v1/` | Validate Agent Plugins 1.0.0 documents |
| `_tree.py` | Render bounded deterministic ASCII trees |
| `_cli.py` | Parse commands and render human or JSON output |
| `_read.py` | Compose installed distribution and plugin metadata into Markdown briefings |
| `_cli.py` | Parse commands, call domain operations, and write human or JSON output |

## Dependency direction

Expand All @@ -72,11 +73,15 @@ Artifact operations depend on plan validation and archive writers. Archive write

Versioned schema loaders produce normalized values. Stdio resolution consumes those values and the selected inventory, independently of JSON parsing. `MCPConfig` composes cached document access with uncached launch preparation. Schema loaders and launch preparation do not depend on build or discovery code.

The CLI parses input, calls public-domain functions, and renders output. Core modules do not depend on terminal state.
The CLI parses input, calls domain functions, and writes their rendered output.
Core modules do not depend on terminal state.

## Public object model

`Plugin` and `Skill` are slotted filesystem handles. Their equality and hash use the resolved root and selected relative filenames. Parsed document content does not participate.
`Plugin` and `Skill` are slotted filesystem handles. Plugin equality and hashing
use the resolved root and selected relative filenames. Skill equality and
hashing also include its structural directory name. Parsed document content
does not participate.

`Manifest` and `MCPConfig` are lazy document handles. `Author`, MCP server values, `ResolvedStdioServer`, `ValidationIssue`, `BuildPlan`, `FileMapping`, and `WheelAttachment` are frozen values.

Expand Down
7 changes: 5 additions & 2 deletions development_docs/testing-and-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ uv run ruff check src tests
uv run ty check
uv run pyrefly check
uv run pytest -q
uvx --from skills-ref==0.1.1 agentskills validate skills/agent-plugins
uvx --from skills-ref==0.1.1 agentskills validate skills/package-agent-plugin
./scripts/build-dist.sh
pnpm --dir docs install --frozen-lockfile
pnpm --dir docs typecheck
Expand All @@ -38,7 +40,8 @@ The distribution verifier:
1. Requires one wheel and one `.tar.gz` source distribution.
2. Rebuilds a wheel from the source distribution.
3. Installs the direct and rebuilt wheels in isolated targets.
4. Verifies plugin file bytes, discovery, manifest access, skill access, CLI `locate`, and CLI `list --json`.
4. Verifies plugin file bytes, discovery, manifest access, skill access, CLI
`locate`, CLI `list --json`, CLI `read`, and the no-argument shortcut.
5. Creates an editable installation and checks that discovery resolves the authored root.
6. Uses the installed Python API and CLI to attach a synthetic external wheel, installs it, and verifies discovery.

Expand All @@ -48,7 +51,7 @@ The distribution verifier:
| --- | --- |
| Build-plan selection and CLI JSON | `tests/test_plan.py` |
| Public wheel attachment, preservation, validation, signatures, and `RECORD` | `tests/test_wheel.py` |
| CLI attachment output, warnings, and exit statuses | `tests/test_cli.py` |
| CLI read and attachment output, warnings, and exit statuses | `tests/test_cli.py` |
| Backend parity, sdist rebuilds, editable markers, and sdist modes | `tests/test_build_backends.py` |
| Installed distribution discovery and marker failures | `tests/test_discovery.py` |
| Project-selected plugin inventory, paths, display, named skills | `tests/test_plugin.py` |
Expand Down
18 changes: 15 additions & 3 deletions docs/guide/inspect-installed.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,24 @@ description: Locate Agent Plugins by Python distribution name and inspect their

# Inspect installed Agent Plugins

Use `locate()` to read the Agent Plugin shipped with an installed Python library. Install `agent-plugins` in the same environment as that library:
Read the guidance packaged with `agent-plugins` itself:

```console
pip install agent-plugins
uvx agent-plugins
```

Read a package's complete primary agent instructions in one command:

```console
uvx --with my-project agent-plugins read my-project
```

uv installs `my-project` and `agent-plugins` in one temporary environment. The
command prints the complete version-matched guidance carried by `my-project`.

Use `locate()` when the Python library is already installed in the environment
where the agent will work:

## Locate one distribution

```python
Expand Down Expand Up @@ -45,7 +57,7 @@ for path in plugin.files:
print(path)

for skill in plugin.skills:
print(skill.path)
print(skill.name, skill.path)

if plugin.mcp is not None:
print(plugin.mcp.path)
Expand Down
10 changes: 4 additions & 6 deletions docs/guide/what-is-an-agent-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ An [Agent Plugin](https://agent-plugins.org/) is a directory with a `plugin.json

`agent-plugins` packages that directory with a Python library. An agent that can execute Python can read the library's packaged instructions, then compose calls to its API for a task. The same workflow applies to a short script, an interactive session, or a notebook.

With `agent-plugins` [installed](/guide/inspect-installed), read its own packaged skill:
Read the package's consumer and repository-integration guidance in a temporary
environment:

```python
import agent_plugins as ap

plugin = ap.locate("agent-plugins")
print(plugin.skill("agent-plugins").source)
```console
uvx agent-plugins
```

An **agent client** is the application hosting the model and its execution tools. It decides which instructions to load and which components to activate. The Python API supplies files, text, validated configuration, and subprocess inputs for that integration.
Expand Down
5 changes: 4 additions & 1 deletion docs/integrations/agent-skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ plugin = ap.locate("my-project")
skill = plugin.skill("review-records")

print(skill.path)
print(skill.name)
print(skill.source)
print(skill.file("references/fields.md"))
```

`skill.files` contains absolute paths from the selected inventory below that skill root. `skill.tree()` renders the same selection as a bounded ASCII tree.
`skill.name` is the structural directory name used by `plugin.skill(name)`.
`skill.files` contains absolute paths from the selected inventory below that
skill root. `skill.tree()` renders the same selection as a bounded ASCII tree.

`plugin.skill(name)` selects an immediate skill by its structural directory name and reports sorted available names when the requested skill is absent.

Expand Down
53 changes: 50 additions & 3 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,65 @@
---
title: CLI reference
description: Reference agent-plugins plan, attach-wheel, locate, and list commands, output formats, and exit statuses.
description: Reference agent-plugins read, plan, attach-wheel, locate, and list commands, output formats, and exit statuses.
---

# CLI reference

The `agent-plugins` command previews package file selection, attaches Agent Plugins to wheels, and locates plugins visible in the current Python environment.
The `agent-plugins` command reads installed plugin instructions, previews package
file selection, attaches Agent Plugins to wheels, and locates plugins visible in
the current Python environment.

```text
agent-plugins {plan,attach-wheel,locate,list} ...
agent-plugins
agent-plugins {read,plan,attach-wheel,locate,list} ...
```

`python -m agent_plugins` runs the same entry point.

With no arguments, `agent-plugins` reads the plugin installed with its own
distribution. These commands produce the same stdout:

```console
uvx agent-plugins
uvx agent-plugins read agent-plugins
```

## `agent-plugins read`

```text
agent-plugins read DISTRIBUTION [--skill NAME]
```

`DISTRIBUTION` is an installed Python distribution name. Human output is a
Markdown briefing containing:

- Python distribution and plugin manifest metadata
- the bounded selected plugin file tree and installed root
- client extension names and manifest validation issues
- MCP server names and transport types, with configured commands, arguments,
environment values, URLs, and headers excluded
- the complete `SKILL.md` source for every packaged Agent Skill by default

The generated introduction explains relative resource paths. Skill source
remains complete. The inventory uses the standard tree bounds of four levels
and 100 files, and reports omitted depth or file counts. Inspect the printed
installed root when a skill routes to a resource outside that view.

`--skill NAME` prints one structurally named skill while retaining the package
metadata, bounded inventory, extension names, and MCP summary. An unavailable
name reports the sorted available skills on stderr.

Use uv to read a package without adding it to the current project:

```console
uvx --with my-package agent-plugins read my-package
```

The package requirement after `--with` and the final distribution argument are
separate inputs. uv installs the requirement into the temporary command
environment. `read` selects that installed distribution through Python
metadata.

## `agent-plugins plan`

```text
Expand Down
12 changes: 8 additions & 4 deletions docs/reference/python-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ Import the top-level API as `agent_plugins`:
import agent_plugins as ap
```

The installed `agent-plugins` distribution includes a skill you can inspect:
The installed `agent-plugins` distribution includes separate consumer and
packaging skills:

```python
plugin = ap.locate("agent-plugins")
skill = plugin.skill("agent-plugins")
print(skill.source)
print(plugin.skill("agent-plugins").source)
print(plugin.skill("package-agent-plugin").source)
```

The distribution supports Python 3.10 through 3.14 and ships a `py.typed` marker.
Expand Down Expand Up @@ -230,6 +231,7 @@ Raises `AgentPluginError` when the root cannot be resolved, is not a directory,

| Property | Type | Behavior |
| --- | --- | --- |
| `name` | `str` | Structural directory name used by `plugin.skill(name)` |
| `path` | `Path` | Resolved absolute skill root |
| `files` | `tuple[Path, ...]` | Absolute paths in the selected skill inventory |
| `frontmatter` | `str` | Raw text between the `---` delimiter lines |
Expand All @@ -254,7 +256,9 @@ skill / "references" / "api.md"

The `/` operator delegates to ordinary unchecked `pathlib.Path` joining. Use `skill.file()` when selection and containment are required.

`Skill.tree()`, native path conversion, display, equality, and hashing follow the `Plugin` contracts.
`Skill.tree()`, native path conversion, and display follow the `Plugin`
contracts. Two `Skill` handles compare equal and have the same hash when their
structural names, resolved roots, and selected relative filenames match.

## `Manifest`

Expand Down
Loading
Loading