manifestv2

package
v1.4.13 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package manifestv2 owns the plugin manifest v2 contract (contract:plugin.manifest).

Purpose: one machine-checkable definition of plugin.json. The Go types here generate schemas/plugin-manifest.v2.schema.json (tools/schemagen), Load is the single reader (v2 natively, v1 through one normalizer), and Projection is the single derivation of the compatibility keys that released 1.4.x CLIs decode.

Inputs: plugin.json bytes or a path. Outputs: a validated *Manifest or a coded error (E106, E111-E114). Constraints: layer L0 (Constitution 2.1): the standard library, internal/errs and internal/compat only; it never imports internal/plugin or cmd/. Released CLIs decode plugin.json permissively, so a v2 key never reuses a v1 key with another JSON type (Epic D1, ADR 0009).

Index

Constants

View Source
const (
	LicenseFree     = "free"
	LicenseLicensed = "licensed"
)

Licence values (D2: bundle membership is not a manifest field).

View Source
const (
	MaturityImplemented  = "implemented"
	MaturityExperimental = "experimental"
	MaturityScaffolded   = "scaffolded"
	MaturityPlanned      = "planned"
	MaturityDeferred     = "deferred"
)

Maturity values (the lifecycle enum; the v1 `status` key is a compatibility key).

View Source
const (
	StateDeprecated = "deprecated"
	StateEOL        = "eol"
)

Deprecation states (deprecation.state, required when maturity is deferred).

View Source
const (
	KindCompose = "compose"
	KindCLI     = "cli"
	KindLibrary = "library"
)

Service kinds.

View Source
const (
	SideRead        = "read"
	SideWrite       = "write"
	SideRemote      = "remote"
	SideDestructive = "destructive"
	OutDocument     = "document"
	OutStream       = "stream"
	OutInteractive  = "interactive"
	JSONNone        = "none"
	JSONLegacy      = "legacy"
	SurfaceAll      = "all"
	SurfaceCLIOnly  = "cli-only"
)

Command attribute values (CANON D5-D7 vocabulary).

View Source
const (
	NamePattern    = `^[a-z][a-z0-9-]*$`
	BinaryPattern  = `^nself-[a-z][a-z0-9-]*$`
	VersionPattern = `^v?[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?(\+[a-zA-Z0-9.]+)?$`
)

Patterns, shared by validation and the generated schema.

View Source
const ManifestVersion = 2

ManifestVersion is the value of manifest_version in a v2 file.

Variables

View Source
var (
	Licenses     = []string{LicenseFree, LicenseLicensed}
	Maturities   = []string{MaturityImplemented, MaturityExperimental, MaturityScaffolded, MaturityPlanned, MaturityDeferred}
	States       = []string{StateDeprecated, StateEOL}
	ServiceKinds = []string{KindCompose, KindCLI, KindLibrary}
	SideEffects  = []string{SideRead, SideWrite, SideRemote, SideDestructive}
	Outputs      = []string{OutDocument, OutStream, OutInteractive}
	JSONModes    = []string{JSONNone, JSONLegacy}
	Surfaces     = []string{SurfaceAll, SurfaceCLIOnly}
	Languages    = []string{"go", "rust", "typescript", "python", "bash"}
)

Enum lists, shared by validation and the generated schema.

View Source
var CoreVerbs = []string{"init", "start", "stop", "restart", "status", "logs", "doctor", "build", "reset",
	"clean", "add", "remove", "config", "db", "backup", "deploy", "update", "license", "mcp", "exec"}

CoreVerbs are the ADR 0016 core command verbs a plugin may not claim (E113). TestCoreVerbsMatchCanon keeps this list equal to internal/canon.Verbs.

View Source
var ForbiddenKeys = []string{"author_public_key", "bundles", "checksum", "signature", "tier_pair"}

ForbiddenKeys are rejected (E111) in a v2 file: they belong to the registry, the release pipeline or ADR 0008 (bundle membership), never to a manifest.

Functions

func ApplyCompat

func ApplyCompat(data []byte) ([]byte, error)

ApplyCompat returns the canonical bytes of a v2 file with only its compatibility keys rewritten to Projection (E112 is what a stale file fails). Every other key keeps its value.

func ApplyProjection

func ApplyProjection(m *Manifest)

ApplyProjection writes Projection(m) into m's compatibility keys.

func Canonical

func Canonical(data []byte) ([]byte, error)

Canonical re-encodes any JSON document with sorted keys, 2-space indent and a trailing newline. Numbers keep their literal text.

func Canonicalize

func Canonicalize(m *Manifest)

Canonicalize makes absent and empty the same value (nil), so a v1 file and its v2 twin decode to equal Manifests. confirm.flags keeps its empty list.

func CheckCompat

func CheckCompat(m *Manifest) error

CheckCompat proves the compatibility keys of m equal Projection(m) (E112). Only the derived keys are compared: the carried ones have no v2 source.

func IsMappedV1Key

func IsMappedV1Key(k string) bool

IsMappedV1Key reports whether the normalizer carries or converts the v1 key k in at least one shape (the migrate tool refuses a drop list that names one).

func IsV1Version

func IsV1Version(v json.RawMessage) bool

IsV1Version reports whether a raw manifest_version value marks a v1 file. Released CLIs ignore the key, so every spelling of "one or nothing" loads as v1: null, 0, "1", 1 and 1.0 (an absent key is v1 too).

func Marshal

func Marshal(m *Manifest) ([]byte, error)

Marshal renders m as the canonical plugin.json: keys sorted at every level, 2-space indent, trailing newline, HTML never escaped.

func PostgresExtensions

func PostgresExtensions(m *Manifest) []string

PostgresExtensions returns requires.postgres_extensions, empty when absent (the install check of P7-ADOPT-06 reads it).

func RegistryKeys

func RegistryKeys(data []byte) []string

RegistryKeys lists the registry-owned keys (E111 in v2) a v1 file carries; converting removes them on purpose and the migrate tool says so.

func Validate

func Validate(m *Manifest) error

Validate checks the structural rules of a v2 manifest: required keys, slug and semver shape, enums, service rules, np_ tables, boot migrations, deprecation state and the commands block. Failures are E106 naming the field, except a core-verb command, which is E113. It does not check compatibility keys (CheckCompat, E112) or the runtime permission allowlist.

Types

type Arg

type Arg struct {
	Name     string `json:"name"`
	Required bool   `json:"required,omitempty"`
	Variadic bool   `json:"variadic,omitempty"`
	Secret   bool   `json:"secret,omitempty"`
}

Arg is a positional argument (registry Arg shape plus secret).

type CLICommand

type CLICommand struct {
	Name        string `json:"name"`
	Description string `json:"description"`
}

CLICommand is one v1 cliCommands entry.

type CLITarget

type CLITarget struct {
	Binary  string
	Command string
}

CLITarget is one command binary a CLI plugin publishes: the binary file name the command proxy execs and the command that names it.

func CLITargets

func CLITargets(name, pluginType, binaryName string, commands []string) []CLITarget

CLITargets returns every command binary a plugin installs, by the installer's rule (P7-PLUG-55). It is the one definition: internal/plugin cliBinaryNames calls it, and manifestv2migrate -targets prints it, so the release pipeline builds exactly what the installer will look for.

Inputs are the v1 view of a manifest (a v2 manifest through Projection): pluginType, binaryName and the cliCommands names. A plugin whose pluginType is set and is not "cli" has none. Each cliCommands entry with a name publishes nself-<name>. With no usable entry, an explicit binaryName is the single binary, and pluginType "cli" without one falls back to nself-<name>. The command of a single binary is its name without the nself- prefix.

func CLITargetsOf

func CLITargetsOf(m *Manifest) []CLITarget

CLITargetsOf is CLITargets over a parsed manifest through its compatibility projection, which is what a released CLI reads from a v2 plugin.json.

type Commands

type Commands struct {
	Command     string       `json:"command"`
	Binary      string       `json:"binary"`
	Summary     string       `json:"summary,omitempty"`
	SideEffect  string       `json:"side_effect,omitempty"`
	Output      string       `json:"output,omitempty"`
	JSON        string       `json:"json,omitempty"`
	Confirm     *Confirm     `json:"confirm,omitempty"`
	Surface     string       `json:"surface,omitempty"`
	Subcommands []Subcommand `json:"subcommands,omitempty"`
}

Commands is the CLI surface block (v1 `cli` is a different key and type). The optional root summary, side_effect, output and json decode and round-trip; absent they mean side_effect destructive and json none (CANON mount contract).

type Compat

type Compat struct {
	PluginType      string       `json:"pluginType,omitempty"`
	BinaryName      string       `json:"binaryName,omitempty"`
	CLICommands     []CLICommand `json:"cliCommands,omitempty"`
	EntryPoint      string       `json:"entryPoint,omitempty"`
	Runtime         string       `json:"runtime,omitempty"`
	CLI             string       `json:"cli,omitempty"`
	MinNselfVersion string       `json:"minNselfVersion,omitempty"`
	Status          string       `json:"status,omitempty"`
	IsCommercial    bool         `json:"isCommercial,omitempty"`
	LicenseType     string       `json:"licenseType,omitempty"`
	RequiresLicense bool         `json:"requires_license,omitempty"`
	Tier            string       `json:"tier,omitempty"`
}

Compat holds the generated compatibility keys (Epic D1). They exist so released 1.4.x CLIs keep decoding a v2 file; authors never write them. Projection derives them; CheckCompat (E112) proves they match. They are removed at v1.6.0.

EntryPoint, Runtime, CLI and the cliCommands entries other than the canonical command are carried verbatim from v1: no v2 field defines them. Tier and LicenseType are carried for a licensed plugin (max, cloud, internal) and generated as free for a free one.

func Projection

func Projection(m *Manifest) Compat

Projection derives the compatibility keys of m (Epic D1). Derived keys are recomputed from the v2 fields: pluginType and binaryName from commands, minNselfVersion from requires.nself, status from maturity and deprecation.state, isCommercial, licenseType, requires_license and tier from license, and the description of the canonical command's cliCommands entry from commands.summary. EntryPoint, Runtime, CLI and the other cliCommands entries are carried from m unchanged, and so are a licensed plugin's tier and licenseType (pro when it has none).

type CompatBlock

type CompatBlock struct {
	Nself    string            `json:"nself,omitempty"`
	Requires map[string]string `json:"requires,omitempty"`
}

CompatBlock is the v1 `compat` key: CLI and service version ranges.

type Confirm

type Confirm struct {
	Flags []string `json:"flags"`
	Plan  *Plan    `json:"plan,omitempty"`
}

Confirm names the bool flags that confirm a destructive action. An empty Flags list is valid: a nonce-only round trip (Epic D16).

type Deprecation

type Deprecation struct {
	AnnouncedDate   string `json:"announcedDate,omitempty"`
	EOLDate         string `json:"eolDate,omitempty"`
	ReplacedBy      string `json:"replacedBy,omitempty"`
	MigrationGuide  string `json:"migrationGuide,omitempty"`
	MigrationScript string `json:"migrationScript,omitempty"`
	// State is deprecated or eol; released CLIs ignore it.
	State string `json:"state,omitempty"`
}

Deprecation is the v1 deprecation block plus the v2 state.

type Env

type Env struct {
	Required []string `json:"required,omitempty"`
	Optional []string `json:"optional,omitempty"`
}

Env lists environment variable names.

type EnvVar

type EnvVar struct {
	Name        string `json:"name"`
	Required    bool   `json:"required"`
	Description string `json:"description"`
	Default     string `json:"default,omitempty"`
}

EnvVar describes an environment variable (v1 shape).

type Flag

type Flag struct {
	Name       string `json:"name"`
	Shorthand  string `json:"shorthand,omitempty"`
	Type       string `json:"type"`
	Default    string `json:"default,omitempty"`
	Usage      string `json:"usage,omitempty"`
	Hidden     bool   `json:"hidden,omitempty"`
	Required   bool   `json:"required,omitempty"`
	Persistent bool   `json:"persistent,omitempty"`
	Env        string `json:"env,omitempty"`
	SideEffect string `json:"side_effect,omitempty"`
	JSON       string `json:"json,omitempty"`
	Output     string `json:"output,omitempty"`
	Secret     bool   `json:"secret,omitempty"`
	CLIOnly    bool   `json:"cli_only,omitempty"`
}

Flag is a flag (registry Flag shape plus secret and cli_only).

type GraphQLBlock

type GraphQLBlock struct {
	Enabled      bool               `json:"enabled"`
	SubgraphName string             `json:"subgraph_name"`
	SubgraphURL  string             `json:"subgraph_url"`
	SchemaPath   string             `json:"schema_path,omitempty"`
	Entities     []GraphQLEntityKey `json:"entities,omitempty"`
}

GraphQLBlock registers the plugin as a federation subgraph (v1 shape).

type GraphQLEntityKey

type GraphQLEntityKey struct {
	Type string `json:"type"`
	Key  string `json:"key"`
}

GraphQLEntityKey names an Apollo Federation entity type.

type Manifest

type Manifest struct {
	ManifestVersion int    `json:"manifest_version"`
	Name            string `json:"name"`
	Version         string `json:"version"`
	Description     string `json:"description"`
	Category        string `json:"category"`
	// License is free or licensed (a v1 plugin.json carried an SPDX-style string
	// here; released CLIs only require it to be non-empty).
	License string `json:"license"`
	// LicenseSPDX is the licence text a v1 file carried in `license` (an SPDX
	// identifier or "Source-Available"). Optional; `plugin info` shows it.
	LicenseSPDX string `json:"license_spdx,omitempty"`
	Maturity    string `json:"maturity"`
	// Installable defaults to true when absent (ADR 0009).
	Installable *bool     `json:"installable,omitempty"`
	Requires    *Requires `json:"requires,omitempty"`
	Service     *Service  `json:"service"`
	// Commands is nil for a plugin that adds no CLI command.
	Commands   *Commands   `json:"commands,omitempty"`
	Schema     *string     `json:"schema,omitempty"`
	Migrations *Migrations `json:"migrations,omitempty"`
	Seed       *Seed       `json:"seed,omitempty"`
	Env        *Env        `json:"env,omitempty"`
	Routes     []Route     `json:"routes,omitempty"`
	// Capabilities lists what the plugin offers (a v1 key some plugins carry,
	// read from the installed plugin.json by the MCP plugin). Optional, same
	// name and type as v1.
	Capabilities []string `json:"capabilities,omitempty"`
	DocsURL      string   `json:"docs_url,omitempty"`

	Shared
	Compat
}

Manifest is a manifest_version 2 plugin.json: the canonical v2 keys, the shared v1 keys (same name and JSON type as v1) and the generated compatibility keys.

func DecodeV2

func DecodeV2(data []byte) (*Manifest, error)

DecodeV2 decodes and validates a v2 file without the compatibility check.

func Load

func Load(path string) (*Manifest, error)

Load reads a plugin.json and returns the validated v2 Manifest. A v2 file is decoded strictly and checked (Validate, CheckCompat); a v1 file (no manifest_version, or 1) is converted by the one normalizer (Normalize). Under compat.V15() a v1 file also prints the once-per-process deprecation notice.

func Normalize

func Normalize(data []byte) (*Manifest, error)

Normalize converts v1 plugin.json bytes into a validated v2 Manifest. It is the one v1 reader: the shape rules of released CLIs (grouped dependencies, object-form webhooks and envVars, object-form apiEndpoints), the status and licence tables of Epic D1, the commands mapping (binaryName becomes commands.binary, the cliCommands entry named like it becomes commands.command, `binaryName: null` becomes `commands: null`) and the service block. It checks what v1.4.12's validateManifest checks and no more (validateV1), so a file the released CLI accepts always normalizes; Validate is for v2-native input. Keys no v1.4.12 reader decodes are not mapped: UnmappedV1Keys lists them and the migrate tool refuses to write a file that has any.

func Parse

func Parse(data []byte) (*Manifest, error)

Parse is Load for bytes already read.

func ParseQuiet

func ParseQuiet(data []byte) (*Manifest, error)

ParseQuiet is Parse without the v1 deprecation notice, for tools that convert v1 files on purpose.

type Migrations

type Migrations struct {
	Dir   string `json:"dir"`
	Apply string `json:"apply"`
}

Migrations declares boot-applied SQL (ADR 0010).

type MultiApp

type MultiApp struct {
	Supported       bool   `json:"supported"`
	IsolationColumn string `json:"isolationColumn,omitempty"`
	PKStrategy      string `json:"pkStrategy,omitempty"`
	DefaultValue    string `json:"defaultValue,omitempty"`
}

MultiApp describes multi-tenancy (v1 shape).

type Plan

type Plan struct {
	Flag   string `json:"flag"`
	IDFlag string `json:"id_flag"`
}

Plan names the flags of a plan/apply pair of one command.

type Requires

type Requires struct {
	// Nself is a semver range for the CLI, e.g. ">=1.5.0".
	Nself string `json:"nself,omitempty"`
	// Plugins are plugin slugs.
	Plugins []string `json:"plugins,omitempty"`
	// PostgresExtensions are extension names checked at install (ADOPT).
	PostgresExtensions []string `json:"postgres_extensions,omitempty"`
}

Requires lists what must exist before the plugin can run.

type RestRoute

type RestRoute struct {
	Method  string `json:"method"`
	Path    string `json:"path"`
	Summary string `json:"summary,omitempty"`
	Auth    string `json:"auth,omitempty"`
	HMAC    string `json:"hmac,omitempty"`
}

RestRoute is one entry of the v1 rest_routes key (read by apidocs). Auth and HMAC are optional additions that carry the v1 routes entries' auth scheme and the name of the env var holding the webhook secret; released readers ignore them.

type Route

type Route struct {
	Path         string `json:"path"`
	UpstreamPort int    `json:"upstream_port"`
}

Route exposes a plugin port through nginx.

type Seed

type Seed struct {
	Command []string `json:"command"`
}

Seed is an idempotent argv run inside the plugin's service.

type Service

type Service struct {
	Kind        string  `json:"kind"`
	Compose     *string `json:"compose,omitempty"`
	Image       *string `json:"image,omitempty"`
	Port        *int    `json:"port,omitempty"`
	Healthcheck *string `json:"healthcheck,omitempty"`
}

Service describes how the plugin runs.

type Shared

type Shared struct {
	Author     string   `json:"author,omitempty"`
	Homepage   string   `json:"homepage,omitempty"`
	Repository string   `json:"repository,omitempty"`
	Tags       []string `json:"tags,omitempty"`

	Language       string   `json:"language,omitempty"`
	Port           int      `json:"port,omitempty"`
	HealthEndpoint string   `json:"health_endpoint,omitempty"`
	PackageManager string   `json:"packageManager,omitempty"`
	Framework      string   `json:"framework,omitempty"`
	MinNodeVersion string   `json:"minNodeVersion,omitempty"`
	ArchSupport    []string `json:"arch_support,omitempty"`

	Tables []string `json:"tables,omitempty"`
	Views  []string `json:"views,omitempty"`

	APIEndpoints []string    `json:"apiEndpoints,omitempty"`
	Webhooks     []string    `json:"webhooks,omitempty"`
	RestRoutes   []RestRoute `json:"rest_routes,omitempty"`
	EnvVars      []EnvVar    `json:"envVars,omitempty"`

	Dependencies         []string            `json:"dependencies,omitempty"`
	OptionalDependencies []string            `json:"optionalDependencies,omitempty"`
	SystemDependencies   *SystemDependencies `json:"systemDependencies,omitempty"`
	Consumes             []string            `json:"consumes,omitempty"`
	Provides             []string            `json:"provides,omitempty"`

	MultiApp *MultiApp `json:"multiApp,omitempty"`
	// Permissions keeps its v1 shape: an array of canonical permission strings
	// or an object grouping actions by category. Validation checks the shape;
	// the fail-closed allowlist stays with the runtime (internal/plugin).
	Permissions any `json:"permissions,omitempty"`

	CompatBlock *CompatBlock  `json:"compat,omitempty"`
	Deprecation *Deprecation  `json:"deprecation,omitempty"`
	GraphQL     *GraphQLBlock `json:"graphql,omitempty"`

	RequiredEntitlements []string          `json:"requiredEntitlements,omitempty"`
	MaxNselfVersion      string            `json:"maxNselfVersion,omitempty"`
	Visibility           string            `json:"visibility,omitempty"`
	UpdatedAt            string            `json:"updated_at,omitempty"`
	PlatformChecksums    map[string]string `json:"platform_checksums,omitempty"`
}

Shared holds the v1 keys that v2 keeps with the same name and JSON type. The authoritative list is tools/manifestv2migrate/testdata/v1412-readers.txt (the keys every v1.4.12 reader decodes); TestReaderScan keeps it covered. Polymorphic v1 shapes (grouped dependencies, object-form webhooks and so on) are authored in their one canonical shape here; the v1 normalizer converts.

type Subcommand

type Subcommand struct {
	// Name is one or more space-separated segments.
	Name       string   `json:"name"`
	Summary    string   `json:"summary,omitempty"`
	SideEffect string   `json:"side_effect,omitempty"`
	Output     string   `json:"output,omitempty"`
	JSON       string   `json:"json,omitempty"`
	Args       []Arg    `json:"args,omitempty"`
	Flags      []Flag   `json:"flags,omitempty"`
	Confirm    *Confirm `json:"confirm,omitempty"`
	Surface    string   `json:"surface,omitempty"`
}

Subcommand is one nested command path below the root.

type SystemDependencies

type SystemDependencies struct {
	Required    []SystemDependency `json:"required,omitempty"`
	Recommended []SystemDependency `json:"recommended,omitempty"`
}

SystemDependencies groups required and recommended host dependencies.

type SystemDependency

type SystemDependency struct {
	Name          string `json:"name"`
	Verify        string `json:"verify"`
	MinVersion    string `json:"minVersion,omitempty"`
	Apt           string `json:"apt,omitempty"`
	Brew          string `json:"brew,omitempty"`
	CustomInstall string `json:"custom_install,omitempty"`
}

SystemDependency is a host-level dependency (v1 shape).

type Unmapped

type Unmapped struct {
	Key  string // top-level key as written
	Path string // JSON path of its value, e.g. $.config
	Kind string // object, array, string, number or bool
	Size int    // entries of an object or array, else 0
}

Unmapped is one v1 key the normalizer has no v2 home for.

func UnmappedV1Keys

func UnmappedV1Keys(data []byte) ([]Unmapped, error)

UnmappedV1Keys lists the non-empty top-level keys of a v1 plugin.json that the normalizer does not carry into v2 (config, hooks, actions, notes, api_version, entry and so on, plus a routes, capabilities, env or env_vars value whose shape does not convert losslessly), sorted by key. Registry-owned keys (ForbiddenKeys) are not listed: ADR 0008 and the release pipeline own them, see RegistryKeys. A null, empty string, empty list or empty object has nothing to lose and is skipped.

func (Unmapped) String

func (u Unmapped) String() string

String renders "$.config (object, 3 entries)".

Jump to

Keyboard shortcuts

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