Skip to main content

What's New

User-visible changes per release, latest first. For full commit history see the GitHub releases page.

0.17.4 — upcoming

The install.sh script now installs on Windows. Run it from a Git Bash (MSYS2 / Cygwin) shell and the installer detects the MINGW* / MSYS* / CYGWIN* platform, downloads the windows_amd64 .zip release, verifies its checksum, and unzips raid.exe into ~/bin (created if missing). If ~/bin is not on your PATH, the script prints the export PATH line to add. WSL is unchanged — it reports linux from uname, so it follows the existing Linux path and installs the Linux binary. Windows is published for amd64 only; arm64 is rejected with a clear message, and the script errors early if unzip is missing.

0.17.3 — upcoming

Test-only hotfix. No behavior change to the shipped binary.

TestWriteIDExclusive_mkdirFailure now passes on Windows. The test pinned writeIDExclusive's "MkdirAll fails → error returned" contract by passing /dev/null/impossible/path/id — a path that only forces MkdirAll to fail on POSIX, where /dev/null is a char-device file the kernel refuses to descend into. On Windows there is no /dev/null, so MkdirAll happily created C:\dev\null\impossible\path\ and the test failed with no returned error. Replaced with a portable file-as-parent-dir trick (write a regular file, then pass a path that treats it as a directory component) which fails MkdirAll on both POSIX (ENOTDIR) and Windows (ERROR_DIRECTORY).

0.17.2 — upcoming

Eighteen High and Medium pre-v1.0 review fixes. No new features; behavior changes are surgical and called out individually below.

Concurrent task output stays line-atomic. Six auxiliary writes in the task runner (continueOnFailure warnings, showExeTime markers, Wait / Retry banners, Prompt / Confirm text) now serialize through the same outputMu as the per-task prefix writer. Previously these could interleave mid-line with a peer concurrent task's prefixed output. Prompt / Confirm release the mutex before the blocking stdin read so concurrent output isn't frozen during user input.

raid deploy version no longer gets misclassified as raid version. isInfoCommand now only matches the first non-flag positional against help / version / completion. A user command that takes one of those words as a positional value no longer triggers info-mode's 1.5s version-check wait + spurious "update available" banner.

raid profile add / remove / create / set-active honor --json. All four subcommands previously printed prose unconditionally; --json consumers got unparseable output. The new shapes follow the existing per-command JSON contract (profile add{action, path, profiles[], existing[], active}; profile remove{removed[], errors[]}; profile set-active → {action, name, path}). Cobra's RunE replaces Run, so every failure flows through the root structured-error handler and gets a category-correct exit code (PROFILE_NOT_FOUND → 5, PROFILE_INVALID → 2, CLONE_FAILED → 4, etc.) instead of always exiting 1.

Deterministic ordering in profile list. Output sorted by name in both text and JSON modes — matching the MCP raid_list_profiles tool's existing behavior. env list is unchanged (kept in YAML-declaration order for author intent).

Profile / repo env merging matches mergeCommands semantics. In single-repo mode, environments declared on both the wrapping profile and the repo's raid.yaml no longer duplicate. Profile wins on name conflict, same contract used for commands. Removes the silent "duplicate env entries in ListEnvs" failure mode where getEnv returned the first while ExecuteEnv wrote variables from whichever happened first in the slice.

runCommand's out: redirection routes through SetCommandOutput. The pre-fix path mutated the package-level commandStdout / commandStderr globals directly, bypassing the documented swap entry point. With MCP capturing output via SetCommandOutput, a out: {file: ...} command whose lifetime overlapped with another MCP tool call had a race window. Both paths now go through the same atomic swap + restore.

raid doctor no longer short-circuits on profile schema failure. A schema error in the wrapping profile previously stopped the doctor report cold, hiding repo-level and verify-block findings. The schema failure is still recorded as an error finding, but doctor now continues into repo checks so the user sees the full health picture in one pass (matching the existing checkVerify contract).

Telemetry consent prompt uses term.IsTerminal instead of os.ModeCharDevice. Agent hosts that wire stdin to /dev/null (also a character device) no longer get misclassified as interactive — the prompt is suppressed and consent stays at the "not decided" zero value as intended. Matches the same TTY check the output-prefix code already uses.

Profile name lookups are case-insensitive end-to-end. Viper stores map keys lowercased, so a profile registered as MyProfile lived under myprofile while lookups in ContainsProfile / RemoveProfile / GetProfile().Path used the original case — leading to "profile not found" errors right after a successful add. All lookups now normalize before indexing.

Multi-document profile YAML uses yaml.NewDecoder. Replaces the literal-string strings.Split(data, "---") with the proper streaming decoder. Profile YAML containing --- as content (e.g. inside a usage: description or a multi-line message:) no longer gets torn at the substring. The schema validator already used NewDecoder — extraction now matches.

Goroutine panic recovery in clone fan-out and ExecuteTasks. A CloneRepository panic could strand the install semaphore and deadlock the parent wg.Wait(). A panic inside a concurrent task goroutine took down the whole raid process (and the MCP server's long-lived stdio session). Both paths now defer recover() and surface the panic as a structured INTERNAL error to the aggregate handler.

Shared reserved-key list across error JSON emitters. EmitJSON (CLI --json errors) and mcpStructuredError (MCP tool-result errors) previously hand-maintained their own reserved-key lists. They now both consult errs.IsReservedErrorKey, so a future error code adding a new envelope field automatically propagates everywhere.

raid_list_repos MCP path caches git state for 1 second. Each call previously forked N git rev-parse + git status subprocesses synchronously. Agents that poll the resource at sub-second intervals no longer hammer git; human-interactive raid context calls still see fresh state within 1s.

parseEnvLines fast-path on unchanged env. Consecutive Shell tasks that don't touch the env produce byte-identical dumps. An FNV-1a hash of the dump lets updateSessionFromEnv skip the parse + diff entirely on a cache hit — meaningful for commands with many Shell tasks and a static env baseline.

applyConfigFlag warns instead of silently dropping bad values. raid --config -mypath … no longer silently drops -mypath (and falls through to cobra's "flag needs an argument" later). A diagnostic on stderr explains the cause so the user can correct the invocation.

Other: stdin-buffer behavior between the telemetry prompt and the first Prompt/Confirm task documented (no real-world impact); runCommand's exe-time emission matrix vs. out: {stdout, stderr, file} documented inline.

0.17.1 — upcoming

Three pre-v1.0 hardening fixes from the release-readiness review. No behavior change for happy paths; all three are correctness/security bugs with regression tests now in place.

Telemetry consent prompt no longer gets killed by --json. The first-run prompt previously persisted decided=off on any skip signal — including transient ones like --json. A user who piped one command through raid context --json | jq was silently opted out of telemetry for life. The consent flow now splits skip signals into two tiers: persistent (--yes / --headless / RAID_HEADLESS / non-TTY / DO_NOT_TRACK) which still persist decided=off, and transient (--json) which skip the prompt without writing state. The next interactive run without the transient signal still gets prompted.

Repo URL credentials no longer leak to ~/.raid/vars or MCP. A profile YAML using https://user:[email protected]/... as a clone URL no longer persists the credential to disk, no longer surfaces it through the MCP raid://workspace/vars resource, and no longer lands verbatim in $RAID_REPO_<NAME>_URL for subprocesses. SSH-style git@host:repo.git URLs round-trip unchanged. If you've previously run raid against a profile with embedded clone credentials, rotate the affected token — this fix prevents new leaks but doesn't scrub historical content from your existing vars file. Re-exported as raid.ScrubURL.

~/.raid/vars now written with mode 0600 instead of 0644. The vars file persists raid-managed variables (scrubbed repo URLs, Set-task values, anything project authors treat as secret-ish) and shouldn't be world-readable. New writes land at 0600 atomically; existing 0644 files are best-effort tightened on the next load.

MCP read/write race on the workspace context. mcp-go dispatches tool calls from a 5-worker pool, so MCP read handlers (raid_list_repos, raid_describe_repo, …) could race with mutating handlers' ForceLoad rewrites of the package-global context. Replaced with atomic.Pointer[Context]; reads are now well-defined under concurrent writes. Race-detector test pins the contract.

0.17.0 — upcoming

Optional opt-out telemetry follow-up. When a user declines the first-run telemetry prompt, raid now asks one follow-up question: may we send a single anonymous event recording your denial? Default is no (capital N) just like the main prompt. If accepted, raid fires exactly one raid_telemetry_opt_out event (with reason: "prompt-declined") under explicit per-event consent and then leaves telemetry permanently off — that's the whole transaction. If declined or skipped, raid touches zero endpoints for the remainder of the install. The follow-up runs only on the explicit-decline path: non-TTY, headless, DO_NOT_TRACK, already-decided, and raid telemetry ... invocations skip both prompts. Closes the opt-out-rate measurement gap that's otherwise impossible to fill from website analytics alone.

Per-task output prefixing in concurrent runs. Tasks with concurrent: true now have their stdout/stderr lines prefixed with [task-name] and rendered in a deterministic per-task color, so interleaved output stays attributable. Prefixing is automatically suppressed on non-TTY sinks (pipes, file redirects, CI logs, and the MCP server's capture buffer), so machine-readable output is byte-identical to today. NO_COLOR=1 strips just the color; --no-prefix / RAID_NO_PREFIX=1 strips both. Partial trailing lines without a final newline are flushed with their prefix when the task exits, so output is never silently lost. See raid → Output prefixing in concurrent runs. Closes #77.

0.16.0 — upcoming

Opt-in anonymous CLI telemetry. raid can now send anonymous usage events to PostHog so the project can prioritize features against real signal (which task types matter, which commands fail, which features go unused). Off by default — a fresh install never sends anything until you opt in. The first interactive run prompts (capital-N default); non-interactive contexts (TTY-less stdin, --yes/--headless, --json, DO_NOT_TRACK=1, or a raid telemetry ... invocation) skip the prompt and leave telemetry off. New raid telemetry on / off / status / purge / preview subcommand manages the state; preview renders the exact payload raid would post (with the API key redacted) so you can audit before opting in. Captured events carry sanitized properties only — command names and task types, never cmd: bodies, paths, env values, or stdout/stderr. See the full disclosure at /docs/telemetry. Closes #80.

0.15.0 — upcoming

Headless mode for CI, scheduled runs, and agents. A new top-level -y / --yes / --headless flag (and RAID_HEADLESS=1 env-var equivalent) auto-resolves interactive prompts so non-interactive callers no longer deadlock on a Confirm or Prompt. Confirm auto-accepts; Prompt skips stdin and uses its default: value; a Prompt without a default fails fast with a structured HEADLESS_PROMPT_NO_DEFAULT error (exit code 3) instead of silently setting the variable to empty. The flag and env var are interchangeable — the flag works by setting the env var, so a single read site in lib serves both the CLI and programmatic entry points. Headless auto-accepts every Confirm, so stronger destructive-action guardrails must be expressed via a verify: entry, a condition:, or an explicit env-var check. See raid → Headless mode. Closes #67.

0.14.0 — upcoming

Agent-oriented metadata on commands. Commands now accept an optional agent: block (safe, reads, writes, description) so MCP clients can decide whether to auto-execute a command or prompt the user for approval. The raid://workspace/commands resource always emits agent.safe for every command — entries authored without an agent: block surface as {safe: false}, preserving the current "requires confirmation" semantics by default. The metadata is a hint: raid surfaces it; the agent client implements the policy. Both top-level profile commands and per-repo raid.yaml commands carry the metadata. See Schema → Agent metadata and Context → Agent metadata on workspace commands. Closes #51.

raid doctor runs verify: entries with self-heal. Every verify: entry on the active profile and per-repo raid.yaml files now runs as part of raid doctor and produces its own finding: ok for a first-try pass, warn when the optional onFail: block recovered a failing precondition (the verify holds now, but didn't before — worth knowing), and error when the precondition can't be made to hold. Failures don't short-circuit subsequent entries, so a single raid doctor run reports the full picture. Doctor invokes the actual tasks: and onFail: blocks — any task type raid supports (shell, HTTP, Git, Template, Prompt/Confirm, SetVar, …), not just shell. Keep verify checks small and fast, since they'll run every time you (or CI, or an agent) checks raid's health. See Doctor → Verify entries. Closes #42.

Declarative verify: blocks. Profiles and per-repo raid.yamls now accept a top-level verify: list. Each entry runs tasks: to assert a precondition (a tool is installed, a port is reachable, a credentials file exists), and an optional onFail: remediation gets exactly one chance to fix things — if it succeeds, raid re-runs tasks: once and the verify is reported as remediated; otherwise it surfaces as a structured VERIFY_FAILED error. Verify entries share execution context with install: tasks (active env + raid vars + task options). raid doctor integration is now wired (see entry above). See Schema → Verify. Closes #38.

Shared options: block on every task type. A new options: block on the base task definition composes uniformly across every task type (and on user-defined commands) so cross-cutting fields don't have to be re-declared per type. The initial field, showExeTime: bool, prints a dim line to stderr after a task or command completes with the elapsed time: task-name complete in 1.2s. Omitting options (or any field within it) leaves current behavior unchanged, so the addition is fully backwards compatible. Additional fields (quiet, timeout, …) will ship additively. Closes #54.

Best-effort tasks via options.continueOnFailure. Setting options.continueOnFailure: true on a task makes its non-zero exit non-fatal — subsequent tasks still run and the command's overall exit code is only affected by non-ignored failures. The ignored failure is surfaced as a dim warning on stderr (warning: <name> failed (continueOnFailure): <err>) so it stays visible. Useful for cleanup teardown, optional lint/format probes, and best-effort smoke checks that shouldn't block the rest of the command. Closes #76.

0.13.0 — upcoming

Structured error output. Every raid failure now carries a stable code (e.g. PROFILE_NOT_FOUND, REPO_NOT_CLONED, CLONE_FAILED, TASK_SHELL_FAILED), a category that maps directly to one of five exit codes (1 generic / 2 config / 3 task / 4 network / 5 not-found), and an optional hint explaining what the user can do next. Pass --json to any command (including raid install, raid profile add, custom commands) and errors come back as a single line of {"error": {"code": "...", "category": "...", "message": "...", "hint": "..."}} — agents can pivot on the code instead of parsing prose. The --json flag itself moved from per-command to a persistent flag on rootCmd, so it now works on every command. Error codes are treated as semver-stable: new codes ship additively; existing codes never change name or category across minor versions. See the new Errors reference for the full table and JSON shape. Closes #47.

0.12.0 — upcoming

Repo-as-a-profile for single-repo projects. raid profile add ./raid.yaml now accepts a repo config directly — no wrapping profile file required. Raid detects the repo schema, registers the file as a single-repo profile named after the raid.yaml's name field, and raid profile <name> activates it like any other profile. Commands, environments, and install tasks defined in the raid.yaml become available at the top level. Existing multi-repo profiles continue to work unchanged. Closes #52.

0.11.1 — upcoming

Schemas published at a stable URL. The profile, repo, and shared-defs JSON Schemas are now served at https://raidcli.dev/schema/v1/raid-profile.schema.json, …/raid-repo.schema.json, and …/raid-defs.schema.json. Generated profile and repo templates point at these URLs out of the box, so YAML LSPs and agents get autocomplete and inline validation against the canonical contract. The /v1/ path is a stability promise — additive changes only; breaking changes will publish to /v2/. The docsite build copies schemas/ into static/schema/v1/, so the canonical source remains the single Go-embedded copy. Closes #48.

0.11.0 — upcoming

Declared arguments and flags on custom commands. commands[] entries now accept an args list (named positional arguments) and a flags list (long/short options with optional default and type — string, bool, or int). Declared values are exported as env vars named after each entry (uppercased), so args: [{name: ticket, required: true}] makes $TICKET available in tasks for the duration of the command. Cobra enforces required values and validates positional cardinality before raid runs anything. RAID_ARG_N continues to work for unnamed positional arguments. Closes #26.

0.10.1 — upcoming

Plain-yaml profiles via raid profile add <url>. When the URL points at a git repo (or a single-file gist) whose profile file isn't named with the *.raid.yaml convention — e.g. just profile.yaml, myprofile.yml, or config.json — raid now picks it up as a fallback after no *.raid.yaml/profile.json matches are found. Schema validation runs the same way, so non-profile YAML lying around in a repo root is still rejected with a clear "invalid profile" message. Makes ad-hoc gists usable without renaming the file.

0.10.0 — upcoming

Local-only repositories. url is now optional on profile repository entries. Omit it for projects that aren't backed by a git remote — raid skips cloning and runs install tasks against the existing path. The path must already exist on disk; if it doesn't, raid surfaces a clear error instead of trying to git clone "". raid doctor no longer flags a missing .git directory as a warning for local-only repos. Closes #71.

0.9.0 — upcoming

Live variable updates in the MCP server. raid context serve now watches ~/.raid/vars and reloads the workspace when the file is modified by another raid process, a Set task in a separate invocation, or a hand edit. Connected MCP hosts see fresh state on the next read instead of stale values cached at server start. Reloads run under the cross-process mutation lock so they serialize cleanly with concurrent install / env-switch / run-task calls. Closes #27.

Variables as an MCP resource. Persisted raid variables — Set-task values plus the auto-derived RAID_REPO_* keys — are now exposed as raid://workspace/vars (JSON object). Joins the existing profile, env, repos, commands, and recent workspace resources.

0.7.0 — upcoming

Add profiles from a URL. raid profile add now accepts a git repo URL or a direct file URL in addition to a local path. Pass a GitHub (or any git host) URL and raid shallow-clones the repo, finds *.raid.yaml, *.raid.yml, or profile.json files at the root, and saves them to ~/<name>.raid.yaml. Pass a raw HTTPS URL ending in .yaml/.yml/.json and raid downloads and registers it directly. Ambiguous HTTPS URLs are probed with git ls-remote to determine the right strategy automatically.

MCP server. raid context serve runs raid as a Model Context Protocol server over stdio, so MCP-aware hosts (Claude Code, Cursor, Cline) can read the active workspace as resources and invoke raid tools (raid_install, raid_env_switch, raid_run_task, raid_list_profiles, raid_list_repos, raid_describe_repo) directly. Output from mutating tools is captured into the tool result so it doesn't corrupt JSON-RPC framing on stdout. See Context → MCP server.

Set variables reach subprocesses. Variables defined by a Set task are now exported as environment variables to Script and Shell task subprocesses, so a script's source can reference $VAR directly without raid pre-expanding the script body. Raid values take precedence over OS-environment variables of the same name.

Repo metadata as variables. Every repository in the active profile is now auto-exposed as RAID_REPO_<NAME>_URL, RAID_REPO_<NAME>_PATH, and RAID_REPO_<NAME>_BRANCH, so tasks can reference repo URLs, paths, and branches without hardcoding them. Names are uppercased with non-alphanumerics replaced by _ (so my-api becomes RAID_REPO_MY_API_URL).

--json on read commands. raid profile list, raid env, raid env list, and raid doctor accept --json for scriptable, machine-readable output. raid context --json already shipped in 0.6.0; this rounds out per-command JSON for shell pipelines and CI checks. Output shapes are stable; doctor severities are encoded as ok/warn/error strings.

Cross-process mutation lock. A flock-backed lock at ~/.raid/.lock serializes mutating operations across any combination of CLI usage and MCP-driven tool calls — concurrent installs or env switches from two raid processes now wait for one another instead of racing on ~/.raid/config.toml or repository state. Read paths are unaffected.

0.6.0 — upcoming

raid context command. A condensed, token-efficient snapshot of the active workspace — profile, environment, repositories with live git state, user-defined commands, and recent command-run history. Use raid context for human-readable output or raid context --json for an MCP-shaped JSON document agents can paste into a chat.

Recent command-run log. raid <command> invocations are recorded to ~/.raid/recent.json (capped at 10 entries) with status, exit code, duration, and timestamp. Surfaced both in raid context output and as the raid://workspace/recent MCP resource. Commands killed mid-execution are reported as interrupted instead of vanishing.

Named task steps. Tasks gained an optional name field. When set, those names appear as a steps outline under the parent command in raid context — letting agents see what a command does without exposing the underlying scripts. Schema also refactored to a shared taskCommon $ref so future shared task properties can be added in a single place.

0.5.0 – 0.5.3 — April 2026

  • Shared stdin reader across Prompt and Confirm tasks so consecutive prompts read cleanly without buffer interleaving (#39)
  • Mobile-friendly docsite refresh and consolidated build process (#36)
  • SEO + LLM-friendly README, llms.txt, page metadata, and social card (#35)
  • Path resolution consistency improvements (#37)

0.4.0 – 0.4.1 — March 2026

Set task type. A dedicated task for defining a variable that persists for the duration of the command session, with the highest precedence in raid's lookup order (#17).

Single-repo install. raid install <repo> clones and installs just the named repo from the active profile, instead of all of them (#19).

Command session management. Variables exported by a Shell task (export FOO=bar) survive into subsequent tasks in the same raid <command> invocation. Resets cleanly between separate command runs (#18).

0.3.0 – 0.3.8 — March 2026

  • User commands accept positional arguments via RAID_ARG_1, RAID_ARG_2, … (#15)
  • User-defined commands now appear in raid --help output (#16)

0.1.0 – 0.2.x — March 2026

Initial public beta. Cross-platform Go CLI with declarative YAML profiles, per-repo raid.yaml configs, install / env / custom-command flows, eleven task types (Shell, Script, Set, Git, HTTP, Wait, Prompt, Confirm, Print, Template, Group), JSON Schema validation, and stable + preview release channels.