tapper

package
v0.40.0 Latest Latest
Warning

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

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

Documentation

Overview

Package tapper — shared OAuth2 hub helpers.

This file holds the hub-auth building blocks that are independent of any single grant type: RFC 8414 authorization-server metadata discovery, hub URL normalization/canonicalization, and opening the user's browser. The device authorization grant (auth_device_flow.go) composes these; there is no longer a loopback/PKCE flow — `tap auth login` standardizes on the device flow for browser-based login.

The metadata + browser helpers take their external dependencies (HTTP client, runtime) as arguments so the flow stays trivially testable against an httptest.Server mock hub.

Package tapper — OAuth2 refresh-token renewal for cached hub credentials.

The device-login flow now persists a refresh token (plus the client_id and token endpoint it must be presented to) alongside the short-lived access token. RefreshHubToken exchanges that refresh token for a fresh access token so a command whose cached token has expired renews silently instead of forcing the user back through `tap auth login`.

Package tapper — hub authentication store.

AuthStore is the on-disk credentials cache used by the hub-auth flow. It maps a canonical hub URL to an access token and token metadata. The store is intentionally minimal — it does not know how to refresh tokens, talk to a hub, or check expiry. Those concerns live in the caller so the store can stay time-agnostic (no clock dependency) and therefore trivially testable under a frozen clock.

File layout: YAML at <StateRoot>/auth.yaml, mode 0600, parent dir 0700 when we create it. Writes go through rt.AtomicWriteFile so a crash or concurrent reader never sees a half-written credential file.

Package tapper — hub token validation via the whoami probe.

ValidateToken confirms a bearer token resolves to a user on the hub. It backs the "paste an authentication token" login path: the token the user pastes (an API token minted on the hub's account page) is checked against GET /api/v1/whoami before it is written to the AuthStore, so a typo or a revoked token fails fast at login rather than on the first real request.

Package tapper — hub keg-administration client calls (grants + visibility).

These talk to a remote hub's per-keg admin endpoints under /api/v1/@{namespace}/kegs/{keg}: listing/creating/revoking grants and updating visibility. Like ValidateToken (auth_whoami.go) and CreateKeg (hub_kegs.go) they are slim, dependency-free functions over http.DefaultClient so tests can point hubURL at an httptest.Server.

Package tapper — hub keg-catalog client calls.

These talk to a remote hub's namespace/keg-catalog endpoints (as opposed to the per-keg operation API in pkg/keg/keg_remote.go): creating a keg and listing the kegs a user can reach. They mirror the slim, dependency-free shape of ValidateToken (auth_whoami.go) — a stand-alone function over http.DefaultClient so tests can point hubURL at an httptest.Server.

Package tapper — hub namespace-administration client calls.

These talk to a remote hub's namespace endpoints under /api/v1/namespaces and /api/v1/@{namespace}/members: listing namespaces and managing membership roles. Slim, dependency-free functions over http.DefaultClient (via doHubJSON) so tests can point hubURL at an httptest.Server.

Index

Constants

View Source
const (
	TapConfigSchemaURL = schemas.TapConfigURL

	// DefaultHubName is the compiled-in name of the default remote hub.
	DefaultHubName = "atlas"

	// DefaultHubURL is the compiled-in fallback hub used by ResolveLoginHubURL
	// and Config.Hub when no explicit hub, defaultHub, fallbackHub, or single
	// configured hub is available and the implicit default has not been
	// disabled. The constant exists so the fallback target is auditable: a
	// deployment that needs to prove no implicit network calls happen sets
	// disableAtlasHub: true (or TAP_DISABLE_ATLAS_HUB=1) and the chain
	// errors out instead of falling through here.
	DefaultHubURL = "https://atlas.foldwise.ai"

	// DefaultHubTokenEnv is the environment variable the default remote hub
	// reads its bearer token from when no explicit credential is configured.
	DefaultHubTokenEnv = "ATLAS_API_KEY"
)
View Source
const (
	// HubKindRemote is a read-write HTTP hub (the default, e.g. atlas).
	HubKindRemote = "remote"
	// HubKindReadonly is a read-only HTTP hub. TODO: enforce read-only writes
	// in the API repository; today the kind only sets Target.Readonly.
	HubKindReadonly = "readonly"
)

Hub kinds describe how a hub's (namespace, name) pairs are backed.

View Source
const (
	// DefaultAppName is the base directory name used for Tapper user
	// configuration. Helpers use this value to build platform specific config
	// paths, for example:
	//   $XDG_CONFIG_HOME/tapper   (or ~/.config/tapper) on Unix-like systems
	//   %APPDATA%\tapper          on Windows
	// Example config file:
	//   $XDG_CONFIG_HOME/tapper/aliases.yaml
	DefaultAppName = "tapper"

	// DefaultLocalConfigDir is the directory name used for repository or
	// project local configuration.
	DefaultLocalConfigDir = ".tapper"
)

Config version strings identify KEG settings schema versions. Each constant is a stable identifier for a particular config schema. When a new schema is introduced add a new constant and update the Config alias to point to the latest version. These values are used by parsing and migration code (for example ParseConfigData) to detect older formats and perform upgrades. Use a YYYY-MM format for easy sorting and human readability.

View Source
const (
	FlightRoleViewer FlightRole = "viewer"
	FlightRoleEditor FlightRole = "editor"
	FlightRoleAdmin  FlightRole = "admin"

	FlightVisibilityPrivate = "private"
	FlightVisibilityPublic  = "public"

	FlightCapabilityManageFlights FlightCapability = "manage_flights"
	FlightCapabilityManageKegs    FlightCapability = "manage_kegs"
	FlightCapabilityFullAccess    FlightCapability = "full_access"

	// MaxFlightSubflights bounds the ordered direct allowlist on one manifest.
	MaxFlightSubflights = 64
	// MaxFlightGraphDescendants bounds unique reachable flights, excluding the
	// pinned root. Shared descendants count once. This is the only bound on
	// traversal: it is enforced inline during the breadth-first walk and is
	// dedup-based, so it holds regardless of the graph's shape.
	MaxFlightGraphDescendants = 256
)
View Source
const (
	// BootstrapKindCloud targets the compiled-in atlas remote hub.
	BootstrapKindCloud = "cloud"
	// BootstrapKindEnterprise registers a user-supplied remote HTTP endpoint.
	BootstrapKindEnterprise = "enterprise"
)

Bootstrap deployment kinds. Each maps onto an existing hub kind/shape — there is no new config field, only a guided way to pick one.

View Source
const (
	ProviderAnthropic = "anthropic"
	ProviderOpenAI    = "openai"
	ProviderOllama    = "ollama"
)

Providers understood by the launcher, parsed from an agent model's prefix.

View Source
const (
	// AuthInherit passes the ambient environment through untouched. It is the
	// default because it matches running the harness bare in your shell.
	AuthInherit = "inherit"
	// AuthSubscription strips inherited provider key variables so the harness
	// falls back to its own stored login. Absence of a key cannot express this
	// on its own, because absence means inherit.
	AuthSubscription = "subscription"
	// AuthAPIKey forwards the variable named by an agent's apiKeyEnv.
	AuthAPIKey = "apiKey"
	// AuthNone means the model needs no credential of ours. It strips the same
	// inherited variables as AuthSubscription but does not imply a stored login
	// to fall back to, which is what a local provider actually wants — and it
	// leaves the placeholder key in place so the harness cannot fall back at
	// all. It is the default for ollama models.
	AuthNone = "none"
)

Auth modes for an agent, selecting where the harness gets its credentials.

View Source
const (
	// FlightManifestSchemaURL is the published JSON Schema for flight manifest
	// YAML. Editor modelines prefer the local copy materialized by pkg/schemas
	// and fall back to this.
	FlightManifestSchemaURL = schemas.FlightManifestURL
)

Variables

View Source
var ConfigExplainFields = []string{
	"defaultKeg",
	"fallbackKeg",
	"flight",
	"agent",
	"logFile",
	"logLevel",
	"defaultHub",
	"fallbackHub",
	"defaultNamespace",
	"fallbackNamespace",
	"disableAtlasHub",
	"disableTelemetry",
}

ConfigExplainFields lists the scalar config fields eligible for explain.

View Source
var ErrAtlasHubDisabled = errors.New("no hub configured; implicit atlas hub disabled")

ErrAtlasHubDisabled is returned by ResolveLoginHubURL when the chain would fall through to the compiled-in DefaultHubURL but the deployment has opted out via Config.DisableAtlasHub. Callers surface it verbatim so SOC2-conscious users see a stable string they can grep for.

View Source
var ErrFlightSubflightNotAllowed = errors.New("flight is not available from the pinned root")

ErrFlightSubflightNotAllowed marks a selection outside the immutable root's live, identity-accessible transitive graph. The historical name is retained for callers that classify this authority denial; selection is no longer limited to direct children.

View Source
var ErrNotBootstrapped = errors.New("tapper is not set up on this machine; run `tap bootstrap` to get started")

ErrNotBootstrapped is returned by hub/namespace-dependent operations on the full `tap` surface when no user config exists yet — i.e. `tap bootstrap` has not been run.

View Source
var ErrTokenRejected = errors.New("hub rejected the token")

ErrTokenRejected marks a token the hub actively refused (HTTP 401/403), as distinct from a transport failure (hub unreachable). Callers use errors.Is to tell "your token is bad" apart from "we couldn't reach the hub" — see Tap.AuthStatus, which renders those two cases differently.

Functions

func AddNamespaceMember added in v0.23.0

func AddNamespaceMember(ctx context.Context, hubURL, token, namespace, username, role string) error

AddNamespaceMember upserts a member via POST /api/v1/@{namespace}/members. role is owner|admin|member.

func BuildOrientationPayload added in v0.35.0

func BuildOrientationPayload(flight *Flight, flightNote, agent string, kegs []OrientationKeg, warnings []string, authority *OrientationAuthority) (string, error)

BuildOrientationPayload renders the provider-neutral orientation document from one flight snapshot and its effective KEG listing. agent names the `tap launch` agent driving the session, or "" when a human is; it is reported because it explains where the flight came from and how to change it.

func CanonicalConfiguredHubURL added in v0.39.0

func CanonicalConfiguredHubURL(s string) string

CanonicalConfiguredHubURL returns the AuthStore identity for a configured hub URL. Config accepts bare hosts and gives them an HTTPS default, while CanonicalHubURL deliberately operates only on the URL it is handed. Keep that distinction explicit at alias-to-auth identity boundaries.

func CanonicalHubURL added in v0.20.0

func CanonicalHubURL(s string) string

CanonicalHubURL returns the canonical form used as the AuthStore key. It strips trailing slashes, lowercases the scheme and host, and preserves the path exactly (per RFC 3986 the path is case-sensitive). Invalid URLs fall through to TrimRight'd input so callers don't have to pre-validate — they'll hit a clearer error at the login step.

func CanonicalKegRef added in v0.37.0

func CanonicalKegRef(target *keg.Target) string

CanonicalKegRef returns the @namespace/keg reference for a resolved target, or "" when the target names no namespaced keg.

func CatViewDocument added in v0.40.0

func CatViewDocument(ctx context.Context, view keg.NodeView, opts CatOptions) (content, meta, stats string)

CatViewDocument returns the machine-readable parts of one node view under opts, for callers handing structured data to a client instead of rendering it for a human.

The fields deliberately mirror the write surface: content and meta are exactly what `edit` accepts, so a read result can be modified and sent back without parsing the rendered output. That is why this does not return the composed `---meta---body` document — `edit` rejects frontmatter inside content, so a composed blob could not be round-tripped.

func CreateGrant added in v0.23.0

func CreateGrant(ctx context.Context, hubURL, token, namespace, alias, username, role string) error

CreateGrant upserts a grant via POST .../grants. role is viewer|editor|admin.

func CreateKeg added in v0.23.0

func CreateKeg(ctx context.Context, hubURL, token, namespace, alias, title, visibility string) error

CreateKeg asks the hub to create @namespace/alias via POST /api/v1/@{namespace}/kegs. A 409 is returned as an error wrapping keg.ErrExist so callers can detect "already exists" with errors.Is; 401/403 wrap ErrTokenRejected; other non-2xx statuses surface the hub's status line.

func DeleteHubFlight added in v0.23.0

func DeleteHubFlight(ctx context.Context, hubURL, token, namespace, slug, expectedHash string) error

func EffectiveOrientationRole added in v0.39.0

func EffectiveOrientationRole(row OrientationKeg) string

EffectiveOrientationRole intersects the identity role with the flight cap. Identity catalog rows have no cap and therefore retain their identity role only for metadata search; operational projections always carry a cap.

func FlightManifestHash added in v0.39.0

func FlightManifestHash(m FlightManifest) string

FlightManifestHash returns the deterministic revision token for a manifest.

func FormatCatViews added in v0.39.0

func FormatCatViews(ctx context.Context, views []keg.NodeView, opts CatOptions) string

FormatCatViews renders views the way Cat does. It is exported so a caller that already holds the views — one that needed CatViews for the per-node hashes — can produce the same text without reading the nodes a second time. Re-reading would also double every access touch.

func IntegrateHosts added in v0.19.0

func IntegrateHosts() []string

func IntegratePlugins added in v0.30.0

func IntegratePlugins(host string) ([]string, error)

IntegratePlugins returns the plugin names advertised by the host's embedded rendered marketplace. The marketplace, rather than installer code, is the source of truth as new optional plugins are added.

func KegBackendLabel added in v0.22.0

func KegBackendLabel(target *keg.Target) string

KegBackendLabel returns a stable, path-free identifier for a keg target suitable for user-facing output. It is used by surfaces that must describe "what kind of keg is this" without leaking the remote URL or other location-revealing details.

Mapping by scheme:

  • hub: "keg:@<namespace>/<kegName>"
  • http(s): "http" or "https"
  • other/unknown: the scheme string, or "" when target is nil

The hub label is the canonical keg reference (Target.String): the real "keg" scheme with the hub resolved from the namespace, never encoded in the string.

func KegLocation added in v0.23.0

func KegLocation(target *keg.Target) string

KegLocation renders where a remotely hosted keg lives for user-facing output after `tap keg create`: "on <hubURL>", or "" when no concrete location is known. Unlike KegBackendLabel it intentionally reveals the URL so a fresh create says exactly where the keg landed.

func LaunchHarnesses added in v0.37.0

func LaunchHarnesses() []string

LaunchHarnesses returns the launchable harness names, sorted. It backs shell completion the way IntegrateHosts does for `tap integrate`.

func LocalGitData

func LocalGitData(ctx context.Context, rt *toolkit.Runtime, projectPath, key string) ([]byte, error)

LocalGitData attempts to run `git -C projectPath config --local --get key`.

If git is not present or the command fails it returns an error. The returned bytes are trimmed of surrounding whitespace. The function logs diagnostic messages using the logger from rt.

func NewAuthStoreTokenResolver added in v0.20.0

func NewAuthStoreTokenResolver(store *AuthStore, rt *toolkit.Runtime, storePath string) keg.TokenResolver

NewAuthStoreTokenResolver returns a keg.TokenResolver backed by store. rt and storePath enable in-place refresh of expired OAuth2 tokens; pass the same runtime and AuthStorePath the store was loaded from. A nil store yields a resolver that always returns "", matching AuthStore's nil-safe contract.

func OpenBrowser added in v0.23.0

func OpenBrowser(ctx context.Context, rt *toolkit.Runtime, rawURL string) error

OpenBrowser launches the platform-native "open URL" command and returns once the process has been started. We do NOT wait for exit because most browsers daemonize and exec.Wait would deadlock the CLI behind the user's window manager.

Quarantined stdlib exception (like pkg/tapper/editor_live.go): this spawns an external browser process whose timing is governed by the user's environment rather than any in-process clock. Routing through exec.CommandContext keeps cancellation working if the caller ctx is cancelled before the command launches.

On unrecognized platforms or launch failure, we print the URL to rt.Stream().Err so the user can copy-paste it manually — that's a successful fallback, not a hard error.

func OrientationOperatingRules added in v0.39.0

func OrientationOperatingRules() string

OrientationOperatingRules returns the static KEG operating preamble: what a KEG is, and the rules for working in one. It carries no session state, so an MCP server can deliver it once at initialization and let a caller that already knows which flight to pass start work without orienting first.

It remains part of the orient payload as well. That duplication is deliberate: initialization instructions are captured once and are discarded by a context reset, so orient has to stay self-contained or a compacted agent has no route back to these rules.

func ParseAgentModel added in v0.37.0

func ParseAgentModel(raw string) (provider, model string, err error)

ParseAgentModel splits a provider-qualified model into its provider and model id. An unqualified model is an error rather than a guess, because the provider decides which protocol the harness must speak.

func RemoveNamespaceMember added in v0.23.0

func RemoveNamespaceMember(ctx context.Context, hubURL, token, namespace, username string) error

RemoveNamespaceMember removes a member via DELETE /api/v1/@{namespace}/members/@{username}.

func RenameKeg added in v0.25.0

func RenameKeg(ctx context.Context, hubURL, token, namespace, oldAlias, newAlias string) error

RenameKeg updates a keg alias in-place within the same namespace via POST .../rename. The hub keeps the immutable keg id and does not create redirects for the old selector.

func ResolveLoginHubURL added in v0.20.0

func ResolveLoginHubURL(cfg *Config, explicit string) (string, error)

ResolveLoginHubURL returns the hub URL the login flow should target, applying the hub resolution chain:

  1. explicit non-empty → canonicalize and use
  2. cfg.DefaultHub names a Hubs entry → use that entry's URL
  3. cfg.FallbackHub names a Hubs entry → use that entry's URL
  4. cfg.Hubs has exactly one remote/readonly entry → use it
  5. cfg.DisableAtlasHub is true → ErrAtlasHubDisabled
  6. fall back to DefaultHubURL

A misconfigured DefaultHub or FallbackHub is a hard error rather than a silent fall-through to step 3 — typos should surface, not silently route to a different hub.

Returned URLs are canonicalized via CanonicalHubURL so callers can compare them against AuthStore keys without re-canonicalizing.

func RevokeGrant added in v0.23.0

func RevokeGrant(ctx context.Context, hubURL, token, namespace, alias, username string) error

RevokeGrant removes a grant via DELETE .../grants/@{username}.

func SetKegVisibility added in v0.23.0

func SetKegVisibility(ctx context.Context, hubURL, token, namespace, alias, visibility string) error

SetKegVisibility updates a keg's visibility via PATCH .../access. visibility is public|private.

func SetNamespaceMemberRole added in v0.23.0

func SetNamespaceMemberRole(ctx context.Context, hubURL, token, namespace, username, role string) error

SetNamespaceMemberRole changes a member's role via PATCH /api/v1/@{namespace}/members/@{username}.

func ValidateKegAlias added in v0.22.0

func ValidateKegAlias(alias string) error

ValidateKegAlias returns nil when alias matches the canonical alias shape and a wrapped keg.ErrInvalid otherwise. Empty input is rejected explicitly so callers can distinguish missing-alias errors from shape errors when reading the wrapped chain.

func ValidateNamespace added in v0.23.0

func ValidateNamespace(ns string) error

ValidateNamespace returns nil when ns is a legal namespace segment and a wrapped keg.ErrInvalid otherwise. Empty input is rejected explicitly. The "@" sigil is never part of the stored value; pass the bare namespace.

func WalkConfigsUp added in v0.23.0

func WalkConfigsUp(rt *toolkit.Runtime, start, rel string) []string

WalkConfigsUp returns the absolute paths of every existing rel file found by walking from start up to the filesystem root, ordered DEEPEST-FIRST (nearest to start first). Missing candidates are skipped. The user-global config is not included; callers layer it underneath the returned project configs.

Types

type AgentEntry added in v0.37.0

type AgentEntry struct {
	Model         string   `yaml:"model,omitempty"`
	BaseURL       string   `yaml:"baseUrl,omitempty"`
	Auth          string   `yaml:"auth,omitempty"`
	APIKeyEnv     string   `yaml:"apiKeyEnv,omitempty"`
	ContextWindow int      `yaml:"contextWindow,omitempty"`
	Args          []string `yaml:"args,omitempty"`
}

AgentEntry is an alias for a model plus how to reach and authenticate against that model, keyed by name in the agents map and consumed by `tap launch`.

Model is provider-qualified ("anthropic/claude-opus-4", "ollama/qwen3.6:35b") so the launcher knows which protocol the harness must speak. Launch roots come from the top-level flight cascade; legacy per-agent flight keys are ignored and preserved as unknown extension data when configuration is rewritten.

BaseURL overrides the provider's endpoint. One value serves both protocols: the launcher adds or removes the /v1 suffix to suit whichever the harness speaks. It defaults to the local Ollama server for ollama models and is empty for hosted providers, leaving the harness on its own endpoint.

Auth selects where credentials come from — inherit (default), subscription, or apiKey. APIKeyEnv names the environment variable holding the key; the name is configured, never the secret, mirroring HubEntry.TokenEnv. Agents therefore hold no secrets, so unlike hubs they need no trust-boundary strip and a project config may safely define them.

Experimental: this shape is expected to change when agents move to the hub. ContextWindow caps the working context in tokens. Harnesses express this differently — Codex as model metadata, Claude Code as an auto-compact threshold — so the launcher translates it per harness rather than passing a raw flag, and reports rather than drops it where there is no equivalent.

type AuthEntry added in v0.20.0

type AuthEntry struct {
	AccessToken string    `yaml:"access_token"`
	TokenType   string    `yaml:"token_type,omitempty"`
	ExpiresAt   time.Time `yaml:"expires_at,omitempty"`
	Scope       string    `yaml:"scope,omitempty"`

	// RefreshToken, ClientID, and TokenEndpoint are populated by the OAuth2
	// device-login flow so the CLI can silently renew an expired AccessToken
	// without a re-login (see RefreshHubToken). All three are empty for a
	// pasted `thub_` API token, which never expires and cannot be refreshed.
	RefreshToken  string `yaml:"refresh_token,omitempty"`
	ClientID      string `yaml:"client_id,omitempty"`
	TokenEndpoint string `yaml:"token_endpoint,omitempty"`
}

AuthEntry is a single hub's cached credential. Plain value type — callers hold copies returned from Get, and pass values into Set.

Fields match the typical OAuth 2.0 shape so we can store whatever a hub returns without transformation. TokenType / ExpiresAt / Scope are all optional: a hub that only returns a bare bearer token will serialize as a single access_token field.

func AuthLoginDevice added in v0.20.0

func AuthLoginDevice(ctx context.Context, rt *toolkit.Runtime, opts AuthLoginDeviceOptions) (*AuthEntry, error)

AuthLogin runs the device authorization grant against the hub described by opts and returns a populated AuthEntry. The store is not touched — the caller persists the result via AuthStore.Set + Save, mirroring the browser-based AuthLogin contract.

func RefreshHubToken added in v0.23.0

func RefreshHubToken(ctx context.Context, rt *toolkit.Runtime, hubURL string, entry *AuthEntry) (*AuthEntry, error)

RefreshHubToken exchanges entry.RefreshToken at the hub's token endpoint and returns a new AuthEntry carrying the rotated access + refresh tokens and a recomputed expiry. The hub rotates refresh tokens single-use, so the caller must persist the returned entry (the old refresh token is now spent).

Endpoint/client resolution: the device-login flow records TokenEndpoint and ClientID on the entry, so a refresh is a single POST with no rediscovery. Entries that predate that (or omit the fields) fall back to rediscovering the token endpoint from hubURL and to the stock public client id.

type AuthLoginDeviceOptions added in v0.20.0

type AuthLoginDeviceOptions struct {
	// HubURL is the hub base (e.g. "https://hub.example.com"). Required.
	HubURL string

	// ClientID is the OAuth2 public client identifier the hub will validate
	// against its registered clients. Required.
	ClientID string

	// Scope is an optional space-separated scope string. Omitted from the
	// device_authorization request when empty.
	Scope string

	// DeviceLabel is an optional human-readable label for this login session.
	// Hubs may display it in account/session views.
	DeviceLabel string

	// Timeout bounds the whole flow including the user's browser action;
	// zero uses defaultDeviceTimeout.
	Timeout time.Duration

	// HTTPClient executes the metadata GET, device_authorization POST, and
	// token POSTs. Default: http.DefaultClient.
	HTTPClient *http.Client

	// PromptOut is the writer that receives the user-facing prompt
	// ("Open <URL> and enter <CODE>"). Default: os.Stderr via the runtime
	// stream when Out is nil; an in-memory buffer in tests.
	PromptOut io.Writer

	// OnUserCode, when non-nil, is invoked once the hub has issued the
	// user_code + verification URI and before polling begins. It owns the
	// user-facing presentation: the CLI installs a handler that prints the
	// code, offers to open the browser (gh-style "press Enter to open"),
	// and falls back to printing the URL for manual copy/paste. When nil,
	// the flow prints a plain copy/paste prompt to PromptOut — the library
	// default never opens a browser, keeping pkg/tapper free of any
	// interactive/TTY dependency. A non-nil error aborts the login.
	OnUserCode func(context.Context, DeviceUserPrompt) error

	// Now returns the current time. Default: time.Now. Tests inject a fake
	// clock to control timeout behavior deterministically.
	Now func() time.Time

	// Sleep blocks for d. Default: time.Sleep. Tests inject a no-op or
	// channel-coordinated stub so polling loops don't actually wait.
	Sleep func(d time.Duration)
}

AuthLoginDeviceOptions is the dependency envelope for AuthLoginDevice. Required: HubURL, ClientID. Everything else has a production default.

type AuthLogoutOptions added in v0.20.0

type AuthLogoutOptions struct {
	// Hub is the raw or canonical hub URL. When empty and exactly one
	// hub is stored, auto-resolves to that single entry; otherwise an
	// empty Hub with multiple stored hubs surfaces a directed error.
	Hub string
}

AuthLogoutOptions selects which hub to log out of. Flat (no KegTargetOptions) because auth state is a user-level concern that spans kegs — a login is per-hub, not per-keg.

type AuthLogoutResult added in v0.20.0

type AuthLogoutResult struct {
	// Removed is true when an entry was actually deleted from the store.
	// False when the store was empty or the hub was not found; both of
	// those cases are soft-successes (no error returned).
	Removed bool
	// HubURL is the canonical hub that was targeted, or "" when the
	// store was empty.
	HubURL string
	// Formatted is the authoritative output line terminated with \n.
	// CLI routes to stdout when Removed=true, stderr otherwise.
	Formatted string
}

AuthLogoutResult is the pre-formatted output plus structured fields for callers that need to route streams or surface structured output. Formatted is authoritative: the CLI emits it verbatim to stdout when Removed=true and stderr otherwise.

type AuthStatusHub added in v0.28.1

type AuthStatusHub struct {
	// Present is false when no matching entry exists.
	Present bool

	// HubURL is the canonical key that matched.
	HubURL string

	// TokenPrefix is the first 12 chars of the access token followed by
	// "..." — matching the non-secret prefix the hub stores and shows in
	// its account UI — or "[set]" when the token is too short for a
	// meaningful prefix. The raw token is never exposed here.
	TokenPrefix string

	// TokenType mirrors the stored entry (e.g. "Bearer"). Empty when
	// the hub returned a bare token with no type.
	TokenType string

	// Account is the username the hub reported for this token via the
	// live whoami probe. Empty when validation was skipped (--offline) or
	// failed.
	Account string

	// DisplayName is the human name the hub reported alongside Account.
	// Empty when the hub omits it or validation didn't run.
	DisplayName string

	// Valid is true when the live whoami probe confirmed the token. False
	// when the token was rejected, the hub was unreachable, or --offline
	// skipped the check.
	Valid bool

	// ValidationError is the error message from a failed/ skipped probe,
	// empty on success. Lets structured consumers branch without parsing
	// Formatted.
	ValidationError string

	// Scope mirrors the stored entry. Empty when no scope was granted.
	Scope string

	// ExpiresAt mirrors the stored entry; zero when no expiry is known.
	ExpiresAt time.Time

	// ExpiryStatus is a three-way tag: "unknown" | "valid" | "expired".
	// Made explicit so callers (and future JSON consumers) don't have
	// to re-derive from ExpiresAt vs clock.
	ExpiryStatus string

	// LoginMethod records how the credential was obtained: "device" for the
	// OAuth2 browser/device flow (carries client + refresh + token endpoint),
	// "token" for a pasted API token. Lets structured consumers branch without
	// parsing Formatted.
	LoginMethod string

	// Renewable is true when a refresh token is stored — i.e. the access token
	// renews silently on expiry rather than forcing a re-login. Always false
	// for a pasted API token.
	Renewable bool

	// Formatted is the exact block rendered for this hub. Terminated with a
	// trailing newline.
	Formatted string
}

AuthStatusHub is the per-hub structured status used by AuthStatusResult.Hubs. Formatted is the exact block rendered for this hub, terminated with a trailing newline.

type AuthStatusOptions added in v0.20.0

type AuthStatusOptions struct {
	// Hub is a raw or canonical hub URL. When empty, AuthStatus reports every
	// stored hub login; an empty store surfaces a directed empty message (see
	// AuthStatus docs).
	Hub string

	// Offline skips the live whoami probe and reports purely from the
	// on-disk store (no network, no account name). Useful for scripts,
	// air-gapped use, or when an agent must not make outbound calls.
	Offline bool
}

AuthStatusOptions selects which hub to report on. Flat (no KegTargetOptions) because auth state is a user-level concern that spans kegs — a login is per-hub, not per-keg.

type AuthStatusResult added in v0.20.0

type AuthStatusResult struct {
	// Present is false when no matching entry exists (empty store
	// with no --hub, or --hub that isn't in the store).
	Present bool

	// HubURL is the canonical key that matched. Zero-value when the
	// caller omitted --hub and the store is empty.
	HubURL string

	// TokenPrefix is the first 12 chars of the access token followed by
	// "..." — matching the non-secret prefix the hub stores and shows in
	// its account UI — or "[set]" when the token is too short for a
	// meaningful prefix. The raw token is never exposed here.
	TokenPrefix string

	// TokenType mirrors the stored entry (e.g. "Bearer"). Empty when
	// the hub returned a bare token with no type.
	TokenType string

	// Account is the username the hub reported for this token via the
	// live whoami probe. Empty when validation was skipped (--offline) or
	// failed.
	Account string

	// DisplayName is the human name the hub reported alongside Account.
	// Empty when the hub omits it or validation didn't run.
	DisplayName string

	// Valid is true when the live whoami probe confirmed the token. False
	// when the token was rejected, the hub was unreachable, or --offline
	// skipped the check.
	Valid bool

	// ValidationError is the error message from a failed/ skipped probe,
	// empty on success. Lets structured consumers branch without parsing
	// Formatted.
	ValidationError string

	// Scope mirrors the stored entry. Empty when no scope was granted.
	Scope string

	// ExpiresAt mirrors the stored entry; zero when no expiry is known.
	ExpiresAt time.Time

	// ExpiryStatus is a three-way tag: "unknown" | "valid" | "expired".
	// Made explicit so callers (and future JSON consumers) don't have
	// to re-derive from ExpiresAt vs clock.
	ExpiryStatus string

	// LoginMethod records how the credential was obtained: "device" for the
	// OAuth2 browser/device flow (carries client + refresh + token endpoint),
	// "token" for a pasted API token. Lets structured consumers branch without
	// parsing Formatted.
	LoginMethod string

	// Renewable is true when a refresh token is stored — i.e. the access token
	// renews silently on expiry rather than forcing a re-login. Always false
	// for a pasted API token.
	Renewable bool

	// Hubs contains structured per-hub status. It has one entry for single-hub
	// status responses and multiple entries when Hub was omitted with multiple
	// stored logins.
	Hubs []AuthStatusHub

	// Formatted is the exact string the CLI prints; MCP returns it
	// verbatim as text content. Terminated with a trailing newline.
	Formatted string
}

AuthStatusResult is the pre-formatted human-readable status output plus structured fields for the MCP surface and any future renderers. Formatted is authoritative: both CLI and MCP emit it verbatim. Scalar fields are populated for single-hub responses; Hubs carries per-hub status entries.

type AuthStore added in v0.20.0

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

AuthStore is the opaque wrapper exposing getters/setters over an authStoreDTO. All methods are nil-safe on the receiver: a (*AuthStore)(nil) reads as an empty store and writes are no-ops. This lets callers skip the "did Load return something?" dance when the file didn't exist.

func LoadAuthStore added in v0.20.0

func LoadAuthStore(ctx context.Context, rt *toolkit.Runtime, path string) (*AuthStore, error)

LoadAuthStore reads the auth store file at path and parses it. A missing file is NOT an error: we return an empty store and nil so first-run callers can treat "no file" and "empty file" identically. Every other read error is wrapped and returned.

func ParseAuthStore added in v0.20.0

func ParseAuthStore(raw []byte) (*AuthStore, error)

ParseAuthStore parses raw YAML bytes into an AuthStore. Pure: no I/O, no clock. Empty input (including whitespace-only) is treated as an empty store rather than a YAML error — first-run and "user cleared the file" look the same to us.

func (*AuthStore) Delete added in v0.20.0

func (s *AuthStore) Delete(hubURL string) bool

Delete removes the entry for hubURL. Returns whether it existed — callers can use this to decide whether to log "logged out" vs "was already logged out".

func (*AuthStore) Get added in v0.20.0

func (s *AuthStore) Get(hubURL string) (*AuthEntry, bool)

Get returns a copy of the entry for hubURL and a present flag. We return a value (not a pointer into the map) so callers can't mutate the stored entry by accident — all edits must go through Set.

func (*AuthStore) Hubs added in v0.20.0

func (s *AuthStore) Hubs() []string

Hubs returns the hub URL keys, sorted, for enumeration. Sorted output makes CLI listings stable without callers having to re-sort.

func (*AuthStore) IsEmpty added in v0.20.0

func (s *AuthStore) IsEmpty() bool

IsEmpty reports whether the store has no hubs. Used by Save to decide whether to delete the file rather than write an empty document.

func (*AuthStore) Save added in v0.20.0

func (s *AuthStore) Save(ctx context.Context, rt *toolkit.Runtime, path string) error

Save writes the store to path. When the store is empty we remove the file instead of writing an empty YAML doc — keeps the filesystem tidy after a `tap auth logout` of the last hub and makes "no file" the canonical empty state (matches LoadAuthStore's contract). Parent directory is created at 0700 if it doesn't exist. If it already exists we don't touch its mode — users/admins may have intentionally widened it, and tightening on every Save would surprise them.

func (*AuthStore) Set added in v0.20.0

func (s *AuthStore) Set(hubURL string, entry AuthEntry)

Set inserts or overwrites the entry for hubURL. Nil receiver is a no-op (matches the "read as empty" contract). We store a copy so later caller mutations don't reach into our map.

type BacklinksOptions

type BacklinksOptions struct {
	KegTargetOptions

	// NodeIDs are the target nodes to inspect incoming links for.
	// Results from all node IDs are merged and deduplicated.
	NodeIDs []string

	// Format is the output template. Legacy verbs %i (id), %t (title),
	// %d (updated), %c (created), %a (accessed) remain supported, and %%
	// renders a literal percent. Named selectors use %{...}: a bare word
	// names a metadata key (%{type}), a leading dot names a statistics field
	// (%{.accessCount}), and %{tags} is the tag list. Selectors other than
	// id, title, and the three dates cost one read per node.
	Format string

	IdOnly bool

	Reverse bool

	// Limit caps the number of results returned. 0 means no limit.
	Limit int

	// Offset skips the first N results before applying limit. Must be >= 0.
	Offset int
}

type BatchCreateNode added in v0.38.0

type BatchCreateNode struct {
	Key     string
	Schema  string
	Content string
	Meta    string
}

type BatchCreateOptions added in v0.38.0

type BatchCreateOptions struct {
	KegTargetOptions
	Nodes []BatchCreateNode
}

type BatchEditItem added in v0.38.0

type BatchEditItem struct {
	NodeID       string
	Schema       string
	Content      string
	HasContent   bool
	Meta         string
	HasMeta      bool
	ExpectedHash string
}

type BatchEditOptions added in v0.38.0

type BatchEditOptions struct {
	KegTargetOptions
	Edits []BatchEditItem
}

type BatchSnapshotItem added in v0.38.0

type BatchSnapshotItem struct {
	NodeID  string
	Message string
}

type BatchSnapshotOptions added in v0.38.0

type BatchSnapshotOptions struct {
	KegTargetOptions
	Nodes []BatchSnapshotItem
}

type BootstrapOptions added in v0.23.0

type BootstrapOptions struct {
	// Kind selects the deployment: cloud | enterprise. Empty defaults
	// to cloud (atlas is the compiled-in default hub).
	Kind string
	// Endpoint is the hub base URL; required when Kind == enterprise, ignored
	// otherwise. A bare host is upgraded to https://.
	Endpoint string
	// HubName overrides the hub key written for an enterprise endpoint. Empty
	// derives it from the endpoint host (see deriveHubName).
	HubName string
	// Namespace overrides the hub's default namespace.
	Namespace string
}

BootstrapOptions configures Tap.Bootstrap, the first-run onboarding that materializes or refreshes the user-level tapper config around a deployment kind.

type BootstrapResult added in v0.23.0

type BootstrapResult struct {
	Path      string          // user config path written
	Created   bool            // true when a fresh file was created, false on update
	Kind      string          // normalized deployment kind
	Hub       string          // hub name written as fallbackHub
	HubURL    string          // login/display URL
	Namespace string          // resolved fallback namespace
	Warnings  []ConfigWarning // semantic warnings from ValidateConfig
}

BootstrapResult reports what Bootstrap wrote so the CLI can phrase its output, drive an optional login, and surface non-fatal config warnings.

type CatOptions

type CatOptions struct {
	// NodeIDs are the node identifiers to read (e.g., "0", "42").
	// Multiple IDs produce concatenated output separated by blank lines.
	NodeIDs []string

	// Query is an optional boolean expression (same syntax as tap tags) used
	// to select nodes. Mutually exclusive with NodeIDs.
	Query string

	KegTargetOptions

	// Edit opens the node in the editor instead of printing output.
	Edit bool

	// ContentOnly displays content only.
	ContentOnly bool

	// StatsOnly displays stats only.
	StatsOnly bool

	// MetaOnly displays metadata only.
	MetaOnly bool

	// Stream carries stdin piping information when editing.
	Stream *toolkit.Stream

	// LockToken is an optional cross-process lock token for edit operations.
	LockToken string
}

type Config

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

Config represents the user's tapper configuration.

Config keeps a typed model alongside its parsed YAML document. Tapper-owned rewrites overlay known values so extension fields and comments survive.

func DefaultProjectConfig

func DefaultProjectConfig(user, userKegRepo string) *Config

DefaultProjectConfig returns a project-scoped config with sensible defaults.

Project config uses DEFAULT slots (defaultHub/defaultNamespace) — the authoritative choice for the project, overriding the user-level fallbacks.

func DefaultUserConfig

func DefaultUserConfig(name string) *Config

DefaultUserConfig returns a sensible default global/user Config.

The global user config uses the FALLBACK hub (fallbackHub) so keg references need not specify a hub. The namespace is NOT pinned by a global fallbackNamespace — it comes from the resolved hub's own namespace field. `name` seeds the default remote hub's namespace.

func MergeConfig

func MergeConfig(cfgs ...*Config) *Config

MergeConfig merges multiple Config values into a single configuration.

Merge semantics:

  • Later configs override earlier values for scalar keys.
  • Hubs are merged by name; later entries override earlier ones.
  • Namespaces are merged by name; later entries override earlier ones.
  • KegMap entries are appended in order, but entries with the same alias + path pattern are replaced by later entries.

func ParseConfig

func ParseConfig(raw []byte) (*Config, error)

ParseConfig parses raw YAML into a Config data model. Unknown keys are ignored by the decoder.

func ReadConfig

func ReadConfig(rt *toolkit.Runtime, path string) (*Config, error)

ReadConfig reads the YAML file at path and returns a parsed Config.

When the file does not exist the function returns a Config value and an error that wraps keg.ErrNotExist so callers can detect no-config cases.

func (*Config) AddKegMap

func (cfg *Config) AddKegMap(entry KegMapEntry) error

AddKegMap adds or updates a keg map entry in the Config. Entries are matched by alias + pathPrefix + pathRegex. An entry with the same alias but a different path pattern is treated as a separate mapping.

func (*Config) Agent added in v0.37.0

func (cfg *Config) Agent(name string) (AgentEntry, bool)

Agent returns the named agent entry. Unlike Hub there are no synthesized built-ins: an agent exists only if configured.

func (*Config) AgentName added in v0.37.0

func (cfg *Config) AgentName() string

AgentName returns the name of the agent driving this process, or "" when none is selected. It indexes Agents; it is not itself an agent definition.

func (*Config) Agents added in v0.37.0

func (cfg *Config) Agents() map[string]AgentEntry

Agents returns the configured `tap launch` agents keyed by alias.

func (*Config) Clone

func (cfg *Config) Clone() *Config

Clone produces a deep copy of the Config.

func (*Config) DefaultHub added in v0.20.0

func (cfg *Config) DefaultHub() string

DefaultHub returns the default hub name (high-precedence slot).

func (*Config) DefaultKeg

func (cfg *Config) DefaultKeg() string

DefaultKeg returns the alias to use when no explicit keg is provided.

func (*Config) DefaultNamespace added in v0.23.0

func (cfg *Config) DefaultNamespace() string

DefaultNamespace returns the default namespace (high-precedence slot).

func (*Config) DeleteHub added in v0.23.0

func (cfg *Config) DeleteHub(name string) (bool, error)

DeleteHub removes a hub entry by name, reporting whether it was present.

func (*Config) DeleteNamespace added in v0.23.0

func (cfg *Config) DeleteNamespace(name string) bool

DeleteNamespace removes a namespace→hub mapping by name, reporting whether it was present. `tap hub remove` uses it to prune namespace pins that route to a hub being removed.

func (*Config) DisableAtlasHub added in v0.23.0

func (cfg *Config) DisableAtlasHub() bool

DisableAtlasHub returns true when the synthesized built-in atlas hub is suppressed.

func (*Config) DisableTelemetry added in v0.34.0

func (cfg *Config) DisableTelemetry() bool

DisableTelemetry returns true when remote invocation reporting is disabled.

func (*Config) FallbackHub added in v0.23.0

func (cfg *Config) FallbackHub() string

FallbackHub returns the fallback hub name (last-resort slot).

func (*Config) FallbackKeg added in v0.2.0

func (cfg *Config) FallbackKeg() string

FallbackKeg returns the last-resort keg alias.

func (*Config) FallbackNamespace added in v0.23.0

func (cfg *Config) FallbackNamespace() string

FallbackNamespace returns the fallback namespace (last-resort slot).

func (*Config) Flight added in v0.23.0

func (cfg *Config) Flight() string

Flight returns the persisted flight reference applied when no --flight flag is given. On a merged config this may have come from the active agent rather than from any file — see ConfigService.load.

func (*Config) Hub added in v0.23.0

func (cfg *Config) Hub(name string) (HubEntry, bool)

Hub returns the named hub entry. The built-in atlas remote hub is synthesized when it is not explicitly configured unless disableAtlasHub is set.

func (*Config) Hubs added in v0.20.0

func (cfg *Config) Hubs() map[string]HubEntry

Hubs returns the map of configured hubs keyed by name.

func (*Config) KegMap

func (cfg *Config) KegMap() []KegMapEntry

KegMap returns the list of path/regex to keg alias mappings.

func (*Config) LogFile

func (cfg *Config) LogFile() string

LogFile returns the log file path.

func (*Config) LogLevel

func (cfg *Config) LogLevel() string

LogLevel returns the log level.

func (*Config) LookupAlias

func (cfg *Config) LookupAlias(rt *toolkit.Runtime, projectRoot string) string

LookupAlias returns the keg alias matching the given project root path. It first checks regex patterns in KegMap entries, then prefix matches. For multiple prefix matches, the longest matching prefix wins. Returns empty string if no match is found or config data is nil.

func (*Config) LookupAliasForTarget added in v0.6.0

func (cfg *Config) LookupAliasForTarget(_ *toolkit.Runtime, _ string) string

LookupAliasForTarget previously reverse-mapped a resolved target back to its configured keg alias. The namespace-centric model has no alias table, so a target no longer carries a short alias; callers fall back to the canonical @namespace/name label. Retained as a no-op so those callers need no change.

func (*Config) Namespace added in v0.23.0

func (cfg *Config) Namespace(name string) (NamespaceRef, bool)

Namespace returns the namespace reference registered under name.

func (*Config) Namespaces added in v0.23.0

func (cfg *Config) Namespaces() map[string]NamespaceRef

Namespaces returns the map of namespace name to hosting hub reference.

func (*Config) ResolveAlias

func (cfg *Config) ResolveAlias(rt *toolkit.Runtime, alias string) (*keg.Target, error)

ResolveAlias resolves a keg selector string to a concrete Target. The selector is parsed as a keg reference (see parseKegRef) and resolved through the namespace-centric ResolveRef chain — there is no kegs alias table.

Returns (nil, error) when the selector is empty or resolution fails.

func (*Config) ResolveDefault

func (cfg *Config) ResolveDefault(rt *toolkit.Runtime) (*keg.Target, error)

ResolveDefault resolves the current DefaultKeg reference to a target.

func (*Config) ResolveKegMap

func (cfg *Config) ResolveKegMap(rt *toolkit.Runtime, projectRoot string) (*keg.Target, error)

ResolveKegMap chooses the appropriate keg (via alias) based on path.

Precedence rules:

  1. Regex entries in KegMap have the highest precedence.
  2. PathPrefix entries are considered next; when multiple prefixes match the longest prefix wins.
  3. If no entry matches, resolution returns an alias-not-found error.

The function expands env vars and tildes prior to comparisons, so stored prefixes and patterns may contain ~ or $VAR values.

func (*Config) ResolveRef added in v0.23.0

func (cfg *Config) ResolveRef(_ *toolkit.Runtime, ref KegRef) (*keg.Target, error)

ResolveRef resolves a (hub, namespace, name) reference into a concrete keg.Target. It applies the namespace-centric chains via resolveNamespaceHub — namespace first (explicit → default/fallback), then the hub that hosts that namespace — and the per-kind backend mapping:

  • remote: <hub.url>/api/v1/@<namespace>/kegs/<name> as a hub target
  • readonly: same URL as remote, with Target.Readonly set

func (*Config) SetDefaultHub added in v0.20.0

func (cfg *Config) SetDefaultHub(_ context.Context, hub string) error

SetDefaultHub sets the default hub name.

func (*Config) SetDefaultKeg

func (cfg *Config) SetDefaultKeg(keg string) error

SetDefaultKeg sets the alias used when no explicit keg is provided.

func (*Config) SetDefaultNamespace added in v0.23.0

func (cfg *Config) SetDefaultNamespace(ns string) error

SetDefaultNamespace sets the default namespace.

func (*Config) SetDisableAtlasHub added in v0.23.0

func (cfg *Config) SetDisableAtlasHub(disable bool) error

SetDisableAtlasHub toggles the synthesized built-in atlas hub.

func (*Config) SetDisableTelemetry added in v0.34.0

func (cfg *Config) SetDisableTelemetry(disable bool) error

SetDisableTelemetry toggles privacy-minimized invocation reporting.

func (*Config) SetFallbackHub added in v0.23.0

func (cfg *Config) SetFallbackHub(hub string) error

SetFallbackHub sets the fallback hub name.

func (*Config) SetFallbackKeg added in v0.2.0

func (cfg *Config) SetFallbackKeg(keg string) error

SetFallbackKeg sets the fallback keg alias.

func (*Config) SetFallbackNamespace added in v0.23.0

func (cfg *Config) SetFallbackNamespace(ns string) error

SetFallbackNamespace sets the fallback namespace.

func (*Config) SetFlight added in v0.23.0

func (cfg *Config) SetFlight(flight string) error

SetFlight sets the persisted flight reference (or clears it when empty).

func (*Config) SetHub added in v0.23.0

func (cfg *Config) SetHub(name string, entry HubEntry) error

SetHub adds or replaces a hub entry by name.

func (*Config) SetLogFile

func (cfg *Config) SetLogFile(_ context.Context, path string) error

SetLogFile sets the log file path.

func (*Config) SetLogLevel

func (cfg *Config) SetLogLevel(level string) error

SetLogLevel sets the log level.

func (*Config) SetNamespace added in v0.23.0

func (cfg *Config) SetNamespace(name string, ref NamespaceRef) error

SetNamespace adds or replaces the hub mapping for a namespace.

func (*Config) ToYAML

func (cfg *Config) ToYAML() ([]byte, error)

ToYAML serializes the Config to YAML bytes.

func (*Config) Touch

func (cfg *Config) Touch(rt *toolkit.Runtime)

Touch updates the Updated timestamp on the Config using the runtime clock.

func (*Config) Updated

func (cfg *Config) Updated() time.Time

Updated returns the last update timestamp.

func (*Config) Write

func (cfg *Config) Write(rt *toolkit.Runtime, path string) error

Write writes the Config back to path using atomic replacement.

type ConfigEditOptions

type ConfigEditOptions struct {
	// Project indicates whether to edit local config instead of user config
	Project bool

	User bool

	ConfigPath string

	Stream *toolkit.Stream
}

ConfigEditOptions configures behavior for Tap.ConfigEdit.

type ConfigExplainOptions added in v0.17.0

type ConfigExplainOptions struct {
	// Field limits the result to a single field. Empty means all fields.
	Field string
}

ConfigExplainOptions configures behavior for Tap.ConfigExplain.

type ConfigExplainResult added in v0.17.0

type ConfigExplainResult struct {
	Field  string // field name (e.g. "defaultKeg")
	Value  string // resolved value in the merged config
	Source string // which provider set this value ("user config", "project config", "env vars", "default")
}

ConfigExplainResult describes the provenance of a single config field.

type ConfigLoadWarning added in v0.17.0

type ConfigLoadWarning struct {
	Source  string // "user config" or "project config"
	Path    string // file path that caused the issue
	Message string // human-readable description
	Err     error  // underlying error
}

ConfigLoadWarning represents a non-fatal issue encountered while loading config.

type ConfigOptions

type ConfigOptions struct {
	// Project indicates whether to display project config
	Project bool

	// User indicates whether to display user config
	User bool

	// ConfigPath directly selects a config file to display.
	ConfigPath string
}

type ConfigService

type ConfigService struct {
	Runtime *toolkit.Runtime

	PathService *PathService

	// ConfigPath is the path to the config file.
	ConfigPath string
	// contains filtered or unexported fields
}

ConfigService loads, merges, and resolves tapper configuration state.

Configuration is read once and then fixed for the life of the process. A `tap` command therefore runs against one consistent snapshot, and a long-lived `tap mcp` session reloads transport configuration while resolving every authority-bearing call. Nothing inside a session can write configuration — the `config` tool is read-only — so "edit the file, then reorient" is the whole update story.

The snapshot is immutable once published, so concurrent readers need no coordination beyond the mutex guarding the pointer itself. The pinned flight root remains immutable even though Hub routing and live authority reload. That matters because the MCP SDK dispatches every call except initialize asynchronously.

Flight authority is not affected by a reload: the MCP session gate snapshots its resolved flight separately, so it stays stable across a reload either way.

func NewConfigService

func NewConfigService(root string, rt *toolkit.Runtime) (*ConfigService, error)

NewConfigService builds a ConfigService rooted at root.

func (*ConfigService) Config

func (s *ConfigService) Config() (*Config, error)

Config returns the merged user, project, and environment configuration from the process snapshot.

func (*ConfigService) Load added in v0.37.0

func (s *ConfigService) Load() (*Config, []ConfigLoadWarning, error)

Load returns the merged configuration together with the non-fatal issues found while reading it. Missing files are not warnings (graceful degradation); corrupt YAML and permission errors are.

func (*ConfigService) ProjectConfig

func (s *ConfigService) ProjectConfig() (*Config, error)

ProjectConfig returns the merged project-level configuration with optional caching. It walks from the workspace root up to the filesystem root, collecting every .tapper/config.yaml, and merges them so a deeper directory overrides a shallower one. Hub definitions and credentials are stripped from project layers — only the user config may define them — and each strip is recorded as a load warning surfaced by Config(). Returns keg.ErrNotExist when no project config exists.

func (*ConfigService) ReadProjectConfigFile added in v0.37.0

func (s *ConfigService) ReadProjectConfigFile() (*Config, error)

ReadProjectConfigFile walks and merges the project configs straight from disk, bypassing the snapshot. Same purpose as ReadUserConfigFile.

func (*ConfigService) ReadUserConfigFile added in v0.37.0

func (s *ConfigService) ReadUserConfigFile() (*Config, error)

ReadUserConfigFile reads the user configuration straight from disk, bypassing the snapshot. Use it when about to modify and rewrite that file, so the read-modify-write cycle starts from what is actually on disk.

func (*ConfigService) Reload added in v0.37.0

func (s *ConfigService) Reload()

Reload discards the snapshot so the next read re-reads from disk. Orientation is its only caller: it is the point at which a session re-establishes the context it is operating under.

func (*ConfigService) ResolveTarget

func (s *ConfigService) ResolveTarget(alias, nsOverride, hubOverride string) (*keg.Target, error)

ResolveTarget resolves a keg selector to a keg target. When the selector is empty it uses defaultKeg, then fallbackKeg. The selector is parsed as a keg reference and turned into a concrete target by Config.ResolveAlias (the namespace-centric ResolveRef chain and per-hub-kind backend mapping).

func (*ConfigService) UserConfig

func (s *ConfigService) UserConfig() (*Config, error)

UserConfig returns the global user configuration from the process snapshot.

func (*ConfigService) UserConfigExists added in v0.23.0

func (s *ConfigService) UserConfigExists() bool

UserConfigExists reports whether a user config file is present — the signal that `tap bootstrap` has been run. When an explicit config path is set (--config) it checks that file; otherwise the standard user config path. It inspects the filesystem only; it never parses, so a corrupt-but-present config still counts as bootstrapped.

type ConfigTemplateOptions added in v0.4.0

type ConfigTemplateOptions struct {
	Project bool
}

type ConfigWarning added in v0.17.0

type ConfigWarning struct {
	Field   string // config field name (e.g., "kegMap[0]", "logLevel")
	Message string // human-readable description
}

ConfigWarning represents a semantic issue found during config validation.

func ValidateConfig added in v0.17.0

func ValidateConfig(cfg *Config) []ConfigWarning

ValidateConfig checks a Config for semantic issues that are valid YAML but likely mistakes. It returns warnings, not errors — the config is still usable.

type CreateFlightOptions added in v0.23.0

type CreateFlightOptions struct {
	Ref          string
	Title        string
	Visibility   string
	Capabilities []FlightCapability
	Instructions string
	Cover        []FlightCover
	Subflights   []string
}

type CreateKegOptions added in v0.37.0

type CreateKegOptions struct {
	Namespace  string
	Keg        string
	Title      string
	Visibility string
}

CreateKegOptions is the agent-facing KEG creation request.

type CreateOptions

type CreateOptions struct {
	KegTargetOptions

	Schema string
	Stream *toolkit.Stream
}

type DeleteFileOptions added in v0.2.0

type DeleteFileOptions struct {
	KegTargetOptions
	NodeID string
	Name   string
}

DeleteFileOptions configures behavior for Tap.DeleteFile.

type DeleteFlightOptions added in v0.23.0

type DeleteFlightOptions struct {
	Ref          string
	ExpectedHash string
}

type DeleteImageOptions added in v0.2.0

type DeleteImageOptions struct {
	KegTargetOptions
	NodeID string
	Name   string
}

DeleteImageOptions configures behavior for Tap.DeleteImage.

type DeviceUserPrompt added in v0.23.0

type DeviceUserPrompt struct {
	UserCode                string
	VerificationURI         string
	VerificationURIComplete string
	ExpiresIn               int64
}

DeviceUserPrompt is the subset of the RFC 8628 device_authorization response an OnUserCode handler needs to drive the user-facing step. It is the exported projection of deviceAuthResponse so callers in other packages (the CLI) can present the code without seeing the wire type. VerificationURIComplete (a URL with the user_code embedded) is retained from the wire response but deliberately never displayed or opened — see VerificationURL.

func (DeviceUserPrompt) VerificationURL added in v0.23.0

func (p DeviceUserPrompt) VerificationURL() string

VerificationURL returns the URL the user should open: always the bare verification_uri, never a code-bearing variant. The user_code is shown separately and typed into the page (GitHub-style, RFC 8628 §3.3.1) — embedding it in the URL would leak it into browser history and any front proxy's access logs. The hub-provided verification_uri_complete is deliberately ignored for the same reason.

type DoctorOptions added in v0.5.0

type DoctorOptions struct {
	KegTargetOptions
}

DoctorOptions configures behavior for Tap.Doctor.

type DownloadFileOptions added in v0.2.0

type DownloadFileOptions struct {
	KegTargetOptions
	NodeID string
	Name   string
	Dest   string
}

DownloadFileOptions configures behavior for Tap.DownloadFile.

type DownloadImageOptions added in v0.2.0

type DownloadImageOptions struct {
	KegTargetOptions
	NodeID string
	Name   string
	Dest   string
}

DownloadImageOptions configures behavior for Tap.DownloadImage.

type EditFlightOptions added in v0.24.0

type EditFlightOptions struct {
	Ref          string
	ExpectedHash string

	// Stream, when piped with non-empty content, supplies the manifest YAML
	// directly so scripts can apply a full manifest without an editor.
	Stream *toolkit.Stream
}

EditFlightOptions configures behavior for Tap.EditFlight.

type EditOptions

type EditOptions struct {
	// NodeID is the node identifier to edit (e.g., "0", "42")
	NodeID string

	KegTargetOptions

	// LockToken is an optional cross-process lock token. When provided, the
	// command validates it against any held lock before proceeding.
	LockToken string
	Schema    string

	// Stream carries stdin piping information.
	Stream *toolkit.Stream
}

type EditSchemaOptions added in v0.25.0

type EditSchemaOptions struct {
	KegTargetOptions
	Type         string
	Stream       *toolkit.Stream
	ExpectedHash string
}

type ExportOptions added in v0.4.0

type ExportOptions struct {
	KegTargetOptions
	NodeIDs     []string
	WithHistory bool
	OutputPath  string
}

type Flight added in v0.23.0

type Flight struct {
	Name         string `yaml:"-" json:"name,omitempty"`
	Namespace    string `yaml:"-" json:"namespace,omitempty"`
	Slug         string `yaml:"-" json:"slug,omitempty"`
	Source       string `yaml:"-" json:"source,omitempty"` // configured hub name
	ManifestHash string `yaml:"-" json:"-"`
	FlightManifest
}

Flight is a discovered flight: its manifest plus provenance.

func (*Flight) HasCapability added in v0.30.0

func (f *Flight) HasCapability(capability FlightCapability) bool

HasCapability reports whether a validated manifest grants capability.

func (*Flight) RoleFor added in v0.23.0

func (f *Flight) RoleFor(alias, namespace, kegName string) (FlightRole, bool)

RoleFor reports the flight-scoped role for a keg. An empty cover denies all KEG access. Manifests normally arrive through normalizeFlightManifest, which folds legacy AllowedKegs into Cover; the fallback here only covers Flight values constructed by hand.

type FlightCapability added in v0.30.0

type FlightCapability string

type FlightCover added in v0.23.0

type FlightCover struct {
	Namespace string     `yaml:"namespace,omitempty" json:"namespace,omitempty"`
	Keg       string     `yaml:"keg" json:"keg"`
	Role      FlightRole `yaml:"role" json:"role"`
}

func ParseFlightCoverSpecs added in v0.23.0

func ParseFlightCoverSpecs(specs []string) ([]FlightCover, error)

ParseFlightCoverSpecs parses CLI/MCP cover specs of the form "keg", "@ns/keg", or "@ns/keg=role". Bare entries default to viewer, matching the manifest parser; editor must be requested explicitly.

type FlightGraph added in v0.39.0

type FlightGraph struct {
	Root      *Flight
	Available []*Flight
	Paths     map[string][]string
	// contains filtered or unexported fields
}

FlightGraph is a deterministic breadth-first projection rooted at Root. Available excludes the root and contains each accessible descendant once. Paths holds the first (therefore shortest and ordered) canonical path found.

func FlattenFlightGraph added in v0.39.0

func FlattenFlightGraph(ctx context.Context, root *Flight, fetch func(context.Context, string) (*Flight, error)) (*FlightGraph, error)

FlattenFlightGraph loads an ordered, bounded, single-source flight graph. A missing/forbidden descendant excludes that branch; all other load errors make the runtime graph unavailable. The root is supplied by the caller so root-loss classification remains transport-specific.

func (*FlightGraph) AvailableRefs added in v0.39.0

func (g *FlightGraph) AvailableRefs() []string

AvailableRefs returns the flattened canonical descendant list.

func (*FlightGraph) Select added in v0.39.0

func (g *FlightGraph) Select(raw string) (*Flight, []string, error)

Select resolves omitted input to the root and an explicit input to either the root or an accessible flattened descendant. Per-tool +slug references are relative to the pinned root namespace.

type FlightManifest added in v0.23.0

type FlightManifest struct {
	Title        string             `yaml:"title,omitempty" json:"title,omitempty"`
	Visibility   string             `yaml:"visibility,omitempty" json:"visibility,omitempty"`
	Capabilities []FlightCapability `yaml:"capabilities,omitempty" json:"capabilities,omitempty"`
	Cover        []FlightCover      `yaml:"cover,omitempty" json:"cover,omitempty"`
	Subflights   []string           `yaml:"subflights,omitempty" json:"subflights,omitempty"`
	AllowedKegs  []string           `yaml:"allowedKegs,omitempty" json:"allowedKegs,omitempty"`
	Instructions string             `yaml:"instructions,omitempty" json:"instructions,omitempty"`
}

FlightManifest is the Hub API shape of a flight: explicit covered kegs plus markdown instructions. AllowedKegs remains a legacy wire field and is normalized into editor-cap cover entries.

type FlightRef added in v0.23.0

type FlightRef struct {
	Namespace string
	Slug      string
}

func ParseFlightRef added in v0.23.0

func ParseFlightRef(raw string, defaultNamespace string) (FlightRef, error)

func (FlightRef) Canonical added in v0.23.0

func (r FlightRef) Canonical() string

type FlightRestrictionError added in v0.23.0

type FlightRestrictionError struct {
	Flight string
	Keg    string
	Want   FlightRole
	Got    FlightRole
}

FlightRestrictionError is returned when a resolved keg falls outside the active flight's cover or role cap.

func (*FlightRestrictionError) Error added in v0.23.0

func (e *FlightRestrictionError) Error() string

type FlightRole added in v0.23.0

type FlightRole string

func (FlightRole) AtLeast added in v0.23.0

func (r FlightRole) AtLeast(want FlightRole) bool

AtLeast reports whether r grants at least want within a flight cover.

type FlightService added in v0.23.0

type FlightService struct {
	Runtime       *toolkit.Runtime
	ConfigService *ConfigService
	// KegService supplies the token resolver (and its cached auth store)
	// for hub requests. Lazily constructed when not wired by NewTap.
	KegService *KegService
	// contains filtered or unexported fields
}

FlightService discovers and loads flights from configured remote hubs.

func (*FlightService) GetFlight added in v0.23.0

func (s *FlightService) GetFlight(ctx context.Context, name string) (*Flight, error)

GetFlight loads a single Hub flight by ref. Returns keg.ErrNotExist when no manifest exists. Unqualified refs resolve through unique Hub slug matches. Results are memoized for the life of the process (see flightCache).

func (*FlightService) GetFlightFresh added in v0.30.0

func (s *FlightService) GetFlightFresh(ctx context.Context, name string) (*Flight, error)

GetFlightFresh bypasses the process cache. MCP sessions use this before gated calls so a manifest change invalidates the pinned session instead of silently changing its authority.

func (*FlightService) ListFlights added in v0.23.0

func (s *FlightService) ListFlights(ctx context.Context, hub string, warnings *[]string) ([]string, error)

ListFlights returns canonical @namespace/+slug refs for flights discovered across configured hubs, sorted. When hub is non-empty, discovery is limited to that configured hub. Remote/auth/network errors are best-effort so shell completion and discovery remain responsive; when warnings is non-nil each skipped hub appends one message so user-facing listings can say what was left out.

func (*FlightService) ResolveFlightGraph added in v0.39.0

func (s *FlightService) ResolveFlightGraph(ctx context.Context, root *Flight) (*FlightGraph, error)

ResolveFlightGraph reloads and flattens the identity-accessible transitive descendants of root. It intentionally bypasses the process cache so every MCP call observes live relations and manifests.

func (*FlightService) StoreSessionFlight added in v0.30.0

func (s *FlightService) StoreSessionFlight(name string, f *Flight)

StoreSessionFlight pins a validated flight in the process cache for Tap's per-operation cover enforcement. MCP session invalidation is handled by the server-owned gate before these cached values are used.

type ForceUnlockOptions added in v0.11.0

type ForceUnlockOptions struct {
	NodeID string
	KegTargetOptions
}

ForceUnlockOptions configures behavior for Tap.ForceUnlock.

type GetFlightOptions added in v0.23.0

type GetFlightOptions struct {
	Name string
}

GetFlightOptions selects a single flight by name.

type GrepOptions

type GrepOptions struct {
	KegTargetOptions

	// Query is the regex pattern used to search nodes.
	Query string

	// Format is the output template. Legacy verbs %i (id), %t (title),
	// %d (updated), %c (created), %a (accessed) remain supported, and %%
	// renders a literal percent. Named selectors use %{...}: a bare word
	// names a metadata key (%{type}), a leading dot names a statistics field
	// (%{.accessCount}), and %{tags} is the tag list. Selectors other than
	// id, title, and the three dates cost one read per node.
	Format string

	IdOnly bool

	Reverse bool

	// IgnoreCase enables case-insensitive regex matching.
	IgnoreCase bool

	// MaxLines caps the number of matched lines returned per node.
	// 0 means unlimited. When > 0, only the first MaxLines matching lines
	// are included per node.
	MaxLines int

	// Limit caps the number of results returned. 0 means no limit.
	Limit int

	// Offset skips the first N results before applying limit. Must be >= 0.
	Offset int
}

type HubAddOptions added in v0.23.0

type HubAddOptions struct {
	Name     string
	URL      string
	TokenEnv string
}

HubAddOptions adds a remote hub connection to user config.

type HubEntry added in v0.23.0

type HubEntry struct {
	Kind string `yaml:"kind,omitempty"`
	// DefaultNamespace is this hub's default namespace, used when a reference
	// resolved against this hub omits its namespace. A hub hosts many namespaces;
	// this is only the default. The "@" sigil is implied — store the bare value.
	DefaultNamespace string `yaml:"defaultNamespace,omitempty"`
	URL              string `yaml:"url,omitempty"`
	Token            string `yaml:"token,omitempty"`
	TokenEnv         string `yaml:"tokenEnv,omitempty"`
}

HubEntry describes a single configured hub, keyed by name in the hubs map.

Kind selects the backend: "remote" (read-write HTTP, the default when Kind is empty) or "readonly" (read-only HTTP).

type HubFlight added in v0.23.0

type HubFlight struct {
	Namespace    string             `json:"namespace"`
	Slug         string             `json:"slug"`
	Title        string             `json:"title"`
	Instructions string             `json:"instructions"`
	Visibility   string             `json:"visibility"`
	Capabilities []FlightCapability `json:"capabilities"`
	Cover        []HubFlightCover   `json:"cover"`
	Subflights   []string           `json:"subflights"`
	Hash         string             `json:"hash,omitempty"`
}

func CreateHubFlight added in v0.23.0

func CreateHubFlight(ctx context.Context, hubURL, token, namespace string, flight HubFlight) (*HubFlight, error)

func GetHubFlight added in v0.23.0

func GetHubFlight(ctx context.Context, hubURL, token, namespace, slug string) (*HubFlight, error)

func ListUserFlights added in v0.23.0

func ListUserFlights(ctx context.Context, hubURL, token string) ([]HubFlight, error)

func UpdateHubFlight added in v0.23.0

func UpdateHubFlight(ctx context.Context, hubURL, token, namespace, slug string, flight HubFlight, expectedHash string) (*HubFlight, error)

type HubFlightCover added in v0.23.0

type HubFlightCover struct {
	Namespace string `json:"namespace,omitempty"`
	Keg       string `json:"keg"`
	Role      string `json:"role"`
}

type HubGrant added in v0.23.0

type HubGrant struct {
	Username string `json:"username"`
	Role     string `json:"role"` // viewer|editor|admin
}

HubGrant is one per-(user, role) grant on a keg. Mirrors the hub's handler.ListGrants JSON body — keep the two in sync. (granted_at is sent by the hub but unused here.)

func ListGrants added in v0.23.0

func ListGrants(ctx context.Context, hubURL, token, namespace, alias string) ([]HubGrant, error)

ListGrants returns the grants on @namespace/alias via GET /api/v1/@{namespace}/kegs/{keg}/grants (admin-only on the hub).

type HubInfo added in v0.23.0

type HubInfo struct {
	Name      string
	URL       string
	Kind      string
	IsDefault bool
	Source    string // "user" or "built-in"
}

HubInfo describes a configured hub for `tap hub list`.

type HubKeg added in v0.23.0

type HubKeg struct {
	Namespace  string `json:"namespace"`
	Alias      string `json:"alias"`
	Title      string `json:"title"`
	Summary    string `json:"summary"`
	Visibility string `json:"visibility"`
	Role       string `json:"role"`
}

HubKeg is one keg the hub reports the authenticated user can reach. It mirrors the hub's handler.UserKegItem JSON body — keep the two in sync.

func ListUserKegs added in v0.23.0

func ListUserKegs(ctx context.Context, hubURL, token string) ([]HubKeg, error)

ListUserKegs returns every keg the hub reports the bearer token can reach (namespace membership + grants) via GET /api/v1/kegs.

type HubListOptions added in v0.23.0

type HubListOptions struct {
	Hub string
}

HubListOptions selects which hub to enumerate. An empty Hub aggregates every configured hub the user can reach.

type HubMember added in v0.23.0

type HubMember struct {
	Username string `json:"username"`
	Role     string `json:"role"` // owner|admin|member
}

HubMember is one namespace membership row. Mirrors the hub's handler.memberWire JSON body — keep the two in sync.

func ListNamespaceMembers added in v0.23.0

func ListNamespaceMembers(ctx context.Context, hubURL, token, namespace string) ([]HubMember, error)

ListNamespaceMembers returns the member roster of a namespace via GET /api/v1/@{namespace}/members.

type HubNamespace added in v0.23.0

type HubNamespace struct {
	Name string `json:"name"`
	Kind string `json:"kind,omitempty"` // user|org
	Role string `json:"role,omitempty"` // caller's role

	// Hub names the configured hub this row came from. It is filled in
	// locally by NamespaceList, not by the hub, so identical namespace names
	// on different hubs stay distinguishable. Not part of namespaceWire.
	Hub string `json:"hub,omitempty"`
}

HubNamespace is one namespace the caller belongs to (or just created). Mirrors the hub's handler.namespaceWire JSON body — keep the two in sync.

func CreateNamespace deprecated added in v0.23.0

func CreateNamespace(ctx context.Context, hubURL, token, name string) (*HubNamespace, error)

CreateNamespace is disabled for remote clients. Namespace creation is a paid hub UI flow; use Tap.NamespaceCreate to get the browser handoff URL.

Deprecated: remote namespace creation is not supported.

func ListNamespaces added in v0.23.0

func ListNamespaces(ctx context.Context, hubURL, token string) ([]HubNamespace, error)

ListNamespaces returns the namespaces the caller belongs to via GET /api/v1/namespaces.

type HubRemoveOptions added in v0.23.0

type HubRemoveOptions struct {
	Name string
}

HubRemoveOptions removes a hub connection from user config.

type HubSetDefaultOptions added in v0.23.0

type HubSetDefaultOptions struct {
	Name string
	User bool
}

HubSetDefaultOptions sets the default hub. It writes project config by default and user config with User=true (mirroring `tap config edit`).

type ImportOptions added in v0.4.0

type ImportOptions struct {
	KegTargetOptions
	Input string
}

type IndexCatOptions added in v0.2.0

type IndexCatOptions struct {
	KegTargetOptions

	// Name is the index file name to dump, e.g. "changes.md" or "nodes.tsv".
	// A leading "dex/" prefix is stripped automatically.
	Name string
}

type IndexOptions

type IndexOptions struct {
	KegTargetOptions

	// NoUpdate skips updating node meta information
	NoUpdate bool
}

type InfoOptions

type InfoOptions struct {
	KegTargetOptions

	// JSON renders the diagnostics as JSON instead of YAML.
	JSON bool

	// Debug includes working-directory and backend resolution diagnostics.
	Debug bool
}

InfoOptions configures behavior for Tap.Info.

type InitOptions

type InitOptions struct {
	Namespace  string
	Hub        string
	Title      string
	Keg        string
	Visibility string

	// RequireBootstrap rejects config-driven creation until user setup exists.
	RequireBootstrap bool
}

InitOptions configures creation of a KEG on a configured remote hub.

type IntegrateOptions added in v0.19.0

type IntegrateOptions struct {
	KegTargetOptions
	Host    string
	DryRun  bool
	Plugins []string
	Scope   string
}

IntegrateOptions selects the host, native install scope, dry-run behavior, and optional plugins for native plugin installation. The baseline tapper plugin is always installed.

type IntegrateResult added in v0.30.0

type IntegrateResult struct {
	Root     string
	Paths    []string
	Commands [][]string
}

IntegrateResult describes the extracted marketplace and the host commands used to inspect, register, and install it.

type InvocationEvent added in v0.34.0

type InvocationEvent struct {
	Surface       string `json:"surface"`
	Command       string `json:"command,omitempty"`
	Tool          string `json:"tool,omitempty"`
	DurationMS    int64  `json:"duration_ms"`
	Success       bool   `json:"success"`
	Interactive   *bool  `json:"interactive,omitempty"`
	ClientVersion string `json:"client_version"`
	Agent         string `json:"agent,omitempty"`
}

InvocationEvent is the privacy-minimized shape accepted by the Tapper Hub invocation telemetry endpoint. Callers must set exactly one of Command or Tool according to Surface. ClientVersion and Agent are injected by the reporter.

Agent is the configured `tap launch` agent alias driving the process, empty when a human is. It is a user-chosen label, not an identifier, and separates agent-driven usage from human usage in aggregate.

type InvocationReporter added in v0.34.0

type InvocationReporter interface {
	// Report queues an event without blocking and may drop it under pressure.
	Report(InvocationEvent)
	// Close waits for a bounded final flush until ctx is done.
	Close(context.Context)
}

InvocationReporter accepts best-effort telemetry without blocking the caller. Close gives queued events a bounded final flush.

func NewInvocationReporter added in v0.34.0

func NewInvocationReporter(rt *toolkit.Runtime, configService *ConfigService, version string) InvocationReporter

NewInvocationReporter resolves the user-scope reporting destination and existing AuthStore token. It returns nil when telemetry is disabled or the client is not bootstrapped, authenticated, or configured with a remote hub.

type Issue added in v0.5.0

type Issue = keg.DoctorIssue

Issue represents a single problem found during a doctor check.

type KegGrantOptions added in v0.23.0

type KegGrantOptions struct {
	Keg       string
	Namespace string
	Hub       string
	User      string
	Role      string // viewer|editor|admin
}

KegGrantOptions upserts a grant on a keg.

type KegGrantsOptions added in v0.23.0

type KegGrantsOptions struct {
	Keg       string
	Namespace string
	Hub       string
}

KegGrantsOptions selects the keg whose grants to list. Keg is the selector (a bare name or @namespace/keg); empty resolves the default keg. Namespace and Hub override the resolved reference's components.

type KegMapEntry

type KegMapEntry struct {
	Alias      string `yaml:"alias,omitempty"`
	PathPrefix string `yaml:"pathPrefix,omitempty"`
	PathRegex  string `yaml:"pathRegex,omitempty"`
}

KegMapEntry is an entry mapping a path prefix or regex to a keg alias.

type KegRef added in v0.23.0

type KegRef struct {
	Hub       string `yaml:"hub,omitempty"`
	Namespace string `yaml:"namespace,omitempty"`
	Name      string `yaml:"name,omitempty"`
}

KegRef is the (hub, namespace, name) triple a keg alias resolves to. An empty Hub falls back to defaultHub/fallbackHub; an empty Namespace falls back to defaultNamespace/fallbackNamespace (see Config.ResolveRef).

func (*KegRef) UnmarshalYAML added in v0.23.0

func (r *KegRef) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML accepts the canonical mapping form ({hub, namespace, name}) and remote scalar shorthand. The canonical shorthand "keg:@ns/name" sets {namespace, name}; the hub is resolved from the namespace and is never encoded. To pin a hub, use the mapping form's "hub" field. Writes always serialize the canonical mapping form.

type KegRenameOptions added in v0.25.0

type KegRenameOptions struct {
	Old       string
	New       string
	Namespace string
	Hub       string
}

KegRenameOptions renames a hub-backed keg alias within one namespace.

type KegRevokeOptions added in v0.23.0

type KegRevokeOptions struct {
	Keg       string
	Namespace string
	Hub       string
	User      string
}

KegRevokeOptions revokes a user's grant on a keg.

type KegService

type KegService struct {
	Runtime       *toolkit.Runtime
	ConfigService *ConfigService
	// contains filtered or unexported fields
}

KegService resolves configured remote KEGs.

func (*KegService) ReloadAuthStore added in v0.40.0

func (s *KegService) ReloadAuthStore()

ReloadAuthStore drops the cached credential store so the next resolution reads it back from disk.

The store is otherwise loaded once per process. A `tap auth login` run in a separate shell writes a new token to disk that a long-lived MCP server would never see, so telling an agent to log in and reorient was advice that could not work (tapper#87). Orientation is already the reload boundary for configuration; this puts credentials on the same boundary.

func (*KegService) Resolve

func (s *KegService) Resolve(ctx context.Context, options ResolveKegOptions) (keg.Keg, error)

Resolve returns a RemoteKeg selected by an explicit reference or config.

type KegSettingsEditOptions added in v0.39.0

type KegSettingsEditOptions struct {
	KegTargetOptions
	Stream       *toolkit.Stream
	ExpectedHash string
}

KegSettingsEditOptions configures behavior for Tap.KegSettingsEdit.

type KegSettingsOptions added in v0.33.0

type KegSettingsOptions struct {
	KegTargetOptions

	// Kegs requests one or more canonical @namespace/keg references. It is
	// mutually exclusive with Keg and is available only in minimal mode.
	Kegs []string

	// Minimal strips large sections (tags, entities, indexes) from the output,
	// returning only core config fields. Useful for MCP tools where response
	// size must stay small.
	Minimal bool
}

KegSettingsOptions configures behavior for Tap.KegSettings.

type KegTargetOptions

type KegTargetOptions struct {
	// Keg is the keg selector: a bare name or an @namespace/keg reference.
	Keg string

	// Namespace overrides the namespace the keg resolves in when Keg is a bare
	// name (it loses to an @namespace/ already present in Keg). Empty means use
	// the configured defaultNamespace/fallbackNamespace chain.
	Namespace string

	// Hub pins the hub the keg resolves on, overriding namespace→hub resolution.
	// Empty means resolve the hub from the namespace as usual.
	Hub string

	// Flight is optional task context that can restrict which kegs are available
	// and injects agent instructions. It composes with the single-keg selectors
	// (Keg/Namespace/Hub): the selector picks a keg and the flight gates it unless
	// BypassFlightRestrictions is true.
	Flight string

	// FlightContext is the immutable, already-resolved flight snapshot used by
	// an MCP session. When set it is authoritative over Flight and avoids
	// consulting the process-wide flight cache while a tool call is running.
	// Direct CLI callers leave this nil.
	FlightContext *Flight

	// BypassFlightRestrictions skips flight cover and role-cap checks while
	// preserving Flight for callers that still need the flight context, such as
	// orient. Leave false for MCP and other agent-facing surfaces.
	BypassFlightRestrictions bool

	// RequireBootstrap makes config-driven resolution fail with
	// ErrNotBootstrapped when no user config exists. Set by the full `tap`
	// surface and the MCP server; direct Tap API callers may leave it false.
	RequireBootstrap bool
}

KegTargetOptions describes how a command should resolve a keg target.

type KegVisibilityOptions added in v0.23.0

type KegVisibilityOptions struct {
	Keg        string
	Namespace  string
	Hub        string
	Visibility string // public|private
}

KegVisibilityOptions sets a keg's visibility.

type LaunchOptions added in v0.37.0

type LaunchOptions struct {
	// Harness names the agent CLI to start: claude, codex, or pi.
	Harness string
	// Agent names an entry in the config's agents map. Empty falls back to the
	// config's agent key (which TAP_AGENT also feeds).
	Agent string
	// Flight is the explicit launch root. Empty falls back through TAP_FLIGHT,
	// project configuration, and user configuration.
	Flight string
	// DryRun resolves and reports the invocation without executing it.
	DryRun bool
	// Args are extra arguments appended to the harness invocation.
	Args []string
}

LaunchOptions configures behavior for Tap.Launch.

type LaunchResult added in v0.37.0

type LaunchResult struct {
	Harness   string
	Agent     string
	Provider  string
	Model     string
	BaseURL   string
	Flight    string
	Auth      string
	Argv      []string
	Env       map[string]string
	StripEnv  []string
	KeySource string
	Warnings  []string
}

LaunchResult reports the resolved invocation. Env holds only the overlay applied on top of the inherited environment; StripEnv names variables removed from it. Neither contains a secret value — a forwarded key is reported by the variable it came from.

Flight is the canonical connection-pinned Hub-backed root exported to the child as TAP_FLIGHT. It is empty when no flight is configured; the harness then runs under no-flight identity authority and Warnings says so.

Warnings are returned rather than printed so a dry run and a real run report the same thing — see ResolveLaunch.

type LinksOptions added in v0.5.0

type LinksOptions struct {
	KegTargetOptions

	// NodeIDs are the source nodes to inspect outgoing links for.
	// Results from all node IDs are merged and deduplicated.
	NodeIDs []string

	// Format is the output template. Legacy verbs %i (id), %t (title),
	// %d (updated), %c (created), %a (accessed) remain supported, and %%
	// renders a literal percent. Named selectors use %{...}: a bare word
	// names a metadata key (%{type}), a leading dot names a statistics field
	// (%{.accessCount}), and %{tags} is the tag list. Selectors other than
	// id, title, and the three dates cost one read per node.
	Format string

	IdOnly bool

	Reverse bool

	// Limit caps the number of results returned. 0 means no limit.
	Limit int

	// Offset skips the first N results before applying limit. Must be >= 0.
	Offset int
}

type ListFilesOptions added in v0.2.0

type ListFilesOptions struct {
	KegTargetOptions
	NodeID string
}

type ListFlightsOptions added in v0.23.0

type ListFlightsOptions struct {
	// Hub limits discovery to one configured hub. Empty discovers flights across
	// every configured hub.
	Hub string
	// Warnings, when non-nil, collects one message per hub that was skipped
	// (missing token, network failure) instead of failing the whole listing.
	// Completion paths leave it nil so discovery stays silent and best-effort.
	Warnings *[]string
}

ListFlightsOptions controls Tap.ListFlights. Flights are hub-scoped, so there is no keg target.

type ListImagesOptions added in v0.2.0

type ListImagesOptions struct {
	KegTargetOptions
	NodeID string
}

ListImagesOptions configures behavior for Tap.ListImages.

type ListOptions

type ListOptions struct {
	KegTargetOptions

	// Query is an optional boolean expression that filters nodes. Supports both
	// plain tag names ("golang") and key=value attribute predicates
	// ("entity=plan"). When empty, all nodes are listed.
	Query string

	// Format is the output template. Legacy verbs %i (id), %t (title),
	// %d (updated), %c (created), %a (accessed) remain supported, and %%
	// renders a literal percent. Named selectors use %{...}: a bare word
	// names a metadata key (%{type}), a leading dot names a statistics field
	// (%{.accessCount}), and %{tags} is the tag list. Selectors other than
	// id, title, and the three dates cost one read per node.
	Format string

	IdOnly bool

	Reverse bool

	// Sort selects the sort order. Empty string means sort by node ID (default).
	Sort ListSortType

	// Limit caps the number of results returned. 0 means no limit.
	Limit int

	// Offset skips the first N results before applying limit. Must be >= 0.
	Offset int
}

type ListSortType added in v0.5.0

type ListSortType string

ListSortType controls the ordering of listed nodes.

const (
	SortByDefault  ListSortType = ""         // default: same as SortByID
	SortByID       ListSortType = "id"       // ascending node ID
	SortByUpdated  ListSortType = "updated"  // ascending by last-updated timestamp
	SortByCreated  ListSortType = "created"  // ascending by creation timestamp
	SortByAccessed ListSortType = "accessed" // ascending by last-accessed timestamp
)

type LockOptions added in v0.11.0

type LockOptions struct {
	NodeID string
	KegTargetOptions
}

LockOptions configures behavior for Tap.Lock.

type LockStatusOptions added in v0.11.0

type LockStatusOptions struct {
	NodeID string
	KegTargetOptions
}

LockStatusOptions configures behavior for Tap.LockStatus.

type MetaOptions

type MetaOptions struct {
	// NodeID is the node identifier to inspect (e.g., "0", "42")
	NodeID string

	KegTargetOptions

	// LockToken is an optional cross-process lock token. When provided, the
	// command validates it against any held lock before proceeding.
	LockToken string
	Schema    string

	// Edit opens metadata in the editor.
	Edit bool

	// Stream carries stdin piping information.
	Stream *toolkit.Stream
}

MetaOptions configures behavior for Tap.Meta.

type MoveOptions

type MoveOptions struct {
	KegTargetOptions

	SourceID     string
	DestID       string
	ExpectedHash string
}

type NamespaceAddMemberOptions added in v0.23.0

type NamespaceAddMemberOptions struct {
	Namespace string
	Hub       string
	User      string
	Role      string // owner|admin|member
}

NamespaceAddMemberOptions upserts a member into a namespace.

type NamespaceCreateOptions added in v0.23.0

type NamespaceCreateOptions struct {
	Name string
	Hub  string
}

NamespaceCreateOptions creates an org namespace.

type NamespaceCreateResult added in v0.23.0

type NamespaceCreateResult struct {
	Name string
	Hub  string
	URL  string
}

NamespaceCreateResult tells the caller where to create the namespace in the hub UI. Namespace creation is a paid hub feature, so the CLI/MCP surface hands the user to the browser instead of calling the API.

type NamespaceListOptions added in v0.23.0

type NamespaceListOptions struct {
	Hub string
}

NamespaceListOptions selects which hub to query for namespaces. An empty Hub aggregates every configured hub the user can reach.

type NamespaceListResult added in v0.40.0

type NamespaceListResult struct {
	Namespaces []HubNamespace
	Warnings   []string
}

NamespaceListResult carries the aggregated rows plus a note for each hub that could not be reached. Warnings are non-fatal by design: one unreachable hub must not blank out the namespaces the others returned.

type NamespaceMembersOptions added in v0.23.0

type NamespaceMembersOptions struct {
	Namespace string
	Hub       string
}

NamespaceMembersOptions selects the namespace whose members to list. Namespace is the selector; empty resolves the default namespace. Hub pins the hub.

type NamespaceRef added in v0.23.0

type NamespaceRef struct {
	Hub string `yaml:"hub,omitempty"`
}

NamespaceRef names the hub that hosts a namespace. It is the conflict resolver for namespace→hub: when a namespace could live on more than one configured hub, an entry here pins which one. An empty Hub falls back to the hub precedence chain (see Config.resolveHubForNamespace).

func (*NamespaceRef) UnmarshalYAML added in v0.23.0

func (r *NamespaceRef) UnmarshalYAML(node *yaml.Node) error

UnmarshalYAML accepts the canonical mapping form ({hub: name}) and the scalar shorthand (a bare hub name), so both `jlrickert: atlas` and `jlrickert: {hub: atlas}` load. Writes always serialize the mapping form.

type NamespaceRemoveMemberOptions added in v0.23.0

type NamespaceRemoveMemberOptions struct {
	Namespace string
	Hub       string
	User      string
}

NamespaceRemoveMemberOptions removes a member from a namespace.

type NamespaceSetRoleOptions added in v0.23.0

type NamespaceSetRoleOptions struct {
	Namespace string
	Hub       string
	User      string
	Role      string // owner|admin|member
}

NamespaceSetRoleOptions changes an existing member's role.

type NodeHistoryOptions added in v0.4.0

type NodeHistoryOptions struct {
	KegTargetOptions
	NodeID string
}

type NodeRestoreOptions added in v0.4.0

type NodeRestoreOptions struct {
	KegTargetOptions
	NodeID string
	Rev    string
}

type NodeSnapshotOptions added in v0.4.0

type NodeSnapshotOptions struct {
	KegTargetOptions
	NodeID  string
	Message string
}

type NodeSnapshotViewOptions added in v0.23.0

type NodeSnapshotViewOptions struct {
	KegTargetOptions
	NodeID string
	Rev    string
}

type OrientOptions added in v0.19.0

type OrientOptions struct {
	KegTargetOptions
}

OrientOptions is the input to Tap.Orient. Flight is the only selector used by orientation; the embedded target options remain for CLI profile compatibility and are intentionally absent from the MCP input.

type OrientationAuthority added in v0.39.0

type OrientationAuthority struct {
	Root             *Flight
	Active           *Flight
	Path             []string
	AvailableFlights []string
	Revision         string
	FullAccess       bool
}

OrientationAuthority describes the connection-pinned launch root and the flight selected from its live transitive graph for this call.

type OrientationKeg added in v0.35.0

type OrientationKeg struct {
	Ref        string
	Namespace  string
	Alias      string
	Title      string
	Summary    string
	Role       string
	Source     string
	Visibility string
	FlightCap  string
	Flights    []string
}

OrientationKeg is one effective KEG exposed by an orientation context.

func ProjectOrientationKegs added in v0.39.0

func ProjectOrientationKegs(flight *Flight, rows []OrientationKeg) []OrientationKeg

ProjectOrientationKegs applies one flight's cover to a previously loaded identity projection. The returned rows retain the identity role and record the independent flight cap so callers can compute the lesser effective role.

type PathService

type PathService struct {
	*appctx.AppPaths
}

func NewPathService

func NewPathService(rt *toolkit.Runtime, root string) (*PathService, error)

func (*PathService) AuthStorePath added in v0.20.0

func (s *PathService) AuthStorePath() string

AuthStorePath returns the on-disk location of the hub-auth credentials store. The file is stored under StateRoot (not ConfigRoot) because it holds mutable per-host tokens rather than user-edited configuration.

func (*PathService) Project

func (s *PathService) Project() string

func (*PathService) ProjectConfig

func (s *PathService) ProjectConfig() string

func (*PathService) UserConfig

func (s *PathService) UserConfig() string

type ReadImageOptions added in v0.24.0

type ReadImageOptions struct {
	KegTargetOptions
	NodeID string
	Name   string
}

ReadImageOptions configures behavior for Tap.ReadImage.

type RefContext added in v0.23.0

type RefContext struct {
	CurrentKeg keg.Keg
}

RefContext carries the "current keg" so a node reference can resolve a keg-local alias against that keg's Links table and imply the hub for a qualified reference from the current keg's hub.

type RemoveOptions

type RemoveOptions struct {
	KegTargetOptions

	// NodeIDs lists explicit node IDs to remove.
	NodeIDs []string

	// Query is an optional boolean expression (tags and/or key=value attr
	// predicates) that selects additional nodes to remove.
	Query string

	ExpectedHash   string
	ExpectedHashes map[string]string
}

type ResolveKegOptions

type ResolveKegOptions struct {
	// Root is used only for workspace kegMap matching.
	Root      string
	Keg       string
	Namespace string
	Hub       string

	RequireBootstrap bool
	NoCache          bool
}

ResolveKegOptions controls remote KEG resolution.

type SchemaOptions added in v0.25.0

type SchemaOptions struct {
	KegTargetOptions
	Type         string
	Data         []byte
	ExpectedHash string
}

type StatsOptions

type StatsOptions struct {
	// NodeID is the node identifier to inspect (e.g., "0", "42")
	NodeID string

	KegTargetOptions
}

type TagsOptions

type TagsOptions struct {
	KegTargetOptions

	// Query is an optional boolean expression that filters nodes. Supports both
	// plain tag names ("golang") and key=value attribute predicates
	// ("entity=plan"). When empty, all tags are listed.
	Query string

	// Format is the output template. Legacy verbs %i (id), %t (title),
	// %d (updated), %c (created), %a (accessed) remain supported, and %%
	// renders a literal percent. Named selectors use %{...}: a bare word
	// names a metadata key (%{type}), a leading dot names a statistics field
	// (%{.accessCount}), and %{tags} is the tag list. Selectors other than
	// id, title, and the three dates cost one read per node.
	Format string

	IdOnly bool

	Reverse bool

	// Limit caps the number of results returned. 0 means no limit.
	Limit int

	// Offset skips the first N results before applying limit. Must be >= 0.
	Offset int
}

type Tap

type Tap struct {
	Root string
	// Runtime carries process-level dependencies.
	Runtime *toolkit.Runtime

	PathService   *PathService
	ConfigService *ConfigService
	KegService    *KegService
	FlightService *FlightService

	// AuthValidateFn is the seam AuthStatus uses for its live whoami probe.
	// Defaulted to ValidateToken in NewTap; tests override it (or point the
	// hub at an httptest server) to avoid real network I/O. Both the CLI and
	// MCP surfaces share the same *Tap, so overriding it covers both.
	AuthValidateFn func(ctx context.Context, rt *toolkit.Runtime, hubURL, token string) (*WhoAmI, error)

	// KegResolver, when non-nil, overrides config-driven keg resolution. It is
	// the seam tapper-hub uses to serve a per-user MCP connector: the hub injects
	// a resolver that opens kegs from its own Postgres catalog and enforces the
	// caller's role, bypassing the on-disk config cascade and AuthStore entirely
	// (which, in the hub server's process, hold no login). role is the access
	// level the calling operation needs — FlightRoleViewer for reads and
	// FlightRoleEditor for writes — so the resolver can map it to a catalog role
	// check. Admin-class flight operations may use a different flight cap while
	// retaining an editor identity requirement. Every node read/write op funnels
	// through resolveKegForRole, so a
	// single resolver covers the whole surface. Left nil for the CLI, which keeps
	// the standard config-driven resolution.
	KegResolver func(ctx context.Context, opts KegTargetOptions, role FlightRole) (keg.Keg, error)
}

func NewTap

func NewTap(opts TapOptions) (*Tap, error)

func (*Tap) ActiveAgentName added in v0.37.0

func (t *Tap) ActiveAgentName() string

ActiveAgentName reports the agent driving this process, or "" when none is selected. Like ActiveFlightName it is a pure read of the current snapshot; the value only changes when a caller reloads.

func (*Tap) ActiveFlightName added in v0.30.0

func (t *Tap) ActiveFlightName(explicit string) string

ActiveFlightName resolves an explicit flight, falling back to the flight in the process configuration snapshot. It is a pure read: it neither writes configuration nor reloads it, so callers that need a fresh cascade call ConfigService.Reload at their own boundary (see Orient and the MCP session gate).

func (*Tap) AuthLogout added in v0.20.0

func (t *Tap) AuthLogout(ctx context.Context, opts AuthLogoutOptions) (*AuthLogoutResult, error)

AuthLogout removes the cached credential for a hub from the on-disk auth store. Unlike AuthStatus this method is intentionally NOT exposed over MCP — an agent should never be able to yank a user's hub token out from under them. The CLI surface is the only consumer.

Resolution precedence mirrors AuthStatus:

  1. Hub set → canonicalize and delete that hub.
  2. Hub empty AND single hub stored → auto-resolve to that hub.
  3. Hub empty AND zero hubs stored → soft-success, "No hub logins stored.".
  4. Hub empty AND multiple hubs stored → error (caller must pick).

Missing entries (hub was provided but not stored) are NOT errors — they return Result{Removed: false} with a clear Formatted line. The command is idempotent by design so cleanup scripts can re-run without special-casing the already-logged-out state.

func (*Tap) AuthRefreshAll added in v0.28.1

func (t *Tap) AuthRefreshAll(ctx context.Context)

AuthRefreshAll renews every stored hub credential whose access token is expired or within refreshSkew of expiring, persisting the rotated pairs. Entries without a refresh token (pasted API tokens) or without a known expiry are skipped. Best-effort by design: failures are logged at debug and never returned — this runs on every CLI/MCP startup and a broken hub must not block unrelated commands. Cost when all tokens are fresh: one file read, zero network calls.

func (*Tap) AuthStatus added in v0.20.0

func (t *Tap) AuthStatus(ctx context.Context, opts AuthStatusOptions) (*AuthStatusResult, error)

AuthStatus reports the login status for a stored hub.

Resolution precedence:

  1. Empty store AND empty Hub → not-present, directed hint message.
  2. Hub set → canonicalize and look up exactly that hub.
  3. Hub empty AND one or more hubs stored → report every stored hub.

Missing entries (hub was provided but not stored) are NOT errors — they return a Result{Present: false} with a clear Formatted line. That keeps `tap auth status --hub X` usable from scripts without requiring caller-side error-matching.

func (t *Tap) Backlinks(ctx context.Context, opts BacklinksOptions) ([]string, error)

func (*Tap) Bootstrap added in v0.23.0

func (t *Tap) Bootstrap(ctx context.Context, opts BootstrapOptions) (*BootstrapResult, error)

Bootstrap creates or refreshes the user-level config for a chosen deployment kind so plain `tap` commands resolve without per-invocation flags. It writes the FALLBACK hub (the user/global convention — project config owns the high-precedence default* slots).

It does not write a global fallbackNamespace or a per-user namespace→hub entry: the preferred namespace comes from the resolved hub's own namespace field. It is the logged-in user's home namespace, adopted onto the hub after login by SetBootstrapNamespace.

It is idempotent: an existing config is loaded and only the fallback hub and the selected hub entry are touched, so extension fields and kegMap rules survive a re-run untouched.

func (*Tap) Cat

func (t *Tap) Cat(ctx context.Context, opts CatOptions) (string, error)

func (*Tap) CatViews added in v0.39.0

func (t *Tap) CatViews(ctx context.Context, opts CatOptions) ([]keg.NodeView, error)

CatViews returns the node views Cat renders, in caller order. It exists so callers needing structured per-node state — an agent reading the content hash it must echo back on its next write — do not have to parse Cat's formatted output. The editor and TTY delegation in Cat is deliberately absent: those paths are interactive and produce no views.

func (*Tap) Config

func (t *Tap) Config(opts ConfigOptions) (string, error)

Config displays the merged or project configuration.

func (*Tap) ConfigEdit

func (t *Tap) ConfigEdit(ctx context.Context, opts ConfigEditOptions) error

ConfigEdit edits the selected tap config file.

If stdin is piped with non-empty content, the piped YAML is validated and written directly without opening an editor. Otherwise the file is opened in the configured editor.

func (*Tap) ConfigExplain added in v0.17.0

func (t *Tap) ConfigExplain(ctx context.Context, opts ConfigExplainOptions) ([]ConfigExplainResult, error)

ConfigExplain returns provenance for config fields, showing which source set each value. It loads each tier individually and walks from most-specific to least-specific to determine the effective source.

func (*Tap) ConfigTemplate added in v0.4.0

func (t *Tap) ConfigTemplate(opts ConfigTemplateOptions) (string, error)

ConfigTemplate returns starter YAML for either user or project config.

func (*Tap) Create

func (t *Tap) Create(ctx context.Context, opts CreateOptions) (keg.NodeId, error)

func (*Tap) CreateBatch added in v0.38.0

func (t *Tap) CreateBatch(ctx context.Context, opts BatchCreateOptions) ([]keg.CreateNodeResult, error)

func (*Tap) CreateFlight added in v0.23.0

func (t *Tap) CreateFlight(ctx context.Context, opts CreateFlightOptions) (*Flight, error)

func (*Tap) CreateSchema added in v0.25.0

func (t *Tap) CreateSchema(ctx context.Context, opts SchemaOptions) error

func (*Tap) DeleteFile added in v0.2.0

func (t *Tap) DeleteFile(ctx context.Context, opts DeleteFileOptions) error

DeleteFile removes a file attachment from a node.

func (*Tap) DeleteFlight added in v0.23.0

func (t *Tap) DeleteFlight(ctx context.Context, opts DeleteFlightOptions) error

func (*Tap) DeleteImage added in v0.2.0

func (t *Tap) DeleteImage(ctx context.Context, opts DeleteImageOptions) error

DeleteImage removes an image from a node.

func (*Tap) DeleteSchema added in v0.25.0

func (t *Tap) DeleteSchema(ctx context.Context, opts SchemaOptions) error

func (*Tap) Doctor added in v0.5.0

func (t *Tap) Doctor(ctx context.Context, opts DoctorOptions) ([]Issue, error)

Doctor scans the resolved keg and reports health issues.

func (*Tap) DoctorConfig added in v0.17.0

func (t *Tap) DoctorConfig() []Issue

DoctorConfig validates the tapper configuration (not keg-level) and returns issues. This does not require a keg to be resolved.

func (*Tap) DownloadFile added in v0.2.0

func (t *Tap) DownloadFile(ctx context.Context, opts DownloadFileOptions) (string, error)

DownloadFile retrieves a node file attachment and writes it to a local path. Returns the destination path.

func (*Tap) DownloadImage added in v0.2.0

func (t *Tap) DownloadImage(ctx context.Context, opts DownloadImageOptions) (string, error)

DownloadImage retrieves a node image and writes it to a local path. Returns the destination path.

func (*Tap) Edit

func (t *Tap) Edit(ctx context.Context, opts EditOptions) error

Edit opens a node in an editor using a temporary file with frontmatter. Changes are sent back to the Hub as the editor saves.

The temp file format is:

---
<meta yaml>
---
<markdown body>

If stdin is piped, it seeds the content directly without opening an editor.

func (*Tap) EditBatch added in v0.38.0

func (t *Tap) EditBatch(ctx context.Context, opts BatchEditOptions) ([]keg.NodeUpdateResult, error)

func (*Tap) EditFlight added in v0.24.0

func (t *Tap) EditFlight(ctx context.Context, opts EditFlightOptions) (*Flight, error)

EditFlight edits a Hub-backed flight's manifest as YAML.

If stdin is piped with non-empty content, the piped manifest is validated and applied directly. Otherwise the manifest opens in the configured editor; every save is validated and PUT to the hub immediately, so the editor session behaves like the rest of tapper's live-save edit flows.

The manifest carries title, visibility, capabilities, cover, and instructions. The slug and namespace are fixed by the ref: the YAML document cannot express them, and a stray "slug" key is rejected as an unknown field.

func (*Tap) EditSchema added in v0.25.0

func (t *Tap) EditSchema(ctx context.Context, opts EditSchemaOptions) error

EditSchema replaces a schema definition. Schemas decide which node types are valid and how every write is checked, so defining them is keg administration rather than content editing — admin here, matching CreateSchema and DeleteSchema. Reading schemas stays viewer.

func (*Tap) Export added in v0.4.0

func (t *Tap) Export(ctx context.Context, opts ExportOptions) (string, error)

Export writes a keg-archive of the selected nodes (all nodes when none are named) to opts.OutputPath and returns the resolved output path.

func (*Tap) ForceUnlock added in v0.11.0

func (t *Tap) ForceUnlock(ctx context.Context, opts ForceUnlockOptions) error

ForceUnlock unconditionally removes a cross-process lock on a node.

func (*Tap) GetFlight added in v0.23.0

func (t *Tap) GetFlight(ctx context.Context, opts GetFlightOptions) (*Flight, error)

GetFlight loads a single flight by name.

func (*Tap) Grep

func (t *Tap) Grep(ctx context.Context, opts GrepOptions) ([]string, error)

func (*Tap) HubAdd added in v0.23.0

func (t *Tap) HubAdd(_ context.Context, opts HubAddOptions) error

HubAdd registers a remote hub connection. Hub entries may only live in USER config (the trust boundary strips hubs from project config), so this always writes the user config regardless of the working directory.

func (*Tap) HubList added in v0.23.0

func (t *Tap) HubList(_ context.Context) ([]HubInfo, error)

HubList returns the configured hubs (plus the synthesized built-ins when none are configured), marking the default and the config layer each came from. It inspects local config only — it does not contact any hub.

func (*Tap) HubListKegs added in v0.23.0

func (t *Tap) HubListKegs(ctx context.Context, opts HubListOptions) ([]string, error)

HubListKegs lists kegs qualified as "@namespace/keg". With no --hub it aggregates across every configured remote/readonly hub via the hub's GET /api/v1/kegs, which returns the kegs the authenticated user can reach (namespace membership + grants). With an explicit --hub only that hub is listed and its errors surface directly; in aggregate mode an unreachable or unauthenticated hub is logged and skipped so one bad hub doesn't blank the whole listing.

func (*Tap) HubRemove added in v0.23.0

func (t *Tap) HubRemove(_ context.Context, opts HubRemoveOptions) error

HubRemove deletes a hub connection (user config only) and prunes any namespace pin that routed to it.

func (*Tap) HubSetDefault added in v0.23.0

func (t *Tap) HubSetDefault(ctx context.Context, opts HubSetDefaultOptions) error

HubSetDefault sets defaultHub. Unlike the hubs map, defaultHub is allowed in project config, so the default write target is the project config, with --user to write the user config instead.

func (*Tap) IdentityKegCatalog added in v0.39.0

func (t *Tap) IdentityKegCatalog(ctx context.Context) ([]OrientationKeg, []string)

IdentityKegCatalog discovers the identity-authorized KEGs from every configured hub without applying flight authority. Each hub is queried at most once. Callers must explicitly project these rows through a selected flight or use them only for identity search.

func (*Tap) Import added in v0.4.0

func (t *Tap) Import(ctx context.Context, opts ImportOptions) ([]keg.NodeId, error)

Import loads a keg-archive from a file path or http(s) URL into the resolved keg and returns the imported node ids.

func (*Tap) Index

func (t *Tap) Index(ctx context.Context, opts IndexOptions) (string, error)

Index rebuilds all indices for a keg (nodes.tsv, tags, links, backlinks) from scratch.

func (*Tap) IndexCat added in v0.2.0

func (t *Tap) IndexCat(ctx context.Context, opts IndexCatOptions) (string, error)

IndexCat returns the raw contents of a named dex index file. opts.Name may include or omit a leading "dex/" prefix; both are accepted.

func (*Tap) Info

func (t *Tap) Info(ctx context.Context, opts InfoOptions) (string, error)

Info displays diagnostics for a resolved keg.

func (*Tap) InitKeg

func (t *Tap) InitKeg(ctx context.Context, options InitOptions) (*keg.Target, error)

InitKeg creates a KEG through the configured hub creation endpoint.

func (*Tap) Integrate added in v0.19.0

func (t *Tap) Integrate(ctx context.Context, opts IntegrateOptions) (*IntegrateResult, error)

Integrate atomically refreshes the embedded marketplace for one host, reuses a matching registration, and installs the requested plugins through the host CLI. Dry-run returns the complete plan without side effects.

func (*Tap) KegGrant added in v0.23.0

func (t *Tap) KegGrant(ctx context.Context, opts KegGrantOptions) error

KegGrant upserts a grant (user → role) on a keg.

func (*Tap) KegGrants added in v0.23.0

func (t *Tap) KegGrants(ctx context.Context, opts KegGrantsOptions) ([]HubGrant, error)

KegGrants lists the per-(user, role) grants on a keg.

func (*Tap) KegRename added in v0.25.0

func (t *Tap) KegRename(ctx context.Context, opts KegRenameOptions) error

KegRename renames a hub-backed keg alias within its namespace.

func (*Tap) KegRevoke added in v0.23.0

func (t *Tap) KegRevoke(ctx context.Context, opts KegRevokeOptions) error

KegRevoke removes a user's grant on a keg.

func (*Tap) KegSettings added in v0.33.0

func (t *Tap) KegSettings(ctx context.Context, opts KegSettingsOptions) (string, error)

KegSettings displays the keg metadata (keg file contents).

func (*Tap) KegSettingsEdit added in v0.39.0

func (t *Tap) KegSettingsEdit(ctx context.Context, opts KegSettingsEditOptions) error

KegSettingsEdit opens the keg settings file in the default editor.

Replacing the settings document is keg administration, so it requires admin on the keg itself and not merely admin on the flight. Asking for editor identity access here previously let a flightless session — which has no flight authority to check — perform the write with editor access alone.

func (*Tap) KegSettingsHash added in v0.39.0

func (t *Tap) KegSettingsHash(ctx context.Context, opts KegTargetOptions) (string, error)

KegSettingsHash performs the read half of an explicit CLI read-before-write flow. Mutation methods never call it implicitly.

func (*Tap) KegVisibility added in v0.23.0

func (t *Tap) KegVisibility(ctx context.Context, opts KegVisibilityOptions) error

KegVisibility sets a keg's visibility to public or private.

func (*Tap) Launch added in v0.37.0

func (t *Tap) Launch(ctx context.Context, opts LaunchOptions) (*LaunchResult, error)

Launch resolves the agent and starts the harness, wiring it to the runtime's streams so it runs interactively. With DryRun set it resolves and returns without executing.

Warnings are written to stderr here, before the harness takes the terminal. Reporting them from the returned result would be too late: Launch does not return until the agent session has ended, so the reader would learn what authority the session had only after it was over. Stderr also keeps them clear of a piped dry-run report.

func (t *Tap) Links(ctx context.Context, opts LinksOptions) ([]string, error)

func (*Tap) List

func (t *Tap) List(ctx context.Context, opts ListOptions) ([]string, error)

func (*Tap) ListFiles added in v0.2.0

func (t *Tap) ListFiles(ctx context.Context, opts ListFilesOptions) ([]string, error)

ListFiles returns the names of file attachments for a node.

func (*Tap) ListFlights added in v0.23.0

func (t *Tap) ListFlights(ctx context.Context, opts ListFlightsOptions) ([]string, error)

ListFlights returns canonical refs discovered across configured hubs, or only opts.Hub when a filter is supplied.

func (*Tap) ListImages added in v0.2.0

func (t *Tap) ListImages(ctx context.Context, opts ListImagesOptions) ([]string, error)

ListImages returns the names of images for a node.

func (*Tap) ListIndexes added in v0.2.0

func (t *Tap) ListIndexes(ctx context.Context, opts IndexCatOptions) ([]string, error)

ListIndexes returns the names of available index files for a keg (e.g. "changes.md", "nodes.tsv").

func (*Tap) ListSchemas added in v0.25.0

func (t *Tap) ListSchemas(ctx context.Context, opts SchemaOptions) ([]string, error)

func (*Tap) Lock added in v0.11.0

func (t *Tap) Lock(ctx context.Context, opts LockOptions) (keg.LockToken, error)

Lock acquires a cross-process lock on a node and returns the token.

func (*Tap) LockStatus added in v0.11.0

func (t *Tap) LockStatus(ctx context.Context, opts LockStatusOptions) (keg.LockInfo, error)

LockStatus returns the lock state for a node.

func (*Tap) LookupKeg

func (t *Tap) LookupKeg(ctx context.Context, kegAlias string) (keg.Keg, error)

func (*Tap) Meta

func (t *Tap) Meta(ctx context.Context, opts MetaOptions) (string, error)

func (*Tap) Move

func (t *Tap) Move(ctx context.Context, opts MoveOptions) error

func (*Tap) NamespaceAddMember added in v0.23.0

func (t *Tap) NamespaceAddMember(ctx context.Context, opts NamespaceAddMemberOptions) error

NamespaceAddMember upserts a member (user → role) into a namespace.

func (*Tap) NamespaceCreate added in v0.23.0

func (t *Tap) NamespaceCreate(ctx context.Context, opts NamespaceCreateOptions) (*NamespaceCreateResult, error)

NamespaceCreate returns the hub UI URL for creating an org namespace. It does not call the namespace creation API.

func (*Tap) NamespaceList added in v0.23.0

func (t *Tap) NamespaceList(ctx context.Context, opts NamespaceListOptions) (NamespaceListResult, error)

NamespaceList returns the namespaces the caller belongs to. With no --hub it aggregates across every configured hub rather than only the selected one, which previously hid memberships on every other hub and gave no way to tell which hub a row came from (tapper#73). Every row carries its source hub, so the same namespace name on two hubs stays two distinct rows.

With an explicit --hub only that hub is queried and its errors surface directly. In aggregate mode an unreachable or unauthenticated hub is recorded as a warning and skipped. This mirrors HubListKegs.

Local namespaces are not represented. Tapper has no local hub kind: config admits only remote and readonly, and every resolver rejects anything else.

func (*Tap) NamespaceMembers added in v0.23.0

func (t *Tap) NamespaceMembers(ctx context.Context, opts NamespaceMembersOptions) ([]HubMember, error)

NamespaceMembers returns the member roster of a namespace.

func (*Tap) NamespaceRemoveMember added in v0.23.0

func (t *Tap) NamespaceRemoveMember(ctx context.Context, opts NamespaceRemoveMemberOptions) error

NamespaceRemoveMember removes a member from a namespace.

func (*Tap) NamespaceSetRole added in v0.23.0

func (t *Tap) NamespaceSetRole(ctx context.Context, opts NamespaceSetRoleOptions) error

NamespaceSetRole changes an existing member's role.

func (*Tap) NodeHash added in v0.39.0

func (t *Tap) NodeHash(ctx context.Context, opts KegTargetOptions, rawID string) (string, error)

NodeHash performs the read half of an explicit CLI read-before-write flow. Mutation methods never call it implicitly.

func (*Tap) NodeHistory added in v0.4.0

func (t *Tap) NodeHistory(ctx context.Context, opts NodeHistoryOptions) ([]keg.Snapshot, error)

func (*Tap) NodeRestore added in v0.4.0

func (t *Tap) NodeRestore(ctx context.Context, opts NodeRestoreOptions) error

func (*Tap) NodeSnapshot added in v0.4.0

func (t *Tap) NodeSnapshot(ctx context.Context, opts NodeSnapshotOptions) (keg.Snapshot, error)

func (*Tap) NodeSnapshotBatch added in v0.38.0

func (t *Tap) NodeSnapshotBatch(ctx context.Context, opts BatchSnapshotOptions) ([]keg.Snapshot, error)

func (*Tap) NodeSnapshotView added in v0.23.0

func (t *Tap) NodeSnapshotView(ctx context.Context, opts NodeSnapshotViewOptions) ([]byte, error)

func (*Tap) Orient added in v0.19.0

func (t *Tap) Orient(ctx context.Context, opts OrientOptions) (string, error)

Orient returns one deterministic KEG system payload. It is best-effort: flight and hub-listing failures do not suppress the core orientation document.

func (*Tap) OrientationKegsForFlight added in v0.39.0

func (t *Tap) OrientationKegsForFlight(ctx context.Context, flight *Flight) ([]OrientationKeg, []string)

OrientationKegsForFlight returns the effective KEG authority projection without rendering a payload. Providers use it to compute the revision first and then render exactly once.

func (*Tap) ReadImage added in v0.24.0

func (t *Tap) ReadImage(ctx context.Context, opts ReadImageOptions) ([]byte, string, error)

ReadImage retrieves a node image and validates that the stored bytes are still one of Tapper's supported image formats.

func (*Tap) ReadSchema added in v0.25.0

func (t *Tap) ReadSchema(ctx context.Context, opts SchemaOptions) ([]byte, error)

func (*Tap) Remove

func (t *Tap) Remove(ctx context.Context, opts RemoveOptions) error

func (*Tap) ResolveLaunch added in v0.37.0

func (t *Tap) ResolveLaunch(opts LaunchOptions) (*LaunchResult, error)

ResolveLaunch resolves options into a complete invocation without running it. Launch is this plus execution, so a dry run and a real run cannot drift.

func (*Tap) ResolveNodeRef added in v0.23.0

func (t *Tap) ResolveNodeRef(ctx context.Context, ref *keg.NodeRef, rc RefContext) (keg.Keg, keg.NodeId, error)

ResolveNodeRef resolves a parsed node reference into the keg that holds it and the numeric node id within that keg:

  • RefLocal: the current keg, with the bare node id.
  • RefAlias: the alias is resolved against the current keg's Links table first (so authored links travel with the keg), then the Tapper configuration.
  • RefQualified: a (hub, namespace, keg) reference whose hub is implied from the current keg's hub.

func (*Tap) SchemaHash added in v0.39.0

func (t *Tap) SchemaHash(ctx context.Context, opts SchemaOptions) (string, error)

SchemaHash performs the read half of an explicit CLI read-before-write flow. Mutation methods never call it implicitly.

func (*Tap) SetBootstrapFlight added in v0.30.0

func (t *Tap) SetBootstrapFlight(ctx context.Context, ref string) error

SetBootstrapFlight validates ref, canonicalizes it, and persists it as the user-level flight baseline. Project config, TAP_FLIGHT, and an explicit --flight flag remain higher-precedence overrides. A blank ref is a no-op.

func (*Tap) SetBootstrapNamespace added in v0.23.0

func (t *Tap) SetBootstrapNamespace(ctx context.Context, hubName, namespace string) error

SetBootstrapNamespace adopts namespace as the named hub's default namespace, then persists the config. It is the post-login step of `tap bootstrap`: once a cloud/enterprise login resolves the authenticated user's home namespace (from the hub's whoami probe), the CLI calls this so plain references resolved against that hub land in the user's own namespace. The namespace lives on the hub entry so each hub carries its own default — there is no global fallbackNamespace and no per-user namespace→hub entry to maintain.

It is idempotent and a no-op when namespace is blank, or when hubName is unknown/blank (nothing to adopt onto), keeping the call safe in either case.

func (*Tap) SetFallbackKeg added in v0.23.0

func (t *Tap) SetFallbackKeg(ctx context.Context, ref string) error

SetFallbackKeg sets the user config's fallbackKeg to ref and persists it. It is the post-login step of `tap bootstrap`: once the user picks a keg (from the hub's list or by typing one), plain `tap` commands resolve it without per-invocation flags. It writes the FALLBACK slot (the global-user convention) rather than defaultKeg, so a project's defaultKeg or a kegMap path rule still overrides it. ref is a keg reference — a bare name, @namespace/name, keg:..., or a path — stored verbatim and resolved later by ResolveRef. A blank ref is a no-op.

func (*Tap) SetHubDefaultNamespaceByURL added in v0.23.0

func (t *Tap) SetHubDefaultNamespaceByURL(ctx context.Context, hubURL, namespace string) (string, error)

SetHubDefaultNamespaceByURL adopts namespace onto the configured hub whose URL matches hubURL. It returns the hub name that was updated. When no configured hub matches (for example, auth login fell through to the compiled-in atlas URL without a user config entry), it is a no-op.

func (*Tap) Stats

func (t *Tap) Stats(ctx context.Context, opts StatsOptions) (string, error)

func (*Tap) Tags

func (t *Tap) Tags(ctx context.Context, opts TagsOptions) ([]string, error)

func (*Tap) Unlock added in v0.11.0

func (t *Tap) Unlock(ctx context.Context, opts UnlockOptions) error

Unlock releases a cross-process lock on a node.

func (*Tap) UpdateFlight added in v0.23.0

func (t *Tap) UpdateFlight(ctx context.Context, opts UpdateFlightOptions) (*Flight, error)

func (*Tap) UploadFile added in v0.2.0

func (t *Tap) UploadFile(ctx context.Context, opts UploadFileOptions) (string, error)

UploadFile reads a local file and stores it as a node file attachment. Returns the stored filename.

func (*Tap) UploadImage added in v0.2.0

func (t *Tap) UploadImage(ctx context.Context, opts UploadImageOptions) (string, error)

UploadImage reads a local file and stores it as a node image. Returns the stored filename.

func (*Tap) Use added in v0.23.0

func (t *Tap) Use(ctx context.Context, opts UseOptions) error

Use records the project's keg + flight, or the user-wide fallback keg, in the appropriate config file. It mirrors the resolution convention: project → defaultKeg, user → fallbackKeg, with flight project-scoped.

func (*Tap) UseStatus added in v0.23.0

func (t *Tap) UseStatus(_ context.Context, opts KegTargetOptions) (string, error)

UseStatus returns a YAML summary of the resolved keg/flight context plus the configured keg slots and the scope that set each, for `tap use` with no args.

func (*Tap) Validate added in v0.25.0

func (t *Tap) Validate(ctx context.Context, opts ValidateOptions) ([]keg.SchemaValidationResult, error)

func (*Tap) WatchNode added in v0.23.0

func (t *Tap) WatchNode(ctx context.Context, opts WatchNodeOptions) (<-chan keg.NodeEvent, error)

WatchNode subscribes to live change events for a single node. The watch is scoped to ctx: events are delivered on the returned channel until ctx is cancelled, at which point the channel is closed.

type TapOptions

type TapOptions struct {
	Root       string
	ConfigPath string
	Runtime    *toolkit.Runtime
}

type UnlockOptions added in v0.11.0

type UnlockOptions struct {
	NodeID string
	Token  string
	KegTargetOptions
}

UnlockOptions configures behavior for Tap.Unlock.

type UpdateFlightOptions added in v0.23.0

type UpdateFlightOptions struct {
	Ref          string
	Title        *string
	Visibility   *string
	Capabilities *[]FlightCapability
	Instructions *string
	Cover        *[]FlightCover
	Subflights   *[]string
	ExpectedHash string
}

UpdateFlightOptions is a partial update: nil fields keep the flight's current value. The merge against the existing flight happens inside Tap.UpdateFlight against the same resolved ref the PUT targets, so a slug that exists in several places cannot read one flight and overwrite another.

type UploadFileOptions added in v0.2.0

type UploadFileOptions struct {
	KegTargetOptions
	NodeID   string
	FilePath string
	Data     []byte
	Name     string
}

UploadFileOptions configures behavior for Tap.UploadFile.

type UploadImageOptions added in v0.2.0

type UploadImageOptions struct {
	KegTargetOptions
	NodeID   string
	FilePath string
	Data     []byte
	Name     string
}

UploadImageOptions configures behavior for Tap.UploadImage.

type UseOptions added in v0.23.0

type UseOptions struct {
	// Keg is the keg reference to record (a bare name or @namespace/keg). Empty
	// leaves the keg slot untouched (unless Clear is set).
	Keg string
	// Flight is a flight reference to record for the project (@namespace/+slug,
	// +slug, or a bare slug). Empty leaves the flight untouched.
	Flight string
	// User writes the user config's fallbackKeg instead of the project config's
	// defaultKeg.
	User bool
	// ConfigPath, when set, writes that explicit config file instead of the
	// user/project file. The slot still follows User.
	ConfigPath string
	// Clear unsets the slot(s) for the chosen scope (defaultKeg + flight for the
	// project scope; fallbackKeg for the user scope).
	Clear bool
}

UseOptions configures Tap.Use, the `tap use` setter that records which keg (and flight) a project resolves, or a user-wide fallback keg.

Scope picks the keg slot: the default (project) scope writes defaultKeg; the user scope (User=true) writes fallbackKeg. Flight is project-scoped only.

type ValidateOptions added in v0.25.0

type ValidateOptions struct {
	KegTargetOptions
	NodeIDs []string
}

type WatchNodeOptions added in v0.23.0

type WatchNodeOptions struct {
	NodeID string
	KegTargetOptions
}

type WhoAmI added in v0.23.0

type WhoAmI struct {
	UserID           int64     `json:"user_id"`
	Username         string    `json:"username"`
	DisplayName      string    `json:"display_name"`
	Email            string    `json:"email"`
	CreatedAt        time.Time `json:"created_at"`
	DefaultNamespace string    `json:"default_namespace"`
	Namespaces       []string  `json:"namespaces,omitempty"`
}

WhoAmI is the authenticated user the hub reports for a token. It mirrors the hub's GET /api/v1/whoami JSON body (handler.WhoamiResponse) — keep the two structs in sync. DisplayName is the human name and is empty when the hub omits it (older hub, or no display name set), in which case callers fall back to the username alone.

DefaultNamespace is the user's home namespace as the hub sees it (its name equals the username by construction). `tap bootstrap` adopts it as the fallback namespace so the hub, not the client, decides which namespace a fresh login lands in. Namespaces lists every namespace the user belongs to (personal + orgs) and is empty when the hub omits it (older hub).

func ValidateToken added in v0.23.0

func ValidateToken(ctx context.Context, rt *toolkit.Runtime, hubURL, token string) (*WhoAmI, error)

ValidateToken calls GET {hubURL}/api/v1/whoami with the bearer token and returns the resolved user. A 401/403 is reported as a rejected token; any other non-200 surfaces the hub's status so misconfigurations are visible. The default HTTP client is used; callers that need to inject one for tests can hit an httptest.Server, whose URL works with http.DefaultClient.

Jump to

Keyboard shortcuts

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