surface

package
v0.19.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package surface holds the provider-surface registry: the verified facts about where each AI coding agent looks for a skill (its "skills home") and where it reads always-on context (CLAUDE.md, AGENTS.md, …), plus the detection and link logic that use those facts.

Why a registry, not a name check

Every fact in this package was read from the provider's own current docs and is written down here with its SourceURL and VerifiedOn date, so it can be re-verified instead of recalled — the harness-discipline rule ("a provider fact is read, written down, and branched on by surface — never recalled") applied to a2a's own product code (spec 32 §2.1). Code that needs a provider fact asks a Surface row a question ("does this surface read AGENTS.md?"); it never branches on a provider id string inline. A new provider is a new row, not a new if-statement.

This package imports nothing of a2ahub's own; internal/cli is the (later) consumer.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrForeignLinkTarget is returned by Link when a surface's
	// <SkillsHome>/a2ahub entry already exists, is not a2ahub-owned (not a
	// symlink into the SSOT tree, not a stub carrying our marker tag), and
	// force is not set. Nothing is written.
	ErrForeignLinkTarget = errors.New("surface: link target is not an a2ahub-managed entry")
)

Sentinel errors, one per failure class (internal/host idiom). Callers use errors.Is against these; a typed *Error carries the operation and offending input on top.

Functions

This section is empty.

Types

type Error

type Error struct {
	// Op names the failing operation (e.g. "Link").
	Op string
	// Input is the offending input, kept for diagnostics (may be empty).
	Input string
	// Err is the wrapped sentinel (see the vars above).
	Err error
}

Error is the small typed error every exported operation in this package returns on failure. It always wraps one of the sentinels above so callers can use errors.Is/As; it never panics on bad input.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type LinkMode

type LinkMode string

LinkMode records how a discovery entry was installed for a surface.

const (
	// LinkSymlink means the entry is a relative symlink to the SSOT tree
	// (the preferred form — Claude Code documents symlinked skill
	// directories explicitly).
	LinkSymlink LinkMode = "symlink"
	// LinkStub means the entry is a thin stub SKILL.md pointing back at the
	// SSOT tree — the fallback used where symlinks are unavailable (e.g.
	// Windows without Developer Mode). The runtime fallback IS the
	// cross-platform mechanism; there is no build-tag branch for it.
	LinkStub LinkMode = "stub"
)

type LinkResult

type LinkResult struct {
	// Surface is the row the entry was installed for.
	Surface Surface
	// Path is the repo-relative a2ahub entry, e.g. ".claude/skills/a2ahub".
	Path string
	// Mode is how the entry was installed.
	Mode LinkMode
}

LinkResult describes one installed discovery entry.

func Link(root string, s Surface, ssotRel string, force bool) (LinkResult, error)

Link installs a discovery entry for surface s under root: <root>/<s.SkillsHome>/a2ahub, pointing at the installed SSOT tree at <root>/<ssotRel> (normally ".a2ahub/skill"). It first tries a relative symlink; if that fails (platform/permission error) it falls back to a stub SKILL.md carrying valid Agent-Skill frontmatter and a pointer to the SSOT tree's own SKILL.md.

Ownership probe (mirrors cmd_skill.go's skillTargetState/errSkillForeignTarget gate): an existing target is "ours" when its symlink destination resolves exactly to this repository's SSOT path, or a directory/file carries linkMarkerTag. A foreign target (present, not ours) is refused with ErrForeignLinkTarget and nothing is written, unless force is set. An absent target is always free to create. An authorized target (ours, or force over foreign) is removed first so the result mirrors — no orphaned stale entry.

type Surface

type Surface struct {
	// ID is the surface's stable identifier ("claude", "codex").
	ID string
	// SkillsHome is the repo-relative directory this surface's runtime scans
	// for skills, e.g. ".claude/skills".
	SkillsHome string
	// ContextFile is the repo-relative file this surface reads as always-on
	// context, e.g. "CLAUDE.md" or "AGENTS.md".
	ContextFile string
	// ReadsAgentsMD is true when this surface's runtime reads AGENTS.md as
	// always-on context (Codex does; Claude Code does not — it reads
	// CLAUDE.md instead, per code.claude.com/docs/en/memory).
	ReadsAgentsMD bool
	// SourceURL is the doc page this row was read from.
	SourceURL string
	// VerifiedOn is the date (YYYY-MM-DD) this row was last verified against
	// SourceURL.
	VerifiedOn string
}

Surface is one verified provider fact row: where that provider's runtime discovers a skill (SkillsHome) and where it reads always-on context (ContextFile), plus the provenance of the row itself (SourceURL, VerifiedOn) so it can be re-verified instead of recalled.

func ByID

func ByID(id string) (Surface, bool)

ByID returns the registry row for id, and whether it was found.

func Detect

func Detect(root string) []Surface

Detect returns every Registry() row whose marker directory (<root>/<Surface.MarkerDir()>, e.g. ".claude") exists under root, in Registry()'s deterministic order. Detection is best-effort: a missing root, a missing marker dir, or an unreadable entry all yield exclusion — Detect never returns an error, so a caller (e.g. `a2a init`) can always treat its result as "the surfaces this repo already shows".

func Registry

func Registry() []Surface

Registry returns every known provider-surface row, in a fixed, deterministic order (claude, then codex). Adding a provider means adding a row here, verified against that provider's own current docs — see spec 32 §4 for the deliberately-out-of-scope list (Cursor, Gemini CLI, Copilot/VS Code, opencode, Amp).

func (Surface) MarkerDir

func (s Surface) MarkerDir() string

MarkerDir is the directory whose presence under a repo root means this surface is in use (".claude", ".codex") — the parent of SkillsHome.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL