sxvault

package
v1.4.2 Latest Latest
Warning

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

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

Documentation

Overview

Package sxvault exposes a small, stable management facade over SX vaults.

Scope: this facade currently covers the publish / manage write path (OpenSkillsNew / OpenGit / OpenPath constructors; EnsureBot, DeleteBot, DeleteAsset, PutAgent, PutSkillZip, InstallAssetToBot mutators) plus read-only browse and download (ListAssets, GetAssetZip). GetAssetZip is the one narrow read path: it wraps the internal GetMetadata / GetAssetByVersion calls and exposes only the asset type, description, and raw zip bytes through AssetZip. The raw GetMetadata / GetAssetByVersion interfaces, along with the broad mutators the internal vault.Vault supports — RemoveAsset, RenameAsset, and asset-uninstall across kinds beyond bot — remain internal and are NOT re-exported yet (UninstallAssetFromBot is the narrow, bot-only public uninstall form), reserved for a follow-up release once consumer needs are clearer. Library consumers needing them today should treat the absence as a "not yet" rather than a "never."

Index

Constants

View Source
const DefaultSkillsNewURL = "https://app.skills.new"

Variables

View Source
var ErrBotNotFound = mgmt.ErrBotNotFound

ErrBotNotFound is reported (via errors.Is) when a method that resolves a bot by name — EnsureBot's update path, PutSkillZip's bot pre-check, UninstallAssetFromBot — is given a bot the vault doesn't have. It re-exports the internal sentinel so library consumers can branch on "bot doesn't exist" without string-matching the error message.

View Source
var ErrBotRuntimeTokensUnsupported = errors.New("sxvault: bot runtime tokens are only supported by skills.new vaults")

ErrBotRuntimeTokensUnsupported is returned by runtime-token methods when the underlying vault does not implement runtime tokens (i.e., any non-skills.new backend). Callers should match with errors.Is to detect this case.

Functions

This section is empty.

Types

type Actor

type Actor struct {
	// Name is the human-readable name used for git commit attribution by
	// OpenGit. The Sleuth backend (OpenSkillsNewWithOptions) ignores it and
	// identifies the actor solely by Email.
	Name string
	// Email identifies the actor for audit/identity context across both
	// backends. The git backend also uses it for commit attribution.
	Email string
}

type AgentResult

type AgentResult struct {
	// AgentName is the canonical agent asset name persisted by the vault.
	// Backends may normalize the requested AgentSpec.AssetName; callers
	// should store this value as their persona asset reference when non-empty.
	AgentName string
	// BotKey is the one-time raw bot API token returned only when PutAgent
	// creates a new bot in a vault type that issues bot tokens. It is empty
	// when the bot already exists and for file-backed Git vaults.
	BotKey string
}

type AgentSpec

type AgentSpec struct {
	BotName   string
	AssetName string
	Version   string
	// Description is the agent asset's description, written into the asset
	// metadata.toml. It is separate from the bot's identity description —
	// publishing multiple agents on the same bot should give each its own
	// Description without rewriting the bot's identity each time.
	Description string
	// BotDescription, when non-empty, becomes the bot's description (on
	// create, or as an update when it differs from the stored value). Leave
	// empty to avoid rewriting an existing bot's description on every
	// publish; pre-create the bot via EnsureBot if you want bot identity
	// fully controlled outside the agent-publish path.
	BotDescription string
	Prompt         string
	// Skills lists existing vault skills to also install on BotName
	// alongside the agent. Each entry must refer to a skill (asset type
	// "skill") already present in the vault — PutAgent verifies this and
	// fails fast on missing names or on a name that resolves to a
	// different asset type. Empty entries are dropped and duplicates are
	// collapsed. Skills are installed on the bot but are NOT persisted
	// into the agent asset's metadata.toml; re-publishing the agent into
	// another vault requires re-supplying Skills.
	//
	// Semantics on re-publish are additive only. Re-publishing the same
	// agent with a shorter Skills list leaves the previously-installed
	// skills attached to BotName — PutAgent never uninstalls. To remove
	// a skill from a bot, call the uninstall path explicitly (out of
	// scope for this facade today).
	//
	// Cost note for git vaults: each skill install is a separate manifest
	// commit + push, so an agent with N skills produces roughly N+2
	// commits per PutAgent call. Keep skill lists modest or expect the
	// publish latency to grow linearly.
	Skills []string
}

type AssetSummary

type AssetSummary struct {
	Name          string
	Type          string
	LatestVersion string
	VersionsCount int
	Description   string
	// CreatedAt and UpdatedAt are the vault-recorded timestamps for the
	// asset's earliest and latest versions. They may be the zero value when
	// the underlying vault doesn't track timestamps for an entry.
	CreatedAt time.Time
	UpdatedAt time.Time
}

type AssetZip added in v1.3.4

type AssetZip struct {
	Name        string
	Version     string
	Type        string
	Description string
	Data        []byte
}

type Bot

type Bot struct {
	Name string
	// Description is the bot's human-readable identity.
	//
	// On UPDATE (bot already exists): EnsureBot rewrites the stored
	// description only when Description is non-empty and differs from the
	// current value. An empty Description preserves whatever is stored
	// — useful for re-running EnsureBot from an agent-publish flow
	// without re-stamping identity.
	//
	// On CREATE (bot doesn't exist yet): EnsureBot writes Description
	// verbatim, so an empty Description produces a bot with no
	// description at all. Pre-seed identity with an explicit
	// EnsureBot(Bot{Name: ..., Description: "..."}) once before relying
	// on the "empty preserves" path.
	Description string
}

type BotRuntimeTokenResult added in v1.3.2

type BotRuntimeTokenResult struct {
	Token     string
	ExpiresAt time.Time
}

type BotRuntimeTokenSpec added in v1.3.2

type BotRuntimeTokenSpec struct {
	BotName string
	// Label is stored with the short-lived runtime token for audit/display.
	// Empty is allowed and lets the backend apply its default label.
	Label string
	// TTLSeconds controls how long the runtime token is valid. Zero means
	// use the backend default. The Skills.new backend currently accepts
	// values from 60 seconds to 24 hours.
	TTLSeconds int
}

type BotSkillSummary added in v1.3.4

type BotSkillSummary struct {
	Name            string
	IsDirectInstall bool
}

type BotSummary added in v1.3.2

type BotSummary struct {
	Name            string
	Slug            string
	Description     string
	Teams           []string
	InstalledSkills []BotSkillSummary
}

type Client

type Client struct {
	// contains filtered or unexported fields
}

func OpenGit

func OpenGit(repoURL string, opts GitOptions) (*Client, error)

func OpenPath

func OpenPath(dir string, opts PathOptions) (*Client, error)

OpenPath opens a file-backed vault rooted at dir. The directory must already exist; the underlying PathVault treats absent directories as a hard error rather than auto-creating. dir may be either a bare directory path (/vault/data) or a file:// URL (file:///vault/data) — the leading scheme is stripped before normalization.

func OpenSkillsNew

func OpenSkillsNew(serverURL, authToken string) (*Client, error)

func OpenSkillsNewWithOptions

func OpenSkillsNewWithOptions(serverURL string, opts SkillsNewOptions) (*Client, error)

func (*Client) AddBotTeam added in v1.3.4

func (c *Client) AddBotTeam(ctx context.Context, botName, teamName string) error

func (*Client) CreateBotRuntimeToken added in v1.3.2

func (c *Client) CreateBotRuntimeToken(ctx context.Context, spec BotRuntimeTokenSpec) (BotRuntimeTokenResult, error)

func (*Client) DeleteAsset added in v1.3.5

func (c *Client) DeleteAsset(ctx context.Context, assetName string) error

DeleteAsset removes all versions of the named asset from the vault.

Git and path vaults remove the asset from sx.toml and delete the asset files from the current vault tip. Skills.new removes the asset and its installations server-side. All install scopes referenced by the asset are removed with it; there is no separate uninstall step. This is the permanent-delete variant of the underlying vault removal API. Git history may still contain older commits.

func (*Client) DeleteBot added in v1.3.3

func (c *Client) DeleteBot(ctx context.Context, botName string) error

DeleteBot removes the named bot from the vault. File-backed vaults also remove any bot-scoped asset installations targeting that bot; asset versions themselves remain in the vault.

func (*Client) EnsureBot

func (c *Client) EnsureBot(ctx context.Context, bot Bot) (string, error)

EnsureBot creates the named bot if missing and updates its description when bot.Description is non-empty and differs from the stored value. An empty bot.Description on an existing bot is a no-op — the stored description is preserved, so repeated EnsureBot calls from agent-publish flows don't rewrite the bot's identity. On the create path (bot does not yet exist) EnsureBot REJECTS an empty bot.Description with an error: creating an identity-less bot is almost never what the caller wants, and the "empty preserves" semantic only makes sense once an identity is already in place.

The returned string is a one-time raw bot API token only when the backend creates a new bot and issues a token. It is empty when the bot already exists and for file-backed Git vaults.

func (*Client) GetAssetZip added in v1.3.4

func (c *Client) GetAssetZip(ctx context.Context, name, version string) (AssetZip, error)

GetAssetZip downloads a single asset version from the vault. It is the only download affordance on the public surface.

When version is empty, the highest-semver version is selected; if no version parses as semver, the last entry in the vault's version list is used as a fallback (see highestSemver). The returned AssetZip.Type is the asset type key (e.g. "skill", "agent"), AssetZip.Description comes from the asset metadata, and AssetZip.Data holds the zip bytes exactly as the vault backend stores them.

func (*Client) InstallAssetToBot

func (c *Client) InstallAssetToBot(ctx context.Context, assetName, botName string) error

func (*Client) ListAssets

func (c *Client) ListAssets(ctx context.Context, typ string) ([]AssetSummary, error)

func (*Client) ListAssetsWithOptions

func (c *Client) ListAssetsWithOptions(ctx context.Context, opts ListOptions) ([]AssetSummary, error)

func (*Client) ListBots added in v1.3.2

func (c *Client) ListBots(ctx context.Context) ([]BotSummary, error)

func (*Client) ListTeams added in v1.3.4

func (c *Client) ListTeams(ctx context.Context) ([]TeamSummary, error)

func (*Client) PutAgent

func (c *Client) PutAgent(ctx context.Context, spec AgentSpec) (AgentResult, error)

PutAgent uploads an agent asset, installs that agent asset on the named bot, and installs any listed skills on the same bot.

Re-publishing an existing AssetName@Version is idempotent for the manifest: the version is listed once and installations are re-run, which also makes this the recovery path for a publish that failed midway. The stored zip bytes themselves follow the vault backend — Sleuth vaults preserve the original (any new Prompt / Description in spec is silently discarded); Git vaults overwrite the stored bytes. Bump the version when you need a guaranteed update across all backends.

PutAgent is NOT transactional. The flow runs as: EnsureBot → validate skills → upload asset → install agent on bot → install each skill on bot. If any step after the asset upload fails (e.g. a transient git push race on the Nth skill), partial install state is left in the vault. Every step is idempotent, so the caller should retry the same PutAgent call to converge — the asset upload no-ops on version match and the install path is an upsert.

The returned AgentResult.AgentName is the canonical persisted agent asset slug. Callers should keep only that light reference locally for later runtime lookup instead of storing the full agent prompt.

func (*Client) PutSkillZip

func (c *Client) PutSkillZip(ctx context.Context, spec SkillZipSpec) error

PutSkillZip uploads a skill zip and, when spec.BotName is non-empty, installs the skill on that bot.

Re-publishing an existing Name@Version is idempotent for the manifest: the version is listed once and installations are re-run, which also makes this the recovery path for a publish that failed midway. The stored zip bytes themselves follow the vault backend — Sleuth vaults preserve the original (new ZipData on a re-publish is silently discarded); Git vaults overwrite the stored bytes. Bump the version when you need a guaranteed update across all backends.

func (*Client) PutSkillZipWithResult added in v1.3.5

func (c *Client) PutSkillZipWithResult(ctx context.Context, spec SkillZipSpec) (SkillZipResult, error)

PutSkillZipWithResult uploads a skill zip and returns the persisted skill identity from the backing vault. For Skills.new this is the server-returned slug, which may differ from spec.Name when the uploaded display name collides with an existing asset slug.

func (*Client) RemoveBotTeam added in v1.3.4

func (c *Client) RemoveBotTeam(ctx context.Context, botName, teamName string) error

func (*Client) RevokeBotRuntimeTokens added in v1.3.2

func (c *Client) RevokeBotRuntimeTokens(ctx context.Context, botName string) (int, error)

func (*Client) UninstallAssetFromBot added in v1.3.4

func (c *Client) UninstallAssetFromBot(ctx context.Context, assetName, botName string) error

type GitOptions

type GitOptions struct {
	// AuthToken authenticates HTTP(S) git remotes through basic auth. SSH
	// remotes ignore this value and use the caller's SSH configuration.
	// SSHKeyPath takes precedence: when both are set with an HTTP(S) URL,
	// the underlying git client rewrites the URL to SSH and AuthToken is
	// not used.
	AuthToken string

	// AuthUsername is the HTTP(S) basic-auth username to pair with AuthToken.
	// Empty uses a host-specific default, currently "x-access-token" except
	// gitlab.com / *.gitlab.com, which use "oauth2". Self-hosted GitLab
	// instances on custom domains are NOT auto-detected — set this to
	// "oauth2" explicitly when targeting one, or git authentication will
	// fail with the default "x-access-token".
	AuthUsername string

	// SSHKeyPath, when non-empty, points the underlying git client at this
	// SSH private key for SSH remotes. It bypasses the process-global SSH
	// key path set by the CLI's --ssh-key flag / SX_SSH_KEY env var, letting
	// library consumers scope SSH auth to a single Client.
	//
	// When set with an HTTP(S) URL, the git client rewrites the URL to SSH
	// at clone time and SSH key auth is what's used end-to-end —
	// AuthToken is ignored on that combination. buildGitClientOptions
	// drops the basic-auth env in this case so the resulting client carries
	// no inert/conflicting credentials.
	SSHKeyPath string

	Actor Actor
}

type ListOptions

type ListOptions struct {
	// Type filters to a single asset-type key (e.g. "skill", "agent",
	// "mcp"). Empty returns every type.
	Type string
	// Search filters returned assets by a free-text query. Semantics
	// differ by backend: Git and Path vaults do a case-insensitive
	// substring match against the asset's name OR description; Sleuth
	// vaults pass the query to the backend's GraphQL search, which may
	// rank or fuzzy-match. Don't depend on exact ordering or scoring
	// across backends.
	Search string
	// Limit caps the number of returned assets. Zero or negative means
	// "backend default" — for Git and Path that is uncapped; for Sleuth
	// the backend silently caps at 50 regardless of the value passed,
	// so callers that need to enumerate every asset in a large Sleuth
	// vault need a different strategy (per-asset lookups) than this
	// list call provides today.
	Limit int
}

type PathOptions

type PathOptions struct {
	// Actor identifies the caller for audit/identity context propagated
	// via mgmt.ContextWithIdentity. PathVault doesn't consult identity
	// directly today, but downstream audit / logging hooks read it
	// through actorContext on every method call.
	Actor Actor
}

PathOptions configures OpenPath. Path vaults have no auth surface — local filesystem access is the trust boundary — so Actor is the only knob, kept on a struct for future extension symmetric with GitOptions.

type SkillZipResult added in v1.3.5

type SkillZipResult struct {
	Name           string
	Version        string
	IsFirstVersion bool
}

SkillZipResult contains the persisted skill identity after PutSkillZip. Server-backed vaults may normalize spec.Name into a slug; use Name for follow-up install/uninstall calls against the same vault. Today only the Sleuth vault normalizes the name — for git/path vaults Name is spec.Name unchanged. IsFirstVersion is true when the upload created the first stored version of this skill (Sleuth-only; git/path vaults always report false).

type SkillZipSpec

type SkillZipSpec struct {
	Name    string
	Version string
	// Description overrides metadata.toml's skill description when non-empty.
	// Empty preserves any description already embedded in the uploaded zip.
	Description string
	ZipData     []byte
	// BotName, when non-empty, installs the published skill onto that bot
	// after the asset upload completes. For a new Skills.new asset, this
	// makes the first upload bot-scoped instead of inheriting the upload
	// endpoint's org-wide default. Leave empty to publish the skill without
	// attaching it to any bot.
	BotName string
}

type SkillsNewOptions

type SkillsNewOptions struct {
	// AuthToken is the bearer token sent on every Sleuth API request.
	// Required — OpenSkillsNewWithOptions returns an error when empty.
	// There is no host-specific default (unlike GitOptions.AuthUsername),
	// because Sleuth endpoints accept exactly one credential shape.
	AuthToken string
	// Actor identifies the caller for audit/identity context propagated
	// via mgmt.ContextWithIdentity. Only Actor.Email is consumed on the
	// Sleuth path — Actor.Name is ignored here (see Actor.Name doc).
	Actor Actor
}

SkillsNewOptions configures OpenSkillsNewWithOptions. Sleuth-backed vaults do not use the SSH key / basic-auth knobs that GitOptions carries, so this type intentionally exposes a narrower surface.

type TeamSummary added in v1.3.4

type TeamSummary struct {
	Name         string
	Description  string
	MemberCount  int
	Repositories []string
}

Jump to

Keyboard shortcuts

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