Documentation
¶
Overview ¶
The lib package is the implementation of the core functionality of the raid CLI tool.
Index ¶
- Constants
- Variables
- func AcquireMutationLock() (func(), error)
- func AddProfile(profile Profile) error
- func AddProfiles(profiles []Profile) error
- func CloneRepository(repo Repo) error
- func ContainsEnv(name string) bool
- func ContainsProfile(name string) bool
- func CreateRepoConfigs(repos []RepoDraft)
- func ExecuteCommand(name string, args []string, named map[string]string) error
- func ExecuteEnv(name string) error
- func ExecuteRepoCommand(repoName, cmdName string, args []string, named map[string]string) error
- func ExecuteTask(task Task) error
- func ExecuteTasks(tasks []Task) error
- func ForceLoad() error
- func GetEnv() string
- func InitConfig() error
- func Install(maxThreads int) error
- func InstallRepo(name string) error
- func IsHeadless() bool
- func ListEnvs() []string
- func Load() error
- func LoadEnv() error
- func PrefixDisabled() bool
- func RecordRecentEnd(command string, runErr error, startedAt time.Time)
- func RecordRecentStart(command string) time.Time
- func RemoveProfile(name string) error
- func ResetContext()
- func ScrubURL(raw string) string
- func Set(key string, value any) error
- func SetCommandOutput(stdout, stderr io.Writer) func()
- func SetDescribeRepoCacheTTLForTest(d time.Duration) func()
- func SetEnv(name string) error
- func SetHeadlessForTest(v bool) func()
- func SetPrefixDisabledForTest(v bool) func()
- func SetProfile(name string) error
- func ValidateProfile(path string) error
- func ValidateRepo(path string) error
- func ValidateSchema(path string, schemaPath string) error
- func WatchRaidVars(ctx stdctx.Context, onChange func()) error
- func WithMutationLock(fn func() error) error
- func Write() error
- func WriteProfileFile(draft ProfileDraft, path string) error
- type Agent
- type Arg
- type Command
- type Condition
- type Context
- type Env
- type EnvVar
- type Finding
- type Flag
- type OnInstall
- type Output
- type Profile
- type ProfileDraft
- type RecentEntry
- type Repo
- type RepoDraft
- type Severity
- type Task
- type TaskOptions
- type TaskProps
- type TaskType
- type Verify
- type VerifyOutcome
- type Workspace
- type WorkspaceAgent
- type WorkspaceCommand
- type WorkspaceContext
- type WorkspaceRepo
- type WorkspaceStep
- type WorkspaceTool
Constants ¶
const ( ConfigDirName = ".raid" ConfigFileName = "config.toml" ConfigPathDefault = "~" + sys.Sep + ConfigDirName + sys.Sep + ConfigFileName ConfigPathFlag = "config" ConfigPathFlagShort = "c" ConfigPathFlagDesc = "configuration file path (default is " + ConfigPathDefault + ")" )
const ( RecentStatusCompleted = "completed" RecentStatusInterrupted = "interrupted" )
Recent statuses surfaced via ReadRecent. "running" only ever appears on disk while a command is in flight; ReadRecent rewrites it to RecentStatusInterrupted so consumers always see one of these two terminal states.
const HeadlessEnvVar = "RAID_HEADLESS"
HeadlessEnvVar is the env var that toggles headless mode. The CLI's `-y` / `--yes` / `--headless` persistent flag sets this var via rootCmd's PersistentPreRunE so a single read site in lib serves both the flag-driven and env-driven entry points (the latter is how CI, scheduled runs, and agent hosts opt in without parsing flags).
const NoPrefixEnvVar = "RAID_NO_PREFIX"
NoPrefixEnvVar toggles per-task output prefixing in concurrent runs. The CLI's --no-prefix persistent flag sets this var via rootCmd's PersistentPreRunE so a single read site in lib serves both the flag-driven and env-driven entry points.
const (
RaidConfigFileName = "raid.yaml"
)
Variables ¶
var CfgPath string
var LockPathOverride string
LockPathOverride redirects the mutation lock file. Tests set this so they don't contend with a real raid invocation running on the developer's machine. Empty in production.
var RecentPathOverride string
RecentPathOverride redirects the recent.json log path. Intended only for tests that exercise ExecuteCommand so they do not pollute the developer's real ~/.raid/recent.json.
Functions ¶
func AcquireMutationLock ¶
func AcquireMutationLock() (func(), error)
AcquireMutationLock blocks until this process holds the raid mutation lock, then returns a release function. Callers MUST defer the release.
This is a cross-process exclusive lock backed by flock(2) on POSIX and LockFileEx on Windows. Any raid invocation (CLI or MCP server) that calls AcquireMutationLock while another raid process holds it will wait until released. The kernel releases the lock automatically if the holder exits unexpectedly — no stale-lock recovery code needed.
Read-only operations (raid context, raid_list_*, raid doctor, etc.) don't need this lock; stale reads during a mutation are recoverable. Only paths that write ~/.raid state, .env files in repos, or run task sequences should acquire it.
func AddProfile ¶
AddProfile registers a profile in the config store.
func AddProfiles ¶
AddProfiles registers multiple profiles in the config store.
func CloneRepository ¶
CloneRepository clones a repository to its configured path. Skips if it already exists. Repos with no configured `url` (local-only) are never cloned — the path must already exist on disk; otherwise an error is returned so the user knows the local repo is missing rather than getting a confusing git error.
func ContainsEnv ¶
ContainsEnv reports whether an environment with the given name exists in the active profile.
func ContainsProfile ¶
ContainsProfile reports whether a profile with the given name is registered. Case-insensitive: viper's GetStringMapString lowercases keys at storage time, so a name typed as `MyProfile` is stored under `myprofile`. Without the lowercase comparison here, `raid profile MyProfile` would fail even though `MyProfile` was just registered.
func CreateRepoConfigs ¶
func CreateRepoConfigs(repos []RepoDraft)
CreateRepoConfigs writes a raid.yaml stub into each repository's local directory.
func ExecuteCommand ¶
ExecuteCommand runs the tasks for the named command, applying any output configuration. Positional `args` are exposed as RAID_ARG_1, RAID_ARG_2, ... environment variables. When `named` is non-nil, each entry is also exported as a env var with the key uppercased — this is how cobra-parsed named arguments and flags reach task scripts. All bindings are unset after the command exits.
func ExecuteEnv ¶
ExecuteEnv writes environment variables to each repo's .env file and runs the environment's tasks.
func ExecuteRepoCommand ¶
ExecuteRepoCommand runs a command defined in a specific repository's raid.yaml. See ExecuteCommand for how `args` and `named` are bound to env vars.
func ExecuteTask ¶
func ExecuteTasks ¶
func ForceLoad ¶
func ForceLoad() error
ForceLoad rebuilds the context from the active profile, ignoring any cached state.
func InitConfig ¶
func InitConfig() error
func InstallRepo ¶
InstallRepo clones a single named repository and runs its install tasks. The profile-level install tasks are not run.
func IsHeadless ¶
func IsHeadless() bool
IsHeadless reports whether interactive prompts (Confirm / Prompt tasks) should be auto-resolved instead of blocking on stdin. True when RAID_HEADLESS is set to a truthy value ("1", "true", "yes", "y", "on" — case-insensitive). Anything else — including "0", "false", and the empty string — is treated as not-headless so a stray export doesn't silently change behavior.
func ListEnvs ¶
func ListEnvs() []string
ListEnvs returns the names of all environments in the active profile.
func Load ¶
func Load() error
Load initializes the context from the active profile, using cached results if available.
func LoadEnv ¶
func LoadEnv() error
LoadEnv loads .env files from all repositories in the active profile into the process environment.
func PrefixDisabled ¶
func PrefixDisabled() bool
PrefixDisabled reports whether per-task output prefixing is suppressed via the --no-prefix flag or RAID_NO_PREFIX env var. Truthy values mirror IsHeadless: "1", "true", "yes", "y", "on" (case-insensitive). Anything else is treated as not-disabled so a stray export can't silently change behavior.
func RecordRecentEnd ¶
RecordRecentEnd updates the placeholder entry written by RecordRecentStart with the command's exit code and total duration. If the matching entry has fallen off the cap, no update is recorded.
func RecordRecentStart ¶
RecordRecentStart prepends a placeholder entry for command in the recent log and returns the moment recording began. Pass the same value to RecordRecentEnd once the command has finished. Errors writing the log are silenced — recording history must never break command execution.
The returned time keeps full nanosecond precision so it can be used as an unambiguous key by RecordRecentEnd: two commands started in the same second would alias if we truncated. Display formatters can re-truncate at render time when a coarser granularity is desired.
func RemoveProfile ¶
RemoveProfile removes a registered profile by name. Case-insensitive lookup mirrors ContainsProfile — viper lowercases keys internally, so a name typed as `MyProfile` is stored as `myprofile` and must be looked up the same way.
func ResetContext ¶
func ResetContext()
ResetContext clears the cached load context, forcing the next Load or ForceLoad to rebuild from the current viper configuration.
func ScrubURL ¶ added in v0.17.2
ScrubURL strips userinfo (user:password@) from a credential-bearing URL so secrets embedded in a clone URL never get persisted or surfaced to MCP clients. Returns the input unchanged when:
- it's empty
- it's an SSH-style URL (`git@host:repo.git` or `ssh://git@host/…`) where the username is the protocol's required login, not a credential — stripping it would change clone semantics
- it can't be parsed as a URL (treated as opaque)
Only `http` and `https` schemes get scrubbed: those are the ones where userinfo carries tokens / basic-auth secrets. SSH userinfo (the `git` user) is preserved so a scrubbed URL is still a valid clone URL for downstream consumers.
func SetCommandOutput ¶
SetCommandOutput swaps the writers used by task execution, repository cloning, and environment setup. The returned function restores the previous writers — call via defer to keep state clean even if the caller panics. Not safe for concurrent calls; serialise at the call site if multiple goroutines may run mutating operations.
func SetDescribeRepoCacheTTLForTest ¶ added in v0.17.2
SetDescribeRepoCacheTTLForTest overrides the TTL for the duration of a test. Returns a restore function. Set to 0 to disable caching entirely.
func SetHeadlessForTest ¶
func SetHeadlessForTest(v bool) func()
SetHeadlessForTest forces the headless toggle for the duration of a test. Returns a restore function to defer. Use this in package-level tests that need deterministic headless behavior without racing on os.Environ.
func SetPrefixDisabledForTest ¶
func SetPrefixDisabledForTest(v bool) func()
SetPrefixDisabledForTest forces the prefix-disabled toggle for the duration of a test. Returns a restore function to defer.
func SetProfile ¶
SetProfile sets the named profile as the active profile.
func ValidateProfile ¶
ValidateProfile validates the profile file at path against the profile JSON schema.
func ValidateRepo ¶
ValidateRepo validates the repo config file at path against the repo JSON schema.
func ValidateSchema ¶
ValidateSchema validates the file at path against the JSON schema at schemaPath. schemaPath must be an absolute or CWD-relative path to a schema file on disk.
func WatchRaidVars ¶
WatchRaidVars watches the raid vars file (~/.raid/vars) for the lifetime of ctx and invokes onChange whenever the file is created, modified, or replaced. Events are debounced. The watcher is attached to the parent directory so atomic-rename writes (which swap the inode) keep firing — a watch on the file itself would silently go deaf after the first rename.
onChange is the caller's reload hook; lib does not assume what to reload, so the MCP server passes a closure that runs ForceLoad under the cross-process mutation lock.
func WithMutationLock ¶
WithMutationLock acquires the mutation lock, runs fn, and releases the lock. Use this when an entire user-visible operation should be atomic across processes — for example, the env-switch sequence (set + force load + execute) where any gap between steps could let another raid invocation interleave.
func WriteProfileFile ¶
func WriteProfileFile(draft ProfileDraft, path string) error
WriteProfileFile serializes draft as YAML and writes it to path, creating parent directories as needed.
Types ¶
type Agent ¶
type Agent struct {
// Safe declares the command idempotent and side-effect free. MCP
// clients that respect the hint may auto-run safe commands; unsafe
// commands require explicit user approval. Defaults to false.
Safe bool `json:"safe" yaml:"safe"`
// Reads lists the paths or globs the command reads. Informational
// only — raid does not parse or enforce these. Mirrors Claude
// Code's permission-model fields so authors can reason about
// safety the same way across tools.
Reads []string `json:"reads,omitempty" yaml:"reads,omitempty"`
// Writes lists the paths or globs the command writes. Same
// semantics as Reads — informational, not enforced.
Writes []string `json:"writes,omitempty" yaml:"writes,omitempty"`
// Description is an agent-facing description of the command. When
// set, it overrides the command's `usage` field in the workspace
// resource — useful when the human-facing usage line is too terse
// to give an agent enough context to choose the command.
Description string `json:"description,omitempty" yaml:"description,omitempty"`
}
Agent is the optional safety / metadata hint on a user-defined command. MCP clients read the resolved form (see WorkspaceAgent) from the `raid://workspace/commands` resource and use it to decide whether to auto-execute a command or prompt the user for approval.
Raid never gates execution on Agent — it surfaces the hint and the client implements the policy. Absence of the block is equivalent to `{Safe: false}` so unannotated commands stay opt-in to automation.
type Arg ¶
type Arg struct {
Name string `json:"name"`
Usage string `json:"usage,omitempty"`
Required bool `json:"required,omitempty"`
}
Arg declares a positional argument for a custom command. The supplied value is bound to the env var named after Name (uppercased) for the duration of the command, so tasks can reference it as `$NAME`. Required args without a matching positional value cause cobra to reject the invocation.
type Command ¶
type Command struct {
Name string `json:"name"`
Usage string `json:"usage"`
Args []Arg `json:"args,omitempty"`
Flags []Flag `json:"flags,omitempty"`
Tasks []Task `json:"tasks"`
Options *TaskOptions `json:"options,omitempty"`
// Agent carries optional MCP-facing safety metadata. A nil Agent
// surfaces to MCP clients as `{safe: false}` so unannotated
// commands keep their "requires confirmation" semantics.
Agent *Agent `json:"agent,omitempty"`
Out *Output `json:"out,omitempty"`
}
Command is a named, user-defined CLI command that can be invoked via 'raid <name>'.
func GetCommands ¶
func GetCommands() []Command
GetCommands returns all commands available in the active profile.
func QuietLoad ¶
func QuietLoad() []Command
QuietLoad attempts a best-effort, read-only profile load. It does not create config files, does not emit warnings, and returns nil if the config is absent or loading fails. Intended for info-command paths (--help, --version) where user-command registration is opportunistic and side effects are undesirable.
type Condition ¶
type Condition struct {
Platform string `json:"platform,omitempty"`
Exists string `json:"exists,omitempty"`
Cmd string `json:"cmd,omitempty"`
}
Condition guards a task — all specified fields must be satisfied for the task to run.
type Env ¶
type Env struct {
Name string `json:"name"`
Variables []EnvVar `json:"variables"`
Tasks []Task `json:"tasks"`
}
Env represents a named environment with variables and tasks.
type Finding ¶
type Finding struct {
Severity Severity
Check string
Message string
Suggestion string // shown when non-empty
}
Finding represents the result of a single doctor check.
type Flag ¶
type Flag struct {
Name string `json:"name"`
Short string `json:"short,omitempty"`
Usage string `json:"usage,omitempty"`
Type string `json:"type,omitempty"`
Required bool `json:"required,omitempty"`
Default any `json:"default,omitempty"`
}
Flag declares a long-form (--name) and optional short-form (-x) flag for a custom command. Type is one of "string" (default), "bool", or "int". Required flags are enforced by cobra. Default supplies the value when the flag is omitted; bool flags default to false unless overridden.
type OnInstall ¶
type OnInstall struct {
Tasks []Task `json:"tasks"`
}
OnInstall holds the tasks to run during profile installation.
type Output ¶
type Output struct {
Stdout bool `json:"stdout"`
Stderr bool `json:"stderr"`
File string `json:"file,omitempty"`
}
Output configures how a command's task output is handled. Stdout and Stderr default to true when Out is nil. When Out is set, only streams explicitly set to true are shown.
type Profile ¶
type Profile struct {
Name string `json:"name"`
Path string `json:"path"`
Repositories []Repo `json:"repositories"`
Environments []Env `json:"environments"`
Install OnInstall `json:"install"`
Groups map[string][]Task `json:"task_groups" yaml:"task_groups"`
Commands []Command `json:"commands"`
Verify []Verify `json:"verify,omitempty"`
}
Profile represents a named collection of repositories, environments, and task groups.
func BuildSingleRepoProfile ¶
BuildSingleRepoProfile validates the raid.yaml at path and returns a synthetic profile whose only repository points at the raid.yaml's directory. The profile's Path is the raid.yaml itself, so IsSingleRepo reports true on subsequent loads. The repository's full configuration (commands, environments, install tasks) is merged in by buildRepo later in the load pipeline.
func ExtractProfile ¶
ExtractProfile reads and returns a single named profile from the given file.
func ExtractProfiles ¶
ExtractProfiles reads all profiles from a YAML or JSON file.
func (Profile) IsSingleRepo ¶
IsSingleRepo reports whether the profile is backed by a raid.yaml (repo config) rather than a profile YAML. Detected by the registered path's basename: when `raid profile add ./raid.yaml` records a path pointing at a repo config, raid synthesizes a single-repo profile around it instead of requiring a wrapping profile file. The buildProfile / doctor paths branch on this check to switch schemas.
type ProfileDraft ¶
type ProfileDraft struct {
Name string `yaml:"name"`
Repositories []RepoDraft `yaml:"repositories,omitempty"`
}
ProfileDraft is the minimal structure written to a new profile file.
type RecentEntry ¶
type RecentEntry struct {
Command string `json:"command"`
Status string `json:"status"`
ExitCode int `json:"exitCode"`
StartedAt time.Time `json:"startedAt"`
DurationMs int64 `json:"durationMs,omitempty"`
}
RecentEntry records a single `raid <command>` invocation. The log is intentionally per-command (not per-task) — agents asking "what did the developer just run?" want a high-level history, not every Shell step.
Lifecycle: an entry is first written on command start with Status="running", then updated to Status="completed" once the command exits normally. If the process is killed (SIGINT/SIGTERM/SIGKILL), the running entry survives on disk and ReadRecent reports it as Status="interrupted".
func ReadRecent ¶
func ReadRecent() []RecentEntry
ReadRecent returns the most-recent-first list of recorded command runs. Returns nil if the log file does not exist or cannot be parsed; callers should treat absence as "no history yet".
Any entry still in the on-disk "running" state is rewritten to RecentStatusInterrupted before returning, so callers always see a terminal status. Concurrent in-flight invocations will be misreported, but that's an acceptable trade-off for a tool that is overwhelmingly run sequentially.
type Repo ¶
type Repo struct {
Name string `json:"name"`
Path string `json:"path"`
URL string `json:"url"`
Branch string `json:"branch"`
Environments []Env `json:"environments"`
Install OnInstall `json:"install"`
Commands []Command `json:"commands"`
Verify []Verify `json:"verify,omitempty"`
}
Repo represents a single repository entry in a profile.
func ExtractRepo ¶
ExtractRepo reads and parses the raid.yaml from the given repository directory.
func (Repo) IsLocalOnly ¶
IsLocalOnly reports whether the repo has no configured git remote. Local-only repos skip cloning; install tasks run directly against the existing path. The path must already exist on disk for install to work.
Whitespace-only URLs (e.g. `url: " "` from a stray edit) are treated as local-only — the trimmed value is what would be handed to `git clone`, and an empty string there produces a confusing error rather than a useful one.
type RepoDraft ¶
type RepoDraft struct {
Name string `yaml:"name"`
Path string `yaml:"path"`
URL string `yaml:"url"`
Branch string `yaml:"branch,omitempty"`
}
RepoDraft holds the fields collected for each repository during profile creation.
func CollectRepos ¶
CollectRepos runs an interactive prompt loop to collect repository details from reader.
type Task ¶
type Task struct {
TaskProps `yaml:",inline"`
Type TaskType `json:"type"`
Concurrent bool `json:"concurrent,omitempty"`
Condition *Condition `json:"condition,omitempty"`
// Shell
Cmd string `json:"cmd,omitempty"`
Literal bool `json:"literal,omitempty"`
Shell string `json:"shell,omitempty"`
// Script
Path string `json:"path,omitempty"`
Runner string `json:"runner,omitempty"`
// HTTP
URL string `json:"url,omitempty"`
Dest string `json:"dest,omitempty"`
// Wait
Timeout string `json:"timeout,omitempty"`
// Template
Src string `json:"src,omitempty"`
// Group
Ref string `json:"ref,omitempty"`
Parallel bool `json:"parallel,omitempty"`
// Git
Op string `json:"op,omitempty"`
Branch string `json:"branch,omitempty"`
// Prompt / Confirm / Print
Message string `json:"message,omitempty"`
// Prompt / SetVar
Var string `json:"var,omitempty"`
Default string `json:"default,omitempty"`
// SetVar
Value string `json:"value,omitempty"`
// Print
Color string `json:"color,omitempty"`
// Retry
Attempts int `json:"attempts,omitempty"`
Delay string `json:"delay,omitempty"`
}
Task represents a single unit of work in a task sequence.
type TaskOptions ¶
type TaskOptions struct {
// ShowExeTime, when true, prints a dim "<label> complete in <time>"
// line to stderr after the task (or command) completes — for both
// success and failure, so the elapsed time is always visible.
ShowExeTime bool `json:"showExeTime,omitempty" yaml:"showExeTime,omitempty"`
// ContinueOnFailure, when true, lets a non-zero task exit slip past
// the sequencer: subsequent tasks still run and the parent command's
// exit code is unaffected by this task. A dim warning is logged to
// stderr so the ignored failure remains visible. Only meaningful on
// tasks — has no effect when set on a command's own options.
ContinueOnFailure bool `json:"continueOnFailure,omitempty" yaml:"continueOnFailure,omitempty"`
}
TaskOptions is the shared `options:` block applied uniformly across all task types and to user-defined commands. New fields ship additively; old fields keep their semantics across minor versions.
type TaskProps ¶
type TaskProps struct {
// Name is an optional human-readable label for the task, surfaced in logs
// and agent-facing output. It does not affect execution.
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// Options is the shared options block — see TaskOptions. Composes across
// every task type and is also accepted on user-defined commands. Omitting
// the block (or any field within) leaves default behavior unchanged.
Options *TaskOptions `json:"options,omitempty" yaml:"options,omitempty"`
}
TaskProps holds properties shared by every task type. It is embedded into Task so the fields below appear at the top level of a task's YAML/JSON representation, and remain accessible via field promotion (e.g. `task.Name`).
type Verify ¶
type Verify struct {
// Name is the human-readable label surfaced in failure messages
// and doctor's findings list. Required.
Name string `json:"name" yaml:"name"`
// Tasks is the precondition assertion. All tasks must exit 0 for
// the verify to pass on the first try.
Tasks []Task `json:"tasks" yaml:"tasks"`
// OnFail is the optional one-shot remediation. When present, a
// first-pass failure triggers OnFail followed by exactly one
// re-run of Tasks. Empty OnFail means the first failure is final.
// The explicit yaml tag is required so YAML's default lowercasing
// doesn't turn `onFail:` into a silently ignored key.
OnFail []Task `json:"onFail,omitempty" yaml:"onFail,omitempty"`
}
Verify is a declarative precondition check. Each entry runs `Tasks` — if any task exits non-zero, the optional `OnFail` block runs once as remediation and then the original `Tasks` re-runs. Verify passes if the original or remediated run succeeds; otherwise it's reported as failed via errs.VerifyFailed.
Verify entries live at the top level of profiles and per-repo raid.yaml files. raid doctor surfaces them as findings: a first-try pass is an OK finding, a successful self-heal is a warning (so the user knows something needed fixing), and a failure is an error.
type VerifyOutcome ¶
type VerifyOutcome int
VerifyOutcome is the tri-state result of running a verify entry: OK (first-try pass), Remediated (self-heal succeeded), or Failed. Doctor maps OK/Remediated to OK/warn severities and Failed to an error severity; RunVerify also returns a non-nil error alongside VerifyOutcomeFailed so direct callers get the underlying cause.
const ( // VerifyOutcomeOK means Tasks passed on the first try; no // remediation ran. VerifyOutcomeOK VerifyOutcome = iota // VerifyOutcomeRemediated means Tasks failed on the first try, // OnFail succeeded, and the retry of Tasks passed. The verify // holds *now*, but it didn't before — worth surfacing as a // warning so the user knows something silently fixed itself. VerifyOutcomeRemediated // VerifyOutcomeFailed means Tasks didn't pass: either no OnFail // was defined, OnFail itself failed, or the retry of Tasks // still failed. RunVerify returns a non-nil error in this case. VerifyOutcomeFailed )
func RunVerify ¶
func RunVerify(v Verify) (VerifyOutcome, error)
RunVerify executes the verify entry per the documented semantics: run Tasks; on failure, if OnFail is set, run it and re-run Tasks once. Returns one of three outcomes — see VerifyOutcome.
An empty Tasks slice is treated as a no-op pass.
Tasks run with raid's normal env / raidVars / command-session context — same as install: tasks — so verifies see whatever the caller has loaded.
type Workspace ¶
type Workspace struct {
Profile string `json:"profile"`
Env string `json:"env,omitempty"`
Repos []WorkspaceRepo `json:"repos"`
Commands []WorkspaceCommand `json:"commands"`
Recent []RecentEntry `json:"recent,omitempty"`
Vars map[string]string `json:"vars,omitempty"`
}
Workspace is the inline workspace state — what would be served via `resources/read` against a `raid://workspace/*` URI by an MCP server.
type WorkspaceAgent ¶
type WorkspaceAgent struct {
Safe bool `json:"safe"`
Reads []string `json:"reads,omitempty"`
Writes []string `json:"writes,omitempty"`
Description string `json:"description,omitempty"`
}
WorkspaceAgent is the wire form of Agent. `Safe` has no `omitempty` so it's always present in the JSON, which is load-bearing for the "default unsafe" contract — clients can read `agent.safe` without distinguishing absence from `false`.
type WorkspaceCommand ¶
type WorkspaceCommand struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Steps []WorkspaceStep `json:"steps,omitempty"`
// Agent is the resolved MCP-facing safety hint. Always emitted so
// clients can rely on `agent.safe` being present — a command with
// no `agent:` block in YAML surfaces as `{safe: false}`.
Agent WorkspaceAgent `json:"agent"`
}
WorkspaceCommand exposes a profile command's name and short description. Script bodies are intentionally excluded so the snapshot stays token-efficient and free of secrets. If any of the command's tasks have a `name` field set, they're surfaced in Steps as an outline of what the command does — also without script bodies.
type WorkspaceContext ¶
type WorkspaceContext struct {
Name string `json:"name"`
Title string `json:"title,omitempty"`
Version string `json:"version,omitempty"`
WebsiteUrl string `json:"websiteUrl,omitempty"`
GeneratedAt time.Time `json:"generatedAt"`
Tools []WorkspaceTool `json:"tools,omitempty"`
Workspace Workspace `json:"workspace"`
}
WorkspaceContext is a condensed snapshot of the active workspace, intended for agent / `raid context` consumption. It is derived from the loaded session context plus on-disk git state per repository.
The top-level Name / Version / WebsiteUrl / GeneratedAt fields identify the producer so an agent that picks up the snapshot in isolation can find the project on GitHub for further context and judge freshness. The Workspace sub-object holds the actual workspace state.
Field naming follows MCP (camelCase) so this shape can be lifted directly into the future `raid context serve` MCP server responses with no further translation.
func GetWorkspaceContext ¶
func GetWorkspaceContext() WorkspaceContext
GetWorkspaceContext returns a snapshot of the active workspace. The session context must already be loaded (Load / ForceLoad). If no profile is active the returned WorkspaceContext has empty Workspace.Profile and empty Repos / Commands slices.
type WorkspaceRepo ¶
type WorkspaceRepo struct {
Name string `json:"name"`
Path string `json:"path"`
Cloned bool `json:"cloned"`
Branch string `json:"branch,omitempty"`
Dirty bool `json:"dirty,omitempty"`
}
WorkspaceRepo describes a single repository in the active profile, as it exists on disk right now (not just as configured).
type WorkspaceStep ¶
type WorkspaceStep struct {
Name string `json:"name"`
}
WorkspaceStep describes one named task inside a command's task sequence. Only tasks with a populated TaskProps.Name appear here; unnamed tasks are omitted to keep the snapshot focused on user-meaningful labels.
type WorkspaceTool ¶
type WorkspaceTool struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
}
WorkspaceTool describes a built-in `raid` subcommand the agent can invoke directly (e.g. `raid install`, `raid env`). User-defined commands live in Workspace.Commands and are not duplicated here.