Files
platform/plugins/AGENTS.md
T
pastilhas 2360a3ef60 agents.md holds the instructions, claude.md points at it
opencode discovers only AGENTS.md, Claude Code only CLAUDE.md — so with the
content living in CLAUDE.md, every doc here was invisible to opencode. Swaps
all five pairs (root, src/apps, src/databases, themes, plugins): AGENTS.md now
holds the full text verbatim, CLAUDE.md is a short pointer. docs-check's
permission-count regex now reads root AGENTS.md instead of CLAUDE.md; the
workspace-level officer-dev/CLAUDE.md check is untouched, out of scope.
2026-08-27 06:35:31 +00:00

4.1 KiB

Plugins

EXTRACTING-A-PLUGIN.md is the runbook for turning a platform feature into a plugin, and EXTRACT-A-PLUGIN-PROMPT.md is the way to hand that to a fresh agent. This file is for the concepts a plugin author needs that are not procedure.

This directory holds documentation, not plugins. Every plugin is its own repository; plugins/<name>/ appears by git clone when somebody installs one, and is gitignored here.


Affordances

docs/affordances.md is the authority — what one is, the three tests for whether something qualifies, the file format and how they reach the agent. Read it before writing one. What follows is only the part that is specific to shipping one from a plugin.

An affordance is something the surface on the other end of the conversation offers the agent — declared by the code that implements it, and read by the agent at runtime. Not what the agent can do; what the client will honour.

A plugin ships an affordances/ directory of markdown-with-frontmatter in its repository. Installing copies it to capabilities/affordances/<publisher>/<appName>/, uninstalling removes it — the same shape as assets/ and publishAssets, and the namespace comes from where it lands rather than from anything inside the file.

The test that catches most bad ones: can it be fixed instead? If the answer is yes, fix it. An affordance describing a defect gives that defect a rationale, and the rationale outlives everyone's memory that it was a bug. See the two worked examples in docs/affordances.md.

Keep it short — every affordance is loaded into every conversation on this machine, including turns that have nothing to do with your plugin.

A plugin-contributed one, for reference## Notifications — the same shape, for push

A plugin can also declare what its push notifications MEAN. Same mechanism, different store:

capabilities/notifications/
  officerdev/music/
    catalogue.yaml
nowPlaying:
  title: 'Now playing'
  route: 'officer://music/{id}'

That becomes the code officerdev/music:nowPlaying. A push carries the code and integers — never content — and the device renders the title and follows the route. The point is that adding a notification is a server change and never an app build, because the mapping is synced to the device rather than compiled into it.

The namespace comes from where the file lands, not from what it says. Writing officer/core:test as a key in your own catalogue produces <you>/<yourplugin>:officer/core:test, not the core code — the same rule as mountPrefix, and pinned by test in src/servers/notifications/catalogue.test.ts.

An entry needs a title; body, target, route and thread are optional, thread defaults to your namespace, and unknown keys are dropped rather than forwarded to the device. Broken YAML in one plugin's catalogue is skipped without affecting anyone else's.

See docs/push-notifications.md.

A plugin-contributed one, for reference

This is the gitea plugin's, and it shows what these are for: the agent cannot discover from the filesystem that tea is authenticated, or that it should prefer git for the things git already does.

---
name: Gitea
description: Use when working with git repositories, or with Gitea issues and pull requests.
version: 1
---

For anything git already does — clone, fetch, pull, push, branches, tags — use plain `git`. It talks
to the server directly.

For anything git does not — pull requests, issues, comments, releases, creating a repository — use
`tea`. It is already logged in as the current user, with that user's own permissions. Do not
configure it, and do not ask the user for a token.

On the word

capability was taken — CAPABILITIES is the permission registry. skill was taken twice: by capabilities/skills/ here and by the wider AI ecosystem.

affordance is the exact term for what an environment offers an actor, and the precision earns the slight awkwardness: rendering an image is not a skill the agent has, it is something the client on the other end permits. Keeping that distinction in the name saves explaining it every time.