Pi reads the top-level skills/ directly via a `pi` block in package.json, so it needs no vendoring or sync step. The README documents the git install only: @neondatabase/agent-skills is not on npm, so `pi install npm:` would fail. The fields a publish needs (pi-package keyword, files, publishConfig.access) are in place so that publishing later is a decision rather than a project.
17 KiB
AGENTS.md
This file provides guidance to AI coding agents (Claude Code, Cursor, Copilot, etc.) when working with code in this repository.
For the complete Agent Skills specification, see: https://agentskills.io/specification
Repository Overview
A collection of skills for coding agents for working with Neon. Skills are packaged instructions and documentation that extend the agent's capabilities.
The repo root is a portable Agent Plugins v1 package
The root plugin.json and mcp.json make this repository directly installable by any client that implements the Agent Plugins v1 specification. Everything the portable format defines lives at the root: the manifest, the MCP configuration, and the skills as immediate children of skills/.
Rules to keep in mind when touching these files:
- The
plugin.jsonschema is closed. Only$schema,name,version,description,author,homepage,repository,license,keywords, andextensionsare allowed. Client fields such asskills,mcpServers,hooks, orlogoare nonconforming at the top level — MCP servers go inmcp.json, skills are discovered fromskills/, and anything else client-specific goes under a reverse-domainextensionsnamespace owned by the client. mcp.jsontransports arestdio,streamable-http, orsse. Note that this differs fromplugins/neon-postgres/mcp.json, which uses Claude/Cursor'shttpspelling; the two files are intentionally not identical.- Only immediate children of
skills/are discovered, and eachSKILL.mdfrontmatternamemust match its directory. - Hooks, agents, commands, LSP servers, and the
marketplace.jsoncatalogs are not portable v1 components. Hooks and the rest belong inside a plugin underplugins/; the catalogs stay at the repo root in.claude-plugin/and.cursor-plugin/, where Claude Code and Cursor look for them, and point back intoplugins/. v1 only claimsplugin.json,mcp.json, andskills/, so conforming clients ignore those extra root directories. kimi.plugin.jsonis Kimi Code's own manifest and is not a v1 component either, so the closed-schema rule above does not apply to it. It declaresskillsandmcpServersinline — nonconforming at the top level of a v1 manifest, but necessary because Kimi does not readmcp.json— and it points at the sameskills/directory, so it needs no vendoring. Conforming v1 clients ignore it, the same way they ignore the catalogs.
npm run validate:agent-plugin (part of validate:ci) enforces the manifest, MCP, and skill-discovery rules above. The last two bullets are packaging conventions rather than checked rules, though validate:versions does hold kimi.plugin.json to the version in package.json like every other manifest.
Pi, and the npm fields that are staged for it
The Pi coding agent loads this repo through the pi block in package.json — "pi": { "skills": ["./skills"] } (see the Pi package docs). Pi would auto-discover a top-level skills/ by convention even without the block, but the explicit path is self-documenting and matches how every other channel here names its skills source.
Like the root Agent Plugins v1 package, Pi reads skills/ directly — no vendoring, no sync step (contrast the plugins/ copies). So a new skill under skills/ becomes a Pi skill automatically; nothing else to touch.
A Pi package declares extensions, skills, prompt templates, and themes — not MCP servers — and Pi ships no built-in MCP by design, leaving it to an extension that reads its own config. So a Pi install carries the skills alone, unlike the Claude, Cursor, and Kimi packaging that declares the Neon MCP Server.
The README advertises the git install only. @neondatabase/agent-skills is not on npm and nothing here publishes it, so pi install npm: would fail today. Three more fields in package.json are nonetheless in place, so publishing is a decision rather than a project:
keywordsincludes"pi-package"— the tag the pi.dev/packages gallery crawls npm for. A git install works but never appears in the gallery, so this is what a publish buys. Keep it in mind if you ever reformatkeywords.filesnarrows the tarball toskills/,plugin.json, andmcp.json(npm always addspackage.json,README.md, andLICENSE). Without it a publish would ship the whole tree —evals/,.github/,scripts/, everything.publishConfig.accessispublic, because npm defaults a scoped package to a restricted (paid) publish and rejects it.
None of these carries a version, so sync-versions.mjs neither reads nor writes them, and no validator enforces them. What's still missing is the release path: Neon publishes its npm packages from a private mirror rather than from the source repo, so wiring that up — and then documenting the npm install — is a follow-up.
Downstream Marketplaces — Keep in Sync
This repo (skills/) is the source of truth. The Neon skills are also published as plugins in external marketplaces that vendor their own copies of the skill files, so changes here do not propagate automatically. Whenever you add or change a skill, open a PR in each downstream marketplace to mirror it:
- OpenAI —
openai/plugins, Neon plugin atplugins/neon-postgres/(fork:andrelandgraf/plugins) - Grok (xAI) —
xai-org/plugin-marketplace, Neon plugin atexternal_plugins/neon/(fork:andrelandgraf/plugin-marketplace) - JetBrains —
JetBrains/skills, top-level skill dirs (e.g.neon/,neon-postgres/); keepmetadata.sourcepointing back here
See CONTRIBUTING.md for the full sync checklist.
Creating a New Skill
Directory Structure
skills/
{skill-name}/ # kebab-case directory name
SKILL.md # Required: skill definition
references/ # Optional: additional documentation
REFERENCE.md # Detailed technical reference
{topic}.md # Domain-specific files
scripts/ # Optional: executable scripts
{script-name}.sh # Bash scripts (preferred)
assets/ # Optional: static resources
templates/ # Document/config templates
images/ # Diagrams, examples
Naming Conventions
- Skill directory: kebab-case, must match
namein frontmatter (e.g.,neon-postgres) - Name field: 1-64 chars, lowercase alphanumeric and hyphens only, no consecutive hyphens (
--), must not start/end with- - SKILL.md: Always uppercase, always this exact filename
- Scripts:
kebab-case.sh(e.g.,deploy.sh,fetch-logs.sh)
SKILL.md Format
The SKILL.md file must contain YAML frontmatter followed by Markdown content.
Frontmatter (required fields)
---
name: skill-name
description: A description of what this skill does and when to use it. Include trigger phrases. Max 1024 characters.
---
Frontmatter (optional fields)
---
name: skill-name
description: A description of what this skill does and when to use it.
license: Apache-2.0
compatibility: Requires git, docker, and network access
metadata:
author: example-org
version: "1.0"
allowed-tools: Bash(git:*) Read
---
| Field | Required | Description |
|---|---|---|
name |
Yes | Max 64 chars. Lowercase, numbers, hyphens. Must match directory name. |
description |
Yes | Max 1024 chars. What the skill does and when to use it. |
license |
No | License name or reference to bundled license file. |
compatibility |
No | Max 500 chars. Environment requirements (system packages, network access, etc.). |
metadata |
No | Arbitrary key-value mapping for additional metadata. |
allowed-tools |
No | Space-delimited list of pre-approved tools. (Experimental) |
Body content
The Markdown body contains skill instructions. Recommended sections:
- Step-by-step instructions
- Examples of inputs and outputs
- Common edge cases
# {Skill Title}
{Brief description of what the skill does.}
## How It Works
{Numbered list explaining the skill's workflow}
## Usage
{Instructions for using the skill, including any script invocations}
## References
See [the reference guide](references/REFERENCE.md) for detailed documentation.
Best Practices for Context Efficiency
Skills are loaded on-demand — only the skill name and description are loaded at startup. The full SKILL.md loads into context only when the agent decides the skill is relevant. To minimize context usage:
- Keep SKILL.md under 500 lines — put detailed reference material in
references/ - Write specific descriptions — helps the agent know exactly when to activate the skill
- Use progressive disclosure — reference supporting files that get read only when needed
- Prefer scripts over inline code — script execution doesn't consume context (only output does)
- File references work one level deep — link directly from SKILL.md to supporting files
Optional Directories
references/
Contains additional documentation that agents can read when needed. Keep files focused — agents load these on demand, so smaller files mean less context usage.
See: https://agentskills.io/specification#references
scripts/
Contains executable code that agents can run. Scripts should:
- Use
#!/bin/bashshebang - Use
set -efor fail-fast behavior - Write status messages to stderr:
echo "Message" >&2 - Write machine-readable output (JSON) to stdout
- Include a cleanup trap for temp files
assets/
Contains static resources like templates, images, and data files.
End-User Installation
Claude Code:
cp -r skills/{skill-name} ~/.claude/skills/
claude.ai: Add the skill to project knowledge or paste SKILL.md contents into the conversation.
If the skill requires network access, instruct users to add required domains at claude.ai/settings/capabilities.
Validation
Use the skills-ref tool to validate your skills:
npm ci --ignore-scripts
npm run validate:skills
# or the full CI gate:
npm run validate:ci
You can also validate a single skill directly:
skills-ref validate ./my-skill
Plugins vendor real skill copies
The plugins under plugins/ are distributed as git repositories, and Cursor/Claude silently drop symlinks that escape the plugin root on install. So each plugin ships real copies of its skills, not symlinks into the top-level skills/.
- The mapping of which skills each plugin vendors lives in the
PLUGIN_SKILLSmap inscripts/sync-plugin-skills.mjs. A value of"*"vendors every skill underskills/(new skills ship automatically); an array vendors only the named skills. npm run sync:pluginsregenerates the copies fromskills/. A git pre-commit hook (wired by thepreparescript onnpm install) runs it automatically and stages the result.npm run validate:plugin-skills(part ofvalidate:ci) fails if the vendored copies drift from the source or if any symlink reappears inside a plugin. The Cursor and Claude plugin validators also hard-error on any in-plugin symlink.
When you add or change a skill that a plugin ships, run npm run sync:plugins (or just commit — the hook handles it).
The root Agent Plugins package is the exception: it reads skills/ directly, so it needs no vendoring and no sync step.
Releasing: bump package.json
package.json holds the plugin version. Every other manifest that declares one is generated from it, the same way plugins/*/skills is generated from skills/:
| File | Field |
|---|---|
plugin.json |
version |
kimi.plugin.json |
version |
.claude-plugin/marketplace.json |
metadata.version and plugins[].version |
.cursor-plugin/marketplace.json |
metadata.version |
plugins/neon-postgres/.claude-plugin/plugin.json |
version |
plugins/neon-postgres/.cursor-plugin/plugin.json |
version |
So a release is one edit:
npm version patch --no-git-tag-version # or minor / major
git commit -am "Release the accumulated skill changes"
The pre-commit hook runs npm run sync:versions and stages the rewritten manifests. npm run validate:versions is the same script in --check mode and runs as part of validate:ci, so a manifest edited by hand, or a commit made with the hook bypassed, still fails the build. When it does, the failure names its own fix: npm run sync:versions for a stale manifest, npm install --ignore-scripts for the lockfile below, and a hand edit for a manifest that has lost its version field.
Do not edit those version fields directly — the hook will overwrite them from package.json on the next commit.
package-lock.json carries the version too, in version and packages[""].version. npm version updates it and git commit -a stages it, so it is checked but never written: rewriting it by text match is unsafe because it repeats "version" for every dependency. If it drifts, run npm install --ignore-scripts, which rewrites it from package.json. Reach for that rather than editing it, because npx can quietly restore the old version from node_modules/.package-lock.json.
The table is what the manifests happen to declare today, not a contract. scripts/sync-versions.mjs syncs whichever version fields a file already has and picks up any new directory under plugins/ automatically — so adding a version to a catalog's plugin entry silently brings it into the set. A file that exists but declares no version at all is an error, so a deleted field cannot pass as "in sync".
The rewrite is a surgical text replacement rather than a JSON re-serialize, so each file's formatting survives untouched. Every file is re-parsed and compared before anything is written, and nothing is written unless all of them verify.
CI/CD
Neon maintains two agent-skill repositories with a shared, hardened CI pipeline. Keep them aligned when you change CI/CD in either repo.
| Repo | GitHub | What CI validates |
|---|---|---|
| agent-skills (this repo) | neondatabase/agent-skills | Every skill under skills/ via skills-ref and its reference graph, plus the root Agent Plugins v1 package, both marketplace catalogs and plugin manifests, the vendored plugin skills, and every manifest version against package.json |
| neon-for-agent-platforms | neondatabase/neon-for-agent-platforms | Every skill under skills/ via skills-ref |
Shared pipeline shape (both repos):
- Workflow:
.github/workflows/validate.yml(job name Validate) - Install:
npm ci --ignore-scriptsfrompackage-lock.json - Entry point:
npm run validate:ci - Supply chain: SHA-pinned GitHub Actions, exact-pinned npm dependencies (
save-exact=truein.npmrc, no ranges and no unpinnednpx),package-lock.jsonresolving fromregistry.npmjs.org,harden-runneregress audit, Dependabot forgithub-actions+npm
Repo-specific (keep — do not drop when aligning): this repo also validates the root Agent Plugins v1 package and the Cursor and Claude plugin manifests under plugins/. That's why validate:ci here is validate:agent-plugin && validate:plugins && validate:versions && validate:skills && validate:references (vs. skills-only in neon-for-agent-platforms) and why this workflow also filters on plugins/**, plugin.json, mcp.json, kimi.plugin.json, .claude-plugin/**, and .cursor-plugin/**. Do not drop the last three: the Kimi manifest and the two catalogs hold four of the synced version fields between them, so losing one of those filters would let a version-bearing change skip validate:versions. Alignment means matching the shared shape above, not stripping this repo's plugin checks.
When you change CI/CD here — workflow triggers, install hardening, skills-ref pinning, Dependabot config, or validate scripts — apply the same change to neondatabase/neon-for-agent-platforms, preserving each repo's intentional differences (this repo's plugin validation and plugins/** path filter).
neon-for-agent-platforms has no plugins/ directory and no root plugin.json yet, so validate:agent-plugin, validate:versions, and the plugin.json/mcp.json/kimi.plugin.json path filters do not port over as-is. Giving that repo its own portable manifest is a follow-up; until then, this is an intentional difference rather than drift.