All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning. Releases are cut by hand from a release PR; see docs/RELEASING.md.
Version history. The next release, v0.3.0, is the first published under the
rhoname and module pathgithub.com/GrayCodeAI/rho. Sections labelledhawkbelow are kept as the historical record of the project before the rename:hawk 0.2.0is thev0.2.0tag, which (likev0.1.0andv0.1.1) was built from thegithub.com/GrayCodeAI/hawkmodule and shipshawk_*archives; the sections marked "untagged" used an earlier numbering that was never tagged. Names in those sections are the names of the time (for example Flux was called eyrie, and several companion repos have since been retired).
- Release process and guards:
docs/RELEASING.md(release PR checklist, tag protection, what the release workflow publishes, how to verify a release, status of every distribution channel);scripts/check-release-tag.sh, used by the release workflow andmake release-check, refuses a tag that is notv+VERSIONor has noCHANGELOG.mdsection;make release-snapshotbuilds every archive locally without publishing or signing. - windows/arm64 release archives: GoReleaser and the CI build matrix now cover all six linux/darwin/windows × amd64/arm64 targets.
- Version 0.3.0:
VERSIONis0.3.0, the first release under the rho name (the Go proxy already holds the hawk-era v0.1.0–v0.2.0), and the compatibility matrixstableentry pins rho 0.3.0 with flux 0.0.1. - Release workflow can publish: it installs syft for the SBOMs, signs
checksums.txtinside GoReleaser with cosign keyless signing (checksums.txt.sigstore.json), re-verifies the published signature, takes the release notes from this file, builds withGOWORK=offand-trimpath, and drops the unusedpackages: writepermission and sibling checkout. - Binary size budget enforced:
make size-checkfails aboveSIZE_LIMIT_MB(70 MiB; linux/amd64 is 59.6 MiB today) and CI runs it instead of only warning above 98 MB. make releaseno longer publishes from a workstation; releases come only from the tag-triggered workflow.- npm scaffolding kept unpublished: packages are marked
"private": truewith the correct MIT license, and assembly stamps the meta package and itsoptionalDependenciesand reads GoReleaser v2's output paths. Nothing is published to npm. - Dependency renamed eyrie → flux: rho now depends on
github.com/GrayCodeAI/flux v0.0.1(the provider runtime was renamed). All imports, env vars (EYRIE_CONFIG_DIR→FLUX_CONFIG_DIR,EYRIE_MODEL_CATALOG_PATH→FLUX_MODEL_CATALOG_PATH), boundary-guard scripts, ecosystem manifest entries, docs, and internal identifiers were renamed to match. User state paths move from~/.../eyrie/provider.jsonto~/.../flux/provider.json. - Makefile lint pin matches CI:
make lint/lint-fix/setupinstallgolangci-lint@v2.1.0(was@latest), the same version CI enforces. - Docs truth and housekeeping: SECURITY.md/CONTRIBUTING.md now describe the actual Go toolchain (golangci-lint, go vet, govulncheck) instead of the polyglot template's ruff/mypy/pip-audit/pnpm-lock language, CONTRIBUTING documents
make setup/boundaries/test-10x/smoke, and the planning docs (SPEC_DRIVEN_PLAN.md,SPEC_DRIVEN_PHASE2_PLAN.md,internal/engine/REFACTOR_PLAN.md) moved todocs/plans/.
install.shverifies releases fail-closed: with cosign installed it verifieschecksums.txt.sigstore.jsonagainst the exact release-workflow identity and aborts on a missing or invalid signature; without cosign it warns and reports the signature as not verified, andRHO_REQUIRE_COSIGN=1makes cosign mandatory. The SHA-256 check always runs, flags are parsed strictly (unknown flags exit 2), and releases older than v0.3.0 (hawk-era archives) are refused.- GitHub Action installs signed release archives through
install.shwith cosign required, instead of building an unverifiedcurl | tarsource tarball;rho-versionaccepts0.3.0,v0.3.0orlatest, and Go is no longer needed. - systemd unit: runs as a dedicated
rhouser with state inStateDirectory/CacheDirectory(the old%hpaths were hidden byProtectHome=true), reads the daemon API key from anEnvironmentFileinstead of the command line, and links the troubleshooting guide instead of a dead domain. - Session lock TOCTOU eliminated:
AcquireLock's stat → stale-if->5min → remove → O_EXCL dance could delete a live lock on misjudged staleness and let two instances open the same session. Mutual exclusion now uses an OS advisory lock (gofrs/flock, promoted to a direct dependency); a crashed holder's lock is reclaimed instantly because the kernel drops the flock at process death. The lock file keeps PID/timestamps purely as diagnostics. - Hardened atomic writes for state files: global settings, checkpoint file contents and restores, handovers, and named checkpoints now go through
internal/safewrite(same 0600 mode as before, plus fsync+rename atomicity and symlink refusal at the destination). - Dead shell-injection surface removed:
AssumptionTracker.VerifyCommandSucceedsran caller-supplied strings throughsh -c, bypassing the permission stack; it had zero callers and is deleted.SelfHealer.RunScriptno longer shell-evaluates the script path (double evaluation) and invokes it directly via/bin/sh.
- Engine subprocesses are bounded and observable: experiment-loop rollback, auto-commit git calls, and post-edit syntax validators (
go vet,python3,node,npx tsc) ran oncontext.Background()with ignored errors; they are now time-bounded and log failures instead of discarding them. - Memory and config failures no longer silently dropped: stream-loop memory persists (assistant learnings, skills, conversation summaries, insights) and the self-improve lesson store log failures via slog, corrupt lesson stores are reported, and the config panel surfaces failed
providersetting saves instead of ignoring them.
- Homebrew publisher and install instructions: the
brewsstanza (deprecated in GoReleaser v2) targeted aGrayCodeAI/homebrew-taprepository and token that do not exist; the README no longer offers Homebrew or npm installs. flake.nixand its.envrc: the flake depended on five deleted repositories and could not evaluate.- ast-grep configuration (
sgconfig.yaml,rules/, lefthook hook): ast-grep never discovered the config and CI never ran it. - BREAKING —
rho credentials migrateremoved: the subcommand, its man page entry, and theMigrateEnvFileCredentialswrappers are gone, andrho pathno longer reports legacy~/.rho/env/~/.rho/.envfiles. Save keys through/config. - BREAKING — settings model/provider migration removed:
LoadSettingsno longer movesmodel/providerfromsettings.jsoninto Flux'sprovider.json, andSetActiveSelectionis deleted. Stalemodel/providervalues left insettings.jsonare now ignored on load (Flux's selection wins;--settingsoverrides still apply); select the model in/config. - BREAKING — startup provider-secrets migration removed: print/REPL/watch/TUI startup no longer calls
MigrateProviderSecrets, and the method is dropped from the gatewayCatalogMaintenanceinterface.rho pathstill fails whenprovider.jsonholds secrets; remove those fields manually. - BREAKING —
shared/typesguards removed:scripts/check-shared-types-imports.sh, thecontracts-guardmake target, its lefthook and CI steps, and the matching testaudit checks are deleted because the package no longer exists. The ecosystem boundary guards still blockrho/internalimports.
- Rho/Flux production boundary completed: Rho owns the product face,
sessions, tools, permissions, and public schemas while Flux v0.2.1 (then
named eyrie; flux itself has only tagged v0.0.1) owns
credentials, catalog resolution, provider transport, resilience, and usage
telemetry behind the stable
flux/enginefacade. - Provider routing and usage attribution hardened: resolved route changes, continuation segments, and terminal usage are propagated without duplicate accounting, and production Flux calls use exactly one resilience layer.
- Daemon conversations are durable: JSON and SSE chat requests create or resume persisted sessions, expose stable session IDs, preserve metadata, and distinguish invalid, missing, and corrupt state.
- Release and supply-chain gates strengthened: exact ecosystem Gitlinks, module/tag parity, Trivy enforcement, public-module builds, SBOM generation, and cross-platform artifacts are part of the release path.
- Fixed
/mode automisclassifying plain English as shell commands:shellmode.ClassifyInputtrustedexec.LookPath(firstWord)alone, so any sentence starting with a word that's also a real Unix binary (make sure this works,find the bug in this file,kill the old branch,sort out the imports...) was silently executed as a shell command instead of being sent to the model — confirmed 18 of 20 sampled sentences misclassified before the fix. Now a curated allowlist of unambiguous dev-tool names (git,npm,docker,ls,cat, ...) is trusted immediately, while every other PATH match requires real shell-syntax evidence (a flag, a path, a file extension, or an operator like|/>/&&) before being trusted as a shell command — matching the same ambiguity Warp's own terminal autodetect documents and resolves with a user-configurable denylist. - Permission system unified into two independent axes: the old
PermissionMode(default/acceptEdits/bypassPermissions/dontAsk/plan) is removed./autonomynow controls the 5-tier trust ladder (Always Ask/Scout/Builder/Operator/Autonomous, bare/autonomyopens a picker), and/speccontrols an independent, orthogonal spec-driven workflow gate (Specify → Plan → Tasks → ApproveImplementation, bare/specopens a picker) that blocks Write/Edit/Bash regardless of trust tier — including at Autonomous. Fixes a real bug where the old Plan Mode's write-block could be silently bypassed at high autonomy tiers, since tier and mode were checked independently with no ordering guarantee. - Fixed
PermissionService.SetAutonomy/Autonomy(): previously wrote to/read from a shadow field the permission engine'sCheckToolnever consulted, meaning autonomy tier changes may not have reliably taken effect. Now both read/write the samePermissionEngine.Autonomyfield the check logic uses. --permission-modeCLI flag removed;--dangerously-skip-permissionsunchanged (now maps to the Autonomous tier). New--dry-runflag added as an unconditional kill switch (deny every tool call, regardless of tier or spec stage) — replacesdontAsk's hard-lockout role.- Version re-baselined to
0.1.0acrosscmd/rho/main.go,cmd/daemon.go,flake.nix,.github/workflows/release.yml, and theupdate/daemon test suites, aligning rho with the rest of the GrayCodeAI ecosystem (flux,shrike,harrier,kestrel,merlin). - Architecture boundary hardening: Rho now owns runtime request/response DTOs, transport config/provider seams, and review/verification product-boundary contracts, with
flux/clientusage restricted to internal adapters and guarded in CI. shared/typesremoved: Rho no longer ships the old shared type path, and local boundary checks now block any attempt to reintroduce it.
- Spec-driven workflow (
/spec): independent, orthogonal permission gate that walks the model throughSpecify → Plan → Tasks, writing realspec.md/plan.md/tasks.mdfiles to.rho/specs/<slug>/, and requires explicitApproveImplementationapproval (always prompts, at any trust tier) before Write/Edit/Bash unlock. The approval prompt shows the actual written content, not a blind yes/no. /autonomyand/specpicker overlays: bare/autonomyor/specopens an arrow-key-navigable, filterable picker (Esc/Enter) instead of requiring subcommand syntax; typed subcommands (/autonomy tier scout,/spec status, etc.) still work.- Watch mode (
--watch): file-watcher loop that acts onAI!(do-now) andAI?(answer) code comments. Off by default. - GitHub Action (
.github/actions/rho): interactive mode on@rhomentions, automation mode on labeled issues/PRs, and skill dispatch for/-prefixed prompts. - Messaging gateways: opt-in Telegram, Discord, and Slack gateways on the daemon for chatting with rho from messaging apps.
- AST repo-map (
internal/context/repomap): structural repository map for richer model context. - Auto codebase analysis on first run (
internal/autoinit): opt-in seeding of project context. - Auto-lint / auto-fix cycle: runs the matching linter after edits and iterates on fixes with bounded retries (opt-in).
- Image / multimodal context (
internal/engine/vision.go): feed screenshots/images to vision-capable models. - Plan & Explore sub-agent modes: read-only
plan(task decomposition) andexplore(codebase investigation) modes; explore supportsquick/medium/very-thoroughthoroughness budgets. - Persona
colorandhooks: per-agent display color and lifecycle hook (pre_run/post_run) fields. - YAML agents & eval tasks: define personas and eval tasks in YAML alongside markdown personas.
- IT-managed policy tier (
internal/context/rules.go): non-excludable org-policy rule tier with highest precedence; strips HTML comments from rule files. - SQL exploration tool (
internal/tool/sql.go): read-only database exploration tool. - Conventional-commit generation:
SmartCommitand the diff summarizer produce Conventional Commit messages from staged changes. - Durable workflows + named checkpoints (
internal/multiagent): LangGraph-style resumable workflows with named, persisted step boundaries. - Human-in-the-loop approval gates (
internal/engine/approval_gate.go): durable approve/reject gates within workflows. - Structured output (
internal/engine/structured_output.go): JSON-Schema-constrained responses, validated and retried once on mismatch. - MCP WebSocket transport (
internal/mcp/ws.go): opt-in WebSocket transport in addition to stdio/HTTP. GET /v1/ready: dependency-aware readiness endpoint on the daemon.- REPL magic commands (%reset, %undo, %tokens, %history, %copy, %save, %compact, %model, %clear)
- Prompt cache keep-alive pings
- Unified finding/severity contracts now live in
eagle/types
- Cavecrew personas (
internal/multiagent/agents): three new built-in personas built into GrayCode Rho (cavecrew-investigator,cavecrew-builder,cavecrew-reviewer). Each enforces a strict output format so downstream agents can parse outputs mechanically:cavecrew-investigator:path:line — symbol — note, max 6 words per notecavecrew-builder: hard-refuses tasks touching 3+ filescavecrew-reviewer: severity emoji (🔴/🟡/🔵/❓) at the start of every line Exposed viaCavecrewPersonas()helper andEnsureCavecrew()registry method;BuiltinPersonas()returns 21 (was 18).
internal/safewritepackage: hardened atomic file-write utility native GrayCode hardened atomic writes. Refuses symlinks at destination and parent, refuses paths that escape via.., opens withO_NOFOLLOWviagolang.org/x/sys/unix, writes to a temp file with mode 0600, syncs to disk, then atomically renames.ErrSymlinkTargetandErrPathEscapesentinel errors.internal/jsoncpackage (since removed): JSON-with-Comments parser andValidateClaudeSettingsvalidator, native GrayCode settings parser andvalidateHookFields. Accepts//and/* */comments plus trailing commas in objects and arrays. Validates Claude Codesettings.jsonfields (model, permissions, hooks, mcpServers, env) with type checks and value validation.internal/permissions/verdict.go(since removed): unifiedPermissionVerdicttype with Risk levels (RiskLow,RiskMedium,RiskHigh,RiskBlocked). Helpers:Allow,Deny,RequireApproval. Additive change — existingGuardianDecisionis unchanged.internal/providerspackage (since removed): PROVIDERS matrix (34 entries) native GrayCode PROVIDERS matrix. Each entry describes an AI coding agent (Claude Code, Cursor, Codex, Aider, etc.) with install mechanism and detection probes. Probe kinds:command(PATH),dir(filesystem),vscode-ext,cursor-ext,macapp,jetbrains-plugin. API:Get(id),All(),Hard(),Detect().Soft: truemeans detection is best-effort; soft providers are excluded from auto-detect.internal/session.GainTracker: per-session gain event recording in a newgainsSQLite table inside the session store. Each event captures original/compressed byte + token counts, mode/tier/model, and a command label. API:Record,AggregateForSession,ListForSession,PruneForSession. Scoped to a single session so callers can selectively compact their own history. Companion to shrike'sinternal/tracking.Tracker(shrike tracks globally, rho tracks per-session).
- Stricter linting:
.golangci.ymlv2 config enablingerrcheck,staticcheck,gocritic(diagnostic + performance),unused,ineffassign,misspell,noctx,bodyclose,unconvert,whitespace, withgovet enable-all(minusfieldalignment). - CI parity: race-detector tests with coverage upload, golangci-lint v2 action,
govulncheckandgosecsecurity scans, multi-platform build matrix (linux/darwin/windows × amd64/arm64), benchmark job on PRs. - Makefile with standard targets:
build,test,test-coverage,test-10x,lint,fmt,vet,security,bench,clean,install,release,help. - Container: Dockerfile uses
tiniinit, embeds tzdata, verifies deps, runs as non-root. - Repository hygiene:
.editorconfigfor cross-editor consistency andCONTRIBUTING.mdwith the full contributor workflow.
- 240+ unchecked error returns hardened across
session,engine,tool,config,auth,cmd,daemon,diffsandbox,analytics,cmdhistory,container,eval,fingerprint,updatepackages. - Dead-code removal: 13 unused declarations removed (caught by the
unusedlinter). - Real bugs fixed where
appendresults were silently discarded (mcp/server.go,repomap/depgraph.go, flagged bystaticcheck SA4010). sessionpackage is now fullyerrcheck-clean, protecting persistence integrity.
authpackage coverage raised from ~18% to ~71% with table-driven tests covering every code path.updatepackage coverage raised from ~22% to ~92% with full HTTP mocking, including error paths (server failure, invalid JSON, unreachable host) andSummary()rendering.
- Exec Subcommand:
rho exec "prompt"— full engine non-interactive mode with--output-format json,--autoautonomy levels,--worktreeisolation,--agentpersonas,--session-idresume, stdin piping - Daemon Server:
rho daemon start/stop/status— background HTTP server with JSON + SSE streaming on/v1/chat,/v1/health,/v1/sessions - Mission Mode:
rho mission "prompt"— multi-agent orchestration decomposing work into parallel features executed in isolated git worktrees.--dry-runfor planning only - Session Search:
rho search "query"— full-text search across all saved sessions with--jsonoutput - Custom Agents:
rho agent list/create/show/remove— markdown persona definitions in~/.rho/agents/with YAML frontmatter (name, description, model) - Snapshot System: Shadow git tracking of every file change.
rho snapshot list/restore/diff+/snapshotslash command. Auto-snapshots on every Write/Edit tool call - Waza Workflows:
/think(plan before code),/hunt(root-cause diagnosis),/check(pre-ship review with auto-fix),/design(screenshot-driven UI iteration) - Structured Compaction: Summary template with Goal/Constraints/Progress/Files/Decisions/Errors/Instructions/Next sections for better intent preservation
- Doom Loop Detection: Lowered threshold to 3 (from 4). Two-tier escalation: first detection injects redirect prompt, doom loop hard-stops with "ask user for help"
- Session Persistence for exec: All exec runs saved to
~/.rho/sessions/and searchable viarho search
mission/— Multi-agent orchestration with worktree-based parallel workersdaemon/— HTTP server with session factory, SSE streaming, PID file managementagents/— Markdown persona loader with frontmatter parsingsnapshot/— Shadow git repository for granular file-level undo
- Factory Droid v0.117.0 (exec mode, daemon, mission orchestration, custom agents)
- OpenCode (structured compaction, snapshot system, doom loop escalation)
- Waza by tw93 (engineering-habit workflows: think, hunt, check, design)
- Model Cascade Router: Cost-aware routing that classifies prompts and selects optimal model tier (simple→Haiku, debug→Sonnet, generation→Opus). Supports frugal mode for aggressive cost savings. Tracks routing decisions for analytics.
- Dynamic max_tokens: Adaptive output budgets based on task type and recent tool-call patterns. Reduces output token costs 15-25% by not over-allocating.
- Cheap Compaction Model: Conversation summaries now use the cheapest available model (Haiku/gpt-4o-mini) instead of the primary model. Saves $0.10-0.50 per compaction.
- Context Budget Allocator: Formal token allocation across system prompt, tool defs, repo map, memory, workspace, pre-loaded files, and conversation. Adaptive: shrinks file budget as conversation grows. Triggers compaction at threshold.
- LLM Reflection Engine: Verbal self-reflection after failed attempts (Reflexion pattern). Asks "what failed, why, what to do differently" instead of mechanical summaries. Accumulates episodic memory buffer.
- Self-Review Before Write: Rubber duck debugging step between code generation and file write. Model explains its code and checks for bugs/regressions before applying.
- Session Lifecycle (Self-Improvement Loop): Closed loop wiring OnSessionStart (retrieve guidelines + skills) and OnSessionEnd (learn guidelines, distill skills, record cost).
- Import/Dependency Graph: Parses import statements for Go, Python, TypeScript. Builds forward/reverse edges. DependenciesOf, DependentsOf, ImpactSet with BFS depth control.
- Change-Set Aware Context: Loads only code relevant to current
git diff. 70-90% context reduction for focused tasks. FormatContext with token budgeting. - Landlock Sandbox (Linux): Zero-dependency, zero-overhead, unprivileged filesystem isolation. Restricts agent to project dir + /tmp. Default Linux sandbox.
- seccomp-bpf Syscall Filtering (Linux): Blocks 21 dangerous syscalls (mount, ptrace, reboot, kexec_load, init_module, bpf, etc.). Applied via SysProcAttr.
generateSummary()now uses cheapest available model per provider instead of primary model- Ecosystem roadmap added:
ECOSYSTEM-ROADMAP.mdwith 30-feature prioritized implementation plan
- Bash Security: zsh bypass protection, process substitution blocking, IFS injection detection, carriage return prevention, ANSI-C quoting detection, git commit safety
- Hook System: 8 event types with priority-based execution (pre_query, post_query, pre_tool, post_tool, session_start, session_end, permission_ask, error)
- Plugin System: manifest validation, install/list/uninstall, hook registration, command execution
- Advanced Permissions: auto-mode learning, command classifier, bypass killswitch, shadowed rule detection
- Model Catalog: 25+ models across 7 providers with pricing and context sizes
- Session Memory: extraction, search, and consolidation
- Analytics: event logging, session traces, cost tracking
- Auth System: secure token storage with OS keychain integration
- Auto-Update: GitHub release checking
- LSP Integration: JSON-RPC client and server manager
- Voice Mode: Whisper.cpp integration
- Magic Docs: Go AST parsing and automatic markdown generation
- Worktree Tools: EnterWorktree/ExitWorktree with validation
- Retry Package: exponential backoff for API resilience
- Circuit Breaker: three-state circuit breaker for fault tolerance
- Rate Limiter: token bucket algorithm
- Logger: structured logging with levels
- Health Checks: registry with status aggregation
- Metrics: counters, gauges, timers with atomic operations
- Graceful Shutdown: signal-based shutdown with hooks
- Profiling: CPU, memory, goroutine profiling
- Tracing: distributed tracing spans
- Config Validation: field-level validation errors
- Benchmarks & Fuzz Tests: bash security parsing
- Shell Completion: bash, zsh, fish, powershell
- Docker: multi-stage build with non-root user
- Nix Flake: reproducible builds
- GitHub Actions: CI with test, build, lint, coverage; release with GoReleaser
- Improved error messages with context wrapping
- JSONL session storage with legacy JSON fallback
- Stream-JSON usage events with token tracking
- Pre-compiled regexes for performance
- Project scaffold with cobra CLI and Bubbletea TUI
- Interactive chat REPL with textarea input, spinner, lipgloss styling
- flux wired as LLM provider dependency
- GitHub Actions CI