sxvault

package
v1.3.2 Latest Latest
Warning

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

Go to latest
Published: May 27, 2026 License: Apache-2.0 Imports: 14 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, PutAgent, PutSkillZip, InstallAssetToBot mutators; ListAssets read-only browse). Read-side primitives that the internal vault.Vault interface supports — GetMetadata, GetAssetByVersion, RemoveAsset, RenameAsset, asset-uninstall — are intentionally NOT re-exported yet and are 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 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 {
	// 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 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 BotSummary added in v1.3.2

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

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) CreateBotRuntimeToken added in v1.3.2

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

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) 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) PutAgent

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

PutAgent uploads an agent asset and installs it (plus any listed skills) on the named 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.

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) RevokeBotRuntimeTokens added in v1.3.2

func (c *Client) RevokeBotRuntimeTokens(ctx context.Context, botName string) (int, 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 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. 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.

Jump to

Keyboard shortcuts

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