Documentation
¶
Overview ¶
Package skills installs the agent-facing documentation that ships inside the binary (§14) into an agent's skill directory.
It does not own the skill's bytes. The canonical — and only — copy of the skill lives at the repository root under skills/pay/, which is both the layout `npx skills add .../skills --skill pay` expects and a Go package that owns the //go:embed directive. This package imports it, so the tree that ships inside `pay` is byte-for-byte the tree in the repository: one copy, no sync step, nothing to drift (§1 conflict 18).
Index ¶
- Constants
- Variables
- func AgentNames() []string
- func DetectProjectRoot(start string) (string, bool)
- func FS() fs.FS
- func GitignoreCovers(root, rel string) (covered, known bool)
- func ManifestPath(dir string) string
- func Names() []string
- func NormalizeProse(s string) string
- func Read(name string) ([]byte, error)
- func RenderProject(ctx ProjectContext) []byte
- func Resolve(name string) string
- func Sum(data []byte) string
- type Agent
- type CollectionInfo
- type File
- type FileResult
- type FileStatus
- type GlobalInfo
- type Manifest
- type Options
- type ProjectContext
- type Result
- type Scope
- type StatusReport
- type TargetResult
- type TargetStatus
Constants ¶
const ( // Name is the skill's directory name and the name agents refer to it by. // It is the root package's Dir, so the directory `pay skills install` // creates and the directory the skill is stored in cannot disagree. Name = root.Dir // SkillFile is the entry point every agent reads first. SkillFile = "SKILL.md" // ReferenceDir holds the deep-dive documents. ReferenceDir = "references" // ProjectFile is the optional, discovery-generated project snapshot. ProjectFile = "references/PROJECT.md" // DirPerm is the mode for created skill directories (§14). DirPerm fs.FileMode = 0o755 // FilePerm is the mode for installed skill files (§14). FilePerm fs.FileMode = 0o644 )
const ( // StatusWritten — the file was created or overwritten. StatusWritten = "written" // StatusUnchanged — the file already had the embedded content. StatusUnchanged = "unchanged" // StatusSkipped — the file (or agent) was deliberately left alone. StatusSkipped = "skipped" // StatusRemoved — the file was deleted by `pay skills uninstall`. StatusRemoved = "removed" // StatusMissing — nothing was installed there. StatusMissing = "missing" )
File and target statuses.
const ( // WarnFileModified — a user-edited file was left alone. WarnFileModified = "skill_file_modified" // WarnNotIgnored — the project's .gitignore does not cover the skill dir. WarnNotIgnored = "skill_dir_not_ignored" // WarnAgentSkipped — an agent was not installed into, and why. WarnAgentSkipped = "skill_agent_skipped" // written (§14: it degrades gracefully). WarnProjectContextUnavailable = "skill_project_context_unavailable" )
Warning codes this package emits.
const ManifestName = ".pay-skill.json"
ManifestName is the install record written next to the skill files (§14).
Variables ¶
var Agents = []Agent{
{Name: "claude", Home: ".claude", Skills: "skills"},
{Name: "codex", Home: ".codex", Skills: "skills"},
{Name: "cursor", Home: ".cursor", Skills: "skills"},
{Name: "gemini", Home: ".gemini", Skills: "skills"},
{Name: "gemini/antigravity", Home: ".antigravity", Skills: "skills"},
{Name: "opencode", Home: ".opencode", Skills: "skills"},
{Name: "windsurf", Home: ".windsurf", Skills: "skills"},
{Name: "continue", Home: ".continue", Skills: "skills"},
{Name: "crush", Home: ".crush", Skills: "skills"},
{Name: "kiro", Home: ".kiro", Skills: "skills"},
{Name: "qwen", Home: ".qwen", Skills: "skills"},
{Name: "qoder", Home: ".qoder", Skills: "skills"},
}
Agents is the §14 target list, in install order.
var MandatoryStatements = []string{
"A read without `--draft` does **not** filter out unpublished documents — documents that were never published are returned with `_status:\"draft\"`. To get only published content, always pass `--published-only` (`_status = published`). `--draft` additionally swaps in the newest draft for documents that **do** have a published version.",
"Payload validates the **whole document** on update: a `PATCH` of one field re-validates every field of the stored document, so the error can name fields you never sent. `error.fields[].sent` is `true` only for paths that were leaves of the body PayCLI actually sent; when every entry is `sent: false`, the stored document was already invalid and your change was rejected by pre-existing state, not by your input.",
"`--locale de` on an untranslated field returns the **default locale's** text unless `fallback-locale=none`, which PayCLI sends by default and reports in `meta.locale`.",
"**Never branch on `error.message` — it is translated.** Payload runs its error strings through i18n, so the same failure reads differently on a German project, and a proxy can change the language by injecting `Accept-Language`. `error.code`, `error.exit` and `ok` are the stable signals.",
}
MandatoryStatements are the four sentences §14 requires verbatim in both SKILL.md and references/gotchas.md. Each one is a place where the obvious agent behaviour produces a confidently wrong answer, so they are asserted by a unit test rather than left to review.
var ProjectMarkers = []string{
"payload.config.ts", "payload.config.js", "payload.config.mjs", "payload.config.mts",
".git", "package.json",
}
ProjectMarkers identify a project root when walking upward from the working directory (§14).
Functions ¶
func AgentNames ¶
func AgentNames() []string
AgentNames lists the known agents, for help text and completions.
func DetectProjectRoot ¶
DetectProjectRoot walks upward from start looking for a project marker. The deepest match wins, so a nested package.json beats the repository root.
func FS ¶
FS returns the embedded skill tree rooted at the skill directory, so fs.ReadFile(skills.FS(), "SKILL.md") works. It is the root skills package's embedded copy of skills/pay/ — this package never embeds its own.
func GitignoreCovers ¶
GitignoreCovers reports whether the project's .gitignore covers rel (a slash-separated path relative to the project root). The second return value is false when there is no .gitignore to consult, in which case no warning is warranted.
This is a deliberately simple prefix/segment matcher, not a gitignore engine: it decides whether to print an informational warning, and a false negative there costs nothing.
func ManifestPath ¶
ManifestPath is the manifest's location inside an installed skill directory.
func Names ¶
func Names() []string
Names lists the embedded document paths, sorted. `pay skills list` prints it.
func NormalizeProse ¶
NormalizeProse strips Markdown blockquote markers and collapses whitespace so a required statement can be compared regardless of how it was wrapped or indented. It is how the mandatory-statement test compares text.
func Read ¶
Read returns one embedded document by its skill-relative path. `pay skills print [NAME]` uses it; NAME defaults to SKILL.md and may be given without the .md suffix or the references/ prefix.
func RenderProject ¶
func RenderProject(ctx ProjectContext) []byte
RenderProject renders references/PROJECT.md.
§14 requires the header comment, the snapshot disclaimer, the collection table, the globals, the auth collection slug with the exact header form, and three examples written against real slugs.
Types ¶
type Agent ¶
type Agent struct {
// Name is what --agent matches, case-insensitively.
Name string `json:"name"`
// Home is the agent's directory relative to the scope root (".claude").
// It is the directory whose EXISTENCE decides whether the default install
// touches this agent at all.
Home string `json:"home"`
// Skills is the skill container inside Home ("skills").
Skills string `json:"skills"`
}
Agent is one coding agent's on-disk skill layout. The table is data in the binary rather than code so a new agent does not require a release; --dir PATH and the skills.extra_dirs config key extend it at runtime.
type CollectionInfo ¶
type CollectionInfo struct {
Slug string `json:"slug"`
Label string `json:"label,omitempty"`
Singular string `json:"singular,omitempty"`
IDType string `json:"id_type,omitempty"`
Ops []string `json:"ops,omitempty"` // create read update delete
Features []string `json:"features,omitempty"` // drafts versions upload trash auth folders
KeyFields []string `json:"key_fields,omitempty"`
Internal bool `json:"internal,omitempty"`
// TotalDocs is negative when unknown.
TotalDocs int `json:"total_docs,omitempty"`
}
CollectionInfo is one collection's row in PROJECT.md.
func (CollectionInfo) HasFeature ¶
func (c CollectionInfo) HasFeature(name string) bool
HasFeature reports whether the collection advertises a capability.
type File ¶
type File struct {
// Path is relative to the skill root, slash-separated ("SKILL.md",
// "references/errors.md").
Path string `json:"path"`
// Data is the file's content.
Data []byte `json:"-"`
// SHA256 is the hex digest recorded in the install manifest.
SHA256 string `json:"sha256"`
}
File is one embedded skill document.
type FileResult ¶
type FileResult struct {
Path string `json:"path"`
Status string `json:"status"`
Reason string `json:"reason,omitempty"`
}
FileResult is what happened to one file.
type FileStatus ¶
type FileStatus struct {
Path string `json:"path"`
// State is "current" | "outdated" | "modified" | "missing" | "unknown".
State string `json:"state"`
}
FileStatus is one file's drift state in `pay skills status`.
type GlobalInfo ¶
type GlobalInfo struct {
Slug string `json:"slug"`
Label string `json:"label,omitempty"`
Features []string `json:"features,omitempty"`
}
GlobalInfo is one global's row in PROJECT.md.
type Manifest ¶
type Manifest struct {
CLIVersion string `json:"cli_version"`
InstalledAt string `json:"installed_at"`
Scope string `json:"scope"`
Agents []string `json:"agents"`
Profile string `json:"profile"`
BaseURL string `json:"base_url"`
DiscoveryRevision string `json:"discovery_revision,omitempty"`
Files map[string]string `json:"files"`
}
Manifest records what was installed, by which binary, against which project. Its Files map is what makes "the user edited this file" detectable: a hash that differs from the recorded one was not written by PayCLI.
func LoadManifest ¶
LoadManifest reads the manifest from an installed skill directory. A missing manifest is (nil, nil): the directory may predate PayCLI or have been created by hand, and that is not an error. An unparseable one is cache_corrupt (exit 1) so the user is told to delete it rather than silently losing the user-edit protection it provides.
type Options ¶
type Options struct {
// Scope is "" for the §14 default (project when a marker is found by
// walking up from StartDir, else user).
Scope Scope
// StartDir is the working directory used for project detection.
StartDir string
// ProjectRoot overrides detection.
ProjectRoot string
// Home is the user's home directory. It is injected rather than looked up
// so the whole package is testable and env-free.
Home string
// Agents selects agents by name. Empty means the §14 default: every agent
// whose Home directory already exists.
Agents []string
// AllAgents is --agent all: install into every known agent, creating the
// directories.
AllAgents bool
// ExtraDirs are --dir PATH and skills.extra_dirs. Each is an agent's
// skills directory; the skill lands in <dir>/pay.
ExtraDirs []string
// Force overwrites files the user edited.
Force bool
// DryRun computes the plan without touching the filesystem.
DryRun bool
// Project is references/PROJECT.md's content from --with-project-context.
// Nil leaves any existing PROJECT.md alone.
Project []byte
// Manifest metadata.
CLIVersion string
Now time.Time
Profile string
BaseURL string
DiscoveryRevision string
}
Options drives Install, Uninstall and Status.
type ProjectContext ¶
type ProjectContext struct {
CLIVersion string
GeneratedAt time.Time
Profile string
BaseURL string
APIPath string
DiscoveryRevision string
PayloadVersion string
AuthCollection string
AuthMode string
Locales []string
DefaultLocale string
Collections []CollectionInfo
Globals []GlobalInfo
// Examples overrides the three generated example commands.
Examples []string
}
ProjectContext is everything PROJECT.md is rendered from. It carries no credential of any kind: the auth header is documented as a form, never with a value, and BaseURL is redacted on render (§14 Privacy).
type Result ¶
type Result struct {
Scope Scope `json:"scope"`
Root string `json:"root"`
Targets []TargetResult `json:"targets"`
Skipped []TargetResult `json:"skipped"`
Warnings []output.Warning `json:"-"`
DryRun bool `json:"dry_run,omitempty"`
}
Result is the envelope payload of `pay skills install` / `uninstall`.
type StatusReport ¶
type StatusReport struct {
Scope Scope `json:"scope"`
Root string `json:"root"`
Targets []TargetStatus `json:"targets"`
}
StatusReport is the payload of `pay skills status`. `pay doctor` uses the same data to say whether the skill is installed and stale.
func Status ¶
func Status(opts Options) (*StatusReport, error)
Status reports every install location, its recorded CLI version against the running binary, per-file drift, and whether PROJECT.md's discovery revision is older than the current one.
type TargetResult ¶
type TargetResult struct {
Agent string `json:"agent"`
Dir string `json:"dir"`
Status string `json:"status"`
Reason string `json:"reason,omitempty"`
Files []FileResult `json:"files,omitempty"`
}
TargetResult is what happened at one install location.
type TargetStatus ¶
type TargetStatus struct {
Agent string `json:"agent"`
Dir string `json:"dir"`
Installed bool `json:"installed"`
CLIVersion string `json:"cli_version,omitempty"`
Stale bool `json:"stale"`
Profile string `json:"profile,omitempty"`
BaseURL string `json:"base_url,omitempty"`
DiscoveryRevision string `json:"discovery_revision,omitempty"`
ProjectDocStale bool `json:"project_doc_stale"`
Files []FileStatus `json:"files,omitempty"`
}
TargetStatus reports one install location.