From c7912e0010473e9fce08de57a6253a3524289882 Mon Sep 17 00:00:00 2001
From: Lakshman Patel
Date: Sun, 11 Oct 2026 07:37:20 +0530
Subject: [PATCH 1/4] refactor: rename Rho to Decoder and integrate renamed Mux
---
.env.example | 14 +-
.github/CODEOWNERS | 2 +-
.github/ISSUE_TEMPLATE/bug_report.yml | 14 +-
.github/ISSUE_TEMPLATE/config.yml | 4 +-
.github/ISSUE_TEMPLATE/feature_request.yml | 12 +-
.../action.yml | 4 +-
.github/actions/{rho => decoder}/action.yml | 160 +++++------
.github/actions/setup-deps/action.yml | 4 +-
.github/workflows/ci.yml | 60 ++--
.github/workflows/compatibility-matrix.yml | 4 +-
.github/workflows/release.yml | 6 +-
.gitignore | 12 +-
.golangci.yml | 2 +-
.goreleaser.yml | 24 +-
.shared-templates/.goreleaser.yml.tmpl | 6 +-
.shared-templates/Makefile.binary.tmpl | 10 +-
.shared-templates/Makefile.library.tmpl | 2 +-
.shared-templates/Makefile.python.tmpl | 2 +-
.shared-templates/README.md | 14 +-
.shared-templates/docs/coverage-matrix.md | 4 +-
.../check-ecosystem-boundaries.sh.tmpl | 26 +-
.shared-templates/scripts/sync-external.sh | 4 +-
.../workflows/compatibility-test.yml.tmpl | 6 +-
.shared-templates/workflows/go-ci.yml.tmpl | 2 +-
.../workflows/go-release.yml.tmpl | 6 +-
.../workflows/python-ci.yml.tmpl | 2 +-
AGENTS.md | 104 +++----
CHANGELOG.md | 80 +++---
CODE_OF_CONDUCT.md | 4 +-
CONTRIBUTING.md | 8 +-
Makefile | 34 +--
README.md | 265 +++++++++---------
SECURITY.md | 26 +-
api/openapi.yaml | 26 +-
cmd/acp.go | 20 +-
cmd/agent.go | 10 +-
cmd/agent_grid.go | 4 +-
cmd/agent_grid_test.go | 2 +-
cmd/agent_test.go | 6 +-
cmd/ai_comments.go | 2 +-
cmd/audit.go | 16 +-
cmd/autoinit.go | 14 +-
cmd/autoinit_test.go | 4 +-
cmd/autonomy_picker.go | 2 +-
cmd/autonomy_picker_test.go | 2 +-
cmd/autonomy_tiers.go | 2 +-
cmd/autonomy_tiers_copy_test.go | 2 +-
cmd/autonomy_tiers_test.go | 2 +-
cmd/bg_sessions.go | 18 +-
cmd/braille_spinner.go | 26 +-
cmd/braille_spinner_test.go | 28 +-
cmd/cascade_diag_test.go | 6 +-
cmd/catalog_startup.go | 10 +-
cmd/chat.go | 94 +++----
cmd/chat_commands.go | 10 +-
cmd/chat_commands_config.go | 18 +-
cmd/chat_commands_image.go | 4 +-
cmd/chat_commands_session.go | 8 +-
cmd/chat_commands_skills.go | 6 +-
cmd/chat_commands_test.go | 14 +-
cmd/chat_commands_tools.go | 8 +-
cmd/chat_commands_util.go | 14 +-
cmd/chat_config_deployment.go | 74 ++---
cmd/chat_config_gateways.go | 30 +-
cmd/chat_config_gateways_test.go | 52 ++--
cmd/chat_config_hub.go | 6 +-
cmd/chat_config_keys.go | 26 +-
cmd/chat_config_keys_test.go | 32 +--
cmd/chat_config_models.go | 36 +--
cmd/chat_config_models_test.go | 4 +-
cmd/chat_config_panel.go | 64 ++---
cmd/chat_config_region.go | 28 +-
cmd/chat_config_remove.go | 16 +-
cmd/chat_config_remove_test.go | 24 +-
cmd/chat_config_save_flow_test.go | 38 +--
cmd/chat_config_security.go | 2 +-
cmd/chat_config_tabs.go | 24 +-
cmd/chat_config_tabs_test.go | 14 +-
cmd/chat_config_ui.go | 10 +-
cmd/chat_copy_e2e_test.go | 12 +-
cmd/chat_copy_test.go | 14 +-
cmd/chat_errors_test.go | 2 +-
cmd/chat_export.go | 4 +-
cmd/chat_focus.go | 6 +-
cmd/chat_history_search.go | 6 +-
cmd/chat_journey_e2e_test.go | 10 +-
cmd/chat_layout_mouse_test.go | 2 +-
cmd/chat_layout_test.go | 10 +-
cmd/chat_model.go | 50 ++--
cmd/chat_model_test.go | 32 +--
cmd/chat_mouse.go | 18 +-
cmd/chat_multiturn_e2e_test.go | 18 +-
cmd/chat_permission_keys_test.go | 10 +-
cmd/chat_platform_ctx.go | 4 +-
cmd/chat_print.go | 42 +--
cmd/chat_print_usage_test.go | 8 +-
cmd/chat_prompt_timeout_test.go | 12 +-
cmd/chat_scrollbar.go | 2 +-
cmd/chat_select.go | 4 +-
cmd/chat_session_picker.go | 6 +-
cmd/chat_status.go | 18 +-
cmd/chat_status_metadata_test.go | 8 +-
cmd/chat_status_test.go | 44 +--
cmd/chat_stream.go | 4 +-
cmd/chat_subcommand.go | 2 +-
cmd/chat_subcommand_brainstorm.go | 2 +-
cmd/chat_subcommand_branch_agent.go | 8 +-
cmd/chat_subcommand_checkpoint.go | 2 +-
cmd/chat_subcommand_context.go | 6 +-
cmd/chat_subcommand_council.go | 4 +-
cmd/chat_subcommand_ecosystem.go | 4 +-
cmd/chat_subcommand_harness.go | 4 +-
cmd/chat_subcommand_help.go | 2 +-
cmd/chat_subcommand_investigate.go | 2 +-
cmd/chat_subcommand_login.go | 2 +-
cmd/chat_subcommand_memory.go | 4 +-
cmd/chat_subcommand_mode.go | 6 +-
cmd/chat_subcommand_model.go | 18 +-
cmd/chat_subcommand_party.go | 2 +-
cmd/chat_subcommand_path.go | 4 +-
cmd/chat_subcommand_recipe.go | 4 +-
cmd/chat_subcommand_reflect.go | 2 +-
cmd/chat_subcommand_render.go | 2 +-
cmd/chat_subcommand_review.go | 2 +-
cmd/chat_subcommand_shell_test.go | 2 +-
cmd/chat_subcommand_simple.go | 70 ++---
cmd/chat_subcommand_soul.go | 2 +-
cmd/chat_subcommand_spec.go | 4 +-
cmd/chat_subcommand_start.go | 4 +-
cmd/chat_subcommand_status.go | 6 +-
cmd/chat_subcommand_trust.go | 4 +-
cmd/chat_subcommand_version.go | 6 +-
cmd/chat_subcommand_voice.go | 2 +-
cmd/chat_submit.go | 14 +-
cmd/chat_terminal_mouse.go | 2 +-
cmd/chat_tools.go | 12 +-
cmd/chat_tools_lsp_test.go | 6 +-
cmd/chat_tools_test.go | 14 +-
cmd/chat_turn.go | 4 +-
cmd/chat_update.go | 22 +-
cmd/chat_update_overlays_test.go | 4 +-
cmd/chat_update_prompts.go | 12 +-
cmd/chat_update_stream.go | 4 +-
cmd/chat_view.go | 26 +-
cmd/chat_view_test.go | 6 +-
cmd/chat_viewport.go | 2 +-
cmd/chat_viewport_render.go | 8 +-
cmd/chat_viewport_test.go | 10 +-
cmd/chat_welcome.go | 68 ++---
cmd/chat_yolo_confirm_test.go | 2 +-
cmd/checkpoint.go | 14 +-
cmd/cli_contracts_test.go | 18 +-
cmd/clipboard.go | 4 +-
cmd/clipboard_test.go | 2 +-
cmd/cloud.go | 20 +-
cmd/cloud_context_test.go | 4 +-
cmd/cloud_graph.go | 6 +-
cmd/cloud_test.go | 26 +-
cmd/cloud_usage.go | 2 +-
cmd/cloud_usage_test.go | 2 +-
cmd/cmdhistory_cmd.go | 4 +-
cmd/command_history.go | 2 +-
cmd/command_palette.go | 8 +-
cmd/compact_ui.go | 6 +-
cmd/compact_ui_test.go | 4 +-
cmd/compat-test/drift.go | 28 +-
cmd/compat-test/drift_test.go | 28 +-
cmd/compat-test/main.go | 6 +-
cmd/completions.go | 92 +++---
cmd/completions_test.go | 36 +--
cmd/config_table.go | 2 +-
cmd/context_export.go | 8 +-
cmd/contextual_help.go | 40 +--
cmd/control_plane_hints.go | 4 +-
cmd/cost.go | 4 +-
cmd/cost_test.go | 2 +-
cmd/credential_gate.go | 2 +-
cmd/credentials.go | 10 +-
cmd/daemon.go | 82 +++---
cmd/daemon_ready_test.go | 36 +--
cmd/{rho => decoder}/main.go | 24 +-
cmd/{rho_mascot.go => decoder_mascot.go} | 6 +-
cmd/diagnostics.go | 58 ++--
cmd/diagnostics_test.go | 38 +--
cmd/dx.go | 40 +--
cmd/dx_test.go | 24 +-
cmd/ecosystem.go | 10 +-
cmd/ecosystem_test.go | 8 +-
cmd/error_classify.go | 26 +-
cmd/error_classify_test.go | 2 +-
cmd/errors.go | 40 +--
cmd/errors_test.go | 10 +-
cmd/eval.go | 18 +-
cmd/eval_tools.go | 16 +-
cmd/exec.go | 80 +++---
cmd/exec_test.go | 22 +-
cmd/execution_graph.go | 24 +-
cmd/execution_graph_test.go | 38 +--
cmd/features.go | 14 +-
cmd/feedback.go | 16 +-
cmd/fingerprint.go | 10 +-
cmd/folder_trust_prompt.go | 2 +-
cmd/folder_trust_prompt_test.go | 2 +-
cmd/footer_layout_clip_test.go | 4 +-
cmd/footer_layout_width_test.go | 2 +-
cmd/formatter.go | 4 +-
cmd/formatter_test.go | 2 +-
cmd/golden_test.go | 4 +-
cmd/governance_cmd.go | 10 +-
cmd/harness.go | 12 +-
cmd/help_template.go | 2 +-
cmd/history.go | 2 +-
cmd/history_test.go | 4 +-
cmd/hud_panel.go | 2 +-
cmd/image.go | 6 +-
cmd/input_indicator.go | 6 +-
cmd/input_indicator_test.go | 2 +-
cmd/issue.go | 2 +-
cmd/learn_cmd.go | 16 +-
cmd/main_test.go | 4 +-
cmd/manpage.go | 32 +--
cmd/manpage_test.go | 2 +-
cmd/markdown.go | 8 +-
cmd/markdown_test.go | 4 +-
cmd/mcp_serve.go | 44 +--
cmd/mcp_serve_test.go | 12 +-
cmd/mentions.go | 4 +-
cmd/mentions_test.go | 2 +-
cmd/mission.go | 30 +-
cmd/mission_graph.go | 6 +-
cmd/mission_graph_test.go | 6 +-
cmd/model_table.go | 18 +-
cmd/model_table_test.go | 6 +-
cmd/models.go | 42 +--
cmd/models_test.go | 6 +-
cmd/notifications.go | 6 +-
cmd/notify.go | 6 +-
cmd/notify_test.go | 4 +-
cmd/ocg_live_test.go | 20 +-
cmd/options.go | 90 +++---
cmd/options_test.go | 2 +-
cmd/options_welcome_test.go | 34 +--
cmd/overlay_styles.go | 2 +-
cmd/overlay_zero_value_test.go | 2 +-
cmd/pager.go | 2 +-
cmd/path.go | 10 +-
cmd/path_test.go | 8 +-
cmd/permissions.go | 12 +-
cmd/permissions_center.go | 22 +-
cmd/permissions_center_test.go | 16 +-
cmd/permissions_inspect_test.go | 4 +-
cmd/plan.go | 22 +-
cmd/plugin_dynamic.go | 20 +-
cmd/power.go | 6 +-
cmd/pr.go | 10 +-
cmd/preflight_test.go | 6 +-
cmd/progress_cli.go | 6 +-
cmd/progress_debug_test.go | 2 +-
cmd/progress_tracker.go | 2 +-
cmd/progress_tracker_test.go | 2 +-
cmd/progressive_disclosure.go | 14 +-
cmd/prompt_input.go | 6 +-
cmd/prompt_input_test.go | 10 +-
cmd/record.go | 2 +-
cmd/record_test.go | 2 +-
cmd/resize_unix.go | 2 +-
cmd/resize_windows.go | 2 +-
cmd/review.go | 24 +-
cmd/review_fix.go | 16 +-
cmd/review_pipeline.go | 2 +-
cmd/review_read.go | 6 +-
cmd/review_refine.go | 18 +-
cmd/review_run.go | 20 +-
cmd/review_store.go | 4 +-
cmd/review_test.go | 34 +--
cmd/review_tui.go | 8 +-
cmd/root.go | 164 +++++------
cmd/rules.go | 30 +-
cmd/search.go | 12 +-
cmd/security_verify_governance_cli_test.go | 6 +-
cmd/securitylog_cmd.go | 10 +-
cmd/session_export.go | 2 +-
cmd/session_migrate.go | 2 +-
cmd/session_migrate_test.go | 4 +-
cmd/session_share.go | 8 +-
cmd/session_sync.go | 10 +-
cmd/session_sync_test.go | 44 +--
cmd/skills_cmd.go | 4 +-
cmd/skills_create.go | 10 +-
cmd/skills_curator_cmd.go | 6 +-
cmd/slash_commands_test.go | 2 +-
cmd/sleep_prevent.go | 2 +-
cmd/snapshot_cmd.go | 6 +-
cmd/spec_picker.go | 2 +-
cmd/spec_picker_test.go | 2 +-
cmd/spinner_wave.go | 10 +-
cmd/spinner_wave_test.go | 6 +-
cmd/stats.go | 6 +-
cmd/status_snapshot.go | 16 +-
cmd/status_snapshot_test.go | 2 +-
cmd/statusbar.go | 10 +-
cmd/statusbar_test.go | 8 +-
cmd/storage_policy_test.go | 14 +-
cmd/tabcomplete.go | 2 +-
cmd/tabcomplete_test.go | 2 +-
cmd/taste.go | 10 +-
cmd/terminal_notify.go | 2 +-
cmd/testfirst_workflow.go | 2 +-
cmd/textutil_shim.go | 2 +-
cmd/theme.go | 24 +-
cmd/theme_picker.go | 4 +-
cmd/tips.go | 10 +-
cmd/tips_test.go | 4 +-
cmd/tool_policy_catalog_test.go | 2 +-
cmd/toolset_cmd.go | 6 +-
cmd/trust.go | 12 +-
cmd/usage.go | 4 +-
cmd/verify_cmd.go | 8 +-
cmd/version_display.go | 8 +-
cmd/version_display_test.go | 14 +-
cmd/visual_diff.go | 2 +-
cmd/watch.go | 2 +-
cmd/welcome_banner.go | 51 ++--
cmd/welcome_banner_test.go | 8 +-
cmd/welcome_inline_test.go | 40 +--
docs/BENCHMARKS.md | 2 +-
docs/COMPETITIVE.md | 18 +-
docs/DAEMON-PORT-THREAT-MODEL.md | 30 +-
docs/DEVELOPER-PATH.md | 78 +++---
docs/DYNAMIC-MODELS.md | 78 +++---
docs/ECOSYSTEM-CONFIG.md | 78 +++---
docs/ECOSYSTEM-ROADMAP.md | 28 +-
docs/ECOSYSTEM-WIRING.md | 86 +++---
docs/IMPLEMENTATION-ROADMAP.md | 66 ++---
docs/OTEL-CONVENTIONS.md | 44 +--
docs/PERMISSION-MODEL-IMPROVEMENTS.md | 26 +-
docs/README.md | 4 +-
docs/RELEASING.md | 42 +--
docs/RESEARCH.md | 8 +-
docs/SECURITY-DEVELOPER.md | 62 ++--
docs/architecture.md | 24 +-
docs/architecture/README.md | 36 +--
...R-0001-graycode-platform-telemetry-edge.md | 32 +--
.../ADR-0002-graycode-cloud-control-plane.md | 24 +-
...-0003-grok-behavioral-port-go-multirepo.md | 20 +-
.../ADR-0004-file-first-session-history.md | 6 +-
docs/architecture/control-plane.md | 16 +-
...ne.md => decoder-architecture-baseline.md} | 60 ++--
...der-architecture-v1-definition-of-done.md} | 46 +--
...y-seams.md => decoder-capability-seams.md} | 2 +-
...tract-spec.md => decoder-contract-spec.md} | 22 +-
...osed.md => decoder-current-vs-proposed.md} | 58 ++--
...y-rules.md => decoder-dependency-rules.md} | 46 +--
...-modules.md => decoder-feature-modules.md} | 18 +-
.../{rho-harness.md => decoder-harness.md} | 10 +-
...ure.md => decoder-product-architecture.md} | 106 +++----
...ion.md => decoder-provider-abstraction.md} | 32 +--
...ho-repo-roles.md => decoder-repo-roles.md} | 50 ++--
....md => decoder-review-verify-lifecycle.md} | 8 +-
...-model.md => decoder-swift-event-model.md} | 6 +-
docs/architecture/ecosystem-architecture.md | 58 ++--
docs/architecture/ecosystem-design.md | 48 ++--
.../ecosystem-implementation-plan.md | 74 ++---
docs/architecture/execution-graph.md | 68 ++---
docs/architecture/frontend-contract.md | 2 +-
.../graycode-ecosystem-summary.md | 48 ++--
docs/architecture/plan.md | 6 +-
docs/architecture/spec.md | 26 +-
docs/architecture/tasks.md | 4 +-
docs/compatibility.md | 27 +-
...HO-CLOUD-SAAS.md => DECODER-CLOUD-SAAS.md} | 88 +++---
docs/design/ECOSYSTEM-MARKETPLACE.md | 152 +++++-----
docs/design/three-repo-architecture.md | 14 +-
docs/ecosystem-message-flow.md | 48 ++--
docs/ecosystem-remediation-plan.md | 24 +-
docs/intelligent-cli.md | 6 +-
docs/mcp-servers.md | 18 +-
docs/monitoring-guide.md | 64 ++---
docs/operations-checklist.md | 36 +--
...FULL-GROK-ECO-TO-DECODER-ECO-PORT-PLAN.md} | 202 ++++++-------
...GROK-CLASS-CAPABILITY-LONG-HORIZON-PLAN.md | 132 ++++-----
docs/plans/SPEC_DRIVEN_PHASE2_PLAN.md | 2 +-
docs/plans/YEAR-0-ACTIVE.md | 20 +-
docs/plans/codex-adoption-plan.md | 36 +--
docs/plans/commandcodeai-adoption-plan.md | 42 +--
.../competitive-gap-02-share-multisession.md | 6 +-
.../competitive-gap-03-kitty-graphics.md | 2 +-
...competitive-gap-04-published-benchmarks.md | 4 +-
.../competitive-gap-05-backend-wiring.md | 16 +-
...=> decoder-contracts-migration-backlog.md} | 82 +++---
...-alignment.md => decoder-tau-alignment.md} | 24 +-
docs/plans/dsh-harness-gap-port-plan.md | 26 +-
docs/plans/dsh-harness-port-plan.md | 20 +-
docs/plans/dsh-harness-rfc-port-plan.md | 32 +--
docs/plans/engine-refactor-plan.md | 24 +-
docs/plans/fix-critical-and-high-review.md | 30 +-
docs/plans/fx-adoption-plan.md | 90 +++---
docs/plans/goose-adoption-plan.md | 36 +--
docs/plans/minimax-adoption-plan.md | 104 +++----
docs/plans/pi-adoption-plan.md | 66 ++---
docs/plans/pi-renderer-and-eval-reporting.md | 10 +-
docs/plans/qwen-code-adoption-plan.md | 20 +-
docs/plans/tau-feature-parity.md | 30 +-
docs/plans/toolbench-comparison-vs-top20.md | 32 +--
docs/platform-capabilities.json | 2 +-
docs/plugin-development.md | 70 ++---
docs/session-decomposition.md | 36 +--
docs/terminal-icons.md | 10 +-
docs/troubleshooting-guide.md | 110 ++++----
docs/user-guide/01-getting-started.md | 70 ++---
docs/user-guide/02-authentication.md | 48 ++--
docs/user-guide/03-keyboard-shortcuts.md | 6 +-
docs/user-guide/04-slash-commands.md | 8 +-
docs/user-guide/05-configuration.md | 30 +-
docs/user-guide/06-theming.md | 20 +-
docs/user-guide/07-mcp-servers.md | 30 +-
docs/user-guide/08-skills.md | 36 +--
docs/user-guide/09-plugins.md | 32 +--
docs/user-guide/10-hooks.md | 30 +-
docs/user-guide/11-custom-models.md | 18 +-
docs/user-guide/12-project-rules.md | 18 +-
docs/user-guide/13-memory.md | 30 +-
docs/user-guide/14-headless-mode.md | 42 +--
docs/user-guide/15-agent-mode.md | 18 +-
docs/user-guide/16-subagents.md | 4 +-
docs/user-guide/17-sessions.md | 16 +-
.../18-execution-and-permissions.md | 8 +-
docs/user-guide/19-plan-mode.md | 10 +-
docs/user-guide/20-background-tasks.md | 2 +-
docs/user-guide/21-terminal-support.md | 8 +-
docs/user-guide/22-permissions-and-safety.md | 2 +-
docs/user-guide/23-dashboard.md | 10 +-
docs/user-guide/24-monitoring-usage.md | 14 +-
docs/user-guide/25-shell-completions.md | 38 +--
docs/user-guide/26-learned-preferences.md | 2 +-
docs/user-guide/27-workflows.md | 8 +-
docs/user-guide/28-workflow-budgets.md | 2 +-
docs/versioning.md | 8 +-
ecosystem.yaml | 32 +--
examples/README.md | 32 +--
.../{rho-ci-exec.yml => decoder-ci-exec.yml} | 36 +--
examples/github/decoder-delivery-context.yml | 47 ++++
...esolver.yml => decoder-issue-resolver.yml} | 40 +--
examples/github/rho-delivery-context.yml | 47 ----
go.mod | 10 +-
go.sum | 4 +-
install.sh | 82 +++---
internal/acp/acp_extra_test.go | 2 +-
internal/acp/client_test.go | 2 +-
internal/acp/content.go | 2 +-
internal/acp/content_test.go | 2 +-
internal/acp/server.go | 24 +-
internal/acp/server_test.go | 20 +-
internal/appverify/appverify_test.go | 2 +-
internal/appverify/manifest.go | 6 +-
internal/appverify/prompt.go | 2 +-
internal/auth/auth.go | 6 +-
internal/auth/auth_extra_test.go | 2 +-
internal/auth/auth_test.go | 18 +-
internal/auth/plaintext_store_test.go | 2 +-
internal/auth/storage_extra_test.go | 10 +-
internal/autoinit/autoinit.go | 18 +-
internal/autoinit/autoinit_test.go | 6 +-
internal/catalogtest/install.go | 12 +-
internal/circuitbreaker/circuitbreaker.go | 2 +-
internal/codegraph/algorithms_cgo_more.go | 6 +-
internal/config/catalog_api.go | 44 +--
internal/config/catalog_compat_test.go | 8 +-
internal/config/catalog_gateways_test.go | 16 +-
internal/config/catalog_health.go | 20 +-
internal/config/catalog_health_test.go | 6 +-
internal/config/catalog_startup.go | 22 +-
.../config/catalog_startup_robust_test.go | 12 +-
internal/config/catalog_startup_test.go | 8 +-
internal/config/config.go | 2 +-
internal/config/config_test.go | 10 +-
internal/config/credentials_store.go | 36 +--
internal/config/credentials_store_test.go | 2 +-
internal/config/deployment.go | 4 +-
internal/config/deployment_status.go | 12 +-
internal/config/deployments_ui_test.go | 2 +-
internal/config/developer_path.go | 40 +--
internal/config/developer_path_test.go | 4 +-
internal/config/ecosystem_report.go | 52 ++--
internal/config/ecosystem_report_test.go | 4 +-
internal/config/envmanager.go | 2 +-
internal/config/envmanager_test.go | 8 +-
internal/config/main_test.go | 4 +-
internal/config/milestone_verify_test.go | 36 +--
.../config/{flux_apply.go => mux_apply.go} | 20 +-
.../config/{flux_engine.go => mux_engine.go} | 40 +--
...flux_engine_test.go => mux_engine_test.go} | 10 +-
.../{flux_selection.go => mux_selection.go} | 26 +-
internal/config/provider_filter.go | 6 +-
internal/config/security_test.go | 4 +-
internal/config/settings.go | 64 ++---
internal/config/settings_status_test.go | 4 +-
internal/config/settings_test.go | 2 +-
internal/config/setup_status.go | 6 +-
internal/config/setup_status_test.go | 6 +-
internal/config/ui_cache.go | 2 +-
internal/config/validator.go | 6 +-
internal/config/validator_test.go | 6 +-
internal/config/xiaomi_setup_test.go | 18 +-
internal/context/repomap/repomap.go | 4 +-
internal/context/repomap/scan.go | 2 +-
internal/contracts/agent/hooks.go | 10 +-
internal/contracts/agent/spawn.go | 2 +-
internal/contracts/events/events.go | 4 +-
internal/contracts/graph/graph.go | 2 +-
internal/contracts/harness/harness.go | 6 +-
internal/contracts/policy/policy.go | 2 +-
internal/contracts/review/review.go | 6 +-
internal/contracts/types/finding.go | 4 +-
internal/contracts/types/severity.go | 2 +-
internal/contracts/verify/verify.go | 6 +-
internal/crash/crash.go | 4 +-
internal/crash/crash_extra_test.go | 4 +-
internal/crash/crash_test.go | 12 +-
internal/crash/crash_unix.go | 2 +-
internal/daemon/contract_parity_test.go | 4 +-
internal/daemon/daemon.go | 68 ++---
internal/daemon/daemon_test.go | 30 +-
internal/daemon/discord.go | 8 +-
internal/daemon/e2e_test.go | 12 +-
internal/daemon/gateway.go | 6 +-
internal/daemon/gateway_test.go | 22 +-
internal/daemon/graph_ledger_sqlite_test.go | 8 +-
internal/daemon/h9_h10_test.go | 4 +-
internal/daemon/middleware.go | 2 +-
internal/daemon/middleware_test.go | 4 +-
internal/daemon/routes_agent_status_test.go | 2 +-
internal/daemon/routes_graph.go | 6 +-
internal/daemon/routes_graph_read.go | 2 +-
internal/daemon/routes_graph_read_test.go | 6 +-
internal/daemon/routes_graph_sync.go | 6 +-
internal/daemon/routes_graph_sync_test.go | 6 +-
internal/daemon/routes_graph_test.go | 10 +-
internal/daemon/routes_lease.go | 2 +-
internal/daemon/routes_lease_test.go | 6 +-
internal/daemon/routes_metrics.go | 14 +-
internal/daemon/routes_review.go | 12 +-
internal/daemon/routes_review_test.go | 4 +-
internal/daemon/routes_sessions.go | 4 +-
internal/daemon/routes_sessions_test.go | 14 +-
internal/daemon/routes_stats.go | 2 +-
internal/daemon/routes_stats_test.go | 10 +-
internal/daemon/routes_status.go | 4 +-
internal/daemon/slack.go | 6 +-
internal/daemon/telegram.go | 20 +-
internal/daemon/telegram_test.go | 46 +--
.../bridge_error_test.go | 2 +-
internal/{rhoerr => decodererr}/classify.go | 8 +-
.../classify_extra_test.go | 6 +-
internal/{rhoerr => decodererr}/errors.go | 4 +-
internal/{rhoerr => decodererr}/exitcode.go | 8 +-
.../{rhoerr => decodererr}/exitcode_test.go | 2 +-
internal/engine/adaptive_prompt.go | 6 +-
internal/engine/adaptive_prompt_test.go | 2 +-
internal/engine/adaptive_system_prompt.go | 6 +-
.../engine/adaptive_system_prompt_test.go | 12 +-
internal/engine/agent/background_agent.go | 4 +-
internal/engine/agent_intelligence.go | 2 +-
internal/engine/agent_intelligence_test.go | 2 +-
internal/engine/agent_resume_test.go | 8 +-
internal/engine/agent_session_tool.go | 20 +-
internal/engine/approval_gate.go | 2 +-
internal/engine/approval_gate_test.go | 2 +-
internal/engine/arc_test.go | 2 +-
internal/engine/architect.go | 14 +-
internal/engine/assumptions.go | 2 +-
internal/engine/auto_commit.go | 4 +-
internal/engine/auto_commit_wire_test.go | 6 +-
internal/engine/background_runner.go | 6 +-
internal/engine/bmad_features_test.go | 2 +-
internal/engine/branching/cascade.go | 8 +-
internal/engine/branching/cascade_test.go | 4 +-
internal/engine/branching/shadow.go | 2 +-
internal/engine/cache_gate.go | 2 +-
internal/engine/cache_gate_test.go | 4 +-
internal/engine/cache_planner.go | 8 +-
internal/engine/cache_planner_test.go | 4 +-
internal/engine/chat_provider.go | 16 +-
internal/engine/chat_provider_test.go | 12 +-
internal/engine/chat_replay.go | 14 +-
internal/engine/chat_replay_test.go | 20 +-
internal/engine/chat_service.go | 42 +--
internal/engine/chat_service_test.go | 44 +--
internal/engine/client_interface.go | 24 +-
internal/engine/coding_soul.go | 6 +-
internal/engine/compact.go | 24 +-
internal/engine/compact/aliases_extra_test.go | 6 +-
internal/engine/compact/api.go | 12 +-
internal/engine/compact/files.go | 6 +-
internal/engine/compact/files_test.go | 6 +-
internal/engine/compact/incremental_test.go | 8 +-
internal/engine/compact/micro.go | 12 +-
internal/engine/compact/prompt.go | 6 +-
internal/engine/compact/session_memory.go | 14 +-
internal/engine/compact/split_test.go | 18 +-
internal/engine/compact/strategy.go | 8 +-
internal/engine/compact/strategy_test.go | 26 +-
.../engine/compact/transcript_segments.go | 10 +-
.../compact/transcript_segments_test.go | 8 +-
internal/engine/compact_auto.go | 12 +-
internal/engine/compact_clear.go | 14 +-
internal/engine/compact_clear_test.go | 14 +-
internal/engine/compact_micro_engine.go | 8 +-
internal/engine/compact_provider_native.go | 18 +-
internal/engine/compact_regression_test.go | 32 +--
internal/engine/compact_relevance.go | 24 +-
internal/engine/compact_relevance_test.go | 10 +-
.../engine/compact_session_memory_engine.go | 14 +-
internal/engine/compact_split.go | 28 +-
internal/engine/compact_strategy_engine.go | 8 +-
internal/engine/compact_strategy_test.go | 20 +-
internal/engine/compression/cross_session.go | 4 +-
.../engine/compression/session_timeline.go | 2 +-
.../compression/session_timeline_test.go | 2 +-
internal/engine/context_compaction.go | 14 +-
internal/engine/context_compaction_test.go | 14 +-
internal/engine/context_governor.go | 8 +-
internal/engine/context_governor_test.go | 6 +-
internal/engine/control/backtrack.go | 18 +-
internal/engine/control/backtrack_test.go | 8 +-
internal/engine/control/stall_detector.go | 2 +-
.../engine/control/stall_detector_test.go | 2 +-
internal/engine/control_plane_test.go | 20 +-
internal/engine/conversation_adapter.go | 4 +-
internal/engine/cost/aliases.go | 2 +-
internal/engine/cost/cost_optimizer.go | 2 +-
internal/engine/cost/cost_optimizer_test.go | 2 +-
internal/engine/cost/cost_table.go | 2 +-
internal/engine/cost/cost_tracker.go | 4 +-
internal/engine/cost/cost_tracker_test.go | 4 +-
internal/engine/council.go | 2 +-
internal/engine/ctxmgr/context_budget.go | 2 +-
internal/engine/ctxmgr/context_collapse.go | 18 +-
.../engine/ctxmgr/context_collapse_test.go | 12 +-
internal/engine/ctxmgr/context_decay.go | 2 +-
internal/engine/ctxmgr/context_decay_test.go | 2 +-
internal/engine/ctxmgr/context_viz.go | 2 +-
internal/engine/ctxmgr/context_viz_test.go | 2 +-
internal/engine/ctxmgr/incremental.go | 8 +-
internal/engine/developer_features_test.go | 2 +-
internal/engine/diff/diff_staging.go | 2 +-
internal/engine/directive_scanner.go | 12 +-
internal/engine/dry_run_test.go | 2 +-
internal/engine/elision.go | 2 +-
internal/engine/engine.go | 6 +-
internal/engine/engine_full_loop_test.go | 6 +-
internal/engine/engine_integration_test.go | 18 +-
internal/engine/engine_stage2_test_helpers.go | 2 +-
internal/engine/engine_test.go | 4 +-
internal/engine/engine_token_helpers.go | 8 +-
internal/engine/errs/aliases.go | 2 +-
internal/engine/errs/error_context.go | 14 +-
internal/engine/errs/error_context_test.go | 6 +-
internal/engine/errs/error_patterns.go | 2 +-
internal/engine/errs/error_recovery.go | 2 +-
internal/engine/event_bus.go | 2 +-
.../engine/execution_graph_observations.go | 50 ++--
.../execution_graph_observations_test.go | 32 +--
internal/engine/experiment_loop.go | 2 +-
internal/engine/external_content.go | 2 +-
internal/engine/extract_targets_test.go | 2 +-
internal/engine/git/git_context.go | 2 +-
internal/engine/git/git_provider.go | 2 +-
internal/engine/git/git_provider_test.go | 2 +-
internal/engine/git/provider_extra_test.go | 12 +-
internal/engine/git_safety.go | 10 +-
internal/engine/git_safety_test.go | 2 +-
internal/engine/goose_extras_test.go | 4 +-
internal/engine/hints_loader.go | 4 +-
internal/engine/history/annotations.go | 14 +-
internal/engine/history/annotations_test.go | 40 +--
.../history/conversation_summarizer_test.go | 2 +-
internal/engine/history/file_mentions.go | 4 +-
internal/engine/history/file_mentions_test.go | 6 +-
internal/engine/incremental.go | 4 +-
internal/engine/incremental_test.go | 8 +-
internal/engine/integration.go | 52 ++--
internal/engine/integration_graph_test.go | 2 +-
internal/engine/integration_test.go | 8 +-
internal/engine/intelligence/capabilities.go | 2 +-
.../engine/intelligence/capabilities_test.go | 2 +-
.../engine/intelligence/command_suggest.go | 2 +-
.../intelligence/command_suggest_test.go | 2 +-
internal/engine/intelligence/tool_selector.go | 2 +-
internal/engine/io/ai_watch.go | 2 +-
internal/engine/io/clipboard_bridge.go | 2 +-
internal/engine/io/clipboard_test.go | 4 +-
internal/engine/journal.go | 26 +-
internal/engine/journal_test.go | 20 +-
internal/engine/jsonl_events.go | 2 +-
internal/engine/l2_home_paths_test.go | 10 +-
internal/engine/lifecycle/lifecycle.go | 2 +-
.../engine/lifecycle/lifecycle_adapters.go | 2 +-
internal/engine/lifecycle/timeout.go | 2 +-
internal/engine/lifecycle/timeout_test.go | 2 +-
internal/engine/lifecycle_finalize_test.go | 8 +-
internal/engine/lifecycle_service.go | 32 +--
internal/engine/llm_client.go | 10 +-
internal/engine/main_test.go | 4 +-
internal/engine/memory/knowledge.go | 2 +-
internal/engine/memory/memory_consolidator.go | 2 +-
internal/engine/memory_service.go | 8 +-
internal/engine/memory_service_test.go | 4 +-
internal/engine/mock_client_test.go | 26 +-
internal/engine/model_switch_test.go | 4 +-
.../observability/feedback_collector.go | 2 +-
.../observability/structured_log_test.go | 6 +-
internal/engine/party_mode.go | 2 +-
internal/engine/permission_exactrules_test.go | 4 +-
internal/engine/permission_service.go | 16 +-
.../permission_service_spec_journal_test.go | 4 +-
internal/engine/permission_service_test.go | 6 +-
internal/engine/permission_session_methods.go | 6 +-
.../engine/permission_turnrecovery_test.go | 2 +-
internal/engine/persistence_service.go | 54 ++--
.../persistence_service_deadlock_test.go | 10 +-
internal/engine/persistence_trim_test.go | 20 +-
internal/engine/planning/goals.go | 2 +-
internal/engine/planning/goals_test.go | 2 +-
internal/engine/planning/suggested_tasks.go | 22 +-
.../engine/planning/suggested_tasks_test.go | 10 +-
.../engine/project/convention_enforcer.go | 2 +-
.../project/convention_enforcer_test.go | 2 +-
internal/engine/project/dep_updater.go | 4 +-
.../engine/project/impact_analyzer_test.go | 4 +-
internal/engine/project/migration_planner.go | 2 +-
.../engine/project/project_analyzer_test.go | 6 +-
internal/engine/project/project_context.go | 4 +-
internal/engine/project/project_metrics.go | 2 +-
internal/engine/project/release.go | 2 +-
internal/engine/project_trust.go | 8 +-
internal/engine/provider_chat_client.go | 10 +-
internal/engine/redaction.go | 2 +-
internal/engine/redaction_test.go | 2 +-
internal/engine/reflect_test.go | 10 +-
internal/engine/resilience_boundary_test.go | 68 ++---
internal/engine/review/consensus.go | 2 +-
internal/engine/review/quality_scorer.go | 2 +-
internal/engine/review/review_bot.go | 2 +-
internal/engine/review/review_bot_rules.go | 2 +-
internal/engine/safety/permission.go | 6 +-
internal/engine/safety/permission_engine.go | 26 +-
.../permission_engine_governance_test.go | 2 +-
.../safety/permission_engine_pretool_test.go | 2 +-
.../engine/safety/permission_engine_test.go | 6 +-
internal/engine/safety/risk_assessor.go | 2 +-
.../safety/spec_approval_summary_test.go | 2 +-
internal/engine/scaffold/fewshot.go | 4 +-
internal/engine/scaffold/fewshot_test.go | 2 +-
internal/engine/scaffold/patterns.go | 30 +-
internal/engine/scaffold/recipe.go | 12 +-
internal/engine/scaffold/recipe_test.go | 16 +-
internal/engine/scale_adaptive.go | 2 +-
internal/engine/search/url_scraper.go | 4 +-
internal/engine/search/url_scraper_test.go | 14 +-
internal/engine/security_events.go | 4 +-
internal/engine/security_events_test.go | 10 +-
internal/engine/selective_rag.go | 2 +-
internal/engine/self_heal.go | 6 +-
internal/engine/self_heal_test.go | 2 +-
internal/engine/self_improve.go | 4 +-
internal/engine/self_review.go | 6 +-
internal/engine/semantic_diff.go | 2 +-
internal/engine/session.go | 74 ++---
internal/engine/session_factory.go | 32 +--
internal/engine/session_factory_test.go | 14 +-
internal/engine/session_h3_h4_test.go | 8 +-
internal/engine/session_mock_test.go | 6 +-
internal/engine/skill_catalog_test.go | 4 +-
internal/engine/smartrouting_test.go | 2 +-
internal/engine/spawn_controller.go | 4 +-
internal/engine/spec_mode_test.go | 8 +-
internal/engine/stage2_move.sh | 4 +-
internal/engine/stream.go | 68 ++---
internal/engine/stream_exhaustion.go | 4 +-
internal/engine/stream_exhaustion_test.go | 10 +-
internal/engine/stream_guards.go | 8 +-
internal/engine/stream_helpers.go | 10 +-
internal/engine/stream_prompt_test.go | 6 +-
internal/engine/stream_tool_exec.go | 8 +-
internal/engine/stream_tool_exec_test.go | 12 +-
internal/engine/stream_usage.go | 20 +-
internal/engine/stream_usage_test.go | 12 +-
internal/engine/structured_output.go | 14 +-
internal/engine/structured_output_test.go | 10 +-
internal/engine/sub_service_wiring_test.go | 10 +-
internal/engine/subagent_synthesis.go | 8 +-
internal/engine/subagent_synthesis_test.go | 18 +-
internal/engine/system_context_test.go | 2 +-
internal/engine/teach.go | 2 +-
internal/engine/title.go | 4 +-
internal/engine/title_test.go | 4 +-
internal/engine/token/aliases.go | 2 +-
internal/engine/token/facade.go | 48 ++--
internal/engine/token/token_budget.go | 8 +-
internal/engine/token/token_budget_test.go | 44 +--
internal/engine/token/token_estimates.go | 6 +-
internal/engine/token/token_predictor.go | 2 +-
internal/engine/token/token_predictor_test.go | 2 +-
internal/engine/token/tokenizer.go | 8 +-
internal/engine/tool_catalog_shrink.go | 20 +-
internal/engine/tool_catalog_shrink_test.go | 30 +-
internal/engine/tool_output_spill.go | 4 +-
internal/engine/tool_pipeline.go | 2 +-
internal/engine/tool_service.go | 28 +-
internal/engine/tool_service_test.go | 4 +-
internal/engine/tool_timeout_test.go | 6 +-
internal/engine/trajectory.go | 8 +-
internal/engine/trajectory_test.go | 18 +-
internal/engine/transfer.go | 4 +-
internal/engine/transfer_test.go | 6 +-
internal/engine/validation/gen_validator.go | 2 +-
internal/engine/validation/test_loop.go | 2 +-
internal/engine/vision.go | 14 +-
internal/engine/work_mode.go | 2 +-
.../engine/workflow/trajectory_inspector.go | 2 +-
.../workflow/trajectory_inspector_test.go | 2 +-
internal/engine/workflow/workspace_state.go | 4 +-
.../engine/workflow/workspace_state_test.go | 2 +-
internal/env/compat.go | 18 +-
internal/env/compat_test.go | 36 +--
internal/env/scrub.go | 8 +-
internal/env/scrub_test.go | 6 +-
internal/errhint/errhint.go | 4 +-
internal/eventlog/boundary.go | 6 +-
internal/eventlog/chunk_rows.go | 2 +-
internal/eventlog/event.go | 6 +-
internal/eventlog/lifecycle.go | 10 +-
internal/eventlog/projection_test.go | 2 +-
internal/executiongraph/execution_graph.go | 144 +++++-----
.../executiongraph/execution_graph_test.go | 38 +--
internal/features/README.md | 2 +-
internal/features/chat/runner.go | 2 +-
internal/features/chat/runner_test.go | 2 +-
internal/features/chat/stream.go | 2 +-
internal/features/chat/stream_test.go | 2 +-
internal/features/chat/transcript.go | 4 +-
internal/features/chat/transcript_test.go | 2 +-
internal/features/commands/catalog.go | 8 +-
internal/features/commands/history.go | 2 +-
internal/features/daemon_flags.go | 12 +-
internal/features/eval/benchmark.go | 2 +-
internal/features/eval/cache.go | 4 +-
internal/features/eval/coverage.go | 2 +-
internal/features/eval/coverage_test.go | 2 +-
internal/features/eval/eval.go | 6 +-
internal/features/eval/parallel_runner.go | 2 +-
.../features/eval/parallel_runner_test.go | 2 +-
internal/features/eval/skills/run_eval.sh | 4 +-
internal/features/eval/skills/scenarios.md | 4 +-
internal/features/eval/store.go | 4 +-
internal/features/eval/tasks_go_more.go | 8 +-
internal/features/eval/toolmatrix.go | 2 +-
internal/features/evalloop/evalloop_test.go | 4 +-
internal/features/evalloop/runtime.go | 2 +-
internal/features/evalloop/session.go | 4 +-
internal/features/feature.go | 8 +-
internal/features/feature_test.go | 10 +-
.../features/fingerprint/fingerprint_test.go | 6 +-
internal/features/fingerprint/project.go | 12 +-
internal/features/fingerprint/project_test.go | 2 +-
internal/features/session/commands.go | 2 +-
internal/features/session/commands_test.go | 2 +-
internal/features/session/export.go | 8 +-
internal/features/session/export_test.go | 2 +-
internal/features/session/filter.go | 2 +-
internal/features/session/filter_test.go | 2 +-
internal/features/session/hydrate.go | 6 +-
internal/features/session/hydrate_test.go | 2 +-
internal/features/session/lifecycle.go | 2 +-
internal/features/session/metadata.go | 4 +-
internal/features/session/mutation.go | 4 +-
internal/features/session/mutation_test.go | 6 +-
internal/features/session/presentation.go | 6 +-
.../features/session/presentation_test.go | 4 +-
internal/features/session/service.go | 10 +-
internal/features/session/service_test.go | 4 +-
internal/features/shellmode/modes.go | 2 +-
internal/features/shellmode/shellmode.go | 2 +-
internal/features/skills/activation.go | 4 +-
internal/features/skills/activation_test.go | 12 +-
internal/features/taste/store.go | 4 +-
...display.png => decoder-mascot-display.png} | Bin
internal/features/welcome/welcome.go | 4 +-
internal/features/workspace/context.go | 4 +-
internal/flags/y0.go | 10 +-
internal/fuzzyfind/fuzzyfind.go | 2 +-
internal/gitworktree/worktree.go | 6 +-
internal/governance/governance.go | 4 +-
internal/graphjournal/journal.go | 16 +-
internal/graphjournal/journal_test.go | 12 +-
internal/harness/evaluator.go | 36 +--
internal/harness/fix.go | 6 +-
internal/harness/journal.go | 6 +-
internal/harness/render.go | 6 +-
internal/harness/workloop.go | 6 +-
internal/hooks/aliases.go | 4 +-
internal/hooks/audit/detectors.go | 2 +-
internal/hooks/discover.go | 4 +-
internal/hooks/file_watcher.go | 2 +-
internal/hooks/hooks.go | 8 +-
internal/hooks/hooks_extra2_test.go | 2 +-
internal/hooks/http_hooks.go | 10 +-
internal/identity/identity.go | 12 +-
internal/identity/identity_test.go | 18 +-
internal/installtxn/installtxn.go | 8 +-
internal/intelligence/memory/auto_memory.go | 4 +-
internal/intelligence/memory/autodream.go | 2 +-
internal/intelligence/memory/autofile.go | 2 +-
internal/intelligence/memory/continuity.go | 2 +-
internal/intelligence/memory/evolving.go | 6 +-
.../memory/evolving_additional_test.go | 12 +-
internal/intelligence/memory/memory.go | 2 +-
internal/intelligence/memory/memory_test.go | 2 +-
.../intelligence/memory/retrieval_metrics.go | 2 +-
internal/intelligence/memory/zenbrain.go | 2 +-
internal/intelligence/planner/planner.go | 8 +-
internal/intelligence/repomap/README.md | 8 +-
internal/intelligence/repomap/callgraph.go | 6 +-
.../intelligence/repomap/callgraph_test.go | 4 +-
internal/intelligence/repomap/complexity.go | 2 +-
.../intelligence/repomap/complexity_test.go | 2 +-
internal/intelligence/repomap/doc.go | 10 +-
internal/intelligence/repomap/doclint.go | 2 +-
internal/intelligence/repomap/health_score.go | 2 +-
internal/intelligence/repomap/imports.go | 2 +-
internal/intelligence/repomap/incremental.go | 2 +-
.../intelligence/repomap/incremental_map.go | 4 +-
.../intelligence/repomap/incremental_test.go | 2 +-
internal/intelligence/repomap/navigation.go | 2 +-
.../intelligence/repomap/navigation_test.go | 2 +-
internal/intelligence/repomap/rerank.go | 2 +-
.../intelligence/repomap/semantic_search.go | 4 +-
internal/intelligence/repomap/summary_test.go | 10 +-
internal/intelligence/skillcurator/record.go | 2 +-
.../intelligence/skillcurator/skillcurator.go | 2 +-
internal/lint/lint.go | 2 +-
internal/lsp/config.go | 4 +-
internal/lsp/env.go | 4 +-
internal/lsp/env_test.go | 16 +-
internal/lsp/lsp_extra_test.go | 2 +-
internal/mcp/http.go | 4 +-
internal/mcp/mcp.go | 10 +-
internal/mcp/oauth.go | 6 +-
internal/mcp/oauth_store.go | 4 +-
internal/mcp/schema.go | 2 +-
internal/mcp/server.go | 6 +-
internal/mcp/server_test.go | 36 +--
internal/mcp/server_tools.go | 68 ++---
internal/mcp/server_tools_test.go | 102 +++----
internal/mcp/ws.go | 2 +-
internal/multiagent/agents/agents.go | 8 +-
internal/multiagent/agents/agents_test.go | 2 +-
internal/multiagent/agents/persona.go | 4 +-
.../multiagent/agents/persona_builtins.go | 4 +-
.../agents/persona_registry_test.go | 6 +-
internal/multiagent/approval.go | 2 +-
internal/multiagent/continuable.go | 6 +-
internal/multiagent/continuable_test.go | 4 +-
internal/multiagent/mission.go | 8 +-
internal/multiagent/mission_test.go | 4 +-
internal/multiagent/parallel/parallel.go | 4 +-
internal/multiagent/parallel/parallel_test.go | 18 +-
internal/multiagent/parallel/worktree.go | 2 +-
.../multiagent/parallel/worktree_manager.go | 4 +-
.../parallel/worktree_manager_test.go | 14 +-
internal/multiagent/portable_graph.go | 42 +--
internal/multiagent/portable_graph_test.go | 2 +-
internal/multiagent/provider.go | 2 +-
internal/multiagent/reflexion_test.go | 10 +-
internal/multiagent/shared_memory_test.go | 10 +-
internal/multiagent/watchdog.go | 4 +-
internal/multiagent/worker.go | 30 +-
internal/multiagent/worker_cleanup_test.go | 18 +-
internal/multiagent/worker_transcript.go | 14 +-
internal/multiagent/worker_transcript_test.go | 6 +-
internal/notify/notify.go | 12 +-
internal/notify/notify_test.go | 10 +-
internal/observability/analytics.go | 2 +-
internal/observability/analytics_test.go | 2 +-
internal/observability/dashboard.go | 4 +-
internal/observability/dashboard_test.go | 2 +-
internal/observability/insights.go | 6 +-
internal/observability/otellog/otellog.go | 2 +-
internal/observability/otellog/otellog_sdk.go | 12 +-
.../observability/otellog/otellog_test.go | 4 +-
internal/observability/oteltrace/langfuse.go | 2 +-
internal/observability/oteltrace/otel.go | 10 +-
internal/observability/oteltrace/otel_test.go | 14 +-
internal/observability/oteltrace/spans.go | 2 +-
internal/observability/oteltrace/trace.go | 2 +-
internal/observability/perf_budget.go | 2 +-
internal/observability/testmain_test.go | 2 +-
internal/onboarding/onboarding.go | 56 ++--
internal/onboarding/onboarding_test.go | 2 +-
internal/pathsafe/pathsafe.go | 32 +--
internal/permissions/stableid/state.go | 2 +-
internal/permissions/stablerules.go | 8 +-
.../permissions/stablerules_reset_test.go | 2 +-
internal/permissions/stablerules_test.go | 2 +-
internal/planning/model_test.go | 12 +-
internal/planning/search.go | 6 +-
internal/platform/cloud/apierror.go | 2 +-
internal/platform/cloud/apierror_test.go | 6 +-
internal/platform/cloud/client.go | 14 +-
internal/platform/cloud/client_test.go | 4 +-
internal/platform/cloud/config.go | 14 +-
internal/platform/cloud/config_test.go | 2 +-
.../cloud/contract_conformance_test.go | 48 ++--
.../platform/cloud/contract_worker_test.go | 4 +-
internal/platform/cloud/delivery.go | 2 +-
internal/platform/cloud/delivery_test.go | 4 +-
internal/platform/cloud/device_login_test.go | 6 +-
internal/platform/cloud/endpoint.go | 8 +-
internal/platform/cloud/endpoint_test.go | 6 +-
internal/platform/cloud/graph_policy_test.go | 10 +-
internal/platform/cloud/graph_test.go | 14 +-
.../testdata/graph_attribute_policy.json | 2 +-
internal/platform/cloud/usage.go | 10 +-
internal/platform/cloud/usage_test.go | 8 +-
internal/plugin/audit.go | 6 +-
internal/plugin/auto_skill.go | 6 +-
internal/plugin/auto_skill_audit_test.go | 10 +-
internal/plugin/bridge.go | 2 +-
internal/plugin/components.go | 2 +-
internal/plugin/dynamic.go | 18 +-
internal/plugin/env.go | 10 +-
internal/plugin/feedback.go | 4 +-
internal/plugin/learn.go | 4 +-
internal/plugin/manager.go | 38 +--
internal/plugin/manager_test.go | 8 +-
internal/plugin/manifest_hardening.go | 4 +-
internal/plugin/manifest_v2.go | 28 +-
internal/plugin/marketplace.go | 12 +-
internal/plugin/marketplace_test.go | 4 +-
internal/plugin/plugin.go | 4 +-
internal/plugin/plugin_test.go | 6 +-
internal/plugin/plugin_tool.go | 2 +-
internal/plugin/provider.go | 4 +-
internal/plugin/registry.go | 8 +-
internal/plugin/registry_test.go | 20 +-
internal/plugin/runtime.go | 6 +-
internal/plugin/scopes.go | 14 +-
internal/plugin/skills_auto.go | 22 +-
internal/plugin/skillslock.go | 4 +-
internal/plugin/testmain_test.go | 4 +-
internal/plugin/wizard.go | 6 +-
internal/prompt/prompt.go | 4 +-
internal/prompt/prompt_test.go | 2 +-
internal/prompts/agents_accumulator.go | 8 +-
internal/prompts/agents_accumulator_test.go | 2 +-
internal/prompts/loader.go | 6 +-
internal/prompts/loader_test.go | 20 +-
internal/prompts/templates/examples.md | 2 +-
internal/prompts/templates/practices.md | 2 +-
internal/prompts/templates/role.md | 2 +-
internal/prompts/templates/subagent.md | 4 +-
internal/prompts/templates/tools.md | 2 +-
internal/prompts/testmain_test.go | 2 +-
internal/prompts/workspace.go | 2 +-
internal/provider/gateway/engine_client.go | 206 +++++++-------
.../provider/gateway/engine_client_test.go | 38 +--
internal/provider/gateway/gateway.go | 180 ++++++------
internal/provider/gateway/media_backends.go | 44 +--
.../provider/gateway/media_backends_stub.go | 6 +-
.../provider/gateway/provider_stub_test.go | 100 +++----
internal/provider/routing/catalog.go | 12 +-
internal/provider/routing/health_router.go | 2 +-
internal/provider/routing/main_test.go | 2 +-
internal/provider/routing/roles.go | 6 +-
internal/provider/routing/tiers.go | 2 +-
internal/recipe/providers.go | 4 +-
internal/recipe/recipe.go | 2 +-
internal/replaycache/replaycache.go | 18 +-
internal/replaycache/replaycache_test.go | 22 +-
internal/resilience/health/diagnostics.go | 28 +-
.../resilience/health/diagnostics_test.go | 16 +-
internal/rules/formats.go | 8 +-
internal/rules/formats_test.go | 30 +-
internal/rules/rules.go | 18 +-
internal/rules/rules_test.go | 62 ++--
internal/safewrite/safewrite_test.go | 2 +-
internal/schedule/fold.go | 2 +-
internal/schedule/manager.go | 2 +-
internal/schedule/schedule_test.go | 2 +-
internal/securitylog/securitylog.go | 4 +-
internal/session/branch.go | 2 +-
internal/session/branch_test.go | 2 +-
internal/session/checkpoint.go | 4 +-
internal/session/conversation_graph.go | 4 +-
internal/session/conversion.go | 22 +-
internal/session/conversion_test.go | 4 +-
internal/session/export.go | 4 +-
internal/session/export_test.go | 2 +-
internal/session/handover.go | 2 +-
internal/session/named_checkpoint.go | 4 +-
internal/session/persist.go | 4 +-
internal/session/persist_integrity_test.go | 8 +-
internal/session/preparations.go | 2 +-
internal/session/preparations_test.go | 2 +-
internal/session/recovery.go | 4 +-
internal/session/search.go | 4 +-
internal/session/session.go | 14 +-
internal/session/session_concurrent_test.go | 12 +-
internal/session/session_test.go | 4 +-
internal/session/snapshot.go | 4 +-
internal/session/snapshot_test.go | 2 +-
internal/session/storage_policy_test.go | 12 +-
internal/session/storage_test_helpers_test.go | 2 +-
internal/session/write_behind.go | 2 +-
internal/session/write_behind_test.go | 2 +-
internal/session/zstd_persist_test.go | 4 +-
internal/sessionquery/db.go | 2 +-
internal/sessionquery/indexer.go | 4 +-
internal/sessionquery/search.go | 2 +-
internal/sessionquery/service.go | 2 +-
internal/sessionquery/sessionquery_test.go | 6 +-
internal/snapshot/l2_home_paths_test.go | 10 +-
internal/snapshot/snapshot.go | 12 +-
internal/snapshot/workspace.go | 8 +-
internal/snapshot/workspace_test.go | 4 +-
internal/spec/config.go | 4 +-
internal/spec/dag.go | 4 +-
internal/spec/schema.go | 2 +-
internal/spec/state.go | 6 +-
internal/spec/state_security_test.go | 2 +-
internal/spec/validator.go | 2 +-
internal/status/snapshot.go | 38 +--
internal/storage/paths.go | 28 +-
internal/storage/paths_extra_test.go | 22 +-
internal/storage/paths_test.go | 28 +-
internal/storage/testdirs.go | 4 +-
internal/stt/stt.go | 4 +-
internal/system/staleness/staleness_test.go | 8 +-
internal/taskruntime/runtime.go | 2 +-
internal/taskruntime/runtime_extra_test.go | 2 +-
internal/taskruntime/runtime_test.go | 2 +-
internal/terminal/store.go | 2 +-
internal/terminal/tape/smoke_test.go | 4 +-
internal/terminal/tape/store.go | 6 +-
internal/terminal/tape/store_test.go | 2 +-
internal/terminal/terminal_test.go | 8 +-
internal/testaudit/audit_test.go | 36 +--
internal/testaudit/changelog_test.go | 6 +-
internal/testaudit/docs_audit_test.go | 12 +-
internal/testaudit/emoji_audit_test.go | 12 +-
internal/testaudit/frontend_contract_test.go | 10 +-
internal/testaudit/helpers.go | 4 +-
internal/testaudit/install_script_test.go | 64 ++---
internal/testaudit/package_boundaries_test.go | 38 +--
internal/testaudit/packaging_test.go | 14 +-
internal/testaudit/release_version_test.go | 2 +-
internal/testaudit/release_workflow_test.go | 18 +-
internal/testrunner/testrunner.go | 2 +-
internal/testutil/network.go | 2 +-
internal/testutil/storage.go | 18 +-
internal/theme/capabilities.go | 2 +-
internal/theme/theme.go | 4 +-
internal/theme/theme_palettes.go | 2 +-
internal/token/estimate.go | 2 +-
internal/token/runtimegraph.go | 2 +-
internal/token/token_test.go | 2 +-
internal/tool/agent.go | 2 +-
internal/tool/agent_limits_test.go | 2 +-
internal/tool/agent_test.go | 2 +-
internal/tool/agentic_fetch.go | 2 +-
internal/tool/agentic_fetch_test.go | 2 +-
internal/tool/announcements.go | 8 +-
internal/tool/api_compat.go | 4 +-
internal/tool/app_verify.go | 6 +-
internal/tool/audit.go | 2 +-
internal/tool/audit_test.go | 2 +-
internal/tool/background.go | 4 +-
internal/tool/backup.go | 2 +-
internal/tool/bash.go | 6 +-
internal/tool/bash_injection_test.go | 6 +-
internal/tool/batch_exec.go | 6 +-
internal/tool/browser.go | 2 +-
internal/tool/browser_ax.go | 2 +-
internal/tool/browser_live_test.go | 8 +-
internal/tool/change_validator.go | 2 +-
internal/tool/change_validator_test.go | 2 +-
internal/tool/code_match.go | 2 +-
internal/tool/code_match_cgo.go | 2 +-
internal/tool/codegraph.go | 2 +-
internal/tool/commitlint.go | 2 +-
internal/tool/commitlint_test.go | 2 +-
internal/tool/download_test.go | 2 +-
internal/tool/extra.go | 4 +-
internal/tool/extra_test.go | 4 +-
internal/tool/file_read.go | 2 +-
internal/tool/file_write.go | 2 +-
internal/tool/fuzzy_find_tool.go | 2 +-
internal/tool/git.go | 2 +-
internal/tool/git_commit.go | 8 +-
internal/tool/git_commit_test.go | 22 +-
internal/tool/git_history.go | 2 +-
internal/tool/git_hooks.go | 60 ++--
internal/tool/git_hooks_test.go | 62 ++--
internal/tool/impact.go | 2 +-
internal/tool/import_organizer_test.go | 8 +-
internal/tool/intents.go | 2 +-
internal/tool/interceptor.go | 2 +-
internal/tool/interceptor_test.go | 2 +-
internal/tool/jobs_tool.go | 4 +-
internal/tool/jobs_tool_test.go | 2 +-
internal/tool/lint_hook.go | 2 +-
internal/tool/lsp.go | 4 +-
internal/tool/mcp_auth.go | 8 +-
internal/tool/mcp_auth_test.go | 4 +-
internal/tool/mcp_lsp.go | 2 +-
internal/tool/mcp_resources.go | 2 +-
internal/tool/mcp_tool.go | 8 +-
internal/tool/media_generation.go | 8 +-
internal/tool/path_resolver.go | 2 +-
internal/tool/project_verify.go | 2 +-
internal/tool/prompt_queue.go | 2 +-
internal/tool/refactor.go | 2 +-
internal/tool/registry_lazy.go | 6 +-
internal/tool/safety_integration_test.go | 34 +--
internal/tool/safety_reexports.go | 2 +-
internal/tool/schedule.go | 2 +-
internal/tool/schedule_test.go | 4 +-
internal/tool/screenshot.go | 2 +-
internal/tool/search_x.go | 2 +-
internal/tool/search_x_test.go | 2 +-
internal/tool/session_query.go | 2 +-
internal/tool/session_query_test.go | 6 +-
internal/tool/shell_safety.go | 4 +-
internal/tool/skill.go | 10 +-
internal/tool/skill_policy_test.go | 2 +-
internal/tool/smart_reader.go | 4 +-
internal/tool/spec.go | 14 +-
internal/tool/spec_analyze.go | 2 +-
internal/tool/spec_bdd.go | 2 +-
internal/tool/spec_clarify.go | 2 +-
internal/tool/spec_constitution.go | 2 +-
internal/tool/spec_converge.go | 2 +-
internal/tool/spec_drift.go | 2 +-
internal/tool/spec_ground.go | 4 +-
internal/tool/spec_links.go | 2 +-
internal/tool/spec_links_test.go | 4 +-
internal/tool/spec_master.go | 2 +-
internal/tool/spec_parallel.go | 4 +-
internal/tool/spec_plan_variations.go | 2 +-
internal/tool/spec_progress.go | 2 +-
internal/tool/spec_properties.go | 2 +-
internal/tool/spec_review.go | 2 +-
internal/tool/spec_test.go | 10 +-
internal/tool/spec_test_first.go | 2 +-
internal/tool/spec_testgen.go | 2 +-
internal/tool/spec_trace.go | 2 +-
internal/tool/spec_version.go | 4 +-
internal/tool/sql.go | 8 +-
internal/tool/task_control.go | 2 +-
internal/tool/task_control_test.go | 2 +-
internal/tool/task_tools.go | 4 +-
internal/tool/terminal.go | 2 +-
internal/tool/terminal_test.go | 2 +-
internal/tool/testmain_test.go | 2 +-
internal/tool/ticket_compliance.go | 8 +-
internal/tool/ticket_compliance_test.go | 42 +--
internal/tool/tool.go | 24 +-
internal/tool/tool_health.go | 2 +-
internal/tool/tool_integration_test.go | 12 +-
internal/tool/tool_metadata_test.go | 12 +-
internal/tool/tool_test.go | 4 +-
internal/tool/toolset_tool.go | 2 +-
internal/tool/transaction.go | 2 +-
internal/tool/treesitter.go | 2 +-
internal/tool/web_fetch.go | 2 +-
internal/tool/web_search.go | 2 +-
internal/tool/web_search_brave.go | 4 +-
internal/tool/web_search_deepseek.go | 4 +-
internal/tool/web_search_exa.go | 4 +-
internal/tool/web_search_perplexity.go | 4 +-
internal/tool/web_search_searxng.go | 4 +-
internal/tool/web_test.go | 2 +-
internal/tool/workflow.go | 2 +-
internal/tool/workflow_test.go | 2 +-
internal/toolsafety/toolsafety.go | 26 +-
internal/toolsafety/toolsafety_test.go | 40 +--
internal/trust/store.go | 28 +-
internal/trust/store_test.go | 8 +-
internal/tui/graphics.go | 6 +-
internal/types/client.go | 54 ++--
internal/types/client_test.go | 6 +-
internal/types/severity.go | 4 +-
internal/ui/icons/codepoints.go | 8 +-
internal/ui/icons/detect.go | 6 +-
internal/ui/icons/detect_test.go | 28 +-
internal/ui/icons/icons.go | 2 +-
internal/update/update.go | 6 +-
internal/update/update_test.go | 6 +-
internal/usage/ledger.go | 2 +-
lefthook.yml | 8 +-
npm/README.md | 16 +-
.../bin/.keep | 0
.../package.json | 6 +-
.../bin/.keep | 0
.../package.json | 6 +-
.../bin/.keep | 0
.../package.json | 6 +-
.../bin/.keep | 0
.../package.json | 6 +-
.../bin/.keep | 0
.../package.json | 6 +-
.../bin/.keep | 0
.../package.json | 6 +-
npm/{rho => decoder}/bin/postinstall.js | 48 ++--
npm/{rho => decoder}/package.json | 16 +-
.../scripts/assemble-platform-packages.js | 54 ++--
packaging/systemd/decoder-daemon.service | 60 ++++
packaging/systemd/rho-daemon.service | 60 ----
scripts/check-ecosystem-boundaries.sh | 8 +-
scripts/check-feature-boundaries.sh | 6 +-
scripts/check-internal-layer-imports.sh | 6 +-
scripts/check-module-release-parity.sh | 10 +-
...imports.sh => check-mux-client-imports.sh} | 10 +-
...undary.sh => check-mux-engine-boundary.sh} | 20 +-
scripts/check-support-repo-coupling.sh | 2 +-
scripts/e2e-macos.sh | 30 +-
scripts/ecosystem-manifest.sh | 4 +-
scripts/fresh-setup-test.sh | 24 +-
scripts/generate-workspace.sh | 4 +-
scripts/{smoke-rho.sh => smoke-decoder.sh} | 10 +-
scripts/stage3_analyze.py | 2 +-
scripts/verify-developer-path.sh | 4 +-
scripts/verify-milestone.sh | 2 +-
spec/README.md | 8 +-
testdata/compatibility-matrix.json | 24 +-
testdata/compatibility-matrix.schema.json | 2 +-
testdata/golden/help_root.txt | 56 ++--
1338 files changed, 8883 insertions(+), 8892 deletions(-)
rename .github/actions/{checkout-flux => checkout-mux}/action.yml (96%)
rename .github/actions/{rho => decoder}/action.yml (58%)
rename cmd/{rho => decoder}/main.go (84%)
rename cmd/{rho_mascot.go => decoder_mascot.go} (55%)
rename docs/architecture/{rho-architecture-baseline.md => decoder-architecture-baseline.md} (79%)
rename docs/architecture/{rho-architecture-v1-definition-of-done.md => decoder-architecture-v1-definition-of-done.md} (71%)
rename docs/architecture/{rho-capability-seams.md => decoder-capability-seams.md} (96%)
rename docs/architecture/{rho-contract-spec.md => decoder-contract-spec.md} (77%)
rename docs/architecture/{rho-current-vs-proposed.md => decoder-current-vs-proposed.md} (72%)
rename docs/architecture/{rho-dependency-rules.md => decoder-dependency-rules.md} (63%)
rename docs/architecture/{rho-feature-modules.md => decoder-feature-modules.md} (89%)
rename docs/architecture/{rho-harness.md => decoder-harness.md} (78%)
rename docs/architecture/{rho-product-architecture.md => decoder-product-architecture.md} (55%)
rename docs/architecture/{rho-provider-abstraction.md => decoder-provider-abstraction.md} (61%)
rename docs/architecture/{rho-repo-roles.md => decoder-repo-roles.md} (60%)
rename docs/architecture/{rho-review-verify-lifecycle.md => decoder-review-verify-lifecycle.md} (81%)
rename docs/architecture/{rho-swift-event-model.md => decoder-swift-event-model.md} (91%)
rename docs/design/{RHO-CLOUD-SAAS.md => DECODER-CLOUD-SAAS.md} (89%)
rename docs/plans/{FULL-GROK-ECO-TO-RHO-ECO-PORT-PLAN.md => FULL-GROK-ECO-TO-DECODER-ECO-PORT-PLAN.md} (74%)
rename docs/plans/{rho-contracts-migration-backlog.md => decoder-contracts-migration-backlog.md} (63%)
rename docs/plans/{rho-tau-alignment.md => decoder-tau-alignment.md} (77%)
rename examples/github/{rho-ci-exec.yml => decoder-ci-exec.yml} (60%)
create mode 100644 examples/github/decoder-delivery-context.yml
rename examples/github/{rho-issue-resolver.yml => decoder-issue-resolver.yml} (56%)
delete mode 100644 examples/github/rho-delivery-context.yml
rename internal/config/{flux_apply.go => mux_apply.go} (72%)
rename internal/config/{flux_engine.go => mux_engine.go} (82%)
rename internal/config/{flux_engine_test.go => mux_engine_test.go} (85%)
rename internal/config/{flux_selection.go => mux_selection.go} (71%)
rename internal/{rhoerr => decodererr}/bridge_error_test.go (96%)
rename internal/{rhoerr => decodererr}/classify.go (97%)
rename internal/{rhoerr => decodererr}/classify_extra_test.go (98%)
rename internal/{rhoerr => decodererr}/errors.go (92%)
rename internal/{rhoerr => decodererr}/exitcode.go (86%)
rename internal/{rhoerr => decodererr}/exitcode_test.go (99%)
rename internal/features/welcome/assets/{rho-mascot-display.png => decoder-mascot-display.png} (100%)
rename npm/{rho-darwin-arm64 => decoder-darwin-arm64}/bin/.keep (100%)
rename npm/{rho-darwin-arm64 => decoder-darwin-arm64}/package.json (58%)
rename npm/{rho-darwin-x64 => decoder-darwin-x64}/bin/.keep (100%)
rename npm/{rho-darwin-x64 => decoder-darwin-x64}/package.json (59%)
rename npm/{rho-linux-arm64 => decoder-linux-arm64}/bin/.keep (100%)
rename npm/{rho-linux-arm64 => decoder-linux-arm64}/package.json (59%)
rename npm/{rho-linux-x64 => decoder-linux-x64}/bin/.keep (100%)
rename npm/{rho-linux-x64 => decoder-linux-x64}/package.json (59%)
rename npm/{rho-win32-arm64 => decoder-win32-arm64}/bin/.keep (100%)
rename npm/{rho-win32-arm64 => decoder-win32-arm64}/package.json (58%)
rename npm/{rho-win32-x64 => decoder-win32-x64}/bin/.keep (100%)
rename npm/{rho-win32-x64 => decoder-win32-x64}/package.json (58%)
rename npm/{rho => decoder}/bin/postinstall.js (79%)
rename npm/{rho => decoder}/package.json (50%)
rename npm/{rho => decoder}/scripts/assemble-platform-packages.js (77%)
create mode 100644 packaging/systemd/decoder-daemon.service
delete mode 100644 packaging/systemd/rho-daemon.service
rename scripts/{check-flux-client-imports.sh => check-mux-client-imports.sh} (52%)
rename scripts/{check-flux-engine-boundary.sh => check-mux-engine-boundary.sh} (59%)
rename scripts/{smoke-rho.sh => smoke-decoder.sh} (83%)
diff --git a/.env.example b/.env.example
index ddfbef9c2..f6299fb56 100644
--- a/.env.example
+++ b/.env.example
@@ -1,10 +1,10 @@
-# rho daemon environment variables — copy to .env and fill in.
-# Only RHO_DAEMON_API_KEY is consumed from the environment.
-RHO_DAEMON_API_KEY=
+# decoder daemon environment variables — copy to .env and fill in.
+# Only DECODER_DAEMON_API_KEY is consumed from the environment.
+DECODER_DAEMON_API_KEY=
-# The following are NOT read by rho — setting them has no effect:
-# RHO_DAEMON_PORT / RHO_DAEMON_HOST — daemon binds 127.0.0.1:4590;
-# override with the --host / --port flags (see `rho daemon start --help`)
-# FLUX_API_KEY / FLUX_BASE_URL, HARRIER_API_KEY / HARRIER_ADDR —
+# The following are NOT read by decoder — setting them has no effect:
+# DECODER_DAEMON_PORT / DECODER_DAEMON_HOST — daemon binds 127.0.0.1:4590;
+# override with the --host / --port flags (see `decoder daemon start --help`)
+# MUX_API_KEY / MUX_BASE_URL, HARRIER_API_KEY / HARRIER_ADDR —
# consumed by sibling services, not by this binary
# See docs/user-guide/05-configuration.md for the full precedence chain.
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index ddef946bb..4b863a150 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,4 +1,4 @@
-# CODEOWNERS for rho
+# CODEOWNERS for decoder
#
# These owners will be the default owners for everything in the repo. Unless
# a later match takes precedence, they will be requested for review when
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index bf5955dd4..19eef71bf 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -11,7 +11,7 @@ body:
of the form as you can — the more we know, the faster we can fix it.
Before submitting:
- - Search [existing issues](https://github.com/GrayCodeAI/rho/issues) to avoid duplicates.
+ - Search [existing issues](https://github.com/GrayCodeAI/decoder/issues) to avoid duplicates.
- If this is a security issue, please **do not** file a public issue. See `SECURITY.md`.
- type: textarea
@@ -19,7 +19,7 @@ body:
attributes:
label: What happened?
description: A clear, concise description of the bug.
- placeholder: When I run `rho ...`, I expected X but got Y.
+ placeholder: When I run `decoder ...`, I expected X but got Y.
validations:
required: true
@@ -29,7 +29,7 @@ body:
label: Steps to reproduce
description: Minimal steps that reliably reproduce the problem.
placeholder: |
- 1. Run `rho ...`
+ 1. Run `decoder ...`
2. Type `...`
3. See error `...`
validations:
@@ -44,10 +44,10 @@ body:
required: true
- type: input
- id: rho-version
+ id: decoder-version
attributes:
- label: rho version
- description: Output of `rho version` (or `rho --version`).
+ label: decoder version
+ description: Output of `decoder version` (or `decoder --version`).
placeholder: "0.1.0"
validations:
required: true
@@ -66,7 +66,7 @@ body:
attributes:
label: Go version (if building from source)
description: Output of `go version`. Skip if you installed a pre-built binary.
- placeholder: "go version go1.26.1 darwin/arm64"
+ placeholder: "go version go1.27.2 darwin/arm64"
- type: textarea
id: logs
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index a6fdeb91e..132cd351d 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,8 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Security vulnerability
- url: https://github.com/GrayCodeAI/rho/security/advisories/new
+ url: https://github.com/GrayCodeAI/decoder/security/advisories/new
about: Please report security issues privately via a GitHub Security Advisory. See SECURITY.md.
- name: Question / discussion
- url: https://github.com/GrayCodeAI/rho/discussions
+ url: https://github.com/GrayCodeAI/decoder/discussions
about: Have a question or want to discuss an idea? Open a discussion instead of an issue.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 992f0f913..b0bad6f34 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -1,5 +1,5 @@
name: Feature request
-description: Suggest an improvement or new capability for rho.
+description: Suggest an improvement or new capability for decoder.
title: "feat: "
labels: ["enhancement", "triage"]
@@ -7,13 +7,13 @@ body:
- type: markdown
attributes:
value: |
- Thanks for proposing a feature. rho is built **for developers first**
+ Thanks for proposing a feature. decoder is built **for developers first**
(one machine, local config, keychain credentials) — teams and enterprise
come later. We evaluate every request against: _"would a single
developer on their own machine benefit from this?"_
Before submitting:
- - Search [existing issues](https://github.com/GrayCodeAI/rho/issues) to avoid duplicates.
+ - Search [existing issues](https://github.com/GrayCodeAI/decoder/issues) to avoid duplicates.
- For large changes, consider opening a discussion first.
- type: textarea
@@ -21,7 +21,7 @@ body:
attributes:
label: What problem are you trying to solve?
description: Describe the user problem first. Solutions can come later.
- placeholder: When I'm doing X, rho makes me do Y, which is painful because Z.
+ placeholder: When I'm doing X, decoder makes me do Y, which is painful because Z.
validations:
required: true
@@ -29,7 +29,7 @@ body:
id: proposal
attributes:
label: Proposed solution
- description: How would you like rho to behave? CLI flags, output, config, etc.
+ description: How would you like decoder to behave? CLI flags, output, config, etc.
validations:
required: true
@@ -55,7 +55,7 @@ body:
id: principles
attributes:
label: Developer fit
- description: rho avoids enterprise scope for now. Confirm this feature respects that.
+ description: decoder avoids enterprise scope for now. Confirm this feature respects that.
options:
- label: Works with zero configuration (sensible defaults).
- label: Works offline / does not require a cloud account.
diff --git a/.github/actions/checkout-flux/action.yml b/.github/actions/checkout-mux/action.yml
similarity index 96%
rename from .github/actions/checkout-flux/action.yml
rename to .github/actions/checkout-mux/action.yml
index 2b1fb2c56..d47124a95 100644
--- a/.github/actions/checkout-flux/action.yml
+++ b/.github/actions/checkout-mux/action.yml
@@ -1,5 +1,5 @@
name: Checkout ecosystem
-description: Clone graycode-eco sibling repos into the workspace parent for rho's go.work
+description: Clone graycode-eco sibling repos into the workspace parent for decoder's go.work
inputs:
ref:
@@ -24,7 +24,7 @@ runs:
# ecosystem migration; downstream guards skip absent checkouts too).
ws_parent="$(cd "${GITHUB_WORKSPACE}/.." && pwd)"
while IFS= read -r repo; do
- [ "$repo" = rho ] && continue
+ [ "$repo" = decoder ] && continue
dest="${ws_parent}/${repo}"
if [ -d "$dest/.git" ]; then
echo "$repo already present at $dest"
diff --git a/.github/actions/rho/action.yml b/.github/actions/decoder/action.yml
similarity index 58%
rename from .github/actions/rho/action.yml
rename to .github/actions/decoder/action.yml
index c43ebff01..9f681b966 100644
--- a/.github/actions/rho/action.yml
+++ b/.github/actions/decoder/action.yml
@@ -1,7 +1,7 @@
-name: Rho
+name: Decoder
description: >-
- Run the Rho coding agent headlessly in a GitHub workflow. Rho is
+ Run the Decoder coding agent headlessly in a GitHub workflow. Decoder is
model- and provider-agnostic: you supply the provider and API key as inputs.
author: GrayCodeAI
@@ -12,7 +12,7 @@ branding:
inputs:
prompt:
- description: The instruction for Rho to execute. Mutually exclusive with prompt-file.
+ description: The instruction for Decoder to execute. Mutually exclusive with prompt-file.
required: false
default: ""
prompt-file:
@@ -29,20 +29,20 @@ inputs:
api-key:
description: >-
The provider API key. Pass it from a repository or organization secret;
- it is exported only for the Rho step and never written to the log.
+ it is exported only for the Decoder step and never written to the log.
required: false
default: ""
api-key-env:
description: >-
Name of the environment variable the chosen provider reads its key from
(for example OPENAI_API_KEY or ANTHROPIC_API_KEY). When set together with
- api-key, that variable is exported only for the Rho step. Leave the action
+ api-key, that variable is exported only for the Decoder step. Leave the action
provider-agnostic by passing the env name your provider expects rather than
hardcoding one here.
required: false
default: ""
model:
- description: Model id to use for the run. Passed to `rho exec --model`.
+ description: Model id to use for the run. Passed to `decoder exec --model`.
required: false
default: ""
auto:
@@ -54,19 +54,19 @@ inputs:
default: supervised
agent:
description: >-
- Agent persona to use (from Rho user state). Maps to `rho exec --agent`.
+ Agent persona to use (from Decoder user state). Maps to `decoder exec --agent`.
required: false
default: ""
cwd:
description: >-
- Working directory override. Maps to `rho exec --cwd`.
+ Working directory override. Maps to `decoder exec --cwd`.
Defaults to the action's working-directory input.
required: false
default: ""
ephemeral:
description: >-
When true, skip session persistence. Ideal for CI runs.
- Maps to `rho exec --ephemeral`.
+ Maps to `decoder exec --ephemeral`.
required: false
default: "false"
worktree:
@@ -80,7 +80,7 @@ inputs:
default: text
post-to:
description: >-
- Optional destination for a run summary after Rho finishes: `pr-comment`
+ Optional destination for a run summary after Decoder finishes: `pr-comment`
posts to the triggering pull request, `slack` posts to slack-webhook-url,
or `none` (default) posts nowhere.
required: false
@@ -93,35 +93,35 @@ inputs:
default: ""
github-token:
description: >-
- Token used to look up the latest Rho release and, when post-to is
+ Token used to look up the latest Decoder release and, when post-to is
pr-comment, to post the PR comment. Defaults to ${{ github.token }}.
required: false
default: ${{ github.token }}
working-directory:
- description: Directory to run Rho in. Defaults to ${{ github.workspace }}.
+ description: Directory to run Decoder in. Defaults to ${{ github.workspace }}.
required: false
default: ${{ github.workspace }}
- rho-version:
+ decoder-version:
description: >-
- Rho release to install (e.g. 0.3.0 or v0.3.0), or latest. Defaults to
+ Decoder release to install (e.g. 0.3.0 or v0.3.0), or latest. Defaults to
the release tag this action is pinned to (uses: ...@v0.3.0); a branch or
- commit-SHA pin installs the latest release. Requires Rho v0.3.0 or later:
- earlier tags predate the rename and have no rho_* archives.
+ commit-SHA pin installs the latest release. Requires Decoder v0.3.0 or later:
+ earlier tags predate the rename and have no decoder_* archives.
required: false
default: ""
- rho-repo:
+ decoder-repo:
description: >-
- Repository to install Rho from (owner/repo). The release archive's
+ Repository to install Decoder from (owner/repo). The release archive's
cosign signature must come from that repository's release workflow.
required: false
- default: GrayCodeAI/rho
+ default: GrayCodeAI/decoder
outputs:
exit-code:
- description: The exit code Rho returned (0 success, 2 usage, 3 provider, non-zero otherwise).
+ description: The exit code Decoder returned (0 success, 2 usage, 3 provider, non-zero otherwise).
value: ${{ steps.run.outputs.exit-code }}
output-file:
- description: Path to the captured Rho stdout (the raw output-format stream).
+ description: Path to the captured Decoder stdout (the raw output-format stream).
value: ${{ steps.run.outputs.output-file }}
summary:
description: A short human-readable summary line parsed from the run, when available.
@@ -131,16 +131,16 @@ runs:
using: composite
steps:
# cosign verifies the release signature; install.sh runs with
- # RHO_REQUIRE_COSIGN=1 so an unsigned or tampered release fails the step.
+ # DECODER_REQUIRE_COSIGN=1 so an unsigned or tampered release fails the step.
- name: Install cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
- - name: Install Rho
+ - name: Install Decoder
id: install
shell: bash
env:
- RHO_REPO: ${{ inputs.rho-repo }}
- RHO_VERSION_INPUT: ${{ inputs.rho-version }}
+ DECODER_REPO: ${{ inputs.decoder-repo }}
+ DECODER_VERSION_INPUT: ${{ inputs.decoder-version }}
ACTION_REF: ${{ github.action_ref }}
ACTION_PATH: ${{ github.action_path }}
GH_TOKEN: ${{ inputs.github-token }}
@@ -148,26 +148,26 @@ runs:
run: |
set -euo pipefail
if [ "${RUNNER_OS}" = "Windows" ]; then
- echo "::error::The Rho action currently supports Linux and macOS runners only." >&2
+ echo "::error::The Decoder action currently supports Linux and macOS runners only." >&2
exit 1
fi
- if ! [[ "${RHO_REPO}" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then
- echo "::error::rho-repo must look like owner/repo." >&2
+ if ! [[ "${DECODER_REPO}" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then
+ echo "::error::decoder-repo must look like owner/repo." >&2
exit 2
fi
release_re='^v?[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'
# Resolve the version: explicit input wins; otherwise the release tag
# this action is pinned to; otherwise (branch or SHA pin) the latest
- # release of rho-repo.
- version="${RHO_VERSION_INPUT}"
+ # release of decoder-repo.
+ version="${DECODER_VERSION_INPUT}"
if [ -z "${version}" ] && [[ "${ACTION_REF}" =~ ${release_re} ]]; then
version="${ACTION_REF}"
fi
if [ -z "${version}" ] || [ "${version}" = "latest" ]; then
- version="$(gh release view --repo "${RHO_REPO}" --json tagName --jq .tagName)"
+ version="$(gh release view --repo "${DECODER_REPO}" --json tagName --jq .tagName)"
fi
if ! [[ "${version}" =~ ${release_re} ]]; then
- echo "::error::rho-version must be a release version such as 0.3.0, or 'latest'." >&2
+ echo "::error::decoder-version must be a release version such as 0.3.0, or 'latest'." >&2
exit 2
fi
version="${version#v}"
@@ -175,31 +175,31 @@ runs:
# release archive and checksums.txt, verifies the cosign signature
# (required here) and the SHA-256, and installs under the prefix.
installer="$(cd "${ACTION_PATH}/../../.." && pwd)/install.sh"
- prefix="${RUNNER_TEMP}/rho"
- RHO_INSTALL_REPO="${RHO_REPO}" RHO_REQUIRE_COSIGN=1 \
+ prefix="${RUNNER_TEMP}/decoder"
+ DECODER_INSTALL_REPO="${DECODER_REPO}" DECODER_REQUIRE_COSIGN=1 \
sh "${installer}" --version "${version}" --prefix "${prefix}"
echo "${prefix}/bin" >> "${GITHUB_PATH}"
- echo "Installed Rho ${version} from ${RHO_REPO}"
+ echo "Installed Decoder ${version} from ${DECODER_REPO}"
- - name: Run Rho
+ - name: Run Decoder
id: run
shell: bash
working-directory: ${{ inputs.working-directory }}
env:
# Secrets are passed via the environment and never echoed. `set +x` and
# the absence of any `echo` of these values keep them out of the log.
- RHO_INPUT_API_KEY: ${{ inputs.api-key }}
- RHO_INPUT_API_KEY_ENV: ${{ inputs.api-key-env }}
- RHO_INPUT_PROVIDER: ${{ inputs.provider }}
- RHO_INPUT_PROMPT: ${{ inputs.prompt }}
- RHO_INPUT_PROMPT_FILE: ${{ inputs.prompt-file }}
- RHO_INPUT_MODEL: ${{ inputs.model }}
- RHO_INPUT_AUTO: ${{ inputs.auto }}
- RHO_INPUT_AGENT: ${{ inputs.agent }}
- RHO_INPUT_CWD: ${{ inputs.cwd }}
- RHO_INPUT_EPHEMERAL: ${{ inputs.ephemeral }}
- RHO_INPUT_WORKTREE: ${{ inputs.worktree }}
- RHO_INPUT_OUTPUT_FORMAT: ${{ inputs.output-format }}
+ DECODER_INPUT_API_KEY: ${{ inputs.api-key }}
+ DECODER_INPUT_API_KEY_ENV: ${{ inputs.api-key-env }}
+ DECODER_INPUT_PROVIDER: ${{ inputs.provider }}
+ DECODER_INPUT_PROMPT: ${{ inputs.prompt }}
+ DECODER_INPUT_PROMPT_FILE: ${{ inputs.prompt-file }}
+ DECODER_INPUT_MODEL: ${{ inputs.model }}
+ DECODER_INPUT_AUTO: ${{ inputs.auto }}
+ DECODER_INPUT_AGENT: ${{ inputs.agent }}
+ DECODER_INPUT_CWD: ${{ inputs.cwd }}
+ DECODER_INPUT_EPHEMERAL: ${{ inputs.ephemeral }}
+ DECODER_INPUT_WORKTREE: ${{ inputs.worktree }}
+ DECODER_INPUT_OUTPUT_FORMAT: ${{ inputs.output-format }}
ACTION_PATH: ${{ github.action_path }}
RUNNER_TEMP: ${{ runner.temp }}
run: |
@@ -208,50 +208,50 @@ runs:
# Export the provider key under the env name the provider expects. This
# keeps the action provider-agnostic: no provider->env mapping is baked
# in. The value is never printed.
- if [ -n "${RHO_INPUT_API_KEY}" ] && [ -n "${RHO_INPUT_API_KEY_ENV}" ]; then
- if ! printf '%s' "${RHO_INPUT_API_KEY_ENV}" | grep -qE '^[A-Za-z_][A-Za-z0-9_]*$'; then
+ if [ -n "${DECODER_INPUT_API_KEY}" ] && [ -n "${DECODER_INPUT_API_KEY_ENV}" ]; then
+ if ! printf '%s' "${DECODER_INPUT_API_KEY_ENV}" | grep -qE '^[A-Za-z_][A-Za-z0-9_]*$'; then
echo "::error::api-key-env must be a valid environment variable name." >&2
exit 2
fi
- export "${RHO_INPUT_API_KEY_ENV}=${RHO_INPUT_API_KEY}"
+ export "${DECODER_INPUT_API_KEY_ENV}=${DECODER_INPUT_API_KEY}"
fi
- if [ -n "${RHO_INPUT_PROVIDER}" ]; then
- export RHO_PROVIDER="${RHO_INPUT_PROVIDER}"
+ if [ -n "${DECODER_INPUT_PROVIDER}" ]; then
+ export DECODER_PROVIDER="${DECODER_INPUT_PROVIDER}"
fi
args=(exec)
- if [ -n "${RHO_INPUT_PROMPT_FILE}" ] && [ -n "${RHO_INPUT_PROMPT}" ]; then
+ if [ -n "${DECODER_INPUT_PROMPT_FILE}" ] && [ -n "${DECODER_INPUT_PROMPT}" ]; then
echo "::error::The 'prompt' and 'prompt-file' inputs are mutually exclusive." >&2
exit 2
fi
- if [ -n "${RHO_INPUT_PROMPT_FILE}" ]; then
- args+=(--file "${RHO_INPUT_PROMPT_FILE}")
- elif [ -n "${RHO_INPUT_PROMPT}" ]; then
- args+=("${RHO_INPUT_PROMPT}")
+ if [ -n "${DECODER_INPUT_PROMPT_FILE}" ]; then
+ args+=(--file "${DECODER_INPUT_PROMPT_FILE}")
+ elif [ -n "${DECODER_INPUT_PROMPT}" ]; then
+ args+=("${DECODER_INPUT_PROMPT}")
else
echo "::error::Provide either the 'prompt' or 'prompt-file' input." >&2
exit 2
fi
- [ -n "${RHO_INPUT_MODEL}" ] && args+=(--model "${RHO_INPUT_MODEL}")
- [ -n "${RHO_INPUT_AUTO}" ] && args+=(--auto "${RHO_INPUT_AUTO}")
- [ -n "${RHO_INPUT_AGENT}" ] && args+=(--agent "${RHO_INPUT_AGENT}")
- [ -n "${RHO_INPUT_CWD}" ] && args+=(--cwd "${RHO_INPUT_CWD}")
- if [ "${RHO_INPUT_EPHEMERAL}" = "true" ]; then
+ [ -n "${DECODER_INPUT_MODEL}" ] && args+=(--model "${DECODER_INPUT_MODEL}")
+ [ -n "${DECODER_INPUT_AUTO}" ] && args+=(--auto "${DECODER_INPUT_AUTO}")
+ [ -n "${DECODER_INPUT_AGENT}" ] && args+=(--agent "${DECODER_INPUT_AGENT}")
+ [ -n "${DECODER_INPUT_CWD}" ] && args+=(--cwd "${DECODER_INPUT_CWD}")
+ if [ "${DECODER_INPUT_EPHEMERAL}" = "true" ]; then
args+=(--ephemeral)
fi
- if [ "${RHO_INPUT_WORKTREE}" = "true" ]; then
+ if [ "${DECODER_INPUT_WORKTREE}" = "true" ]; then
args+=(--worktree)
fi
- [ -n "${RHO_INPUT_OUTPUT_FORMAT}" ] && args+=(--output-format "${RHO_INPUT_OUTPUT_FORMAT}")
+ [ -n "${DECODER_INPUT_OUTPUT_FORMAT}" ] && args+=(--output-format "${DECODER_INPUT_OUTPUT_FORMAT}")
- output_file="${RUNNER_TEMP}/rho-output.txt"
+ output_file="${RUNNER_TEMP}/decoder-output.txt"
- # Run Rho. Capture stdout to a file AND echo it to the log. Surface the
+ # Run Decoder. Capture stdout to a file AND echo it to the log. Surface the
# real exit code as the step's status.
set +e
- rho "${args[@]}" | tee "${output_file}"
+ decoder "${args[@]}" | tee "${output_file}"
code=${PIPESTATUS[0]}
set -e
@@ -260,14 +260,14 @@ runs:
# Best-effort one-line summary
if [ "${code}" = "0" ]; then
- summary="Rho run succeeded"
+ summary="Decoder run succeeded"
else
- summary="Rho run failed (exit ${code})"
+ summary="Decoder run failed (exit ${code})"
fi
{
- echo "summary<> "${GITHUB_OUTPUT}"
exit "${code}"
@@ -278,13 +278,13 @@ runs:
env:
GH_TOKEN: ${{ inputs.github-token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
- RHO_EXIT: ${{ steps.run.outputs.exit-code }}
- RHO_SUMMARY: ${{ steps.run.outputs.summary }}
+ DECODER_EXIT: ${{ steps.run.outputs.exit-code }}
+ DECODER_SUMMARY: ${{ steps.run.outputs.summary }}
run: |
set -euo pipefail
status="succeeded"
- [ "${RHO_EXIT}" != "0" ] && status="failed (exit ${RHO_EXIT})"
- body="$(printf 'Rho run %s.\n\n%s' "${status}" "${RHO_SUMMARY}")"
+ [ "${DECODER_EXIT}" != "0" ] && status="failed (exit ${DECODER_EXIT})"
+ body="$(printf 'Decoder run %s.\n\n%s' "${status}" "${DECODER_SUMMARY}")"
gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \
-f body="${body}" >/dev/null
@@ -293,14 +293,14 @@ runs:
shell: bash
env:
SLACK_WEBHOOK_URL: ${{ inputs.slack-webhook-url }}
- RHO_EXIT: ${{ steps.run.outputs.exit-code }}
- RHO_SUMMARY: ${{ steps.run.outputs.summary }}
+ DECODER_EXIT: ${{ steps.run.outputs.exit-code }}
+ DECODER_SUMMARY: ${{ steps.run.outputs.summary }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
status="succeeded"
- [ "${RHO_EXIT}" != "0" ] && status="failed (exit ${RHO_EXIT})"
- text="Rho run ${status} for ${GITHUB_REPOSITORY}@${GITHUB_REF_NAME}. ${RHO_SUMMARY} ${RUN_URL}"
+ [ "${DECODER_EXIT}" != "0" ] && status="failed (exit ${DECODER_EXIT})"
+ text="Decoder run ${status} for ${GITHUB_REPOSITORY}@${GITHUB_REF_NAME}. ${DECODER_SUMMARY} ${RUN_URL}"
payload="$(jq -n --arg text "${text}" '{text: $text}')"
curl --fail --silent --show-error -X POST -H 'Content-Type: application/json' \
-d "${payload}" "${SLACK_WEBHOOK_URL}" >/dev/null || \
diff --git a/.github/actions/setup-deps/action.yml b/.github/actions/setup-deps/action.yml
index 53a187601..64abd1a9c 100644
--- a/.github/actions/setup-deps/action.yml
+++ b/.github/actions/setup-deps/action.yml
@@ -4,7 +4,7 @@ description: Clone ecosystem sibling repos with retry, setup Go, sync workspace
inputs:
go-version:
description: Go version to install
- default: '1.26.1'
+ default: '1.27.2'
token:
description: GitHub token for authenticated clones
required: true
@@ -28,7 +28,7 @@ runs:
ws_parent="$(cd "${GITHUB_WORKSPACE}/.." && pwd)"
mkdir -p "$ws_parent"
while IFS= read -r repo; do
- [ "$repo" = rho ] && continue
+ [ "$repo" = decoder ] && continue
dest="$ws_parent/$repo"
if [ -d "$dest/.git" ]; then
echo "$repo already present at $dest"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9c2ca8196..c119afd05 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,8 +19,8 @@ concurrency:
cancel-in-progress: true
env:
- GO_VERSION: "1.26.6"
- # Module resolution: flux is the only GrayCodeAI module dependency and it is
+ GO_VERSION: "1.27.2"
+ # Module resolution: mux is the only GrayCodeAI module dependency and it is
# published on the public proxy. Direct-VCS fallback is retained for anything
# else.
GOPROXY: "https://proxy.golang.org,direct"
@@ -29,7 +29,7 @@ env:
# Go's reference is explicit that a committed go.work "may cause a continuous
# integration (CI) system to select and thus test the wrong versions of a
# module's dependencies" and that "CI systems should generally not be allowed to
- # use the go.work file". Because ./.github/actions/checkout-flux clones the
+ # use the go.work file". Because ./.github/actions/checkout-mux clones the
# siblings at branch HEAD into the workspace parent, workspace mode would silently
# hide version skew (e.g. a shared pin that no longer matches).
# The `module` job opts back in (GOWORK: "auto") since `go work sync` and the
@@ -73,13 +73,13 @@ jobs:
run: bash ./scripts/check-ecosystem-boundaries.sh
- name: internal layer boundary guard
run: bash ./scripts/check-internal-layer-imports.sh
- - name: flux client boundary guard
- run: bash ./scripts/check-flux-client-imports.sh
- - name: flux engine facade boundary guard
- run: bash ./scripts/check-flux-engine-boundary.sh
+ - name: mux client boundary guard
+ run: bash ./scripts/check-mux-client-imports.sh
+ - name: mux engine facade boundary guard
+ run: bash ./scripts/check-mux-engine-boundary.sh
# -------------------------------------------------------------------------
- # 2. Module hygiene — tidy, verify Rho plus the sibling Go modules via go.work.
+ # 2. Module hygiene — tidy, verify Decoder plus the sibling Go modules via go.work.
# -------------------------------------------------------------------------
module:
name: module hygiene
@@ -94,7 +94,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Generate ecosystem workspace
@@ -109,7 +109,7 @@ jobs:
# go mod tidy can mis-resolve workspace modules here; go work sync is
# the supported workspace hygiene step.
go work sync
- go build -mod=readonly -o /dev/null ./cmd/rho
+ go build -mod=readonly -o /dev/null ./cmd/decoder
if ! git diff --quiet -- go.mod go.sum go.work go.work.sum; then
echo "::error::go.mod / go.sum / go.work files out of date — run 'go work sync' locally and commit"
git diff -- go.mod go.sum go.work go.work.sum
@@ -121,7 +121,7 @@ jobs:
run: |
workspace_file="${GITHUB_WORKSPACE}/../go.work"
while IFS= read -r module; do
- [ "$module" = rho ] && continue
+ [ "$module" = decoder ] && continue
if ! grep -q "./${module}" "$workspace_file"; then
echo "::error::go.work must include ./${module}."
cat "$workspace_file"
@@ -145,7 +145,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -158,7 +158,7 @@ jobs:
run: |
go mod download
go mod verify
- go build -mod=readonly ./cmd/rho
+ go build -mod=readonly ./cmd/decoder
go test ./... -count=1 -timeout=300s
release-parity:
@@ -168,7 +168,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -187,7 +187,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -196,8 +196,8 @@ jobs:
cache: true
- name: go vet
run: go vet ./...
- - name: rho harness evaluation audit
- run: go run ./cmd/rho harness --out-dir .rho/harness
+ - name: decoder harness evaluation audit
+ run: go run ./cmd/decoder harness --out-dir .decoder/harness
- name: support repo coupling guard
run: bash ./scripts/check-support-repo-coupling.sh
@@ -212,7 +212,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -232,7 +232,7 @@ jobs:
runs-on: ubuntu-latest
# NOTE: depends only on `format`, deliberately NOT on `vet`.
# A `vet` (or upstream) failure must never skip the test job — that
- # historically masked real test regressions (see rho PR #155, where
+ # historically masked real test regressions (see decoder PR #155, where
# DrainAlerts code shipped with failing tests because `test` was skipped
# when `vet` failed on the trailer-strip force-push). Tests must always
# run so regressions surface instead of being hidden.
@@ -241,7 +241,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -313,7 +313,7 @@ jobs:
echo ""
echo "Policy: Every t.Skip() should have a comment linking to a GitHub issue."
echo "Example:"
- echo " // TODO: https://github.com/GrayCodeAI/rho/issues/123"
+ echo " // TODO: https://github.com/GrayCodeAI/decoder/issues/123"
echo " t.Skip(\"not yet implemented\")"
fi
@@ -328,7 +328,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -436,7 +436,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c
@@ -491,7 +491,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -506,7 +506,7 @@ jobs:
run: go build -trimpath -v ./...
- name: Binary size budget (linux/amd64 only)
if: matrix.goos == 'linux' && matrix.goarch == 'amd64'
- # Builds bin/rho with the release ldflags (-s -w) and fails when it
+ # Builds bin/decoder with the release ldflags (-s -w) and fails when it
# exceeds SIZE_LIMIT_MB in the Makefile — the single source of the budget.
run: make size-check
@@ -521,7 +521,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
@@ -544,7 +544,7 @@ jobs:
go test -run='^$' -fuzz=FuzzParseToolCallResult -fuzztime=60s ./internal/mcp
# -------------------------------------------------------------------------
- # 10. Smoke — build rho and verify ecosystem CLI wiring.
+ # 10. Smoke — build decoder and verify ecosystem CLI wiring.
# -------------------------------------------------------------------------
smoke:
name: smoke
@@ -554,12 +554,12 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- - name: smoke-rho.sh
- run: ./scripts/smoke-rho.sh
+ - name: smoke-decoder.sh
+ run: ./scripts/smoke-decoder.sh
diff --git a/.github/workflows/compatibility-matrix.yml b/.github/workflows/compatibility-matrix.yml
index ac80831db..3cac8b8cd 100644
--- a/.github/workflows/compatibility-matrix.yml
+++ b/.github/workflows/compatibility-matrix.yml
@@ -23,12 +23,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: ./.github/actions/checkout-flux
+ - uses: ./.github/actions/checkout-mux
with:
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
- go-version: "1.26.6"
+ go-version: "1.27.2"
cache: true
- name: Structural validation (schema + version pins)
run: make compat-check
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index fa0b179ee..aff18ba4c 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,4 +1,4 @@
-# Release workflow for rho. A maintainer pushes a v tag after the
+# Release workflow for decoder. A maintainer pushes a v tag after the
# release PR (VERSION + CHANGELOG) has merged; creating v* tags is restricted by
# the repository ruleset "protect-release-tags". See docs/RELEASING.md.
# Source of truth: .shared-templates/workflows/go-release.yml.tmpl
@@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
env:
GOPROXY: "https://proxy.golang.org,direct"
- # Release builds resolve every dependency (including flux) from
+ # Release builds resolve every dependency (including mux) from
# go.mod/go.sum through the public proxy — never from sibling checkouts.
GOWORK: "off"
steps:
@@ -40,7 +40,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
- go-version: "1.26.6"
+ go-version: "1.27.2"
cache: true
- name: Refuse local replace directives
diff --git a/.gitignore b/.gitignore
index 637ffaa90..7903bccc6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,11 @@
# Binaries
-/rho
+/decoder
# Ignore build output in bin/, but track committed source scripts like bin/buf.
bin/*
!bin/buf
# GoReleaser output (goreleaser release --snapshot / make release).
/dist/
-rho_bin
+decoder_bin
*.exe
*.dll
*.so
@@ -14,7 +14,7 @@ rho_bin
.claude/
.codegraph/
.commandcode/
-.rho/
+.decoder/
.harrier/
.openclaude/
.pi/
@@ -49,11 +49,11 @@ go.work.sum
# Lefthook-generated git hook wrappers
.githooks/
__pycache__/
-rho_bin
+decoder_bin
# Logs
*.log
-rho-sec105b.log
+decoder-sec105b.log
# Compiled Go test binaries
*.test
@@ -63,7 +63,7 @@ rho-sec105b.log
# for tools that prefer it; keep the regenerated copy out of git.
/CLAUDE.md
-# Local module overlay for building against a sibling checkout (e.g. flux).
+# Local module overlay for building against a sibling checkout (e.g. mux).
# go.local.mod carries a `replace` directive pointing at ../; committing
# it would break CI, which builds against the pinned published module.
/go.local.mod
diff --git a/.golangci.yml b/.golangci.yml
index 2f7923bbb..88040715a 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -24,7 +24,7 @@ linters:
# production code with this set). Deliberately excluded floods:
# G104 — unhandled errors, already covered by errcheck
# G301/G306 — 0755/0644 perms are intentional for user-visible files
- # G304 — rho reads user-supplied file paths by design (CLI agent)
+ # G304 — decoder reads user-supplied file paths by design (CLI agent)
includes:
- G101 # hardcoded credentials
- G102 # bind to all interfaces
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 783e89c25..d11598581 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -1,5 +1,5 @@
-# GoReleaser config for rho (the terminal AI coding agent).
-# Derived from .shared-templates/.goreleaser.yml.tmpl; rho-specific deltas are
+# GoReleaser config for decoder (the terminal AI coding agent).
+# Derived from .shared-templates/.goreleaser.yml.tmpl; decoder-specific deltas are
# commented inline. Run by .github/workflows/release.yml on a v* tag; see
# docs/RELEASING.md for the release process.
#
@@ -8,7 +8,7 @@
# goreleaser release --snapshot --clean --skip=publish,sign
version: 2
-project_name: rho
+project_name: decoder
# ---------------------------------------------------------------------------
# Pre-build hooks — verify module checksums before building anything.
@@ -23,9 +23,9 @@ before:
# rather than the build host's clock.
# ---------------------------------------------------------------------------
builds:
- - id: rho
- main: ./cmd/rho
- binary: rho
+ - id: decoder
+ main: ./cmd/decoder
+ binary: decoder
env:
- CGO_ENABLED=0
# Build strictly from go.mod/go.sum, never from a developer go.work.
@@ -48,7 +48,7 @@ builds:
# ---------------------------------------------------------------------------
# Archives — tar.gz on Unix, zip on Windows. Names are
-# rho___.; install.sh and .github/actions/rho depend
+# decoder___.; install.sh and .github/actions/decoder depend
# on this exact shape.
# ---------------------------------------------------------------------------
archives:
@@ -94,7 +94,7 @@ checksum:
# uploaded with the release as checksums.txt.sigstore.json. Verify with:
#
# cosign verify-blob --bundle checksums.txt.sigstore.json \
-# --certificate-identity "https://github.com/GrayCodeAI/rho/.github/workflows/release.yml@refs/tags/vX.Y.Z" \
+# --certificate-identity "https://github.com/GrayCodeAI/decoder/.github/workflows/release.yml@refs/tags/vX.Y.Z" \
# --certificate-oidc-issuer https://token.actions.githubusercontent.com \
# checksums.txt
# ---------------------------------------------------------------------------
@@ -164,9 +164,9 @@ release:
prerelease: auto
name_template: "v{{ .Version }}"
header: |
- ## rho v{{ .Version }}
+ ## decoder v{{ .Version }}
- Rho is the terminal AI coding agent from GrayCode (pre-1.0).
+ Decoder is the terminal AI coding agent from GrayCode (pre-1.0).
footer: |
### Verify this release
@@ -176,10 +176,10 @@ release:
```sh
cosign verify-blob --bundle checksums.txt.sigstore.json \
- --certificate-identity "https://github.com/GrayCodeAI/rho/.github/workflows/release.yml@refs/tags/{{ .Tag }}" \
+ --certificate-identity "https://github.com/GrayCodeAI/decoder/.github/workflows/release.yml@refs/tags/{{ .Tag }}" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
checksums.txt
sha256sum --ignore-missing -c checksums.txt
```
- {{ if .PreviousTag }}**Full changelog:** https://github.com/GrayCodeAI/rho/compare/{{ .PreviousTag }}...{{ .Tag }}{{ end }}
+ {{ if .PreviousTag }}**Full changelog:** https://github.com/GrayCodeAI/decoder/compare/{{ .PreviousTag }}...{{ .Tag }}{{ end }}
diff --git a/.shared-templates/.goreleaser.yml.tmpl b/.shared-templates/.goreleaser.yml.tmpl
index eec7aedf3..ae9ad4bd1 100644
--- a/.shared-templates/.goreleaser.yml.tmpl
+++ b/.shared-templates/.goreleaser.yml.tmpl
@@ -1,11 +1,11 @@
# Canonical GrayCodeAI goreleaser config for Go binary repos.
-# Source of truth: .shared-templates/.goreleaser.yml.tmpl (rho's
+# Source of truth: .shared-templates/.goreleaser.yml.tmpl (decoder's
# .goreleaser.yml is the reference rendering).
#
# Placeholders rendered per repo (ALL-CAPS, distinct from goreleaser's own
# `{{.Version}}`-style Go template fields, which are left as-is below):
-# {{NAME}} — short repo name (e.g. rho)
-# {{MAIN_PKG}} — main package path (e.g. ./ or ./cmd/rho)
+# {{NAME}} — short repo name (e.g. decoder)
+# {{MAIN_PKG}} — main package path (e.g. ./ or ./cmd/decoder)
# {{DESCRIPTION}} — short single-line description for the release header
# {{VERSION_PKG}} — Go package path holding Version vars
# (e.g. main or github.com/GrayCodeAI//internal/version)
diff --git a/.shared-templates/Makefile.binary.tmpl b/.shared-templates/Makefile.binary.tmpl
index 1646cc356..3f06b178d 100644
--- a/.shared-templates/Makefile.binary.tmpl
+++ b/.shared-templates/Makefile.binary.tmpl
@@ -2,13 +2,13 @@
# Source of truth: .shared-templates/Makefile.binary.tmpl at the eco root.
# Placeholders rendered per repo: {{NAME}}, {{MAIN_PKG}}.
#
-# rho is currently the only Go binary repo in the ecosystem, and its real
-# Makefile extends this core with rho-specific targets (workspace `setup`,
+# decoder is currently the only Go binary repo in the ecosystem, and its real
+# Makefile extends this core with decoder-specific targets (workspace `setup`,
# `compat-test`/`compat-check`, `sync-submodules`/`sync-external`,
# `build-all`/`build-static`/`size-check`, and split `*-guard` boundary
# checks instead of the single generic `boundaries` below). Treat this file
# as the floor every Go binary repo starts from, not a literal copy of
-# rho/Makefile.
+# decoder/Makefile.
# ---------------------------------------------------------------------------
# Project metadata
@@ -18,7 +18,7 @@ MAIN_PKG := {{MAIN_PKG}}
# ---------------------------------------------------------------------------
# Versioning — sourced from VERSION file; falls back to git describe.
-# See https://github.com/GrayCodeAI/rho/blob/main/docs/versioning.md.
+# See https://github.com/GrayCodeAI/decoder/blob/main/docs/versioning.md.
# ---------------------------------------------------------------------------
VERSION ?= $(shell v=$$(cat VERSION 2>/dev/null | head -n1 | tr -d '[:space:]'); if [ -n "$$v" ]; then echo "$$v"; else git describe --tags --always --dirty 2>/dev/null || echo "dev"; fi)
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "none")
@@ -139,5 +139,5 @@ hooks: ## Install git hooks via lefthook (formatting, linting, conventional comm
# ---------------------------------------------------------------------------
# Repo-specific extensions go below this line — workspace setup, submodule
# sync, cross-platform build matrices, compatibility-matrix checks, etc.
-# See rho/Makefile for the real, extended reference implementation.
+# See decoder/Makefile for the real, extended reference implementation.
# ---------------------------------------------------------------------------
diff --git a/.shared-templates/Makefile.library.tmpl b/.shared-templates/Makefile.library.tmpl
index d2b16e25a..7a8643ca7 100644
--- a/.shared-templates/Makefile.library.tmpl
+++ b/.shared-templates/Makefile.library.tmpl
@@ -9,7 +9,7 @@ NAME := {{NAME}}
# ---------------------------------------------------------------------------
# Versioning — sourced from VERSION file; falls back to git describe.
-# See https://github.com/GrayCodeAI/rho/blob/main/VERSIONING.md.
+# See https://github.com/GrayCodeAI/decoder/blob/main/VERSIONING.md.
# ---------------------------------------------------------------------------
VERSION ?= $(shell v=$$(cat VERSION 2>/dev/null | head -n1 | tr -d '[:space:]'); if [ -n "$$v" ]; then echo "$$v"; else git describe --tags --always --dirty 2>/dev/null || echo "dev"; fi)
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "none")
diff --git a/.shared-templates/Makefile.python.tmpl b/.shared-templates/Makefile.python.tmpl
index 24b1a6720..4a53beb63 100644
--- a/.shared-templates/Makefile.python.tmpl
+++ b/.shared-templates/Makefile.python.tmpl
@@ -63,7 +63,7 @@ fmt: ## Format with ruff.
vet: ## Type-check with mypy.
$(PYTHON) -m mypy src/
-boundary-guard: ## Fail if the SDK references support engines or Rho private packages.
+boundary-guard: ## Fail if the SDK references support engines or Decoder private packages.
bash ./scripts/check-consumer-boundaries.sh
lint: ## Lint with ruff.
diff --git a/.shared-templates/README.md b/.shared-templates/README.md
index bcfb91eb4..826bc41d8 100644
--- a/.shared-templates/README.md
+++ b/.shared-templates/README.md
@@ -7,17 +7,17 @@ Every graycode-ecosystem repo's `Makefile`, `lefthook.yml`, and
# Source of truth: .shared-templates/Makefile.library.tmpl at the eco root.
```
-This directory is that source of truth. It lives here, in `rho`, because
-`rho` is the one repo every consumer already depends on or references —
+This directory is that source of truth. It lives here, in `decoder`, because
+`decoder` is the one repo every consumer already depends on or references —
there is no separate monorepo at the workspace root to hold it.
-**This directory is not built or run by rho itself.** It is a template
+**This directory is not built or run by decoder itself.** It is a template
library that other graycode-ecosystem repos copy from and diff against.
## Layout
- `Makefile.library.tmpl` — Go library repos (engines, SDKs, foundation repos)
-- `Makefile.binary.tmpl` — Go binary repos (currently only `rho`)
+- `Makefile.binary.tmpl` — Go binary repos (currently only `decoder`)
- `Makefile.python.tmpl` — Python repos (`robin`)
- `lefthook.yml.tmpl` — git hooks config, identical across all Go repos
- `.goreleaser.yml.tmpl` — goreleaser config for Go binary repos
@@ -28,7 +28,7 @@ library that other graycode-ecosystem repos copy from and diff against.
- `workflows/python-release.yml.tmpl` — PyPI publish workflow (Trusted Publishing)
- `workflows/compatibility-test.yml.tmpl` — cross-repo compatibility matrix check (see `docs/compatibility.md`)
- `scripts/check-ecosystem-boundaries.sh.tmpl` — the import-boundary guard, parameterized per repo role
-- `scripts/sync-external.sh` — read-only drift report for `rho`'s `external/` submodule pins (rho-specific, not templated elsewhere)
+- `scripts/sync-external.sh` — read-only drift report for `decoder`'s `external/` submodule pins (decoder-specific, not templated elsewhere)
- `docs/coverage-matrix.md` — per-repo test coverage thresholds enforced in CI, kept in one place so they don't silently drift out of sync with each repo's `go-ci.yml`
## How repos use this
@@ -37,9 +37,9 @@ There is currently no rendering tool — repos copy a template, replace the
placeholders marked `{{LIKE_THIS}}`, and keep the "Source of truth" header
comment pointing back here. When you change a template, the repos that
copied it are now stale; update them in the same PR or file a follow-up
-per repo. `rho`'s own `Makefile`/`lefthook.yml`/CI predate this directory
+per repo. `decoder`'s own `Makefile`/`lefthook.yml`/CI predate this directory
and intentionally diverge in a few binary-specific ways (see
-`Makefile.binary.tmpl`, which documents the real deltas against `rho`'s
+`Makefile.binary.tmpl`, which documents the real deltas against `decoder`'s
Makefile).
## Boundary rule
diff --git a/.shared-templates/docs/coverage-matrix.md b/.shared-templates/docs/coverage-matrix.md
index ed283de1f..d33414b69 100644
--- a/.shared-templates/docs/coverage-matrix.md
+++ b/.shared-templates/docs/coverage-matrix.md
@@ -8,8 +8,8 @@ repo's threshold, update both the CI file and this table in the same PR.**
| Repo | Threshold | Mechanism |
|---|---|---|
-| `rho` | 65% | inline `bc` check in `ci.yml` |
-| `flux` | 60% | inline `bc` check in `ci.yml` |
+| `decoder` | 65% | inline `bc` check in `ci.yml` |
+| `mux` | 60% | inline `bc` check in `ci.yml` |
| `graycode-skills` | n/a | no Go/Python test suite (skill/content registry) |
## Why thresholds differ per repo
diff --git a/.shared-templates/scripts/check-ecosystem-boundaries.sh.tmpl b/.shared-templates/scripts/check-ecosystem-boundaries.sh.tmpl
index 2dc77a715..5beca785f 100644
--- a/.shared-templates/scripts/check-ecosystem-boundaries.sh.tmpl
+++ b/.shared-templates/scripts/check-ecosystem-boundaries.sh.tmpl
@@ -12,29 +12,29 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"
# =============================================================================
-# VARIANT 1 — Support engine (flux, harrier, shrike, swift, kestrel, merlin).
+# VARIANT 1 — Support engine (mux, harrier, shrike, swift, kestrel, merlin).
# Engines are peers: they may depend on falcon,
-# but never on rho/internal/* or another engine.
+# but never on decoder/internal/* or another engine.
# =============================================================================
-FORBIDDEN_RHO='github\.com/GrayCodeAI/rho/internal/'
+FORBIDDEN_DECODER='github\.com/GrayCodeAI/decoder/internal/'
FORBIDDEN_ENGINES='github\.com/GrayCodeAI/(harrier|shrike|swift|kestrel|merlin)(/|")'
# ^ list every OTHER engine here — never include yourself.
exit_code=0
if command -v rg >/dev/null 2>&1; then
- violations="$(rg -n "$FORBIDDEN_RHO" --glob '*.go' . || true)"
+ violations="$(rg -n "$FORBIDDEN_DECODER" --glob '*.go' . || true)"
engine_violations="$(rg -n "$FORBIDDEN_ENGINES" --glob '*.go' . || true)"
else
- violations="$(grep -rn --include='*.go' -E "$FORBIDDEN_RHO" . || true)"
+ violations="$(grep -rn --include='*.go' -E "$FORBIDDEN_DECODER" . || true)"
engine_violations="$(grep -rn --include='*.go' -E "$FORBIDDEN_ENGINES" . || true)"
fi
if [[ -n "${violations}" ]]; then
- echo "forbidden Rho imports found:"
+ echo "forbidden Decoder imports found:"
echo "${violations}"
echo
- echo "support repos must use local contracts, not rho/internal"
+ echo "support repos must use local contracts, not decoder/internal"
exit_code=1
fi
@@ -70,19 +70,19 @@ echo "ecosystem boundary guard passed"
# echo "forbidden graycode-eco imports found in {{OWN_MODULE}}:"
# echo "${violations}"
# echo
-# echo "{{OWN_MODULE}} is a foundation repo — it must not depend on rho, engines, or any other GrayCodeAI/* package"
+# echo "{{OWN_MODULE}} is a foundation repo — it must not depend on decoder, engines, or any other GrayCodeAI/* package"
# exit 1
# fi
#
# echo "ecosystem boundary guard passed"
# =============================================================================
-# VARIANT 3 — SDK / skills consumer (graycode-skills). Consumers may depend on rho's public surfaces
-# only — never on a support engine directly, and never on rho/internal.
+# VARIANT 3 — SDK / skills consumer (graycode-skills). Consumers may depend on decoder's public surfaces
+# only — never on a support engine directly, and never on decoder/internal.
# =============================================================================
#
-# FORBIDDEN_ENGINES='github\.com/GrayCodeAI/(flux|harrier|shrike|swift|kestrel|merlin)(/|")'
-# FORBIDDEN_INTERNAL='github\.com/GrayCodeAI/rho/internal'
+# FORBIDDEN_ENGINES='github\.com/GrayCodeAI/(mux|harrier|shrike|swift|kestrel|merlin)(/|")'
+# FORBIDDEN_INTERNAL='github\.com/GrayCodeAI/decoder/internal'
#
# (same rg/grep + report pattern as Variant 1, naming "SDKs/skills must go
-# through rho's public API, not engines directly" as the violation message)
+# through decoder's public API, not engines directly" as the violation message)
diff --git a/.shared-templates/scripts/sync-external.sh b/.shared-templates/scripts/sync-external.sh
index a911365bf..f22a0ce6b 100755
--- a/.shared-templates/scripts/sync-external.sh
+++ b/.shared-templates/scripts/sync-external.sh
@@ -5,7 +5,7 @@
# the submodule checkout), this makes no changes — it only reports.
#
# Typical drift: you commit changes in ../shrike, but forget `make
-# sync-submodules` + a commit in rho to bump the external/tok pin. This
+# sync-submodules` + a commit in decoder to bump the external/tok pin. This
# script catches that before it becomes a stale-dependency surprise in CI.
set -euo pipefail
@@ -62,7 +62,7 @@ done < <(git config -f .gitmodules --get-regexp path | awk '{print $2}')
if [[ $exit_code -ne 0 ]]; then
echo
- echo "drift detected — run 'make sync-submodules' in rho after confirming the sibling repos are what you expect, then commit the updated external/ pins"
+ echo "drift detected — run 'make sync-submodules' in decoder after confirming the sibling repos are what you expect, then commit the updated external/ pins"
fi
exit $exit_code
diff --git a/.shared-templates/workflows/compatibility-test.yml.tmpl b/.shared-templates/workflows/compatibility-test.yml.tmpl
index d53d0abbd..6df35c95b 100644
--- a/.shared-templates/workflows/compatibility-test.yml.tmpl
+++ b/.shared-templates/workflows/compatibility-test.yml.tmpl
@@ -1,7 +1,7 @@
-# Cross-repo compatibility matrix check, referenced from rho/docs/compatibility.md.
+# Cross-repo compatibility matrix check, referenced from decoder/docs/compatibility.md.
# Source of truth: .shared-templates/workflows/compatibility-test.yml.tmpl
#
-# Lives (and runs) in rho only — rho owns testdata/compatibility-matrix.json
+# Lives (and runs) in decoder only — decoder owns testdata/compatibility-matrix.json
# and the `compat-test`/`compat-check` Make targets that validate it. Other
# repos don't need a copy of this workflow; they're read as data, not as a
# workflow trigger.
@@ -36,7 +36,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
- go-version: "1.26.5"
+ go-version: "1.27.2"
cache: true
- name: Structural validation (schema + version pins)
run: make compat-check
diff --git a/.shared-templates/workflows/go-ci.yml.tmpl b/.shared-templates/workflows/go-ci.yml.tmpl
index f36742492..002e6b934 100644
--- a/.shared-templates/workflows/go-ci.yml.tmpl
+++ b/.shared-templates/workflows/go-ci.yml.tmpl
@@ -37,7 +37,7 @@ concurrency:
cancel-in-progress: true
env:
- GO_VERSION: "1.26.5"
+ GO_VERSION: "1.27.2"
GOPROXY: "https://proxy.golang.org,direct"
GOPRIVATE: "github.com/GrayCodeAI/*"
GONOSUMDB: "github.com/GrayCodeAI/*"
diff --git a/.shared-templates/workflows/go-release.yml.tmpl b/.shared-templates/workflows/go-release.yml.tmpl
index d97a444b6..2e84b29e3 100644
--- a/.shared-templates/workflows/go-release.yml.tmpl
+++ b/.shared-templates/workflows/go-release.yml.tmpl
@@ -2,7 +2,7 @@
# A maintainer pushes a v tag after the release PR (VERSION +
# CHANGELOG) merges; protect v* tags with a repository ruleset.
# Source of truth: .shared-templates/workflows/go-release.yml.tmpl
-# (rho's .github/workflows/release.yml is the reference rendering).
+# (decoder's .github/workflows/release.yml is the reference rendering).
name: release
@@ -35,14 +35,14 @@ jobs:
# Refuses a tag that disagrees with VERSION or has no CHANGELOG section,
# and extracts that section as the release notes. Copy
- # scripts/check-release-tag.sh from rho.
+ # scripts/check-release-tag.sh from decoder.
- name: Check tag against VERSION and CHANGELOG
run: bash ./scripts/check-release-tag.sh --notes "${RUNNER_TEMP}/release-notes.md" "${GITHUB_REF_NAME}"
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
- go-version: "1.26.6"
+ go-version: "1.27.2"
cache: true
# GoReleaser shells out to syft for the `sboms:` stanza; the runner image
diff --git a/.shared-templates/workflows/python-ci.yml.tmpl b/.shared-templates/workflows/python-ci.yml.tmpl
index ead5a693b..2af8c8254 100644
--- a/.shared-templates/workflows/python-ci.yml.tmpl
+++ b/.shared-templates/workflows/python-ci.yml.tmpl
@@ -2,7 +2,7 @@
# Source of truth: .shared-templates/workflows/python-ci.yml.tmpl
#
# Placeholders rendered per repo:
-# {{PACKAGE}} — importable package name for --cov (e.g. rho)
+# {{PACKAGE}} — importable package name for --cov (e.g. decoder)
# {{THRESHOLD}} — minimum coverage percentage, kept in sync with
# docs/coverage-matrix.md
diff --git a/AGENTS.md b/AGENTS.md
index ead53ba9b..6258d9016 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,15 +1,15 @@
---
-description: Extending rho — how to write AGENTS.md files, custom specialists, skills, hooks, MCP servers, and plugins.
+description: Extending decoder — how to write AGENTS.md files, custom specialists, skills, hooks, MCP servers, and plugins.
globs: "*.go, *.js, *.md, *.json, *.toml, *.yaml, *.yml"
alwaysApply: false
---
-# Extending rho
+# Extending decoder
-rho is an open-source code intelligence platform. It lives in the `graycode-eco`
-workspace alongside the ecosystem repos that power it (`flux`,
+decoder is an open-source code intelligence platform. It lives in the `graycode-eco`
+workspace alongside the ecosystem repos that power it (`mux`,
`shrike`, `harrier`, `swift`, `kestrel`, `merlin`). This document describes how to extend
-rho with custom tools, skills, hooks, and integrations.
+decoder with custom tools, skills, hooks, and integrations.
## Development workflow
@@ -17,7 +17,7 @@ When starting any new work (feature, fix, refactor, chore), always create a feat
## 1. Drop a project `AGENTS.md`
-When rho starts in a directory, it looks for project-level instructions and injects them into the system prompt. The lookup walks from your current working directory **up to the nearest git root** and reads the first matching file at each level — general rules at the repo root, more specific rules in sub-trees. Files are labeled with their directory in the prompt (e.g. `## Project guidelines (services/api/AGENTS.md)`).
+When decoder starts in a directory, it looks for project-level instructions and injects them into the system prompt. The lookup walks from your current working directory **up to the nearest git root** and reads the first matching file at each level — general rules at the repo root, more specific rules in sub-trees. Files are labeled with their directory in the prompt (e.g. `## Project guidelines (services/api/AGENTS.md)`).
Accepted file names, in priority order at each level:
@@ -29,7 +29,7 @@ Accepted file names, in priority order at each level:
Matching is **case-insensitive** on the basename, so `AGENTS.md`, `Agents.md`, and `agents.md` resolve to the same file on Windows and macOS. The git-tracked filename in this repo is `AGENTS.md` — keep that on case-sensitive filesystems (Linux, the WSL filesystem, or a CI runner) to match what the loader looks for.
-Both files use the same format. YAML frontmatter is optional; the markdown body is loaded as instructions for the agent. rho reads the file once at session start, so changes take effect on the next launch — not mid-session.
+Both files use the same format. YAML frontmatter is optional; the markdown body is loaded as instructions for the agent. decoder reads the file once at session start, so changes take effect on the next launch — not mid-session.
```markdown
# Project conventions for
@@ -42,26 +42,26 @@ Both files use the same format. YAML frontmatter is optional; the markdown body
Tips:
-- Keep each file under ~8 KiB. rho caps the **total** across all matched files at 32 KiB; everything past the cap is dropped.
+- Keep each file under ~8 KiB. decoder caps the **total** across all matched files at 32 KiB; everything past the cap is dropped.
- Re-state rules in the imperative voice: "Run `make lint`", not "you should consider running the linter".
- Don't put secrets, model IDs, or environment-specific paths in `AGENTS.md`. Use config files for those.
-- In a monorepo, drop a narrower `AGENTS.md` in each sub-tree (e.g. `services/api/AGENTS.md`). rho picks those up automatically when you launch from inside the sub-tree.
+- In a monorepo, drop a narrower `AGENTS.md` in each sub-tree (e.g. `services/api/AGENTS.md`). decoder picks those up automatically when you launch from inside the sub-tree.
- A YAML frontmatter block (`---\n...\n---`) at the top is preserved verbatim in the injected prompt but is not parsed for `globs:` or `alwaysApply:` scoping today — keep the body self-contained.
### Personal guidelines, across every project
-For preferences that follow *you*, not a specific repo (tone, tooling habits, workflow), drop a `ZERO.md` in your user config directory: `~/.rho/ZERO.md` on Linux/macOS, `%AppData%\rho\ZERO.md` on Windows — the same directory as config files and your personal specialists. Same format and 8 KiB cap as the project files above, and the same case-insensitive basename match.
+For preferences that follow *you*, not a specific repo (tone, tooling habits, workflow), drop a `ZERO.md` in your user config directory: `~/.decoder/ZERO.md` on Linux/macOS, `%AppData%\decoder\ZERO.md` on Windows — the same directory as config files and your personal specialists. Same format and 8 KiB cap as the project files above, and the same case-insensitive basename match.
This file is injected as its own `## User guidelines` section, before the project's `AGENTS.md`/`ZERO.md`, and is labeled as personal preference in the prompt: project guidelines are the later, more specific instruction and take precedence over it when the two conflict.
## 2. Custom specialists
-Specialists are rho's sub-agents. Three scopes, in priority order:
+Specialists are decoder's sub-agents. Three scopes, in priority order:
| Scope | Path | Shared? |
| --- | --- | --- |
-| Built-in | compiled into rho | yes |
-| User | `~/.rho/specialists/*.md` | no — your machine only |
+| Built-in | compiled into decoder | yes |
+| User | `~/.decoder/specialists/*.md` | no — your machine only |
| Project | `./.zero/specialists/*.md` | yes — the repo team |
Project overrides user overrides built-in when names collide.
@@ -89,33 +89,33 @@ Reply with one JSON object per finding: `{"file", "line", "severity", "message",
CLI management:
```bash
-rho specialist list
-rho specialist show api-reviewer
-rho specialist create api-reviewer \
+decoder specialist list
+decoder specialist show api-reviewer
+decoder specialist create api-reviewer \
--project \
--description "Reviews API changes" \
--tools read-only,plan \
--prompt "$(cat api-reviewer.md)"
-rho specialist edit api-reviewer --project
-rho specialist delete api-reviewer --project
-rho specialist path # prints the resolved specialists directory
+decoder specialist edit api-reviewer --project
+decoder specialist delete api-reviewer --project
+decoder specialist path # prints the resolved specialists directory
```
## 3. Skills
-rho ships **no bundled skills** by default. Skills are markdown instruction
+decoder ships **no bundled skills** by default. Skills are markdown instruction
files that extend agent capabilities, sourced from the separate
`GrayCodeAI/graycode-skills` repo and installed on demand:
```bash
-rho skills search # find skills in graycode-skills
-rho skills install [skill-name] # install after user approval
-rho skills list # list installed skills
-rho skills remove
+decoder skills search # find skills in graycode-skills
+decoder skills install [skill-name] # install after user approval
+decoder skills list # list installed skills
+decoder skills remove
```
Installed skills live in user or project scope:
-- User-scoped: `~/.rho/skills/`
+- User-scoped: `~/.decoder/skills/`
- Project-scoped: `./.zero/skills/` or `./skills/`
A skill manifest:
@@ -144,56 +144,56 @@ Hooks allow custom commands to run at specific lifecycle points:
- `sessionEnd` — runs at session teardown
```bash
-rho hook add beforeReview --command "lint-check"
-rho hook remove beforeReview
-rho hook list
+decoder hook add beforeReview --command "lint-check"
+decoder hook remove beforeReview
+decoder hook list
```
## 5. MCP integration
-MCP (Model Context Protocol) servers can expose tools to rho:
+MCP (Model Context Protocol) servers can expose tools to decoder:
```bash
-rho mcp add --name server --url http://localhost:8080
-rho mcp remove server
-rho mcp list
+decoder mcp add --name server --url http://localhost:8080
+decoder mcp remove server
+decoder mcp list
```
## 6. Plugins
-Plugins extend rho with custom tools and capabilities:
+Plugins extend decoder with custom tools and capabilities:
```bash
-rho plugin add --name my-plugin --path ./my-plugin
-rho plugin remove my-plugin
-rho plugin list
+decoder plugin add --name my-plugin --path ./my-plugin
+decoder plugin remove my-plugin
+decoder plugin list
```
## 7. Verification
-rho includes a self-verification system to validate local changes before contributing:
+decoder includes a self-verification system to validate local changes before contributing:
```bash
-rho verify
-rho verify --fix
+decoder verify
+decoder verify --fix
```
## Development
```bash
make lint
-rho verify
+decoder verify
```
### Architecture note: cross-repo contracts
-Cross-repo severity and finding contracts now live in rho's `internal/contracts` (vendored from the removed `github.com/GrayCodeAI/eagle` module) — extensions and support repos must vendor the needed DTOs instead of Rho internals until a published contracts module exists.
+Cross-repo severity and finding contracts now live in decoder's `internal/contracts` (vendored from the removed `github.com/GrayCodeAI/eagle` module) — extensions and support repos must vendor the needed DTOs instead of Decoder internals until a published contracts module exists.
### Architecture note: provider ownership
Implement provider protocols, adapters, catalog metadata, credential mappings, and
-provider contract tests in `../flux` (the flux engine's repo) first. Rho consumes providers only
-through Flux's stable engine facade; Rho changes should be limited to host UX
+provider contract tests in `../mux` (the mux engine's repo) first. Decoder consumes providers only
+through Mux's stable engine facade; Decoder changes should be limited to host UX
and facade integration. Concentrate AI is a pay-as-you-go gateway implemented
with its native Responses API (`/v1/responses`) under the
`concentrate-payg` deployment.
@@ -201,7 +201,7 @@ with its native Responses API (`/v1/responses`) under the
## GitNexus — Code Intelligence
-This project is indexed by GitNexus as **rho** (97743 symbols, 322940 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
+This project is indexed by GitNexus as **decoder** (97743 symbols, 322940 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
> Index stale? Run `node .gitnexus/run.cjs analyze` from the project root — it auto-selects an available runner. No `.gitnexus/run.cjs` yet? `npx gitnexus analyze` (npm 11 crash → `npm i -g gitnexus`; #1939).
@@ -225,10 +225,10 @@ This project is indexed by GitNexus as **rho** (97743 symbols, 322940 relationsh
| Resource | Use for |
|----------|---------|
-| `gitnexus://repo/rho/context` | Codebase overview, check index freshness |
-| `gitnexus://repo/rho/clusters` | All functional areas |
-| `gitnexus://repo/rho/processes` | All execution flows |
-| `gitnexus://repo/rho/process/{name}` | Step-by-step execution trace |
+| `gitnexus://repo/decoder/context` | Codebase overview, check index freshness |
+| `gitnexus://repo/decoder/clusters` | All functional areas |
+| `gitnexus://repo/decoder/processes` | All execution flows |
+| `gitnexus://repo/decoder/process/{name}` | Step-by-step execution trace |
## CLI
@@ -245,10 +245,10 @@ This project is indexed by GitNexus as **rho** (97743 symbols, 322940 relationsh
### Workspace workflow (sibling repos)
-rho depends on ecosystem repos (`flux`, etc.) as independent sibling repos in the `graycode-eco` workspace. Rho's `go.work` lists them as `../`, so local changes in any sibling are automatically picked up by rho. Each sibling is its own git repo, versioned and released independently.
+decoder depends on ecosystem repos (`mux`, etc.) as independent sibling repos in the `graycode-eco` workspace. Decoder's `go.work` lists them as `../`, so local changes in any sibling are automatically picked up by decoder. Each sibling is its own git repo, versioned and released independently.
-1. Edit + test in `../` — run its tests, run `make test` in rho
+1. Edit + test in `../` — run its tests, run `make test` in decoder
2. Push from the sibling: `git push origin `
3. Open a PR in the sibling repo → merge to `main`
-4. Ensure rho's `go.mod` pins a version that resolves to (or is an ancestor of) the sibling's `main` — run `make sync` to verify parity
-5. No pointer commits: rho resolves the sibling via `go.work` for local dev and via the pinned `go.mod` version for standalone/module-mode builds (Docker, released consumers)
+4. Ensure decoder's `go.mod` pins a version that resolves to (or is an ancestor of) the sibling's `main` — run `make sync` to verify parity
+5. No pointer commits: decoder resolves the sibling via `go.work` for local dev and via the pinned `go.mod` version for standalone/module-mode builds (Docker, released consumers)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7c4578dfd..f489f64b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,41 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Releases are cut by hand from a release PR; see [docs/RELEASING.md](docs/RELEASING.md).
> **Version history.** The next release, **v0.3.0**, is the first published
-> under the `rho` name and module path `github.com/GrayCodeAI/rho`. Sections
+> under the `decoder` name and module path `github.com/GrayCodeAI/decoder`. Sections
> labelled `hawk` below are kept as the historical record of the project
> before the rename: `hawk 0.2.0` is the `v0.2.0` tag, which (like `v0.1.0`
> and `v0.1.1`) was built from the `github.com/GrayCodeAI/hawk` module and
> ships `hawk_*` 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
+> the time (for example Mux was called eyrie, and several companion repos
> have since been retired).
## [Unreleased]
+### Changed
+
+- The module, CLI, environment variables, state paths, integrations and packaging now use Decoder, backed by the renamed Mux module; Go 1.27.2 is required.
+
### Added
- **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 and `make release-check`, refuses a tag that is not `v` + `VERSION` or has no `CHANGELOG.md` section; `make release-snapshot` builds 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.
### Changed
-- **Version 0.3.0**: `VERSION` is `0.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 matrix `stable` entry pins rho 0.3.0 with flux 0.0.1.
+- **Version 0.3.0**: `VERSION` is `0.3.0`, the first release under the decoder name (the Go proxy already holds the hawk-era v0.1.0–v0.2.0), and the compatibility matrix `stable` entry pins decoder 0.3.0 with mux 0.0.1.
- **Release workflow can publish**: it installs syft for the SBOMs, signs `checksums.txt` inside GoReleaser with cosign keyless signing (`checksums.txt.sigstore.json`), re-verifies the published signature, takes the release notes from this file, builds with `GOWORK=off` and `-trimpath`, and drops the unused `packages: write` permission and sibling checkout.
- **Binary size budget enforced**: `make size-check` fails above `SIZE_LIMIT_MB` (70 MiB; linux/amd64 is 59.6 MiB today) and CI runs it instead of only warning above 98 MB.
- **`make release` no longer publishes** from a workstation; releases come only from the tag-triggered workflow.
- **npm scaffolding kept unpublished**: packages are marked `"private": true` with the correct MIT license, and assembly stamps the meta package and its `optionalDependencies` and 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
+- **Dependency renamed eyrie → mux**: decoder now depends on
+ `github.com/GrayCodeAI/mux v0.0.1` (the provider runtime was renamed).
+ All imports, env vars (`EYRIE_CONFIG_DIR` → `MUX_CONFIG_DIR`,
+ `EYRIE_MODEL_CATALOG_PATH` → `MUX_MODEL_CATALOG_PATH`), boundary-guard
scripts, ecosystem manifest entries, docs, and internal identifiers were
renamed to match. User state paths move from `~/.../eyrie/provider.json`
- to `~/.../flux/provider.json`.
+ to `~/.../mux/provider.json`.
- **Makefile lint pin matches CI**: `make lint`/`lint-fix`/`setup` install `golangci-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 to `docs/plans/`.
### Security
-- **`install.sh` verifies releases fail-closed**: with cosign installed it verifies `checksums.txt.sigstore.json` against the exact release-workflow identity and aborts on a missing or invalid signature; without cosign it warns and reports the signature as not verified, and `RHO_REQUIRE_COSIGN=1` makes 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.sh` with cosign required, instead of building an unverified `curl | tar` source tarball; `rho-version` accepts `0.3.0`, `v0.3.0` or `latest`, and Go is no longer needed.
-- **systemd unit**: runs as a dedicated `rho` user with state in `StateDirectory`/`CacheDirectory` (the old `%h` paths were hidden by `ProtectHome=true`), reads the daemon API key from an `EnvironmentFile` instead of the command line, and links the troubleshooting guide instead of a dead domain.
+- **`install.sh` verifies releases fail-closed**: with cosign installed it verifies `checksums.txt.sigstore.json` against the exact release-workflow identity and aborts on a missing or invalid signature; without cosign it warns and reports the signature as not verified, and `DECODER_REQUIRE_COSIGN=1` makes 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.sh` with cosign required, instead of building an unverified `curl | tar` source tarball; `decoder-version` accepts `0.3.0`, `v0.3.0` or `latest`, and Go is no longer needed.
+- **systemd unit**: runs as a dedicated `decoder` user with state in `StateDirectory`/`CacheDirectory` (the old `%h` paths were hidden by `ProtectHome=true`), reads the daemon API key from an `EnvironmentFile` instead 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.VerifyCommandSucceeds` ran caller-supplied strings through `sh -c`, bypassing the permission stack; it had zero callers and is deleted. `SelfHealer.RunScript` no longer shell-evaluates the script path (double evaluation) and invokes it directly via `/bin/sh`.
@@ -54,22 +58,22 @@ Releases are cut by hand from a release PR; see [docs/RELEASING.md](docs/RELEASI
- **Homebrew publisher and install instructions**: the `brews` stanza (deprecated in GoReleaser v2) targeted a `GrayCodeAI/homebrew-tap` repository and token that do not exist; the README no longer offers Homebrew or npm installs.
- **`flake.nix` and 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 migrate` removed**: the subcommand, its man page entry, and the `MigrateEnvFileCredentials` wrappers are gone, and `rho path` no longer reports legacy `~/.rho/env` / `~/.rho/.env` files. Save keys through `/config`.
-- **BREAKING — settings model/provider migration removed**: `LoadSettings` no longer moves `model`/`provider` from `settings.json` into Flux's `provider.json`, and `SetActiveSelection` is deleted. Stale `model`/`provider` values left in `settings.json` are now ignored on load (Flux's selection wins; `--settings` overrides 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 gateway `CatalogMaintenance` interface. `rho path` still fails when `provider.json` holds secrets; remove those fields manually.
-- **BREAKING — `shared/types` guards removed**: `scripts/check-shared-types-imports.sh`, the `contracts-guard` make target, its lefthook and CI steps, and the matching testaudit checks are deleted because the package no longer exists. The ecosystem boundary guards still block `rho/internal` imports.
+- **BREAKING — `decoder credentials migrate` removed**: the subcommand, its man page entry, and the `MigrateEnvFileCredentials` wrappers are gone, and `decoder path` no longer reports legacy `~/.decoder/env` / `~/.decoder/.env` files. Save keys through `/config`.
+- **BREAKING — settings model/provider migration removed**: `LoadSettings` no longer moves `model`/`provider` from `settings.json` into Mux's `provider.json`, and `SetActiveSelection` is deleted. Stale `model`/`provider` values left in `settings.json` are now ignored on load (Mux's selection wins; `--settings` overrides 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 gateway `CatalogMaintenance` interface. `decoder path` still fails when `provider.json` holds secrets; remove those fields manually.
+- **BREAKING — `shared/types` guards removed**: `scripts/check-shared-types-imports.sh`, the `contracts-guard` make target, its lefthook and CI steps, and the matching testaudit checks are deleted because the package no longer exists. The ecosystem boundary guards still block `decoder/internal` imports.
## [hawk 0.2.0] — 2026-07-13
### Changed
-- **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
+- **Decoder/Mux production boundary completed**: Decoder owns the product face,
+ sessions, tools, permissions, and public schemas while Mux v0.2.1 (then
+ named eyrie; mux itself has only tagged v0.0.1) owns
credentials, catalog resolution, provider transport, resilience, and usage
- telemetry behind the stable `flux/engine` facade.
+ telemetry behind the stable `mux/engine` facade.
- **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.
+ accounting, and production Mux 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.
@@ -80,18 +84,18 @@ Releases are cut by hand from a release PR; see [docs/RELEASING.md](docs/RELEASI
- **Permission system unified into two independent axes**: the old `PermissionMode` (`default`/`acceptEdits`/`bypassPermissions`/`dontAsk`/`plan`) is removed. `/autonomy` now controls the 5-tier trust ladder (`Always Ask`/`Scout`/`Builder`/`Operator`/`Autonomous`, bare `/autonomy` opens a picker), and `/spec` controls an independent, orthogonal spec-driven workflow gate (`Specify → Plan → Tasks → ApproveImplementation`, bare `/spec` opens 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's `CheckTool` never consulted, meaning autonomy tier changes may not have reliably taken effect. Now both read/write the same `PermissionEngine.Autonomy` field the check logic uses.
- **`--permission-mode` CLI flag removed**; `--dangerously-skip-permissions` unchanged (now maps to the Autonomous tier). New `--dry-run` flag added as an unconditional kill switch (deny every tool call, regardless of tier or spec stage) — replaces `dontAsk`'s hard-lockout role.
-- **Version re-baselined to `0.1.0`** across `cmd/rho/main.go`, `cmd/daemon.go`,
- `flake.nix`, `.github/workflows/release.yml`, and the `update`/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/client` usage restricted to internal adapters and guarded in CI.
-- **`shared/types` removed**: Rho no longer ships the old shared type path, and local boundary checks now block any attempt to reintroduce it.
+- **Version re-baselined to `0.1.0`** across `cmd/decoder/main.go`, `cmd/daemon.go`,
+ `flake.nix`, `.github/workflows/release.yml`, and the `update`/daemon test suites, aligning decoder
+ with the rest of the GrayCodeAI ecosystem (`mux`, `shrike`, `harrier`, `kestrel`, `merlin`).
+- **Architecture boundary hardening**: Decoder now owns runtime request/response DTOs, transport config/provider seams, and review/verification product-boundary contracts, with `mux/client` usage restricted to internal adapters and guarded in CI.
+- **`shared/types` removed**: Decoder no longer ships the old shared type path, and local boundary checks now block any attempt to reintroduce it.
### Added
-- **Spec-driven workflow (`/spec`)**: independent, orthogonal permission gate that walks the model through `Specify → Plan → Tasks`, writing real `spec.md`/`plan.md`/`tasks.md` files to `.rho/specs//`, and requires explicit `ApproveImplementation` approval (always prompts, at any trust tier) before Write/Edit/Bash unlock. The approval prompt shows the actual written content, not a blind yes/no.
+- **Spec-driven workflow (`/spec`)**: independent, orthogonal permission gate that walks the model through `Specify → Plan → Tasks`, writing real `spec.md`/`plan.md`/`tasks.md` files to `.decoder/specs//`, and requires explicit `ApproveImplementation` approval (always prompts, at any trust tier) before Write/Edit/Bash unlock. The approval prompt shows the actual written content, not a blind yes/no.
- **`/autonomy` and `/spec` picker overlays**: bare `/autonomy` or `/spec` opens 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 on `AI!` (do-now) and `AI?` (answer) code comments. Off by default.
-- **GitHub Action** (`.github/actions/rho`): interactive mode on `@rho` mentions, 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.
+- **GitHub Action** (`.github/actions/decoder`): interactive mode on `@decoder` mentions, 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 decoder 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).
@@ -113,7 +117,7 @@ Releases are cut by hand from a release PR; see [docs/RELEASING.md](docs/RELEASI
### Added — Round 2 ecosystem improvements (2026-06-01)
- **Cavecrew personas** (`internal/multiagent/agents`): three new
- built-in personas built into GrayCode Rho
+ built-in personas built into GrayCode Decoder
(`cavecrew-investigator`, `cavecrew-builder`, `cavecrew-reviewer`).
Each enforces a strict output format so downstream agents can parse
outputs mechanically:
@@ -152,7 +156,7 @@ Releases are cut by hand from a release PR; see [docs/RELEASING.md](docs/RELEASI
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's `internal/tracking.Tracker` (shrike tracks globally, rho tracks
+ shrike's `internal/tracking.Tracker` (shrike tracks globally, decoder tracks
per-session).
### Added — Production Hardening (top-50 OSS parity)
@@ -187,16 +191,16 @@ Releases are cut by hand from a release PR; see [docs/RELEASING.md](docs/RELEASI
## [hawk 0.4.0, untagged] — 2026-05-05
### Added
-- **Exec Subcommand**: `rho exec "prompt"` — full engine non-interactive mode with `--output-format json`, `--auto` autonomy levels, `--worktree` isolation, `--agent` personas, `--session-id` resume, 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-run` for planning only
-- **Session Search**: `rho search "query"` — full-text search across all saved sessions with `--json` output
-- **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` + `/snapshot` slash command. Auto-snapshots on every Write/Edit tool call
+- **Exec Subcommand**: `decoder exec "prompt"` — full engine non-interactive mode with `--output-format json`, `--auto` autonomy levels, `--worktree` isolation, `--agent` personas, `--session-id` resume, stdin piping
+- **Daemon Server**: `decoder daemon start/stop/status` — background HTTP server with JSON + SSE streaming on `/v1/chat`, `/v1/health`, `/v1/sessions`
+- **Mission Mode**: `decoder mission "prompt"` — multi-agent orchestration decomposing work into parallel features executed in isolated git worktrees. `--dry-run` for planning only
+- **Session Search**: `decoder search "query"` — full-text search across all saved sessions with `--json` output
+- **Custom Agents**: `decoder agent list/create/show/remove` — markdown persona definitions in `~/.decoder/agents/` with YAML frontmatter (name, description, model)
+- **Snapshot System**: Shadow git tracking of every file change. `decoder snapshot list/restore/diff` + `/snapshot` slash 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 via `rho search`
+- **Session Persistence for exec**: All exec runs saved to `~/.decoder/sessions/` and searchable via `decoder search`
### Packages Added
- `mission/` — Multi-agent orchestration with worktree-based parallel workers
@@ -271,5 +275,5 @@ Releases are cut by hand from a release PR; see [docs/RELEASING.md](docs/RELEASI
### Added
- Project scaffold with cobra CLI and Bubbletea TUI
- Interactive chat REPL with textarea input, spinner, lipgloss styling
-- flux wired as LLM provider dependency
+- mux wired as LLM provider dependency
- GitHub Actions CI
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index e4bb52a8b..c9fd22d4e 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -2,7 +2,7 @@
## Our pledge
-We — the maintainers and contributors of the rho project — pledge to
+We — the maintainers and contributors of the decoder project — pledge to
make participation in our community a harassment-free experience for everyone,
regardless of age, body size, visible or invisible disability, ethnicity, sex
characteristics, gender identity and expression, level of experience,
@@ -45,7 +45,7 @@ offensive, or harmful.
Instances of abusive, harassing, or otherwise unacceptable behaviour may be
reported to the maintainers via the contact in `SECURITY.md` or by opening a
confidential GitHub Security Advisory at
-. All
+. All
complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 085d7633a..91c056b74 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,8 +1,8 @@
-# Contributing to rho
+# Contributing to decoder
Thanks for your interest! This guide covers the conventions used across the
GrayCodeAI repositories. The shared standards (versioning, release tooling, repo layout)
-are defined in .
+are defined in .
## Quick start
@@ -141,8 +141,8 @@ Before requesting review:
## Reporting bugs
-Open an issue using the bug-report template. Include the `rho`
-version (`rho --version` for binaries, `rho.Version` for
+Open an issue using the bug-report template. Include the `decoder`
+version (`decoder --version` for binaries, `decoder.Version` for
libraries — see this repo's `VERSION` file), reproduction steps, expected
behaviour, and actual behaviour.
diff --git a/Makefile b/Makefile
index 266adec94..6ae6c888c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,16 @@
# Canonical GrayCodeAI Makefile for Go binary repos.
# Source of truth: .shared-templates/Makefile.binary.tmpl at the eco root.
-# Placeholders rendered per repo: rho, ..
+# Placeholders rendered per repo: decoder, ..
# ---------------------------------------------------------------------------
# Project metadata
# ---------------------------------------------------------------------------
-NAME := rho
-MAIN_PKG := ./cmd/rho
+NAME := decoder
+MAIN_PKG := ./cmd/decoder
# ---------------------------------------------------------------------------
# Versioning — sourced from VERSION file; falls back to git describe.
-# See https://github.com/GrayCodeAI/rho/blob/main/docs/versioning.md.
+# See https://github.com/GrayCodeAI/decoder/blob/main/docs/versioning.md.
# ---------------------------------------------------------------------------
VERSION ?= $(shell v=$$(cat VERSION 2>/dev/null | head -n1 | tr -d '[:space:]'); if [ -n "$$v" ]; then echo "$$v"; else git describe --tags --always --dirty 2>/dev/null || echo "dev"; fi)
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "none")
@@ -35,7 +35,7 @@ GOVULNCHECK := $(GOBIN_DIR)/govulncheck
# ---------------------------------------------------------------------------
# Phony declarations (alphabetical).
# ---------------------------------------------------------------------------
-.PHONY: all bench boundaries build check-replace ci clean ecosystem-guard feature-boundaries-guard flux-client-guard flux-engine-guard manifest-guard peer-guard internal-layers-guard package-boundaries-guard release-parity cover cover-new fmt help install lint lint-fix \
+.PHONY: all bench boundaries build check-replace ci clean ecosystem-guard feature-boundaries-guard mux-client-guard mux-engine-guard manifest-guard peer-guard internal-layers-guard package-boundaries-guard release-parity cover cover-new fmt help install lint lint-fix \
release release-check release-snapshot security setup smoke path sync test test-10x test-live test-new test-race tidy version vet api-docs api-validate workspace
check-replace: ## Fail if go.mod has local replace directives (run before tagging)
@@ -132,19 +132,19 @@ fmt-check: ## Verify formatting without rewriting files (CI-safe).
vet: ## Run go vet.
go vet ./...
-ecosystem-guard: ## Fail if external ecosystem repos import rho/internal.
+ecosystem-guard: ## Fail if external ecosystem repos import decoder/internal.
bash ./scripts/check-ecosystem-boundaries.sh
-flux-client-guard: ## Fail on any production flux/client import.
- bash ./scripts/check-flux-client-imports.sh
+mux-client-guard: ## Fail on any production mux/client import.
+ bash ./scripts/check-mux-client-imports.sh
-flux-engine-guard: ## Require all production Flux imports to use the stable engine facade.
- bash ./scripts/check-flux-engine-boundary.sh
+mux-engine-guard: ## Require all production Mux imports to use the stable engine facade.
+ bash ./scripts/check-mux-engine-boundary.sh
-peer-guard: ## Fail if support engines import each other instead of depending only on Rho contracts.
+peer-guard: ## Fail if support engines import each other instead of depending only on Decoder contracts.
bash ./scripts/check-support-repo-coupling.sh
-internal-layers-guard: ## Enforce one-way dependencies across stable Rho internal layers.
+internal-layers-guard: ## Enforce one-way dependencies across stable Decoder internal layers.
bash ./scripts/check-internal-layer-imports.sh
package-boundaries-guard: ## Enforce AST/package-graph boundaries with file/line diagnostics.
@@ -153,7 +153,7 @@ package-boundaries-guard: ## Enforce AST/package-graph boundaries with file/line
feature-boundaries-guard: ## Prevent feature packages from importing delivery or sibling features.
bash ./scripts/check-feature-boundaries.sh
-boundaries: manifest-guard check-replace ecosystem-guard feature-boundaries-guard flux-client-guard flux-engine-guard peer-guard internal-layers-guard package-boundaries-guard ## Alias for all boundary guards (matches `make boundaries` in engine repos).
+boundaries: manifest-guard check-replace ecosystem-guard feature-boundaries-guard mux-client-guard mux-engine-guard peer-guard internal-layers-guard package-boundaries-guard ## Alias for all boundary guards (matches `make boundaries` in engine repos).
release-parity: ## Verify every go.mod ecosystem version resolves to a reachable remote commit.
bash ./scripts/check-module-release-parity.sh
@@ -181,7 +181,7 @@ ci: tidy fmt-check vet boundaries lint test-race security api-validate ## Run ev
@echo "All CI checks passed."
smoke: ## Quick build + doctor + ecosystem verification.
- ./scripts/smoke-rho.sh
+ ./scripts/smoke-decoder.sh
path: ## Verify developer path (setup, security, milestone tests).
./scripts/verify-developer-path.sh
@@ -205,7 +205,7 @@ workspace: ## Regenerate the ecosystem root go.work from ecosystem.yaml.
@bash ./scripts/generate-workspace.sh
setup: workspace ## Set up local development environment and development tools.
- @echo "=== Setting up rho development environment ==="
+ @echo "=== Setting up decoder development environment ==="
@echo "✓ go.work generated and synced from ecosystem.yaml"
@echo ""
@echo "=== Environment check ==="
@@ -231,7 +231,7 @@ help: ## Show this help.
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'
# ---------------------------------------------------------------------------
-# Compatibility matrix (rho-specific extension to the canonical template).
+# Compatibility matrix (decoder-specific extension to the canonical template).
# Validates compatibility-matrix.json and reports the resolved versions for
# a chosen matrix entry. Wired into the compatibility-test workflow.
# ---------------------------------------------------------------------------
@@ -243,7 +243,7 @@ compat-test: ## Validate testdata/compatibility-matrix.json and report the 'next
compat-check: ## Strict validation — non-zero exit if any component lacks a version.
@go run ./cmd/compat-test -matrix=next -strict -file=testdata/compatibility-matrix.json
-compat-drift: ## Advisory: report pin drift between Rho and sibling repositories. Never fails.
+compat-drift: ## Advisory: report pin drift between Decoder and sibling repositories. Never fails.
@go run ./cmd/compat-test -check-external -file=testdata/compatibility-matrix.json
.PHONY: hooks sync
diff --git a/README.md b/README.md
index 221bc2d0a..655654c76 100644
--- a/README.md
+++ b/README.md
@@ -5,11 +5,11 @@
-
+
-
-
-
+
+
+
@@ -25,13 +25,13 @@
---
-## Why rho
+## Why decoder
-rho is an AI-powered coding agent that lives in your terminal. It reads your codebase, writes and edits files, runs tests, and manages git — all through natural language. Unlike IDE-bound tools, rho works over SSH and on any machine with a shell.
+decoder is an AI-powered coding agent that lives in your terminal. It reads your codebase, writes and edits files, runs tests, and manages git — all through natural language. Unlike IDE-bound tools, decoder works over SSH and on any machine with a shell.
-**Developer path:** one machine, keychain credentials, local memory. Run `rho path` to check readiness.
+**Developer path:** one machine, keychain credentials, local memory. Run `decoder path` to check readiness.
-- **Model-agnostic** — supports many first-class providers through [flux](https://github.com/GrayCodeAI/flux) (the exact count is dynamic — see `rho --help`), including Anthropic, OpenAI, Gemini, Fireworks AI, Concentrate AI (pay-as-you-go), DeepSeek, and Ollama
+- **Model-agnostic** — supports many first-class providers through [mux](https://github.com/GrayCodeAI/mux) (the exact count is dynamic — see `decoder --help`), including Anthropic, OpenAI, Gemini, Fireworks AI, Concentrate AI (pay-as-you-go), DeepSeek, and Ollama
- **Zero CGO** — single static binary, cross-compiled for linux/darwin/windows on amd64/arm64
- **Privacy-first** — your code never leaves your machine except to the LLM API you choose
- **Runs anywhere** — host execution on any machine with a shell, including over SSH
@@ -39,76 +39,81 @@ rho is an AI-powered coding agent that lives in your terminal. It reads your cod
## Status
-**Rho is in active development.** Contributor source builds are the primary path today while we keep hardening the product in the open. Tagged releases and install assets may exist for validation, but they are not the recommended first path yet.
+**Decoder is in active development.** Contributor source builds are the primary path today while we keep hardening the product in the open. Tagged releases and install assets may exist for validation, but they are not the recommended first path yet.
-Follow [GrayCode](https://github.com/GrayCodeAI) for progress. When Rho is ready to try, we will announce it on [graycodeai.com](https://graycodeai.com/changelog).
+Follow [GrayCode](https://github.com/GrayCodeAI) for progress. When Decoder is ready to try, we will announce it on [graycodeai.com](https://graycodeai.com/changelog).
## Install
Prebuilt installs are **available from v0.3.0**, the first release published
-under the `rho` name. Until v0.3.0 appears on the
-[releases page](https://github.com/GrayCodeAI/rho/releases), build from source
+under the `decoder` name. Until v0.3.0 appears on the
+[releases page](https://github.com/GrayCodeAI/decoder/releases), build from source
(see [Quick Start](#quick-start-contributors--from-source)). The older
`v0.1.0`–`v0.2.0` tags predate the rename: they ship `hawk_*` archives under
-the old module path and cannot be installed as `rho`.
+the old module path and cannot be installed as `decoder`.
From v0.3.0:
```bash
-# Script: installs ~/.rho/bin/rho- and links it as ~/.rho/bin/rho.
+# Script: installs ~/.decoder/bin/decoder- and links it as ~/.decoder/bin/decoder.
# Always checks the archive's SHA-256 against checksums.txt; also verifies the
# cosign signature of checksums.txt when cosign is installed (it says so when
-# it is not). Set RHO_REQUIRE_COSIGN=1 to refuse installing without cosign.
-curl -fsSL https://raw.githubusercontent.com/GrayCodeAI/rho/v0.3.0/install.sh | sh
+# it is not). Set DECODER_REQUIRE_COSIGN=1 to refuse installing without cosign.
+curl -fsSL https://raw.githubusercontent.com/GrayCodeAI/decoder/v0.3.0/install.sh | sh
# Pin a version or choose the install prefix (see: sh install.sh --help)
-curl -fsSL https://raw.githubusercontent.com/GrayCodeAI/rho/v0.3.0/install.sh | sh -s -- --version 0.3.0 --prefix "$HOME/.rho"
+curl -fsSL https://raw.githubusercontent.com/GrayCodeAI/decoder/v0.3.0/install.sh | sh -s -- --version 0.3.0 --prefix "$HOME/.decoder"
-# Go toolchain (Go 1.26+): builds the tagged module from source
-go install github.com/GrayCodeAI/rho/cmd/rho@latest
+# Go toolchain (Go 1.27.2+): builds the tagged module from source
+go install github.com/GrayCodeAI/decoder/cmd/decoder@latest
```
-Each release carries `rho___` archives for
+Each release carries `decoder___` archives for
linux/darwin/windows on amd64/arm64, `checksums.txt`, its cosign signature
bundle `checksums.txt.sigstore.json`, and SPDX SBOMs; the release notes show how
to verify them by hand. Homebrew and npm packages are **not available**: there
is no `graycodeai/tap` tap and nothing is published under `@graycodeai` on npm.
-If `~/.rho/bin` is not on your `PATH`, add it to your shell profile.
+If `~/.decoder/bin` is not on your `PATH`, add it to your shell profile.
Then:
```bash
-rho # interactive REPL (/config on first run: API key + model)
-rho path # verify readiness
+decoder # interactive REPL (/config on first run: API key + model)
+decoder path # verify readiness
```
## Quick Start (contributors — from source)
+This development revision uses `DECODER_*` environment variables, `.decoder`
+state paths, and the `decoder` keychain namespace. Configure credentials and
+migrate any existing settings to these names before using the new binary.
+
+
```bash
-git clone https://github.com/GrayCodeAI/rho && cd rho
+git clone https://github.com/GrayCodeAI/decoder && cd decoder
make setup # generates go.work referencing sibling support repos in the graycode-eco workspace
-go build -o rho ./cmd/rho
-./rho
+go build -o decoder ./cmd/decoder
+./decoder
# First run — paste API key in /config (stored in macOS Keychain / Linux keyring)
# Verify readiness
-./rho path
+./decoder path
```
-**No Docker or container runtime is required.** Rho executes agent commands
-directly on the host. Run `rho path` (or `rho doctor`) to see an onboarding
+**No Docker or container runtime is required.** Decoder executes agent commands
+directly on the host. Run `decoder path` (or `decoder doctor`) to see an onboarding
checklist: credentials → model → catalog → ecosystem.
See [docs/SECURITY-DEVELOPER.md](docs/SECURITY-DEVELOPER.md) for the credential model.
-Do not put API keys in shell env or `.env` for rho.
+Do not put API keys in shell env or `.env` for decoder.
Optional: install the current `main` with the Go toolchain. Use `@main` until
v0.3.0 is tagged: `@latest` still resolves to the hawk-era v0.2.0, which does not
-contain `cmd/rho`.
+contain `cmd/decoder`.
```bash
-go install github.com/GrayCodeAI/rho/cmd/rho@main
+go install github.com/GrayCodeAI/decoder/cmd/decoder@main
```
## Features
@@ -131,17 +136,17 @@ Built with [Bubble Tea](https://github.com/charmbracelet/bubbletea) for a smooth
### Portable Execution Graph
-Export the latest or a selected Rho session as validated graph nodes, edges,
+Export the latest or a selected Decoder session as validated graph nodes, edges,
and lifecycle events:
```bash
-rho graph export
-rho graph export
-rho graph export --mission-dir /path/to/mission
+decoder graph export
+decoder graph export
+decoder graph export --mission-dir /path/to/mission
# Explicitly privacy-normalize and sync the graph for a connected cloud project
-rho cloud graph sync
-rho cloud graph sync --mission-dir /path/to/mission
+decoder cloud graph sync
+decoder cloud graph sync --mission-dir /path/to/mission
```
Syncing needs a [GrayCode Cloud](#graycode-cloud-optional) connection.
@@ -156,37 +161,37 @@ synchronized explicitly with the `--mission-dir` variants above.
### GrayCode Cloud (optional)
GrayCode Cloud is the optional, opt-in hosted control plane for device login,
-usage, delivery context and graph sync. Rho works fully without it and sends
+usage, delivery context and graph sync. Decoder works fully without it and sends
nothing until you connect. It is alpha and still being rolled out: if
-`rho cloud login` cannot reach `cloud.graycodeai.com`, the hosted service is
-not available to you yet, and nothing else in Rho is affected.
+`decoder cloud login` cannot reach `cloud.graycodeai.com`, the hosted service is
+not available to you yet, and nothing else in Decoder is affected.
```bash
-rho cloud login # browser device login
-rho cloud status # endpoint, device, project, token storage
-rho cloud context # sync repository, branch, CI and deployment context
-rho cloud graph sync # upload a privacy-normalized execution graph
+decoder cloud login # browser device login
+decoder cloud status # endpoint, device, project, token storage
+decoder cloud context # sync repository, branch, CI and deployment context
+decoder cloud graph sync # upload a privacy-normalized execution graph
```
- **Endpoint.** New connections use `https://cloud.graycodeai.com` unless you
- pass `--endpoint` or set `RHO_CLOUD_URL` (for example a local Worker at
+ pass `--endpoint` or set `DECODER_CLOUD_URL` (for example a local Worker at
`http://127.0.0.1:8787`). Only `https://` is accepted, except plain
`http://` on `localhost`, `127.0.0.1` and `[::1]`. A saved connection keeps
the endpoint that issued its token. `https://api.graycodeai.com` is the
browser API and rejects device tokens.
-- **What is sent.** Once connected, each `rho exec` run reports one usage
+- **What is sent.** Once connected, each `decoder exec` run reports one usage
event (model, token counts, duration, status). This is fail-open: it never
- changes the run's result, and rho waits at most 3 seconds for it after the
- output is written. `rho cloud context` and `rho cloud graph sync` are
+ changes the run's result, and decoder waits at most 3 seconds for it after the
+ output is written. `decoder cloud context` and `decoder cloud graph sync` are
explicit, and any rejection is reported as an error.
-- **Device token.** rho keeps the token in the macOS Keychain or the Windows
+- **Device token.** decoder keeps the token in the macOS Keychain or the Windows
Credential Manager. Linux and other platforms have no credential-store
- integration yet, so the token is written to `.tokens` in the Rho config
- directory (`~/.config/rho/.tokens` by default, or `$RHO_CONFIG_DIR/.tokens`)
- as plaintext with mode `0600`. `rho cloud login`/`connect` print a warning
- when that happens and `rho cloud status` shows where the token lives.
+ integration yet, so the token is written to `.tokens` in the Decoder config
+ directory (`~/.config/decoder/.tokens` by default, or `$DECODER_CONFIG_DIR/.tokens`)
+ as plaintext with mode `0600`. `decoder cloud login`/`connect` print a warning
+ when that happens and `decoder cloud status` shows where the token lives.
- **Manual connection.**
- `rho cloud connect --device-id --project-id --token-stdin < token.txt`
+ `decoder cloud connect --device-id --project-id --token-stdin < token.txt`
saves an existing device; without `--token-stdin` it prompts for the token
without echo. `--token ` still works but is
deprecated because it exposes the token in shell history and `ps`.
@@ -196,7 +201,7 @@ rho cloud graph sync # upload a privacy-normalized execution grap
For larger tasks, decompose work into parallel feature branches (power-user / future team workflows):
```bash
-rho mission "Add auth, rate limiting, and logging"
+decoder mission "Add auth, rate limiting, and logging"
```
Each sub-agent runs in its own git worktree with full autonomy.
@@ -206,14 +211,14 @@ Each sub-agent runs in its own git worktree with full autonomy.
Discover and install modular instruction packages for specialized workflows:
```bash
-rho skills search api # Search community registry
-rho skills install go-review # Install from GitHub
-rho skills audit # Security scan installed skills
+decoder skills search api # Search community registry
+decoder skills install go-review # Install from GitHub
+decoder skills audit # Security scan installed skills
```
### Permission Center
-rho exposes two independent chat command centers — trust tier and the
+decoder exposes two independent chat command centers — trust tier and the
spec-driven workflow gate — rather than one merged permission mode:
```text
@@ -245,7 +250,7 @@ The model is:
- `Rules` control explicit allow/deny exceptions.
- `Spec` is a separate, independent workflow gate (bare `/spec` opens a
picker): starting it walks the model through `Specify → Plan → Tasks`,
- writing real files to `.rho/specs//`, and blocks Write/Edit/Bash
+ writing real files to `.decoder/specs//`, and blocks Write/Edit/Bash
until you approve moving to implementation — at **any** trust tier,
including Autonomous.
@@ -259,23 +264,23 @@ Connect external tools via [Model Context Protocol](https://modelcontextprotocol
### Watch Mode (AI-comment loop)
-`rho --watch` watches your tree for `AI!` (do it now) and `AI?` (answer my question) comments and acts on them automatically — leave a directive in code, save, and rho responds. Off by default; enabled via the `--watch` flag.
+`decoder --watch` watches your tree for `AI!` (do it now) and `AI?` (answer my question) comments and acts on them automatically — leave a directive in code, save, and decoder responds. Off by default; enabled via the `--watch` flag.
### CI / GitHub Action
-A bundled GitHub Action (`.github/actions/rho`) runs rho in your pipeline: interactive mode on `@rho` mentions in issue/PR comments, automation mode on labeled issues/PRs, and skill dispatch when a prompt begins with `/` (e.g. `/code-review`).
+A bundled GitHub Action (`.github/actions/decoder`) runs decoder in your pipeline: interactive mode on `@decoder` mentions in issue/PR comments, automation mode on labeled issues/PRs, and skill dispatch when a prompt begins with `/` (e.g. `/code-review`).
### Messaging Gateways (opt-in)
-The daemon exposes Telegram, Discord, and Slack gateways so you can chat with rho from your messaging app. Disabled by default; enabled per-channel via daemon config.
+The daemon exposes Telegram, Discord, and Slack gateways so you can chat with decoder from your messaging app. Disabled by default; enabled per-channel via daemon config.
### AST Repo-Map & Codebase Analysis
-An AST-based repository map (`internal/context/repomap`) gives the model a structural overview of your code. On first run, rho can auto-analyze the codebase to seed context (default-off, opt-in).
+An AST-based repository map (`internal/context/repomap`) gives the model a structural overview of your code. On first run, decoder can auto-analyze the codebase to seed context (default-off, opt-in).
### Auto-Lint / Auto-Fix Cycle
-After edits, rho can run the matching linter and iterate on fixes (bounded retries) before handing back. Opt-in; preserves existing behavior when disabled.
+After edits, decoder can run the matching linter and iterate on fixes (bounded retries) before handing back. Opt-in; preserves existing behavior when disabled.
### Image / Multimodal Context
@@ -311,17 +316,17 @@ Features adopted from open-source agent projects. All are off by default unless
| Feature | Flag / Command | What it does |
|---|---|---|
-| Best-of-N fan-out | `rho exec --fanout N` | Run the same prompt in N isolated worktrees, compare, merge winner |
-| Completion notifications | `RHO_NOTIFY_WEBHOOK_URL` / `RHO_NOTIFY_TELEGRAM_TOKEN` + `_CHAT_ID` | Webhook or Telegram ping when a run finishes |
-| Incremental system-context | `RHO_INCREMENTAL_CONTEXT=1` | Reconcile dynamic sections instead of rebuilding the prompt |
-| Tool-catalog shrink | `RHO_TOOL_SHRINK=1` | Compress the tool catalog sent on every request |
-| Compaction segments | `RHO_COMPACTION_SEGMENT_DETAIL=verbose\|balanced\|minimal\|none` | Persist verbatim compacted turns to disk |
-| Skill curator | `rho skills curator status/run/pin/unpin/archive` + `RHO_SKILL_CURATOR=1` | Auto-archive cold agent-created skills (recoverable) |
+| Best-of-N fan-out | `decoder exec --fanout N` | Run the same prompt in N isolated worktrees, compare, merge winner |
+| Completion notifications | `DECODER_NOTIFY_WEBHOOK_URL` / `DECODER_NOTIFY_TELEGRAM_TOKEN` + `_CHAT_ID` | Webhook or Telegram ping when a run finishes |
+| Incremental system-context | `DECODER_INCREMENTAL_CONTEXT=1` | Reconcile dynamic sections instead of rebuilding the prompt |
+| Tool-catalog shrink | `DECODER_TOOL_SHRINK=1` | Compress the tool catalog sent on every request |
+| Compaction segments | `DECODER_COMPACTION_SEGMENT_DETAIL=verbose\|balanced\|minimal\|none` | Persist verbatim compacted turns to disk |
+| Skill curator | `decoder skills curator status/run/pin/unpin/archive` + `DECODER_SKILL_CURATOR=1` | Auto-archive cold agent-created skills (recoverable) |
| Structural code match | `CodeMatch` tool | Tree-sitter query search over Go/Python/TS/TSX |
-| Composable toolsets | `rho toolset [name]` + `Toolset` tool | Named tool groups (research, dev, ops, full_stack) |
+| Composable toolsets | `decoder toolset [name]` + `Toolset` tool | Named tool groups (research, dev, ops, full_stack) |
| App verification | `AppVerify` tool | Boot-smoke check with readiness polling and evidence artifacts |
-| Media generation | `GenerateMedia` tool | Image/video generation with local persistence. Backend via `tool.SetMediaEngine`; an OpenAI-compatible client ships in `flux/client` (`ImageClient`), wired by the host (boundary-guarded — rho routes through the flux facade) |
-| Voice transcription | Telegram voice notes + `stt` package | Transcribe Telegram voice/audio into the prompt. Backend via `stt.SetTranscriber`; an OpenAI-compatible client ships in `flux/client` (`AudioClient`), wired by the host |
+| Media generation | `GenerateMedia` tool | Image/video generation with local persistence. Backend via `tool.SetMediaEngine`; an OpenAI-compatible client ships in `mux/client` (`ImageClient`), wired by the host (boundary-guarded — decoder routes through the mux facade) |
+| Voice transcription | Telegram voice notes + `stt` package | Transcribe Telegram voice/audio into the prompt. Backend via `stt.SetTranscriber`; an OpenAI-compatible client ships in `mux/client` (`AudioClient`), wired by the host |
| Bounded autonomous budgets | `internal/engine` (`AutonomousBudget`) | Track turns/tokens/time/continuations; report why a run stopped (budget vs gate-passed vs error) |
| Agent family messaging | `internal/multiagent` (`FamilyMessenger`) | Direct parent/sibling/child messages with pending caps + rate limits |
| Path reservations | `internal/multiagent` ledger | Detect overlapping-file changes between parallel branches |
@@ -329,27 +334,27 @@ Features adopted from open-source agent projects. All are off by default unless
| X/Twitter search | `SearchX` tool | Live X search by forwarding a query to an xAI endpoint with server-side search; returns a cited summary. Requires `XAI_API_KEY` (or `GROK_API_KEY`) |
| Desktop computer-use | `ComputerUse` tool | snapshot/click/type/scroll/press/screenshot via a pluggable `tool.SetComputerBackend` seam (host wires a native macOS accessibility backend) |
| Token-cheaper file views | `Read` tool `--minify` | Read-only, comment-stripped, whitespace-dense file view (Go via `go/parser`; other languages string-aware; never touches disk) — fewer tokens per read |
-| Classified provider hints | `internal/errhint` | Buckets provider errors (Auth/RateLimit/Connectivity/ModelNotFound/ContextOverflow) into a one-line fixable next step. Wired into TUI error rows (`friendlyErrorMessage`) and `rho exec` CLI errors |
+| Classified provider hints | `internal/errhint` | Buckets provider errors (Auth/RateLimit/Connectivity/ModelNotFound/ContextOverflow) into a one-line fixable next step. Wired into TUI error rows (`friendlyErrorMessage`) and `decoder exec` CLI errors |
| Atomic install transactions | `internal/installtxn` | Cross-process staged install/remove with rollback. Wired into skill install (atomic `SKILL.md` publish) |
-| Test command discovery | `internal/testrunner` | Auto-detect test/verify commands (Go/npm/bun/pnpm/yarn/pytest/cargo) and parse runner output into structured results. Wired into `rho verify` |
+| Test command discovery | `internal/testrunner` | Auto-detect test/verify commands (Go/npm/bun/pnpm/yarn/pytest/cargo) and parse runner output into structured results. Wired into `decoder verify` |
| Circuit breaker | `internal/circuitbreaker` | Closed/open/half-open retry-storm protection with cooldown. Wired into auto-compaction (cooldown + half-open auto-retry) |
| Smart turn routing | `internal/smartrouting` | Deterministic simple/strong turn classifier with fail-toward-strong safety. Wired into per-turn model selection (`settings.smart_routing`) |
| Conversation arc | `internal/conversationarc` | Durable sidecar memory of goals/decisions/milestones/phase with a byte-stable summary. Wired into sessions (loaded on open, saved on close, injected into the system prompt) |
| Relevance pruning | `internal/relevanceprune` | Token-budgeted context pruning preserving recent turns/tool calls/errors. Wired into compaction as a `relevance` strategy |
| Tool-result clearing | `internal/engine` (`ClearOldToolResults`) | Two-tier context management: at 80% of the context window, stale tool-result content is replaced with `[output cleared]` placeholders (tool_use kept intact) before compacting — a gentler tier below compaction |
| Approval pause timing | `internal/permissions` | Approval requests record decision timestamp + human deliberation duration (`DecisionAt`/`PauseDuration`) for approval-latency observability |
-| Graceful exhaustion | `internal/engine` (`SynthesisForExhaustion`) | When turn/token/time limits hit, one final tools-disabled LLM call synthesizes a coherent completion (accomplished/remaining/next steps) instead of a bare stop line. Opt-in via `RHO_GRACEFUL_EXHAUSTION=1` |
-| Deterministic replay cache | `internal/replaycache` (`RHO_REPLAY_CACHE_DIR`) | Disk-persisted SHA-256-keyed cache of completions; identical requests replay stored responses for reproducible regression runs |
+| Graceful exhaustion | `internal/engine` (`SynthesisForExhaustion`) | When turn/token/time limits hit, one final tools-disabled LLM call synthesizes a coherent completion (accomplished/remaining/next steps) instead of a bare stop line. Opt-in via `DECODER_GRACEFUL_EXHAUSTION=1` |
+| Deterministic replay cache | `internal/replaycache` (`DECODER_REPLAY_CACHE_DIR`) | Disk-persisted SHA-256-keyed cache of completions; identical requests replay stored responses for reproducible regression runs |
## Usage
### Interactive Mode
```bash
-rho # Start REPL
-rho -r abc123 # Resume session
-rho -c # Continue latest session
-rho --provider openai --model gpt-4o # Override provider
+decoder # Start REPL
+decoder -r abc123 # Resume session
+decoder -c # Continue latest session
+decoder --provider openai --model gpt-4o # Override provider
```
### Permission Examples
@@ -368,37 +373,37 @@ rho --provider openai --model gpt-4o # Override provider
### Non-Interactive Mode
```bash
-rho -p "explain this repo" # Print response, exit
-rho -p "fix tests" --allowed-tools "Bash(go test:*) Edit Read"
-rho exec "refactor auth module" # Full engine, non-interactive
-rho exec --auto full "add error handling" # Full autonomy
-rho exec --worktree "add rate limiting" # Isolated branch
-rho exec --agent reviewer "review last commit" # Custom persona
+decoder -p "explain this repo" # Print response, exit
+decoder -p "fix tests" --allowed-tools "Bash(go test:*) Edit Read"
+decoder exec "refactor auth module" # Full engine, non-interactive
+decoder exec --auto full "add error handling" # Full autonomy
+decoder exec --worktree "add rate limiting" # Isolated branch
+decoder exec --agent reviewer "review last commit" # Custom persona
```
### Diagnostics & ecosystem
```bash
-rho path # Developer path readiness (setup + security)
-rho doctor # Full health report (flux + token pipeline panel)
-rho ecosystem # Ecosystem panel only
-rho preflight # Quick ready-to-chat check
+decoder path # Developer path readiness (setup + security)
+decoder doctor # Full health report (mux + token pipeline panel)
+decoder ecosystem # Ecosystem panel only
+decoder preflight # Quick ready-to-chat check
make path # Developer path verification
make smoke # Build + quick verification script
```
See [docs/SECURITY-DEVELOPER.md](docs/SECURITY-DEVELOPER.md).
-See [docs/ecosystem-message-flow.md](docs/ecosystem-message-flow.md) for how flux connects during a chat session, and [docs/ECOSYSTEM-WIRING.md](docs/ECOSYSTEM-WIRING.md) for the current-to-proposed architecture and repository boundaries.
+See [docs/ecosystem-message-flow.md](docs/ecosystem-message-flow.md) for how mux connects during a chat session, and [docs/ECOSYSTEM-WIRING.md](docs/ECOSYSTEM-WIRING.md) for the current-to-proposed architecture and repository boundaries.
In the TUI: `/path`, `/ecosystem`, `/memory` (AGENTS.md).
### Daemon Mode
```bash
-rho daemon start # Background HTTP server on port 4590
-rho daemon status # Check if running
-rho daemon stop # Graceful shutdown
+decoder daemon start # Background HTTP server on port 4590
+decoder daemon status # Check if running
+decoder daemon stop # Graceful shutdown
```
Endpoints: `GET /v1/health`, `GET /v1/ready` (dependency-aware readiness), `POST /v1/chat` (JSON or SSE streaming)
@@ -406,15 +411,15 @@ Endpoints: `GET /v1/health`, `GET /v1/ready` (dependency-aware readiness), `POST
### Mission Mode
```bash
-rho mission "Add auth, rate limiting, and logging"
-rho mission --workers 6 "Refactor into microservices"
-rho mission --dry-run "What would this decompose into?"
-rho mission --from-tasks # Execute validated dependency waves
+decoder mission "Add auth, rate limiting, and logging"
+decoder mission --workers 6 "Refactor into microservices"
+decoder mission --dry-run "What would this decompose into?"
+decoder mission --from-tasks # Execute validated dependency waves
```
## Providers
-rho works with any LLM provider. **Developer path:** paste keys in `/config` (stored in OS keychain) — not shell env or `.env`. Use `rho credentials status` to verify.
+decoder works with any LLM provider. **Developer path:** paste keys in `/config` (stored in OS keychain) — not shell env or `.env`. Use `decoder credentials status` to verify.
| Provider | ID | Key (via `/config`) |
|---|---|---|
@@ -432,20 +437,20 @@ rho works with any LLM provider. **Developer path:** paste keys in `/config` (st
| Xiaomi (MiMo) Token Plan | `xiaomi_mimo_token_plan` | `XIAOMI_MIMO_TOKEN_PLAN_API_KEY` (pick region in `/config`) |
| Ollama (local) | `ollama` | `OLLAMA_BASE_URL` (no API key) |
-Provider routing, model resolution, and retries are handled by [flux](https://github.com/GrayCodeAI/flux).
-For deployment-aware routing, set `"deployment_routing": true` in `.rho/settings.json`
-or export `RHO_DEPLOYMENT_ROUTING=true`. Rho will route canonical model IDs through
-Flux's deployment catalog, so new models can be exposed by refreshing the catalog
-instead of changing Rho. In chat, run `/refresh-model-catalog` to fetch the latest
-deployment-aware catalog into `~/.flux/model_catalog.json`.
+Provider routing, model resolution, and retries are handled by [mux](https://github.com/GrayCodeAI/mux).
+For deployment-aware routing, set `"deployment_routing": true` in `.decoder/settings.json`
+or export `DECODER_DEPLOYMENT_ROUTING=true`. Decoder will route canonical model IDs through
+Mux's deployment catalog, so new models can be exposed by refreshing the catalog
+instead of changing Decoder. In chat, run `/refresh-model-catalog` to fetch the latest
+deployment-aware catalog into `~/.mux/model_catalog.json`.
## Architecture
-rho is built in Go with a modular, layered architecture:
+decoder is built in Go with a modular, layered architecture:
```
-rho/
-├── bin/ # Built binaries (rho, rho_bin)
+decoder/
+├── bin/ # Built binaries (decoder, decoder_bin)
├── cmd/ # CLI entry point (Cobra + Bubble Tea TUI)
├── internal/
│ ├── engine/ # Agent loop, compaction, self-improvement
@@ -473,30 +478,30 @@ rho/
Ecosystem sibling repos (independent Git repos in the `graycode-eco` parent
folder):
-├── flux/ # LLM provider runtime
+├── mux/ # LLM provider runtime
```
### Ecosystem
-rho is the main CLI/product and integrates these GrayCodeAI repositories in
+decoder is the main CLI/product and integrates these GrayCodeAI repositories in
three runtime layers plus optional tooling/platform services:
-- **Primary product:** **rho** is the only end-user product surface in this ecosystem.
-- **Provider engine mounted by Rho:** **flux** is the LLM provider runtime, consumed through its stable engine facade.
-- **API consumers/extensions:** **graycode-skills** provides Rho skills
- installed on demand (`rho skills install`).
-- **Tooling/platform:** **graycode-platform** contains the optional web/BFF/Rho
- Cloud plane and is outside the Rho Go runtime graph.
+- **Primary product:** **decoder** is the only end-user product surface in this ecosystem.
+- **Provider engine mounted by Decoder:** **mux** is the LLM provider runtime, consumed through its stable engine facade.
+- **API consumers/extensions:** **graycode-skills** provides Decoder skills
+ installed on demand (`decoder skills install`).
+- **Tooling/platform:** **graycode-platform** contains the optional web/BFF/Decoder
+ Cloud plane and is outside the Decoder Go runtime graph.
Local development uses:
-- **`go.mod` modules:** pinned requirements for `flux`
+- **`go.mod` modules:** pinned requirements for `mux`
- **Workspace + `go.work`:** sibling support repos are cloned in the `graycode-eco` workspace (as `../`); `go.work` resolves the module paths to those local checkouts
- **Module-mode builds:** standalone builds resolve the pinned `go.mod` versions from the module proxy (no workspace)
Cross-repo contracts now live in `internal/contracts` (vendored from the
removed `github.com/GrayCodeAI/eagle` module) so support repos do not depend
-on Rho internals. External consumers should vendor the needed DTOs from `internal/contracts`
+on Decoder internals. External consumers should vendor the needed DTOs from `internal/contracts`
until a published contracts module exists.
Current contract packages (`internal/contracts/`):
@@ -514,26 +519,26 @@ You may keep a **personal** parent **`go.work`** that lists alternate clones on
| Component | Repository | Purpose |
|---|---|---|
-| **rho** | This repo | AI coding agent |
-| **flux** | [GrayCodeAI/flux](https://github.com/GrayCodeAI/flux) | LLM provider runtime |
+| **decoder** | This repo | AI coding agent |
+| **mux** | [GrayCodeAI/mux](https://github.com/GrayCodeAI/mux) | LLM provider runtime |
| **graycode-skills** | [GrayCodeAI/graycode-skills](https://github.com/GrayCodeAI/graycode-skills) | Community skill registry |
-| **graycode-platform** | [GrayCodeAI/graycode-platform](https://github.com/GrayCodeAI/graycode-platform) | Web, BFF, and Rho Cloud |
+| **graycode-platform** | [GrayCodeAI/graycode-platform](https://github.com/GrayCodeAI/graycode-platform) | Web, BFF, and Decoder Cloud |
The canonical inventory of sibling repositories is
[`GrayCodeAI/graycode-eco/ecosystem.yaml`](https://github.com/GrayCodeAI/graycode-eco/blob/main/ecosystem.yaml),
not the `ecosystem.yaml` in this repo, which is deprecated and incomplete. The
inventory moved because a product must not own the registry of its siblings: it
-lived here, `rho` was renamed from `hawk` without signalling the other nine
+lived here, `decoder` was renamed from `hawk` without signalling the other nine
repositories, and the list silently omitted `beam`. See
[graycode-eco/adr/0001](https://github.com/GrayCodeAI/graycode-eco/blob/main/adr/README.md).
`scripts/ecosystem-manifest.sh` reads the roof's file and falls back to the
deprecated local copy only when the roof is not checked out alongside.
-`flux` is the only Go module dependency in the entire ecosystem; it is consumed
+`mux` is the only Go module dependency in the entire ecosystem; it is consumed
through its stable engine facade.
-For the consolidated repo map and the current-vs-proposed architecture diagrams, see [docs/architecture/rho-current-vs-proposed.md](docs/architecture/rho-current-vs-proposed.md).
+For the consolidated repo map and the current-vs-proposed architecture diagrams, see [docs/architecture/decoder-current-vs-proposed.md](docs/architecture/decoder-current-vs-proposed.md).
For execution-graph ownership, automatic capture seams, and export/sync
commands, see
[docs/architecture/execution-graph.md](docs/architecture/execution-graph.md).
@@ -542,12 +547,12 @@ commands, see
### Prerequisites
-- Go 1.26+
+- Go 1.27.2+
### Build & Test
```bash
-go build ./cmd/rho # Build binary
+go build ./cmd/decoder # Build binary
go test -race ./... # Run all tests with race detector
make ci # Run full CI suite (lint, test, security)
make cover # Generate coverage report
@@ -571,7 +576,7 @@ Headline numbers (Go 1.26.6, AMD EPYC 7543P, `go test -bench -benchmem -count=3`
### Project Structure
-rho follows Go conventions: `cmd/` for entry points, `internal/` for private code, tests alongside source files. See [docs/architecture.md](docs/architecture.md) for details.
+decoder follows Go conventions: `cmd/` for entry points, `internal/` for private code, tests alongside source files. See [docs/architecture.md](docs/architecture.md) for details.
## Contributing
diff --git a/SECURITY.md b/SECURITY.md
index 207af0b89..436841af6 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -1,4 +1,4 @@
-# Security Policy — rho
+# Security Policy — decoder
## Supported versions
@@ -7,15 +7,15 @@ minor versions once `1.x` ships. Older versions receive critical-severity
fixes only on a best-effort basis.
The current canonical version is the contents of the [`VERSION`](./VERSION)
-file at the repo root. See [`docs/versioning.md`](https://github.com/GrayCodeAI/rho/blob/main/docs/versioning.md)
+file at the repo root. See [`docs/versioning.md`](https://github.com/GrayCodeAI/decoder/blob/main/docs/versioning.md)
for the eco-wide versioning scheme.
## Reporting a vulnerability
**Do not open a public GitHub issue for security vulnerabilities.** Instead:
-1. Open a private [GitHub Security Advisory](https://github.com/GrayCodeAI/rho/security/advisories/new), **or**
-2. Email `security@rho.ai` with the details below.
+1. Open a private [GitHub Security Advisory](https://github.com/GrayCodeAI/decoder/security/advisories/new), **or**
+2. Email `security@decoder.ai` with the details below.
Include in your report:
@@ -63,28 +63,28 @@ This policy covers the code in this repository and the release artefacts
published from it. It does not cover:
- Third-party dependencies (report to upstream).
-- LLM provider services that rho integrates with (report to the
+- LLM provider services that decoder integrates with (report to the
provider).
- Local filesystem misuse where an attacker already has shell access (out of
threat model).
-For rho-specific threat-model notes, see the README and any docs in
+For decoder-specific threat-model notes, see the README and any docs in
this repo.
## Config security model
### Clone-and-load attack defense
-Project-level `.rho/settings.json` can be committed to a git repository.
+Project-level `.decoder/settings.json` can be committed to a git repository.
An attacker who controls a repository could define MCP servers that execute
-arbitrary commands when a developer clones and runs rho in that directory.
+arbitrary commands when a developer clones and runs decoder in that directory.
**Mitigation:** Project-level MCP servers are stripped from project config
(`projectSafeSettings` in `internal/config/settings.go`) and project
hooks/MCP/plugins/LSP additionally require folder trust: the project root
-must be trusted via `rho trust add` (`AllowProjectAutomation` in
+must be trusted via `decoder trust add` (`AllowProjectAutomation` in
`internal/trust/store.go`). There is no `--allow-project-mcp` flag.
-Global MCP servers (from `~/.rho/settings.json`) are always loaded.
+Global MCP servers (from `~/.decoder/settings.json`) are always loaded.
### Security-sensitive fields
@@ -107,8 +107,8 @@ Highest priority first (`LoadSettings` / `LoadSettingsWithOverride` in
1. CLI `--settings` JSON override
2. Per-command CLI flags (e.g., `--model`, `--provider`)
3. Environment variables (only where explicitly read; there is no global env layer)
-4. Project `.rho/settings.json` (repository-safe subset only — see above)
-5. Global `~/.rho/settings.json`
+4. Project `.decoder/settings.json` (repository-safe subset only — see above)
+5. Global `~/.decoder/settings.json`
6. Built-in defaults (lowest priority)
Project-level config CANNOT escalate permissions beyond what global config
@@ -118,7 +118,7 @@ implements field-by-field merging with explicit precedence rules.
### Credential storage
API keys and secrets are stored in the OS secret store (macOS Keychain,
-Linux secret service, Windows Credential Manager) via the `flux/credentials`
+Linux secret service, Windows Credential Manager) via the `mux/credentials`
package. They are never written to `settings.json`, `.env`, or any file
in the repository. The `/config` command manages credential storage
interactively.
diff --git a/api/openapi.yaml b/api/openapi.yaml
index ca80217a4..d13136170 100644
--- a/api/openapi.yaml
+++ b/api/openapi.yaml
@@ -1,19 +1,19 @@
openapi: "3.1.0"
info:
- title: Rho Daemon API
+ title: Decoder Daemon API
description: |
- HTTP API served by the rho daemon on port 4590.
+ HTTP API served by the decoder daemon on port 4590.
Used by sparrow, robin, and external integrations.
- The daemon must be running (`rho daemon start`) before calling these endpoints.
+ The daemon must be running (`decoder daemon start`) before calling these endpoints.
This spec is kept in lockstep with the registered routes in
internal/daemon; the daemon test suite fails if they drift.
version: "0.1.0"
license:
name: MIT
- url: https://github.com/GrayCodeAI/rho/blob/main/LICENSE
+ url: https://github.com/GrayCodeAI/decoder/blob/main/LICENSE
contact:
- url: https://github.com/GrayCodeAI/rho
+ url: https://github.com/GrayCodeAI/decoder
servers:
- url: http://127.0.0.1:4590
@@ -60,7 +60,7 @@ components:
description: Existing directory associated with session metadata. The daemon executes tools from its startup working directory; it never performs a process-wide chdir per request.
agent:
type: string
- description: Named Rho agent persona to apply. Continuations inherit the persisted persona when omitted.
+ description: Named Decoder agent persona to apply. Continuations inherit the persisted persona when omitted.
ChatResponse:
type: object
@@ -254,7 +254,7 @@ components:
properties:
schema_version:
type: string
- enum: [rho.graph/v1]
+ enum: [decoder.graph/v1]
generated_at:
type: string
format: date-time
@@ -457,7 +457,7 @@ components:
properties:
status:
type: string
- description: Output of `rho review status`
+ description: Output of `decoder review status`
Error:
type: object
@@ -565,7 +565,7 @@ paths:
tags: [system]
summary: Readiness probe
description: |
- Returns 200 only when a session factory is configured and Flux's local
+ Returns 200 only when a session factory is configured and Mux's local
preflight confirms provider state, catalog, credentials, and model
selection are ready. Returns 503 with the failed dependency otherwise.
security: []
@@ -600,7 +600,7 @@ paths:
Omit `session_id` to create and durably persist a new session. Supply a
previously returned `session_id` to load its transcript, append a turn,
and update that same durable session. The returned JSON field and the
- `X-Rho-Session-ID` header identify a retrievable `/v1/sessions/{id}`.
+ `X-Decoder-Session-ID` header identify a retrievable `/v1/sessions/{id}`.
requestBody:
required: true
content:
@@ -611,7 +611,7 @@ paths:
"200":
description: Agent response (or SSE stream)
headers:
- X-Rho-Session-ID:
+ X-Decoder-Session-ID:
description: Durable session ID created or continued by this request.
schema:
type: string
@@ -873,10 +873,10 @@ paths:
tags: [graphs]
summary: Project a persisted session as a portable execution graph
description: |
- Returns Rho's privacy-safe, read-only `rho.graph/v1` projection.
+ Returns Decoder's privacy-safe, read-only `decoder.graph/v1` projection.
Prompt text, tool arguments, tool output, and verification details are
excluded. Explicit Swift checkpoint IDs are additive to authoritative
- Swift session correlation performed by Rho.
+ Swift session correlation performed by Decoder.
parameters:
- name: id
in: path
diff --git a/cmd/acp.go b/cmd/acp.go
index 0ee51b3c0..2cfa5ff16 100644
--- a/cmd/acp.go
+++ b/cmd/acp.go
@@ -7,19 +7,19 @@ import (
"path/filepath"
"syscall"
- "github.com/GrayCodeAI/rho/internal/acp"
- "github.com/GrayCodeAI/rho/internal/attachment"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/observability/logger"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/acp"
+ "github.com/GrayCodeAI/decoder/internal/attachment"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/observability/logger"
+ "github.com/GrayCodeAI/decoder/internal/storage"
"github.com/spf13/cobra"
)
var acpCmd = &cobra.Command{
Use: "acp",
- Short: "Run rho as an Agent Client Protocol (ACP) server",
- Long: "Run rho as an ACP server over stdio (JSON-RPC 2.0) so editors such as " +
+ Short: "Run decoder as an Agent Client Protocol (ACP) server",
+ Long: "Run decoder as an ACP server over stdio (JSON-RPC 2.0) so editors such as " +
"Zed can drive it. Tool-permission prompts are routed back to the client " +
"via session/request_permission.",
RunE: runACP,
@@ -30,8 +30,8 @@ func init() {
}
func runACP(cmd *cobra.Command, _ []string) error {
- settings := rhoconfig.LoadSettings()
- newSession := newConfiguredRhoSessionFactory(settings, logger.New(io.Discard, logger.Error))
+ settings := decoderconfig.LoadSettings()
+ newSession := newConfiguredDecoderSessionFactory(settings, logger.New(io.Discard, logger.Error))
factory := func() (*engine.Session, error) {
systemPrompt, err := buildSystemPrompt()
diff --git a/cmd/agent.go b/cmd/agent.go
index aa32f471c..fd20159f3 100644
--- a/cmd/agent.go
+++ b/cmd/agent.go
@@ -6,8 +6,8 @@ import (
"os"
"path/filepath"
- "github.com/GrayCodeAI/rho/internal/multiagent/agents"
- "github.com/GrayCodeAI/rho/internal/theme"
+ "github.com/GrayCodeAI/decoder/internal/multiagent/agents"
+ "github.com/GrayCodeAI/decoder/internal/theme"
"github.com/spf13/cobra"
"golang.org/x/text/cases"
"golang.org/x/text/language"
@@ -16,7 +16,7 @@ import (
var agentCmd = &cobra.Command{
Use: "agent",
Short: "Manage custom agent personas",
- Long: "Create, list, and manage custom agent personas stored in Rho user state.",
+ Long: "Create, list, and manage custom agent personas stored in Decoder user state.",
}
var agentListJSON bool
@@ -82,7 +82,7 @@ func runAgentList(cmd *cobra.Command, _ []string) error {
return nil
}
if len(all) == 0 {
- fmt.Printf("%s\n", auditTint("No agents found. Create one with: rho agent create ", textMuted))
+ fmt.Printf("%s\n", auditTint("No agents found. Create one with: decoder agent create ", textMuted))
fmt.Printf("%s\n", auditTint("Agent directory: "+agents.DefaultDir(), textPrimary))
return nil
}
@@ -165,7 +165,7 @@ func runAgentShow(_ *cobra.Command, args []string) error {
}
fmt.Printf("%s %s\n", auditTint("Model:", textMuted), auditTint(model, textPrimary))
fmt.Printf("%s %s\n", auditTint("File:", textMuted), auditTint(a.FilePath, textPrimary))
- fmt.Printf("\n%s\n%s\n", auditTint("--- Prompt ---", rhoColor), a.Prompt)
+ fmt.Printf("\n%s\n%s\n", auditTint("--- Prompt ---", decoderColor), a.Prompt)
return nil
}
diff --git a/cmd/agent_grid.go b/cmd/agent_grid.go
index 0ebae3ae3..d807353bc 100644
--- a/cmd/agent_grid.go
+++ b/cmd/agent_grid.go
@@ -9,7 +9,7 @@ import (
"charm.land/bubbles/v2/viewport"
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
var (
@@ -17,7 +17,7 @@ var (
// can read agent state at a glance. Active matches Talon Gold,
// done matches the success palette, fail matches error, idle
// matches disabled.
- agentActiveStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).BorderForeground(rhoColor).Padding(0, 1)
+ agentActiveStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).BorderForeground(decoderColor).Padding(0, 1)
agentDoneStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).BorderForeground(doneGreen).Padding(0, 1)
agentFailStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).BorderForeground(errorCoral).Padding(0, 1)
agentIdleStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).BorderForeground(textDisabled).Padding(0, 1)
diff --git a/cmd/agent_grid_test.go b/cmd/agent_grid_test.go
index 06b796535..197578d21 100644
--- a/cmd/agent_grid_test.go
+++ b/cmd/agent_grid_test.go
@@ -3,7 +3,7 @@ package cmd
import (
"testing"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func TestAgentStateString(t *testing.T) {
diff --git a/cmd/agent_test.go b/cmd/agent_test.go
index 3dfac3d3b..fe987407d 100644
--- a/cmd/agent_test.go
+++ b/cmd/agent_test.go
@@ -7,7 +7,7 @@ import (
"path/filepath"
"testing"
- "github.com/GrayCodeAI/rho/internal/multiagent/agents"
+ "github.com/GrayCodeAI/decoder/internal/multiagent/agents"
)
// sampleAgentMarkdown returns a minimal valid agent definition.
@@ -17,7 +17,7 @@ func sampleAgentMarkdown(name, description, model string) string {
func TestAgentList_JSON_Empty(t *testing.T) {
dir := t.TempDir()
- t.Setenv("RHO_STATE_DIR", filepath.Join(dir, "state"))
+ t.Setenv("DECODER_STATE_DIR", filepath.Join(dir, "state"))
if err := os.MkdirAll(filepath.Join(dir, "state", "agents"), 0o755); err != nil {
t.Fatal(err)
}
@@ -49,7 +49,7 @@ func TestAgentList_JSON_Empty(t *testing.T) {
func TestAgentList_JSON(t *testing.T) {
dir := t.TempDir()
stateDir := filepath.Join(dir, "state")
- t.Setenv("RHO_STATE_DIR", stateDir)
+ t.Setenv("DECODER_STATE_DIR", stateDir)
agentDir := filepath.Join(stateDir, "agents")
if err := os.MkdirAll(agentDir, 0o755); err != nil {
t.Fatal(err)
diff --git a/cmd/ai_comments.go b/cmd/ai_comments.go
index d29984040..86dc3ded6 100644
--- a/cmd/ai_comments.go
+++ b/cmd/ai_comments.go
@@ -9,7 +9,7 @@ import (
"sort"
"strings"
- "github.com/GrayCodeAI/rho/internal/fsutil"
+ "github.com/GrayCodeAI/decoder/internal/fsutil"
)
// AIDirective represents a found AI comment directive in a source file.
diff --git a/cmd/audit.go b/cmd/audit.go
index ce94e3fbb..0773d5ba3 100644
--- a/cmd/audit.go
+++ b/cmd/audit.go
@@ -11,8 +11,8 @@ import (
"time"
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/hooks/audit"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/hooks/audit"
+ "github.com/GrayCodeAI/decoder/internal/storage"
"github.com/spf13/cobra"
)
@@ -31,7 +31,7 @@ var auditCmd = &cobra.Command{
redundant cd commands, unnecessary cat/head usage, long sleep loops,
and other patterns that waste tokens and wall-clock time.
-Reports what rho would have caught with current policies enabled,
+Reports what decoder would have caught with current policies enabled,
plus audit-only detectors that identify optimization opportunities.`,
RunE: runAudit,
}
@@ -213,9 +213,9 @@ func discoverSessions(days int, projectFilter string) ([]SessionInfo, error) {
cutoff := time.Now().AddDate(0, 0, -days)
var sessions []SessionInfo
- // Scan rho sessions directory
- rhoDir := storage.SessionsDir()
- entries, err := os.ReadDir(rhoDir)
+ // Scan decoder sessions directory
+ decoderDir := storage.SessionsDir()
+ entries, err := os.ReadDir(decoderDir)
if err != nil && !os.IsNotExist(err) {
return nil, err
}
@@ -224,7 +224,7 @@ func discoverSessions(days int, projectFilter string) ([]SessionInfo, error) {
if e.IsDir() || !strings.HasSuffix(e.Name(), ".jsonl") {
continue
}
- path := filepath.Join(rhoDir, e.Name())
+ path := filepath.Join(decoderDir, e.Name())
info, err := os.Stat(path)
if err != nil {
continue
@@ -311,7 +311,7 @@ func printAuditText(cmd *cobra.Command, result AuditResult) {
_, _ = fmt.Fprintf(w, "\n")
_, _ = fmt.Fprintf(w, "═══════════════════════════════════════════════════════════════\n")
- _, _ = fmt.Fprintf(w, " %s\n", auditTint("Rho Audit Report", rhoColor))
+ _, _ = fmt.Fprintf(w, " %s\n", auditTint("Decoder Audit Report", decoderColor))
_, _ = fmt.Fprintf(w, "═══════════════════════════════════════════════════════════════\n")
_, _ = fmt.Fprintf(w, "\n")
_, _ = fmt.Fprintf(w, " %s %d sessions (last %d days)\n",
diff --git a/cmd/autoinit.go b/cmd/autoinit.go
index 46a3dfb27..f224c22fe 100644
--- a/cmd/autoinit.go
+++ b/cmd/autoinit.go
@@ -8,8 +8,8 @@ import (
"path/filepath"
"time"
- "github.com/GrayCodeAI/rho/internal/autoinit"
- "github.com/GrayCodeAI/rho/internal/intelligence/repomap"
+ "github.com/GrayCodeAI/decoder/internal/autoinit"
+ "github.com/GrayCodeAI/decoder/internal/intelligence/repomap"
)
// autoInitContextFile is the project-level context file the auto-init runner
@@ -22,9 +22,9 @@ const autoInitContextFile = "AGENTS.md"
// project. It is intentionally additive and safe-by-default:
//
// - It runs in a background goroutine so it never blocks chat startup.
-// - It is a no-op unless the project has NO context file (AGENTS.md / RHO.md
+// - It is a no-op unless the project has NO context file (AGENTS.md / DECODER.md
// / CONTEXT.md), no auto-init marker exists yet, and the
-// RHO_DISABLE_AUTO_INIT kill switch is unset — all enforced by
+// DECODER_DISABLE_AUTO_INIT kill switch is unset — all enforced by
// autoinit.MaybeRun.
// - Any failure (analysis error, write error) is swallowed; startup proceeds.
//
@@ -50,7 +50,7 @@ func maybeAutoInit(ctx context.Context) {
// autoInitRunner drives the existing codebase-analysis machinery (the same
// hierarchical repomap summary that powers init/repomap) and writes a starter
// AGENTS.md context file for the project. It mirrors the intent of the
-// init-deep skill / `rho init` without coupling to the agentic flow: a cheap,
+// init-deep skill / `decoder init` without coupling to the agentic flow: a cheap,
// deterministic, dependency-free pass that gives the project a baseline context
// file. The function is only ever invoked by autoinit.MaybeRun, which has
// already confirmed the project has no context file.
@@ -103,8 +103,8 @@ func autoInitContextContent(projectName, summary string) string {
}
return fmt.Sprintf(`# %s
-> Auto-generated by rho on first run. Edit freely or delete to regenerate.
-> Set RHO_DISABLE_AUTO_INIT=1 to opt out of automatic context generation.
+> Auto-generated by decoder on first run. Edit freely or delete to regenerate.
+> Set DECODER_DISABLE_AUTO_INIT=1 to opt out of automatic context generation.
## Package map
diff --git a/cmd/autoinit_test.go b/cmd/autoinit_test.go
index 2df70aba5..fbbeb87d5 100644
--- a/cmd/autoinit_test.go
+++ b/cmd/autoinit_test.go
@@ -6,14 +6,14 @@ import (
"path/filepath"
"testing"
- "github.com/GrayCodeAI/rho/internal/autoinit"
+ "github.com/GrayCodeAI/decoder/internal/autoinit"
)
// TestAutoInitRunner_WritesContextFileOnce verifies the cmd-layer runner
// produces a recognized context file and that MaybeRun invokes it exactly once
// for a fresh project, then gates on the marker thereafter.
func TestAutoInitRunner_WritesContextFileOnce(t *testing.T) {
- t.Setenv("RHO_STATE_DIR", filepath.Join(t.TempDir(), "state"))
+ t.Setenv("DECODER_STATE_DIR", filepath.Join(t.TempDir(), "state"))
root := t.TempDir()
// A trivial Go file so BuildHierarchy has something to summarize.
if err := os.WriteFile(filepath.Join(root, "main.go"), []byte("package main\n\nfunc Foo() {}\n"), 0o644); err != nil {
diff --git a/cmd/autonomy_picker.go b/cmd/autonomy_picker.go
index 8b69d22c2..8eeb576d2 100644
--- a/cmd/autonomy_picker.go
+++ b/cmd/autonomy_picker.go
@@ -3,7 +3,7 @@ package cmd
import (
"strings"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
"charm.land/bubbles/v2/textinput"
tea "charm.land/bubbletea/v2"
diff --git a/cmd/autonomy_picker_test.go b/cmd/autonomy_picker_test.go
index e03dd772a..37750a307 100644
--- a/cmd/autonomy_picker_test.go
+++ b/cmd/autonomy_picker_test.go
@@ -3,7 +3,7 @@ package cmd
import (
"testing"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
tea "charm.land/bubbletea/v2"
"github.com/mattn/go-runewidth"
diff --git a/cmd/autonomy_tiers.go b/cmd/autonomy_tiers.go
index de7bea817..14d3884c6 100644
--- a/cmd/autonomy_tiers.go
+++ b/cmd/autonomy_tiers.go
@@ -4,7 +4,7 @@ import (
"fmt"
"image/color"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
lipgloss "charm.land/lipgloss/v2"
)
diff --git a/cmd/autonomy_tiers_copy_test.go b/cmd/autonomy_tiers_copy_test.go
index f0fb1b5ae..27ff03365 100644
--- a/cmd/autonomy_tiers_copy_test.go
+++ b/cmd/autonomy_tiers_copy_test.go
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
)
func TestAutonomyTierDescriptions_PlainLanguage(t *testing.T) {
diff --git a/cmd/autonomy_tiers_test.go b/cmd/autonomy_tiers_test.go
index 0cd28911e..f640d7f6a 100644
--- a/cmd/autonomy_tiers_test.go
+++ b/cmd/autonomy_tiers_test.go
@@ -4,7 +4,7 @@ import (
"fmt"
"testing"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
)
func TestAutonomyTierNames(t *testing.T) {
diff --git a/cmd/bg_sessions.go b/cmd/bg_sessions.go
index 1d401fb25..8c6cfb78b 100644
--- a/cmd/bg_sessions.go
+++ b/cmd/bg_sessions.go
@@ -11,12 +11,12 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/storage"
"github.com/spf13/cobra"
)
// ─────────────────────────────────────────────────────────────────────────────
-// Background Sessions — run rho sessions in the background and manage them.
+// Background Sessions — run decoder sessions in the background and manage them.
// ─────────────────────────────────────────────────────────────────────────────
func bgSessionsDir() string {
@@ -119,15 +119,15 @@ func KillBGSession(id string) error {
return SaveBGSession(info)
}
-// StartBGSession launches rho in background mode.
+// StartBGSession launches decoder in background mode.
func StartBGSession(prompt string, args []string) (*BGSessionInfo, error) {
id := genID()
cwd, _ := os.Getwd()
logFile := filepath.Join(bgSessionsDir(), id+".log")
- // Build command: rho --print with all inherited flags
+ // Build command: decoder --print with all inherited flags
cmdArgs := append([]string{"--print", "--session-id", id, prompt}, args...)
- cmd := exec.CommandContext(context.Background(), "rho", cmdArgs...) // #nosec G204 -- fixed command 'rho' relaunching self with internal flags
+ cmd := exec.CommandContext(context.Background(), "decoder", cmdArgs...) // #nosec G204 -- fixed command 'decoder' relaunching self with internal flags
cmd.Dir = cwd
// 0600: the log captures full session output (private user state, matching
@@ -207,11 +207,11 @@ func FormatBGSessions(sessions []*BGSessionInfo) string {
var bgCmd = &cobra.Command{
Use: "bg [prompt]",
Short: "Run a session in the background",
- Long: `Start rho in the background and continue working in your terminal.
+ Long: `Start decoder in the background and continue working in your terminal.
Examples:
- rho bg "Refactor the auth module"
- rho bg "Run tests and fix failures"`,
+ decoder bg "Refactor the auth module"
+ decoder bg "Run tests and fix failures"`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return fmt.Errorf("prompt required")
@@ -229,7 +229,7 @@ Examples:
if len(attachID) > 8 {
attachID = attachID[:8]
}
- cmd.Printf("%s\n", auditTint("Attach: rho attach "+attachID, textMuted))
+ cmd.Printf("%s\n", auditTint("Attach: decoder attach "+attachID, textMuted))
return nil
},
}
diff --git a/cmd/braille_spinner.go b/cmd/braille_spinner.go
index 4de1382ef..79dad54fb 100644
--- a/cmd/braille_spinner.go
+++ b/cmd/braille_spinner.go
@@ -12,8 +12,8 @@ type SpinnerStyle string
const (
SpinnerBraille SpinnerStyle = "braille"
SpinnerBrailleWave SpinnerStyle = "braillewave"
- SpinnerRho SpinnerStyle = "rho"
- SpinnerRhoQuad SpinnerStyle = "rhoquad"
+ SpinnerDecoder SpinnerStyle = "decoder"
+ SpinnerDecoderQuad SpinnerStyle = "decoderquad"
SpinnerDNA SpinnerStyle = "dna"
SpinnerScan SpinnerStyle = "scan"
SpinnerPulse SpinnerStyle = "pulse"
@@ -24,18 +24,18 @@ const (
SpinnerRandom SpinnerStyle = "random"
)
-// rhoSpinnerGlyphs is the default TUI spinner — partial-circle compass (smooth, readable).
-var rhoSpinnerGlyphs = []string{"◐", "◓", "◑", "◒"}
+// decoderSpinnerGlyphs is the default TUI spinner — partial-circle compass (smooth, readable).
+var decoderSpinnerGlyphs = []string{"◐", "◓", "◑", "◒"}
-// rhoQuadBlockGlyphs is the legacy QUADBLOCK animation (kept for tests / bubbles compat).
-var rhoQuadBlockGlyphs = []string{"▛", "▜", "▟", "▙"}
+// decoderQuadBlockGlyphs is the legacy QUADBLOCK animation (kept for tests / bubbles compat).
+var decoderQuadBlockGlyphs = []string{"▛", "▜", "▟", "▙"}
// spinnerFrames maps style names to their animation frames.
var spinnerFrames = map[SpinnerStyle][]string{
SpinnerBraille: {"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
SpinnerBrailleWave: {"⠁⠂⠄⡀", "⠂⠄⡀⢀", "⠄⡀⢀⠠", "⡀⢀⠠⠐", "⢀⠠⠐⠈", "⠠⠐⠈⠁", "⠐⠈⠁⠂", "⠈⠁⠂⠄"},
- SpinnerRho: rhoSpinnerGlyphs,
- SpinnerRhoQuad: rhoQuadBlockGlyphs,
+ SpinnerDecoder: decoderSpinnerGlyphs,
+ SpinnerDecoderQuad: decoderQuadBlockGlyphs,
SpinnerDNA: {"⠋⠉⠙⠚", "⠉⠙⠚⠒", "⠙⠚⠒⠂", "⠚⠒⠂⠂", "⠒⠂⠂⠒", "⠂⠂⠒⠲", "⠂⠒⠲⠴", "⠒⠲⠴⠤", "⠲⠴⠤⠄", "⠴⠤⠄⠋", "⠤⠄⠋⠉", "⠄⠋⠉⠙"},
SpinnerScan: {"⡇⠀⠀⠀", "⣿⠀⠀⠀", "⢸⡇⠀⠀", "⠀⣿⠀⠀", "⠀⢸⡇⠀", "⠀⠀⣿⠀", "⠀⠀⢸⡇", "⠀⠀⠀⣿", "⠀⠀⠀⢸", "⠀⠀⠀⠀"},
SpinnerPulse: {"⠀", "⠄", "⠆", "⠇", "⡇", "⣇", "⣧", "⣷", "⣿", "⣷", "⣧", "⣇", "⡇", "⠇", "⠆", "⠄"},
@@ -45,8 +45,8 @@ var spinnerFrames = map[SpinnerStyle][]string{
SpinnerTalons: {"⩤", "⩥", "⩦", "⩧"},
}
-// rhoTypingDots is the number of trailing typing-indicator dots.
-const rhoTypingDots = 3
+// decoderTypingDots is the number of trailing typing-indicator dots.
+const decoderTypingDots = 3
// BrailleSpinner renders the glyph frame (◐◓◑◒) and a 20-color wave on the
// whole status strip: glyph → verb → ▪▫▫.
@@ -57,7 +57,7 @@ type BrailleSpinner struct {
frame int // glyph animation frame (mod len(frames))
wavePhase int // 0..19 flowing color wave (glyph + verb + dots)
text string
- dots int // 0..rhoTypingDots-1 — position of the highlighted dot
+ dots int // 0..decoderTypingDots-1 — position of the highlighted dot
running bool
stopCh chan struct{}
}
@@ -65,7 +65,7 @@ type BrailleSpinner struct {
// NewBrailleSpinner creates a spinner with the given style and label text.
func NewBrailleSpinner(style SpinnerStyle, text string) *BrailleSpinner {
if style == SpinnerRandom {
- styles := []SpinnerStyle{SpinnerRho, SpinnerBraille, SpinnerBrailleWave, SpinnerDNA, SpinnerScan, SpinnerPulse, SpinnerSnake, SpinnerOrbit}
+ styles := []SpinnerStyle{SpinnerDecoder, SpinnerBraille, SpinnerBrailleWave, SpinnerDNA, SpinnerScan, SpinnerPulse, SpinnerSnake, SpinnerOrbit}
style = styles[rand.Intn(len(styles))] // #nosec G404 -- non-cryptographic use (random spinner style selection)
}
frames := spinnerFrames[style]
@@ -110,7 +110,7 @@ func (s *BrailleSpinner) Tick() string {
s.mu.Lock()
s.frame++
s.wavePhase = (s.wavePhase + 1) % spinnerWaveLen
- s.dots = (s.dots + 1) % rhoTypingDots
+ s.dots = (s.dots + 1) % decoderTypingDots
s.mu.Unlock()
return s.Frame()
}
diff --git a/cmd/braille_spinner_test.go b/cmd/braille_spinner_test.go
index 2375c0ebc..f06db36f3 100644
--- a/cmd/braille_spinner_test.go
+++ b/cmd/braille_spinner_test.go
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func TestBrailleSpinner_Tick(t *testing.T) {
@@ -29,7 +29,7 @@ func TestBrailleSpinner_Tick(t *testing.T) {
func TestBrailleSpinner_AllStyles(t *testing.T) {
styles := []SpinnerStyle{
- SpinnerBraille, SpinnerBrailleWave, SpinnerRho, SpinnerDNA,
+ SpinnerBraille, SpinnerBrailleWave, SpinnerDecoder, SpinnerDNA,
SpinnerScan, SpinnerPulse, SpinnerSnake, SpinnerOrbit,
SpinnerWing, SpinnerTalons,
}
@@ -50,14 +50,14 @@ func TestBrailleSpinner_Random(t *testing.T) {
}
}
-func TestRhoSpinner_Frames(t *testing.T) {
- if len(rhoSpinnerGlyphs) != 4 {
- t.Fatalf("expected 4 compass glyphs, got %d", len(rhoSpinnerGlyphs))
+func TestDecoderSpinner_Frames(t *testing.T) {
+ if len(decoderSpinnerGlyphs) != 4 {
+ t.Fatalf("expected 4 compass glyphs, got %d", len(decoderSpinnerGlyphs))
}
- if rhoSpinnerGlyphs[0] != "◐" {
- t.Fatalf("expected first compass frame ◐, got %q", rhoSpinnerGlyphs[0])
+ if decoderSpinnerGlyphs[0] != "◐" {
+ t.Fatalf("expected first compass frame ◐, got %q", decoderSpinnerGlyphs[0])
}
- s := NewBrailleSpinner(SpinnerRho, "Working")
+ s := NewBrailleSpinner(SpinnerDecoder, "Working")
f0 := s.Frame()
if !strings.Contains(f0, "◐") {
t.Fatalf("expected compass glyph, got %q", f0)
@@ -70,20 +70,20 @@ func TestRhoSpinner_Frames(t *testing.T) {
}
}
-func TestRhoQuadBlock_LegacyFrames(t *testing.T) {
- s := NewBrailleSpinner(SpinnerRhoQuad, "Working")
+func TestDecoderQuadBlock_LegacyFrames(t *testing.T) {
+ s := NewBrailleSpinner(SpinnerDecoderQuad, "Working")
if !strings.Contains(s.Frame(), "▛") {
t.Fatalf("expected QuadBlock glyph, got %q", s.Frame())
}
}
-func TestRhoAnimatedDots_PresentInFrame(t *testing.T) {
- s := NewBrailleSpinner(SpinnerRho, "Crafting")
+func TestDecoderAnimatedDots_PresentInFrame(t *testing.T) {
+ s := NewBrailleSpinner(SpinnerDecoder, "Crafting")
f := s.Frame()
// Three progress dots ride after the verb: one bright, two dim.
total := strings.Count(f, icons.CircleFilled()) + strings.Count(f, icons.CircleOutline())
- if total != rhoTypingDots {
- t.Errorf("expected %d trailing circle-dots, got %d in %q", rhoTypingDots, total, f)
+ if total != decoderTypingDots {
+ t.Errorf("expected %d trailing circle-dots, got %d in %q", decoderTypingDots, total, f)
}
// Tick advances the highlighted dot position.
idxBefore := s.dots
diff --git a/cmd/cascade_diag_test.go b/cmd/cascade_diag_test.go
index 521bd443f..2c11d875b 100644
--- a/cmd/cascade_diag_test.go
+++ b/cmd/cascade_diag_test.go
@@ -3,14 +3,14 @@ package cmd
import (
"testing"
- rhobranch "github.com/GrayCodeAI/rho/internal/engine/branching"
- "github.com/GrayCodeAI/rho/internal/provider/routing"
+ decoderbranch "github.com/GrayCodeAI/decoder/internal/engine/branching"
+ "github.com/GrayCodeAI/decoder/internal/provider/routing"
)
func TestCascadeSelectsForOpenCodeGoHi(t *testing.T) {
roles := routing.DefaultRoles("opencodego/minimax-m2.5")
t.Logf("cheapest=%s commit=%s", routing.CheapestForProvider("opencodego", "minimax-m2.5"), roles.Commit)
- cr := rhobranch.NewCascadeRouter("opencodego/minimax-m2.5", roles)
+ cr := decoderbranch.NewCascadeRouter("opencodego/minimax-m2.5", roles)
cr.Enabled = true
got := cr.SelectModel("Hi", "opencodego/minimax-m2.5", "")
t.Logf("selected=%s", got)
diff --git a/cmd/catalog_startup.go b/cmd/catalog_startup.go
index 5bf74fde8..84f9cf99a 100644
--- a/cmd/catalog_startup.go
+++ b/cmd/catalog_startup.go
@@ -4,7 +4,7 @@ import (
"context"
"os"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
var (
@@ -13,15 +13,15 @@ var (
)
func ensureCatalogBeforeAgent(ctx context.Context, strict bool) error {
- opts := rhoconfig.CatalogStartupOptions{
+ opts := decoderconfig.CatalogStartupOptions{
ForceRefresh: refreshCatalogFlag,
SkipAutoRefresh: skipCatalogRefreshFlag,
VerboseOutput: refreshCatalogFlag,
}
if strict {
- return rhoconfig.PrepareCatalogForSession(ctx, os.Stderr, opts)
+ return decoderconfig.PrepareCatalogForSession(ctx, os.Stderr, opts)
}
- rhoconfig.StartupCatalogPrefetch(ctx)
+ decoderconfig.StartupCatalogPrefetch(ctx)
return nil
}
@@ -29,5 +29,5 @@ func startBackgroundCatalogRefresh(ctx context.Context) {
if skipCatalogRefreshFlag {
return
}
- rhoconfig.ScheduleBackgroundCatalogRefresh(ctx)
+ decoderconfig.ScheduleBackgroundCatalogRefresh(ctx)
}
diff --git a/cmd/chat.go b/cmd/chat.go
index 5873baf85..c1a064348 100644
--- a/cmd/chat.go
+++ b/cmd/chat.go
@@ -16,7 +16,7 @@ import (
"syscall"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
"golang.org/x/term"
@@ -27,23 +27,23 @@ import (
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/bridge/sessioncapture"
- "github.com/GrayCodeAI/rho/internal/codegraph"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- chatfeature "github.com/GrayCodeAI/rho/internal/features/chat"
- sessionfeature "github.com/GrayCodeAI/rho/internal/features/session"
- "github.com/GrayCodeAI/rho/internal/features/shellmode"
- "github.com/GrayCodeAI/rho/internal/features/taste"
- "github.com/GrayCodeAI/rho/internal/intelligence/repomap"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/startup"
- rhostorage "github.com/GrayCodeAI/rho/internal/storage"
- "github.com/GrayCodeAI/rho/internal/system/staleness"
- "github.com/GrayCodeAI/rho/internal/tool"
- "github.com/GrayCodeAI/rho/internal/tui"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/bridge/sessioncapture"
+ "github.com/GrayCodeAI/decoder/internal/codegraph"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ chatfeature "github.com/GrayCodeAI/decoder/internal/features/chat"
+ sessionfeature "github.com/GrayCodeAI/decoder/internal/features/session"
+ "github.com/GrayCodeAI/decoder/internal/features/shellmode"
+ "github.com/GrayCodeAI/decoder/internal/features/taste"
+ "github.com/GrayCodeAI/decoder/internal/intelligence/repomap"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/startup"
+ decoderstorage "github.com/GrayCodeAI/decoder/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/system/staleness"
+ "github.com/GrayCodeAI/decoder/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/tui"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// Types, styles, and model struct are in chat_model.go
@@ -52,7 +52,7 @@ import (
// Tool-registry construction (essential/optional tools) is in chat_tools.go
// The Bubble Tea event loop (Update, applyPromptArrowKey) is in chat_update.go
-const workInputPlaceholder = `Ask Rho to inspect, edit, or run something... (Shift+Enter for newline, ? for help)`
+const workInputPlaceholder = `Ask Decoder to inspect, edit, or run something... (Shift+Enter for newline, ? for help)`
func genID() string {
b := make([]byte, 8)
@@ -73,7 +73,7 @@ func prepareSession(sess *engine.Session) (string, *session.Session, error) {
}
if sessionIDFlag != "" && (resumeID != "" || continueFlag) {
// --session-id is ignored when --resume or --continue is also given.
- fmt.Fprintf(os.Stderr, "%s\n", auditTint("rho: --session-id ignored during resume/continue", textMuted))
+ fmt.Fprintf(os.Stderr, "%s\n", auditTint("decoder: --session-id ignored during resume/continue", textMuted))
}
if resumeID == "" && !continueFlag {
return id, nil, nil
@@ -107,7 +107,7 @@ func prepareSession(sess *engine.Session) (string, *session.Session, error) {
return saved.ID, saved, nil
}
-func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhoconfig.Settings, registry *tool.Registry) (chatModel, error) {
+func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings decoderconfig.Settings, registry *tool.Registry) (chatModel, error) {
startup.MarkPhase("newChatModel:total")
startup.MarkPhase("newChatModel:ui-init")
@@ -127,15 +127,15 @@ func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhocon
CursorLine: lipgloss.NewStyle(),
Base: lipgloss.NewStyle().Foreground(textPrimary),
Placeholder: lipgloss.NewStyle().Foreground(textPlaceholder),
- Prompt: lipgloss.NewStyle().Foreground(rhoColor).Bold(true),
+ Prompt: lipgloss.NewStyle().Foreground(decoderColor).Bold(true),
},
Blurred: textarea.StyleState{
Base: lipgloss.NewStyle().Foreground(textPlaceholder),
Placeholder: lipgloss.NewStyle().Foreground(textPlaceholder),
- Prompt: lipgloss.NewStyle().Foreground(rhoColor).Bold(true),
+ Prompt: lipgloss.NewStyle().Foreground(decoderColor).Bold(true),
},
Cursor: textarea.CursorStyle{
- Color: rhoColor,
+ Color: decoderColor,
},
})
ta.Prompt = icons.ChevronRight() + " "
@@ -147,8 +147,8 @@ func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhocon
ci.EchoMode = textinput.EchoNormal
sp := spinner.New()
- sp.Spinner = spinner.Spinner{Frames: rhoSpinnerFrames, FPS: rhoSpinnerFrameInterval}
- sp.Style = lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
+ sp.Spinner = spinner.Spinner{Frames: decoderSpinnerFrames, FPS: decoderSpinnerFrameInterval}
+ sp.Style = lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
startup.EndPhase("newChatModel:ui-init")
startup.MarkPhase("newChatModel:effectiveModelAndProvider")
@@ -159,9 +159,9 @@ func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhocon
startup.MarkPhase("newChatModel:defaultRegistry")
startup.EndPhase("newChatModel:defaultRegistry")
- startup.MarkPhase("newChatModel:newRhoSession")
- sess := newStartupRhoSession(selection, systemPrompt, registry)
- startup.EndPhase("newChatModel:newRhoSession")
+ startup.MarkPhase("newChatModel:newDecoderSession")
+ sess := newStartupDecoderSession(selection, systemPrompt, registry)
+ startup.EndPhase("newChatModel:newDecoderSession")
startup.MarkPhase("newChatModel:configureSession")
if cfgErr := prepareInteractiveSessionStartup(sess, settings); cfgErr != nil {
@@ -185,7 +185,7 @@ func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhocon
// Initialize conversation DAG for branching support
startup.MarkPhase("newChatModel:dag")
- graphPath := filepath.Join(rhostorage.SessionsDir(), "conversations", sid+".json")
+ graphPath := filepath.Join(decoderstorage.SessionsDir(), "conversations", sid+".json")
if graph, err := session.OpenConversationGraph(graphPath, sid); err == nil {
sess.SetConversationGraph(graph)
}
@@ -204,7 +204,7 @@ func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhocon
now := time.Now()
// Create a cancel function for background goroutines that gets called on quit.
_, bgCancel := context.WithCancel(context.Background())
- m := chatModel{input: ta, configInput: ci, spinner: sp, viewport: vp, session: sess, registry: registry, settings: settings, ref: ref, sessionID: sid, partial: &strings.Builder{}, spinnerVerb: spinnerVerbs[rand.Intn(len(spinnerVerbs))], width: initWidth, height: initHeight, history: chatfeature.NewHistory(nil, chatfeature.DefaultHistoryLimit), autoScroll: true, streamFollow: true, uiFocus: focusPrompt, startedAt: now, sessionStartedAt: now, activeSkills: make(map[string]plugin.SmartSkill), toolResultExpanded: make(map[int]bool), bgCancel: bgCancel, mascotEnabled: rhoMascotEnabled()} // #nosec G404 -- non-cryptographic use: non-cryptographic spinner selection
+ m := chatModel{input: ta, configInput: ci, spinner: sp, viewport: vp, session: sess, registry: registry, settings: settings, ref: ref, sessionID: sid, partial: &strings.Builder{}, spinnerVerb: spinnerVerbs[rand.Intn(len(spinnerVerbs))], width: initWidth, height: initHeight, history: chatfeature.NewHistory(nil, chatfeature.DefaultHistoryLimit), autoScroll: true, streamFollow: true, uiFocus: focusPrompt, startedAt: now, sessionStartedAt: now, activeSkills: make(map[string]plugin.SmartSkill), toolResultExpanded: make(map[int]bool), bgCancel: bgCancel, mascotEnabled: decoderMascotEnabled()} // #nosec G404 -- non-cryptographic use: non-cryptographic spinner selection
applyLiveModelMetadata(sess, effectiveProvider, effectiveModel)
startup.MarkPhase("newChatModel:commandPalette")
@@ -245,7 +245,7 @@ func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhocon
m.contextualHelp = NewContextualHelp()
m.modeManager = shellmode.NewModeManager()
m.modeManager.LoadPersistedMode()
- m.brailleSpinner = NewBrailleSpinner(SpinnerRho, "")
+ m.brailleSpinner = NewBrailleSpinner(SpinnerDecoder, "")
m.brailleSpinner.SetLabel(m.spinnerVerb)
startup.EndPhase("newChatModel:lacy-features")
@@ -288,8 +288,8 @@ func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhocon
// Prefetch live models for the active provider so footer ctx/pricing stay current.
go func() {
providerName := effectiveProvider
- entries, _ := rhoconfig.ListEngineModels(context.Background(), providerName, false)
- opts := configModelOptionsFromFlux(entries)
+ entries, _ := decoderconfig.ListEngineModels(context.Background(), providerName, false)
+ opts := configModelOptionsFromMux(entries)
if len(opts) > 0 {
modelCacheMu.Lock()
modelCache[providerName] = opts
@@ -315,7 +315,7 @@ func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhocon
m.welcomeCache = buildWelcomeMessageWithSnapshotAndMascot(sess, sid, registry, saved, settings, 0, connectedMCPCount(registry), 0, initWidth, initHeight, quickSnapshot, "", m.mascotEnabled)
m.messages = append(m.messages, displayMsg{role: "welcome", content: m.welcomeCache})
// First-session control-plane tip (skip when resuming history or when quiet env var is set).
- if saved == nil && os.Getenv("RHO_QUIET_START") == "" && os.Getenv("RHO_SUPPRESS_HINTS") == "" && os.Getenv("RHO_QUIET") == "" {
+ if saved == nil && os.Getenv("DECODER_QUIET_START") == "" && os.Getenv("DECODER_SUPPRESS_HINTS") == "" && os.Getenv("DECODER_QUIET") == "" {
m.messages = append(m.messages, displayMsg{role: "system", content: controlPlaneOnboardingHint(sess)})
}
startup.EndPhase("newChatModel:welcome")
@@ -388,7 +388,7 @@ func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhocon
// the initial UI.
go func(currentSessionID string) {
if recovered := session.CheckForRecovery(); len(recovered) > 0 {
- walDir := rhostorage.SessionsDir()
+ walDir := decoderstorage.SessionsDir()
for _, rid := range recovered {
if rid == currentSessionID {
continue // current session WAL
@@ -404,7 +404,7 @@ func newChatModelWithRegistry(ref *progRef, systemPrompt string, settings rhocon
// Warm footer data and the model catalog after the first frame.
go func(model chatModel) {
startup.MarkPhase("newChatModel:ui-cache-warm")
- rhoconfig.RefreshConfigCredSnapshot(context.Background())
+ decoderconfig.RefreshConfigCredSnapshot(context.Background())
// Network reachability runs off the startup critical path: an offline
// machine stalls here (background) instead of before first paint.
if msg := checkNetworkReachability(model.settings); msg != "" {
@@ -543,7 +543,7 @@ func (m *chatModel) refreshInputPlaceholder() {
func (m chatModel) Init() tea.Cmd {
cmds := []tea.Cmd{initTerminalMouseCmd(m.mouseEnabled()), promptKeepAliveCmd(), eyeBlinkTickCmd()}
if m.mascotEnabled {
- cmds = append(cmds, emitRhoMascotCmd())
+ cmds = append(cmds, emitDecoderMascotCmd())
}
if gw, _ := m.sessionGatewayModel(); strings.TrimSpace(gw) != "" {
cmds = append(cmds, fetchModelsAsync(gw))
@@ -610,7 +610,7 @@ func runChat() error {
// One-time, gated codebase analysis for projects with no context file.
// Runs in the background and never blocks startup; fully opt-out via
- // RHO_DISABLE_AUTO_INIT. No-op for projects that already have context.
+ // DECODER_DISABLE_AUTO_INIT. No-op for projects that already have context.
maybeAutoInit(context.Background())
ref := &progRef{}
@@ -619,7 +619,7 @@ func runChat() error {
err error
}
type startupSettingsResult struct {
- settings rhoconfig.Settings
+ settings decoderconfig.Settings
err error
}
type startupRegistryResult struct {
@@ -683,7 +683,7 @@ func runChat() error {
m.waiting = true
}
- // Suppress library log output (e.g. flux retry warnings) from corrupting the TUI.
+ // Suppress library log output (e.g. mux retry warnings) from corrupting the TUI.
// Must be set BEFORE tea.NewProgram so no initialization logs leak through.
log.SetOutput(io.Discard)
@@ -747,10 +747,10 @@ func runChat() error {
// frame and any terminal-persistent mascot so shutdown has one clean,
// predictable final state.
fmt.Print("\x1b[2J\x1b[H")
- fmt.Println("Thank you for using Rho!")
+ fmt.Println("Thank you for using Decoder!")
return nil
}
- rhoC := ansiOrange
+ decoderC := ansiOrange
rst := ansiReset
fmt.Print(fm.welcomeCache)
@@ -758,10 +758,10 @@ func runChat() error {
for _, msg := range fm.messages {
switch msg.role {
case "user":
- fmt.Println(rhoC + "█" + rst + " " + msg.content)
+ fmt.Println(decoderC + "█" + rst + " " + msg.content)
fmt.Println()
case "assistant":
- fmt.Println(rhoC + icons.Robot() + " " + rst + msg.content)
+ fmt.Println(decoderC + icons.Robot() + " " + rst + msg.content)
fmt.Println()
case "system":
fmt.Println(dimStyle.Render("● " + msg.content))
@@ -793,12 +793,12 @@ func runChat() error {
border := strings.Repeat("─", viewWidth)
borderStyle := lipgloss.NewStyle().Foreground(borderDim)
fmt.Println(borderStyle.Render(border))
- fmt.Println(lipgloss.NewStyle().Foreground(rhoColor).Bold(true).Render(">") + " ")
+ fmt.Println(lipgloss.NewStyle().Foreground(decoderColor).Bold(true).Render(">") + " ")
fmt.Println(borderStyle.Render(border))
fmt.Println(dimStyle.Render("? for help"))
if fm.sessionID != "" {
- fmt.Println(dimStyle.Render(fmt.Sprintf("To resume this session, run: rho --resume %s", fm.sessionID)))
+ fmt.Println(dimStyle.Render(fmt.Sprintf("To resume this session, run: decoder --resume %s", fm.sessionID)))
}
return nil
}
diff --git a/cmd/chat_commands.go b/cmd/chat_commands.go
index db33636f8..eb97580aa 100644
--- a/cmd/chat_commands.go
+++ b/cmd/chat_commands.go
@@ -12,11 +12,11 @@ import (
tea "charm.land/bubbletea/v2"
- commandfeature "github.com/GrayCodeAI/rho/internal/features/commands"
- parallelfeature "github.com/GrayCodeAI/rho/internal/features/parallel"
- "github.com/GrayCodeAI/rho/internal/multiagent/parallel"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ commandfeature "github.com/GrayCodeAI/decoder/internal/features/commands"
+ parallelfeature "github.com/GrayCodeAI/decoder/internal/features/parallel"
+ "github.com/GrayCodeAI/decoder/internal/multiagent/parallel"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// slashCmdCache caches the slash commands list to avoid rebuilding.
diff --git a/cmd/chat_commands_config.go b/cmd/chat_commands_config.go
index 4db437b8a..b4ffd1242 100644
--- a/cmd/chat_commands_config.go
+++ b/cmd/chat_commands_config.go
@@ -6,8 +6,8 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- configfeature "github.com/GrayCodeAI/rho/internal/features/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ configfeature "github.com/GrayCodeAI/decoder/internal/features/config"
)
// handleConfigCommand handles /config policy through the feature parser and
@@ -21,7 +21,7 @@ func (m *chatModel) handleConfigCommand(parts []string, text string) (tea.Model,
switch command.Action {
case configfeature.ActionProvider:
- if err := rhoconfig.SetGlobalSetting("provider", command.Value); err != nil {
+ if err := decoderconfig.SetGlobalSetting("provider", command.Value); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
return m, nil
}
@@ -31,9 +31,9 @@ func (m *chatModel) handleConfigCommand(parts []string, text string) (tea.Model,
modelCacheMu.RUnlock()
if cacheHit && len(cached) > 0 {
m.session.SetModel(cached[0].ID)
- _ = rhoconfig.SetGlobalSetting("model", cached[0].ID)
+ _ = decoderconfig.SetGlobalSetting("model", cached[0].ID)
}
- m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Provider set to: %s\nModel: %s\nSaved in flux (provider.json).", command.Value, m.session.Model())})
+ m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Provider set to: %s\nModel: %s\nSaved in mux (provider.json).", command.Value, m.session.Model())})
return m, nil
case configfeature.ActionModel:
@@ -53,12 +53,12 @@ func (m *chatModel) handleConfigCommand(parts []string, text string) (tea.Model,
return m, nil
}
}
- if err := rhoconfig.SetGlobalSetting("model", value); err != nil {
+ if err := decoderconfig.SetGlobalSetting("model", value); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
return m, nil
}
m.syncSessionSelection()
- m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Model switched to: %s\nSaved in flux (provider.json).", m.session.Model())})
+ m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Model switched to: %s\nSaved in mux (provider.json).", m.session.Model())})
return m, nil
case configfeature.ActionKeys:
@@ -74,7 +74,7 @@ func (m *chatModel) handleConfigCommand(parts []string, text string) (tea.Model,
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
return m, nil
}
- value, ok := rhoconfig.SettingValue(settings, command.Key)
+ value, ok := decoderconfig.SettingValue(settings, command.Key)
if !ok {
m.messages = append(m.messages, displayMsg{role: "error", content: fmt.Sprintf("Unsupported setting key %q", command.Key)})
return m, nil
@@ -86,7 +86,7 @@ func (m *chatModel) handleConfigCommand(parts []string, text string) (tea.Model,
return m, nil
case configfeature.ActionSet:
- if err := rhoconfig.SetGlobalSetting(command.Key, command.Value); err != nil {
+ if err := decoderconfig.SetGlobalSetting(command.Key, command.Value); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
return m, nil
}
diff --git a/cmd/chat_commands_image.go b/cmd/chat_commands_image.go
index bfdab010b..5c6d0bac7 100644
--- a/cmd/chat_commands_image.go
+++ b/cmd/chat_commands_image.go
@@ -8,7 +8,7 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// handleImageCommand implements the /image slash command:
@@ -17,7 +17,7 @@ import (
//
// It reads an image (or PDF) file, builds a multimodal user message gated on the
// active model's vision capability, and starts a turn. For PDFs the text is
-// extracted and injected inline (flux has no native document block). Without a
+// extracted and injected inline (mux has no native document block). Without a
// vision-capable model the image degrades to a text-only note.
func (m *chatModel) handleImageCommand(parts []string, text string) (tea.Model, tea.Cmd) {
if len(parts) < 2 {
diff --git a/cmd/chat_commands_session.go b/cmd/chat_commands_session.go
index bd8ebac4c..de489afc5 100644
--- a/cmd/chat_commands_session.go
+++ b/cmd/chat_commands_session.go
@@ -7,9 +7,9 @@ import (
tea "charm.land/bubbletea/v2"
- sessionfeature "github.com/GrayCodeAI/rho/internal/features/session"
- workspacefeature "github.com/GrayCodeAI/rho/internal/features/workspace"
- "github.com/GrayCodeAI/rho/internal/session"
+ sessionfeature "github.com/GrayCodeAI/decoder/internal/features/session"
+ workspacefeature "github.com/GrayCodeAI/decoder/internal/features/workspace"
+ "github.com/GrayCodeAI/decoder/internal/session"
)
type sessionSaveResultMsg struct {
@@ -415,7 +415,7 @@ func (m *chatModel) handleSessionCommand(cmd string, parts []string, text string
case "/session":
info := fmt.Sprintf("Session: %s\nModel: %s/%s\nSpec stage: %s\nMessages: %d\nTools: %d\n%s",
m.sessionID, m.session.Provider(), m.session.Model(),
- specStageLabel(m.session), m.session.MessageCount(), len(m.registry.FluxTools()), m.session.CostValue().Summary())
+ specStageLabel(m.session), m.session.MessageCount(), len(m.registry.MuxTools()), m.session.CostValue().Summary())
m.messages = append(m.messages, displayMsg{role: "system", content: info})
return m, nil
diff --git a/cmd/chat_commands_skills.go b/cmd/chat_commands_skills.go
index 2d2450bf3..6c4e012fb 100644
--- a/cmd/chat_commands_skills.go
+++ b/cmd/chat_commands_skills.go
@@ -10,9 +10,9 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/tool"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// handleSkillsCommand handles the /skills command and all its subcommands.
diff --git a/cmd/chat_commands_test.go b/cmd/chat_commands_test.go
index c7f27e4e5..845357415 100644
--- a/cmd/chat_commands_test.go
+++ b/cmd/chat_commands_test.go
@@ -6,9 +6,9 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/tool"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
func TestAdditionalDirContextLoadsInstructions(t *testing.T) {
@@ -69,7 +69,7 @@ func TestLocalSlashCommands(t *testing.T) {
m := &chatModel{
session: sess,
registry: tool.NewRegistry(tool.LSTool{}),
- settings: rhoconfig.Settings{MCPServers: []rhoconfig.MCPServerConfig{{Name: "demo", Command: "demo-mcp"}}},
+ settings: decoderconfig.Settings{MCPServers: []decoderconfig.MCPServerConfig{{Name: "demo", Command: "demo-mcp"}}},
sessionID: "test",
width: 80,
height: 24,
@@ -94,16 +94,16 @@ func TestLocalSlashCommands(t *testing.T) {
func TestDiagnosticSummaries(t *testing.T) {
preserveCLICompilerVersionState(t)
version = "test-version"
- settings := rhoconfig.Settings{
+ settings := decoderconfig.Settings{
Provider: "openai",
Model: "gpt-4o",
- MCPServers: []rhoconfig.MCPServerConfig{
+ MCPServers: []decoderconfig.MCPServerConfig{
{Name: "demo", Command: "demo-mcp", Args: []string{"--stdio"}},
},
}
report := doctorReport(settings)
- if !strings.Contains(report, "Rho doctor") || !strings.Contains(report, "Built-in tools") {
+ if !strings.Contains(report, "Decoder doctor") || !strings.Contains(report, "Built-in tools") {
t.Fatalf("unexpected doctor report: %s", report)
}
if summary := mcpConfigSummary(settings); !strings.Contains(summary, "demo") {
diff --git a/cmd/chat_commands_tools.go b/cmd/chat_commands_tools.go
index 93d1112a8..d8042ccae 100644
--- a/cmd/chat_commands_tools.go
+++ b/cmd/chat_commands_tools.go
@@ -7,10 +7,10 @@ import (
tea "charm.land/bubbletea/v2"
- explainfeature "github.com/GrayCodeAI/rho/internal/features/explain"
- "github.com/GrayCodeAI/rho/internal/features/shellmode"
- skillsfeature "github.com/GrayCodeAI/rho/internal/features/skills"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ explainfeature "github.com/GrayCodeAI/decoder/internal/features/explain"
+ "github.com/GrayCodeAI/decoder/internal/features/shellmode"
+ skillsfeature "github.com/GrayCodeAI/decoder/internal/features/skills"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// explainCode traces a file/line back to the git commit and session that created it.
diff --git a/cmd/chat_commands_util.go b/cmd/chat_commands_util.go
index e2ca1c5fb..fceaba19d 100644
--- a/cmd/chat_commands_util.go
+++ b/cmd/chat_commands_util.go
@@ -4,11 +4,11 @@ import (
"fmt"
"strings"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/features/taste"
- workspacefeature "github.com/GrayCodeAI/rho/internal/features/workspace"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/system/staleness"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/features/taste"
+ workspacefeature "github.com/GrayCodeAI/decoder/internal/features/workspace"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/system/staleness"
)
func gitOutput(args ...string) (string, error) {
@@ -56,7 +56,7 @@ func (m *chatModel) mcpSummary() string {
}
if m.registry != nil {
var toolNames []string
- for _, t := range m.registry.FluxTools() {
+ for _, t := range m.registry.MuxTools() {
if strings.HasPrefix(t.Name, "mcp__") {
toolNames = append(toolNames, t.Name)
}
@@ -77,7 +77,7 @@ func sessionStats(sess *engine.Session, id string) string {
}
func hooksSummary() string {
- return "Hooks: pre_query, post_query, pre_tool, post_tool, session_start, session_end, permission_ask, error\nConfigure in Rho user settings"
+ return "Hooks: pre_query, post_query, pre_tool, post_tool, session_start, session_end, permission_ask, error\nConfigure in Decoder user settings"
}
func pluginsSummary(rt *plugin.Runtime) string {
diff --git a/cmd/chat_config_deployment.go b/cmd/chat_config_deployment.go
index 62f159396..f69a1c969 100644
--- a/cmd/chat_config_deployment.go
+++ b/cmd/chat_config_deployment.go
@@ -9,9 +9,9 @@ import (
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
type configApplyCredentialsMsg struct {
@@ -24,39 +24,39 @@ type configApplyCredentialsMsg struct {
func firstRunModelProvider(m chatModel) string {
ctx := context.Background()
- if p := strings.TrimSpace(m.configModelProvider); p != "" && rhoconfig.HasStoredCredentialForProvider(ctx, p) {
+ if p := strings.TrimSpace(m.configModelProvider); p != "" && decoderconfig.HasStoredCredentialForProvider(ctx, p) {
return p
}
if m.session != nil {
- if p := strings.TrimSpace(m.session.Provider()); p != "" && rhoconfig.HasStoredCredentialForProvider(ctx, p) {
+ if p := strings.TrimSpace(m.session.Provider()); p != "" && decoderconfig.HasStoredCredentialForProvider(ctx, p) {
return p
}
}
- if p := strings.TrimSpace(rhoconfig.ActiveGateway(ctx)); p != "" && rhoconfig.HasStoredCredentialForProvider(ctx, p) {
+ if p := strings.TrimSpace(decoderconfig.ActiveGateway(ctx)); p != "" && decoderconfig.HasStoredCredentialForProvider(ctx, p) {
return p
}
- if p := rhoconfig.DefaultModelProviderFilter(ctx); p != "" && rhoconfig.HasStoredCredentialForProvider(ctx, p) {
+ if p := decoderconfig.DefaultModelProviderFilter(ctx); p != "" && decoderconfig.HasStoredCredentialForProvider(ctx, p) {
return p
}
- for _, p := range rhoconfig.AllSetupGateways() {
- if rhoconfig.HasStoredCredentialForProvider(ctx, p) {
+ for _, p := range decoderconfig.AllSetupGateways() {
+ if decoderconfig.HasStoredCredentialForProvider(ctx, p) {
return p
}
}
return ""
}
-func saveProviderKeyAsync(inference rhoconfig.CredentialInference, secret string) tea.Cmd {
+func saveProviderKeyAsync(inference decoderconfig.CredentialInference, secret string) tea.Cmd {
return saveCredentialAsync(inference, secret)
}
func saveOllamaAsync(baseURL string) tea.Cmd {
return func() tea.Msg {
- inference, err := rhoconfig.LocalCredentialInference(configProviderOllama)
+ inference, err := decoderconfig.LocalCredentialInference(configProviderOllama)
if err != nil {
return configApplyCredentialsMsg{err: err}
}
- inf := rhoconfig.CredentialInference{
+ inf := decoderconfig.CredentialInference{
ProviderID: inference.ProviderID,
DeploymentID: inference.DeploymentID,
EnvVar: inference.EnvVar,
@@ -66,22 +66,22 @@ func saveOllamaAsync(baseURL string) tea.Cmd {
}
}
-func saveCredentialAsync(inference rhoconfig.CredentialInference, secret string) tea.Cmd {
+func saveCredentialAsync(inference decoderconfig.CredentialInference, secret string) tea.Cmd {
return func() tea.Msg {
ctx := context.Background()
- if err := rhoconfig.SaveCredential(ctx, inference, secret); err != nil {
+ if err := decoderconfig.SaveCredential(ctx, inference, secret); err != nil {
return configApplyCredentialsMsg{
err: err,
providerID: inference.ProviderID,
deploymentID: inference.DeploymentID,
}
}
- rhoconfig.InvalidateConfigUICache()
- rhoconfig.RefreshConfigCredSnapshot(ctx)
- result, err := rhoconfig.ApplyFluxCredentialsForProvider(ctx, inference.ProviderID)
- if err != nil && rhoconfig.IsCatalogCacheRequired(err) {
- if refreshErr := rhoconfig.RefreshCatalogAfterCredentials(ctx, nil); refreshErr == nil {
- result, err = rhoconfig.ApplyFluxCredentialsForProvider(ctx, inference.ProviderID)
+ decoderconfig.InvalidateConfigUICache()
+ decoderconfig.RefreshConfigCredSnapshot(ctx)
+ result, err := decoderconfig.ApplyMuxCredentialsForProvider(ctx, inference.ProviderID)
+ if err != nil && decoderconfig.IsCatalogCacheRequired(err) {
+ if refreshErr := decoderconfig.RefreshCatalogAfterCredentials(ctx, nil); refreshErr == nil {
+ result, err = decoderconfig.ApplyMuxCredentialsForProvider(ctx, inference.ProviderID)
} else {
err = fmt.Errorf("%w; automatic catalog refresh failed: %w", err, refreshErr)
}
@@ -94,7 +94,7 @@ func saveCredentialAsync(inference rhoconfig.CredentialInference, secret string)
}
}
- entries, listErr := rhoconfig.ListEngineModels(ctx, inference.ProviderID, false)
+ entries, listErr := decoderconfig.ListEngineModels(ctx, inference.ProviderID, false)
if listErr != nil {
return configApplyCredentialsMsg{
err: listErr,
@@ -102,9 +102,9 @@ func saveCredentialAsync(inference rhoconfig.CredentialInference, secret string)
deploymentID: inference.DeploymentID,
}
}
- opts := configModelOptionsFromFlux(entries)
+ opts := configModelOptionsFromMux(entries)
return configApplyCredentialsMsg{
- summary: rhoconfig.FormatApplyCredentialsSummary(result),
+ summary: decoderconfig.FormatApplyCredentialsSummary(result),
providerID: inference.ProviderID,
deploymentID: inference.DeploymentID,
modelOptions: opts,
@@ -134,15 +134,15 @@ func (m chatModel) startConfigURLInput(defaultURL string) (chatModel, tea.Cmd) {
m.configInput.EchoMode = textinput.EchoNormal
m.configInput.SetStyles(textinput.Styles{
Focused: textinput.StyleState{
- Prompt: lipgloss.NewStyle().Foreground(rhoColor).Bold(true),
+ Prompt: lipgloss.NewStyle().Foreground(decoderColor).Bold(true),
Text: lipgloss.NewStyle().Foreground(textPrimary),
},
Blurred: textinput.StyleState{
- Prompt: lipgloss.NewStyle().Foreground(rhoColor).Bold(true),
+ Prompt: lipgloss.NewStyle().Foreground(decoderColor).Bold(true),
Text: lipgloss.NewStyle().Foreground(textPrimary),
},
Cursor: textinput.CursorStyle{
- Color: rhoColor,
+ Color: decoderColor,
},
})
m.configInput.Focus()
@@ -152,27 +152,27 @@ func (m chatModel) startConfigURLInput(defaultURL string) (chatModel, tea.Cmd) {
func (m chatModel) handleConfigApplyCredentialsMsg(msg configApplyCredentialsMsg) (chatModel, tea.Cmd) {
m.configSaving = false
ctx := context.Background()
- rhoconfig.RefreshConfigCredSnapshot(ctx)
+ decoderconfig.RefreshConfigCredSnapshot(ctx)
m = m.refreshConfigGatewayRows()
if msg.err != nil {
m.invalidateConnStatus()
if msg.providerID == configProviderOllama {
return m.returnToOllamaURLAfterError(msg.err)
}
- notice := sanitizeConfigNotice(rhoconfig.FormatConfigProviderError(msg.providerID, msg.err))
- saved := rhoconfig.HasStoredCredentialForProvider(ctx, msg.providerID) ||
+ notice := sanitizeConfigNotice(decoderconfig.FormatConfigProviderError(msg.providerID, msg.err))
+ saved := decoderconfig.HasStoredCredentialForProvider(ctx, msg.providerID) ||
strings.Contains(strings.ToLower(msg.err.Error()), "key saved in keychain")
if saved {
- if rhoconfig.IsCatalogCacheRequired(msg.err) {
+ if decoderconfig.IsCatalogCacheRequired(msg.err) {
notice = "Key saved in " + credentialsStoreLabel() + " — model catalog unavailable: " + notice
- notice += " · run rho models refresh"
+ notice += " · run decoder models refresh"
} else if configCredentialRejected(msg.err) {
notice = "Key saved in " + credentialsStoreLabel() + " — provider rejected this key: " + notice
} else {
notice = "Key saved in " + credentialsStoreLabel() + " — catalog refresh failed: " + notice
}
- if !rhoconfig.IsCatalogCacheRequired(msg.err) && !strings.Contains(strings.ToLower(notice), "refresh") {
- notice += " · press r on " + rhoconfig.GatewayDisplayName(msg.providerID) + " to retry"
+ if !decoderconfig.IsCatalogCacheRequired(msg.err) && !strings.Contains(strings.ToLower(notice), "refresh") {
+ notice += " · press r on " + decoderconfig.GatewayDisplayName(msg.providerID) + " to retry"
}
} else {
notice = "Could not save key — " + notice
@@ -206,11 +206,11 @@ func (m chatModel) handleConfigApplyCredentialsMsg(msg configApplyCredentialsMsg
if idx := next.configGatewayRowIndex(post); idx >= 0 {
next.configSel = idx
}
- next.configNotice = "Key updated for " + rhoconfig.GatewayDisplayName(post)
+ next.configNotice = "Key updated for " + decoderconfig.GatewayDisplayName(post)
return next, cmd
}
if msg.providerID == configProviderOllama {
- _ = rhoconfig.SetGlobalSetting("provider", configProviderOllama)
+ _ = decoderconfig.SetGlobalSetting("provider", configProviderOllama)
next.syncSessionSelection()
}
next.configGuideAfterKey = false
@@ -253,9 +253,9 @@ func configCredentialRejected(err error) bool {
}
func (m chatModel) rebuildSessionTransport() (chatModel, tea.Cmd) {
- m.settings = rhoconfig.LoadSettings()
+ m.settings = decoderconfig.LoadSettings()
m.syncSessionSelection()
- selection := rhoconfig.EffectiveSelectionWithSettings(context.Background(), m.settings, rhoconfig.SelectionOptions{
+ selection := decoderconfig.EffectiveSelectionWithSettings(context.Background(), m.settings, decoderconfig.SelectionOptions{
ProviderOverride: firstNonEmptyTrimmed(m.session.Provider(), m.settings.Provider),
ModelOverride: firstNonEmptyTrimmed(m.session.Model(), m.settings.Model),
})
diff --git a/cmd/chat_config_gateways.go b/cmd/chat_config_gateways.go
index 9f96f83ef..519c73b72 100644
--- a/cmd/chat_config_gateways.go
+++ b/cmd/chat_config_gateways.go
@@ -7,8 +7,8 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
type configGatewayRow struct {
@@ -47,7 +47,7 @@ func (m chatModel) loadConfigGatewayRows() []configGatewayRow {
if m.session != nil {
activeModel = strings.TrimSpace(m.session.Model())
}
- statuses := rhoconfig.GatewayStatuses(ctx, active, activeModel)
+ statuses := decoderconfig.GatewayStatuses(ctx, active, activeModel)
rows := make([]configGatewayRow, 0, len(statuses))
for _, status := range statuses {
if status.ID == "" {
@@ -64,10 +64,10 @@ func (m chatModel) loadConfigGatewayRows() []configGatewayRow {
hasKey := status.HasStoredCredential
credentialEnv, keyConflict := "", false
if hasKey {
- credentialEnv, keyConflict = rhoconfig.CredentialEnvironmentConflict(ctx, status.ID)
+ credentialEnv, keyConflict = decoderconfig.CredentialEnvironmentConflict(ctx, status.ID)
}
display := status.DisplayName
- if status.RegionRequired || status.RegionLabel != "" || rhoconfig.HasRegionOptions(status.ID) {
+ if status.RegionRequired || status.RegionLabel != "" || decoderconfig.HasRegionOptions(status.ID) {
if reg := status.RegionLabel; reg != "" {
display += " · " + reg
} else if status.RegionRequired {
@@ -82,7 +82,7 @@ func (m chatModel) loadConfigGatewayRows() []configGatewayRow {
HasKey: hasKey,
Configured: status.HasConfiguredDeployment || hasKey,
ModelCount: count,
- Active: status.Active || rhoconfig.ActiveProviderID(status.ID) == rhoconfig.ActiveProviderID(active),
+ Active: status.Active || decoderconfig.ActiveProviderID(status.ID) == decoderconfig.ActiveProviderID(active),
RegionLabel: status.RegionLabel,
RegionRequired: status.RegionRequired,
CredentialEnv: credentialEnv,
@@ -266,18 +266,18 @@ func (m chatModel) configGatewaysView() string {
ctx := context.Background()
indent := strings.Repeat(" ", configTableIndent)
if m.configKeysPendingRemove != "" {
- name := rhoconfig.GatewayDisplayName(m.configKeysPendingRemove)
+ name := decoderconfig.GatewayDisplayName(m.configKeysPendingRemove)
b.WriteString("\n" + mutedStyle.Render(indent+configGatewayRemovePrompt(m.configKeysRemoveStep, name)))
- } else if !rhoconfig.HasConfiguredDeploymentCached(ctx) {
+ } else if !decoderconfig.HasConfiguredDeploymentCached(ctx) {
hint := "Select a gateway · enter · paste API key · then Models tab"
- if targetIdx >= 0 && targetIdx < len(rows) && (rows[targetIdx].RegionRequired || rows[targetIdx].RegionLabel != "" || rhoconfig.HasRegionOptions(rows[targetIdx].ID)) {
+ if targetIdx >= 0 && targetIdx < len(rows) && (rows[targetIdx].RegionRequired || rows[targetIdx].RegionLabel != "" || decoderconfig.HasRegionOptions(rows[targetIdx].ID)) {
hint = rows[targetIdx].DisplayName + ": enter pick region then key · g change region"
}
b.WriteString("\n" + mutedStyle.Render(indent+hint))
} else {
hints := "enter use gateway · k view key · delete remove · r refresh"
- if targetIdx >= 0 && targetIdx < len(rows) && (rows[targetIdx].RegionRequired || rows[targetIdx].RegionLabel != "" || rhoconfig.HasRegionOptions(rows[targetIdx].ID)) {
+ if targetIdx >= 0 && targetIdx < len(rows) && (rows[targetIdx].RegionRequired || rows[targetIdx].RegionLabel != "" || decoderconfig.HasRegionOptions(rows[targetIdx].ID)) {
hints = "enter · g region · k key · delete · r refresh"
}
@@ -321,7 +321,7 @@ func (m chatModel) handleConfigGatewaysSelect() (chatModel, tea.Cmd) {
return m, nil
}
row := rows[m.configSel]
- if (row.RegionRequired || rhoconfig.HasRegionOptions(row.ID)) && (!row.HasKey || row.RegionRequired) {
+ if (row.RegionRequired || decoderconfig.HasRegionOptions(row.ID)) && (!row.HasKey || row.RegionRequired) {
m.configGatewayFocus = m.configSel
return m.startConfigGatewayRegion(row.ID), nil
}
@@ -336,8 +336,8 @@ func (m chatModel) handleConfigGatewaysSelect() (chatModel, tea.Cmd) {
gw := row.ID
m.configGatewayFocus = m.configSel
m.configModelProvider = gw
- _ = rhoconfig.SetGlobalSetting("provider", gw)
- if active := rhoconfig.ActiveProvider(context.Background()); active != "" {
+ _ = decoderconfig.SetGlobalSetting("provider", gw)
+ if active := decoderconfig.ActiveProvider(context.Background()); active != "" {
m.session.SetProvider(active)
}
m.configTab = configTabModels
@@ -349,7 +349,7 @@ func (m chatModel) handleConfigGatewaysSelect() (chatModel, tea.Cmd) {
func refreshGatewayAsync(providerID string) tea.Cmd {
return func() tea.Msg {
- summary, err := rhoconfig.RefreshGatewayCatalog(context.Background(), providerID)
+ summary, err := decoderconfig.RefreshGatewayCatalog(context.Background(), providerID)
return configGatewayRefreshMsg{providerID: providerID, summary: summary, err: err}
}
}
@@ -359,7 +359,7 @@ func (m chatModel) handleConfigGatewayRefreshMsg(msg configGatewayRefreshMsg) ch
InvalidateModelCacheProvider(msg.providerID)
m = m.refreshConfigGatewayRows()
if msg.err != nil {
- m.configNotice = sanitizeConfigNotice(rhoconfig.FormatConfigProviderError(msg.providerID, msg.err))
+ m.configNotice = sanitizeConfigNotice(decoderconfig.FormatConfigProviderError(msg.providerID, msg.err))
return m
}
m.configNotice = msg.summary
diff --git a/cmd/chat_config_gateways_test.go b/cmd/chat_config_gateways_test.go
index 434edea1a..5ecbd66c0 100644
--- a/cmd/chat_config_gateways_test.go
+++ b/cmd/chat_config_gateways_test.go
@@ -7,9 +7,9 @@ import (
"charm.land/bubbles/v2/textarea"
"charm.land/bubbles/v2/textinput"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
)
func chatModelForConfigPasteTest() chatModel {
@@ -37,12 +37,12 @@ func TestConfigGatewayRows_UsesPanelCacheUntilInvalidated(t *testing.T) {
func TestConfigGatewayRowsKeepRegistryOrderAfterKeySaved(t *testing.T) {
isolateCredentialHome(t)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
m := chatModel{}
@@ -50,7 +50,7 @@ func TestConfigGatewayRowsKeepRegistryOrderAfterKeySaved(t *testing.T) {
if err := store.Set(t.Context(), gateway.AccountForEnv("CONCENTRATE_API_KEY"), "test-key-1234567890"); err != nil {
t.Fatal(err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
after := m.loadConfigGatewayRows()
if len(after) != len(before) {
@@ -65,12 +65,12 @@ func TestConfigGatewayRowsKeepRegistryOrderAfterKeySaved(t *testing.T) {
func TestConfigGatewaysView_RequiresKeyForModelCounts(t *testing.T) {
isolateCredentialHome(t)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
m := chatModel{configTab: configTabGateways}
@@ -87,12 +87,12 @@ func TestConfigGatewaysView_RequiresKeyForModelCounts(t *testing.T) {
}
func TestConfigGatewaysView_ShowsSaveOrProbeNotice(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
m := chatModel{
@@ -109,17 +109,17 @@ func TestConfigGatewaysView_ShowsSaveOrProbeNotice(t *testing.T) {
}
func TestConfigGatewayRefreshTargetIndex_UsesSelectedRow(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
sess := engine.NewSession("", "", "", nil)
sess.SetProvider("openrouter")
@@ -138,17 +138,17 @@ func TestConfigGatewayRefreshTargetIndex_UsesSelectedRow(t *testing.T) {
}
func TestConfigGatewayRefreshTargetIndex_UsesFocusOnRefreshRow(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
rows := []configGatewayRow{
{ID: "openai", DisplayName: "OpenAI", HasKey: false},
@@ -162,17 +162,17 @@ func TestConfigGatewayRefreshTargetIndex_UsesFocusOnRefreshRow(t *testing.T) {
}
func TestFocusConfigActiveGateway_SelectsActiveRow(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
sess := engine.NewSession("", "", "", nil)
sess.SetProvider("openrouter")
@@ -196,19 +196,19 @@ func TestFocusConfigActiveGateway_SelectsActiveRow(t *testing.T) {
}
func TestHandleConfigGatewaysSelect_TokenPlanNoKeyShowsRegion(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
m := chatModel{configTab: configTabGateways}
rows := m.configGatewayRows()
idx := -1
for i, row := range rows {
- if row.ID == rhoconfig.ProviderXiaomiTokenPlan {
+ if row.ID == decoderconfig.ProviderXiaomiTokenPlan {
idx = i
break
}
@@ -221,18 +221,18 @@ func TestHandleConfigGatewaysSelect_TokenPlanNoKeyShowsRegion(t *testing.T) {
if next.configEntry != configEntryXiaomiRegion {
t.Fatalf("entry = %q, want xiaomi region picker", next.configEntry)
}
- if next.configProvider != rhoconfig.ProviderXiaomiTokenPlan {
+ if next.configProvider != decoderconfig.ProviderXiaomiTokenPlan {
t.Fatalf("provider = %q", next.configProvider)
}
}
func TestHandleConfigGatewaysSelect_NoKeyStartsPaste(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
m := chatModelForConfigPasteTest()
@@ -243,7 +243,7 @@ func TestHandleConfigGatewaysSelect_NoKeyStartsPaste(t *testing.T) {
}
sel := 0
for i, row := range gwRows {
- if row.ID == rhoconfig.ProviderXiaomiTokenPlan {
+ if row.ID == decoderconfig.ProviderXiaomiTokenPlan {
continue
}
sel = i
diff --git a/cmd/chat_config_hub.go b/cmd/chat_config_hub.go
index 8fd3527ac..9db414fbb 100644
--- a/cmd/chat_config_hub.go
+++ b/cmd/chat_config_hub.go
@@ -5,7 +5,7 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func (m chatModel) openConfigPanel() (chatModel, tea.Cmd) {
@@ -69,7 +69,7 @@ func catalogPricesAreStale(opts []configModelOption) bool {
}
func providerHasLiveFetcher(providerID string) bool {
- return rhoconfig.GatewaySupportsLiveDiscovery(providerID)
+ return decoderconfig.GatewaySupportsLiveDiscovery(providerID)
}
func (m chatModel) returnToOllamaURLAfterError(err error) (chatModel, tea.Cmd) {
@@ -80,7 +80,7 @@ func (m chatModel) returnToOllamaURLAfterError(err error) (chatModel, tea.Cmd) {
url = configDefaultOllamaURL
}
if err != nil {
- m.configNotice = rhoconfig.FormatConfigProviderError(configProviderOllama, err)
+ m.configNotice = decoderconfig.FormatConfigProviderError(configProviderOllama, err)
}
return m.startConfigOllamaURLWithValue(url)
}
diff --git a/cmd/chat_config_keys.go b/cmd/chat_config_keys.go
index aa88fd77f..87983ec6f 100644
--- a/cmd/chat_config_keys.go
+++ b/cmd/chat_config_keys.go
@@ -7,11 +7,11 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func credentialsStoreLabel() string {
- return rhoconfig.CredentialStoreName()
+ return decoderconfig.CredentialStoreName()
}
func configGatewayRemovePrompt(step int, gatewayName string) string {
@@ -37,15 +37,15 @@ func (m chatModel) configKeyDetailView() string {
accentStyle := configAccentStyle()
activeStyle := configActiveStyle()
providerName := strings.TrimSpace(m.configProvider)
- displayName := rhoconfig.GatewayDisplayName(providerName)
- masked := rhoconfig.MaskCredentialForProvider(context.Background(), providerName)
+ displayName := decoderconfig.GatewayDisplayName(providerName)
+ masked := decoderconfig.MaskCredentialForProvider(context.Background(), providerName)
var b strings.Builder
b.WriteString(renderConfigBreadcrumb(displayName+" key") + "\n\n")
b.WriteString(mutedStyle.Render(" Gateway: ") + accentStyle.Render(displayName) + "\n")
b.WriteString(mutedStyle.Render(" Key: ") + activeStyle.Render(masked) + "\n")
b.WriteString(mutedStyle.Render(" Stored in: "+credentialsStoreLabel()) + "\n")
- if reg := rhoconfig.GatewayRegionLabel(providerName); reg != "" || rhoconfig.NeedsGatewayRegion(providerName) || rhoconfig.HasRegionOptions(providerName) {
+ if reg := decoderconfig.GatewayRegionLabel(providerName); reg != "" || decoderconfig.NeedsGatewayRegion(providerName) || decoderconfig.HasRegionOptions(providerName) {
if reg == "" {
reg = "(not set — press g)"
}
@@ -68,32 +68,32 @@ func (m chatModel) startConfigKeyForProvider(provider string) (chatModel, tea.Cm
if provider == "" {
return m, nil
}
- if rhoconfig.NeedsGatewayRegion(provider) {
+ if decoderconfig.NeedsGatewayRegion(provider) {
m.configPostSaveKeysProvider = provider
return m.startConfigGatewayRegion(provider), nil
}
- name := rhoconfig.GatewayDisplayName(provider)
+ name := decoderconfig.GatewayDisplayName(provider)
m.configNotice = "Paste API key for " + name
return m.startConfigEntry(configEntryAPIKeyPaste, provider)
}
func (m chatModel) startConfigKeyReplace(provider string) (chatModel, tea.Cmd) {
- if rhoconfig.NeedsGatewayRegion(provider) {
+ if decoderconfig.NeedsGatewayRegion(provider) {
m.configPostSaveKeysProvider = provider
return m.startConfigGatewayRegion(provider), nil
}
m.configReplaceProvider = provider
m.configEntry = configEntryNone
- m.configNotice = "Paste replacement API key for " + rhoconfig.GatewayDisplayName(provider)
+ m.configNotice = "Paste replacement API key for " + decoderconfig.GatewayDisplayName(provider)
return m.startConfigEntry(configEntryAPIKeyPaste, provider)
}
func (m chatModel) beginConfigGatewayKeyRemove(provider string) chatModel {
m.configKeysPendingRemove = provider
m.configKeysRemoveStep = 1
- name := rhoconfig.GatewayDisplayName(provider)
+ name := decoderconfig.GatewayDisplayName(provider)
m.configNotice = configGatewayRemoveNotice(1, name)
return m
}
@@ -116,7 +116,7 @@ func (m chatModel) advanceConfigGatewayKeyRemove() (chatModel, tea.Cmd) {
}
if m.configKeysRemoveStep < 2 {
m.configKeysRemoveStep = 2
- name := rhoconfig.GatewayDisplayName(trimmedProvider)
+ name := decoderconfig.GatewayDisplayName(trimmedProvider)
m.configNotice = configGatewayRemoveNotice(2, name)
return m, nil
}
@@ -131,7 +131,7 @@ func (m chatModel) confirmConfigGatewayKeyRemove() (chatModel, tea.Cmd) {
m.configKeysPendingRemove = ""
m.configKeysRemoveStep = 0
m.configSaving = true
- m.configNotice = fmt.Sprintf("Removing key for %s…", rhoconfig.GatewayDisplayName(trimmedProvider))
+ m.configNotice = fmt.Sprintf("Removing key for %s…", decoderconfig.GatewayDisplayName(trimmedProvider))
if m.configEntry == configEntryKeyView {
m.configEntry = configEntryNone
m.configProvider = ""
@@ -164,7 +164,7 @@ func (m chatModel) handleConfigKeyViewKey(msg tea.KeyMsg) (chatModel, tea.Cmd) {
}
return m.startConfigKeyReplace(trimmedProvider)
default:
- if (rhoconfig.HasRegionOptions(trimmedProvider) || rhoconfig.GatewayRegionLabel(trimmedProvider) != "") && strings.EqualFold(key.Text, "g") {
+ if (decoderconfig.HasRegionOptions(trimmedProvider) || decoderconfig.GatewayRegionLabel(trimmedProvider) != "") && strings.EqualFold(key.Text, "g") {
return m.startConfigGatewayRegion(trimmedProvider), nil
}
return m, nil
diff --git a/cmd/chat_config_keys_test.go b/cmd/chat_config_keys_test.go
index f8502db99..050b81b12 100644
--- a/cmd/chat_config_keys_test.go
+++ b/cmd/chat_config_keys_test.go
@@ -5,22 +5,22 @@ import (
"testing"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
)
func TestConfigGatewaysView_KeyHintsWithCredentials(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
m := chatModel{configTab: configTabGateways}
view := m.configGatewaysView()
@@ -30,17 +30,17 @@ func TestConfigGatewaysView_KeyHintsWithCredentials(t *testing.T) {
}
func TestConfigGatewaysKeyView_OpenWithK(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
rows := chatModel{}.configGatewayRows()
sel := 0
@@ -61,17 +61,17 @@ func TestConfigGatewaysKeyView_OpenWithK(t *testing.T) {
}
func TestConfigGatewaysDelete_PendingRemove(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
rows := chatModel{}.configGatewayRows()
sel := 0
@@ -92,17 +92,17 @@ func TestConfigGatewaysDelete_PendingRemove(t *testing.T) {
}
func TestConfigGatewaysDelete_DoubleConfirm(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
rows := chatModel{}.configGatewayRows()
sel := 0
@@ -131,12 +131,12 @@ func TestConfigGatewaysDelete_DoubleConfirm(t *testing.T) {
}
func TestOpenConfigRemoveKeyPanel_OpensGatewaysTab(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
m := chatModel{}
diff --git a/cmd/chat_config_models.go b/cmd/chat_config_models.go
index 0d3f3000d..85ba9df4d 100644
--- a/cmd/chat_config_models.go
+++ b/cmd/chat_config_models.go
@@ -5,15 +5,15 @@ import (
"strings"
"sync"
- "github.com/GrayCodeAI/rho/internal/engine/cost"
+ "github.com/GrayCodeAI/decoder/internal/engine/cost"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
-// configModelOption is one row in the /config model picker (display from flux, id for settings).
+// configModelOption is one row in the /config model picker (display from mux, id for settings).
type configModelOption struct {
ID string
CanonicalID string
@@ -44,7 +44,7 @@ func InvalidateModelCache() {
modelSyncAttempted = make(map[string]bool)
modelSyncMu.Unlock()
invalidatePlatformContextCache()
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
}
// InvalidateModelCacheProvider drops one gateway's cached picker rows.
@@ -56,7 +56,7 @@ func InvalidateModelCacheProvider(provider string) {
modelSyncMu.Lock()
delete(modelSyncAttempted, provider)
modelSyncMu.Unlock()
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
}
func fetchModelsAsync(provider string) tea.Cmd {
@@ -64,19 +64,19 @@ func fetchModelsAsync(provider string) tea.Cmd {
ctx := context.Background()
provider = strings.TrimSpace(provider)
if provider == "" {
- provider = rhoconfig.DefaultModelProviderFilter(ctx)
+ provider = decoderconfig.DefaultModelProviderFilter(ctx)
}
- entries, err := rhoconfig.ListEngineModels(ctx, provider, false)
+ entries, err := decoderconfig.ListEngineModels(ctx, provider, false)
if err != nil {
- if _, derr := rhoconfig.ListEngineModels(ctx, provider, true); derr == nil {
+ if _, derr := decoderconfig.ListEngineModels(ctx, provider, true); derr == nil {
InvalidateModelCacheProvider(provider)
- entries, err = rhoconfig.ListEngineModels(ctx, provider, false)
+ entries, err = decoderconfig.ListEngineModels(ctx, provider, false)
}
}
if err != nil {
return modelsFetchedMsg{provider: provider, err: err}
}
- opts := configModelOptionsFromFlux(entries)
+ opts := configModelOptionsFromMux(entries)
if len(opts) > 0 {
modelCacheMu.Lock()
modelCache[provider] = opts
@@ -86,7 +86,7 @@ func fetchModelsAsync(provider string) tea.Cmd {
}
}
-func configModelOptionsFromFlux(entries []rhoconfig.EngineModel) []configModelOption {
+func configModelOptionsFromMux(entries []decoderconfig.EngineModel) []configModelOption {
opts := make([]configModelOption, len(entries))
for i, e := range entries {
opts[i] = configModelOption{
@@ -170,10 +170,10 @@ func ensureModelCacheLoaded(provider string) {
modelSyncMu.Unlock()
ctx := context.Background()
- entries, err := rhoconfig.ListEngineModels(ctx, provider, false)
+ entries, err := decoderconfig.ListEngineModels(ctx, provider, false)
if err != nil {
- if _, derr := rhoconfig.ListEngineModels(ctx, provider, true); derr == nil {
- entries, err = rhoconfig.ListEngineModels(ctx, provider, false)
+ if _, derr := decoderconfig.ListEngineModels(ctx, provider, true); derr == nil {
+ entries, err = decoderconfig.ListEngineModels(ctx, provider, false)
}
}
if err != nil || len(entries) == 0 {
@@ -182,7 +182,7 @@ func ensureModelCacheLoaded(provider string) {
modelSyncMu.Unlock()
return
}
- opts := configModelOptionsFromFlux(entries)
+ opts := configModelOptionsFromMux(entries)
modelCacheMu.Lock()
modelCache[provider] = opts
modelCacheMu.Unlock()
@@ -252,9 +252,9 @@ func loadConfigModelOptions(provider string) []configModelOption {
return cached
}
modelCacheMu.RUnlock()
- entries, err := rhoconfig.ListEngineModels(context.Background(), provider, false)
+ entries, err := decoderconfig.ListEngineModels(context.Background(), provider, false)
if err == nil && len(entries) > 0 {
- opts := configModelOptionsFromFlux(entries)
+ opts := configModelOptionsFromMux(entries)
modelCacheMu.Lock()
modelCache[provider] = opts
modelCacheMu.Unlock()
diff --git a/cmd/chat_config_models_test.go b/cmd/chat_config_models_test.go
index 1b37096ef..986c7eef0 100644
--- a/cmd/chat_config_models_test.go
+++ b/cmd/chat_config_models_test.go
@@ -3,7 +3,7 @@ package cmd
import (
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func TestFilterConfigModelOptions(t *testing.T) {
@@ -45,7 +45,7 @@ func TestModelOptionIsActive(t *testing.T) {
}
func TestConfigModelOptionsCarryResolvedEngineIdentity(t *testing.T) {
- opts := configModelOptionsFromFlux([]rhoconfig.EngineModel{{
+ opts := configModelOptionsFromMux([]decoderconfig.EngineModel{{
ID: "models/gemini-pro", CanonicalID: "google/gemini-pro",
ProviderID: "google", GatewayID: "gemini", Capabilities: []string{"tools", "vision"},
}})
diff --git a/cmd/chat_config_panel.go b/cmd/chat_config_panel.go
index 2f1da79ca..fcdde1989 100644
--- a/cmd/chat_config_panel.go
+++ b/cmd/chat_config_panel.go
@@ -9,8 +9,8 @@ import (
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func configModelChoices(opts []configModelOption, showProvider bool) []string {
@@ -87,11 +87,11 @@ func (m chatModel) configProviderKeyView() string {
title := icons.Key() + " Paste API key"
hint := "validates with provider API · stored in " + credentialsStoreLabel()
if providerName != "" {
- title = icons.Key() + " " + rhoconfig.GatewayDisplayName(providerName)
+ title = icons.Key() + " " + decoderconfig.GatewayDisplayName(providerName)
hint = "paste key for this gateway only · " + hint
}
- if providerName == rhoconfig.ProviderXiaomiTokenPlan {
- reg := rhoconfig.GatewayRegionLabel(rhoconfig.ProviderXiaomiTokenPlan)
+ if providerName == decoderconfig.ProviderXiaomiTokenPlan {
+ reg := decoderconfig.GatewayRegionLabel(decoderconfig.ProviderXiaomiTokenPlan)
if reg == "" {
reg = "not set — esc and pick region with g or enter on gateway row"
}
@@ -116,7 +116,7 @@ func (m chatModel) configOllamaURLView() string {
var b strings.Builder
b.WriteString(titleStyle.Render(icons.Llama()+" Ollama local") + "\n")
- b.WriteString(mutedStyle.Render("no API key · flux discovers installed models") + "\n\n")
+ b.WriteString(mutedStyle.Render("no API key · mux discovers installed models") + "\n\n")
if notice := strings.TrimSpace(m.configNotice); notice != "" {
b.WriteString(mutedStyle.Render(sanitizeConfigNotice(notice)) + "\n\n")
}
@@ -198,7 +198,7 @@ func (m chatModel) configModelsTabView() string {
gw = strings.TrimSpace(m.session.Provider())
}
if gw != "" {
- body.WriteString(renderConfigGatewayLine(rhoconfig.GatewayDisplayName(gw)) + "\n\n")
+ body.WriteString(renderConfigGatewayLine(decoderconfig.GatewayDisplayName(gw)) + "\n\n")
}
if len(m.configModelOptions) > 0 || m.configModelSearchActive {
@@ -245,15 +245,15 @@ func (m chatModel) startConfigModelSearch() (chatModel, tea.Cmd) {
m.configInput.EchoCharacter = 0
m.configInput.SetStyles(textinput.Styles{
Focused: textinput.StyleState{
- Prompt: lipgloss.NewStyle().Foreground(rhoColor).Bold(true),
+ Prompt: lipgloss.NewStyle().Foreground(decoderColor).Bold(true),
Text: lipgloss.NewStyle().Foreground(textPrimary),
},
Blurred: textinput.StyleState{
- Prompt: lipgloss.NewStyle().Foreground(rhoColor).Bold(true),
+ Prompt: lipgloss.NewStyle().Foreground(decoderColor).Bold(true),
Text: lipgloss.NewStyle().Foreground(textPrimary),
},
Cursor: textinput.CursorStyle{
- Color: rhoColor,
+ Color: decoderColor,
},
})
m.configInput.Focus()
@@ -333,11 +333,11 @@ func (m chatModel) configActiveModelID() string {
return modelName
}
}
- return strings.TrimSpace(rhoconfig.ActiveModel(context.Background()))
+ return strings.TrimSpace(decoderconfig.ActiveModel(context.Background()))
}
func modelOptionIsActive(opt configModelOption, activeModelID string) bool {
- return modelOptionIsActiveResolved(opt, activeModelID, rhoconfig.CanonicalModelID(context.Background(), activeModelID))
+ return modelOptionIsActiveResolved(opt, activeModelID, decoderconfig.CanonicalModelID(context.Background(), activeModelID))
}
func modelOptionIsActiveResolved(opt configModelOption, activeModelID, activeCanonicalID string) bool {
@@ -364,7 +364,7 @@ func (m chatModel) focusConfigActiveModelSelection() chatModel {
return m
}
activeID := m.configActiveModelID()
- activeCanonicalID := rhoconfig.CanonicalModelID(context.Background(), activeID)
+ activeCanonicalID := decoderconfig.CanonicalModelID(context.Background(), activeID)
windowSize := m.configVisibleRows()
for i, opt := range opts {
if modelOptionIsActiveResolved(opt, activeID, activeCanonicalID) {
@@ -405,7 +405,7 @@ func (m chatModel) configModelsBody() string {
total := len(opts)
allTotal := len(m.configModelOptions)
activeModelID := m.configActiveModelID()
- activeCanonicalID := rhoconfig.CanonicalModelID(context.Background(), activeModelID)
+ activeCanonicalID := decoderconfig.CanonicalModelID(context.Background(), activeModelID)
windowSize := m.configVisibleRows()
maxScroll := maxInt(0, total-windowSize)
if m.configScroll > maxScroll {
@@ -446,7 +446,7 @@ func (m chatModel) configModelsBody() string {
return b.String()
}
b.WriteString(mutedStyle.Render(" No models available.") + "\n")
- if hint := rhoconfig.CatalogEmptyHint(context.Background()); hint != "" {
+ if hint := decoderconfig.CatalogEmptyHint(context.Background()); hint != "" {
b.WriteString(mutedStyle.Render(" "+hint) + "\n")
}
if gw == configProviderOllama {
@@ -523,15 +523,15 @@ func (m chatModel) startConfigEntry(kind, provider string) (chatModel, tea.Cmd)
m.configInput.EchoCharacter = '*'
m.configInput.SetStyles(textinput.Styles{
Focused: textinput.StyleState{
- Prompt: lipgloss.NewStyle().Foreground(rhoColor).Bold(true),
+ Prompt: lipgloss.NewStyle().Foreground(decoderColor).Bold(true),
Text: lipgloss.NewStyle().Foreground(textPrimary),
},
Blurred: textinput.StyleState{
- Prompt: lipgloss.NewStyle().Foreground(rhoColor).Bold(true),
+ Prompt: lipgloss.NewStyle().Foreground(decoderColor).Bold(true),
Text: lipgloss.NewStyle().Foreground(textPrimary),
},
Cursor: textinput.CursorStyle{
- Color: rhoColor,
+ Color: decoderColor,
},
})
m.configInput.Focus()
@@ -580,7 +580,7 @@ func (m chatModel) finishConfigEntry() (chatModel, tea.Cmd) {
m.restoreChatInput()
return m, nil
}
- if providerName == rhoconfig.ProviderXiaomiTokenPlan && rhoconfig.NeedsGatewayRegion(providerName) {
+ if providerName == decoderconfig.ProviderXiaomiTokenPlan && decoderconfig.NeedsGatewayRegion(providerName) {
m.configEntry = configEntryNone
m.wipeConfigKeyInput()
m.restoreChatInput()
@@ -592,7 +592,7 @@ func (m chatModel) finishConfigEntry() (chatModel, tea.Cmd) {
m.configProvider = ""
m.wipeConfigKeyInput()
m.restoreChatInput()
- inference, err := rhoconfig.CredentialInferenceForProvider(providerName)
+ inference, err := decoderconfig.CredentialInferenceForProvider(providerName)
if err != nil {
m.configTab = configTabGateways
m.configNotice = "Could not save key: " + sanitizeConfigNotice(err.Error())
@@ -604,7 +604,7 @@ func (m chatModel) finishConfigEntry() (chatModel, tea.Cmd) {
m.configPostSaveKeysProvider = providerName
m.configSaving = true
notice := fmt.Sprintf("Validating key for %s…", inference.DisplayName)
- if hint := rhoconfig.CredentialGuidance(providerName, value); hint != "" {
+ if hint := decoderconfig.CredentialGuidance(providerName, value); hint != "" {
notice = hint + " · " + notice
}
m.configNotice = notice
@@ -867,7 +867,7 @@ func (m chatModel) handleConfigKey(msg tea.KeyMsg) (chatModel, tea.Cmd) {
return m.startConfigKeyView(row.ID), nil
}
case "g", "G":
- if row, ok := m.selectedConfigGateway(); ok && row.ID == rhoconfig.ProviderXiaomiTokenPlan {
+ if row, ok := m.selectedConfigGateway(); ok && row.ID == decoderconfig.ProviderXiaomiTokenPlan {
return m.startConfigGatewayRegion(row.ID), nil
}
}
@@ -960,7 +960,7 @@ func (m chatModel) selectConfigModelFromOptions(opts []configModelOption) (chatM
}
selected := opts[m.configSel]
modelID := selected.ID
- if err := rhoconfig.SetGlobalSetting("model", modelID); err != nil {
+ if err := decoderconfig.SetGlobalSetting("model", modelID); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
return m.closeConfigPanel(), nil
}
@@ -976,7 +976,7 @@ func (m chatModel) selectConfigModelFromOptions(opts []configModelOption) (chatM
provider = prov
}
if provider != "" {
- if err := rhoconfig.SetGlobalSetting("provider", provider); err != nil {
+ if err := decoderconfig.SetGlobalSetting("provider", provider); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: "model set, but saving provider failed: " + err.Error()})
}
}
@@ -986,7 +986,7 @@ func (m chatModel) selectConfigModelFromOptions(opts []configModelOption) (chatM
next.invalidateConnStatus()
next = next.stopConfigModelSearch(true)
next = next.closeConfigPanel()
- if !rhoconfig.EvaluateSetupCached(context.Background()).NeedsSetup {
+ if !decoderconfig.EvaluateSetupCached(context.Background()).NeedsSetup {
next.messages = append(next.messages, displayMsg{
role: "setup_complete",
content: next.session.Model(),
@@ -1001,19 +1001,19 @@ func (m chatModel) toggleConfigModelThinking() (chatModel, tea.Cmd) {
return m, nil
}
selected := opts[m.configSel]
- if !rhoconfig.ModelCapabilitySupportsThinking(selected.Capabilities) {
+ if !decoderconfig.ModelCapabilitySupportsThinking(selected.Capabilities) {
m.configNotice = "Thinking not supported for this model"
return m, nil
}
- settings := rhoconfig.LoadSettings()
- pref := rhoconfig.ThinkingPrefForModel(settings, selected.ID)
+ settings := decoderconfig.LoadSettings()
+ pref := decoderconfig.ThinkingPrefForModel(settings, selected.ID)
// Current effective display: unset → off. Toggle flips that.
currentlyOn := false
if pref != nil {
currentlyOn = *pref
}
next := !currentlyOn
- if err := rhoconfig.SetModelThinking(selected.ID, next); err != nil {
+ if err := decoderconfig.SetModelThinking(selected.ID, next); err != nil {
m.configNotice = err.Error()
return m, nil
}
@@ -1027,7 +1027,7 @@ func (m chatModel) toggleConfigModelThinking() (chatModel, tea.Cmd) {
m.configNotice = label + " thinking → off"
}
// If this is the active model, apply immediately.
- if m.session != nil && modelOptionIsActiveResolved(selected, m.configActiveModelID(), rhoconfig.CanonicalModelID(context.Background(), m.configActiveModelID())) {
+ if m.session != nil && modelOptionIsActiveResolved(selected, m.configActiveModelID(), decoderconfig.CanonicalModelID(context.Background(), m.configActiveModelID())) {
m.session.SetThinkingEnabled(&next)
}
return m, nil
@@ -1037,7 +1037,7 @@ func (m chatModel) applyModelThinkingPref(selected configModelOption) {
if m.session == nil {
return
}
- settings := rhoconfig.LoadSettings()
+ settings := decoderconfig.LoadSettings()
provider := strings.TrimSpace(m.configModelProvider)
if provider == "" {
provider = strings.TrimSpace(selected.GatewayID)
@@ -1045,5 +1045,5 @@ func (m chatModel) applyModelThinkingPref(selected configModelOption) {
if provider == "" {
provider = strings.TrimSpace(selected.ProviderID)
}
- m.session.SetThinkingEnabled(rhoconfig.ResolveThinkingForModel(settings, selected.ID, provider))
+ m.session.SetThinkingEnabled(decoderconfig.ResolveThinkingForModel(settings, selected.ID, provider))
}
diff --git a/cmd/chat_config_region.go b/cmd/chat_config_region.go
index 4cbba73a6..8f439e980 100644
--- a/cmd/chat_config_region.go
+++ b/cmd/chat_config_region.go
@@ -7,7 +7,7 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func gatewayRegionOptionIndex(providerID, region string) int {
@@ -15,7 +15,7 @@ func gatewayRegionOptionIndex(providerID, region string) int {
if region == "" {
return 0
}
- opts := rhoconfig.GatewayRegionOptions(providerID)
+ opts := decoderconfig.GatewayRegionOptions(providerID)
for i, r := range opts {
if strings.EqualFold(r.Value, region) {
return i
@@ -32,23 +32,23 @@ func (m chatModel) closeConfigEntry() chatModel {
func (m chatModel) startConfigGatewayRegion(providerID string) chatModel {
switch providerID {
- case rhoconfig.ProviderXiaomiTokenPlan:
+ case decoderconfig.ProviderXiaomiTokenPlan:
m.configEntry = configEntryXiaomiRegion
- case rhoconfig.ProviderZAICoding, rhoconfig.ProviderZAIPayg:
+ case decoderconfig.ProviderZAICoding, decoderconfig.ProviderZAIPayg:
m.configEntry = configEntryZAIRegion
default:
m.configEntry = configEntryGatewayRegion
}
m.configProvider = providerID
idx := 0
- if !rhoconfig.NeedsGatewayRegion(providerID) {
- idx = gatewayRegionOptionIndex(providerID, rhoconfig.GatewayRegionLabel(providerID))
+ if !decoderconfig.NeedsGatewayRegion(providerID) {
+ idx = gatewayRegionOptionIndex(providerID, decoderconfig.GatewayRegionLabel(providerID))
}
m.configGatewayRegionSel = idx
m.configZAIRegionSel = idx
- name := rhoconfig.GatewayDisplayName(providerID)
+ name := decoderconfig.GatewayDisplayName(providerID)
notice := fmt.Sprintf("Select %s region (↑↓ · enter · esc cancel)", name)
- if saved := rhoconfig.GatewayRegionLabel(providerID); saved != "" {
+ if saved := decoderconfig.GatewayRegionLabel(providerID); saved != "" {
notice = fmt.Sprintf("%s region · current %s (↑↓ · enter · esc cancel)", name, saved)
}
m.configNotice = notice
@@ -61,9 +61,9 @@ func (m chatModel) configGatewayRegionView() string {
rowStyle := configRowStyle()
var b strings.Builder
prov := m.configProvider
- name := rhoconfig.GatewayDisplayName(prov)
+ name := decoderconfig.GatewayDisplayName(prov)
b.WriteString(renderConfigBreadcrumb(name+" region") + "\n\n")
- opts := rhoconfig.GatewayRegionOptions(prov)
+ opts := decoderconfig.GatewayRegionOptions(prov)
for i, r := range opts {
prefix := " "
if i == m.configGatewayRegionSel {
@@ -84,7 +84,7 @@ func (m chatModel) configGatewayRegionView() string {
}
func (m chatModel) handleConfigGatewayRegionKey(msg tea.KeyMsg) (chatModel, tea.Cmd) {
- opts := rhoconfig.GatewayRegionOptions(m.configProvider)
+ opts := decoderconfig.GatewayRegionOptions(m.configProvider)
count := len(opts)
if count == 0 {
return m.closeConfigEntry(), nil
@@ -105,7 +105,7 @@ func (m chatModel) handleConfigGatewayRegionKey(msg tea.KeyMsg) (chatModel, tea.
case "enter":
if m.configGatewayRegionSel >= 0 && m.configGatewayRegionSel < count {
chosen := opts[m.configGatewayRegionSel]
- if err := rhoconfig.SetGatewayRegion(m.configProvider, chosen.Value); err != nil {
+ if err := decoderconfig.SetGatewayRegion(m.configProvider, chosen.Value); err != nil {
m.configNotice = "Error saving region: " + err.Error()
return m, nil
}
@@ -116,8 +116,8 @@ func (m chatModel) handleConfigGatewayRegionKey(msg tea.KeyMsg) (chatModel, tea.
m.configPostSaveKeysProvider = ""
return m.startConfigKeyReplace(m.configProvider)
}
- if rhoconfig.HasStoredCredentialForProvider(ctx, m.configProvider) {
- m.configNotice = "Saved region for " + rhoconfig.GatewayDisplayName(m.configProvider)
+ if decoderconfig.HasStoredCredentialForProvider(ctx, m.configProvider) {
+ m.configNotice = "Saved region for " + decoderconfig.GatewayDisplayName(m.configProvider)
if idx := m.configGatewayRowIndex(m.configProvider); idx >= 0 {
m.configSel = idx
}
diff --git a/cmd/chat_config_remove.go b/cmd/chat_config_remove.go
index b4304e217..6f02b5a3e 100644
--- a/cmd/chat_config_remove.go
+++ b/cmd/chat_config_remove.go
@@ -6,7 +6,7 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
type configRemoveCredentialMsg struct {
@@ -17,7 +17,7 @@ type configRemoveCredentialMsg struct {
func removeCredentialAsync(provider string) tea.Cmd {
return func() tea.Msg {
- removed, err := rhoconfig.RemoveStoredCredential(context.Background(), provider)
+ removed, err := decoderconfig.RemoveStoredCredential(context.Background(), provider)
return configRemoveCredentialMsg{
provider: provider,
removed: removed,
@@ -34,10 +34,10 @@ func (m chatModel) handleConfigRemoveCredentialMsg(msg configRemoveCredentialMsg
}
delete(modelCache, msg.provider)
ctx := context.Background()
- rhoconfig.RefreshConfigCredSnapshot(ctx)
+ decoderconfig.RefreshConfigCredSnapshot(ctx)
m = m.refreshConfigGatewayRows()
- if rhoconfig.ShouldClearSelectionAfterCredentialRemove(ctx, msg.provider) {
- _ = rhoconfig.ClearActiveSelection(ctx)
+ if decoderconfig.ShouldClearSelectionAfterCredentialRemove(ctx, msg.provider) {
+ _ = decoderconfig.ClearActiveSelection(ctx)
m.configModelProvider = ""
m.configModelOptions = nil
m.session.SetProvider("")
@@ -46,8 +46,8 @@ func (m chatModel) handleConfigRemoveCredentialMsg(msg configRemoveCredentialMsg
m.configTab = configTabGateways
m.configSel = 0
m.configScroll = 0
- m.configNotice = fmt.Sprintf("Removed API key for %s", rhoconfig.GatewayDisplayName(msg.provider))
- if !rhoconfig.HasConfiguredDeploymentCached(ctx) {
+ m.configNotice = fmt.Sprintf("Removed API key for %s", decoderconfig.GatewayDisplayName(msg.provider))
+ if !decoderconfig.HasConfiguredDeploymentCached(ctx) {
m.configNotice += " — add an API key to continue"
}
next, cmd := m.rebuildSessionTransport()
@@ -59,7 +59,7 @@ func (m chatModel) handleConfigRemoveCredentialMsg(msg configRemoveCredentialMsg
func (m chatModel) openConfigRemoveKeyPanel() (chatModel, tea.Cmd) {
next, cmd := m.openConfigAtTab(configTabGateways)
- if len(rhoconfig.ConfiguredCredentialProviders()) == 0 {
+ if len(decoderconfig.ConfiguredCredentialProviders()) == 0 {
next.configNotice = "No stored API keys"
}
return next, cmd
diff --git a/cmd/chat_config_remove_test.go b/cmd/chat_config_remove_test.go
index 01de618b0..e456873fa 100644
--- a/cmd/chat_config_remove_test.go
+++ b/cmd/chat_config_remove_test.go
@@ -4,22 +4,22 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
)
func TestConfigGatewayRows_ShowsSavedKey(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
rows := chatModel{}.configGatewayRows()
var found bool
@@ -35,36 +35,36 @@ func TestConfigGatewayRows_ShowsSavedKey(t *testing.T) {
}
func TestConfiguredCredentialProviders_UsedByGatewaysTab(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
- got := rhoconfig.ConfiguredCredentialProviders()
+ got := decoderconfig.ConfiguredCredentialProviders()
if len(got) != 1 || got[0] != "openrouter" {
t.Fatalf("configured = %v", got)
}
}
func TestRemoveCredentialAsync(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
cmd := removeCredentialAsync("openrouter")
if cmd == nil {
diff --git a/cmd/chat_config_save_flow_test.go b/cmd/chat_config_save_flow_test.go
index efe5b3154..81b7e6e7b 100644
--- a/cmd/chat_config_save_flow_test.go
+++ b/cmd/chat_config_save_flow_test.go
@@ -8,25 +8,25 @@ import (
"testing"
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/flux/catalog"
- "github.com/GrayCodeAI/flux/credentials"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/mux/catalog"
+ "github.com/GrayCodeAI/mux/credentials"
)
func TestFinishConfigEntry_APIKeyPaste_SavesBeforeProbe(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &credentials.MapStore{}
credentials.SetDefaultStore(store)
t.Cleanup(func() {
credentials.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
oldTransport := http.DefaultTransport
http.DefaultTransport = configSaveTestTransport(http.StatusUnauthorized)
t.Cleanup(func() { http.DefaultTransport = oldTransport })
- if _, err := rhoconfig.CredentialInferenceForProvider("xiaomi_mimo_payg"); err != nil {
+ if _, err := decoderconfig.CredentialInferenceForProvider("xiaomi_mimo_payg"); err != nil {
t.Fatalf("CredentialInferenceForProvider: %v", err)
}
@@ -111,7 +111,7 @@ func TestConfigGatewaysSelect_AddKeyOpensPaste(t *testing.T) {
}
}
if sel < 0 {
- t.Skip("all gateways already have keys in this environment") // TODO: https://github.com/GrayCodeAI/rho/issues/28
+ t.Skip("all gateways already have keys in this environment") // TODO: https://github.com/GrayCodeAI/decoder/issues/28
}
m.configSel = sel
next, _ := m.handleConfigGatewaysSelect()
@@ -134,7 +134,7 @@ func configSaveTestTransport(status int) http.RoundTripper {
})
}
-// roundTripFunc is defined in flux/runtime tests; duplicate here for rho cmd tests.
+// roundTripFunc is defined in mux/runtime tests; duplicate here for decoder cmd tests.
type roundTripFunc func(*http.Request) (*http.Response, error)
func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
@@ -142,12 +142,12 @@ func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
}
func TestHandleConfigKey_EnterOnPasteSubmits(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &credentials.MapStore{}
credentials.SetDefaultStore(store)
t.Cleanup(func() {
credentials.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
oldTransport := http.DefaultTransport
http.DefaultTransport = configSaveTestTransport(http.StatusUnauthorized)
@@ -197,12 +197,12 @@ func TestStartConfigEntry_APIKeyPasteHasNoPlaceholder(t *testing.T) {
}
func TestHandleConfigApplyCredentialsMsg_CatalogFailureDoesNotBlameProvider(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &credentials.MapStore{}
credentials.SetDefaultStore(store)
t.Cleanup(func() {
credentials.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), credentials.AccountForEnv("POOLSIDE_API_KEY"), "poolside-test-key"); err != nil {
t.Fatalf("store key: %v", err)
@@ -218,19 +218,19 @@ func TestHandleConfigApplyCredentialsMsg_CatalogFailureDoesNotBlameProvider(t *t
t.Fatalf("catalog failure blamed provider key: %q", next.configNotice)
}
if !strings.Contains(next.configNotice, "model catalog unavailable") ||
- !strings.Contains(next.configNotice, "rho models refresh") {
+ !strings.Contains(next.configNotice, "decoder models refresh") {
t.Fatalf("catalog recovery guidance missing: %q", next.configNotice)
}
}
-// Skipped: integration test requiring specific flux model catalog state
+// Skipped: integration test requiring specific mux model catalog state
func TestHandleConfigApplyCredentialsMsg_ValidationFailureDoesNotBlameProvider(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &credentials.MapStore{}
credentials.SetDefaultStore(store)
t.Cleanup(func() {
credentials.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), credentials.AccountForEnv("CONCENTRATE_API_KEY"), "concentrate-test-key"); err != nil {
t.Fatalf("store key: %v", err)
@@ -250,14 +250,14 @@ func TestHandleConfigApplyCredentialsMsg_ValidationFailureDoesNotBlameProvider(t
}
}
-// Skipped: integration test requiring specific flux model catalog state
+// Skipped: integration test requiring specific mux model catalog state
func TestHandleConfigApplyCredentialsMsg_AuthenticationFailureBlamesKey(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &credentials.MapStore{}
credentials.SetDefaultStore(store)
t.Cleanup(func() {
credentials.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
if err := store.Set(t.Context(), credentials.AccountForEnv("CONCENTRATE_API_KEY"), "concentrate-test-key"); err != nil {
t.Fatalf("store key: %v", err)
diff --git a/cmd/chat_config_security.go b/cmd/chat_config_security.go
index fff732853..5b997c7e7 100644
--- a/cmd/chat_config_security.go
+++ b/cmd/chat_config_security.go
@@ -4,7 +4,7 @@ import (
"strings"
"sync"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
)
var (
diff --git a/cmd/chat_config_tabs.go b/cmd/chat_config_tabs.go
index 18b9b46b1..8ba6dc41e 100644
--- a/cmd/chat_config_tabs.go
+++ b/cmd/chat_config_tabs.go
@@ -7,20 +7,20 @@ import (
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func (m chatModel) configStatus() (gateway, model string, configured bool) {
ctx := context.Background()
- if !rhoconfig.HasConfiguredDeploymentCached(ctx) {
+ if !decoderconfig.HasConfiguredDeploymentCached(ctx) {
return "none", "", false
}
gw := strings.TrimSpace(m.configModelProvider)
- if gw != "" && rhoconfig.IsSetupGateway(gw) {
- gw = rhoconfig.GatewayDisplayName(gw)
- } else if active := rhoconfig.ActiveGateway(ctx); active != "" {
- gw = rhoconfig.GatewayDisplayName(active)
+ if gw != "" && decoderconfig.IsSetupGateway(gw) {
+ gw = decoderconfig.GatewayDisplayName(gw)
+ } else if active := decoderconfig.ActiveGateway(ctx); active != "" {
+ gw = decoderconfig.GatewayDisplayName(active)
} else {
gw = "none"
}
@@ -28,7 +28,7 @@ func (m chatModel) configStatus() (gateway, model string, configured bool) {
model = strings.TrimSpace(m.session.Model())
}
if model == "" {
- model = strings.TrimSpace(rhoconfig.ActiveModel(ctx))
+ model = strings.TrimSpace(decoderconfig.ActiveModel(ctx))
}
return gw, model, true
}
@@ -44,7 +44,7 @@ func configTabDot(active bool) string {
func configTabLabelStyle(active bool) lipgloss.Style {
if active {
- return lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
+ return lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
}
return configMutedStyle()
}
@@ -90,7 +90,7 @@ func (m chatModel) switchConfigTab(tab int) (chatModel, tea.Cmd) {
m = m.stopConfigModelSearch(true)
}
ctx := context.Background()
- if tab == configTabModels && !rhoconfig.HasConfiguredDeploymentCached(ctx) {
+ if tab == configTabModels && !decoderconfig.HasConfiguredDeploymentCached(ctx) {
tab = configTabGateways
m.configNotice = "Select a gateway first · enter · paste API key"
m = m.focusConfigActiveGateway()
@@ -122,9 +122,9 @@ func (m chatModel) openConfigAtTab(tab int) (chatModel, tea.Cmd) {
m.configSel = 0
m.configScroll = 0
m.viewDirty = true
- rhoconfig.RefreshConfigCredSnapshot(ctx)
+ decoderconfig.RefreshConfigCredSnapshot(ctx)
m = m.refreshConfigGatewayRows()
- setup := rhoconfig.EvaluateSetupCached(ctx)
+ setup := decoderconfig.EvaluateSetupCached(ctx)
if tab < 0 {
if setup.HasCredentials {
diff --git a/cmd/chat_config_tabs_test.go b/cmd/chat_config_tabs_test.go
index 24af97697..4a519c9d2 100644
--- a/cmd/chat_config_tabs_test.go
+++ b/cmd/chat_config_tabs_test.go
@@ -4,9 +4,9 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func TestRenderConfigTabBar_DotIndicators(t *testing.T) {
@@ -28,12 +28,12 @@ func TestRenderConfigTabBar_DotIndicators(t *testing.T) {
}
func TestOpenConfigPanel_FirstRunOpensGateways(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
m := chatModel{}
@@ -47,12 +47,12 @@ func TestOpenConfigPanel_FirstRunOpensGateways(t *testing.T) {
}
func TestOpenConfigAtTab_ModelsWithoutCredentialsFallsBackToGateways(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
m := chatModel{}
diff --git a/cmd/chat_config_ui.go b/cmd/chat_config_ui.go
index 23884ffc2..a6f364551 100644
--- a/cmd/chat_config_ui.go
+++ b/cmd/chat_config_ui.go
@@ -4,7 +4,7 @@ import (
"strings"
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func configMutedStyle() lipgloss.Style {
@@ -13,19 +13,19 @@ func configMutedStyle() lipgloss.Style {
func configTitleStyle() lipgloss.Style {
// Talon Gold — title is the voice of the config panel.
- return lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
+ return lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
}
func configSelectedStyle() lipgloss.Style {
// Talon Gold (bold) marks the focused row. Keep it distinct from
// the active/current value, which uses configActiveStyle.
- return lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
+ return lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
}
func configAccentStyle() lipgloss.Style {
// Accent for inline highlights (breadcrumb, status line values).
// Same as title — both are the panel's voice.
- return lipgloss.NewStyle().Foreground(rhoColor)
+ return lipgloss.NewStyle().Foreground(decoderColor)
}
func renderConfigBreadcrumb(title string) string {
@@ -109,7 +109,7 @@ func configNoticeStyle(notice string) lipgloss.Style {
strings.Contains(n, "unauthorized"):
return lipgloss.NewStyle().Foreground(errorCoral)
case strings.HasPrefix(notice, "Refreshed"),
- strings.HasPrefix(notice, "Flux:"),
+ strings.HasPrefix(notice, "Mux:"),
strings.Contains(notice, "Removed API key"),
strings.Contains(notice, "Setup complete"),
strings.Contains(n, "key saved"),
diff --git a/cmd/chat_copy_e2e_test.go b/cmd/chat_copy_e2e_test.go
index 49959ff0b..78b39c6c7 100644
--- a/cmd/chat_copy_e2e_test.go
+++ b/cmd/chat_copy_e2e_test.go
@@ -8,7 +8,7 @@ import (
"charm.land/bubbles/v2/viewport"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
// runCopySelectionE2EPass exercises chat + input copy/select/mouse flows in one pass.
@@ -88,7 +88,7 @@ func runCopySelectionE2EPass(t *testing.T, pass int) {
}
// --- Mouse toggle (OpenCode-style) ---
- t.Setenv("RHO_MOUSE", "")
+ t.Setenv("DECODER_MOUSE", "")
m.handleMouseCommand([]string{"/mouse", "off"})
if m.mouseEnabled() {
t.Fatalf("pass %d: expected mouse off after /mouse off", pass)
@@ -109,13 +109,13 @@ func runCopySelectionE2EPass(t *testing.T, pass int) {
}
// --- Pass B: assistant reply path ---
- m.messages = append(m.messages, displayMsg{role: "assistant", content: "Hello from rho"})
+ m.messages = append(m.messages, displayMsg{role: "assistant", content: "Hello from decoder"})
m.input.SetValue("")
- if content, _, got := m.copyContent(copyModeAssistant); !got || content != "Hello from rho" {
+ if content, _, got := m.copyContent(copyModeAssistant); !got || content != "Hello from decoder" {
t.Fatalf("pass %d: /copy assistant content = %q got=%v", pass, content, got)
}
- if line, got := m.lastMessageContent(); !got || !strings.Contains(line, "Hello from rho") {
+ if line, got := m.lastMessageContent(); !got || !strings.Contains(line, "Hello from decoder") {
t.Fatalf("pass %d: last message = %q got=%v", pass, line, got)
}
@@ -128,7 +128,7 @@ func runCopySelectionE2EPass(t *testing.T, pass int) {
// Settings-backed mouse default
disabled := false
- m2 := chatModel{settings: rhoconfig.Settings{TuiMouse: &disabled}}
+ m2 := chatModel{settings: decoderconfig.Settings{TuiMouse: &disabled}}
if m2.mouseEnabled() {
t.Fatalf("pass %d: settings tui_mouse=false should disable capture", pass)
}
diff --git a/cmd/chat_copy_test.go b/cmd/chat_copy_test.go
index d6d7ca158..0f7bc6dd0 100644
--- a/cmd/chat_copy_test.go
+++ b/cmd/chat_copy_test.go
@@ -7,7 +7,7 @@ import (
"charm.land/bubbles/v2/textarea"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func TestCopyableTranscript_IncludesInputDraft(t *testing.T) {
@@ -80,24 +80,24 @@ func TestIsCopyToClipboardKey(t *testing.T) {
}
func TestMouseEnabled_SettingsAndEnv(t *testing.T) {
- t.Setenv("RHO_MOUSE", "")
+ t.Setenv("DECODER_MOUSE", "")
if !(chatModel{}).mouseEnabled() {
t.Fatal("expected mouse capture to default on")
}
disabled := false
- m := chatModel{settings: rhoconfig.Settings{TuiMouse: &disabled}}
+ m := chatModel{settings: decoderconfig.Settings{TuiMouse: &disabled}}
if m.mouseEnabled() {
t.Fatal("expected settings tui_mouse=false to disable capture")
}
- t.Setenv("RHO_MOUSE", "0")
+ t.Setenv("DECODER_MOUSE", "0")
if m.mouseEnabled() {
- t.Fatal("expected RHO_MOUSE=0 to disable capture")
+ t.Fatal("expected DECODER_MOUSE=0 to disable capture")
}
- t.Setenv("RHO_MOUSE", "1")
+ t.Setenv("DECODER_MOUSE", "1")
if !m.mouseEnabled() {
- t.Fatal("expected RHO_MOUSE=1 to enable capture")
+ t.Fatal("expected DECODER_MOUSE=1 to enable capture")
}
}
diff --git a/cmd/chat_errors_test.go b/cmd/chat_errors_test.go
index 4eab49735..a67c20e0d 100644
--- a/cmd/chat_errors_test.go
+++ b/cmd/chat_errors_test.go
@@ -12,7 +12,7 @@ func TestFriendlyError(t *testing.T) {
err string
contains string
}{
- {"rate limit 429", "flux: openai stream request failed: max retries (3) exceeded: HTTP 429", "Rate limited"},
+ {"rate limit 429", "mux: openai stream request failed: max retries (3) exceeded: HTTP 429", "Rate limited"},
{"unauthorized 401", "HTTP 401 Unauthorized", "Authentication failed"},
{"forbidden 403", "HTTP 403 Forbidden", "Access denied"},
{"not found 404", "model not found", "/model"},
diff --git a/cmd/chat_export.go b/cmd/chat_export.go
index 9dfaa94d8..7ead2cc9c 100644
--- a/cmd/chat_export.go
+++ b/cmd/chat_export.go
@@ -4,8 +4,8 @@ import (
"fmt"
"path/filepath"
- sessionfeature "github.com/GrayCodeAI/rho/internal/features/session"
- "github.com/GrayCodeAI/rho/internal/storage"
+ sessionfeature "github.com/GrayCodeAI/decoder/internal/features/session"
+ "github.com/GrayCodeAI/decoder/internal/storage"
)
func chatExportRequest(m *chatModel, format string, redact bool) (sessionfeature.ExportRequest, error) {
diff --git a/cmd/chat_focus.go b/cmd/chat_focus.go
index 5d03eff29..f2863d613 100644
--- a/cmd/chat_focus.go
+++ b/cmd/chat_focus.go
@@ -9,9 +9,9 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/storage"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// UI focus areas — Grok Build cycles Prompt ↔ Scrollback (Tab).
diff --git a/cmd/chat_history_search.go b/cmd/chat_history_search.go
index b48c93b1b..4c01e1189 100644
--- a/cmd/chat_history_search.go
+++ b/cmd/chat_history_search.go
@@ -4,9 +4,9 @@ import (
"strconv"
"strings"
- chatfeature "github.com/GrayCodeAI/rho/internal/features/chat"
- "github.com/GrayCodeAI/rho/internal/textutil"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ chatfeature "github.com/GrayCodeAI/decoder/internal/features/chat"
+ "github.com/GrayCodeAI/decoder/internal/textutil"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
"github.com/mattn/go-runewidth"
)
diff --git a/cmd/chat_journey_e2e_test.go b/cmd/chat_journey_e2e_test.go
index 647f5a6dc..bd6060102 100644
--- a/cmd/chat_journey_e2e_test.go
+++ b/cmd/chat_journey_e2e_test.go
@@ -5,8 +5,8 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
)
func requireChatModel(t *testing.T, model any) *chatModel {
@@ -23,20 +23,20 @@ func requireChatModel(t *testing.T, model any) *chatModel {
}
func TestChatJourney_ConfigPermissionsAndCoreCommands(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
isolateCredentialHome(t)
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
if err := store.Set(ctx, gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatal(err)
}
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
m := newTestChatModel()
diff --git a/cmd/chat_layout_mouse_test.go b/cmd/chat_layout_mouse_test.go
index 00e5ba0f2..6a7eb148a 100644
--- a/cmd/chat_layout_mouse_test.go
+++ b/cmd/chat_layout_mouse_test.go
@@ -14,7 +14,7 @@ func TestView_LineCountMatchesHeight(t *testing.T) {
m := chatModel{
height: 24,
width: 80,
- welcomeCache: "RHO LOGO\nv0.1.0",
+ welcomeCache: "DECODER LOGO\nv0.1.0",
input: textarea.New(),
viewport: viewport.New(viewport.WithWidth(80), viewport.WithHeight(8)),
ghostText: NewGhostText(),
diff --git a/cmd/chat_layout_test.go b/cmd/chat_layout_test.go
index 95b0582cd..7abbf0961 100644
--- a/cmd/chat_layout_test.go
+++ b/cmd/chat_layout_test.go
@@ -12,7 +12,7 @@ func TestView_PinsWelcomeAboveViewport(t *testing.T) {
m := chatModel{
height: 24,
width: 80,
- welcomeCache: "RHO LOGO\nv0.1.0",
+ welcomeCache: "DECODER LOGO\nv0.1.0",
input: textarea.New(),
viewport: viewport.New(viewport.WithWidth(80), viewport.WithHeight(8)),
ghostText: NewGhostText(),
@@ -21,7 +21,7 @@ func TestView_PinsWelcomeAboveViewport(t *testing.T) {
m.viewDirty = true
m.updateViewportContent()
got := m.View().Content
- if !strings.Contains(got, "RHO LOGO") {
+ if !strings.Contains(got, "DECODER LOGO") {
t.Fatalf("welcome should be pinned at top, got prefix: %q", got[:min(40, len(got))])
}
if !strings.Contains(got, "─") {
@@ -33,20 +33,20 @@ func TestPrimeInitialViewportContent_RendersWelcomeBeforeFirstFrame(t *testing.T
m := chatModel{
height: 24,
width: 80,
- welcomeCache: "RHO LOGO\nv0.1.0",
+ welcomeCache: "DECODER LOGO\nv0.1.0",
input: textarea.New(),
viewport: viewport.New(viewport.WithWidth(80), viewport.WithHeight(8)),
ghostText: NewGhostText(),
}
m = m.withSyncedLayout()
- if strings.Contains(m.viewport.View(), "RHO LOGO") {
+ if strings.Contains(m.viewport.View(), "DECODER LOGO") {
t.Fatal("expected empty initial viewport before priming")
}
m.primeInitialViewportContent()
- if !strings.Contains(m.viewport.View(), "RHO LOGO") {
+ if !strings.Contains(m.viewport.View(), "DECODER LOGO") {
t.Fatalf("expected primed viewport to include welcome content, got %q", m.viewport.View())
}
}
diff --git a/cmd/chat_model.go b/cmd/chat_model.go
index 0f9e9e21b..76f2e45d7 100644
--- a/cmd/chat_model.go
+++ b/cmd/chat_model.go
@@ -6,8 +6,8 @@ import (
"sync"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
- chatfeature "github.com/GrayCodeAI/rho/internal/features/chat"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+ chatfeature "github.com/GrayCodeAI/decoder/internal/features/chat"
"charm.land/bubbles/v2/spinner"
"charm.land/bubbles/v2/textarea"
@@ -16,15 +16,15 @@ import (
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/bridge/sessioncapture"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/features/shellmode"
- "github.com/GrayCodeAI/rho/internal/features/taste"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/system/staleness"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/bridge/sessioncapture"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/features/shellmode"
+ "github.com/GrayCodeAI/decoder/internal/features/taste"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/system/staleness"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
// sessionWAL is the durability surface the chat model needs from its
@@ -56,10 +56,10 @@ func (m *chatModel) recordWALError(err error) {
if err == nil || m.durabilityWarning != "" {
return
}
- m.durabilityWarning = "Warning: session persistence is failing — recent messages may be lost if rho crashes. Check disk space and permissions."
+ m.durabilityWarning = "Warning: session persistence is failing — recent messages may be lost if decoder crashes. Check disk space and permissions."
}
-// All rho color/icon/glyph constants live in theme.go. This file holds
+// All decoder color/icon/glyph constants live in theme.go. This file holds
// the pre-built lipgloss styles that combine a color with attributes
// (bold, italic, border, etc.) for the most common patterns.
@@ -75,8 +75,8 @@ var (
slashCmdStyle = lipgloss.NewStyle().Foreground(textDisabled)
slashDescStyle = lipgloss.NewStyle().Foreground(textDisabled)
- slashSelCmdStyle = lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
- slashSelDescStyle = lipgloss.NewStyle().Foreground(rhoColor)
+ slashSelCmdStyle = lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
+ slashSelDescStyle = lipgloss.NewStyle().Foreground(decoderColor)
inputBorderStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder(), true, false, true, false).BorderForeground(borderDim)
// Backwards-compatible alias for callers that still use the old name.
@@ -88,13 +88,13 @@ func ghostHintStyle() lipgloss.Style {
return lipgloss.NewStyle().Foreground(textDisabled).Italic(true)
}
-// rhoSpinnerFrames feeds the bubbles spinner (matches BrailleSpinner default).
-var rhoSpinnerFrames = rhoSpinnerGlyphs
+// decoderSpinnerFrames feeds the bubbles spinner (matches BrailleSpinner default).
+var decoderSpinnerFrames = decoderSpinnerGlyphs
-// rhoSpinnerFrameInterval — compass frame cadence.
-const rhoSpinnerFrameInterval = 80 * time.Millisecond
+// decoderSpinnerFrameInterval — compass frame cadence.
+const decoderSpinnerFrameInterval = 80 * time.Millisecond
-// Spinner verbs (from rho-archive) — picked randomly per session
+// Spinner verbs (from decoder-archive) — picked randomly per session
var spinnerVerbs = []string{
"Abstracting", "Architecting", "Brewing", "Calculating", "Cogitating",
"Compiling", "Computing", "Conjuring", "Contemplating", "Cooking",
@@ -154,7 +154,7 @@ type (
statusLeftBranch string
connStatusVal string
connStatusKey string
- welcomeSetup rhoconfig.SetupState
+ welcomeSetup decoderconfig.SetupState
welcomeAgentsOK bool
}
processArrowTickMsg struct {
@@ -219,7 +219,7 @@ type chatModel struct {
viewport viewport.Model
session *engine.Session
registry *tool.Registry
- settings rhoconfig.Settings
+ settings decoderconfig.Settings
ref *progRef
cancel context.CancelFunc // cancel current stream
sessionID string
@@ -257,7 +257,7 @@ type chatModel struct {
width int
height int
quitting bool
- mascotEnabled bool // inline RHO mascot is available in the active terminal
+ mascotEnabled bool // inline DECODER mascot is available in the active terminal
blinkClosed bool
eyeFrame int
slashSel int
@@ -270,7 +270,7 @@ type chatModel struct {
configNotice string
configEntry string // configEntryNone, configEntryAPIKeyPaste, configEntryOllamaURL
configProvider string // e.g. configProviderOllama while entry overlay is open
- configModelOptions []configModelOption // labels + ids from flux catalog
+ configModelOptions []configModelOption // labels + ids from mux catalog
configModelProvider string // filter models after API key paste
configModelSearch string // active model filter query
configModelSearchActive bool // typing into model search input
@@ -323,7 +323,7 @@ type chatModel struct {
sessionBootstrapDone bool
toolStartTime time.Time
welcomeCache string
- welcomeSetupState rhoconfig.SetupState
+ welcomeSetupState decoderconfig.SetupState
welcomeAgentsOK bool
viewDirty bool
layoutKey int // input lines + slash menu height fingerprint
diff --git a/cmd/chat_model_test.go b/cmd/chat_model_test.go
index 8f1b86897..78619099c 100644
--- a/cmd/chat_model_test.go
+++ b/cmd/chat_model_test.go
@@ -11,15 +11,15 @@ import (
"charm.land/bubbles/v2/textarea"
"charm.land/bubbles/v2/viewport"
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/bridge/sessioncapture"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- chatfeature "github.com/GrayCodeAI/rho/internal/features/chat"
- "github.com/GrayCodeAI/rho/internal/features/shellmode"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/storage"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/bridge/sessioncapture"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ chatfeature "github.com/GrayCodeAI/decoder/internal/features/chat"
+ "github.com/GrayCodeAI/decoder/internal/features/shellmode"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
func newTestChatModel() *chatModel {
@@ -44,7 +44,7 @@ func newTestChatModel() *chatModel {
hintsLoader: engine.NewHintsLoader(),
selfImprover: engine.NewSelfImprover(),
codingSoul: engine.LoadCodingSoul(),
- brailleSpinner: NewBrailleSpinner(SpinnerRho, "Thinking"),
+ brailleSpinner: NewBrailleSpinner(SpinnerDecoder, "Thinking"),
testStreamStarter: func() {},
}
return m
@@ -63,12 +63,12 @@ func isolateChatCommandSweepEnv(t *testing.T) {
root := t.TempDir()
storage.SetTestDirs(t, root)
isolateCredentialHome(t)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
gateway.SetDefaultStore(&gateway.MapStore{})
restoreThemeGlobals(t)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
}
@@ -78,7 +78,7 @@ func isolateChatCommandSweepEnv(t *testing.T) {
// (e.g. TestAdaptiveNeutralsPreserveDarkAppearance).
func restoreThemeGlobals(t *testing.T) {
t.Helper()
- savedRho, savedSuccess, savedWarn, savedErr, savedInfo := rhoColor, successTeal, warnAmber, errorCoral, infoSky
+ savedDecoder, savedSuccess, savedWarn, savedErr, savedInfo := decoderColor, successTeal, warnAmber, errorCoral, infoSky
savedTool, savedAgent, savedDone, savedFileHeader := toolGold, agentGold, doneGreen, fileHeaderBlue
savedInspect, savedEdit, savedRun, savedTrust := tierInspect, tierEdit, tierRun, tierTrust
savedHudBorder, savedHudLabel := hudBorderPurple, hudLabelPink
@@ -100,7 +100,7 @@ func restoreThemeGlobals(t *testing.T) {
savedMinimalChrome := minimalChrome
hasDark := lipgloss.HasDarkBackground(os.Stdin, os.Stdout)
t.Cleanup(func() {
- rhoColor, successTeal, warnAmber, errorCoral, infoSky = savedRho, savedSuccess, savedWarn, savedErr, savedInfo
+ decoderColor, successTeal, warnAmber, errorCoral, infoSky = savedDecoder, savedSuccess, savedWarn, savedErr, savedInfo
toolGold, agentGold, doneGreen, fileHeaderBlue = savedTool, savedAgent, savedDone, savedFileHeader
tierInspect, tierEdit, tierRun, tierTrust = savedInspect, savedEdit, savedRun, savedTrust
hudBorderPurple, hudLabelPink = savedHudBorder, savedHudLabel
@@ -170,7 +170,7 @@ func TestChatModel_SlashClear(t *testing.T) {
func TestFormatQuitResumeMessage(t *testing.T) {
got := formatQuitResumeMessage("44418bdd52745678")
- want := "Thank you for using Rho!\n\nTo resume this session, run: rho --resume 44418bdd52745678\n"
+ want := "Thank you for using Decoder!\n\nTo resume this session, run: decoder --resume 44418bdd52745678\n"
if got != want {
t.Fatalf("quit message mismatch:\nwant %q\ngot %q", want, got)
}
@@ -178,7 +178,7 @@ func TestFormatQuitResumeMessage(t *testing.T) {
func TestFormatQuitResumeMessage_NoSession(t *testing.T) {
got := formatQuitResumeMessage("")
- want := "Thank you for using Rho!\n"
+ want := "Thank you for using Decoder!\n"
if got != want {
t.Fatalf("quit message mismatch:\nwant %q\ngot %q", want, got)
}
diff --git a/cmd/chat_mouse.go b/cmd/chat_mouse.go
index 4f403a81b..1de5746e7 100644
--- a/cmd/chat_mouse.go
+++ b/cmd/chat_mouse.go
@@ -5,11 +5,11 @@ import (
"os"
"strings"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func mouseEnabledFromEnv() bool {
- v := strings.TrimSpace(os.Getenv("RHO_MOUSE"))
+ v := strings.TrimSpace(os.Getenv("DECODER_MOUSE"))
if v == "0" || strings.EqualFold(v, "false") || strings.EqualFold(v, "off") {
return false
}
@@ -17,13 +17,13 @@ func mouseEnabledFromEnv() bool {
}
func envOverridesMouse() bool {
- v := strings.TrimSpace(os.Getenv("RHO_MOUSE"))
+ v := strings.TrimSpace(os.Getenv("DECODER_MOUSE"))
return v != ""
}
// mouseEnabled reports whether the TUI should capture mouse events for chat wheel
// scroll. When false, the terminal handles click-drag selection natively (OpenCode
-// "mouse": false). Priority: RHO_MOUSE env → runtime override → settings → default on.
+// "mouse": false). Priority: DECODER_MOUSE env → runtime override → settings → default on.
func (m chatModel) mouseEnabled() bool {
if envOverridesMouse() {
return mouseEnabledFromEnv()
@@ -54,7 +54,7 @@ func (m *chatModel) handleMouseCommand(parts []string) {
source := "default"
switch {
case envOverridesMouse():
- source = "RHO_MOUSE env"
+ source = "DECODER_MOUSE env"
case m.mouseOverride != nil:
source = "session"
case m.settings.TuiMouse != nil:
@@ -76,7 +76,7 @@ func (m *chatModel) handleMouseCommand(parts []string) {
if envOverridesMouse() {
m.messages = append(m.messages, displayMsg{
role: "system",
- content: "Mouse is controlled by RHO_MOUSE env in this session. " +
+ content: "Mouse is controlled by DECODER_MOUSE env in this session. " +
"Unset it to use /mouse or settings.json tui_mouse.",
})
return
@@ -85,11 +85,11 @@ func (m *chatModel) handleMouseCommand(parts []string) {
switch strings.ToLower(parts[1]) {
case "on", "true", "1", "enable":
m.setMouseEnabled(true)
- _ = rhoconfig.SetGlobalSetting("tui_mouse", "true")
+ _ = decoderconfig.SetGlobalSetting("tui_mouse", "true")
m.messages = append(m.messages, displayMsg{role: "system", content: "Mouse capture on — chat wheel scroll enabled."})
case "off", "false", "0", "disable":
m.setMouseEnabled(false)
- _ = rhoconfig.SetGlobalSetting("tui_mouse", "false")
+ _ = decoderconfig.SetGlobalSetting("tui_mouse", "false")
m.messages = append(m.messages, displayMsg{
role: "system",
content: "Mouse capture off — use click-drag to select text. /copy and Ctrl+Shift+C still work.",
@@ -103,7 +103,7 @@ func (m *chatModel) handleMouseCommand(parts []string) {
val = "true"
msg = "Mouse capture on — chat wheel scroll enabled."
}
- _ = rhoconfig.SetGlobalSetting("tui_mouse", val)
+ _ = decoderconfig.SetGlobalSetting("tui_mouse", val)
m.messages = append(m.messages, displayMsg{role: "system", content: msg})
default:
m.messages = append(m.messages, displayMsg{role: "system", content: "Usage: /mouse [on|off|toggle]"})
diff --git a/cmd/chat_multiturn_e2e_test.go b/cmd/chat_multiturn_e2e_test.go
index e90bfea30..21f37f5b6 100644
--- a/cmd/chat_multiturn_e2e_test.go
+++ b/cmd/chat_multiturn_e2e_test.go
@@ -6,35 +6,35 @@ import (
"testing"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
)
func configureReadyChatState(t *testing.T) {
t.Helper()
isolateChatCommandSweepEnv(t)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
if err := store.Set(ctx, gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatal(err)
}
- if err := rhoconfig.SetActiveProvider(ctx, "openrouter"); err != nil {
+ if err := decoderconfig.SetActiveProvider(ctx, "openrouter"); err != nil {
t.Fatal(err)
}
- if err := rhoconfig.SetActiveModel(ctx, "gpt-4o"); err != nil {
+ if err := decoderconfig.SetActiveModel(ctx, "gpt-4o"); err != nil {
t.Fatal(err)
}
- rhoconfig.InvalidateConfigUICache()
- rhoconfig.RefreshConfigCredSnapshot(ctx)
+ decoderconfig.InvalidateConfigUICache()
+ decoderconfig.RefreshConfigCredSnapshot(ctx)
}
func countMessagesByRole(msgs []displayMsg, role string) int {
diff --git a/cmd/chat_permission_keys_test.go b/cmd/chat_permission_keys_test.go
index ad9e595a0..b61d340bc 100644
--- a/cmd/chat_permission_keys_test.go
+++ b/cmd/chat_permission_keys_test.go
@@ -6,13 +6,13 @@ import (
"testing"
"time"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
- "github.com/GrayCodeAI/rho/internal/permissions"
- "github.com/GrayCodeAI/rho/internal/permissions/stableid"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/permissions"
+ "github.com/GrayCodeAI/decoder/internal/permissions/stableid"
tea "charm.land/bubbletea/v2"
- contracts "github.com/GrayCodeAI/rho/internal/contracts/policy"
+ contracts "github.com/GrayCodeAI/decoder/internal/contracts/policy"
)
func TestHighRiskApprovalUsesKeyboardActions(t *testing.T) {
diff --git a/cmd/chat_platform_ctx.go b/cmd/chat_platform_ctx.go
index 008307a18..07230d925 100644
--- a/cmd/chat_platform_ctx.go
+++ b/cmd/chat_platform_ctx.go
@@ -8,7 +8,7 @@ import (
"time"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
var platformCtxCache struct {
@@ -51,7 +51,7 @@ type platformContextIndexMsg struct {
func fetchPlatformContextIndexCmd() tea.Cmd {
return func() tea.Msg {
- models, err := rhoconfig.ListPublicEngineModels(context.Background(), "xiaomi_mimo_payg")
+ models, err := decoderconfig.ListPublicEngineModels(context.Background(), "xiaomi_mimo_payg")
if err != nil {
return platformContextIndexMsg{err: err}
}
diff --git a/cmd/chat_print.go b/cmd/chat_print.go
index 09521cf6f..c5e60171c 100644
--- a/cmd/chat_print.go
+++ b/cmd/chat_print.go
@@ -14,13 +14,13 @@ import (
"unicode/utf8"
lipgloss "charm.land/lipgloss/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- aiwatch "github.com/GrayCodeAI/rho/internal/engine/io"
- "github.com/GrayCodeAI/rho/internal/engine/lifecycle"
- chatfeature "github.com/GrayCodeAI/rho/internal/features/chat"
- "github.com/GrayCodeAI/rho/internal/observability/logger"
- "github.com/GrayCodeAI/rho/internal/session"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ aiwatch "github.com/GrayCodeAI/decoder/internal/engine/io"
+ "github.com/GrayCodeAI/decoder/internal/engine/lifecycle"
+ chatfeature "github.com/GrayCodeAI/decoder/internal/features/chat"
+ "github.com/GrayCodeAI/decoder/internal/observability/logger"
+ "github.com/GrayCodeAI/decoder/internal/session"
)
// Print mode and session persistence functions extracted from chat.go
@@ -41,7 +41,7 @@ func runPrint(text string) error {
return err
}
- sess, cfgErr := newConfiguredRhoSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry, logger.New(io.Discard, logger.Error))
+ sess, cfgErr := newConfiguredDecoderSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry, logger.New(io.Discard, logger.Error))
if cfgErr != nil {
return cfgErr
}
@@ -138,7 +138,7 @@ func runPrint(text string) error {
writePrintResult(printed.String(), sessionID, sess, false, nil)
}
if !noSessionPersistence {
- saveFluxSession(sessionID, sess)
+ saveMuxSession(sessionID, sess)
}
return nil
}
@@ -156,7 +156,7 @@ func runPrint(text string) error {
writePrintResult(printed.String(), sessionID, sess, false, nil)
}
if !noSessionPersistence {
- saveFluxSession(sessionID, sess)
+ saveMuxSession(sessionID, sess)
}
return nil
}
@@ -206,7 +206,7 @@ func printTextUsageFooter(usage *engine.StreamUsage, started time.Time, turns in
// ANSI so it can be pasted into a bug report or piped to a file.
func printTranscript(sessionID, model, response string, usage *engine.StreamUsage, started time.Time, turns int) {
var b strings.Builder
- fmt.Fprintf(&b, "# rho transcript\n")
+ fmt.Fprintf(&b, "# decoder transcript\n")
fmt.Fprintf(&b, "session: %s\n", sessionID)
if model != "" {
fmt.Fprintf(&b, "model: %s\n", model)
@@ -312,7 +312,7 @@ func writePrintEvent(sessionID, eventType, content, toolName string) {
fmt.Println(string(data))
}
-func saveFluxSession(id string, sess *engine.Session) {
+func saveMuxSession(id string, sess *engine.Session) {
raw := sess.RawMessages()
if len(raw) == 0 {
return
@@ -328,7 +328,7 @@ func saveFluxSession(id string, sess *engine.Session) {
// runRepl starts an interactive REPL mode for multi-turn conversation without TUI.
func runRepl() error {
- fmt.Fprintln(os.Stderr, auditTint("Rho REPL", textPrimary)+auditTint(" — type 'exit' or 'quit' to leave, 'help' for commands", textMuted))
+ fmt.Fprintln(os.Stderr, auditTint("Decoder REPL", textPrimary)+auditTint(" — type 'exit' or 'quit' to leave, 'help' for commands", textMuted))
fmt.Fprintln(os.Stderr)
systemPrompt, err := buildSystemPrompt()
@@ -347,7 +347,7 @@ func runRepl() error {
return err
}
- sess, cfgErr := newConfiguredRhoSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry, logger.New(io.Discard, logger.Error))
+ sess, cfgErr := newConfiguredDecoderSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry, logger.New(io.Discard, logger.Error))
if cfgErr != nil {
return cfgErr
}
@@ -482,7 +482,7 @@ func runRepl() error {
writePrintResult(printed.String(), sessionID, sess, false, nil)
}
if !noSessionPersistence {
- saveFluxSession(sessionID, sess)
+ saveMuxSession(sessionID, sess)
}
}
}
@@ -492,7 +492,7 @@ func runRepl() error {
}
}
-func replBuiltinResponse(input string, sess *engine.Session, settings rhoconfig.Settings, sessionID string) (string, bool, error) {
+func replBuiltinResponse(input string, sess *engine.Session, settings decoderconfig.Settings, sessionID string) (string, bool, error) {
switch strings.TrimSpace(input) {
case "/tools":
return builtInToolsSummary(), true, nil
@@ -511,12 +511,12 @@ func replBuiltinResponse(input string, sess *engine.Session, settings rhoconfig.
}
}
-func replModelsSummary(settings rhoconfig.Settings, sessionProvider string) (string, bool, error) {
+func replModelsSummary(settings decoderconfig.Settings, sessionProvider string) (string, bool, error) {
providerName := effectiveProviderForREPL(settings, sessionProvider)
if providerName == "" {
- return "No active provider selected. Set one with `rho config provider ` or start REPL with `--provider`.", true, nil
+ return "No active provider selected. Set one with `decoder config provider ` or start REPL with `--provider`.", true, nil
}
- models, err := rhoconfig.FetchModelsForProvider(providerName)
+ models, err := decoderconfig.FetchModelsForProvider(providerName)
if err != nil {
return "", true, err
}
@@ -542,7 +542,7 @@ func replModelsSummary(settings rhoconfig.Settings, sessionProvider string) (str
return b.String(), true, nil
}
-func effectiveProviderForREPL(settings rhoconfig.Settings, sessionProvider string) string {
+func effectiveProviderForREPL(settings decoderconfig.Settings, sessionProvider string) string {
if provider != "" {
return strings.TrimSpace(provider)
}
@@ -567,7 +567,7 @@ func formatModelTablePlain(rows []modelTableRow) string {
}
// watchIgnoreDirs are directory names skipped when scanning for AI directives.
-var watchIgnoreDirs = []string{".git", "node_modules", "vendor", "__pycache__", ".rho"}
+var watchIgnoreDirs = []string{".git", "node_modules", "vendor", "__pycache__", ".decoder"}
// runWatch watches the working directory for AI!/AI? comment directives and
// dispatches a targeted LLM edit for each one as files change (Aider-style
diff --git a/cmd/chat_print_usage_test.go b/cmd/chat_print_usage_test.go
index df0b0f683..a0fe83072 100644
--- a/cmd/chat_print_usage_test.go
+++ b/cmd/chat_print_usage_test.go
@@ -6,7 +6,7 @@ import (
"testing"
"time"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// captureStderr runs fn with os.Stderr redirected to a pipe and returns the
@@ -38,7 +38,7 @@ func TestPrintTextUsageFooter(t *testing.T) {
printTextUsageFooter(&engine.StreamUsage{
PromptTokens: 100,
CompletionTokens: 50,
- }, started, 3, "rho-pro")
+ }, started, 3, "decoder-pro")
})
if !strings.Contains(got, "100 in · 50 out") {
t.Errorf("footer missing token counts: %q", got)
@@ -49,7 +49,7 @@ func TestPrintTextUsageFooter(t *testing.T) {
if !strings.Contains(got, "3 turn(s)") {
t.Errorf("footer missing turn count: %q", got)
}
- if !strings.Contains(got, "rho-pro") {
+ if !strings.Contains(got, "decoder-pro") {
t.Errorf("footer missing model: %q", got)
}
if !strings.Contains(got, "2s") {
@@ -90,7 +90,7 @@ func TestPrintTextUsageFooter(t *testing.T) {
CompletionTokens: 5,
}, started, 1, "")
})
- if strings.Contains(got, "rho-pro") {
+ if strings.Contains(got, "decoder-pro") {
t.Errorf("footer should omit empty model: %q", got)
}
})
diff --git a/cmd/chat_prompt_timeout_test.go b/cmd/chat_prompt_timeout_test.go
index fbc198ebd..41cd2dbae 100644
--- a/cmd/chat_prompt_timeout_test.go
+++ b/cmd/chat_prompt_timeout_test.go
@@ -5,11 +5,11 @@ import (
"testing"
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/tool"
- contracts "github.com/GrayCodeAI/rho/internal/contracts/policy"
+ contracts "github.com/GrayCodeAI/decoder/internal/contracts/policy"
)
func TestPermissionPromptTimeoutClearsStaleState(t *testing.T) {
@@ -236,7 +236,7 @@ func TestClearInteractivePromptsFailsClosedImmediately(t *testing.T) {
m.credentialQueue = []credentialAskMsg{{response: make(chan tool.CredentialResponse, 1)}}
m.permReq = &safety.PermissionRequest{Response: permissionResponse}
- m.clearInteractivePrompts("rho is exiting")
+ m.clearInteractivePrompts("decoder is exiting")
if m.askReq != nil || m.credentialReq != nil || m.permReq != nil || len(m.askQueue) != 0 || len(m.credentialQueue) != 0 {
t.Fatal("interactive prompts were not fully cleared")
@@ -248,7 +248,7 @@ func TestClearInteractivePromptsFailsClosedImmediately(t *testing.T) {
}
select {
case response := <-credentialResponse:
- if response.Approved || response.Reason != "rho is exiting" {
+ if response.Approved || response.Reason != "decoder is exiting" {
t.Fatalf("unexpected credential shutdown response: %+v", response)
}
default:
diff --git a/cmd/chat_scrollbar.go b/cmd/chat_scrollbar.go
index ec4003621..ae818265b 100644
--- a/cmd/chat_scrollbar.go
+++ b/cmd/chat_scrollbar.go
@@ -19,7 +19,7 @@ const (
// scrollbarThumbStyle — Talon Gold thumb so it reads as a brand control.
func scrollbarThumbStyle() lipgloss.Style {
- return lipgloss.NewStyle().Foreground(rhoColor)
+ return lipgloss.NewStyle().Foreground(decoderColor)
}
func scrollbarTrackStyle() lipgloss.Style {
diff --git a/cmd/chat_select.go b/cmd/chat_select.go
index 390eaac45..cf286c6bd 100644
--- a/cmd/chat_select.go
+++ b/cmd/chat_select.go
@@ -9,7 +9,7 @@ import (
tea "charm.land/bubbletea/v2"
"golang.org/x/term"
- chatfeature "github.com/GrayCodeAI/rho/internal/features/chat"
+ chatfeature "github.com/GrayCodeAI/decoder/internal/features/chat"
)
// selectionResumedMsg is delivered to the chat model after the user finishes a
@@ -57,7 +57,7 @@ func enterSelectionMode(ref *progRef, transcript string, restoreMouse bool) tea.
fmt.Fprintln(os.Stderr, " Click and drag to select text in this terminal.")
fmt.Fprintln(os.Stderr, " Copy with your terminal's normal copy shortcut (e.g. Cmd+C,")
fmt.Fprintln(os.Stderr, " Ctrl+Shift+C, or Ctrl+Insert).")
- fmt.Fprintln(os.Stderr, " Press any key to return to rho.")
+ fmt.Fprintln(os.Stderr, " Press any key to return to decoder.")
fmt.Fprintln(os.Stderr, "────────────────────────────────────────────────────────────")
fmt.Fprintln(os.Stderr, "")
// Block on stdin in raw mode so any single keypress resumes the
diff --git a/cmd/chat_session_picker.go b/cmd/chat_session_picker.go
index 8144fa01b..abf8556af 100644
--- a/cmd/chat_session_picker.go
+++ b/cmd/chat_session_picker.go
@@ -7,11 +7,11 @@ import (
"unicode/utf8"
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
"github.com/mattn/go-runewidth"
- sessionfeature "github.com/GrayCodeAI/rho/internal/features/session"
- "github.com/GrayCodeAI/rho/internal/session"
+ sessionfeature "github.com/GrayCodeAI/decoder/internal/features/session"
+ "github.com/GrayCodeAI/decoder/internal/session"
)
// applySessionPickerFilter filters the session entries based on the current search query.
diff --git a/cmd/chat_status.go b/cmd/chat_status.go
index 3bc1fdfb8..62fa54b1b 100644
--- a/cmd/chat_status.go
+++ b/cmd/chat_status.go
@@ -8,8 +8,8 @@ import (
lipgloss "charm.land/lipgloss/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
func modelStatusMeta(gateway, modelID string) (displayName, contextLabel string) {
@@ -61,7 +61,7 @@ func (m *chatModel) invalidateConnStatus() {
func (m chatModel) connStatusFingerprint() string {
gw, modelName := m.sessionGatewayModel()
- creds := strings.Join(rhoconfig.ConfiguredCredentialProviders(), ",")
+ creds := strings.Join(decoderconfig.ConfiguredCredentialProviders(), ",")
api := 0
if m.session != nil {
api = m.session.LastPromptTokens()
@@ -83,7 +83,7 @@ func (m chatModel) sessionGatewayModel() (gateway, model string) {
model = explicitModel
}
if gateway == "" && model != "" {
- gateway = strings.TrimSpace(rhoconfig.ProviderOfModel(model))
+ gateway = strings.TrimSpace(decoderconfig.ProviderOfModel(model))
}
if explicitGateway == "" && explicitModel == "" && model == "" {
switch strings.TrimSpace(gateway) {
@@ -96,10 +96,10 @@ func (m chatModel) sessionGatewayModel() (gateway, model string) {
func (m *chatModel) chatConnectionStatus() string {
ctx := context.Background()
- if !rhoconfig.CredentialSnapshotReady() {
+ if !decoderconfig.CredentialSnapshotReady() {
return ""
}
- if !rhoconfig.HasConfiguredDeploymentCached(ctx) {
+ if !decoderconfig.HasConfiguredDeploymentCached(ctx) {
return ""
}
m.syncSessionSelection()
@@ -138,7 +138,7 @@ func (m chatModel) buildConnectionStatusPlain() string {
func (m chatModel) connectionStatusParts() (gateway, model, contextLabel string) {
gw, modelID := m.sessionGatewayModel()
- gateway = rhoconfig.GatewayDisplayName(gw)
+ gateway = decoderconfig.GatewayDisplayName(gw)
if gateway == "" {
gateway = gw
}
@@ -196,10 +196,10 @@ func trimRepeatedGatewayPrefix(gateway, model string) string {
// footer segments so context can sit flush on the right edge.
func (m chatModel) renderConnectionStatusSplit() (modelRendered string, modelVis int, ctxRendered string, ctxVis int) {
ctx := context.Background()
- if !rhoconfig.CredentialSnapshotReady() {
+ if !decoderconfig.CredentialSnapshotReady() {
return "", 0, "", 0
}
- if !rhoconfig.HasConfiguredDeploymentCached(ctx) {
+ if !decoderconfig.HasConfiguredDeploymentCached(ctx) {
return "", 0, "", 0
}
diff --git a/cmd/chat_status_metadata_test.go b/cmd/chat_status_metadata_test.go
index ce33becea..d8da3e507 100644
--- a/cmd/chat_status_metadata_test.go
+++ b/cmd/chat_status_metadata_test.go
@@ -4,8 +4,8 @@ import (
"testing"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// seedPlatformContextCacheForTest primes the platform context cache so tests
@@ -133,10 +133,10 @@ func TestConnectionStatusParts_MimoShowsPlatformContext_HyphenProvider(t *testin
}
func TestGatewayDisplayName_XiaomiTokenPlanHyphen(t *testing.T) {
- if got := rhoconfig.GatewayDisplayName("xiaomi-mimo-token-plan"); got != "Xiaomi MiMo — Token Plan" {
+ if got := decoderconfig.GatewayDisplayName("xiaomi-mimo-token-plan"); got != "Xiaomi MiMo — Token Plan" {
t.Fatalf("GatewayDisplayName(hyphen) = %q, want nice name", got)
}
- if got := rhoconfig.GatewayDisplayName("xiaomi_mimo_token_plan"); got != "Xiaomi MiMo — Token Plan" {
+ if got := decoderconfig.GatewayDisplayName("xiaomi_mimo_token_plan"); got != "Xiaomi MiMo — Token Plan" {
t.Fatalf("GatewayDisplayName(underscore) = %q, want nice name", got)
}
}
diff --git a/cmd/chat_status_test.go b/cmd/chat_status_test.go
index 5443490a4..6c9bd1543 100644
--- a/cmd/chat_status_test.go
+++ b/cmd/chat_status_test.go
@@ -6,9 +6,9 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
"github.com/charmbracelet/x/ansi"
)
@@ -91,23 +91,23 @@ func TestFormatContextUsedLabel(t *testing.T) {
}
func TestChatConnectionStatus_WithModel(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
isolateCredentialHome(t)
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
if err := store.Set(ctx, gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
- _ = rhoconfig.SetActiveProvider(ctx, "openrouter")
- _ = rhoconfig.SetActiveModel(ctx, "moonshotai/kimi-k2.6")
- rhoconfig.RefreshConfigCredSnapshot(ctx)
+ decoderconfig.InvalidateConfigUICache()
+ _ = decoderconfig.SetActiveProvider(ctx, "openrouter")
+ _ = decoderconfig.SetActiveModel(ctx, "moonshotai/kimi-k2.6")
+ decoderconfig.RefreshConfigCredSnapshot(ctx)
sess := engine.NewSession("openrouter", "moonshotai/kimi-k2.6", "", nil)
@@ -125,23 +125,23 @@ func TestChatConnectionStatus_WithModel(t *testing.T) {
}
func TestChatConnectionStatus_KeyNoModel(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
isolateCredentialHome(t)
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
if err := store.Set(ctx, gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
- _ = rhoconfig.ClearActiveSelection(ctx)
- _ = rhoconfig.SetActiveProvider(ctx, "openrouter")
- rhoconfig.RefreshConfigCredSnapshot(ctx)
+ decoderconfig.InvalidateConfigUICache()
+ _ = decoderconfig.ClearActiveSelection(ctx)
+ _ = decoderconfig.SetActiveProvider(ctx, "openrouter")
+ decoderconfig.RefreshConfigCredSnapshot(ctx)
m := chatModel{session: &engine.Session{}}
got := m.chatConnectionStatus()
@@ -151,22 +151,22 @@ func TestChatConnectionStatus_KeyNoModel(t *testing.T) {
}
func TestChatConnectionStatus_NoGatewayNoModel(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
isolateCredentialHome(t)
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
if err := store.Set(ctx, gateway.AccountForEnv("ANTHROPIC_API_KEY"), "sk-ant-test-key-long-enough"); err != nil {
t.Fatalf("store.Set: %v", err)
}
- rhoconfig.InvalidateConfigUICache()
- _ = rhoconfig.ClearActiveSelection(ctx)
- rhoconfig.RefreshConfigCredSnapshot(ctx)
+ decoderconfig.InvalidateConfigUICache()
+ _ = decoderconfig.ClearActiveSelection(ctx)
+ decoderconfig.RefreshConfigCredSnapshot(ctx)
m := chatModel{session: &engine.Session{}}
got := m.chatConnectionStatus()
@@ -183,7 +183,7 @@ func TestStartupWarmMsg_RefreshesFooterCache(t *testing.T) {
statusLeftBranch: "main",
connStatusVal: "OpenRouter · gpt-4",
connStatusKey: "cache-key",
- welcomeSetup: rhoconfig.SetupState{NeedsSetup: true},
+ welcomeSetup: decoderconfig.SetupState{NeedsSetup: true},
welcomeAgentsOK: true,
})
next := nextModel.(chatModel)
@@ -247,7 +247,7 @@ func TestShowWelcomeBanner_WithMessages(t *testing.T) {
func TestBuildWelcomeMessage_UsesDisplayVersion(t *testing.T) {
SetVersion("dev")
- msg := buildWelcomeMessage(nil, "", nil, nil, rhoconfig.Settings{}, 0, false, 80, 24)
+ msg := buildWelcomeMessage(nil, "", nil, nil, decoderconfig.Settings{}, 0, false, 80, 24)
if strings.Contains(msg, "vdev") {
t.Fatal("welcome should not show vdev; DisplayVersion should read VERSION file or dev")
}
diff --git a/cmd/chat_stream.go b/cmd/chat_stream.go
index f276753d3..29d3cb98f 100644
--- a/cmd/chat_stream.go
+++ b/cmd/chat_stream.go
@@ -6,8 +6,8 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
- chatfeature "github.com/GrayCodeAI/rho/internal/features/chat"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ chatfeature "github.com/GrayCodeAI/decoder/internal/features/chat"
)
// Streaming and prompt command functions extracted from chat.go
diff --git a/cmd/chat_subcommand.go b/cmd/chat_subcommand.go
index ede02d5a1..b9828aeea 100644
--- a/cmd/chat_subcommand.go
+++ b/cmd/chat_subcommand.go
@@ -6,7 +6,7 @@ import (
"sync"
tea "charm.land/bubbletea/v2"
- commandfeature "github.com/GrayCodeAI/rho/internal/features/commands"
+ commandfeature "github.com/GrayCodeAI/decoder/internal/features/commands"
)
// ChatSubcommand is a single slash-command handler. Implementations live in
diff --git a/cmd/chat_subcommand_brainstorm.go b/cmd/chat_subcommand_brainstorm.go
index 2585d8cdd..9349d48ae 100644
--- a/cmd/chat_subcommand_brainstorm.go
+++ b/cmd/chat_subcommand_brainstorm.go
@@ -5,7 +5,7 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// brainstormSubcommand implements the /brainstorm slash command. It
diff --git a/cmd/chat_subcommand_branch_agent.go b/cmd/chat_subcommand_branch_agent.go
index 58f32103c..c1a00430d 100644
--- a/cmd/chat_subcommand_branch_agent.go
+++ b/cmd/chat_subcommand_branch_agent.go
@@ -5,17 +5,17 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
-// branchAgentSubcommand creates a rho/agent-* branch from main/master.
+// branchAgentSubcommand creates a decoder/agent-* branch from main/master.
type branchAgentSubcommand struct{}
func (c *branchAgentSubcommand) Name() string { return "branch-agent" }
func (c *branchAgentSubcommand) Aliases() []string { return []string{"agent-branch"} }
func (c *branchAgentSubcommand) Description() string {
- return "create rho/agent-* branch if on main/master"
+ return "create decoder/agent-* branch if on main/master"
}
func (c *branchAgentSubcommand) Usage() string { return "/branch-agent" }
diff --git a/cmd/chat_subcommand_checkpoint.go b/cmd/chat_subcommand_checkpoint.go
index c135c512e..a398adb12 100644
--- a/cmd/chat_subcommand_checkpoint.go
+++ b/cmd/chat_subcommand_checkpoint.go
@@ -3,7 +3,7 @@ package cmd
import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// checkpointSubcommand implements the /checkpoint slash command.
diff --git a/cmd/chat_subcommand_context.go b/cmd/chat_subcommand_context.go
index db9f862ad..b07fb45a5 100644
--- a/cmd/chat_subcommand_context.go
+++ b/cmd/chat_subcommand_context.go
@@ -6,8 +6,8 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine/project"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine/project"
)
// contextSubcommand implements the /context slash command. It
@@ -37,7 +37,7 @@ func (c *contextSubcommand) Handle(m *chatModel, args []string, text string) (te
}
return m, nil
}
- m.messages = append(m.messages, displayMsg{role: "system", content: rhoconfig.BuildContextWithDirs(addDirs)})
+ m.messages = append(m.messages, displayMsg{role: "system", content: decoderconfig.BuildContextWithDirs(addDirs)})
return m, nil
}
diff --git a/cmd/chat_subcommand_council.go b/cmd/chat_subcommand_council.go
index ff9b4a21a..8347bc307 100644
--- a/cmd/chat_subcommand_council.go
+++ b/cmd/chat_subcommand_council.go
@@ -7,8 +7,8 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// councilSubcommand implements the /council slash command. It
diff --git a/cmd/chat_subcommand_ecosystem.go b/cmd/chat_subcommand_ecosystem.go
index 16ad6240b..65347b3ad 100644
--- a/cmd/chat_subcommand_ecosystem.go
+++ b/cmd/chat_subcommand_ecosystem.go
@@ -5,7 +5,7 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
// ecosystemSubcommand implements the /ecosystem slash command. It
@@ -28,7 +28,7 @@ func (e *ecosystemSubcommand) Handle(m *chatModel, args []string, text string) (
if providerName == "" {
providerName = "auto"
}
- m.messages = append(m.messages, displayMsg{role: "system", content: rhoconfig.FormatEcosystemPanel(context.Background(), providerName, modelName)})
+ m.messages = append(m.messages, displayMsg{role: "system", content: decoderconfig.FormatEcosystemPanel(context.Background(), providerName, modelName)})
return m, nil
}
diff --git a/cmd/chat_subcommand_harness.go b/cmd/chat_subcommand_harness.go
index 40c2a6d13..1d11e4f06 100644
--- a/cmd/chat_subcommand_harness.go
+++ b/cmd/chat_subcommand_harness.go
@@ -6,7 +6,7 @@ import (
"os"
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/harness"
+ "github.com/GrayCodeAI/decoder/internal/harness"
)
type harnessSubcommand struct{}
@@ -29,7 +29,7 @@ func (h *harnessSubcommand) Handle(m *chatModel, args []string, text string) (te
return m.startPromptCommand("/harness", prompt)
}
- prompt := fmt.Sprintf("I ran a Rho Agent Harness Review on this repository (%s).\n\nOverall Score: %d/100 (%s)\nPrioritized Findings (%d):\n\n%s\n\nPlease help me address the highest priority findings to improve our AI coding harness.",
+ prompt := fmt.Sprintf("I ran a Decoder Agent Harness Review on this repository (%s).\n\nOverall Score: %d/100 (%s)\nPrioritized Findings (%d):\n\n%s\n\nPlease help me address the highest priority findings to improve our AI coding harness.",
report.TargetPath, report.OverallScore, report.OverallStatus, len(report.Findings), harness.RenderMarkdown(report))
return m.startPromptCommand("/harness", prompt)
diff --git a/cmd/chat_subcommand_help.go b/cmd/chat_subcommand_help.go
index 3f5952231..66e0a889c 100644
--- a/cmd/chat_subcommand_help.go
+++ b/cmd/chat_subcommand_help.go
@@ -6,7 +6,7 @@ import (
"strings"
tea "charm.land/bubbletea/v2"
- commandfeature "github.com/GrayCodeAI/rho/internal/features/commands"
+ commandfeature "github.com/GrayCodeAI/decoder/internal/features/commands"
)
// helpCategory returns the display category for a slash command name,
diff --git a/cmd/chat_subcommand_investigate.go b/cmd/chat_subcommand_investigate.go
index 971a14946..f843f03e1 100644
--- a/cmd/chat_subcommand_investigate.go
+++ b/cmd/chat_subcommand_investigate.go
@@ -5,7 +5,7 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// investigateSubcommand implements the /investigate slash command.
diff --git a/cmd/chat_subcommand_login.go b/cmd/chat_subcommand_login.go
index 2cc4b534d..94232850a 100644
--- a/cmd/chat_subcommand_login.go
+++ b/cmd/chat_subcommand_login.go
@@ -7,7 +7,7 @@ import (
)
// loginSubcommand implements the /login slash command. Tau uses /login as its
-// provider-auth entry point; Rho routes it to the existing config panel, which
+// provider-auth entry point; Decoder routes it to the existing config panel, which
// owns credential storage (OS keychain) and provider/model selection.
//
// `/login ` preselects a provider before opening the panel so the
diff --git a/cmd/chat_subcommand_memory.go b/cmd/chat_subcommand_memory.go
index e13fbd2f7..8b892ad30 100644
--- a/cmd/chat_subcommand_memory.go
+++ b/cmd/chat_subcommand_memory.go
@@ -5,7 +5,7 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
// memorySubcommand implements the /memory slash command.
@@ -17,7 +17,7 @@ func (m *memorySubcommand) Aliases() []string { return nil }
func (m *memorySubcommand) Description() string { return "print project instructions (AGENTS.md)" }
func (m *memorySubcommand) Usage() string { return "" }
func (m *memorySubcommand) Handle(ml *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
- md := strings.TrimSpace(rhoconfig.LoadAgentsMD())
+ md := strings.TrimSpace(decoderconfig.LoadAgentsMD())
if md == "" {
ml.messages = append(ml.messages, displayMsg{role: "system", content: "No AGENTS.md project instructions found."})
} else {
diff --git a/cmd/chat_subcommand_mode.go b/cmd/chat_subcommand_mode.go
index e1d78eff2..082be38a9 100644
--- a/cmd/chat_subcommand_mode.go
+++ b/cmd/chat_subcommand_mode.go
@@ -6,8 +6,8 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/features/shellmode"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/features/shellmode"
)
// modeSubcommand implements the /mode slash command.
@@ -41,7 +41,7 @@ func (mo *modeSubcommand) Handle(m *chatModel, args []string, text string) (tea.
}
visible := 0
if m.session != nil && m.session.Tools() != nil && m.session.Tools().Registry() != nil {
- visible = len(m.session.Tools().Registry().FluxTools())
+ visible = len(m.session.Tools().Registry().MuxTools())
}
m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf(
"Work mode: %s (plan | act | review)\nShell mode: %s (auto | shell | agent)\nTrust: %s\nAuto-commit: %s\nTools visible: %d\n\n/start · /trust · /branch-agent · /auto-commit",
diff --git a/cmd/chat_subcommand_model.go b/cmd/chat_subcommand_model.go
index 80a6e0c72..ce9c4ea80 100644
--- a/cmd/chat_subcommand_model.go
+++ b/cmd/chat_subcommand_model.go
@@ -6,7 +6,7 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
// modelSubcommand implements the /model slash command. It shows the
@@ -60,15 +60,15 @@ func (mo *modelSubcommand) Handle(m *chatModel, args []string, text string) (tea
return m, nil
}
}
- if rhoconfig.DeploymentRoutingEnabled(m.settings) {
- arg = rhoconfig.ResolveCanonicalModel(arg)
+ if decoderconfig.DeploymentRoutingEnabled(m.settings) {
+ arg = decoderconfig.ResolveCanonicalModel(arg)
}
prevModel := m.session.Model()
if strings.EqualFold(strings.TrimSpace(prevModel), strings.TrimSpace(arg)) {
m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Already using %s — no change.", prevModel)})
return m, nil
}
- if err := rhoconfig.SetGlobalSetting("model", arg); err != nil {
+ if err := decoderconfig.SetGlobalSetting("model", arg); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
return m, nil
}
@@ -81,15 +81,15 @@ func (mo *modelSubcommand) Handle(m *chatModel, args []string, text string) (tea
if m.session != nil {
provider = m.session.Provider()
}
- m.session.SetThinkingEnabled(rhoconfig.ResolveThinkingForModel(rhoconfig.LoadSettings(), arg, provider))
+ m.session.SetThinkingEnabled(decoderconfig.ResolveThinkingForModel(decoderconfig.LoadSettings(), arg, provider))
}
- thinkLabel := rhoconfig.FormatModelThinkingLabel(
- selected != nil && rhoconfig.ModelCapabilitySupportsThinking(selected.Capabilities),
- rhoconfig.ThinkingPrefForModel(rhoconfig.LoadSettings(), arg),
+ thinkLabel := decoderconfig.FormatModelThinkingLabel(
+ selected != nil && decoderconfig.ModelCapabilitySupportsThinking(selected.Capabilities),
+ decoderconfig.ThinkingPrefForModel(decoderconfig.LoadSettings(), arg),
m.session.Provider(),
)
m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf(
- "Model switched: %s → %s (Think: %s)\nConversation history preserved (%d messages); new requests use the new model.\nSaved in flux (provider.json). Use /model and press t to toggle Think.",
+ "Model switched: %s → %s (Think: %s)\nConversation history preserved (%d messages); new requests use the new model.\nSaved in mux (provider.json). Use /model and press t to toggle Think.",
prevModel, m.session.Model(), thinkLabel, msgCount,
)})
return m, nil
diff --git a/cmd/chat_subcommand_party.go b/cmd/chat_subcommand_party.go
index 4aa0c8347..77e853a23 100644
--- a/cmd/chat_subcommand_party.go
+++ b/cmd/chat_subcommand_party.go
@@ -5,7 +5,7 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// partySubcommand implements the /party slash command. It starts a
diff --git a/cmd/chat_subcommand_path.go b/cmd/chat_subcommand_path.go
index 94d4c6f35..eed5b831e 100644
--- a/cmd/chat_subcommand_path.go
+++ b/cmd/chat_subcommand_path.go
@@ -5,7 +5,7 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
// pathSubcommand implements the /path slash command. It prints
@@ -17,7 +17,7 @@ func (p *pathSubcommand) Aliases() []string { return nil }
func (p *pathSubcommand) Description() string { return "show developer path (HOME, GOROOT, etc.)" }
func (p *pathSubcommand) Usage() string { return "" }
func (p *pathSubcommand) Handle(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
- m.messages = append(m.messages, displayMsg{role: "system", content: rhoconfig.FormatDeveloperPathReport(context.Background())})
+ m.messages = append(m.messages, displayMsg{role: "system", content: decoderconfig.FormatDeveloperPathReport(context.Background())})
return m, nil
}
diff --git a/cmd/chat_subcommand_recipe.go b/cmd/chat_subcommand_recipe.go
index 3ccd5bf80..043e9f0e2 100644
--- a/cmd/chat_subcommand_recipe.go
+++ b/cmd/chat_subcommand_recipe.go
@@ -7,7 +7,7 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/recipe"
+ "github.com/GrayCodeAI/decoder/internal/recipe"
)
// recipeSubcommand implements the /recipe slash command. It
@@ -25,7 +25,7 @@ func (r *recipeSubcommand) Handle(m *chatModel, args []string, text string) (tea
rn := recipe.NewRunner()
recipes := rn.List()
if len(recipes) == 0 {
- m.messages = append(m.messages, displayMsg{role: "system", content: "No recipes found in Rho user state or .agents/recipes/"})
+ m.messages = append(m.messages, displayMsg{role: "system", content: "No recipes found in Decoder user state or .agents/recipes/"})
} else {
var list string
for _, r := range recipes {
diff --git a/cmd/chat_subcommand_reflect.go b/cmd/chat_subcommand_reflect.go
index efdba6c3a..294939b4f 100644
--- a/cmd/chat_subcommand_reflect.go
+++ b/cmd/chat_subcommand_reflect.go
@@ -3,7 +3,7 @@ package cmd
import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// reflectSubcommand implements the /reflect slash command. It
diff --git a/cmd/chat_subcommand_render.go b/cmd/chat_subcommand_render.go
index 5e5d67bb1..55985445d 100644
--- a/cmd/chat_subcommand_render.go
+++ b/cmd/chat_subcommand_render.go
@@ -6,7 +6,7 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// renderSubcommand implements the /render slash command. It
diff --git a/cmd/chat_subcommand_review.go b/cmd/chat_subcommand_review.go
index 80c181682..746453f5f 100644
--- a/cmd/chat_subcommand_review.go
+++ b/cmd/chat_subcommand_review.go
@@ -3,7 +3,7 @@ package cmd
import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// reviewSubcommand implements the /review slash command. It
diff --git a/cmd/chat_subcommand_shell_test.go b/cmd/chat_subcommand_shell_test.go
index aa10dfbe7..14b697efd 100644
--- a/cmd/chat_subcommand_shell_test.go
+++ b/cmd/chat_subcommand_shell_test.go
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
)
func TestRunSubcommand_UsesBashToolForSafeCommand(t *testing.T) {
diff --git a/cmd/chat_subcommand_simple.go b/cmd/chat_subcommand_simple.go
index ba85aa986..f3547189e 100644
--- a/cmd/chat_subcommand_simple.go
+++ b/cmd/chat_subcommand_simple.go
@@ -11,13 +11,13 @@ import (
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- analytics "github.com/GrayCodeAI/rho/internal/observability"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/storage"
- "github.com/GrayCodeAI/rho/internal/theme"
- "github.com/GrayCodeAI/rho/internal/tool"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ analytics "github.com/GrayCodeAI/decoder/internal/observability"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/theme"
+ "github.com/GrayCodeAI/decoder/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// init() registers a large batch of simple /slash commands via
@@ -88,7 +88,7 @@ func init() {
m.themePicker = NewThemePicker()
}
// Pre-select the current saved theme.
- current := rhoconfig.LoadGlobalSettings().Theme
+ current := decoderconfig.LoadGlobalSettings().Theme
m.themePicker.OpenWithCurrent(current)
m.viewDirty = true
m.updateViewportContent()
@@ -96,7 +96,7 @@ func init() {
}
// Inline: /theme
themeName := args[0]
- if err := rhoconfig.SetGlobalSetting("theme", themeName); err != nil {
+ if err := decoderconfig.SetGlobalSetting("theme", themeName); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
} else {
// Apply immediately — full palette swap, no restart needed.
@@ -117,7 +117,7 @@ func init() {
m.messages = append(m.messages, displayMsg{role: "system", content: "Usage: /color "})
return m, nil
}
- if err := rhoconfig.SetGlobalSetting("agentColor", args[0]); err != nil {
+ if err := decoderconfig.SetGlobalSetting("agentColor", args[0]); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
} else {
m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Agent color set to: %s", args[0])})
@@ -132,12 +132,12 @@ func init() {
description: "toggle fast mode (cheapest model for this provider)",
usage: "",
handler: func(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
- savedModel := rhoconfig.ActiveModel(context.Background())
+ savedModel := decoderconfig.ActiveModel(context.Background())
if m.session.Model() == savedModel {
providerName := strings.TrimSpace(m.session.Provider())
- fastModel := rhoconfig.CheapestModelForProvider(providerName, m.session.Model())
+ fastModel := decoderconfig.CheapestModelForProvider(providerName, m.session.Model())
if strings.TrimSpace(fastModel) == "" {
- fastModel = rhoconfig.DefaultModelForProvider(providerName)
+ fastModel = decoderconfig.DefaultModelForProvider(providerName)
}
if strings.TrimSpace(fastModel) == "" {
m.messages = append(m.messages, displayMsg{role: "error", content: "Fast mode: no catalog model resolved for this provider"})
@@ -166,7 +166,7 @@ func init() {
level := strings.ToLower(args[0])
switch level {
case "low", "medium", "high":
- _ = rhoconfig.SetGlobalSetting("reasoningEffort", level)
+ _ = decoderconfig.SetGlobalSetting("reasoningEffort", level)
m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Reasoning effort → %s", level)})
default:
m.messages = append(m.messages, displayMsg{role: "error", content: "Valid levels: low, medium, high"})
@@ -321,14 +321,14 @@ func init() {
description: "toggle compact mode (removes outer padding)",
usage: "",
handler: func(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
- settings := rhoconfig.LoadGlobalSettings()
+ settings := decoderconfig.LoadGlobalSettings()
current := settings.CompactMode
newVal := !current
valStr := "false"
if newVal {
valStr = "true"
}
- if err := rhoconfig.SetGlobalSetting("compact_mode", valStr); err != nil {
+ if err := decoderconfig.SetGlobalSetting("compact_mode", valStr); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
} else {
state := "disabled"
@@ -350,7 +350,7 @@ func init() {
usage: "/scroll-speed <1-100>",
handler: func(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
if len(args) < 1 {
- m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Usage: /scroll-speed <1-100>\nCurrent: %d", rhoconfig.LoadGlobalSettings().ScrollSpeed)})
+ m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Usage: /scroll-speed <1-100>\nCurrent: %d", decoderconfig.LoadGlobalSettings().ScrollSpeed)})
return m, nil
}
speed, err := strconv.Atoi(args[0])
@@ -358,7 +358,7 @@ func init() {
m.messages = append(m.messages, displayMsg{role: "error", content: "Scroll speed must be 1-100"})
return m, nil
}
- if err := rhoconfig.SetGlobalSetting("scroll_speed", args[0]); err != nil {
+ if err := decoderconfig.SetGlobalSetting("scroll_speed", args[0]); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
} else {
m.messages = append(m.messages, displayMsg{role: "system", content: "Scroll speed → " + args[0]})
@@ -373,7 +373,7 @@ func init() {
description: "toggle natural scrolling (invert direction)",
usage: "",
handler: func(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
- settings := rhoconfig.LoadGlobalSettings()
+ settings := decoderconfig.LoadGlobalSettings()
current := settings.InvertScroll
newVal := !current
valStr := "false"
@@ -384,7 +384,7 @@ func init() {
if newVal {
enabled = "enabled"
}
- if err := rhoconfig.SetGlobalSetting("invert_scroll", valStr); err != nil {
+ if err := decoderconfig.SetGlobalSetting("invert_scroll", valStr); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
} else {
m.messages = append(m.messages, displayMsg{role: "system", content: "Natural scrolling " + enabled})
@@ -400,13 +400,13 @@ func init() {
usage: "/scroll-mode ",
handler: func(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
if len(args) < 1 {
- m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Usage: /scroll-mode \nCurrent: %s", rhoconfig.LoadGlobalSettings().ScrollMode)})
+ m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Usage: /scroll-mode \nCurrent: %s", decoderconfig.LoadGlobalSettings().ScrollMode)})
return m, nil
}
mode := strings.ToLower(args[0])
switch mode {
case "auto", "wheel", "trackpad":
- if err := rhoconfig.SetGlobalSetting("scrollmode", mode); err != nil {
+ if err := decoderconfig.SetGlobalSetting("scrollmode", mode); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
} else {
m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Scroll mode → %s", mode)})
@@ -445,7 +445,7 @@ func init() {
level = "256-color"
}
- m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Terminal Setup Recommendations:\n\nColor Support: %s\nScroll Mode: %s (use /scroll-mode to change)\nScroll Speed: %d (use /scroll-speed to change)\nCompact Mode: %v (use /compact-mode to toggle)\n\nTips:\n- Set COLORTERM=truecolor for best color experience\n- Use tmux with set -g default-terminal \"tmux-256color\" for 256-color support\n- Enable mouse reporting in your terminal for full TUI interaction", level, rhoconfig.LoadGlobalSettings().ScrollMode, rhoconfig.LoadGlobalSettings().ScrollSpeed, rhoconfig.LoadGlobalSettings().CompactMode)})
+ m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Terminal Setup Recommendations:\n\nColor Support: %s\nScroll Mode: %s (use /scroll-mode to change)\nScroll Speed: %d (use /scroll-speed to change)\nCompact Mode: %v (use /compact-mode to toggle)\n\nTips:\n- Set COLORTERM=truecolor for best color experience\n- Use tmux with set -g default-terminal \"tmux-256color\" for 256-color support\n- Enable mouse reporting in your terminal for full TUI interaction", level, decoderconfig.LoadGlobalSettings().ScrollMode, decoderconfig.LoadGlobalSettings().ScrollSpeed, decoderconfig.LoadGlobalSettings().CompactMode)})
return m, nil
},
})
@@ -457,7 +457,7 @@ func init() {
usage: "/pager-config ",
handler: func(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
if len(args) < 2 {
- s := rhoconfig.LoadGlobalSettings()
+ s := decoderconfig.LoadGlobalSettings()
ln := false
messages := fmt.Sprintf("Pager Configuration:\n lines: %d (0 = unlimited)\n linenumbers: %v\n\nUsage: /pager-config ", s.PaginatorLines, ln)
if s.PaginatorShowLineNums != nil {
@@ -475,7 +475,7 @@ func init() {
m.messages = append(m.messages, displayMsg{role: "error", content: "Lines must be a positive number (0 = unlimited)"})
return m, nil
}
- if err := rhoconfig.SetGlobalSetting("paginatorlines", value); err != nil {
+ if err := decoderconfig.SetGlobalSetting("paginatorlines", value); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
} else {
m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Pager lines → %d", lines)})
@@ -484,13 +484,13 @@ func init() {
case "linenumbers", "linenums", "ln":
switch strings.ToLower(value) {
case "1", "true", "yes", "on":
- if err := rhoconfig.SetGlobalSetting("paginatorshowlinenumbers", "true"); err != nil {
+ if err := decoderconfig.SetGlobalSetting("paginatorshowlinenumbers", "true"); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
} else {
m.messages = append(m.messages, displayMsg{role: "system", content: "Pager line numbers → enabled"})
}
case "0", "false", "no", "off":
- if err := rhoconfig.SetGlobalSetting("paginatorshowlinenumbers", "false"); err != nil {
+ if err := decoderconfig.SetGlobalSetting("paginatorshowlinenumbers", "false"); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
} else {
m.messages = append(m.messages, displayMsg{role: "system", content: "Pager line numbers → disabled"})
@@ -531,10 +531,10 @@ func init() {
// /upgrade — check for updates
subcommandRegistry.Register(&delegatingCommand{
name: "upgrade",
- description: "check for rho updates",
+ description: "check for decoder updates",
usage: "",
handler: func(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
- return m.startPromptCommand("/upgrade", "Check for rho updates and show the latest available version.")
+ return m.startPromptCommand("/upgrade", "Check for decoder updates and show the latest available version.")
},
})
@@ -784,7 +784,7 @@ func init() {
style := strings.ToLower(args[0])
switch style {
case "concise", "normal", "detailed":
- _ = rhoconfig.SetGlobalSetting("outputStyle", style)
+ _ = decoderconfig.SetGlobalSetting("outputStyle", style)
m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("Output style → %s", style)})
default:
m.messages = append(m.messages, displayMsg{role: "error", content: "Valid styles: concise, normal, detailed"})
@@ -929,15 +929,15 @@ func init() {
},
})
- // /feedback — submit feedback saved to Rho user state.
+ // /feedback — submit feedback saved to Decoder user state.
subcommandRegistry.Register(&delegatingCommand{
name: "feedback",
- description: "submit feedback (saved to Rho user state)",
+ description: "submit feedback (saved to Decoder user state)",
usage: "/feedback ",
handler: func(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
body := strings.TrimSpace(strings.TrimPrefix(text, "/feedback"))
if body == "" {
- m.messages = append(m.messages, displayMsg{role: "system", content: "Usage: /feedback \nCaptures session context and saves feedback to Rho user state."})
+ m.messages = append(m.messages, displayMsg{role: "system", content: "Usage: /feedback \nCaptures session context and saves feedback to Decoder user state."})
return m, nil
}
feedDir := filepath.Join(storage.StateDir(), "feedback")
@@ -1042,7 +1042,7 @@ func init() {
description: "show provider deployment status",
usage: "",
handler: func(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
- report, err := rhoconfig.DeploymentStatusReport(context.Background(), m.session.Model())
+ report, err := decoderconfig.DeploymentStatusReport(context.Background(), m.session.Model())
if err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: fmt.Sprintf("Provider status failed: %v", err)})
return m, nil
@@ -1058,7 +1058,7 @@ func init() {
description: "refresh the model catalog",
usage: "",
handler: func(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
- summary, err := rhoconfig.RefreshModelCatalogV1(context.Background())
+ summary, err := decoderconfig.RefreshModelCatalogV1(context.Background())
if err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: fmt.Sprintf("Model catalog refresh failed: %v", err)})
return m, nil
diff --git a/cmd/chat_subcommand_soul.go b/cmd/chat_subcommand_soul.go
index 333d6c01e..70d6a27bb 100644
--- a/cmd/chat_subcommand_soul.go
+++ b/cmd/chat_subcommand_soul.go
@@ -5,7 +5,7 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// soulSubcommand implements the /soul slash command. It shows the
diff --git a/cmd/chat_subcommand_spec.go b/cmd/chat_subcommand_spec.go
index 185948c64..cf72b8efb 100644
--- a/cmd/chat_subcommand_spec.go
+++ b/cmd/chat_subcommand_spec.go
@@ -4,11 +4,11 @@ import (
"fmt"
"strings"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/spec"
+ "github.com/GrayCodeAI/decoder/internal/spec"
)
// specSubcommand implements the /spec slash command: starts (or reports
diff --git a/cmd/chat_subcommand_start.go b/cmd/chat_subcommand_start.go
index fef470b0f..5f62eecc8 100644
--- a/cmd/chat_subcommand_start.go
+++ b/cmd/chat_subcommand_start.go
@@ -6,7 +6,7 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// startSubcommand is the first-run / guided success path.
@@ -32,7 +32,7 @@ func (c *startSubcommand) Handle(m *chatModel, args []string, text string) (tea.
}
var b strings.Builder
- b.WriteString("## Rho quick start\n\n")
+ b.WriteString("## Decoder quick start\n\n")
// 1. Model / session
if m.session != nil {
diff --git a/cmd/chat_subcommand_status.go b/cmd/chat_subcommand_status.go
index 73e5581c1..320385a97 100644
--- a/cmd/chat_subcommand_status.go
+++ b/cmd/chat_subcommand_status.go
@@ -6,8 +6,8 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// statusSubcommand implements the /status slash command. It prints
@@ -35,7 +35,7 @@ func buildStatusInfo(m *chatModel) string {
visible := 0
if m.registry != nil {
toolCount = len(m.registry.PrimaryTools())
- visible = len(m.registry.FluxTools())
+ visible = len(m.registry.MuxTools())
}
work := m.session.WorkMode()
if work == "" {
diff --git a/cmd/chat_subcommand_trust.go b/cmd/chat_subcommand_trust.go
index 786c3d0ec..2d7dbf1d1 100644
--- a/cmd/chat_subcommand_trust.go
+++ b/cmd/chat_subcommand_trust.go
@@ -6,8 +6,8 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// trustSubcommand manages folder trust from the chat TUI.
diff --git a/cmd/chat_subcommand_version.go b/cmd/chat_subcommand_version.go
index f9eac8efb..f33f8903e 100644
--- a/cmd/chat_subcommand_version.go
+++ b/cmd/chat_subcommand_version.go
@@ -7,16 +7,16 @@ import (
)
// versionSubcommand implements the /version slash command. It prints
-// the running rho version. Follows the SubcommandRegistry pattern
+// the running decoder version. Follows the SubcommandRegistry pattern
// demonstrated in chat_subcommand_branch.go.
type versionSubcommand struct{}
func (v *versionSubcommand) Name() string { return "version" }
func (v *versionSubcommand) Aliases() []string { return nil }
-func (v *versionSubcommand) Description() string { return "print the running rho version" }
+func (v *versionSubcommand) Description() string { return "print the running decoder version" }
func (v *versionSubcommand) Usage() string { return "" }
func (v *versionSubcommand) Handle(m *chatModel, args []string, text string) (tea.Model, tea.Cmd) {
- m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("rho v%s", DisplayVersion())})
+ m.messages = append(m.messages, displayMsg{role: "system", content: fmt.Sprintf("decoder v%s", DisplayVersion())})
return m, nil
}
diff --git a/cmd/chat_subcommand_voice.go b/cmd/chat_subcommand_voice.go
index b3cfb62bc..9b10ef0c4 100644
--- a/cmd/chat_subcommand_voice.go
+++ b/cmd/chat_subcommand_voice.go
@@ -47,7 +47,7 @@ func (v *voiceSubcommand) Handle(m *chatModel, args []string, text string) (tea.
// outcome as a voiceResultMsg handled in the update loop.
func (v *voiceSubcommand) recordAndTranscribe() tea.Cmd {
return func() tea.Msg {
- tmpFile := filepath.Join(os.TempDir(), "rho_voice_input.wav")
+ tmpFile := filepath.Join(os.TempDir(), "decoder_voice_input.wav")
var recordCmd *exec.Cmd
if _, err := exec.LookPath("sox"); err == nil {
recordCmd = exec.Command("sox", "-d", tmpFile, "trim", "0", "10") // #nosec G204 -- fixed command 'sox' resolved via exec.LookPath
diff --git a/cmd/chat_submit.go b/cmd/chat_submit.go
index eb6a12e41..4ad3d5a8c 100644
--- a/cmd/chat_submit.go
+++ b/cmd/chat_submit.go
@@ -9,15 +9,15 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/features/shellmode"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/features/shellmode"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// submitUserMessage handles Enter on a non-empty prompt (slash commands, shell, or agent turn).
@@ -79,7 +79,7 @@ func (m chatModel) submitUserMessage() (chatModel, tea.Cmd) {
}
return m, cmd
}
- if setup := rhoconfig.EvaluateSetupCached(context.Background()); setup.NeedsSetup {
+ if setup := decoderconfig.EvaluateSetupCached(context.Background()); setup.NeedsSetup {
hint := setup.Hint
if hint == "" {
hint = "Complete setup in /config (keychain + model)."
diff --git a/cmd/chat_terminal_mouse.go b/cmd/chat_terminal_mouse.go
index a9ea61eb6..1c1c10e49 100644
--- a/cmd/chat_terminal_mouse.go
+++ b/cmd/chat_terminal_mouse.go
@@ -11,7 +11,7 @@ import (
// scroll events to arrive as literal "[<65;99;16M" KeyRunes in the input.
const (
disableMouseCSI = "\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l"
- // Explicitly disable any-motion mode left by an older Rho process, then
+ // Explicitly disable any-motion mode left by an older Decoder process, then
// enable button/cell tracking. Wheel and click events still arrive, while
// ordinary pointer movement no longer floods the Bubble Tea update loop.
enableMouseCSI = "\x1b[?1003l\x1b[?1006h\x1b[?1002h"
diff --git a/cmd/chat_tools.go b/cmd/chat_tools.go
index 49315aae9..598af1340 100644
--- a/cmd/chat_tools.go
+++ b/cmd/chat_tools.go
@@ -6,9 +6,9 @@ import (
"sync"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/lsp"
- "github.com/GrayCodeAI/rho/internal/tool"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/lsp"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
// This file holds the tool-registry construction used by the chat TUI:
@@ -188,7 +188,7 @@ func optionalTools() []tool.Tool {
}
}
-func configuredStartupMCPServers(settings rhoconfig.Settings) []startupMCPServerSpec {
+func configuredStartupMCPServers(settings decoderconfig.Settings) []startupMCPServerSpec {
servers := make([]startupMCPServerSpec, 0, len(settings.MCPServers)+len(mcpServers))
for _, cfg := range settings.MCPServers {
if cfg.Name == "" {
@@ -237,7 +237,7 @@ func configuredStartupMCPServers(settings rhoconfig.Settings) []startupMCPServer
// non-expired OAuth token is stored for this server (see
// internal/tool/mcp_auth.go). A configured static Authorization header, if
// any, takes precedence over the auto-injected one.
-func mergedMCPHeaders(cfg rhoconfig.MCPServerConfig) map[string]string {
+func mergedMCPHeaders(cfg decoderconfig.MCPServerConfig) map[string]string {
headers := make(map[string]string, len(cfg.Headers)+1)
for k, v := range cfg.Headers {
headers[k] = v
@@ -286,7 +286,7 @@ func loadStartupMCPToolSetsWith(loadMCP func(context.Context, string, string, ..
return results
}
-func defaultRegistry(settings rhoconfig.Settings) (*tool.Registry, error) {
+func defaultRegistry(settings decoderconfig.Settings) (*tool.Registry, error) {
// Load essential tools first for fast startup
tools := essentialTools()
if tool.IsPowerShellAvailable() {
diff --git a/cmd/chat_tools_lsp_test.go b/cmd/chat_tools_lsp_test.go
index d1984ea55..f6a2fc639 100644
--- a/cmd/chat_tools_lsp_test.go
+++ b/cmd/chat_tools_lsp_test.go
@@ -3,12 +3,12 @@ package cmd
import (
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/tool"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
func TestDefaultRegistryWiresLanguageServerManager(t *testing.T) {
- registry, err := defaultRegistry(rhoconfig.Settings{})
+ registry, err := defaultRegistry(decoderconfig.Settings{})
if err != nil {
t.Fatal(err)
}
diff --git a/cmd/chat_tools_test.go b/cmd/chat_tools_test.go
index 0a9077c78..2a22edb49 100644
--- a/cmd/chat_tools_test.go
+++ b/cmd/chat_tools_test.go
@@ -8,8 +8,8 @@ import (
"testing"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/tool"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
type registryTestTool struct {
@@ -72,8 +72,8 @@ func TestLoadStartupMCPToolSets_UsesTimeoutAndPreservesOrder(t *testing.T) {
}
func TestConfiguredStartupMCPServers_DispatchesByType(t *testing.T) {
- settings := rhoconfig.Settings{
- MCPServers: []rhoconfig.MCPServerConfig{
+ settings := decoderconfig.Settings{
+ MCPServers: []decoderconfig.MCPServerConfig{
{Name: "stdio-default", Command: "stdio-mcp"},
{Name: "stdio-explicit", Type: "stdio", Command: "stdio-mcp-2"},
{Name: "http-server", Type: "http", URL: "https://example.com/mcp"},
@@ -176,7 +176,7 @@ func TestLoadStartupMCPToolSets_DispatchesRemoteSpecsToRemoteLoader(t *testing.T
}
func TestMergedMCPHeaders_ConfiguredAuthorizationTakesPrecedence(t *testing.T) {
- cfg := rhoconfig.MCPServerConfig{
+ cfg := decoderconfig.MCPServerConfig{
Name: "svc",
Headers: map[string]string{"Authorization": "Bearer static-token", "X-Other": "1"},
}
@@ -220,8 +220,8 @@ func TestDefaultRegistry_SkipsFailedStartupMCPServers(t *testing.T) {
return nil, errors.New("boom")
}
- registry, err := defaultRegistry(rhoconfig.Settings{
- MCPServers: []rhoconfig.MCPServerConfig{{Name: "demo", Command: "demo-mcp"}},
+ registry, err := defaultRegistry(decoderconfig.Settings{
+ MCPServers: []decoderconfig.MCPServerConfig{{Name: "demo", Command: "demo-mcp"}},
})
if err != nil {
t.Fatalf("defaultRegistry returned error: %v", err)
diff --git a/cmd/chat_turn.go b/cmd/chat_turn.go
index ef2ba8ac5..bcaf20fd0 100644
--- a/cmd/chat_turn.go
+++ b/cmd/chat_turn.go
@@ -1,10 +1,10 @@
package cmd
-import chatfeature "github.com/GrayCodeAI/rho/internal/features/chat"
+import chatfeature "github.com/GrayCodeAI/decoder/internal/features/chat"
// turnHadThinkingOnly reports whether the latest user turn ended with internal
// reasoning visible but no assistant reply or tool activity. This is the TUI
-// symptom of flux's ResponseErrorOnlyReasoning health check.
+// symptom of mux's ResponseErrorOnlyReasoning health check.
func turnHadThinkingOnly(messages []displayMsg) bool {
return chatfeature.HadThinkingOnly(toFeatureMessages(messages))
}
diff --git a/cmd/chat_update.go b/cmd/chat_update.go
index 66137ed63..ba6867be6 100644
--- a/cmd/chat_update.go
+++ b/cmd/chat_update.go
@@ -7,15 +7,15 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
"charm.land/bubbles/v2/spinner"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/spec"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/spec"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// This file holds the Bubble Tea event loop for the chat TUI: the central
@@ -92,7 +92,7 @@ func shouldReturnToPromptOnType(msg tea.KeyMsg) bool {
// background workers (watcher, parallel agents, background tasks), and mark
// the model as quitting so the final view can show the resume hint.
func (m *chatModel) quitModel() (tea.Model, tea.Cmd) {
- m.clearInteractivePrompts("rho is exiting")
+ m.clearInteractivePrompts("decoder is exiting")
if m.cancel != nil {
m.cancel()
m.cancel = nil
@@ -312,7 +312,7 @@ func (m chatModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
chosen, handled := m.themePicker.Update(msg)
if handled {
if chosen != nil {
- if err := rhoconfig.SetGlobalSetting("theme", chosen.Name); err != nil {
+ if err := decoderconfig.SetGlobalSetting("theme", chosen.Name); err != nil {
m.messages = append(m.messages, displayMsg{role: "error", content: err.Error()})
} else {
// Apply immediately — repaints with full palette on next frame.
@@ -736,7 +736,7 @@ func (m chatModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.configSaving = false
if msg.err != nil {
if m.configOpen {
- m.configNotice = sanitizeConfigNotice(rhoconfig.FormatConfigProviderError(msg.provider, msg.err))
+ m.configNotice = sanitizeConfigNotice(decoderconfig.FormatConfigProviderError(msg.provider, msg.err))
m.viewDirty = true
m.updateViewportContent()
}
@@ -753,7 +753,7 @@ func (m chatModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.configNotice = ""
}
} else if m.configOpen {
- m.configNotice = rhoconfig.CatalogEmptyHint(context.Background())
+ m.configNotice = decoderconfig.CatalogEmptyHint(context.Background())
}
if m.session != nil && msg.provider != "" {
gw, _ := m.sessionGatewayModel()
@@ -944,8 +944,8 @@ func (m chatModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
line := fmt.Sprintf(
"Context compacted (%s): ~%s → ~%s tokens",
msg.strategy,
- formatRhoTokenCount(msg.tokensBefore),
- formatRhoTokenCount(msg.tokensAfter),
+ formatDecoderTokenCount(msg.tokensBefore),
+ formatDecoderTokenCount(msg.tokensAfter),
)
m.messages = append(m.messages, displayMsg{role: "system", content: line})
m.invalidateConnStatus()
diff --git a/cmd/chat_update_overlays_test.go b/cmd/chat_update_overlays_test.go
index 10a60b61b..30e2f8bcd 100644
--- a/cmd/chat_update_overlays_test.go
+++ b/cmd/chat_update_overlays_test.go
@@ -4,7 +4,7 @@ import (
"testing"
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/session"
)
func TestHistorySearchOverlaySelectsResultAndCloses(t *testing.T) {
@@ -30,7 +30,7 @@ func TestHistorySearchOverlaySelectsResultAndCloses(t *testing.T) {
func TestSessionPickerOverlayDismissesAndClearsState(t *testing.T) {
m := newTestChatModel()
m.sessionPickerOpen = true
- m.sessionPickerInput = "rho"
+ m.sessionPickerInput = "decoder"
m.sessionPickerSel = 2
m.sessionPickerEntries = make([]session.Entry, 1)
m.sessionPickerFiltered = m.sessionPickerEntries
diff --git a/cmd/chat_update_prompts.go b/cmd/chat_update_prompts.go
index 67662c03a..3a6f0088d 100644
--- a/cmd/chat_update_prompts.go
+++ b/cmd/chat_update_prompts.go
@@ -6,11 +6,11 @@ import (
"time"
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
- "github.com/GrayCodeAI/rho/internal/permissions/stableid"
- "github.com/GrayCodeAI/rho/internal/tool"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/permissions/stableid"
+ "github.com/GrayCodeAI/decoder/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// maxPendingPrompts bounds memory and waiting tool calls when a provider emits
@@ -163,7 +163,7 @@ func (m chatModel) handlePermissionAsk(msg permissionAskMsg) (tea.Model, tea.Cmd
func (m chatModel) activatePermissionRequest(req safety.PermissionRequest) (tea.Model, tea.Cmd) {
// Autonomous mode is policy-driven, not interactive. The safety engine has
// already classified this request as requiring a permission callback; at
- // this tier the user explicitly chose for rho to resolve it without a
+ // this tier the user explicitly chose for decoder to resolve it without a
// human-in-the-loop card.
if m.session != nil && m.session.PermSvc() != nil && m.session.PermSvc().RuntimeState().Autonomy == safety.AutonomyYOLO {
resolvePermissionResponse(&req, true)
diff --git a/cmd/chat_update_stream.go b/cmd/chat_update_stream.go
index 9a6b24835..c4753a171 100644
--- a/cmd/chat_update_stream.go
+++ b/cmd/chat_update_stream.go
@@ -7,7 +7,7 @@ import (
"unicode/utf8"
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/session"
)
// Stream-event handlers are kept separate from the main input router. They
@@ -167,7 +167,7 @@ func (m chatModel) handleStreamDone() (tea.Model, tea.Cmd) {
}
ClearTabProgress()
if m.backgrounded && !wasCancelled && hadOutput {
- sendTerminalNotification("rho", "Agent turn complete")
+ sendTerminalNotification("decoder", "Agent turn complete")
}
m.backgrounded = false
m.notifiedComplete = false
diff --git a/cmd/chat_view.go b/cmd/chat_view.go
index 9f0b956ae..d8ce628dc 100644
--- a/cmd/chat_view.go
+++ b/cmd/chat_view.go
@@ -12,7 +12,7 @@ import (
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
"github.com/mattn/go-runewidth"
)
@@ -62,11 +62,11 @@ var (
reCreator = regexp.MustCompile(`(?i)(made|created|developed|built|trained|designed)\s+by\s+(?:a\s+company\s+called\s+|a\s+team\s+(?:at|called)\s+|the\s+team\s+at\s+)?\*{0,2}(Moonshot\s*AI|OpenAI|Anthropic|Google|Google\s*DeepMind|DeepMind|Meta|Meta\s*AI|Alibaba|Alibaba\s*Cloud|Mistral\s*AI|xAI|Microsoft|Microsoft\s*AI|Amazon|AWS|Cohere|01\.AI|Baidu|Huawei|IBM|Nvidia|EleutherAI|Hugging\s*Face|AI21\s*Labs|Yandex|Databricks|StepFun|Xiaomi|Sarvam\s*AI|MiniMax|BharatGen|Z\.ai|Zhipu\s*AI|Cerebras|Technology\s*Innovation\s*Institute|TII|Inflection\s*AI|Stability\s*AI|Anysphere|Cognition\s*AI|Scale\s*AI|Sakana\s*AI)\*{0,2}`)
)
-// sanitizeIdentity replaces model self-identifications with "rho" / "GrayCode AI".
+// sanitizeIdentity replaces model self-identifications with "decoder" / "GrayCode AI".
func sanitizeIdentity(s string) string {
s = reModelName.ReplaceAllStringFunc(s, func(m string) string {
parts := reModelName.FindStringSubmatch(m)
- return parts[1] + " rho"
+ return parts[1] + " decoder"
})
s = reCreator.ReplaceAllString(s, "${1} by GrayCode AI")
return s
@@ -552,7 +552,7 @@ func renderPermissionBox(summary string, width int, timeoutAt time.Time) string
}
}
body := lipgloss.JoinVertical(lipgloss.Left, bodyParts...)
- options := lipgloss.NewStyle().Foreground(rhoColor).Render(strings.Join([]string{
+ options := lipgloss.NewStyle().Foreground(decoderColor).Render(strings.Join([]string{
"[y] allow once [n] deny once",
"[s] allow this action for session",
"[d] deny this tool for session",
@@ -569,7 +569,7 @@ func renderPermissionBox(summary string, width int, timeoutAt time.Time) string
func renderApprovalBox(summary string, width int, timeoutAt time.Time) string {
title := lipgloss.NewStyle().Foreground(errorCoral).Bold(true).Render(icons.Alert() + " High-risk approval required")
body := renderPromptBody(summary, width)
- options := lipgloss.NewStyle().Foreground(rhoColor).Render(strings.Join([]string{
+ options := lipgloss.NewStyle().Foreground(decoderColor).Render(strings.Join([]string{
"[y] approve once [n] deny once",
"[s] approve category for session",
"[5] approve next 5 actions",
@@ -581,7 +581,7 @@ func renderApprovalBox(summary string, width int, timeoutAt time.Time) string {
func renderCredentialBox(summary string, width int, timeoutAt time.Time) string {
title := lipgloss.NewStyle().Foreground(warnAmber).Bold(true).Render(icons.Key() + " Credential access required")
body := renderPromptBody(summary, width)
- options := lipgloss.NewStyle().Foreground(rhoColor).Render("[y] allow access [n] deny access")
+ options := lipgloss.NewStyle().Foreground(decoderColor).Render("[y] allow access [n] deny access")
hint := lipgloss.NewStyle().Foreground(textMuted).Render("Credentials are never shown in the transcript · Esc denies")
return renderPromptCard(title, body, options, hint, warnAmber, width, timeoutAt)
}
@@ -589,7 +589,7 @@ func renderCredentialBox(summary string, width int, timeoutAt time.Time) string
func renderQuestionBox(question string, width int, timeoutAt time.Time) string {
title := lipgloss.NewStyle().Foreground(successTeal).Bold(true).Render(icons.HelpCircle() + " Input required")
body := renderPromptBody(question, width)
- options := lipgloss.NewStyle().Foreground(rhoColor).Render("Type your answer · [Enter] submit · [Esc] deny")
+ options := lipgloss.NewStyle().Foreground(decoderColor).Render("Type your answer · [Enter] submit · [Esc] deny")
hint := lipgloss.NewStyle().Foreground(textMuted).Render("No answer is sent if the prompt expires")
return renderPromptCard(title, body, options, hint, successTeal, width, timeoutAt)
}
@@ -709,7 +709,7 @@ func renderReflectionBox(reflection string, width int) string {
boxW = 40
}
- titleStyle := lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
+ titleStyle := lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
labelStyle := lipgloss.NewStyle().Foreground(infoSky).Bold(true)
contentStyle := lipgloss.NewStyle().Foreground(textPrimary)
@@ -739,7 +739,7 @@ func renderReflectionBox(reflection string, width int) string {
border := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
- BorderForeground(rhoColor).
+ BorderForeground(decoderColor).
Width(boxW).
Padding(0, 1)
@@ -778,12 +778,12 @@ func (m *chatModel) renderTokenCounters() string {
var b strings.Builder
b.WriteString(ansiMagenta + ansiBold + "↓" + ansiReset)
b.WriteString(ansiMagenta)
- b.WriteString(formatRhoTokenCount(outTok))
+ b.WriteString(formatDecoderTokenCount(outTok))
b.WriteString(ansiReset)
b.WriteString(ansiDim + " " + ansiReset)
b.WriteString(ansiCyan + ansiBold + "↑" + ansiReset)
b.WriteString(ansiCyan)
- b.WriteString(formatRhoTokenCount(inTok))
+ b.WriteString(formatDecoderTokenCount(inTok))
b.WriteString(ansiReset)
return b.String()
}
@@ -820,9 +820,9 @@ func (m *chatModel) tokenOutputTarget() int {
return m.turnEstimatedOutputRunes / 4
}
-// formatRhoTokenCount renders a token count in rho's compact form:
+// formatDecoderTokenCount renders a token count in decoder's compact form:
// ≥1m → "1.5m", ≥10k → "150k", else raw digits.
-func formatRhoTokenCount(tokens int) string {
+func formatDecoderTokenCount(tokens int) string {
if tokens <= 0 {
return "0"
}
diff --git a/cmd/chat_view_test.go b/cmd/chat_view_test.go
index 4662015da..cc71eb99e 100644
--- a/cmd/chat_view_test.go
+++ b/cmd/chat_view_test.go
@@ -4,7 +4,7 @@ import (
"testing"
)
-func TestFormatRhoTokenCount(t *testing.T) {
+func TestFormatDecoderTokenCount(t *testing.T) {
t.Parallel()
cases := []struct {
in int
@@ -25,9 +25,9 @@ func TestFormatRhoTokenCount(t *testing.T) {
tc := tc
t.Run("", func(t *testing.T) {
t.Parallel()
- got := formatRhoTokenCount(tc.in)
+ got := formatDecoderTokenCount(tc.in)
if got != tc.want {
- t.Fatalf("formatRhoTokenCount(%d) = %q, want %q", tc.in, got, tc.want)
+ t.Fatalf("formatDecoderTokenCount(%d) = %q, want %q", tc.in, got, tc.want)
}
})
}
diff --git a/cmd/chat_viewport.go b/cmd/chat_viewport.go
index 3e4230871..23a1b6fdc 100644
--- a/cmd/chat_viewport.go
+++ b/cmd/chat_viewport.go
@@ -237,7 +237,7 @@ func (m chatModel) effectiveWheelY(msg tea.MouseMsg) int {
return y
}
-// syncViewportMouseWheel disables bubbletea viewport auto-wheel; rho routes wheel
+// syncViewportMouseWheel disables bubbletea viewport auto-wheel; decoder routes wheel
// events manually so chat scrolls only when the pointer is over the chat pane.
func (m chatModel) syncViewportMouseWheel() chatModel {
m.viewport.MouseWheelEnabled = false
diff --git a/cmd/chat_viewport_render.go b/cmd/chat_viewport_render.go
index 71e592766..3e20fc3c7 100644
--- a/cmd/chat_viewport_render.go
+++ b/cmd/chat_viewport_render.go
@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// Viewport render cache — avoids re-wrapping and re-rendering markdown for the
@@ -30,7 +30,7 @@ const (
)
func renderDisplayMessage(msg displayMsg, i int, messages []displayMsg, viewWidth int, expanded map[int]bool) string {
- rhoC := ansiOrange
+ decoderC := ansiOrange
rst := ansiReset
bgDark := "\033[48;2;30;30;40m"
@@ -50,7 +50,7 @@ func renderDisplayMessage(msg displayMsg, i int, messages []displayMsg, viewWidt
wrappedLines := strings.Split(wrapped, "\n")
for li, wl := range wrappedLines {
if li == 0 {
- b.WriteString(bgDark + rhoC + "█" + rst + bgDark + " " + wl)
+ b.WriteString(bgDark + decoderC + "█" + rst + bgDark + " " + wl)
} else {
b.WriteString(bgDark + " " + wl)
}
@@ -70,7 +70,7 @@ func renderDisplayMessage(msg displayMsg, i int, messages []displayMsg, viewWidt
// message entirely rather than leaving an orphan "◈" line.
return ""
}
- b.WriteString(rhoC + icons.Robot() + " " + rst + renderMarkdown(content, viewWidth-3))
+ b.WriteString(decoderC + icons.Robot() + " " + rst + renderMarkdown(content, viewWidth-3))
case "tool_use":
b.WriteString(toolStyle.Render(icons.CircleFilled() + " " + msg.content))
case "tool_result":
diff --git a/cmd/chat_viewport_test.go b/cmd/chat_viewport_test.go
index b812e331f..860b81b4b 100644
--- a/cmd/chat_viewport_test.go
+++ b/cmd/chat_viewport_test.go
@@ -8,7 +8,7 @@ import (
"charm.land/bubbles/v2/viewport"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func TestRouteKeyToViewport_ArrowsInPromptFocus(t *testing.T) {
@@ -84,20 +84,20 @@ func TestShouldRouteMouseToViewport_SplitPaneUX(t *testing.T) {
}
func TestSyncViewportMouseWheel_ManualRouting(t *testing.T) {
- t.Setenv("RHO_MOUSE", "")
+ t.Setenv("DECODER_MOUSE", "")
vp := viewport.New(viewport.WithWidth(80), viewport.WithHeight(10))
m := chatModel{viewport: vp, uiFocus: focusPrompt}
m = m.syncViewportMouseWheel()
if m.viewport.MouseWheelEnabled {
- t.Fatal("viewport auto-wheel must stay off; rho routes wheel by pane")
+ t.Fatal("viewport auto-wheel must stay off; decoder routes wheel by pane")
}
}
func TestSyncViewportMouseWheel_DisabledWithOptOut(t *testing.T) {
- t.Setenv("RHO_MOUSE", "0")
+ t.Setenv("DECODER_MOUSE", "0")
vp := viewport.New(viewport.WithWidth(80), viewport.WithHeight(10))
disabled := false
- m := chatModel{viewport: vp, uiFocus: focusPrompt, settings: rhoconfig.Settings{TuiMouse: &disabled}}
+ m := chatModel{viewport: vp, uiFocus: focusPrompt, settings: decoderconfig.Settings{TuiMouse: &disabled}}
m = m.syncViewportMouseWheel()
if m.viewport.MouseWheelEnabled {
t.Fatal("wheel should be disabled when mouse capture is off")
diff --git a/cmd/chat_welcome.go b/cmd/chat_welcome.go
index a0ab5f909..12bc138ba 100644
--- a/cmd/chat_welcome.go
+++ b/cmd/chat_welcome.go
@@ -9,23 +9,23 @@ import (
"github.com/mattn/go-runewidth"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/tool"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
type welcomeStatusSnapshot struct {
- setup rhoconfig.SetupState
+ setup decoderconfig.SetupState
agentsOK bool
}
func loadWelcomeStatusSnapshot() welcomeStatusSnapshot {
ctx := context.Background()
return welcomeStatusSnapshot{
- setup: rhoconfig.EvaluateSetupCached(ctx),
- agentsOK: rhoconfig.LoadAgentsMD() != "",
+ setup: decoderconfig.EvaluateSetupCached(ctx),
+ agentsOK: decoderconfig.LoadAgentsMD() != "",
}
}
@@ -71,8 +71,8 @@ func (m *chatModel) rebuildWelcomeCache(opts ...any) {
m.welcomeCache = buildWelcomeMessageWithSnapshotAndMascot(m.session, m.sessionID, m.registry, nil, m.settings, skillsCount, connectedMCPCount(m.registry), frame, width, height, m.welcomeStatusSnapshot(), m.lastCommand, m.mascotEnabled)
}
-// buildWelcomeMessage renders the branded inline RHO welcome block.
-func buildWelcomeMessage(sess *engine.Session, sessionID string, registry *tool.Registry, saved *session.Session, settings rhoconfig.Settings, skillsCount int, blinkClosed bool, width, height int) string {
+// buildWelcomeMessage renders the branded inline DECODER welcome block.
+func buildWelcomeMessage(sess *engine.Session, sessionID string, registry *tool.Registry, saved *session.Session, settings decoderconfig.Settings, skillsCount int, blinkClosed bool, width, height int) string {
frame := 0
if blinkClosed {
frame = 2
@@ -80,12 +80,12 @@ func buildWelcomeMessage(sess *engine.Session, sessionID string, registry *tool.
return buildWelcomeMessageWithSnapshot(sess, sessionID, registry, saved, settings, skillsCount, connectedMCPCount(registry), frame, width, height, loadWelcomeStatusSnapshot(), "")
}
-func buildWelcomeMessageWithSnapshot(sess *engine.Session, sessionID string, registry *tool.Registry, saved *session.Session, settings rhoconfig.Settings, skillsCount, mcpCount int, eyeFrame int, width, height int, snapshot welcomeStatusSnapshot, lastCommand string) string {
+func buildWelcomeMessageWithSnapshot(sess *engine.Session, sessionID string, registry *tool.Registry, saved *session.Session, settings decoderconfig.Settings, skillsCount, mcpCount int, eyeFrame int, width, height int, snapshot welcomeStatusSnapshot, lastCommand string) string {
return buildWelcomeMessageWithSnapshotAndMascot(sess, sessionID, registry, saved, settings, skillsCount, mcpCount, eyeFrame, width, height, snapshot, lastCommand, false)
}
-func buildWelcomeMessageWithSnapshotAndMascot(sess *engine.Session, sessionID string, registry *tool.Registry, saved *session.Session, settings rhoconfig.Settings, skillsCount, mcpCount int, eyeFrame int, width, height int, snapshot welcomeStatusSnapshot, lastCommand string, useMascot bool) string {
- // Talon Gold is used for the RHO wordmark. All escapes come from the
+func buildWelcomeMessageWithSnapshotAndMascot(sess *engine.Session, sessionID string, registry *tool.Registry, saved *session.Session, settings decoderconfig.Settings, skillsCount, mcpCount int, eyeFrame int, width, height int, snapshot welcomeStatusSnapshot, lastCommand string, useMascot bool) string {
+ // Talon Gold is used for the DECODER wordmark. All escapes come from the
// theme palette (theme.go) so a rebrand stays a one-file change.
logoC := ansiOrange
dimC := ansiDim
@@ -123,7 +123,7 @@ func buildWelcomeMessageWithSnapshotAndMascot(sess *engine.Session, sessionID st
return strings.Repeat(" ", pad) + styled
}
- art := rhoLogoArtLines
+ art := decoderLogoArtLines
useMascot = useMascot && !tight
// Keep the text wordmark even when a graphical mascot is requested. The
// mascot is a best-effort terminal escape sequence; hiding the canonical
@@ -137,13 +137,13 @@ func buildWelcomeMessageWithSnapshotAndMascot(sess *engine.Session, sessionID st
eyeGlyph = "|-\\/-|"
}
if eyeGlyph != "" && !useMascot {
- art = append([]string(nil), rhoLogoArtLines...)
+ art = append([]string(nil), decoderLogoArtLines...)
for i, line := range art {
art[i] = strings.Replace(line, "|0\\/0|", eyeGlyph, 1)
}
}
- // Inject the version into the rho's body — centered in the lower gap.
+ // Inject the version into the decoder's body — centered in the lower gap.
verStr := DisplayVersion()
if verStr != "" && !strings.HasPrefix(verStr, "v") && !strings.HasPrefix(verStr, "V") {
verStr = "v" + verStr
@@ -166,13 +166,13 @@ func buildWelcomeMessageWithSnapshotAndMascot(sess *engine.Session, sessionID st
if tight {
// Compact single-line wordmark for small terminals — version sits
- // inline so it's always visible even when the full rho is hidden.
+ // inline so it's always visible even when the full decoder is hidden.
verDisplay := DisplayVersion()
if verDisplay != "" && !strings.HasPrefix(verDisplay, "v") && !strings.HasPrefix(verDisplay, "V") {
verDisplay = "v" + verDisplay
}
- compactArt := logoC + "RHO" + rst + " " + verDisplay
- b.WriteString(center(runewidth.StringWidth("RHO "+verDisplay), compactArt) + "\n")
+ compactArt := logoC + "DECODER" + rst + " " + verDisplay
+ b.WriteString(center(runewidth.StringWidth("DECODER "+verDisplay), compactArt) + "\n")
} else {
artW := blockLinesWidth(art)
for _, line := range art {
@@ -204,7 +204,7 @@ func buildWelcomeMessageWithSnapshotAndMascot(sess *engine.Session, sessionID st
// short lines rather than a panel: the input remains the primary action,
// while the empty state explains what to type without consuming the chat.
b.WriteString("\n")
- guidance := dimC + "Inspect, change, or test this codebase with rho." + rst
+ guidance := dimC + "Inspect, change, or test this codebase with decoder." + rst
examples := dimC + `Try: "explain this repo" · "run the tests" · "/help"` + rst
b.WriteString(center(visibleWidth(guidance), guidance) + "\n")
b.WriteString(center(visibleWidth(examples), examples) + "\n")
@@ -321,7 +321,7 @@ func welcomeIndicatorRow(skillsCount int, agentsOK bool, mcpCount int, activeC,
)
}
-// welcomeModeBadge is intentionally absent; rho uses host permission tiers.
+// welcomeModeBadge is intentionally absent; decoder uses host permission tiers.
func actLine(saved *session.Session, sessionID string) string {
if saved != nil && len(sessionID) >= 8 {
@@ -334,7 +334,7 @@ func toolListSummary(registry *tool.Registry) string {
if registry == nil {
return "No tools enabled."
}
- tools := registry.FluxTools()
+ tools := registry.MuxTools()
registered := len(registry.PrimaryTools())
if len(tools) == 0 {
return "No tools enabled."
@@ -364,7 +364,7 @@ func envSummary(provider, model string) string {
func envSummaryWithSelection(provider, model string, includeSelection bool) string {
var providers []string
- for _, gateway := range rhoconfig.GatewayStatuses(context.Background(), provider, model) {
+ for _, gateway := range decoderconfig.GatewayStatuses(context.Background(), provider, model) {
providers = append(providers, gateway.ID)
}
sort.Strings(providers)
@@ -372,17 +372,17 @@ func envSummaryWithSelection(provider, model string, includeSelection bool) stri
if includeSelection {
b.WriteString(fmt.Sprintf("Provider: %s\nModel: %s\n\n", provider, model))
}
- b.WriteString(fmt.Sprintf("Credentials (%s):\n", rhoconfig.CredentialStoreName()))
+ b.WriteString(fmt.Sprintf("Credentials (%s):\n", decoderconfig.CredentialStoreName()))
for _, providerID := range providers {
- b.WriteString(fmt.Sprintf(" %s: %s\n", providerID, rhoconfig.EnvKeyStatus(providerID)))
+ b.WriteString(fmt.Sprintf(" %s: %s\n", providerID, decoderconfig.EnvKeyStatus(providerID)))
}
return strings.TrimRight(b.String(), "\n")
}
-func configCommandSummary(settings rhoconfig.Settings) string {
+func configCommandSummary(settings decoderconfig.Settings) string {
_ = settings
- providerName := displayConfigValue(rhoconfig.ActiveProvider(context.Background()))
- modelName := displayConfigValue(rhoconfig.ActiveModel(context.Background()))
+ providerName := displayConfigValue(decoderconfig.ActiveProvider(context.Background()))
+ modelName := displayConfigValue(decoderconfig.ActiveModel(context.Background()))
keys := configuredKeyList()
keysColor := infoSky
if keys == "(none)" {
@@ -392,15 +392,15 @@ func configCommandSummary(settings rhoconfig.Settings) string {
/config → paste API key (OS keychain) + pick model
/path → verify readiness in TUI
- rho path (CLI)
+ decoder path (CLI)
%s:
%s %s
%s %s
%s %s
-Model catalog and routing live in flux — rho is the UI only.`,
- auditTint("Setup (flux)", textPrimary),
+Model catalog and routing live in mux — decoder is the UI only.`,
+ auditTint("Setup (mux)", textPrimary),
auditTint("Current", textPrimary),
auditTint("provider:", textMuted), auditTint(providerName, infoSky),
auditTint("model:", textMuted), auditTint(modelName, infoSky),
@@ -408,7 +408,7 @@ Model catalog and routing live in flux — rho is the UI only.`,
}
func apiKeyConfigSummary() string {
- return auditTint("API keys ("+rhoconfig.CredentialStoreName()+")", textPrimary) + "\n" + indentedAPIKeyLines()
+ return auditTint("API keys ("+decoderconfig.CredentialStoreName()+")", textPrimary) + "\n" + indentedAPIKeyLines()
}
func configuredKeyList() string {
@@ -454,11 +454,11 @@ func apiKeyStatusColor(status string) color.Color {
}
func apiKeyStatusLines() []string {
- providers := rhoconfig.AllSetupGateways()
+ providers := decoderconfig.AllSetupGateways()
sort.Strings(providers)
var lines []string
for _, provider := range providers {
- lines = append(lines, fmt.Sprintf("%s: %s", provider, rhoconfig.EnvKeyStatus(provider)))
+ lines = append(lines, fmt.Sprintf("%s: %s", provider, decoderconfig.EnvKeyStatus(provider)))
}
return lines
}
diff --git a/cmd/chat_yolo_confirm_test.go b/cmd/chat_yolo_confirm_test.go
index f48602fcb..4d18103b3 100644
--- a/cmd/chat_yolo_confirm_test.go
+++ b/cmd/chat_yolo_confirm_test.go
@@ -5,7 +5,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
)
func TestYOLOConfirm_PendingConsumesNextInput(t *testing.T) {
diff --git a/cmd/checkpoint.go b/cmd/checkpoint.go
index cab4e4558..70e3c124d 100644
--- a/cmd/checkpoint.go
+++ b/cmd/checkpoint.go
@@ -5,19 +5,19 @@ import (
"fmt"
"time"
- "github.com/GrayCodeAI/rho/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/session"
"github.com/spf13/cobra"
)
// checkpointCmd groups named session-checkpoint operations: snapshot the current
// (or latest) session under a label, list snapshots, restore one, or delete one.
// This is additive on top of `--resume `; named checkpoints let you save a
-// labeled point you can come back to with `rho resume `.
+// labeled point you can come back to with `decoder resume `.
var checkpointCmd = &cobra.Command{
Use: "checkpoint",
Short: "Save and restore named session checkpoints",
Long: `checkpoint snapshots a session under a human-friendly label so you can
-return to it later with "rho resume ".
+return to it later with "decoder resume ".
Subcommands:
save Snapshot the latest session in this directory under
@@ -49,7 +49,7 @@ var checkpointSaveCmd = &cobra.Command{
return err
}
cmd.Printf("%s\n", auditTint("Saved checkpoint ", doneGreen)+auditTint(cp.Name, textPrimary)+auditTint(fmt.Sprintf(" (session %s, %d messages, %s/%s)", cp.Session.ID, len(cp.Session.Messages), cp.Session.Provider, cp.Session.Model), textMuted))
- cmd.Printf("%s\n", auditTint("Resume with: rho resume "+name, textMuted))
+ cmd.Printf("%s\n", auditTint("Resume with: decoder resume "+name, textMuted))
return nil
},
}
@@ -125,12 +125,12 @@ var checkpointDeleteCmd = &cobra.Command{
},
}
-// resumeCmd is a top-level convenience for `rho resume `: it restores a
+// resumeCmd is a top-level convenience for `decoder resume `: it restores a
// named checkpoint into a session file and tells the user how to continue it.
var resumeCmd = &cobra.Command{
Use: "resume ",
Short: "Restore a named session checkpoint and resume it",
- Long: `resume restores a session previously saved with "rho checkpoint save"
+ Long: `resume restores a session previously saved with "decoder checkpoint save"
into a resumable session, then prints the command to continue the conversation.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
@@ -154,7 +154,7 @@ func restoreNamedCheckpoint(cmd *cobra.Command, name string) error {
return fmt.Errorf("restore session: %w", err)
}
cmd.Printf("%s\n", auditTint("Restored checkpoint ", doneGreen)+auditTint(cp.Name, textPrimary)+auditTint(fmt.Sprintf(" into session %s (%d messages, %s/%s)", cp.Session.ID, len(cp.Session.Messages), cp.Session.Provider, cp.Session.Model), textMuted))
- cmd.Printf("%s\n", auditTint("Continue with: rho --resume "+cp.Session.ID, textMuted))
+ cmd.Printf("%s\n", auditTint("Continue with: decoder --resume "+cp.Session.ID, textMuted))
return nil
}
diff --git a/cmd/cli_contracts_test.go b/cmd/cli_contracts_test.go
index 010b99b8f..f7c869e61 100644
--- a/cmd/cli_contracts_test.go
+++ b/cmd/cli_contracts_test.go
@@ -10,9 +10,9 @@ import (
"testing"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/session"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/session"
)
func TestResumeRecoveredSession_StartsChatFlow(t *testing.T) {
@@ -62,7 +62,7 @@ func TestResumeRecoveredSession_StartsChatFlow(t *testing.T) {
}
func TestPrepareSession_ResumeUsesRecoveryPath(t *testing.T) {
- t.Setenv("RHO_STATE_DIR", t.TempDir())
+ t.Setenv("DECODER_STATE_DIR", t.TempDir())
oldResumeID := resumeID
oldContinueFlag := continueFlag
@@ -121,7 +121,7 @@ func TestPrepareSession_ResumeUsesRecoveryPath(t *testing.T) {
t.Fatalf("loaded persisted messages = %d, want %d", sess.MessageCount(), len(saved.Messages))
}
- walPath := filepath.Join(os.Getenv("RHO_STATE_DIR"), "sessions", saved.ID+".wal")
+ walPath := filepath.Join(os.Getenv("DECODER_STATE_DIR"), "sessions", saved.ID+".wal")
if _, err := os.Stat(walPath); !os.IsNotExist(err) {
t.Fatalf("expected stale WAL to be removed, stat err = %v", err)
}
@@ -154,7 +154,7 @@ func TestReplBuiltinResponse_ToolsAndSession(t *testing.T) {
sess := engine.NewSession("demo-provider", "demo-model", "system", nil)
sess.AddUser("hello")
- toolsOut, handled, err := replBuiltinResponse("/tools", sess, rhoconfig.Settings{}, "session-1")
+ toolsOut, handled, err := replBuiltinResponse("/tools", sess, decoderconfig.Settings{}, "session-1")
if err != nil {
t.Fatalf("/tools error = %v", err)
}
@@ -165,7 +165,7 @@ func TestReplBuiltinResponse_ToolsAndSession(t *testing.T) {
t.Fatalf("/tools output missing tool summary: %q", toolsOut)
}
- sessionOut, handled, err := replBuiltinResponse("/session", sess, rhoconfig.Settings{}, "session-1")
+ sessionOut, handled, err := replBuiltinResponse("/session", sess, decoderconfig.Settings{}, "session-1")
if err != nil {
t.Fatalf("/session error = %v", err)
}
@@ -181,7 +181,7 @@ func TestReplBuiltinResponse_ToolsAndSession(t *testing.T) {
func TestReplBuiltinResponse_Models(t *testing.T) {
sess := engine.NewSession("openrouter", "openrouter/auto", "system", nil)
- out, handled, err := replBuiltinResponse("/models", sess, rhoconfig.Settings{}, "session-1")
+ out, handled, err := replBuiltinResponse("/models", sess, decoderconfig.Settings{}, "session-1")
if err != nil {
t.Fatalf("/models error = %v", err)
}
@@ -218,7 +218,7 @@ func TestPluginListSubcommandUsesCobraTree(t *testing.T) {
}
func TestRecoverCommand_ExecutesResumeFlow(t *testing.T) {
- t.Setenv("RHO_STATE_DIR", t.TempDir())
+ t.Setenv("DECODER_STATE_DIR", t.TempDir())
oldResumeID := resumeID
oldContinueFlag := continueFlag
diff --git a/cmd/clipboard.go b/cmd/clipboard.go
index 5dc2e99bc..199d27877 100644
--- a/cmd/clipboard.go
+++ b/cmd/clipboard.go
@@ -11,7 +11,7 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/storage"
)
// copyResult describes where the copied content ended up.
@@ -68,7 +68,7 @@ func copyToClipboardNative(text string) error {
}
// copyToFallbackFile writes the given text to a timestamped file in the
-// rho state directory when the system clipboard is unavailable. This
+// decoder state directory when the system clipboard is unavailable. This
// ensures the user can still recover copied content from SSH sessions,
// containers, or headless environments.
func copyToFallbackFile(text string) (string, error) {
diff --git a/cmd/clipboard_test.go b/cmd/clipboard_test.go
index c0437147b..d60b06edb 100644
--- a/cmd/clipboard_test.go
+++ b/cmd/clipboard_test.go
@@ -30,7 +30,7 @@ func TestClipboardRoundTrip(t *testing.T) {
t.Skip("skipping clipboard test on linux (requires xclip/xsel)")
}
- text := "rho clipboard test"
+ text := "decoder clipboard test"
if err := copyToClipboardNative(text); err != nil {
t.Skipf("native clipboard unavailable: %v", err)
}
diff --git a/cmd/cloud.go b/cmd/cloud.go
index 24ec543ce..d00c5f3f4 100644
--- a/cmd/cloud.go
+++ b/cmd/cloud.go
@@ -12,7 +12,7 @@ import (
"time"
"unicode"
- cloud "github.com/GrayCodeAI/rho/internal/platform/cloud"
+ cloud "github.com/GrayCodeAI/decoder/internal/platform/cloud"
"github.com/spf13/cobra"
"golang.org/x/term"
)
@@ -29,12 +29,12 @@ var cloudCmd = &cobra.Command{Use: "cloud", Short: "Manage optional GrayCode Clo
func newCloudConnectCmd() *cobra.Command {
command := &cobra.Command{
Use: "connect",
- Short: "Connect this Rho device to GrayCode Cloud with an existing device token",
- Long: `Save an existing GrayCode Cloud device connection. Prefer "rho cloud login",
+ Short: "Connect this Decoder device to GrayCode Cloud with an existing device token",
+ Long: `Save an existing GrayCode Cloud device connection. Prefer "decoder cloud login",
which needs no token. The device token is read with --token-stdin or from a
hidden prompt, never from the command line:
- rho cloud connect --device-id --project-id --token-stdin < token.txt`,
+ decoder cloud connect --device-id --project-id --token-stdin < token.txt`,
RunE: func(cmd *cobra.Command, _ []string) error {
endpointFlag, _ := cmd.Flags().GetString("endpoint")
endpoint, err := cloud.ResolveEndpoint(endpointFlag)
@@ -88,11 +88,11 @@ func warnIfPlaintextTokenStore(cmd *cobra.Command) {
if !plaintext {
return
}
- cmd.PrintErrln(auditTint("Warning: rho has no OS credential store integration on this platform, so the GrayCode Cloud device token was saved in the "+where+
+ cmd.PrintErrln(auditTint("Warning: decoder has no OS credential store integration on this platform, so the GrayCode Cloud device token was saved in the "+where+
". Any process running as your user, and any backup of that file, can read it. Keep the file private and revoke the device in GrayCode Cloud if this machine is shared or lost.", warnAmber))
}
-// readDeviceToken returns the device token for `rho cloud connect` from, in
+// readDeviceToken returns the device token for `decoder cloud connect` from, in
// order: --token-stdin, the deprecated --token flag, or a hidden prompt when
// stdin is a terminal. The token never has to appear in argv, where it would
// land in shell history and be visible to other users via ps.
@@ -123,7 +123,7 @@ func readDeviceToken(cmd *cobra.Command) (string, error) {
}
raw = string(data)
default:
- return "", errors.New("a device token is required: pipe it with --token-stdin, or run in a terminal to be prompted (`rho cloud login` needs no token)")
+ return "", errors.New("a device token is required: pipe it with --token-stdin, or run in a terminal to be prompted (`decoder cloud login` needs no token)")
}
token := strings.TrimSpace(raw)
if token == "" {
@@ -167,7 +167,7 @@ http:// on localhost, 127.0.0.1 and [::1].`,
if err != nil {
return err
}
- cmd.Printf("%s\n", auditTint("Open ", textPrimary)+auditTint(start.VerificationURI, infoSky)+auditTint(" and enter code ", textPrimary)+auditTint(start.UserCode, rhoColor))
+ cmd.Printf("%s\n", auditTint("Open ", textPrimary)+auditTint(start.VerificationURI, infoSky)+auditTint(" and enter code ", textPrimary)+auditTint(start.UserCode, decoderColor))
if err := openBrowser(approvalURL); err != nil {
cmd.Printf("%s\n", auditTint(fmt.Sprintf("Could not open the browser automatically: %v", err), textMuted))
}
@@ -208,7 +208,7 @@ http:// on localhost, 127.0.0.1 and [::1].`,
},
}
command.Flags().String("endpoint", "", cloudEndpointFlagHelp)
- command.Flags().String("label", "", "Name for this Rho device")
+ command.Flags().String("label", "", "Name for this Decoder device")
return command
}
@@ -218,7 +218,7 @@ func newCloudStatusCmd() *cobra.Command {
RunE: func(cmd *cobra.Command, _ []string) error {
client, cfg, err := loadCloudClient()
if errors.Is(err, cloud.ErrNotConnected) {
- cmd.Println(auditTint("GrayCode Cloud is not connected. Run `rho cloud login` to connect.", textMuted))
+ cmd.Println(auditTint("GrayCode Cloud is not connected. Run `decoder cloud login` to connect.", textMuted))
return nil
}
if err != nil {
diff --git a/cmd/cloud_context_test.go b/cmd/cloud_context_test.go
index 6941350c2..a05235305 100644
--- a/cmd/cloud_context_test.go
+++ b/cmd/cloud_context_test.go
@@ -12,7 +12,7 @@ func TestDetectGitContext(t *testing.T) {
runCloudGit = func(_ context.Context, args ...string) (string, error) {
switch args[0] {
case "config":
- return "git@github.com:GrayCodeAI/rho.git", nil
+ return "git@github.com:GrayCodeAI/decoder.git", nil
case "branch":
return "main", nil
case "rev-parse":
@@ -25,7 +25,7 @@ func TestDetectGitContext(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if got.Repository != "GrayCodeAI/rho" || got.Provider != "github" || got.Branch != "main" || got.Commit != "abc123" {
+ if got.Repository != "GrayCodeAI/decoder" || got.Provider != "github" || got.Branch != "main" || got.Commit != "abc123" {
t.Fatalf("context = %+v", got)
}
}
diff --git a/cmd/cloud_graph.go b/cmd/cloud_graph.go
index 3001d55a8..ba1caecca 100644
--- a/cmd/cloud_graph.go
+++ b/cmd/cloud_graph.go
@@ -5,8 +5,8 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/executiongraph"
- cloud "github.com/GrayCodeAI/rho/internal/platform/cloud"
+ "github.com/GrayCodeAI/decoder/internal/executiongraph"
+ cloud "github.com/GrayCodeAI/decoder/internal/platform/cloud"
"github.com/spf13/cobra"
)
@@ -23,7 +23,7 @@ func newCloudGraphCmd() *cobra.Command {
syncCmd := &cobra.Command{
Use: "sync [session-id]",
Short: "Upload a privacy-normalized execution graph to GrayCode Cloud",
- Long: `Build the same read-only execution graph as "rho graph export", hash
+ Long: `Build the same read-only execution graph as "decoder graph export", hash
cloud-sensitive metadata, enforce GrayCode Cloud's upload bounds, and upload it
with a deterministic idempotency key. Sync completed session snapshots: graph
facts are immutable after acceptance. This is explicit and opt-in; local
diff --git a/cmd/cloud_test.go b/cmd/cloud_test.go
index cdc503a4f..9dfed2775 100644
--- a/cmd/cloud_test.go
+++ b/cmd/cloud_test.go
@@ -12,8 +12,8 @@ import (
"sync/atomic"
"testing"
- "github.com/GrayCodeAI/rho/internal/executiongraph"
- cloud "github.com/GrayCodeAI/rho/internal/platform/cloud"
+ "github.com/GrayCodeAI/decoder/internal/executiongraph"
+ cloud "github.com/GrayCodeAI/decoder/internal/platform/cloud"
"github.com/spf13/cobra"
)
@@ -42,7 +42,7 @@ func TestCloudLoginHelpNamesDefaultEndpoint(t *testing.T) {
}
}
-func TestCloudLoginUsesRHOCloudURL(t *testing.T) {
+func TestCloudLoginUsesDECODERCloudURL(t *testing.T) {
var hits atomic.Int32
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/v1/auth/device/start" {
@@ -56,7 +56,7 @@ func TestCloudLoginUsesRHOCloudURL(t *testing.T) {
t.Fatal("login succeeded against a failing server")
}
if hits.Load() != 1 {
- t.Fatalf("device start hits = %d, want 1 (RHO_CLOUD_URL was not used)", hits.Load())
+ t.Fatalf("device start hits = %d, want 1 (DECODER_CLOUD_URL was not used)", hits.Load())
}
}
@@ -110,7 +110,7 @@ func TestCloudContextReportsWorkerRejection(t *testing.T) {
defer server.Close()
useCloudClient(t, cloud.New(cloud.Config{Endpoint: server.URL, DeviceToken: "hwc_test"}), cloud.DeviceConfig{ProjectID: "project_0123456789"}, nil)
- out, err := runCloudCommand(t, newCloudContextCmd(), "--repository", "GrayCodeAI/rho")
+ out, err := runCloudCommand(t, newCloudContextCmd(), "--repository", "GrayCodeAI/decoder")
if err == nil || !strings.Contains(err.Error(), "Device not found") {
t.Fatalf("error = %v, want the Worker's rejection", err)
}
@@ -128,7 +128,7 @@ func TestCloudContextReportsSuccessOnlyWhenAccepted(t *testing.T) {
defer server.Close()
useCloudClient(t, cloud.New(cloud.Config{Endpoint: server.URL, DeviceToken: "hwc_test"}), cloud.DeviceConfig{ProjectID: "project_0123456789"}, nil)
- out, err := runCloudCommand(t, newCloudContextCmd(), "--repository", "GrayCodeAI/rho", "--ci-run", "42", "--ci-status", "succeeded")
+ out, err := runCloudCommand(t, newCloudContextCmd(), "--repository", "GrayCodeAI/decoder", "--ci-run", "42", "--ci-status", "succeeded")
if err != nil || !strings.Contains(out, "synced to GrayCode Cloud") {
t.Fatalf("out = %q, err = %v", out, err)
}
@@ -144,11 +144,11 @@ func TestCloudContextRejectsUnknownStatusFlags(t *testing.T) {
defer server.Close()
useCloudClient(t, cloud.New(cloud.Config{Endpoint: server.URL, DeviceToken: "hwc_test"}), cloud.DeviceConfig{ProjectID: "project_0123456789"}, nil)
- _, err := runCloudCommand(t, newCloudContextCmd(), "--repository", "GrayCodeAI/rho", "--ci-run", "42", "--ci-status", "passed")
+ _, err := runCloudCommand(t, newCloudContextCmd(), "--repository", "GrayCodeAI/decoder", "--ci-run", "42", "--ci-status", "passed")
if err == nil || !strings.Contains(err.Error(), "--ci-status") {
t.Fatalf("error = %v, want a --ci-status error", err)
}
- _, err = runCloudCommand(t, newCloudContextCmd(), "--repository", "GrayCodeAI/rho", "--deployment", "d1", "--deployment-environment", "prod", "--deployment-status", "done")
+ _, err = runCloudCommand(t, newCloudContextCmd(), "--repository", "GrayCodeAI/decoder", "--deployment", "d1", "--deployment-environment", "prod", "--deployment-status", "done")
if err == nil || !strings.Contains(err.Error(), "--deployment-status") || !strings.Contains(err.Error(), "rolled_back") {
t.Fatalf("error = %v, want a --deployment-status error listing rolled_back", err)
}
@@ -190,7 +190,7 @@ func TestExplicitCloudCommandsReportLoadErrors(t *testing.T) {
noGitRemote(t)
broken := errors.New("GrayCode Cloud configuration is incomplete")
useCloudClient(t, nil, cloud.DeviceConfig{}, broken)
- if _, err := runCloudCommand(t, newCloudContextCmd(), "--repository", "GrayCodeAI/rho"); !errors.Is(err, broken) {
+ if _, err := runCloudCommand(t, newCloudContextCmd(), "--repository", "GrayCodeAI/decoder"); !errors.Is(err, broken) {
t.Fatalf("context error = %v, want the load failure", err)
}
missionDir := t.TempDir()
@@ -319,12 +319,12 @@ func useTokenStorage(t *testing.T, where string, plaintext bool) {
func TestCloudConnectWarnsAboutPlaintextTokenStore(t *testing.T) {
captureCloudSave(t)
promptable(t, true, "hwc_prompted")
- useTokenStorage(t, "plaintext file /home/dev/.config/rho/.tokens (mode 0600)", true)
+ useTokenStorage(t, "plaintext file /home/dev/.config/decoder/.tokens (mode 0600)", true)
out, err := runCloudCommand(t, newCloudConnectCmd(), connectIDs...)
if err != nil {
t.Fatal(err)
}
- if !strings.Contains(out, "Warning:") || !strings.Contains(out, "/home/dev/.config/rho/.tokens") {
+ if !strings.Contains(out, "Warning:") || !strings.Contains(out, "/home/dev/.config/decoder/.tokens") {
t.Fatalf("output = %q, want a plaintext token warning naming the file", out)
}
@@ -338,9 +338,9 @@ func TestCloudConnectWarnsAboutPlaintextTokenStore(t *testing.T) {
func TestCloudStatusShowsTokenStorage(t *testing.T) {
cfg := cloud.DeviceConfig{Endpoint: cloud.DefaultEndpoint, DeviceID: "device_0123456789", ProjectID: "project_0123456789"}
useCloudClient(t, cloud.New(cloud.Config{Endpoint: cfg.Endpoint, DeviceToken: "hwc_test"}), cfg, nil)
- useTokenStorage(t, "plaintext file /tmp/rho/.tokens (mode 0600)", true)
+ useTokenStorage(t, "plaintext file /tmp/decoder/.tokens (mode 0600)", true)
out, err := runCloudCommand(t, newCloudStatusCmd())
- if err != nil || !strings.Contains(out, "Device token: plaintext file /tmp/rho/.tokens") || !strings.Contains(out, "not an OS credential store") {
+ if err != nil || !strings.Contains(out, "Device token: plaintext file /tmp/decoder/.tokens") || !strings.Contains(out, "not an OS credential store") {
t.Fatalf("out = %q, err = %v", out, err)
}
}
diff --git a/cmd/cloud_usage.go b/cmd/cloud_usage.go
index 2b56f86f9..ac1ddf9ff 100644
--- a/cmd/cloud_usage.go
+++ b/cmd/cloud_usage.go
@@ -7,7 +7,7 @@ import (
"io"
"time"
- cloud "github.com/GrayCodeAI/rho/internal/platform/cloud"
+ cloud "github.com/GrayCodeAI/decoder/internal/platform/cloud"
)
// cloudUsageWait bounds how long a command waits, after writing its output,
diff --git a/cmd/cloud_usage_test.go b/cmd/cloud_usage_test.go
index 56545fd97..3101cfa3a 100644
--- a/cmd/cloud_usage_test.go
+++ b/cmd/cloud_usage_test.go
@@ -10,7 +10,7 @@ import (
"testing"
"time"
- cloud "github.com/GrayCodeAI/rho/internal/platform/cloud"
+ cloud "github.com/GrayCodeAI/decoder/internal/platform/cloud"
)
var testUsageConfig = cloud.DeviceConfig{Endpoint: "https://cloud.graycodeai.com", DeviceID: "device_0123456789", ProjectID: "project_0123456789"}
diff --git a/cmd/cmdhistory_cmd.go b/cmd/cmdhistory_cmd.go
index 67c93dc1c..6ed85c44d 100644
--- a/cmd/cmdhistory_cmd.go
+++ b/cmd/cmdhistory_cmd.go
@@ -6,8 +6,8 @@ import (
"path/filepath"
"strconv"
- "github.com/GrayCodeAI/rho/internal/cmdhistory"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/cmdhistory"
+ "github.com/GrayCodeAI/decoder/internal/storage"
"github.com/spf13/cobra"
)
diff --git a/cmd/command_history.go b/cmd/command_history.go
index 7ceda8148..f7d2dc613 100644
--- a/cmd/command_history.go
+++ b/cmd/command_history.go
@@ -7,7 +7,7 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/storage"
)
// commandHistory persists recently-used slash commands so the command
diff --git a/cmd/command_palette.go b/cmd/command_palette.go
index 3a212a048..fa8f8b422 100644
--- a/cmd/command_palette.go
+++ b/cmd/command_palette.go
@@ -8,8 +8,8 @@ import (
"charm.land/bubbles/v2/textinput"
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
- commandfeature "github.com/GrayCodeAI/rho/internal/features/commands"
- "github.com/GrayCodeAI/rho/internal/plugin"
+ commandfeature "github.com/GrayCodeAI/decoder/internal/features/commands"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
)
// CommandPaletteEntry represents a single command in the palette.
@@ -45,7 +45,7 @@ func (cp *CommandPalette) ensureInput() {
// Palette styles are functions rather than package-level values so live theme
// changes apply to every picker, not only to newly created widgets.
func paletteTitleStyle() lipgloss.Style {
- return lipgloss.NewStyle().Bold(true).Foreground(rhoColor)
+ return lipgloss.NewStyle().Bold(true).Foreground(decoderColor)
}
func paletteInputStyle() lipgloss.Style {
@@ -65,7 +65,7 @@ func paletteDescStyle() lipgloss.Style {
}
func paletteCategoryStyle() lipgloss.Style {
- return lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
+ return lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
}
func paletteDimStyle() lipgloss.Style {
diff --git a/cmd/compact_ui.go b/cmd/compact_ui.go
index cb1a3bee9..3d130e196 100644
--- a/cmd/compact_ui.go
+++ b/cmd/compact_ui.go
@@ -7,14 +7,14 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/token"
+ "github.com/GrayCodeAI/decoder/internal/engine/token"
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
"github.com/mattn/go-runewidth"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
const compactProgressBarWidth = 40
diff --git a/cmd/compact_ui_test.go b/cmd/compact_ui_test.go
index 0257de29e..2b16bf15c 100644
--- a/cmd/compact_ui_test.go
+++ b/cmd/compact_ui_test.go
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
func TestRenderContextUsageBar(t *testing.T) {
@@ -32,7 +32,7 @@ func TestContextUsagePercentForBar(t *testing.T) {
func TestRenderCompactProgressPanel(t *testing.T) {
m := chatModel{
session: &engine.Session{},
- brailleSpinner: NewBrailleSpinner(SpinnerRho, "Compacting conversation"),
+ brailleSpinner: NewBrailleSpinner(SpinnerDecoder, "Compacting conversation"),
manualCompacting: true,
}
out := m.renderCompactProgressPanel(80)
diff --git a/cmd/compat-test/drift.go b/cmd/compat-test/drift.go
index 84ca5bed0..6a35174d3 100644
--- a/cmd/compat-test/drift.go
+++ b/cmd/compat-test/drift.go
@@ -9,22 +9,22 @@ import (
)
// trackedPins are the shared leaf dependencies most likely to drift silently:
-// a sibling repo can pin an older version than what rho's own go.mod requires,
-// and Go's minimal version selection will silently pull in rho's newer version
-// at build time without the consumer's own CI ever having tested it. Rho's
-// only external GrayCodeAI dependency is flux. See docs/compatibility.md.
+// a sibling repo can pin an older version than what decoder's own go.mod requires,
+// and Go's minimal version selection will silently pull in decoder's newer version
+// at build time without the consumer's own CI ever having tested it. Decoder's
+// only external GrayCodeAI dependency is mux. See docs/compatibility.md.
var trackedPins = []string{
- "github.com/GrayCodeAI/flux",
+ "github.com/GrayCodeAI/mux",
}
-// checkDrift compares rho's own go.mod requirements for trackedPins against
-// what each sibling repo (a peer checkout of a rho dependency in the shared
+// checkDrift compares decoder's own go.mod requirements for trackedPins against
+// what each sibling repo (a peer checkout of a decoder dependency in the shared
// workspace) declares for the same modules in its own go.mod. It never fails —
// this is advisory, printed for humans/CI logs to notice, not a build gate.
func checkDrift(repoRoot string) error {
- rhoRequires, err := readRequires(filepath.Join(repoRoot, "go.mod"))
+ decoderRequires, err := readRequires(filepath.Join(repoRoot, "go.mod"))
if err != nil {
- return fmt.Errorf("read rho go.mod: %w", err)
+ return fmt.Errorf("read decoder go.mod: %w", err)
}
workspaceDir := filepath.Join(repoRoot, "..")
@@ -45,18 +45,18 @@ func checkDrift(repoRoot string) error {
continue // sibling not a Go module / no go.mod — skip silently
}
for _, pin := range trackedPins {
- rhoVer, rhoHas := rhoRequires[pin]
+ decoderVer, decoderHas := decoderRequires[pin]
consumerVer, consumerHas := consumerRequires[pin]
- if !rhoHas || !consumerHas || rhoVer == consumerVer {
+ if !decoderHas || !consumerHas || decoderVer == consumerVer {
continue
}
drifted++
- fmt.Printf(" %-22s requires %s@%s, rho requires %s@%s\n",
- e.Name(), pin, consumerVer, pin, rhoVer)
+ fmt.Printf(" %-22s requires %s@%s, decoder requires %s@%s\n",
+ e.Name(), pin, consumerVer, pin, decoderVer)
}
}
if drifted == 0 {
- fmt.Println(" OK — no drift between rho's pins and sibling consumers")
+ fmt.Println(" OK — no drift between decoder's pins and sibling consumers")
}
return nil
}
diff --git a/cmd/compat-test/drift_test.go b/cmd/compat-test/drift_test.go
index e6c834765..72bef8ca8 100644
--- a/cmd/compat-test/drift_test.go
+++ b/cmd/compat-test/drift_test.go
@@ -28,7 +28,7 @@ func TestReadRequires(t *testing.T) {
go 1.26
require (
- github.com/GrayCodeAI/flux v1.0.0
+ github.com/GrayCodeAI/mux v1.0.0
github.com/spf13/cobra v1.8.0
)
@@ -40,7 +40,7 @@ require github.com/GrayCodeAI/other v1.9.0 // indirect
t.Fatalf("readRequires: %v", err)
}
tests := map[string]string{
- "github.com/GrayCodeAI/flux": "v1.0.0",
+ "github.com/GrayCodeAI/mux": "v1.0.0",
"github.com/spf13/cobra": "v1.8.0",
"github.com/GrayCodeAI/other": "v1.9.0",
}
@@ -68,28 +68,28 @@ func TestReadRequires_InvalidMod(t *testing.T) {
}
}
-// TestCheckDrift reports drift when a consumer pins an older version than rho.
+// TestCheckDrift reports drift when a consumer pins an older version than decoder.
func TestCheckDrift_DetectsDrift(t *testing.T) {
ws := t.TempDir()
- writeMod(t, filepath.Join(ws, "rho", "go.mod"), `module github.com/GrayCodeAI/rho
+ writeMod(t, filepath.Join(ws, "decoder", "go.mod"), `module github.com/GrayCodeAI/decoder
go 1.26
-require github.com/GrayCodeAI/flux v1.5.0
+require github.com/GrayCodeAI/mux v1.5.0
`)
// Consumer sibling pins an older version of the shared dependency.
writeMod(t, filepath.Join(ws, "consumer", "go.mod"), `module github.com/GrayCodeAI/consumer
go 1.26
-require github.com/GrayCodeAI/flux v1.2.0
+require github.com/GrayCodeAI/mux v1.2.0
`)
var buf bytes.Buffer
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
- err := checkDrift(filepath.Join(ws, "rho"))
+ err := checkDrift(filepath.Join(ws, "decoder"))
_ = w.Close()
os.Stdout = old
_, _ = buf.ReadFrom(r)
@@ -106,24 +106,24 @@ require github.com/GrayCodeAI/flux v1.2.0
// pins produce the "OK" line and no per-consumer drift lines.
func TestCheckDrift_NoDriftWhenVersionsMatch(t *testing.T) {
ws := t.TempDir()
- writeMod(t, filepath.Join(ws, "rho", "go.mod"), `module github.com/GrayCodeAI/rho
+ writeMod(t, filepath.Join(ws, "decoder", "go.mod"), `module github.com/GrayCodeAI/decoder
go 1.26
-require github.com/GrayCodeAI/flux v1.5.0
+require github.com/GrayCodeAI/mux v1.5.0
`)
writeMod(t, filepath.Join(ws, "consumer", "go.mod"), `module github.com/GrayCodeAI/consumer
go 1.26
-require github.com/GrayCodeAI/flux v1.5.0
+require github.com/GrayCodeAI/mux v1.5.0
`)
var buf bytes.Buffer
r, w, _ := os.Pipe()
old := os.Stdout
os.Stdout = w
- err := checkDrift(filepath.Join(ws, "rho"))
+ err := checkDrift(filepath.Join(ws, "decoder"))
_ = w.Close()
os.Stdout = old
_, _ = buf.ReadFrom(r)
@@ -140,11 +140,11 @@ require github.com/GrayCodeAI/flux v1.5.0
// without a go.mod (e.g. not a Go module) is skipped without failing.
func TestCheckDrift_SkipsMissingSiblings(t *testing.T) {
ws := t.TempDir()
- writeMod(t, filepath.Join(ws, "rho", "go.mod"), `module github.com/GrayCodeAI/rho
+ writeMod(t, filepath.Join(ws, "decoder", "go.mod"), `module github.com/GrayCodeAI/decoder
go 1.26
-require github.com/GrayCodeAI/flux v1.5.0
+require github.com/GrayCodeAI/mux v1.5.0
`)
// Directory present but no go.mod — must be skipped silently.
if err := os.MkdirAll(filepath.Join(ws, "not-checked-out"), 0o755); err != nil {
@@ -154,7 +154,7 @@ require github.com/GrayCodeAI/flux v1.5.0
r, w, _ := os.Pipe()
old := os.Stdout
os.Stdout = w
- err := checkDrift(filepath.Join(ws, "rho"))
+ err := checkDrift(filepath.Join(ws, "decoder"))
_ = w.Close()
os.Stdout = old
_, _ = io.Copy(io.Discard, r)
diff --git a/cmd/compat-test/main.go b/cmd/compat-test/main.go
index 4fe909e4d..4f77805fe 100644
--- a/cmd/compat-test/main.go
+++ b/cmd/compat-test/main.go
@@ -17,7 +17,7 @@
// go run ./cmd/compat-test -matrix=stable -strict
// # exit non-zero if any
// # component lacks a version
-// go run ./cmd/compat-test -check-external # advisory: compare rho's own
+// go run ./cmd/compat-test -check-external # advisory: compare decoder's own
// # go.mod pins for shared leaf
// # deps against what each
// # sibling repo declares.
@@ -176,7 +176,7 @@ func report(mf matrixFile, m matrix, strict bool) error {
}
// findMatrixFile locates the cross-repo compatibility matrix (testdata/compatibility-matrix.json).
-// It must not pick rho/platform-capabilities.json, which is a different document.
+// It must not pick decoder/platform-capabilities.json, which is a different document.
func findMatrixFile() string {
dir, err := os.Getwd()
if err != nil {
@@ -184,7 +184,7 @@ func findMatrixFile() string {
}
candidates := []string{
"testdata/compatibility-matrix.json",
- "rho/testdata/compatibility-matrix.json",
+ "decoder/testdata/compatibility-matrix.json",
}
for i := 0; i < 6; i++ {
for _, rel := range candidates {
diff --git a/cmd/completions.go b/cmd/completions.go
index e0b41eb5f..c9488364f 100644
--- a/cmd/completions.go
+++ b/cmd/completions.go
@@ -9,9 +9,9 @@ import (
"sort"
"strings"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/provider/routing"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/provider/routing"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@@ -33,7 +33,7 @@ type CommandInfo struct {
Flags []FlagInfo `json:"flags,omitempty"`
}
-// CompletionGenerator generates shell completion scripts for rho.
+// CompletionGenerator generates shell completion scripts for decoder.
type CompletionGenerator struct {
Commands []CommandInfo `json:"commands"`
Flags []FlagInfo `json:"flags"`
@@ -42,7 +42,7 @@ type CompletionGenerator struct {
Providers []string `json:"providers"`
}
-// NewCompletionGenerator creates a CompletionGenerator pre-populated with rho's
+// NewCompletionGenerator creates a CompletionGenerator pre-populated with decoder's
// command structure, flags, providers, models, and slash commands.
func NewCompletionGenerator() *CompletionGenerator {
g := &CompletionGenerator{}
@@ -64,7 +64,7 @@ func (g *CompletionGenerator) populateFlags() {
}
func (g *CompletionGenerator) populateProviders() {
- g.Providers = rhoconfig.AllSetupGateways()
+ g.Providers = decoderconfig.AllSetupGateways()
}
func (g *CompletionGenerator) populateModels() {
@@ -83,16 +83,16 @@ func (g *CompletionGenerator) populateSlashCommands() {
return
}
// Completion must remain available when a plugin manifest is malformed or
- // unreadable. Static rho commands are still a complete fallback.
+ // unreadable. Static decoder commands are still a complete fallback.
g.SlashCommands = slashCommands()
}
-// GenerateBash returns a complete bash completion script for rho.
+// GenerateBash returns a complete bash completion script for decoder.
func (g *CompletionGenerator) GenerateBash() string {
var b strings.Builder
- b.WriteString("# bash completion for rho\n")
- b.WriteString("# Auto-generated by rho completions generator\n\n")
+ b.WriteString("# bash completion for decoder\n")
+ b.WriteString("# Auto-generated by decoder completions generator\n\n")
// Build subcommand list
subcommands := make([]string, 0, len(g.Commands))
@@ -115,7 +115,7 @@ func (g *CompletionGenerator) GenerateBash() string {
// Build slash commands list
slashCmds := strings.Join(g.SlashCommands, " ")
- b.WriteString("_rho_completions() {\n")
+ b.WriteString("_decoder_completions() {\n")
b.WriteString(" local cur prev words cword\n")
b.WriteString(" _init_completion || return\n")
b.WriteString("\n")
@@ -162,7 +162,7 @@ func (g *CompletionGenerator) GenerateBash() string {
b.WriteString(" return 0\n")
b.WriteString(" fi\n")
b.WriteString("\n")
- b.WriteString(" # Complete subcommands after rho\n")
+ b.WriteString(" # Complete subcommands after decoder\n")
b.WriteString(" if [[ ${COMP_CWORD} -eq 1 ]]; then\n")
b.WriteString(fmt.Sprintf(" COMPREPLY=($(compgen -W \"%s\" -- \"$cur\"))\n", strings.Join(subcommands, " ")))
b.WriteString(" return 0\n")
@@ -190,20 +190,20 @@ func (g *CompletionGenerator) GenerateBash() string {
b.WriteString(" return 0\n")
b.WriteString("}\n")
b.WriteString("\n")
- b.WriteString("complete -F _rho_completions rho\n")
+ b.WriteString("complete -F _decoder_completions decoder\n")
return b.String()
}
-// GenerateZsh returns a complete zsh completion script for rho.
+// GenerateZsh returns a complete zsh completion script for decoder.
func (g *CompletionGenerator) GenerateZsh() string {
var b strings.Builder
- b.WriteString("#compdef rho\n")
- b.WriteString("# zsh completion for rho\n")
- b.WriteString("# Auto-generated by rho completions generator\n\n")
+ b.WriteString("#compdef decoder\n")
+ b.WriteString("# zsh completion for decoder\n")
+ b.WriteString("# Auto-generated by decoder completions generator\n\n")
- b.WriteString("_rho() {\n")
+ b.WriteString("_decoder() {\n")
b.WriteString(" local -a commands\n")
b.WriteString(" local -a global_flags\n")
b.WriteString("\n")
@@ -246,7 +246,7 @@ func (g *CompletionGenerator) GenerateZsh() string {
b.WriteString(" case $state in\n")
b.WriteString(" commands)\n")
- b.WriteString(" _describe -t commands 'rho commands' commands\n")
+ b.WriteString(" _describe -t commands 'decoder commands' commands\n")
b.WriteString(" ;;\n")
b.WriteString(" args)\n")
b.WriteString(" case $words[1] in\n")
@@ -269,7 +269,7 @@ func (g *CompletionGenerator) GenerateZsh() string {
b.WriteString("}\n\n")
// Slash commands completion function
- b.WriteString("_rho_slash_commands() {\n")
+ b.WriteString("_decoder_slash_commands() {\n")
b.WriteString(" local -a slash_commands\n")
b.WriteString(" slash_commands=(\n")
for _, sc := range g.SlashCommands {
@@ -280,7 +280,7 @@ func (g *CompletionGenerator) GenerateZsh() string {
b.WriteString("}\n\n")
// Provider completion function
- b.WriteString("_rho_providers() {\n")
+ b.WriteString("_decoder_providers() {\n")
b.WriteString(" local -a providers\n")
b.WriteString(" providers=(\n")
for _, p := range g.Providers {
@@ -290,25 +290,25 @@ func (g *CompletionGenerator) GenerateZsh() string {
b.WriteString(" compadd -a providers\n")
b.WriteString("}\n\n")
- b.WriteString("_rho \"$@\"\n")
+ b.WriteString("_decoder \"$@\"\n")
return b.String()
}
-// GenerateFish returns a complete fish shell completion script for rho.
+// GenerateFish returns a complete fish shell completion script for decoder.
func (g *CompletionGenerator) GenerateFish() string {
var b strings.Builder
- b.WriteString("# fish completion for rho\n")
- b.WriteString("# Auto-generated by rho completions generator\n\n")
+ b.WriteString("# fish completion for decoder\n")
+ b.WriteString("# Auto-generated by decoder completions generator\n\n")
// Disable file completions by default
- b.WriteString("complete -c rho -f\n\n")
+ b.WriteString("complete -c decoder -f\n\n")
// Subcommands
b.WriteString("# Subcommands\n")
for _, cmd := range g.Commands {
- b.WriteString(fmt.Sprintf("complete -c rho -n '__fish_use_subcommand' -a '%s' -d '%s'\n",
+ b.WriteString(fmt.Sprintf("complete -c decoder -n '__fish_use_subcommand' -a '%s' -d '%s'\n",
cmd.Name, escapeFish(cmd.Description)))
}
b.WriteString("\n")
@@ -318,7 +318,7 @@ func (g *CompletionGenerator) GenerateFish() string {
if len(cmd.Subcommands) > 0 {
b.WriteString(fmt.Sprintf("# %s subcommands\n", cmd.Name))
for _, sc := range cmd.Subcommands {
- b.WriteString(fmt.Sprintf("complete -c rho -n '__fish_seen_subcommand_from %s' -a '%s' -d '%s'\n",
+ b.WriteString(fmt.Sprintf("complete -c decoder -n '__fish_seen_subcommand_from %s' -a '%s' -d '%s'\n",
cmd.Name, sc.Name, escapeFish(sc.Description)))
}
b.WriteString("\n")
@@ -328,10 +328,10 @@ func (g *CompletionGenerator) GenerateFish() string {
b.WriteString(fmt.Sprintf("# %s flags\n", cmd.Name))
for _, f := range cmd.Flags {
if f.Short != "" {
- b.WriteString(fmt.Sprintf("complete -c rho -n '__fish_seen_subcommand_from %s' -l '%s' -s '%s' -d '%s'",
+ b.WriteString(fmt.Sprintf("complete -c decoder -n '__fish_seen_subcommand_from %s' -l '%s' -s '%s' -d '%s'",
cmd.Name, f.Name, f.Short, escapeFish(f.Description)))
} else {
- b.WriteString(fmt.Sprintf("complete -c rho -n '__fish_seen_subcommand_from %s' -l '%s' -d '%s'",
+ b.WriteString(fmt.Sprintf("complete -c decoder -n '__fish_seen_subcommand_from %s' -l '%s' -d '%s'",
cmd.Name, f.Name, escapeFish(f.Description)))
}
if f.Type == "bool" {
@@ -352,10 +352,10 @@ func (g *CompletionGenerator) GenerateFish() string {
b.WriteString("# Global flags\n")
for _, f := range g.Flags {
if f.Short != "" {
- b.WriteString(fmt.Sprintf("complete -c rho -l '%s' -s '%s' -d '%s'",
+ b.WriteString(fmt.Sprintf("complete -c decoder -l '%s' -s '%s' -d '%s'",
f.Name, f.Short, escapeFish(f.Description)))
} else {
- b.WriteString(fmt.Sprintf("complete -c rho -l '%s' -d '%s'",
+ b.WriteString(fmt.Sprintf("complete -c decoder -l '%s' -d '%s'",
f.Name, escapeFish(f.Description)))
}
if f.Type == "bool" {
@@ -372,14 +372,14 @@ func (g *CompletionGenerator) GenerateFish() string {
// Provider completions for --provider
b.WriteString("# Provider completions\n")
- b.WriteString(fmt.Sprintf("complete -c rho -l 'provider' -r -a '%s' -d 'LLM provider'\n",
+ b.WriteString(fmt.Sprintf("complete -c decoder -l 'provider' -r -a '%s' -d 'LLM provider'\n",
strings.Join(g.Providers, " ")))
b.WriteString("\n")
// Slash commands
b.WriteString("# Slash commands (for interactive mode reference)\n")
for _, sc := range g.SlashCommands {
- b.WriteString(fmt.Sprintf("complete -c rho -a '%s' -d 'Slash command'\n", sc))
+ b.WriteString(fmt.Sprintf("complete -c decoder -a '%s' -d 'Slash command'\n", sc))
}
return b.String()
@@ -400,7 +400,7 @@ func (g *CompletionGenerator) GenerateJSON() (string, error) {
Providers []string `json:"providers"`
Models []string `json:"models"`
}{
- Name: "rho",
+ Name: "decoder",
Version: v,
Commands: g.Commands,
GlobalFlags: g.Flags,
@@ -530,11 +530,11 @@ func bashInstallPath() string {
// Prefer user-local path
home, err := os.UserHomeDir()
if err != nil {
- return "/etc/bash_completion.d/rho"
+ return "/etc/bash_completion.d/decoder"
}
localDir := filepath.Join(home, ".local", "share", "bash-completion", "completions")
if info, err := os.Stat(localDir); err == nil && info.IsDir() {
- return filepath.Join(localDir, "rho")
+ return filepath.Join(localDir, "decoder")
}
// On macOS, use homebrew path if available.
// ARM Macs (M1+) install Homebrew to /opt/homebrew; Intel Macs use /usr/local.
@@ -542,17 +542,17 @@ func bashInstallPath() string {
for _, prefix := range []string{"/opt/homebrew", "/usr/local"} {
brewDir := filepath.Join(prefix, "etc", "bash_completion.d")
if info, err := os.Stat(brewDir); err == nil && info.IsDir() {
- return filepath.Join(brewDir, "rho")
+ return filepath.Join(brewDir, "decoder")
}
}
}
// Fallback: try system-wide
sysDir := "/etc/bash_completion.d"
if info, err := os.Stat(sysDir); err == nil && info.IsDir() {
- return filepath.Join(sysDir, "rho")
+ return filepath.Join(sysDir, "decoder")
}
// Final fallback: user-local
- return filepath.Join(home, ".local", "share", "bash-completion", "completions", "rho")
+ return filepath.Join(home, ".local", "share", "bash-completion", "completions", "decoder")
}
func zshInstallPath() string {
@@ -563,28 +563,28 @@ func zshInstallPath() string {
for _, p := range parts {
if p != "" {
if info, err := os.Stat(p); err == nil && info.IsDir() { // #nosec G703 -- shell completion only probes the user-selected directory
- return filepath.Join(p, "_rho")
+ return filepath.Join(p, "_decoder")
}
}
}
// Use first entry even if it doesn't exist yet
if parts[0] != "" {
- return filepath.Join(parts[0], "_rho")
+ return filepath.Join(parts[0], "_decoder")
}
}
home, err := os.UserHomeDir()
if err != nil {
- return "/usr/local/share/zsh/site-functions/_rho"
+ return "/usr/local/share/zsh/site-functions/_decoder"
}
- return filepath.Join(home, ".zsh", "completions", "_rho")
+ return filepath.Join(home, ".zsh", "completions", "_decoder")
}
func fishInstallPath() string {
home, err := os.UserHomeDir()
if err != nil {
- return filepath.Join(os.TempDir(), "rho.fish")
+ return filepath.Join(os.TempDir(), "decoder.fish")
}
- return filepath.Join(home, ".config", "fish", "completions", "rho.fish")
+ return filepath.Join(home, ".config", "fish", "completions", "decoder.fish")
}
// escapeZsh escapes single quotes for zsh completion descriptions.
diff --git a/cmd/completions_test.go b/cmd/completions_test.go
index 31009a17e..88dac7fc5 100644
--- a/cmd/completions_test.go
+++ b/cmd/completions_test.go
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/flux/catalog/registry"
+ "github.com/GrayCodeAI/mux/catalog/registry"
)
func TestNewCompletionGenerator(t *testing.T) {
@@ -44,10 +44,10 @@ func TestGenerateBashContainsFunctionDefinition(t *testing.T) {
g := NewCompletionGenerator()
bash := g.GenerateBash()
- if !strings.Contains(bash, "_rho_completions()") {
- t.Error("Bash completion should contain _rho_completions() function definition")
+ if !strings.Contains(bash, "_decoder_completions()") {
+ t.Error("Bash completion should contain _decoder_completions() function definition")
}
- if !strings.Contains(bash, "complete -F _rho_completions rho") {
+ if !strings.Contains(bash, "complete -F _decoder_completions decoder") {
t.Error("Bash completion should register the completion function with 'complete'")
}
}
@@ -106,8 +106,8 @@ func TestGenerateZshContainsCompdefHeader(t *testing.T) {
g := NewCompletionGenerator()
zsh := g.GenerateZsh()
- if !strings.HasPrefix(zsh, "#compdef rho") {
- t.Error("Zsh completion should start with #compdef rho header")
+ if !strings.HasPrefix(zsh, "#compdef decoder") {
+ t.Error("Zsh completion should start with #compdef decoder header")
}
}
@@ -115,8 +115,8 @@ func TestGenerateZshContainsFunction(t *testing.T) {
g := NewCompletionGenerator()
zsh := g.GenerateZsh()
- if !strings.Contains(zsh, "_rho()") {
- t.Error("Zsh completion should contain _rho() function")
+ if !strings.Contains(zsh, "_decoder()") {
+ t.Error("Zsh completion should contain _decoder() function")
}
if !strings.Contains(zsh, "_arguments") {
t.Error("Zsh completion should use _arguments for flag completion")
@@ -165,8 +165,8 @@ func TestGenerateFishContainsCompleteDirectives(t *testing.T) {
g := NewCompletionGenerator()
fish := g.GenerateFish()
- if !strings.Contains(fish, "complete -c rho") {
- t.Error("Fish completion should contain 'complete -c rho' directives")
+ if !strings.Contains(fish, "complete -c decoder") {
+ t.Error("Fish completion should contain 'complete -c decoder' directives")
}
}
@@ -328,8 +328,8 @@ func TestInstallCompletionBash(t *testing.T) {
if path == "" {
t.Error("InstallCompletion(bash) returned empty path")
}
- if !strings.Contains(path, "rho") {
- t.Errorf("Bash install path should contain 'rho', got %q", path)
+ if !strings.Contains(path, "decoder") {
+ t.Errorf("Bash install path should contain 'decoder', got %q", path)
}
// Should be a bash-related path
if !strings.Contains(path, "bash") && !strings.Contains(path, "completion") {
@@ -345,8 +345,8 @@ func TestInstallCompletionZsh(t *testing.T) {
if path == "" {
t.Error("InstallCompletion(zsh) returned empty path")
}
- if !strings.Contains(path, "_rho") {
- t.Errorf("Zsh install path should contain '_rho', got %q", path)
+ if !strings.Contains(path, "_decoder") {
+ t.Errorf("Zsh install path should contain '_decoder', got %q", path)
}
}
@@ -358,8 +358,8 @@ func TestInstallCompletionFish(t *testing.T) {
if path == "" {
t.Error("InstallCompletion(fish) returned empty path")
}
- if !strings.Contains(path, "rho.fish") {
- t.Errorf("Fish install path should contain 'rho.fish', got %q", path)
+ if !strings.Contains(path, "decoder.fish") {
+ t.Errorf("Fish install path should contain 'decoder.fish', got %q", path)
}
if !strings.Contains(path, "fish") {
t.Errorf("Fish install path should be fish-related, got %q", path)
@@ -516,8 +516,8 @@ func TestGenerateZshProviderChoices(t *testing.T) {
zsh := g.GenerateZsh()
// The provider completion function should list all providers
- if !strings.Contains(zsh, "_rho_providers()") {
- t.Error("Zsh completion should contain _rho_providers() function")
+ if !strings.Contains(zsh, "_decoder_providers()") {
+ t.Error("Zsh completion should contain _decoder_providers() function")
}
}
diff --git a/cmd/config_table.go b/cmd/config_table.go
index 4aa68cb99..facbc6640 100644
--- a/cmd/config_table.go
+++ b/cmd/config_table.go
@@ -5,7 +5,7 @@ import (
"strings"
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
"github.com/mattn/go-runewidth"
)
diff --git a/cmd/context_export.go b/cmd/context_export.go
index 466edcee6..8b4315e72 100644
--- a/cmd/context_export.go
+++ b/cmd/context_export.go
@@ -9,9 +9,9 @@ import (
"path/filepath"
"strings"
- "github.com/GrayCodeAI/rho/internal/fsutil"
- "github.com/GrayCodeAI/rho/internal/intelligence/repomap"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/fsutil"
+ "github.com/GrayCodeAI/decoder/internal/intelligence/repomap"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
// ExportContext generates a comprehensive context document about the current project.
@@ -62,7 +62,7 @@ func ExportContext(dir string, focus string) (string, error) {
}
// AGENTS.md / project instructions
- for _, instrFile := range []string{"AGENTS.md", ".rho.md"} {
+ for _, instrFile := range []string{"AGENTS.md", ".decoder.md"} {
data, err := os.ReadFile(filepath.Join(dir, instrFile)) // #nosec G304 -- instrFile is one of a fixed set of well-known project instruction filenames
if err == nil && len(data) > 0 {
b.WriteString(fmt.Sprintf("## Project Instructions (%s)\n\n%s\n\n", instrFile, strings.TrimSpace(string(data))))
diff --git a/cmd/contextual_help.go b/cmd/contextual_help.go
index 8013ff8e3..c69d416a0 100644
--- a/cmd/contextual_help.go
+++ b/cmd/contextual_help.go
@@ -84,7 +84,7 @@ var builtinHelpEntries = []*HelpEntry{
{
Topic: "/undo",
Summary: "Undo last action safely",
- Detail: "Reverts the last rho action (commit, file edit, etc.) using safe snapshot-based rollback.",
+ Detail: "Reverts the last decoder action (commit, file edit, etc.) using safe snapshot-based rollback.",
Examples: []string{"/undo — undo last action", "/undo --hard — undo and discard changes", "/undo 3 — undo last 3 actions"},
Related: []string{"/commit", "/snapshot", "/history"},
Category: "slash-commands",
@@ -108,7 +108,7 @@ var builtinHelpEntries = []*HelpEntry{
{
Topic: "/config",
Summary: "Open configuration panel",
- Detail: "Opens the interactive configuration panel for rho settings, model selection, and preferences.",
+ Detail: "Opens the interactive configuration panel for decoder settings, model selection, and preferences.",
Examples: []string{"/config — open config panel", "/config model — change model", "/config key remove — remove stored API key", "/config keys — show key status"},
Related: []string{"/session", "/profile", "/rules"},
Category: "slash-commands",
@@ -171,8 +171,8 @@ var builtinHelpEntries = []*HelpEntry{
},
{
Topic: "/session",
- Summary: "Manage rho sessions",
- Detail: "Start, stop, resume, or list rho working sessions with full context preservation.",
+ Summary: "Manage decoder sessions",
+ Detail: "Start, stop, resume, or list decoder working sessions with full context preservation.",
Examples: []string{"/session — show current session", "/session new — start new session", "/session resume 3 — resume session #3"},
Related: []string{"/status", "/history", "/config"},
Category: "slash-commands",
@@ -236,7 +236,7 @@ var builtinHelpEntries = []*HelpEntry{
// ─── Common Tasks ────────────────────────────────────────────
{
Topic: "how to fix tests",
- Summary: "Fixing failing tests with rho",
+ Summary: "Fixing failing tests with decoder",
Detail: "Use /test to run tests and identify failures, then /fix test to apply AI-generated fixes. For complex failures, use /chat to discuss the issue.",
Examples: []string{"/test — identify failures", "/fix test — auto-fix test failures", "/chat \"why is TestX failing?\""},
Related: []string{"/test", "/fix", "/bugfind"},
@@ -244,7 +244,7 @@ var builtinHelpEntries = []*HelpEntry{
},
{
Topic: "how to commit",
- Summary: "Making commits with rho",
+ Summary: "Making commits with decoder",
Detail: "Stage your changes with git add, then use /commit to create a commit with an AI-generated message. Use /diff first to review what you are committing.",
Examples: []string{"/diff --staged — review staged changes", "/commit — commit with AI message", `/commit "my message" — commit with custom message`},
Related: []string{"/commit", "/diff", "/branch"},
@@ -252,7 +252,7 @@ var builtinHelpEntries = []*HelpEntry{
},
{
Topic: "how to debug",
- Summary: "Debugging with rho AI assistance",
+ Summary: "Debugging with decoder AI assistance",
Detail: "Describe the bug in /chat or use /bugfind for automated detection. For test failures, /test with /fix provides targeted debugging.",
Examples: []string{"/bugfind — automated bug detection", "/chat \"I see panic at line 42\"", "/test -v ./pkg/... — verbose test output"},
Related: []string{"/bugfind", "/test", "/fix", "/chat"},
@@ -269,16 +269,16 @@ var builtinHelpEntries = []*HelpEntry{
{
Topic: "how to refactor",
Summary: "Refactoring code with AI assistance",
- Detail: "Use /chat to discuss refactoring strategies, then rho can apply changes. Use /snapshot before large refactors for safety.",
+ Detail: "Use /chat to discuss refactoring strategies, then decoder can apply changes. Use /snapshot before large refactors for safety.",
Examples: []string{"/snapshot — save state before refactor", "/chat \"refactor auth to use interfaces\"", "/test — verify nothing broke"},
Related: []string{"/chat", "/snapshot", "/test", "/undo"},
Category: "common-tasks",
},
{
Topic: "how to start a session",
- Summary: "Starting a new rho session",
- Detail: "Run rho in your project directory to start a session. Your context is preserved across the session. Use /session to manage sessions.",
- Examples: []string{"rho — start rho in current dir", "/session new — start fresh session", "/session resume — resume last session"},
+ Summary: "Starting a new decoder session",
+ Detail: "Run decoder in your project directory to start a session. Your context is preserved across the session. Use /session to manage sessions.",
+ Examples: []string{"decoder — start decoder in current dir", "/session new — start fresh session", "/session resume — resume last session"},
Related: []string{"/session", "/config", "/status"},
Category: "common-tasks",
},
@@ -287,14 +287,14 @@ var builtinHelpEntries = []*HelpEntry{
Topic: "error: api key invalid",
Summary: "API key is missing or invalid",
Detail: "Your API key is not configured or has expired. Save a new key via /config (paste in the panel). Keys are stored in the OS secret store (macOS Keychain / Linux keyring).",
- Examples: []string{"/config — paste API key in the config panel", "rho credentials status — verify stored keys"},
+ Examples: []string{"/config — paste API key in the config panel", "decoder credentials status — verify stored keys"},
Related: []string{"/config", "error: rate limit", "error: network"},
Category: "errors",
},
{
Topic: "error: rate limit",
Summary: "API rate limit exceeded",
- Detail: "You have exceeded the API rate limit. Rho will automatically retry with exponential backoff. Consider upgrading your plan for higher limits.",
+ Detail: "You have exceeded the API rate limit. Decoder will automatically retry with exponential backoff. Consider upgrading your plan for higher limits.",
Examples: []string{"/config model — switch to a lower-tier model", "/status — check rate limit status"},
Related: []string{"error: api key invalid", "/config", "error: timeout"},
Category: "errors",
@@ -318,7 +318,7 @@ var builtinHelpEntries = []*HelpEntry{
{
Topic: "error: git conflict",
Summary: "Git merge conflict detected",
- Detail: "A merge conflict was encountered. Rho can assist with conflict resolution using AI to understand both sides.",
+ Detail: "A merge conflict was encountered. Decoder can assist with conflict resolution using AI to understand both sides.",
Examples: []string{"/merge --resolve — AI-assisted resolution", "/diff --conflicts — show conflict details", "/undo — abort and go back"},
Related: []string{"/merge", "/diff", "/undo"},
Category: "errors",
@@ -326,7 +326,7 @@ var builtinHelpEntries = []*HelpEntry{
{
Topic: "error: no git repo",
Summary: "Not in a git repository",
- Detail: "Rho requires a git repository. Initialize one with git init or navigate to an existing repo.",
+ Detail: "Decoder requires a git repository. Initialize one with git init or navigate to an existing repo.",
Examples: []string{"git init — initialize new repo", "cd /path/to/repo — navigate to a repo"},
Related: []string{"/status", "/branch", "/commit"},
Category: "errors",
@@ -360,7 +360,7 @@ var builtinHelpEntries = []*HelpEntry{
Topic: "config: api-key",
Summary: "Set the API key",
Detail: "API keys are stored in the OS secret store. Use /config to paste a key, or /config key remove to delete one.",
- Examples: []string{"/config — paste API key in the config panel", "/config key remove — remove a stored key", "rho credentials status — list configured providers"},
+ Examples: []string{"/config — paste API key in the config panel", "/config key remove — remove a stored key", "decoder credentials status — list configured providers"},
Related: []string{"/config", "config: model", "error: api key invalid"},
Category: "configuration",
},
@@ -383,7 +383,7 @@ var builtinHelpEntries = []*HelpEntry{
{
Topic: "config: editor",
Summary: "Set preferred editor",
- Detail: "Configure which editor rho uses when opening files for editing.",
+ Detail: "Configure which editor decoder uses when opening files for editing.",
Examples: []string{"/config editor vim — use vim", "/config editor code — use VS Code", "/config editor nano — use nano"},
Related: []string{"/config", "config: theme", "config: shell"},
Category: "configuration",
@@ -391,7 +391,7 @@ var builtinHelpEntries = []*HelpEntry{
{
Topic: "config: theme",
Summary: "Set color theme",
- Detail: "Choose the color theme for rho terminal output. Supports light and dark terminal backgrounds.",
+ Detail: "Choose the color theme for decoder terminal output. Supports light and dark terminal backgrounds.",
Examples: []string{"/config theme dark — dark background theme", "/config theme light — light background theme", "/config theme none — disable colors"},
Related: []string{"/config", "config: editor", "config: shell"},
Category: "configuration",
@@ -399,7 +399,7 @@ var builtinHelpEntries = []*HelpEntry{
{
Topic: "config: shell",
Summary: "Set shell for command execution",
- Detail: "Configure which shell rho uses when running commands.",
+ Detail: "Configure which shell decoder uses when running commands.",
Examples: []string{"/config shell bash — use bash", "/config shell zsh — use zsh", "/config shell fish — use fish"},
Related: []string{"/config", "config: editor", "config: theme"},
Category: "configuration",
@@ -473,7 +473,7 @@ var builtinHelpEntries = []*HelpEntry{
Topic: "tool: daemon",
Summary: "Background daemon service",
Detail: "Runs in the background to provide file watching, indexing, and real-time analysis of your project.",
- Examples: []string{"rho daemon start — start the daemon", "rho daemon status — check daemon status", "rho daemon stop — stop the daemon"},
+ Examples: []string{"decoder daemon start — start the daemon", "decoder daemon status — check daemon status", "decoder daemon stop — stop the daemon"},
Related: []string{"/status", "tool: repomap", "tool: memory"},
Category: "tools",
},
diff --git a/cmd/control_plane_hints.go b/cmd/control_plane_hints.go
index 71be5625f..83e62eac1 100644
--- a/cmd/control_plane_hints.go
+++ b/cmd/control_plane_hints.go
@@ -3,7 +3,7 @@ package cmd
import (
"fmt"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
// controlPlaneOnboardingHint is a short first-session tip (not a wall of text).
@@ -24,7 +24,7 @@ func workModeSwitchSummary(sess *engine.Session, wm engine.WorkMode) string {
}
visible := 0
if sess != nil && sess.Tools() != nil && sess.Tools().Registry() != nil {
- visible = len(sess.Tools().Registry().FluxTools())
+ visible = len(sess.Tools().Registry().MuxTools())
}
return fmt.Sprintf("Work mode → %s\n%s\nModel-visible tools: %d · /status for full control plane", wm, hint, visible)
}
diff --git a/cmd/cost.go b/cmd/cost.go
index 007bfdea3..2ce427e48 100644
--- a/cmd/cost.go
+++ b/cmd/cost.go
@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
- analytics "github.com/GrayCodeAI/rho/internal/observability"
+ analytics "github.com/GrayCodeAI/decoder/internal/observability"
"github.com/spf13/cobra"
)
@@ -64,7 +64,7 @@ var costAnalyzeCmd = &cobra.Command{
cmd.Println(auditTint(" - Model routing recommendations", textMuted))
cmd.Println(auditTint(" - Prompt caching suggestions", textMuted))
cmd.Println()
- cmd.Println(auditTint("To track progress: https://github.com/GrayCodeAI/rho/issues", textMuted))
+ cmd.Println(auditTint("To track progress: https://github.com/GrayCodeAI/decoder/issues", textMuted))
return nil
}
diff --git a/cmd/cost_test.go b/cmd/cost_test.go
index d7ec4b3e7..f7a05e3ba 100644
--- a/cmd/cost_test.go
+++ b/cmd/cost_test.go
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
- analytics "github.com/GrayCodeAI/rho/internal/observability"
+ analytics "github.com/GrayCodeAI/decoder/internal/observability"
)
func TestCostAnalyze_JSON_Empty(t *testing.T) {
diff --git a/cmd/credential_gate.go b/cmd/credential_gate.go
index 169de452e..cd64c2700 100644
--- a/cmd/credential_gate.go
+++ b/cmd/credential_gate.go
@@ -3,7 +3,7 @@ package cmd
import (
"sync/atomic"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
// credentialGate holds the current host-side credential gate callback. It is
diff --git a/cmd/credentials.go b/cmd/credentials.go
index 92ccef4d1..342deed5c 100644
--- a/cmd/credentials.go
+++ b/cmd/credentials.go
@@ -5,7 +5,7 @@ import (
"fmt"
"strings"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
"github.com/spf13/cobra"
)
@@ -19,7 +19,7 @@ var credentialsStatusCmd = &cobra.Command{
Short: "Show where API keys are stored",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
- cmd.Println(rhoconfig.FormatCredentialCLIStatus(ctx))
+ cmd.Println(decoderconfig.FormatCredentialCLIStatus(ctx))
return nil
},
}
@@ -33,7 +33,7 @@ var credentialsRemoveCmd = &cobra.Command{
ok, _ := cmd.Flags().GetBool("yes")
if !ok {
var err error
- ok, err = confirmDestructive(fmt.Sprintf("Remove stored API key(s) for %q from %s?", args[0], rhoconfig.CredentialStoreName()))
+ ok, err = confirmDestructive(fmt.Sprintf("Remove stored API key(s) for %q from %s?", args[0], decoderconfig.CredentialStoreName()))
if err != nil {
return err
}
@@ -42,11 +42,11 @@ var credentialsRemoveCmd = &cobra.Command{
cmd.Printf("%s\n", auditTint("Cancelled.", textMuted))
return nil
}
- removed, err := rhoconfig.RemoveStoredCredential(ctx, args[0])
+ removed, err := decoderconfig.RemoveStoredCredential(ctx, args[0])
if err != nil {
return err
}
- cmd.Printf("%s\n", auditTint(fmt.Sprintf("Removed %d key(s) from %s: %s", len(removed), rhoconfig.CredentialStoreName(), strings.Join(removed, ", ")), doneGreen))
+ cmd.Printf("%s\n", auditTint(fmt.Sprintf("Removed %d key(s) from %s: %s", len(removed), decoderconfig.CredentialStoreName(), strings.Join(removed, ", ")), doneGreen))
return nil
},
}
diff --git a/cmd/daemon.go b/cmd/daemon.go
index 24af20d46..d313c3f44 100644
--- a/cmd/daemon.go
+++ b/cmd/daemon.go
@@ -14,20 +14,20 @@ import (
"syscall"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
-
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/daemon"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/executiongraph"
- "github.com/GrayCodeAI/rho/internal/fsutil"
- "github.com/GrayCodeAI/rho/internal/multiagent/agents"
- "github.com/GrayCodeAI/rho/internal/netutil"
- "github.com/GrayCodeAI/rho/internal/observability/logger"
- "github.com/GrayCodeAI/rho/internal/observability/otellog"
- "github.com/GrayCodeAI/rho/internal/observability/oteltrace"
- "github.com/GrayCodeAI/rho/internal/securitylog"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/daemon"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/executiongraph"
+ "github.com/GrayCodeAI/decoder/internal/fsutil"
+ "github.com/GrayCodeAI/decoder/internal/multiagent/agents"
+ "github.com/GrayCodeAI/decoder/internal/netutil"
+ "github.com/GrayCodeAI/decoder/internal/observability/logger"
+ "github.com/GrayCodeAI/decoder/internal/observability/otellog"
+ "github.com/GrayCodeAI/decoder/internal/observability/oteltrace"
+ "github.com/GrayCodeAI/decoder/internal/securitylog"
+ "github.com/GrayCodeAI/decoder/internal/storage"
"github.com/spf13/cobra"
)
@@ -45,8 +45,8 @@ var (
var daemonCmd = &cobra.Command{
Use: "daemon",
- Short: "Manage the rho background server",
- Long: "Run rho as a background HTTP server for programmatic/CI access.",
+ Short: "Manage the decoder background server",
+ Long: "Run decoder as a background HTTP server for programmatic/CI access.",
}
var daemonStartCmd = &cobra.Command{
@@ -70,7 +70,7 @@ var daemonStatusCmd = &cobra.Command{
func init() {
daemonStartCmd.Flags().IntVarP(&daemonPort, "port", "p", 4590, "Port to listen on")
daemonStartCmd.Flags().StringVar(&daemonHost, "host", netutil.LoopbackHost, "Host to bind to (default: 127.0.0.1, use 0.0.0.0 for remote access)")
- daemonStartCmd.Flags().StringVar(&daemonAPIKey, "api-key", "", "API key for protected daemon endpoints (defaults to RHO_DAEMON_API_KEY or a generated key)")
+ daemonStartCmd.Flags().StringVar(&daemonAPIKey, "api-key", "", "API key for protected daemon endpoints (defaults to DECODER_DAEMON_API_KEY or a generated key)")
daemonStartCmd.Flags().StringVar(&daemonLogLevel, "log-level", "INFO", "Log level for daemon output (DEBUG, INFO, WARN, ERROR)")
daemonStartCmd.Flags().StringSliceVar(&daemonCORSOrigins, "cors", []string{}, "Comma-separated list of allowed CORS origins (empty disables CORS, '*' allows all)")
daemonStartCmd.Flags().StringVar(&daemonTLSCertFile, "tls-cert", "", "Path to TLS certificate file (enables HTTPS when paired with --tls-key)")
@@ -83,9 +83,9 @@ func init() {
}
func runDaemonStart(_ *cobra.Command, _ []string) error {
- settings := rhoconfig.LoadSettings()
+ settings := decoderconfig.LoadSettings()
- // Initialize OpenTelemetry telemetry (opt-in via RHO_ENABLE_TELEMETRY=1).
+ // Initialize OpenTelemetry telemetry (opt-in via DECODER_ENABLE_TELEMETRY=1).
telemetryProviders, telemetryErr := oteltrace.InitTelemetry(oteltrace.DefaultTelemetryConfig())
if telemetryErr != nil {
fmt.Fprintf(os.Stderr, "%s\n", auditTint(fmt.Sprintf("warning: telemetry initialization failed: %v", telemetryErr), warnAmber))
@@ -113,7 +113,7 @@ func runDaemonStart(_ *cobra.Command, _ []string) error {
}
// Set up file-backed logging for the daemon. Logs go to
- // ~/.rho/state/daemon.log with slog structured output.
+ // ~/.decoder/state/daemon.log with slog structured output.
logFile, logErr := openDaemonLogFile()
var daemonLogger *logger.Logger
if logErr != nil {
@@ -130,10 +130,10 @@ func runDaemonStart(_ *cobra.Command, _ []string) error {
}
// Replace the discarded logger with the real file-backed logger.
- newSession := newConfiguredRhoSessionFactory(settings, daemonLogger)
+ newSession := newConfiguredDecoderSessionFactory(settings, daemonLogger)
// Log startup banner.
- daemonLogger.Info("rho daemon starting", map[string]interface{}{
+ daemonLogger.Info("decoder daemon starting", map[string]interface{}{
"host": daemonHost,
"port": daemonPort,
"telemetry_enabled": telemetryProviders != nil && telemetryProviders.IsEnabled(),
@@ -141,7 +141,7 @@ func runDaemonStart(_ *cobra.Command, _ []string) error {
apiKey := daemonAPIKey
if apiKey == "" {
- apiKey = os.Getenv("RHO_DAEMON_API_KEY")
+ apiKey = os.Getenv("DECODER_DAEMON_API_KEY")
}
if apiKey == "" {
var err error
@@ -211,9 +211,9 @@ func runDaemonStart(_ *cobra.Command, _ []string) error {
)
})
- // Wire Flux's authoritative local preflight into GET /v1/ready. A session
- // factory only proves Rho can attempt construction; readiness additionally
- // requires Flux's provider state, catalog, credentials, and model selection.
+ // Wire Mux's authoritative local preflight into GET /v1/ready. A session
+ // factory only proves Decoder can attempt construction; readiness additionally
+ // requires Mux's provider state, catalog, credentials, and model selection.
srv.SetReadyFn(daemonReadyProbe(factory))
addr, err := srv.Start()
if err != nil {
@@ -229,19 +229,19 @@ func runDaemonStart(_ *cobra.Command, _ []string) error {
})
defer preheater.Stop()
- fmt.Printf("rho daemon running on http://%s\n", addr)
+ fmt.Printf("decoder daemon running on http://%s\n", addr)
fmt.Println("Endpoints: GET /v1/health, GET /v1/ready, POST /v1/chat, GET /v1/sessions, GET /v1/metrics")
fmt.Println("Protected endpoints require Authorization: Bearer or X-API-Key.")
if len(apiKey) > 8 {
fmt.Printf("API key: %s...%s\n", apiKey[:4], apiKey[len(apiKey)-4:])
} else {
- fmt.Println("API key: (set via --api-key or RHO_DAEMON_API_KEY)")
+ fmt.Println("API key: (set via --api-key or DECODER_DAEMON_API_KEY)")
}
fmt.Printf("Logs: %s\n", filepath.Join(storage.DaemonRunDir(), "daemon.log"))
if telemetryProviders != nil && telemetryProviders.IsEnabled() {
fmt.Println("Telemetry: enabled (OTLP export configured)")
} else {
- fmt.Println("Telemetry: disabled (set RHO_ENABLE_TELEMETRY=1 to enable)")
+ fmt.Println("Telemetry: disabled (set DECODER_ENABLE_TELEMETRY=1 to enable)")
}
keyFile := filepath.Join(storage.DaemonRunDir(), "daemon.key")
_ = os.MkdirAll(filepath.Dir(keyFile), 0o700)
@@ -285,7 +285,7 @@ func runDaemonStart(_ *cobra.Command, _ []string) error {
}
// openDaemonLogFile opens (or creates) the daemon log file at
-// ~/.rho/state/daemon.log and returns it. The directory is created if needed.
+// ~/.decoder/state/daemon.log and returns it. The directory is created if needed.
func openDaemonLogFile() (*os.File, error) {
dir := storage.DaemonRunDir()
if err := os.MkdirAll(dir, 0o750); err != nil { // #nosec G301 -- daemon run dir needs group traversal
@@ -329,26 +329,26 @@ func slogLevelFromString(s string) slog.Level {
}
// daemonReadyProbe builds the readiness function installed via SetReadyFn. It
-// performs Flux's local preflight (provider state, catalog, credentials, and
+// performs Mux's local preflight (provider state, catalog, credentials, and
// model selection) under a short timeout:
//
// - No session factory wired -> not ready ("engine not configured").
// - Preflight reports ready -> ready.
-// - Preflight reports incomplete -> not ready with the failed Flux check.
+// - Preflight reports incomplete -> not ready with the failed Mux check.
//
-// This never performs a paid/live model call — Flux preflight only inspects
+// This never performs a paid/live model call — Mux preflight only inspects
// local catalog/credential/model state — so it is safe to call on every probe.
func daemonReadyProbe(factory daemon.SessionFactory) func() (bool, string) {
- return daemonReadyProbeWithPreflight(factory, rhoconfig.EnginePreflightReport)
+ return daemonReadyProbeWithPreflight(factory, decoderconfig.EnginePreflightReport)
}
-func daemonReadyProbeWithPreflight(factory daemon.SessionFactory, preflight func(context.Context) rhoconfig.EnginePreflight) func() (bool, string) {
+func daemonReadyProbeWithPreflight(factory daemon.SessionFactory, preflight func(context.Context) decoderconfig.EnginePreflight) func() (bool, string) {
return func() (bool, string) {
if factory == nil {
return false, "engine not configured"
}
if preflight == nil {
- return false, "Flux readiness probe not configured"
+ return false, "Mux readiness probe not configured"
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
@@ -362,13 +362,13 @@ func daemonReadyProbeWithPreflight(factory daemon.SessionFactory, preflight func
if detail == "" {
detail = "failed"
}
- return false, fmt.Sprintf("Flux %s: %s", check.Name, detail)
+ return false, fmt.Sprintf("Mux %s: %s", check.Name, detail)
}
}
if ctx.Err() != nil {
- return false, "Flux preflight timed out"
+ return false, "Mux preflight timed out"
}
- return false, "Flux preflight is not ready"
+ return false, "Mux preflight is not ready"
}
}
@@ -399,14 +399,14 @@ func generateDaemonAPIKey() (string, error) {
return base64.RawURLEncoding.EncodeToString(b[:]), nil
}
-// daemonAutonomyFromFlag resolves the --autonomy flag / RHO_DAEMON_AUTONOMY
+// daemonAutonomyFromFlag resolves the --autonomy flag / DECODER_DAEMON_AUTONOMY
// env var into the server-side autonomy cap. An empty value leaves the
// default cap (AutonomySemi) in place; invalid values fail closed at
// "supervised" rather than silently allowing full autonomy.
func daemonAutonomyFromFlag(s string) safety.AutonomyLevel {
s = strings.TrimSpace(s)
if s == "" {
- s = os.Getenv("RHO_DAEMON_AUTONOMY")
+ s = os.Getenv("DECODER_DAEMON_AUTONOMY")
}
if s == "" {
return 0 // zero => DefaultMaxAutonomy in the daemon
diff --git a/cmd/daemon_ready_test.go b/cmd/daemon_ready_test.go
index 179f428d0..854b38194 100644
--- a/cmd/daemon_ready_test.go
+++ b/cmd/daemon_ready_test.go
@@ -12,10 +12,10 @@ import (
"testing"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/daemon"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/storage"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/daemon"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/storage"
)
// TestDaemonReadyProbe_NilFactory verifies the probe reports not-ready when no
@@ -30,30 +30,30 @@ func TestDaemonReadyProbe_NilFactory(t *testing.T) {
}
}
-// TestDaemonReadyProbe_FailedFluxPreflight verifies a factory alone does not
-// make the daemon ready when Flux's authoritative preflight is incomplete.
-func TestDaemonReadyProbe_FailedFluxPreflight(t *testing.T) {
+// TestDaemonReadyProbe_FailedMuxPreflight verifies a factory alone does not
+// make the daemon ready when Mux's authoritative preflight is incomplete.
+func TestDaemonReadyProbe_FailedMuxPreflight(t *testing.T) {
factory := func(daemon.ChatRequest) (*engine.Session, error) { return nil, nil }
- probe := daemonReadyProbeWithPreflight(factory, func(context.Context) rhoconfig.EnginePreflight {
- return rhoconfig.EnginePreflight{Ready: false}
+ probe := daemonReadyProbeWithPreflight(factory, func(context.Context) decoderconfig.EnginePreflight {
+ return decoderconfig.EnginePreflight{Ready: false}
})
ok, reason := probe()
if ok {
- t.Fatal("failed Flux preflight must report not ready")
+ t.Fatal("failed Mux preflight must report not ready")
}
if reason == "" {
- t.Fatal("failed Flux preflight must include a reason")
+ t.Fatal("failed Mux preflight must include a reason")
}
}
-func TestDaemonReadyProbe_ReadyFluxPreflight(t *testing.T) {
+func TestDaemonReadyProbe_ReadyMuxPreflight(t *testing.T) {
factory := func(daemon.ChatRequest) (*engine.Session, error) { return nil, nil }
- probe := daemonReadyProbeWithPreflight(factory, func(context.Context) rhoconfig.EnginePreflight {
- return rhoconfig.EnginePreflight{Ready: true}
+ probe := daemonReadyProbeWithPreflight(factory, func(context.Context) decoderconfig.EnginePreflight {
+ return decoderconfig.EnginePreflight{Ready: true}
})
ok, reason := probe()
if !ok || reason != "" {
- t.Fatalf("ready Flux preflight = (%v, %q), want (true, empty)", ok, reason)
+ t.Fatalf("ready Mux preflight = (%v, %q), want (true, empty)", ok, reason)
}
}
@@ -62,8 +62,8 @@ func TestDaemonReadyProbe_ReadyFluxPreflight(t *testing.T) {
func TestDaemonReadyProbe_AffectsReadyEndpoint(t *testing.T) {
factory := func(daemon.ChatRequest) (*engine.Session, error) { return nil, nil }
srv := daemon.New(daemon.Config{Port: 0, Host: "127.0.0.1"}, factory)
- srv.SetReadyFn(daemonReadyProbeWithPreflight(factory, func(context.Context) rhoconfig.EnginePreflight {
- return rhoconfig.EnginePreflight{Ready: false}
+ srv.SetReadyFn(daemonReadyProbeWithPreflight(factory, func(context.Context) decoderconfig.EnginePreflight {
+ return decoderconfig.EnginePreflight{Ready: false}
}))
addr, err := srv.Start()
@@ -93,7 +93,7 @@ func TestDaemonReadyProbe_AffectsReadyEndpoint(t *testing.T) {
defer resp.Body.Close()
if resp.StatusCode != http.StatusServiceUnavailable {
- t.Errorf("expected 503 from /v1/ready when Flux is not ready, got %d", resp.StatusCode)
+ t.Errorf("expected 503 from /v1/ready when Mux is not ready, got %d", resp.StatusCode)
}
var body daemon.ReadyResponse
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
diff --git a/cmd/rho/main.go b/cmd/decoder/main.go
similarity index 84%
rename from cmd/rho/main.go
rename to cmd/decoder/main.go
index fa7e5e433..ad702c719 100644
--- a/cmd/rho/main.go
+++ b/cmd/decoder/main.go
@@ -9,13 +9,13 @@ import (
"golang.org/x/term"
- "github.com/GrayCodeAI/rho/cmd"
- "github.com/GrayCodeAI/rho/internal/crash"
- "github.com/GrayCodeAI/rho/internal/mcp"
- "github.com/GrayCodeAI/rho/internal/observability/otellog"
- "github.com/GrayCodeAI/rho/internal/observability/oteltrace"
- "github.com/GrayCodeAI/rho/internal/rhoerr"
- internaltheme "github.com/GrayCodeAI/rho/internal/theme"
+ "github.com/GrayCodeAI/decoder/cmd"
+ "github.com/GrayCodeAI/decoder/internal/crash"
+ "github.com/GrayCodeAI/decoder/internal/decodererr"
+ "github.com/GrayCodeAI/decoder/internal/mcp"
+ "github.com/GrayCodeAI/decoder/internal/observability/otellog"
+ "github.com/GrayCodeAI/decoder/internal/observability/oteltrace"
+ internaltheme "github.com/GrayCodeAI/decoder/internal/theme"
)
// Version, Commit, and BuildDate are set at build time via ldflags.
@@ -45,12 +45,12 @@ func main() {
// Handle --version flag immediately
if len(os.Args) > 1 && os.Args[1] == "--version" {
- fmt.Println("rho " + Version)
+ fmt.Println("decoder " + Version)
return
}
- // Initialize OpenTelemetry telemetry (opt-in via RHO_ENABLE_TELEMETRY=1).
- // Telemetry failures are non-fatal: rho continues with in-memory tracing only.
+ // Initialize OpenTelemetry telemetry (opt-in via DECODER_ENABLE_TELEMETRY=1).
+ // Telemetry failures are non-fatal: decoder continues with in-memory tracing only.
telemetryProviders, telemetryErr := oteltrace.InitTelemetry(oteltrace.DefaultTelemetryConfig())
if telemetryErr != nil {
fmt.Fprintln(os.Stderr, "warning: telemetry initialization failed:", telemetryErr)
@@ -64,7 +64,7 @@ func main() {
}
// OTLP log-record export (DSH session-telemetry-otel port). Opt-in like
- // tracing: RHO_ENABLE_TELEMETRY=1 plus an OTLP logs endpoint. The
+ // tracing: DECODER_ENABLE_TELEMETRY=1 plus an OTLP logs endpoint. The
// sharing policy gates emission; failures are non-fatal.
logBackend, logBackendErr := otellog.NewBackend(otellog.DefaultConfig())
if logBackendErr != nil {
@@ -94,7 +94,7 @@ func main() {
if errors.As(err, &exitErr) {
os.Exit(exitErr.Code)
}
- os.Exit(rhoerr.ClassifyExitCode(err))
+ os.Exit(decodererr.ClassifyExitCode(err))
}
}
diff --git a/cmd/rho_mascot.go b/cmd/decoder_mascot.go
similarity index 55%
rename from cmd/rho_mascot.go
rename to cmd/decoder_mascot.go
index 40c0549c7..fb1cec303 100644
--- a/cmd/rho_mascot.go
+++ b/cmd/decoder_mascot.go
@@ -5,14 +5,14 @@ import (
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/features/welcome"
+ "github.com/GrayCodeAI/decoder/internal/features/welcome"
)
-func rhoMascotEnabled() bool {
+func decoderMascotEnabled() bool {
return welcome.Enabled()
}
-func emitRhoMascotCmd() tea.Cmd {
+func emitDecoderMascotCmd() tea.Cmd {
return func() tea.Msg {
_ = welcome.Emit(os.Stderr)
return nil
diff --git a/cmd/diagnostics.go b/cmd/diagnostics.go
index ce913295c..f06924bc2 100644
--- a/cmd/diagnostics.go
+++ b/cmd/diagnostics.go
@@ -12,17 +12,17 @@ import (
"strings"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/resilience/health"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/storage"
- "github.com/GrayCodeAI/rho/internal/stt"
- "github.com/GrayCodeAI/rho/internal/tool"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/resilience/health"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/stt"
+ "github.com/GrayCodeAI/decoder/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
-func doctorReport(settings rhoconfig.Settings) string {
+func doctorReport(settings decoderconfig.Settings) string {
// Diagnostics must report the requested/effective selection even when its
// credential is missing; readiness and health sections explain why it is
// not yet usable. Hiding it as auto/default makes misconfiguration harder
@@ -38,7 +38,7 @@ func doctorReport(settings rhoconfig.Settings) string {
cwd, _ := os.Getwd()
var b strings.Builder
- b.WriteString("Rho doctor\n")
+ b.WriteString("Decoder doctor\n")
b.WriteString(fmt.Sprintf("Version: %s\n", version))
b.WriteString(fmt.Sprintf("Go version: %s\n", runtime.Version()))
b.WriteString(fmt.Sprintf("Directory: %s\n", cwd))
@@ -55,7 +55,7 @@ func doctorReport(settings rhoconfig.Settings) string {
// Ecosystem versions
b.WriteString("\nEcosystem versions:\n")
for _, component := range []struct{ directory, product string }{
- {directory: "flux", product: "Flux"},
+ {directory: "mux", product: "Mux"},
} {
versionFile := filepath.Join(filepath.Dir(cwd), component.directory, "VERSION")
// #nosec G304 -- versionFile is built from a fixed sibling-repo list
@@ -65,16 +65,16 @@ func doctorReport(settings rhoconfig.Settings) string {
b.WriteString(fmt.Sprintf(" %s (%s): not checked out\n", component.product, component.directory))
}
}
- b.WriteString("\n" + rhoconfig.FormatEcosystemPanel(context.Background(), providerName, modelName) + "\n")
- b.WriteString("\n" + rhoconfig.FormatCatalogHealth(rhoconfig.CatalogHealthReport(context.Background())) + "\n")
- preflight := rhoconfig.EnginePreflightReportWithSettings(context.Background(), settings, rhoconfig.EnginePreflightOptions{})
- b.WriteString("\n" + rhoconfig.FormatEnginePreflight(preflight) + "\n")
+ b.WriteString("\n" + decoderconfig.FormatEcosystemPanel(context.Background(), providerName, modelName) + "\n")
+ b.WriteString("\n" + decoderconfig.FormatCatalogHealth(decoderconfig.CatalogHealthReport(context.Background())) + "\n")
+ preflight := decoderconfig.EnginePreflightReportWithSettings(context.Background(), settings, decoderconfig.EnginePreflightOptions{})
+ b.WriteString("\n" + decoderconfig.FormatEnginePreflight(preflight) + "\n")
b.WriteString("\nBackends (Gap-05):\n")
b.WriteString(fmt.Sprintf(" media: %s\n", backendStatus(tool.MediaEngineName(), tool.MediaEngineName() != "")))
b.WriteString(fmt.Sprintf(" stt: %s\n", backendStatus("", stt.Enabled())))
b.WriteString(fmt.Sprintf(" computer: %s\n", backendStatus(tool.ComputerBackendName(), tool.ComputerBackendName() != "")))
- b.WriteString("\n" + rhoconfig.CredentialStorageStatus(context.Background()).Formatted + "\n")
- if deployReport, err := rhoconfig.DeploymentStatusReportWithSettings(context.Background(), settings, modelName); err == nil {
+ b.WriteString("\n" + decoderconfig.CredentialStorageStatus(context.Background()).Formatted + "\n")
+ if deployReport, err := decoderconfig.DeploymentStatusReportWithSettings(context.Background(), settings, modelName); err == nil {
b.WriteString("\n" + deployReport + "\n")
}
b.WriteString("\n" + envSummaryWithSelection(providerName, modelName, false) + "\n")
@@ -86,18 +86,18 @@ func doctorReport(settings rhoconfig.Settings) string {
}
// Project instructions
- if md := rhoconfig.LoadAgentsMD(); md != "" {
+ if md := decoderconfig.LoadAgentsMD(); md != "" {
b.WriteString("\nProject instructions: found\n")
} else {
b.WriteString("\nProject instructions: not found (consider creating AGENTS.md)\n")
}
- // Installed skills (rho ships none; skills come from user/marketplace installs)
+ // Installed skills (decoder ships none; skills come from user/marketplace installs)
skillsDir := filepath.Join(storage.StateDir(), "skills")
if entries, err := os.ReadDir(skillsDir); err == nil && len(entries) > 0 {
b.WriteString(fmt.Sprintf("Installed skills: %d\n", len(entries)))
} else {
- b.WriteString("Installed skills: none (install with `rho skills install`)\n")
+ b.WriteString("Installed skills: none (install with `decoder skills install`)\n")
}
// Warn when installed skills drifted from the lockfile pins (content
// changed or SKILL.md removed after install). Warn-only: local edits are
@@ -120,7 +120,7 @@ func doctorReport(settings rhoconfig.Settings) string {
// Session recovery status
recoveryCandidates := session.ScanForRecovery()
if len(recoveryCandidates) > 0 {
- b.WriteString(fmt.Sprintf("\nInterrupted sessions: %d (run rho recover)\n", len(recoveryCandidates)))
+ b.WriteString(fmt.Sprintf("\nInterrupted sessions: %d (run decoder recover)\n", len(recoveryCandidates)))
} else {
b.WriteString("\nInterrupted sessions: none\n")
}
@@ -142,14 +142,14 @@ func backendStatus(name string, enabled bool) string {
return "wired (" + name + ")"
}
-func healthCheckReport(settings rhoconfig.Settings, provider string) string {
+func healthCheckReport(settings decoderconfig.Settings, provider string) string {
registry := health.NewRegistry()
registry.Register("api_key", providerCredentialHealthChecker(provider))
// Settings validation
registry.Register("config", func(ctx context.Context) health.Check {
- result := rhoconfig.ValidateSettings(settings)
+ result := decoderconfig.ValidateSettings(settings)
if result.Valid {
return health.Check{Name: "config", Status: health.Healthy, Message: "Configuration valid"}
}
@@ -211,7 +211,7 @@ func providerCredentialHealthChecker(provider string) health.Checker {
status := health.Unhealthy
message := label + " credential not configured"
- if providerID != "" && rhoconfig.HasStoredCredentialForProvider(ctx, providerID) {
+ if providerID != "" && decoderconfig.HasStoredCredentialForProvider(ctx, providerID) {
status = health.Healthy
message = label + " credential configured"
}
@@ -229,19 +229,19 @@ func providerCredentialHealthChecker(provider string) health.Checker {
func diagnosticsProvider(ctx context.Context, provider string) string {
provider = strings.TrimSpace(provider)
if provider == "" || strings.EqualFold(provider, "auto") {
- provider = strings.TrimSpace(rhoconfig.ActiveGateway(ctx))
+ provider = strings.TrimSpace(decoderconfig.ActiveGateway(ctx))
if provider == "" || strings.EqualFold(provider, "auto") {
- provider = strings.TrimSpace(rhoconfig.EffectiveSelection(ctx, rhoconfig.SelectionOptions{}).Provider)
+ provider = strings.TrimSpace(decoderconfig.EffectiveSelection(ctx, decoderconfig.SelectionOptions{}).Provider)
}
}
- return rhoconfig.ActiveProviderID(provider)
+ return decoderconfig.ActiveProviderID(provider)
}
-func settingsSummary(settings rhoconfig.Settings) string {
+func settingsSummary(settings decoderconfig.Settings) string {
return configCommandSummary(settings)
}
-func mcpConfigSummary(settings rhoconfig.Settings) string {
+func mcpConfigSummary(settings decoderconfig.Settings) string {
if len(settings.MCPServers) == 0 && len(mcpServers) == 0 {
return auditTint("No MCP servers configured.", textMuted)
}
diff --git a/cmd/diagnostics_test.go b/cmd/diagnostics_test.go
index 66a4987af..0f8957330 100644
--- a/cmd/diagnostics_test.go
+++ b/cmd/diagnostics_test.go
@@ -6,9 +6,9 @@ import (
"testing"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
- "github.com/GrayCodeAI/rho/internal/resilience/health"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
+ "github.com/GrayCodeAI/decoder/internal/resilience/health"
)
type diagnosticsContextKey struct{}
@@ -25,7 +25,7 @@ func (s *contextRecordingCredentialStore) Get(ctx context.Context, account strin
func TestDoctorReport(t *testing.T) {
t.Parallel()
- settings := rhoconfig.Settings{}
+ settings := decoderconfig.Settings{}
report := doctorReport(settings)
if report == "" {
t.Error("doctorReport should produce non-empty output")
@@ -33,14 +33,14 @@ func TestDoctorReport(t *testing.T) {
if !strings.Contains(report, "Version") {
t.Error("report should mention version")
}
- if !strings.Contains(report, "Ecosystem (flux · token engine)") {
+ if !strings.Contains(report, "Ecosystem (mux · token engine)") {
t.Error("report should include ecosystem panel")
}
}
func TestDoctorReportProviderModelOrder(t *testing.T) {
t.Parallel()
- settings := rhoconfig.Settings{
+ settings := decoderconfig.Settings{
Model: "claude-sonnet-4-20250514",
Provider: "anthropic",
}
@@ -56,14 +56,14 @@ func TestDoctorReportProviderModelOrder(t *testing.T) {
func TestDoctorReportUsesResolvedProviderForChecks(t *testing.T) {
isolateCredentialHome(t)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
gateway.SetDefaultStore(&gateway.MapStore{})
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
- report := doctorReport(rhoconfig.Settings{
+ report := doctorReport(decoderconfig.Settings{
Model: "claude-sonnet-4-20250514",
Provider: "anthropic",
})
@@ -74,23 +74,23 @@ func TestDoctorReportUsesResolvedProviderForChecks(t *testing.T) {
func TestProviderCredentialHealthCheckerResolvesAuto(t *testing.T) {
isolateCredentialHome(t)
- t.Setenv("FLUX_CONFIG_DIR", t.TempDir())
- rhoconfig.InvalidateConfigUICache()
+ t.Setenv("MUX_CONFIG_DIR", t.TempDir())
+ decoderconfig.InvalidateConfigUICache()
store := &contextRecordingCredentialStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.WithValue(context.Background(), diagnosticsContextKey{}, "checker-context")
if err := store.Set(ctx, gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890"); err != nil {
t.Fatal(err)
}
- if err := rhoconfig.SetActiveProvider(ctx, "openrouter"); err != nil {
+ if err := decoderconfig.SetActiveProvider(ctx, "openrouter"); err != nil {
t.Fatal(err)
}
- if err := rhoconfig.SetActiveModel(ctx, "gpt-4o"); err != nil {
+ if err := decoderconfig.SetActiveModel(ctx, "gpt-4o"); err != nil {
t.Fatal(err)
}
store.contextValue = nil
@@ -117,12 +117,12 @@ func TestProviderCredentialHealthCheckerResolvesAuto(t *testing.T) {
func TestProviderCredentialHealthCheckerMissingIsUnhealthy(t *testing.T) {
isolateCredentialHome(t)
- t.Setenv("FLUX_CONFIG_DIR", t.TempDir())
- rhoconfig.InvalidateConfigUICache()
+ t.Setenv("MUX_CONFIG_DIR", t.TempDir())
+ decoderconfig.InvalidateConfigUICache()
gateway.SetDefaultStore(&gateway.MapStore{})
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
result := providerCredentialHealthChecker("openai")(context.Background())
@@ -142,7 +142,7 @@ func TestProviderCredentialHealthCheckerMissingIsUnhealthy(t *testing.T) {
func TestSettingsSummary(t *testing.T) {
t.Parallel()
- settings := rhoconfig.Settings{
+ settings := decoderconfig.Settings{
Model: "claude-sonnet-4-20250514",
Provider: "anthropic",
}
@@ -154,7 +154,7 @@ func TestSettingsSummary(t *testing.T) {
func TestMcpConfigSummary(t *testing.T) {
t.Parallel()
- settings := rhoconfig.Settings{}
+ settings := decoderconfig.Settings{}
summary := mcpConfigSummary(settings)
if summary == "" {
t.Error("mcpConfigSummary should produce output")
diff --git a/cmd/dx.go b/cmd/dx.go
index ab3bfcca7..6264af107 100644
--- a/cmd/dx.go
+++ b/cmd/dx.go
@@ -10,19 +10,19 @@ import (
"strings"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/storage"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/storage"
)
// startTime records when the process started, used by debugOutput for uptime.
var startTime = time.Now()
// doctorOutput returns a comprehensive system diagnostics string.
-func doctorOutput(settings rhoconfig.Settings) string {
+func doctorOutput(settings decoderconfig.Settings) string {
var b strings.Builder
- b.WriteString("=== Rho Doctor ===\n\n")
+ b.WriteString("=== Decoder Doctor ===\n\n")
// Go version, OS, arch
b.WriteString("System:\n")
@@ -49,12 +49,12 @@ func doctorOutput(settings rhoconfig.Settings) string {
b.WriteString(fmt.Sprintf(" TERM: %s\n", termVal))
b.WriteString(fmt.Sprintf(" COLORTERM: %s\n", colorTerm))
- // Rho version
+ // Decoder version
v := version
if v == "" {
v = "(dev)"
}
- b.WriteString("\nRho:\n")
+ b.WriteString("\nDecoder:\n")
b.WriteString(fmt.Sprintf(" Version: %s\n", v))
if buildDate != "" && buildDate != "unknown" {
b.WriteString(fmt.Sprintf(" Build date: %s\n", buildDate))
@@ -67,10 +67,10 @@ func doctorOutput(settings rhoconfig.Settings) string {
}
b.WriteString("\nProvider:\n")
b.WriteString(fmt.Sprintf(" Provider: %s\n", effectiveProvider))
- b.WriteString(fmt.Sprintf(" API key: %s\n", maskedKeyStatus(rhoconfig.ActiveProvider(context.Background()))))
+ b.WriteString(fmt.Sprintf(" API key: %s\n", maskedKeyStatus(decoderconfig.ActiveProvider(context.Background()))))
- // Model configured (flux provider.json)
- effectiveModel := strings.TrimSpace(rhoconfig.ActiveModel(context.Background()))
+ // Model configured (mux provider.json)
+ effectiveModel := strings.TrimSpace(decoderconfig.ActiveModel(context.Background()))
if effectiveModel == "" {
effectiveModel = "(not configured)"
}
@@ -111,7 +111,7 @@ func doctorOutput(settings rhoconfig.Settings) string {
}
// AGENTS.md found
- agentsMD := rhoconfig.LoadAgentsMD()
+ agentsMD := decoderconfig.LoadAgentsMD()
if agentsMD != "" {
b.WriteString("AGENTS.md: found\n")
} else {
@@ -146,7 +146,7 @@ func doctorOutput(settings rhoconfig.Settings) string {
// doctorJSON returns the doctor diagnostics as indented JSON, mirroring the
// fields of doctorOutput but as machine-parseable structured data.
-func doctorJSON(settings rhoconfig.Settings) string {
+func doctorJSON(settings decoderconfig.Settings) string {
type sessionDirInfo struct {
Path string `json:"path"`
Status string `json:"status"`
@@ -165,7 +165,7 @@ func doctorJSON(settings rhoconfig.Settings) string {
if effectiveProvider == "" {
effectiveProvider = "(not configured)"
}
- effectiveModel := strings.TrimSpace(rhoconfig.ActiveModel(context.Background()))
+ effectiveModel := strings.TrimSpace(decoderconfig.ActiveModel(context.Background()))
if effectiveModel == "" {
effectiveModel = "(not configured)"
}
@@ -219,7 +219,7 @@ func doctorJSON(settings rhoconfig.Settings) string {
plugins = len(manifests)
}
- agentsMD := rhoconfig.LoadAgentsMD()
+ agentsMD := decoderconfig.LoadAgentsMD()
agentsState := "not found"
if agentsMD != "" {
agentsState = "found"
@@ -274,7 +274,7 @@ func doctorJSON(settings rhoconfig.Settings) string {
Version: v,
BuildDate: buildDate,
Provider: effectiveProvider,
- APIKey: maskedKeyStatus(rhoconfig.ActiveProvider(context.Background())),
+ APIKey: maskedKeyStatus(decoderconfig.ActiveProvider(context.Background())),
Model: effectiveModel,
SessionDir: sessDir,
MCPServers: mcpCount,
@@ -293,7 +293,7 @@ func maskedKeyStatus(provider string) string {
if provider == "" {
return "(no provider set)"
}
- status := rhoconfig.EnvKeyStatus(provider)
+ status := decoderconfig.EnvKeyStatus(provider)
if status == "set" {
return "configured (masked)"
}
@@ -414,7 +414,7 @@ func countOpenFDs() int {
// Returns the file path and any error.
func exportMarkdown(messages []displayMsg, sessionID string) (string, error) {
var b strings.Builder
- b.WriteString(fmt.Sprintf("# Rho Session: %s\n\n", sessionID))
+ b.WriteString(fmt.Sprintf("# Decoder Session: %s\n\n", sessionID))
b.WriteString(fmt.Sprintf("Exported: %s\n\n", time.Now().Format(time.RFC3339)))
b.WriteString("---\n\n")
@@ -443,7 +443,7 @@ func exportMarkdown(messages []displayMsg, sessionID string) (string, error) {
}
}
- filename := fmt.Sprintf("rho-session-%s.md", sessionID)
+ filename := fmt.Sprintf("decoder-session-%s.md", sessionID)
if err := os.WriteFile(filename, []byte(b.String()), 0o600); err != nil {
return "", fmt.Errorf("failed to write %s: %w", filename, err)
}
@@ -490,7 +490,7 @@ func exportJSON(messages []displayMsg, sessionID string) (string, error) {
return "", fmt.Errorf("failed to marshal session: %w", err)
}
- filename := fmt.Sprintf("rho-session-%s.json", sessionID)
+ filename := fmt.Sprintf("decoder-session-%s.json", sessionID)
if err := os.WriteFile(filename, data, 0o600); err != nil {
return "", fmt.Errorf("failed to write %s: %w", filename, err)
}
diff --git a/cmd/dx_test.go b/cmd/dx_test.go
index e730ccac3..21bfc3389 100644
--- a/cmd/dx_test.go
+++ b/cmd/dx_test.go
@@ -7,15 +7,15 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/tool"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
func TestDoctorOutputContainsSections(t *testing.T) {
preserveCLICompilerVersionState(t)
version = "test-dx-version"
- settings := rhoconfig.Settings{
+ settings := decoderconfig.Settings{
Provider: "openai",
Model: "gpt-4o",
}
@@ -23,7 +23,7 @@ func TestDoctorOutputContainsSections(t *testing.T) {
out := doctorOutput(settings)
sections := []string{
- "Rho Doctor",
+ "Decoder Doctor",
"Go version:",
"OS:",
"Arch:",
@@ -50,10 +50,10 @@ func TestDoctorOutputContainsSections(t *testing.T) {
func TestDoctorOutputWithMCPServers(t *testing.T) {
preserveCLICompilerVersionState(t)
version = "test-dx-version"
- settings := rhoconfig.Settings{
+ settings := decoderconfig.Settings{
Provider: "anthropic",
Model: "claude-sonnet-4-20250514",
- MCPServers: []rhoconfig.MCPServerConfig{
+ MCPServers: []decoderconfig.MCPServerConfig{
{Name: "test-mcp", Command: "test-cmd"},
},
}
@@ -67,10 +67,10 @@ func TestDoctorOutputWithMCPServers(t *testing.T) {
func TestDoctorJSONIsValidStructuredOutput(t *testing.T) {
preserveCLICompilerVersionState(t)
version = "test-dx-version"
- settings := rhoconfig.Settings{
+ settings := decoderconfig.Settings{
Provider: "anthropic",
Model: "claude-sonnet-4-20250514",
- MCPServers: []rhoconfig.MCPServerConfig{
+ MCPServers: []decoderconfig.MCPServerConfig{
{Name: "test-mcp", Command: "test-cmd"},
},
}
@@ -168,7 +168,7 @@ func TestExportMarkdownCreatesFile(t *testing.T) {
defer os.Chdir(origDir)
messages := []displayMsg{
- {role: "user", content: "Hello rho"},
+ {role: "user", content: "Hello decoder"},
{role: "assistant", content: "Hello! How can I help?"},
{role: "system", content: "System message here"},
{role: "welcome", content: "Should be skipped"},
@@ -189,10 +189,10 @@ func TestExportMarkdownCreatesFile(t *testing.T) {
}
content := string(data)
- if !strings.Contains(content, "# Rho Session: test-export-id") {
+ if !strings.Contains(content, "# Decoder Session: test-export-id") {
t.Errorf("export missing session header")
}
- if !strings.Contains(content, "Hello rho") {
+ if !strings.Contains(content, "Hello decoder") {
t.Errorf("export missing user message")
}
if !strings.Contains(content, "Hello! How can I help?") {
diff --git a/cmd/ecosystem.go b/cmd/ecosystem.go
index aefec2184..6ee8d8006 100644
--- a/cmd/ecosystem.go
+++ b/cmd/ecosystem.go
@@ -4,7 +4,7 @@ import (
"context"
"encoding/json"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
"github.com/spf13/cobra"
)
@@ -12,8 +12,8 @@ var ecosystemJSON bool
var ecosystemCmd = &cobra.Command{
Use: "ecosystem",
- Short: "Show flux and token-pipeline integration status",
- Long: "Print the ecosystem panel summarizing the LLM provider runtime (flux) and the local token/compression pipeline. Same block as the top of rho doctor.",
+ Short: "Show mux and token-pipeline integration status",
+ Long: "Print the ecosystem panel summarizing the LLM provider runtime (mux) and the local token/compression pipeline. Same block as the top of decoder doctor.",
RunE: func(cmd *cobra.Command, args []string) error {
settings, err := loadEffectiveSettings()
if err != nil {
@@ -24,12 +24,12 @@ var ecosystemCmd = &cobra.Command{
providerName = "auto"
}
if ecosystemJSON {
- report := rhoconfig.BuildEcosystemReport(context.Background(), providerName, modelName)
+ report := decoderconfig.BuildEcosystemReport(context.Background(), providerName, modelName)
enc := json.NewEncoder(cmd.OutOrStdout())
enc.SetIndent("", " ")
return enc.Encode(report)
}
- cmd.Println(rhoconfig.FormatEcosystemPanel(context.Background(), providerName, modelName))
+ cmd.Println(decoderconfig.FormatEcosystemPanel(context.Background(), providerName, modelName))
return nil
},
}
diff --git a/cmd/ecosystem_test.go b/cmd/ecosystem_test.go
index 9b2578e6b..e86d86bae 100644
--- a/cmd/ecosystem_test.go
+++ b/cmd/ecosystem_test.go
@@ -4,17 +4,17 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func TestEcosystemCmdRuns(t *testing.T) {
- settings := rhoconfig.Settings{}
+ settings := decoderconfig.Settings{}
model, provider := effectiveModelAndProvider(settings)
if provider == "" {
provider = "auto"
}
- out := rhoconfig.FormatEcosystemPanel(t.Context(), provider, model)
- if !strings.Contains(out, "Ecosystem (flux · token engine)") {
+ out := decoderconfig.FormatEcosystemPanel(t.Context(), provider, model)
+ if !strings.Contains(out, "Ecosystem (mux · token engine)") {
t.Fatalf("unexpected panel: %q", out)
}
if err := ecosystemCmd.RunE(ecosystemCmd, nil); err != nil {
diff --git a/cmd/error_classify.go b/cmd/error_classify.go
index 4fc8b2163..7d3895e4e 100644
--- a/cmd/error_classify.go
+++ b/cmd/error_classify.go
@@ -4,41 +4,41 @@ import (
"fmt"
"strings"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/errhint"
- "github.com/GrayCodeAI/rho/internal/rhoerr"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/decodererr"
+ "github.com/GrayCodeAI/decoder/internal/errhint"
)
// friendlyErrorMessage returns the user-friendly message for an error.
-// Delegates to the shared rhoerr.ClassifyErrorMessage for the base message,
+// Delegates to the shared decodererr.ClassifyErrorMessage for the base message,
// then enriches specific cases with dynamic hints that require the config
-// package (rhoerr can't import internal/config without a cycle).
+// package (decodererr can't import internal/config without a cycle).
func friendlyErrorMessage(err error) string {
- msg := rhoerr.ClassifyErrorMessage(err)
+ msg := decodererr.ClassifyErrorMessage(err)
if err == nil {
return msg
}
- ec := rhoerr.ClassifyError(err)
+ ec := decodererr.ClassifyError(err)
low := strings.ToLower(err.Error())
switch ec.ExitCode {
- case rhoerr.ExitNotFound:
+ case decodererr.ExitNotFound:
// Enrich model-not-found errors with concrete examples from the catalog.
if strings.Contains(low, "model") || strings.Contains(low, "unknown") ||
strings.Contains(low, "does not exist") {
- ex1, ex2 := rhoconfig.ExampleModelHints()
+ ex1, ex2 := decoderconfig.ExampleModelHints()
msg = fmt.Sprintf(
- "Model not found. Check your model name with /model.\n Examples from the flux catalog: %s, %s\n Use /models to list all models, or /config to change provider.",
+ "Model not found. Check your model name with /model.\n Examples from the mux catalog: %s, %s\n Use /models to list all models, or /config to change provider.",
ex1, ex2,
)
}
- case rhoerr.ExitAuth:
+ case decodererr.ExitAuth:
msg += "\n Check your API key with /config. Keys can expire or be revoked."
- case rhoerr.ExitNetwork:
+ case decodererr.ExitNetwork:
msg += "\n Check your internet connection. If you're behind a proxy, configure it with /config."
- case rhoerr.ExitTimeout:
+ case decodererr.ExitTimeout:
msg += "\n The request took too long. Try again, or use /model to switch to a faster provider."
}
diff --git a/cmd/error_classify_test.go b/cmd/error_classify_test.go
index 057af69b8..c10374900 100644
--- a/cmd/error_classify_test.go
+++ b/cmd/error_classify_test.go
@@ -15,7 +15,7 @@ func TestFriendlyErrorMessageAppendsProviderHint(t *testing.T) {
}
func TestFriendlyErrorMessageNoHintForLocalError(t *testing.T) {
- // A local error must not draw an errhint provider hint (rho's own
+ // A local error must not draw an errhint provider hint (decoder's own
// ExitNotFound enrichment is separate and fine).
msg := friendlyErrorMessage(errors.New("file not found: x"))
for _, marker := range []string{"API key rejected", "Rate limited", "Can't reach the provider", "Context window full", "Model unavailable"} {
diff --git a/cmd/errors.go b/cmd/errors.go
index 57f7dc564..970a75fd1 100644
--- a/cmd/errors.go
+++ b/cmd/errors.go
@@ -11,8 +11,8 @@ import (
"sync"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/storage"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/storage"
)
// friendlyError translates a raw error into a user-friendly message with an
@@ -25,7 +25,7 @@ func friendlyError(err error) string {
// ─── panicRecovery ────────────────────────────────────────────────────────────
// Catches panics, saves the current session state, logs the stack trace to
-// Rho's user state crash log, and exits with a user-friendly message.
+// Decoder's user state crash log, and exits with a user-friendly message.
// panicSaveFn is set by runChat to a closure that persists the active session.
// panicRecovery invokes it on an unexpected panic so a crash saves as much work
@@ -49,7 +49,7 @@ func panicRecovery(saveFn func()) {
stack := string(debug.Stack())
// Generate a short, unique error ID for support reference.
- // Format: rho-YYMMDD-<6 hex chars from stack hash>
+ // Format: decoder-YYMMDD-<6 hex chars from stack hash>
errorID := generateErrorID(stack)
// Attempt to save session
@@ -82,14 +82,14 @@ func panicRecovery(saveFn func()) {
}
// Print user-friendly message
- _, _ = fmt.Fprintf(os.Stderr, "\nrho encountered an unexpected error and needs to exit.\n")
+ _, _ = fmt.Fprintf(os.Stderr, "\ndecoder encountered an unexpected error and needs to exit.\n")
if saveFn != nil {
_, _ = fmt.Fprintf(os.Stderr, "Your session has been saved.\n")
} else {
_, _ = fmt.Fprintf(os.Stderr, "Session messages are persisted incrementally; the in-flight message may be lost.\n")
}
_, _ = fmt.Fprintf(os.Stderr, "Details logged to %s\n", filepath.Join(storage.StateDir(), "crash.log"))
- _, _ = fmt.Fprintf(os.Stderr, "Please report this at: https://github.com/GrayCodeAI/rho/issues\n")
+ _, _ = fmt.Fprintf(os.Stderr, "Please report this at: https://github.com/GrayCodeAI/decoder/issues\n")
_, _ = fmt.Fprintf(os.Stderr, "Include this error ID: %s\n\n", errorID)
_, _ = fmt.Fprintf(os.Stderr, "panic: %v\n", r)
os.Exit(1) // os.Exit intentional: panic recovery, defer already unwound
@@ -97,7 +97,7 @@ func panicRecovery(saveFn func()) {
}
// generateErrorID creates a short, unique error ID from the stack trace.
-// Format: rho-YYMMDD-<6 hex chars> — enough to correlate with crash.log
+// Format: decoder-YYMMDD-<6 hex chars> — enough to correlate with crash.log
// entries without requiring a random source.
func generateErrorID(stack string) string {
// Simple hash of the stack trace for uniqueness.
@@ -105,18 +105,18 @@ func generateErrorID(stack string) string {
for i := 0; i < len(stack) && i < 2000; i++ {
hash = ((hash << 5) + hash) ^ uint32(stack[i])
}
- return fmt.Sprintf("rho-%s-%06x", time.Now().Format("060102"), hash&0xFFFFFF)
+ return fmt.Sprintf("decoder-%s-%06x", time.Now().Format("060102"), hash&0xFFFFFF)
}
// ─── errorLogger ──────────────────────────────────────────────────────────────
-// Writes errors to Rho's user state error log with timestamps. Thread-safe.
+// Writes errors to Decoder's user state error log with timestamps. Thread-safe.
type errorLoggerT struct {
mu sync.Mutex
path string
}
-// LogError writes a timestamped error entry to the Rho error log.
+// LogError writes a timestamped error entry to the Decoder error log.
func (l *errorLoggerT) LogError(context string, err error) {
if l == nil || err == nil {
return
@@ -140,7 +140,7 @@ func (l *errorLoggerT) LogError(context string, err error) {
_, _ = f.WriteString(entry)
}
-// LogErrorf writes a formatted, timestamped error entry to the Rho error log.
+// LogErrorf writes a formatted, timestamped error entry to the Decoder error log.
func (l *errorLoggerT) LogErrorf(format string, args ...interface{}) {
if l == nil {
return
@@ -179,24 +179,24 @@ func (w StartupWarning) String() string {
return fmt.Sprintf("[%s] %s", w.Check, w.Message)
}
-func validateStartup(settings rhoconfig.Settings) []StartupWarning {
+func validateStartup(settings decoderconfig.Settings) []StartupWarning {
var warnings []StartupWarning
// 1. Check API key for configured provider.
- // Rho reads credentials from the OS secret store (macOS Keychain /
+ // Decoder reads credentials from the OS secret store (macOS Keychain /
// Linux Keyring), not just env vars — so we must check there too.
providerName := strings.TrimSpace(settings.Provider)
if providerName == "" {
- providerName = strings.TrimSpace(rhoconfig.ActiveProvider(context.Background()))
+ providerName = strings.TrimSpace(decoderconfig.ActiveProvider(context.Background()))
}
if providerName != "" && providerName != "ollama" {
hasEnv := false
- if envKey := rhoconfig.ProviderAPIKeyEnv(providerName); envKey != "" {
+ if envKey := decoderconfig.ProviderAPIKeyEnv(providerName); envKey != "" {
hasEnv = os.Getenv(envKey) != ""
}
- hasStored := rhoconfig.HasStoredCredentialForProvider(context.Background(), providerName)
+ hasStored := decoderconfig.HasStoredCredentialForProvider(context.Background(), providerName)
if !hasEnv && !hasStored {
- envKey := rhoconfig.ProviderAPIKeyEnv(providerName)
+ envKey := decoderconfig.ProviderAPIKeyEnv(providerName)
warnings = append(warnings, StartupWarning{
Check: "api_key",
Message: fmt.Sprintf("No API key found for %s. Set %s in your environment or run /config.", providerName, envKey),
@@ -232,10 +232,10 @@ func validateStartup(settings rhoconfig.Settings) []StartupWarning {
// post-first-paint (background), not on the TUI startup critical path where an
// offline machine would stall the UI for seconds. Returns a warning message, or
// "" when reachable/not applicable.
-func checkNetworkReachability(settings rhoconfig.Settings) string {
+func checkNetworkReachability(settings decoderconfig.Settings) string {
providerName := strings.TrimSpace(settings.Provider)
if providerName == "" {
- providerName = strings.TrimSpace(rhoconfig.ActiveProvider(context.Background()))
+ providerName = strings.TrimSpace(decoderconfig.ActiveProvider(context.Background()))
}
if providerName == "" || providerName == "ollama" {
return ""
@@ -252,5 +252,5 @@ func checkNetworkReachability(settings rhoconfig.Settings) string {
// providerDNSHost returns a hostname to check DNS resolution for a provider.
func providerDNSHost(provider string) string {
- return rhoconfig.GatewayDNSHost(provider)
+ return decoderconfig.GatewayDNSHost(provider)
}
diff --git a/cmd/errors_test.go b/cmd/errors_test.go
index aed33822c..6cc28f132 100644
--- a/cmd/errors_test.go
+++ b/cmd/errors_test.go
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func TestFriendlyErrorNil(t *testing.T) {
@@ -151,7 +151,7 @@ func TestFriendlyErrorInvalidModel(t *testing.T) {
if !strings.Contains(got, "/model") {
t.Errorf("friendlyError(%q) = %q, should suggest /model", tt.errMsg, got)
}
- example1, example2 := rhoconfig.ExampleModelHints()
+ example1, example2 := decoderconfig.ExampleModelHints()
if !strings.Contains(got, example1) || !strings.Contains(got, example2) {
t.Errorf("friendlyError(%q) = %q, should suggest valid model names", tt.errMsg, got)
}
@@ -582,7 +582,7 @@ func TestFriendlyErrorBackwardCompat(t *testing.T) {
err string
contains string
}{
- {"rate limit 429", "flux: openai stream request failed: max retries (3) exceeded: HTTP 429", "Rate limited"},
+ {"rate limit 429", "mux: openai stream request failed: max retries (3) exceeded: HTTP 429", "Rate limited"},
{"unauthorized 401", "HTTP 401 Unauthorized", "Authentication failed"},
{"forbidden 403", "HTTP 403 Forbidden", "Access denied"},
{"not found 404", "model not found", "/model"},
@@ -604,8 +604,8 @@ func TestFriendlyErrorBackwardCompat(t *testing.T) {
}
// helper for tests
-func emptySettings() rhoconfig.Settings {
- return rhoconfig.Settings{}
+func emptySettings() decoderconfig.Settings {
+ return decoderconfig.Settings{}
}
// ── signalHandler test ────────────────────────────────────────────────────────
diff --git a/cmd/eval.go b/cmd/eval.go
index c031b08aa..f3f6aced4 100644
--- a/cmd/eval.go
+++ b/cmd/eval.go
@@ -9,10 +9,10 @@ import (
"strings"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/features/eval"
- "github.com/GrayCodeAI/rho/internal/features/evalloop"
- "github.com/GrayCodeAI/rho/internal/tool"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/features/eval"
+ "github.com/GrayCodeAI/decoder/internal/features/evalloop"
+ "github.com/GrayCodeAI/decoder/internal/tool"
"github.com/spf13/cobra"
)
@@ -98,22 +98,22 @@ func runEvalLoop(cmd *cobra.Command, _ []string) error {
if strings.TrimSpace(evalLoopPrompt) == "" {
return fmt.Errorf("--prompt is required")
}
- settings := rhoconfig.LoadGlobalSettings()
+ settings := decoderconfig.LoadGlobalSettings()
ctx := context.Background()
- gw, err := rhoconfig.NewFluxEngineForSettings(settings)
+ gw, err := decoderconfig.NewMuxEngineForSettings(settings)
if err != nil {
return fmt.Errorf("eval loop: build engine client: %w", err)
}
model := strings.TrimSpace(evalLoopModel)
if model == "" {
- model = strings.TrimSpace(rhoconfig.ActiveModel(ctx))
+ model = strings.TrimSpace(decoderconfig.ActiveModel(ctx))
}
if model == "" {
model = strings.TrimSpace(settings.Model)
}
- workDir, err := os.MkdirTemp("", "rho-eval-loop-*")
+ workDir, err := os.MkdirTemp("", "decoder-eval-loop-*")
if err != nil {
return fmt.Errorf("eval loop: create temp dir: %w", err)
}
@@ -225,7 +225,7 @@ func runEval(_ *cobra.Command, _ []string) error {
fmt.Printf("%s\n", auditTint(fmt.Sprintf("Running %d tasks with model %s...", len(tasks), modelName), textPrimary))
- suite := &eval.BenchmarkSuite{Name: "rho-eval", Tasks: tasks}
+ suite := &eval.BenchmarkSuite{Name: "decoder-eval", Tasks: tasks}
runner := eval.NewRunner(modelName, "")
runner.NoCache = evalNoCache
if !evalNoCache {
diff --git a/cmd/eval_tools.go b/cmd/eval_tools.go
index 8bd13525b..35c107f62 100644
--- a/cmd/eval_tools.go
+++ b/cmd/eval_tools.go
@@ -6,9 +6,9 @@ import (
"fmt"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/features/eval"
- "github.com/GrayCodeAI/rho/internal/types"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/features/eval"
+ "github.com/GrayCodeAI/decoder/internal/types"
"github.com/spf13/cobra"
)
@@ -29,7 +29,7 @@ var evalToolsCmd = &cobra.Command{
}
// defaultToolUseCases is a small built-in set exercising clear positive and
-// negative tool-trigger situations against rho's standard tools.
+// negative tool-trigger situations against decoder's standard tools.
func defaultToolUseCases() []eval.ToolUseCase {
return []eval.ToolUseCase{
{
@@ -68,7 +68,7 @@ func defaultToolUseCases() []eval.ToolUseCase {
}
func runEvalTools(cmd *cobra.Command, _ []string) error {
- settings := rhoconfig.LoadSettings()
+ settings := decoderconfig.LoadSettings()
registry, err := defaultRegistry(settings)
if err != nil {
@@ -79,18 +79,18 @@ func runEvalTools(cmd *cobra.Command, _ []string) error {
return err
}
modelName, providerName := effectiveModelAndProvider(settings)
- sess, err := newConfiguredRhoSession(settings, providerName, modelName, systemPrompt, registry, nil)
+ sess, err := newConfiguredDecoderSession(settings, providerName, modelName, systemPrompt, registry, nil)
if err != nil {
return err
}
- tools := registry.FluxTools()
+ tools := registry.MuxTools()
// caller performs one tool-aware turn and reports the first tool the model
// chose (if any). It does not execute the tool — we are scoring selection,
// not effects.
caller := func(ctx context.Context, c eval.ToolUseCase) (eval.ObservedCall, error) {
- resp, err := sess.Chat(ctx, []types.FluxMessage{
+ resp, err := sess.Chat(ctx, []types.MuxMessage{
{Role: "user", Content: c.Prompt},
}, types.ChatOptions{Model: model, Tools: tools})
if err != nil {
diff --git a/cmd/exec.go b/cmd/exec.go
index 6aa325339..004cc0f44 100644
--- a/cmd/exec.go
+++ b/cmd/exec.go
@@ -14,17 +14,17 @@ import (
"time"
"unicode/utf8"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
-
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/errhint"
- "github.com/GrayCodeAI/rho/internal/multiagent/agents"
- "github.com/GrayCodeAI/rho/internal/notify"
- "github.com/GrayCodeAI/rho/internal/observability/logger"
- cloud "github.com/GrayCodeAI/rho/internal/platform/cloud"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/errhint"
+ "github.com/GrayCodeAI/decoder/internal/multiagent/agents"
+ "github.com/GrayCodeAI/decoder/internal/notify"
+ "github.com/GrayCodeAI/decoder/internal/observability/logger"
+ cloud "github.com/GrayCodeAI/decoder/internal/platform/cloud"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
"github.com/spf13/cobra"
)
@@ -94,13 +94,13 @@ Autonomy Levels:
yolo Never ask for permission
Examples:
- rho exec "analyze this codebase"
- rho exec --auto full "fix the tests and commit"
- rho exec --json "what files are in src/"
- rho exec --ephemeral --json "run tests and report" > result.json
- echo "explain main.go" | rho exec -
- rho exec --agent reviewer "review the latest commit"
- rho exec --model claude-sonnet-4-6 "quick fix: typo in README"`,
+ decoder exec "analyze this codebase"
+ decoder exec --auto full "fix the tests and commit"
+ decoder exec --json "what files are in src/"
+ decoder exec --ephemeral --json "run tests and report" > result.json
+ echo "explain main.go" | decoder exec -
+ decoder exec --agent reviewer "review the latest commit"
+ decoder exec --model claude-sonnet-4-6 "quick fix: typo in README"`,
Args: cobra.MaximumNArgs(1),
RunE: runExec,
}
@@ -111,7 +111,7 @@ func init() {
execCmd.Flags().StringVarP(&execModel, "model", "m", "", "Model ID to use")
execCmd.Flags().IntVar(&execMaxTurns, "max-turns", 0, "Maximum agentic turns (0 = unlimited)")
execCmd.Flags().StringVar(&execCWD, "cwd", "", "Working directory")
- execCmd.Flags().StringVar(&execAgent, "agent", "", "Agent persona to use (from Rho user state)")
+ execCmd.Flags().StringVar(&execAgent, "agent", "", "Agent persona to use (from Decoder user state)")
execCmd.Flags().StringVarP(&execSessionID, "session-id", "s", "", "Continue an existing session")
execCmd.Flags().StringVar(&execTag, "tag", "", "Session tag for categorization")
execCmd.Flags().BoolVarP(&execWorktree, "worktree", "w", false, "Run in an isolated git worktree")
@@ -177,7 +177,7 @@ func runExec(_ *cobra.Command, args []string) error {
base := getCurrentBranch(cwd)
branch := execWorktreeName
if branch == "" {
- branch = fmt.Sprintf("rho-exec/%d-%s", start.UnixMilli(), randomHex(4))
+ branch = fmt.Sprintf("decoder-exec/%d-%s", start.UnixMilli(), randomHex(4))
}
var wtErr error
wtPath, wtErr = createExecWorktree(cwd, base, branch)
@@ -192,7 +192,7 @@ func runExec(_ *cobra.Command, args []string) error {
}
// Load settings
- settings := rhoconfig.LoadSettings()
+ settings := decoderconfig.LoadSettings()
// Build system prompt
systemPrompt, err := buildSystemPrompt()
@@ -228,7 +228,7 @@ func runExec(_ *cobra.Command, args []string) error {
}
// Create engine session
- sess, cfgErr := newConfiguredRhoSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry, logger.New(io.Discard, logger.Error), execMaxTurns)
+ sess, cfgErr := newConfiguredDecoderSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry, logger.New(io.Discard, logger.Error), execMaxTurns)
if cfgErr != nil {
return cfgErr
}
@@ -245,11 +245,11 @@ func runExec(_ *cobra.Command, args []string) error {
// GitHub Actions event (an outside contributor's issue/PR/comment body),
// clamp autonomy to read-only auto-approval so attacker-controlled text
// cannot drive writes or Bash. Maintainers can opt out with
- // RHO_GHA_TRUST_EVENT=1.
+ // DECODER_GHA_TRUST_EVENT=1.
if ghaCtx.Active && !ghaCtx.Trusted {
const ceiling = safety.AutonomyBasic
if sess.PermSvc().RuntimeState().Autonomy > ceiling {
- fmt.Fprintf(os.Stderr, "%s\n", auditTint(fmt.Sprintf("rho: untrusted GitHub event (author_association=%q); capping autonomy at %s", ghaCtx.AuthorAssociation, ceiling), warnAmber))
+ fmt.Fprintf(os.Stderr, "%s\n", auditTint(fmt.Sprintf("decoder: untrusted GitHub event (author_association=%q); capping autonomy at %s", ghaCtx.AuthorAssociation, ceiling), warnAmber))
sess.PermSvc().SetAutonomy(ceiling)
}
}
@@ -379,7 +379,7 @@ func runExec(_ *cobra.Command, args []string) error {
DeviceID: cfg.DeviceID,
ProjectID: cfg.ProjectID,
SessionID: sessionID,
- Capability: cloud.CapabilityRho,
+ Capability: cloud.CapabilityDecoder,
Model: effectiveModel,
InputTokens: totalIn,
OutputTokens: totalOut,
@@ -401,10 +401,10 @@ func runExec(_ *cobra.Command, args []string) error {
fmt.Println()
}
if !IsQuiet() {
- summary := fmt.Sprintf("rho: %d tokens in / %d out · %d turn(s) · %s · %s",
+ summary := fmt.Sprintf("decoder: %d tokens in / %d out · %d turn(s) · %s · %s",
totalIn, totalOut, turns, time.Since(start).Round(time.Millisecond), effectiveModel)
if cacheRead > 0 || cacheWrite > 0 {
- summary = fmt.Sprintf("rho: %d tokens in / %d out (cache %d read · %d write) · %d turn(s) · %s · %s",
+ summary = fmt.Sprintf("decoder: %d tokens in / %d out (cache %d read · %d write) · %d turn(s) · %s · %s",
totalIn, totalOut, cacheRead, cacheWrite, turns, time.Since(start).Round(time.Millisecond), effectiveModel)
}
fmt.Fprintf(os.Stderr, "%s\n", auditTint(summary, textMuted))
@@ -469,16 +469,16 @@ type GHAMode string
const (
// GHAModeNone means we are not running inside GitHub Actions.
GHAModeNone GHAMode = ""
- // GHAModeInteractive is used when a human mentioned @rho in a comment and
+ // GHAModeInteractive is used when a human mentioned @decoder in a comment and
// expects a conversational reply.
GHAModeInteractive GHAMode = "interactive"
- // GHAModeAutomation is used for label/issue triggers where rho should act
+ // GHAModeAutomation is used for label/issue triggers where decoder should act
// autonomously on the issue/PR body.
GHAModeAutomation GHAMode = "automation"
)
// ghMention is the trigger token that promotes an event to interactive mode.
-const ghMention = "@rho"
+const ghMention = "@decoder"
// ghTrustedAssociations are the GitHub author_association values that identify
// a repository insider. Everyone else (CONTRIBUTOR, FIRST_TIME_CONTRIBUTOR,
@@ -496,7 +496,7 @@ type GHAContext struct {
EventName string // GITHUB_EVENT_NAME
Mode GHAMode // resolved operating mode
Prompt string // event-derived prompt body
- Mention bool // whether an @rho mention was found in a comment
+ Mention bool // whether an @decoder mention was found in a comment
AuthorAssociation string // GitHub author_association of the triggering actor
Trusted bool // author is a repo insider (or explicitly trusted)
}
@@ -529,7 +529,7 @@ func detectGitHubActions(getenv func(string) string, readFile func(string) ([]by
// Trust signal: GitHub reports the actor's relationship to the repo.
// Only insiders are trusted to drive high-autonomy tool use; content
// from outside contributors is untrusted (prompt-injection surface).
- // RHO_GHA_TRUST_EVENT=1 lets a maintainer opt into trusting all events.
+ // DECODER_GHA_TRUST_EVENT=1 lets a maintainer opt into trusting all events.
ctx.AuthorAssociation = ghAuthorAssociation(payload)
ctx.Trusted = ghTrustedAssociations[strings.ToUpper(strings.TrimSpace(ctx.AuthorAssociation))] ||
ghTrustEventOverride(getenv)
@@ -557,7 +557,7 @@ func detectGitHubActions(getenv func(string) string, readFile func(string) ([]by
// ghTrustEventOverride reports whether the maintainer has opted into
// trusting GitHub Actions event content regardless of author association.
func ghTrustEventOverride(getenv func(string) string) bool {
- switch strings.ToLower(strings.TrimSpace(getenv("RHO_GHA_TRUST_EVENT"))) {
+ switch strings.ToLower(strings.TrimSpace(getenv("DECODER_GHA_TRUST_EVENT"))) {
case "1", "true", "yes", "on":
return true
default:
@@ -614,7 +614,7 @@ func ghIssueBody(payload map[string]interface{}) string {
return strings.TrimSpace(ghCommentBody(payload))
}
-// ghStripMention removes the leading @rho mention from a comment so the
+// ghStripMention removes the leading @decoder mention from a comment so the
// remaining text becomes the prompt.
func ghStripMention(body string) string {
out := body
@@ -636,7 +636,7 @@ type skillRunner interface {
Run(name string) (string, error)
}
-// pluginSkillRunner is the production skillRunner backed by Rho skill storage.
+// pluginSkillRunner is the production skillRunner backed by Decoder skill storage.
type pluginSkillRunner struct{}
func (pluginSkillRunner) Run(name string) (string, error) {
@@ -646,7 +646,7 @@ func (pluginSkillRunner) Run(name string) (string, error) {
return fmt.Sprintf("[Skill: %s]\n\n%s", s.Name, s.Content), nil
}
}
- return "", fmt.Errorf("skill %q not found (run `rho skills` to list available skills)", name)
+ return "", fmt.Errorf("skill %q not found (run `decoder skills` to list available skills)", name)
}
// defaultSkillRunner is overridable in tests.
@@ -775,7 +775,7 @@ func runExecFanout(prompt string, n int) error {
fmt.Fprintf(os.Stderr, "\n%s\n", auditTint(fmt.Sprintf("=== fanout attempt %d/%d ===", i, n), infoSky))
att := fanoutAttempt{Attempt: i}
- branch := fmt.Sprintf("rho-exec/%d-fanout%d-%s", start.UnixMilli(), i, randomHex(4))
+ branch := fmt.Sprintf("decoder-exec/%d-fanout%d-%s", start.UnixMilli(), i, randomHex(4))
wtPath, wtErr := createExecWorktree(cwd, base, branch)
if wtErr != nil {
att.Error = fmt.Sprintf("worktree: %v", wtErr)
@@ -844,7 +844,7 @@ func runExecFanout(prompt string, n int) error {
// best-effort and only when a channel is configured.
title := fmt.Sprintf("Fan-out finished: %d/%d attempts succeeded", countOK(attempts), n)
_ = notify.SendCompletion(notify.Completion{
- Title: title, Source: "rho exec --fanout", OK: anyOK, Body: fanoutSummaryLines(attempts),
+ Title: title, Source: "decoder exec --fanout", OK: anyOK, Body: fanoutSummaryLines(attempts),
})
if !anyOK {
@@ -908,7 +908,7 @@ func printFanoutReport(attempts []fanoutAttempt) {
// (expected to be the attempt's worktree) and returns the structured result.
// Stream events are captured rather than printed so N attempts do not interleave.
func execOnceInWorktree(prompt string, attemptIdx int) (*ExecResult, error) {
- settings := rhoconfig.LoadSettings()
+ settings := decoderconfig.LoadSettings()
systemPrompt, err := buildSystemPrompt()
if err != nil {
@@ -931,7 +931,7 @@ func execOnceInWorktree(prompt string, attemptIdx int) (*ExecResult, error) {
if err != nil {
return nil, err
}
- sess, cfgErr := newConfiguredRhoSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry, logger.New(io.Discard, logger.Error), execMaxTurns)
+ sess, cfgErr := newConfiguredDecoderSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry, logger.New(io.Discard, logger.Error), execMaxTurns)
if cfgErr != nil {
return nil, cfgErr
}
diff --git a/cmd/exec_test.go b/cmd/exec_test.go
index 59e24400d..94abe815e 100644
--- a/cmd/exec_test.go
+++ b/cmd/exec_test.go
@@ -7,7 +7,7 @@ import (
"path/filepath"
"testing"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/storage"
)
// --- Skill dispatch tests ---------------------------------------------------
@@ -134,7 +134,7 @@ func TestDetectGitHubActions_InteractiveMention(t *testing.T) {
"GITHUB_EVENT_NAME": "issue_comment",
"GITHUB_EVENT_PATH": "/tmp/event.json",
}
- payload := `{"comment":{"body":"@rho please fix the failing test"}}`
+ payload := `{"comment":{"body":"@decoder please fix the failing test"}}`
gha := detectGitHubActions(envFunc(env), fileFunc(payload))
if !gha.Active {
t.Fatal("expected Active=true")
@@ -156,7 +156,7 @@ func TestDetectGitHubActions_ReviewCommentMention(t *testing.T) {
"GITHUB_EVENT_NAME": "pull_request_review_comment",
"GITHUB_EVENT_PATH": "/tmp/event.json",
}
- payload := `{"comment":{"body":"@Rho explain this change"}}`
+ payload := `{"comment":{"body":"@Decoder explain this change"}}`
gha := detectGitHubActions(envFunc(env), fileFunc(payload))
if gha.Mode != GHAModeInteractive {
t.Errorf("expected interactive mode for review comment, got %q", gha.Mode)
@@ -223,14 +223,14 @@ func TestDetectGitHubActions_TrustFromAssociation(t *testing.T) {
func TestDetectGitHubActions_TrustEnvOverride(t *testing.T) {
env := map[string]string{
- "GITHUB_ACTIONS": "true",
- "GITHUB_EVENT_NAME": "issues",
- "GITHUB_EVENT_PATH": "/tmp/event.json",
- "RHO_GHA_TRUST_EVENT": "1",
+ "GITHUB_ACTIONS": "true",
+ "GITHUB_EVENT_NAME": "issues",
+ "GITHUB_EVENT_PATH": "/tmp/event.json",
+ "DECODER_GHA_TRUST_EVENT": "1",
}
outsider := `{"issue":{"title":"t","body":"b","author_association":"NONE"}}`
if gha := detectGitHubActions(envFunc(env), fileFunc(outsider)); !gha.Trusted {
- t.Error("RHO_GHA_TRUST_EVENT=1 should trust even NONE association")
+ t.Error("DECODER_GHA_TRUST_EVENT=1 should trust even NONE association")
}
}
@@ -254,7 +254,7 @@ func TestResolveExecPrompt_Empty(t *testing.T) {
func TestPersistExecSession(t *testing.T) {
// Set up temp session dir
dir := t.TempDir()
- t.Setenv("RHO_STATE_DIR", filepath.Join(dir, "state"))
+ t.Setenv("DECODER_STATE_DIR", filepath.Join(dir, "state"))
persistExecSession("test-123", "claude-opus", "anthropic", "hello", "world")
@@ -276,7 +276,7 @@ func TestExecResult_JSON(t *testing.T) {
Duration: "1.5s",
Model: "test-model",
Worktree: "/tmp/wt",
- Branch: "rho-exec/123",
+ Branch: "decoder-exec/123",
}
data, err := json.Marshal(r)
if err != nil {
@@ -292,7 +292,7 @@ func TestExecResult_JSON(t *testing.T) {
if decoded.Worktree != "/tmp/wt" {
t.Errorf("expected worktree path, got %s", decoded.Worktree)
}
- if decoded.Branch != "rho-exec/123" {
+ if decoded.Branch != "decoder-exec/123" {
t.Errorf("expected branch, got %s", decoded.Branch)
}
}
diff --git a/cmd/execution_graph.go b/cmd/execution_graph.go
index 58d8fa5fd..2766a1ea8 100644
--- a/cmd/execution_graph.go
+++ b/cmd/execution_graph.go
@@ -9,14 +9,14 @@ import (
"strings"
"time"
- graphcontracts "github.com/GrayCodeAI/rho/internal/contracts/graph"
- policycontracts "github.com/GrayCodeAI/rho/internal/contracts/policy"
- "github.com/GrayCodeAI/rho/internal/executiongraph"
- "github.com/GrayCodeAI/rho/internal/fsutil"
- "github.com/GrayCodeAI/rho/internal/graphjournal"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/taskruntime"
- "github.com/GrayCodeAI/rho/internal/tool"
+ graphcontracts "github.com/GrayCodeAI/decoder/internal/contracts/graph"
+ policycontracts "github.com/GrayCodeAI/decoder/internal/contracts/policy"
+ "github.com/GrayCodeAI/decoder/internal/executiongraph"
+ "github.com/GrayCodeAI/decoder/internal/fsutil"
+ "github.com/GrayCodeAI/decoder/internal/graphjournal"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/taskruntime"
+ "github.com/GrayCodeAI/decoder/internal/tool"
"github.com/spf13/cobra"
)
@@ -24,7 +24,7 @@ func newExecutionGraphCmd() *cobra.Command {
graphCmd := &cobra.Command{
Use: "graph",
Short: "Export a portable execution graph",
- Long: `Project Rho-owned sessions, task requests, structured tasks, runtime tasks,
+ Long: `Project Decoder-owned sessions, task requests, structured tasks, runtime tasks,
tool calls, policy observations, verification results, and explicit checkpoint
links into the shared graph contract.
@@ -38,7 +38,7 @@ truth for scheduling, tools, policy, verification, persistence, and tracing.`,
var missionDir string
exportCmd := &cobra.Command{
Use: "export [session-id]",
- Short: "Export a Rho session or mission as graph JSON",
+ Short: "Export a Decoder session or mission as graph JSON",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
var export executiongraph.Export
@@ -280,12 +280,12 @@ func loadRuntimeGraphObservations(
for _, entry := range entries {
subject := graphcontracts.Ref{
Kind: graphcontracts.NodeExecution,
- ID: "rho/session/" + saved.ID,
+ ID: "decoder/session/" + saved.ID,
}
if _, ok := toolCallIDs[entry.ToolCallID]; ok && entry.ToolCallID != "" {
subject = graphcontracts.Ref{
Kind: graphcontracts.NodeExecution,
- ID: "rho/tool-call/" + saved.ID + "/" + entry.ToolCallID,
+ ID: "decoder/tool-call/" + saved.ID + "/" + entry.ToolCallID,
}
}
if entry.Policy != nil {
diff --git a/cmd/execution_graph_test.go b/cmd/execution_graph_test.go
index 4c5cee66a..c1367836b 100644
--- a/cmd/execution_graph_test.go
+++ b/cmd/execution_graph_test.go
@@ -9,11 +9,11 @@ import (
"testing"
"time"
- graphcontracts "github.com/GrayCodeAI/rho/internal/contracts/graph"
- policycontracts "github.com/GrayCodeAI/rho/internal/contracts/policy"
- "github.com/GrayCodeAI/rho/internal/executiongraph"
- "github.com/GrayCodeAI/rho/internal/graphjournal"
- "github.com/GrayCodeAI/rho/internal/session"
+ graphcontracts "github.com/GrayCodeAI/decoder/internal/contracts/graph"
+ policycontracts "github.com/GrayCodeAI/decoder/internal/contracts/policy"
+ "github.com/GrayCodeAI/decoder/internal/executiongraph"
+ "github.com/GrayCodeAI/decoder/internal/graphjournal"
+ "github.com/GrayCodeAI/decoder/internal/session"
)
func TestExecutionGraphCommandIsVisible(t *testing.T) {
@@ -32,18 +32,18 @@ func TestLoadMissionGraphExportValidatesTopology(t *testing.T) {
t.Parallel()
now := time.Date(2026, time.July, 25, 7, 0, 0, 0, time.UTC)
- mission := graphcontracts.Ref{Kind: graphcontracts.NodeExecution, ID: "rho/mission/m1"}
+ mission := graphcontracts.Ref{Kind: graphcontracts.NodeExecution, ID: "decoder/mission/m1"}
export := executiongraph.Export{
SchemaVersion: executiongraph.SchemaVersion,
GeneratedAt: now,
Nodes: []graphcontracts.Node{{
ID: mission.ID, Kind: mission.Kind, CreatedAt: now,
- Provenance: graphcontracts.Provenance{Producer: "rho"},
+ Provenance: graphcontracts.Provenance{Producer: "decoder"},
}},
Events: []graphcontracts.Event{{
- ID: "rho/event/mission/m1/created", Type: graphcontracts.EventCreated,
+ ID: "decoder/event/mission/m1/created", Type: graphcontracts.EventCreated,
Subject: mission, OccurredAt: now,
- Provenance: graphcontracts.Provenance{Producer: "rho"},
+ Provenance: graphcontracts.Provenance{Producer: "decoder"},
}},
}
dir := t.TempDir()
@@ -62,7 +62,7 @@ func TestLoadMissionGraphExportValidatesTopology(t *testing.T) {
t.Fatalf("loaded graph = %#v", loaded)
}
- export.Events[0].Subject.ID = "rho/mission/missing"
+ export.Events[0].Subject.ID = "decoder/mission/missing"
data, _ = json.Marshal(export)
if err := os.WriteFile(filepath.Join(dir, "mission-graph.json"), data, 0o600); err != nil {
t.Fatalf("rewrite graph: %v", err)
@@ -75,11 +75,11 @@ func TestLoadMissionGraphExportValidatesTopology(t *testing.T) {
func TestExecutionGraphRepositoryID(t *testing.T) {
t.Parallel()
- if got := executionGraphRepositoryID("custom", "/work/rho"); got != "custom" {
+ if got := executionGraphRepositoryID("custom", "/work/decoder"); got != "custom" {
t.Fatalf("override repository ID = %q, want custom", got)
}
- if got := executionGraphRepositoryID("", "/work/rho"); got != "rho" {
- t.Fatalf("derived repository ID = %q, want rho", got)
+ if got := executionGraphRepositoryID("", "/work/decoder"); got != "decoder" {
+ t.Fatalf("derived repository ID = %q, want decoder", got)
}
}
@@ -97,11 +97,11 @@ func TestValidateSwiftCheckpointID(t *testing.T) {
}
func TestExecutionGraphExportCommand(t *testing.T) {
- t.Setenv("RHO_STATE_DIR", t.TempDir())
+ t.Setenv("DECODER_STATE_DIR", t.TempDir())
saved := &session.Session{
ID: "graph-command-session",
- CWD: "/workspace/rho",
+ CWD: "/workspace/decoder",
CreatedAt: time.Date(2026, time.July, 25, 4, 0, 0, 0, time.UTC),
Messages: []session.Message{{
Role: "user",
@@ -209,8 +209,8 @@ func TestExecutionGraphExportCommand(t *testing.T) {
if export.SchemaVersion != executiongraph.SchemaVersion {
t.Fatalf("SchemaVersion = %q, want %q", export.SchemaVersion, executiongraph.SchemaVersion)
}
- if export.Scope.RepositoryID != "rho" {
- t.Fatalf("Scope.RepositoryID = %q, want rho", export.Scope.RepositoryID)
+ if export.Scope.RepositoryID != "decoder" {
+ t.Fatalf("Scope.RepositoryID = %q, want decoder", export.Scope.RepositoryID)
}
if output.String() == "" {
t.Fatal("graph export command produced no output")
@@ -224,10 +224,10 @@ func TestExecutionGraphExportCommand(t *testing.T) {
t.Fatalf("graph export command leaked %q", secret)
}
}
- if !hasExportNodePrefix(export, "rho/policy/") {
+ if !hasExportNodePrefix(export, "decoder/policy/") {
t.Fatal("graph export omitted automatic policy observation")
}
- if !hasExportNodePrefix(export, "rho/verification/") {
+ if !hasExportNodePrefix(export, "decoder/verification/") {
t.Fatal("graph export omitted automatic verification observation")
}
if !hasExportNodePrefix(export, "memory/") {
diff --git a/cmd/features.go b/cmd/features.go
index 9941d7c5c..9a982e323 100644
--- a/cmd/features.go
+++ b/cmd/features.go
@@ -6,7 +6,7 @@ import (
"sort"
"strings"
- feature "github.com/GrayCodeAI/rho/internal/features"
+ feature "github.com/GrayCodeAI/decoder/internal/features"
"github.com/spf13/cobra"
)
@@ -21,14 +21,14 @@ capabilities without code changes or restarts (some changes may require
a daemon restart).
Override a flag via environment variable:
- RHO_FEATURE_=1 rho daemon start
+ DECODER_FEATURE_=1 decoder daemon start
Show a specific flag:
- rho features get `,
+ decoder features get `,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 && args[0] == "get" {
if len(args) < 2 {
- return fmt.Errorf("usage: rho features get ")
+ return fmt.Errorf("usage: decoder features get ")
}
f, ok := feature.Info(args[1])
if !ok {
@@ -38,7 +38,7 @@ Show a specific flag:
fmt.Printf("%s\n", auditTint("Default: ", textMuted)+auditTint(fmt.Sprintf("%v", f.DefaultValue()), textPrimary))
fmt.Printf("%s\n", auditTint("Current: ", textMuted)+auditTint(fmt.Sprintf("%v", feature.EnabledByName(args[1])), textPrimary))
fmt.Printf("%s\n", auditTint("Description: ", textMuted)+auditTint(f.Description(), textPrimary))
- envVar := "RHO_FEATURE_" + strings.ReplaceAll(strings.ToUpper(args[1]), "-", "_")
+ envVar := "DECODER_FEATURE_" + strings.ReplaceAll(strings.ToUpper(args[1]), "-", "_")
fmt.Printf("%s\n", auditTint("Env var: ", textMuted)+auditTint(envVar, textPrimary))
return nil
}
@@ -50,7 +50,7 @@ Show a specific flag:
}
sort.Strings(names)
- fmt.Println(auditTint("Feature Flags:", rhoColor))
+ fmt.Println(auditTint("Feature Flags:", decoderColor))
fmt.Println()
for _, name := range names {
f, _ := feature.Info(name)
@@ -65,7 +65,7 @@ Show a specific flag:
if f != nil {
fmt.Printf("%s\n", auditTint(fmt.Sprintf(" default: %v", f.DefaultValue()), textMuted))
fmt.Printf("%s\n", auditTint(" description: "+f.Description(), textMuted))
- envVar := "RHO_FEATURE_" + strings.ReplaceAll(strings.ToUpper(name), "-", "_")
+ envVar := "DECODER_FEATURE_" + strings.ReplaceAll(strings.ToUpper(name), "-", "_")
fmt.Printf("%s\n", auditTint(" env: "+envVar, textMuted))
}
fmt.Println()
diff --git a/cmd/feedback.go b/cmd/feedback.go
index 7a4ea11d9..5703b2441 100644
--- a/cmd/feedback.go
+++ b/cmd/feedback.go
@@ -12,7 +12,7 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/storage"
"github.com/spf13/cobra"
)
@@ -37,17 +37,17 @@ type FeedbackReport struct {
var feedbackCmd = &cobra.Command{
Use: "feedback [message]",
- Short: "Submit feedback about rho",
- Long: `Capture feedback about your rho experience. By default, opens a
+ Short: "Submit feedback about decoder",
+ Long: `Capture feedback about your decoder experience. By default, opens a
GitHub issue template URL in your browser. Use --local to save feedback
-to Rho's user state directory for later submission.
+to Decoder's user state directory for later submission.
Categories: bug, feature, ux, performance, other
Examples:
- rho feedback "The completion is slow"
- rho feedback --category bug "Crash when using /compact"
- rho feedback --local "Wish it could do X"`,
+ decoder feedback "The completion is slow"
+ decoder feedback --category bug "Crash when using /compact"
+ decoder feedback --local "Wish it could do X"`,
Args: cobra.MinimumNArgs(0),
RunE: runFeedback,
}
@@ -141,7 +141,7 @@ func openFeedbackIssue(report FeedbackReport) error {
bodyBuilder.WriteString(fmt.Sprintf("- **Timestamp:** %s\n", report.Timestamp))
issueURL := fmt.Sprintf(
- "https://github.com/GrayCodeAI/rho/issues/new?title=%s&body=%s&labels=%s",
+ "https://github.com/GrayCodeAI/decoder/issues/new?title=%s&body=%s&labels=%s",
url.QueryEscape(title),
url.QueryEscape(bodyBuilder.String()),
url.QueryEscape(report.Category),
diff --git a/cmd/fingerprint.go b/cmd/fingerprint.go
index 25432e2b0..85a2aba01 100644
--- a/cmd/fingerprint.go
+++ b/cmd/fingerprint.go
@@ -5,7 +5,7 @@ import (
"fmt"
"os"
- "github.com/GrayCodeAI/rho/internal/features/fingerprint"
+ "github.com/GrayCodeAI/decoder/internal/features/fingerprint"
"github.com/spf13/cobra"
)
@@ -19,10 +19,10 @@ including detected languages, dependency counts, CI presence, license,
and git metadata.
Examples:
- rho fingerprint
- rho fingerprint ./myproject
- rho fingerprint --format json .
- rho fingerprint --format markdown /path/to/repo`,
+ decoder fingerprint
+ decoder fingerprint ./myproject
+ decoder fingerprint --format json .
+ decoder fingerprint --format markdown /path/to/repo`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
dir := "."
diff --git a/cmd/folder_trust_prompt.go b/cmd/folder_trust_prompt.go
index f23f0a848..2a7141675 100644
--- a/cmd/folder_trust_prompt.go
+++ b/cmd/folder_trust_prompt.go
@@ -7,7 +7,7 @@ import (
"os"
"strings"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
"golang.org/x/term"
)
diff --git a/cmd/folder_trust_prompt_test.go b/cmd/folder_trust_prompt_test.go
index d4df11eff..2aeb76c99 100644
--- a/cmd/folder_trust_prompt_test.go
+++ b/cmd/folder_trust_prompt_test.go
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
func TestPromptForInteractiveFolderTrustAccepts(t *testing.T) {
diff --git a/cmd/footer_layout_clip_test.go b/cmd/footer_layout_clip_test.go
index 940851274..43c14427d 100644
--- a/cmd/footer_layout_clip_test.go
+++ b/cmd/footer_layout_clip_test.go
@@ -9,7 +9,7 @@ import (
func TestLayoutFooterRow_TokensSurviveFinishFooterLine(t *testing.T) {
m := chatModel{width: 70, height: 24}
- left := lipgloss.NewStyle().Foreground(statusCWDColor).Inline(true).Render("~/OSS2026/RealWork/graycode-eco/rho")
+ left := lipgloss.NewStyle().Foreground(statusCWDColor).Inline(true).Render("~/OSS2026/RealWork/graycode-eco/decoder")
left += " " + lipgloss.NewStyle().Foreground(statusBranchColor).Inline(true).Render("⎇ main")
right := lipgloss.NewStyle().Foreground(statusTokenColor).Inline(true).Render("[db] 13k")
right += lipgloss.NewStyle().Foreground(dimColor).Inline(true).Render(" · ")
@@ -42,7 +42,7 @@ func TestLayoutFooterRow_LeftWiderThanFooterStillShowsTokens(t *testing.T) {
func TestLayoutFooterRow_ClipDoesNotDropStyledTokens(t *testing.T) {
m := chatModel{width: 55, height: 24}
- left := lipgloss.NewStyle().Foreground(statusCWDColor).Inline(true).Render("~/Desktop/OSS2026/RealWork/graycode-eco/rho")
+ left := lipgloss.NewStyle().Foreground(statusCWDColor).Inline(true).Render("~/Desktop/OSS2026/RealWork/graycode-eco/decoder")
left += " " + lipgloss.NewStyle().Foreground(statusBranchColor).Inline(true).Render("⎇ feature/footer-fix")
dim := lipgloss.NewStyle().Foreground(dimColor).Inline(true)
tok := lipgloss.NewStyle().Foreground(statusTokenColor).Inline(true)
diff --git a/cmd/footer_layout_width_test.go b/cmd/footer_layout_width_test.go
index eb169e04a..98f7a87dd 100644
--- a/cmd/footer_layout_width_test.go
+++ b/cmd/footer_layout_width_test.go
@@ -13,7 +13,7 @@ func TestLayoutFooterRow_StyledStringsAlignRight(t *testing.T) {
tokenStyle := lipgloss.NewStyle().Foreground(statusTokenColor).Inline(true)
dim := lipgloss.NewStyle().Foreground(dimColor).Inline(true)
- left := cwdStyle.Render("~/rho") + " " + cwdStyle.Render("⎇ main")
+ left := cwdStyle.Render("~/decoder") + " " + cwdStyle.Render("⎇ main")
right := tokenStyle.Render("[db] 13k") + dim.Render(" · ") + tokenStyle.Render("$0.00")
width := 80
diff --git a/cmd/formatter.go b/cmd/formatter.go
index 25a6b6cb8..168c777ed 100644
--- a/cmd/formatter.go
+++ b/cmd/formatter.go
@@ -9,12 +9,12 @@ import (
"golang.org/x/term"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// stdoutIsTerminal reports whether stdout is connected to a terminal (TTY).
// When stdout is a pipe or file — which is exactly the case when an agent or
-// shell script captures rho's output — this is false, and color/Unicode
+// shell script captures decoder's output — this is false, and color/Unicode
// chrome must be suppressed so the payload stays clean. It is a var so tests
// can override it.
var stdoutIsTerminal = func() bool {
diff --git a/cmd/formatter_test.go b/cmd/formatter_test.go
index 11a688759..d98ee1714 100644
--- a/cmd/formatter_test.go
+++ b/cmd/formatter_test.go
@@ -6,7 +6,7 @@ import (
"testing"
"time"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func TestDetectColorSupport_NonTTYStdout(t *testing.T) {
diff --git a/cmd/golden_test.go b/cmd/golden_test.go
index 974308102..b1609b054 100644
--- a/cmd/golden_test.go
+++ b/cmd/golden_test.go
@@ -59,8 +59,8 @@ func TestGoldenHelp(t *testing.T) {
t.Fatalf("golden file %s not found (run with -update-golden to create): %v", golden, err)
}
- if !strings.Contains(got, "rho") {
- t.Error("help output should contain 'rho'")
+ if !strings.Contains(got, "decoder") {
+ t.Error("help output should contain 'decoder'")
}
if len(got) < 100 {
t.Error("help output seems too short")
diff --git a/cmd/governance_cmd.go b/cmd/governance_cmd.go
index 89462bf8a..957673965 100644
--- a/cmd/governance_cmd.go
+++ b/cmd/governance_cmd.go
@@ -6,7 +6,7 @@ import (
"sort"
"strings"
- "github.com/GrayCodeAI/rho/internal/governance"
+ "github.com/GrayCodeAI/decoder/internal/governance"
"github.com/spf13/cobra"
)
@@ -20,10 +20,10 @@ var governanceCmd = &cobra.Command{
per-session PROFILE (tightest-wins). Tools are permitted only when both
layers allow them.
- rho governance Show the managed policy status
- rho governance show Print the effective capability rows
- rho governance validate Validate a policy or profile document
- rho governance explain Evaluate a tool against the policy`,
+ decoder governance Show the managed policy status
+ decoder governance show Print the effective capability rows
+ decoder governance validate Validate a policy or profile document
+ decoder governance explain Evaluate a tool against the policy`,
RunE: func(cmd *cobra.Command, args []string) error {
return runGovernanceStatus(cmd)
},
diff --git a/cmd/harness.go b/cmd/harness.go
index ef31e6309..926438f13 100644
--- a/cmd/harness.go
+++ b/cmd/harness.go
@@ -7,7 +7,7 @@ import (
"os"
"path/filepath"
- "github.com/GrayCodeAI/rho/internal/harness"
+ "github.com/GrayCodeAI/decoder/internal/harness"
"github.com/spf13/cobra"
)
@@ -84,7 +84,7 @@ Use --fix to automatically repair missing AGENTS.md, skills, or spec directories
if fixErr != nil {
return fmt.Errorf("harness auto-fix failed: %w", fixErr)
}
- fmt.Printf("%s\n", auditTint("[FIX] Rho Harness Auto-Repair Results:", warnAmber))
+ fmt.Printf("%s\n", auditTint("[FIX] Decoder Harness Auto-Repair Results:", warnAmber))
for _, repair := range fixResult.RepairsPerformed {
fmt.Printf("%s\n", auditTint(" + "+repair, doneGreen))
}
@@ -95,7 +95,7 @@ Use --fix to automatically repair missing AGENTS.md, skills, or spec directories
outDir := harnessOutDir
if outDir == "" {
- outDir = filepath.Join(targetDir, ".rho", "harness")
+ outDir = filepath.Join(targetDir, ".decoder", "harness")
}
if mkdirErr := os.MkdirAll(outDir, 0o750); mkdirErr != nil {
@@ -132,11 +132,11 @@ Use --fix to automatically repair missing AGENTS.md, skills, or spec directories
return fmt.Errorf("failed to write findings.json: %w", writeErr)
}
- // Journal quality observation to Rho execution graph
+ // Journal quality observation to Decoder execution graph
_ = harness.JournalHarnessReport(report, "")
finish()
- fmt.Printf("%s\n", auditTint("[RHO] Rho Harness Evaluation Complete", rhoColor))
+ fmt.Printf("%s\n", auditTint("[DECODER] Decoder Harness Evaluation Complete", decoderColor))
fmt.Printf(" %s : %s (%s)\n",
auditTint("Overall Score", textPrimary),
auditTint(fmt.Sprintf("%d/100", report.OverallScore), textPrimary),
@@ -151,7 +151,7 @@ Use --fix to automatically repair missing AGENTS.md, skills, or spec directories
}
func init() {
- harnessCmd.Flags().StringVar(&harnessOutDir, "out-dir", "", "Directory to save harness reports (default: .rho/harness)")
+ harnessCmd.Flags().StringVar(&harnessOutDir, "out-dir", "", "Directory to save harness reports (default: .decoder/harness)")
harnessCmd.Flags().StringVar(&harnessFormat, "format", "all", "Report output format (html, markdown, json, all)")
harnessCmd.Flags().BoolVar(&harnessFix, "fix", false, "Automatically repair missing harness assets (AGENTS.md, skills, specs)")
}
diff --git a/cmd/help_template.go b/cmd/help_template.go
index f0436ecd8..e85d8a388 100644
--- a/cmd/help_template.go
+++ b/cmd/help_template.go
@@ -10,7 +10,7 @@ import (
// last column so coloring them (zero-width ANSI) cannot break alignment. All
// color honors ShouldColor() (NO_COLOR, --quiet, non-TTY) via auditTint.
func init() {
- cobra.AddTemplateFunc("gcHeader", func(s string) string { return auditTint(s, rhoColor) })
+ cobra.AddTemplateFunc("gcHeader", func(s string) string { return auditTint(s, decoderColor) })
cobra.AddTemplateFunc("gcCmd", func(s string) string { return auditTint(s, textPrimary) })
cobra.AddTemplateFunc("gcDesc", func(s string) string { return auditTint(s, textMuted) })
rootCmd.SetUsageTemplate(modernUsageTemplate)
diff --git a/cmd/history.go b/cmd/history.go
index b4c2d0099..19b308d48 100644
--- a/cmd/history.go
+++ b/cmd/history.go
@@ -1,6 +1,6 @@
package cmd
-import commandfeature "github.com/GrayCodeAI/rho/internal/features/commands"
+import commandfeature "github.com/GrayCodeAI/decoder/internal/features/commands"
// Compatibility wrappers keep the TUI and existing command tests independent
// of the feature package's storage implementation during migration.
diff --git a/cmd/history_test.go b/cmd/history_test.go
index d11dce66c..9dbd80810 100644
--- a/cmd/history_test.go
+++ b/cmd/history_test.go
@@ -5,7 +5,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/testutil"
+ "github.com/GrayCodeAI/decoder/internal/testutil"
)
func TestLoadInputHistory_Empty(t *testing.T) {
@@ -94,7 +94,7 @@ func TestAppendToHistory_EmptySkipped(t *testing.T) {
func TestHistoryFilePath(t *testing.T) {
stateDir := filepath.Join(t.TempDir(), "state")
- t.Setenv("RHO_STATE_DIR", stateDir)
+ t.Setenv("DECODER_STATE_DIR", stateDir)
expected := filepath.Join(stateDir, "history")
if got := historyFilePath(); got != expected {
t.Fatalf("got %q, want %q", got, expected)
diff --git a/cmd/hud_panel.go b/cmd/hud_panel.go
index 535536af0..edc2b96fa 100644
--- a/cmd/hud_panel.go
+++ b/cmd/hud_panel.go
@@ -6,7 +6,7 @@ import (
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// HUDData is a snapshot of agent/mission/memory state rendered by the HUD panel.
diff --git a/cmd/image.go b/cmd/image.go
index 25af02708..3215206ed 100644
--- a/cmd/image.go
+++ b/cmd/image.go
@@ -13,8 +13,8 @@ import (
"regexp"
"strings"
- "github.com/GrayCodeAI/rho/internal/tui"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/tui"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// ImageAttachment represents an image ready to be attached to a message.
@@ -188,7 +188,7 @@ func IsPDFFile(path string) bool {
// ReadPDFText reads a PDF and extracts its text content using stdlib only.
//
-// flux does not expose a native document/PDF content block, so PDFs are
+// mux does not expose a native document/PDF content block, so PDFs are
// degraded to text and injected inline. This is a best-effort extractor: it
// inflates FlateDecode content streams and pulls text from PDF text-showing
// operators (Tj / TJ). It does not handle every PDF (encrypted, scanned-image,
diff --git a/cmd/input_indicator.go b/cmd/input_indicator.go
index e0bab78a0..115976366 100644
--- a/cmd/input_indicator.go
+++ b/cmd/input_indicator.go
@@ -3,8 +3,8 @@ package cmd
import (
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/features/shellmode"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/features/shellmode"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// InputClass represents the classification of user input.
@@ -31,7 +31,7 @@ func inputIndicatorAgentStyle() lipgloss.Style {
}
func inputIndicatorSlashStyle() lipgloss.Style {
- return lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
+ return lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
}
func inputIndicatorNeutralStyle() lipgloss.Style {
diff --git a/cmd/input_indicator_test.go b/cmd/input_indicator_test.go
index b84a78c7e..fa979bad1 100644
--- a/cmd/input_indicator_test.go
+++ b/cmd/input_indicator_test.go
@@ -3,7 +3,7 @@ package cmd
import (
"testing"
- "github.com/GrayCodeAI/rho/internal/features/shellmode"
+ "github.com/GrayCodeAI/decoder/internal/features/shellmode"
)
func TestInputIndicator_Classify(t *testing.T) {
diff --git a/cmd/issue.go b/cmd/issue.go
index 0d3d200b2..4b9a470ae 100644
--- a/cmd/issue.go
+++ b/cmd/issue.go
@@ -134,5 +134,5 @@ func generateIssueBody(ctx string) string {
if ctx == "" {
return "No additional context was provided."
}
- return "**Reported via rho**\n\n```\n" + ctx + "\n```\n"
+ return "**Reported via decoder**\n\n```\n" + ctx + "\n```\n"
}
diff --git a/cmd/learn_cmd.go b/cmd/learn_cmd.go
index 0663a8d2a..fd3d37f61 100644
--- a/cmd/learn_cmd.go
+++ b/cmd/learn_cmd.go
@@ -6,8 +6,8 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
"github.com/spf13/cobra"
)
@@ -25,13 +25,13 @@ var (
var learnCmd = &cobra.Command{
Use: "learn",
Short: "Manage lessons learned across sessions",
- Long: `Rho persists lessons from failures (and manual entries) so future
+ Long: `Decoder persists lessons from failures (and manual entries) so future
sessions avoid repeating them. Lessons are injected into the system prompt.
- rho learn List recent lessons
- rho learn add Add a lesson manually
- rho learn prompt Print the lesson-extraction prompt for a context
- rho learn clear Remove all lessons`,
+ decoder learn List recent lessons
+ decoder learn add Add a lesson manually
+ decoder learn prompt Print the lesson-extraction prompt for a context
+ decoder learn clear Remove all lessons`,
RunE: func(cmd *cobra.Command, args []string) error {
return runLearnList(cmd)
},
@@ -110,7 +110,7 @@ func runLearnList(cmd *cobra.Command) error {
si := engine.NewSelfImprover()
lessons := si.Lessons("")
if len(lessons) == 0 {
- cmd.Println(auditTint("No lessons yet. Add one with: rho learn add --what ... --lesson ...", textMuted))
+ cmd.Println(auditTint("No lessons yet. Add one with: decoder learn add --what ... --lesson ...", textMuted))
return nil
}
diff --git a/cmd/main_test.go b/cmd/main_test.go
index 9e0b493ae..70c009e26 100644
--- a/cmd/main_test.go
+++ b/cmd/main_test.go
@@ -4,8 +4,8 @@ import (
"os"
"testing"
- "github.com/GrayCodeAI/rho/internal/catalogtest"
- "github.com/GrayCodeAI/rho/internal/testutil"
+ "github.com/GrayCodeAI/decoder/internal/catalogtest"
+ "github.com/GrayCodeAI/decoder/internal/testutil"
)
func TestMain(m *testing.M) {
diff --git a/cmd/manpage.go b/cmd/manpage.go
index 731564772..8b33b0e27 100644
--- a/cmd/manpage.go
+++ b/cmd/manpage.go
@@ -12,7 +12,7 @@ import (
var manpageCmd = &cobra.Command{
Use: "manpage",
Short: "Generate man page in roff format",
- Long: "Generate a man page for rho in roff format and print it to stdout.\nRedirect to a file in your man path, e.g.: rho manpage > /usr/local/share/man/man1/rho.1",
+ Long: "Generate a man page for decoder in roff format and print it to stdout.\nRedirect to a file in your man path, e.g.: decoder manpage > /usr/local/share/man/man1/decoder.1",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
if _, err := fmt.Fprint(cmd.OutOrStdout(), GenerateManPage()); err != nil {
@@ -22,7 +22,7 @@ var manpageCmd = &cobra.Command{
},
}
-// GenerateManPage produces a man page in roff format for rho.
+// GenerateManPage produces a man page in roff format for decoder.
// The OPTIONS section is generated from the live Cobra flag set so it
// never drifts from the actual CLI surface.
func GenerateManPage() string {
@@ -35,20 +35,20 @@ func GenerateManPage() string {
var b strings.Builder
// Header
- b.WriteString(fmt.Sprintf(`.TH RHO 1 "%s" "%s" "User Commands"`, date, ver))
+ b.WriteString(fmt.Sprintf(`.TH DECODER 1 "%s" "%s" "User Commands"`, date, ver))
b.WriteString("\n")
// Name
- b.WriteString(".SH NAME\nrho \\- AI coding agent powered by flux\n")
+ b.WriteString(".SH NAME\ndecoder \\- AI coding agent powered by mux\n")
// Synopsis
b.WriteString(".SH SYNOPSIS\n")
- b.WriteString(".B rho\n[\\fIOPTIONS\\fR] [\\fIPROMPT\\fR]\n")
+ b.WriteString(".B decoder\n[\\fIOPTIONS\\fR] [\\fIPROMPT\\fR]\n")
// Description
b.WriteString(".SH DESCRIPTION\n")
- b.WriteString("rho is an AI coding agent that reads, writes, and runs code in your terminal.\n")
- fmt.Fprintf(&b, "It connects to %d first-class LLM providers through flux, executes tools (file I/O,\n", registeredProviderCount())
+ b.WriteString("decoder is an AI coding agent that reads, writes, and runs code in your terminal.\n")
+ fmt.Fprintf(&b, "It connects to %d first-class LLM providers through mux, executes tools (file I/O,\n", registeredProviderCount())
b.WriteString("shell, git, web search), and manages sessions from a keyboard-driven TUI\n")
b.WriteString("or headless mode for scripts and CI.\n")
@@ -81,7 +81,7 @@ func GenerateManPage() string {
if sub.Hidden {
continue
}
- b.WriteString(fmt.Sprintf(".TP\n\\fBrho %s\\fR\n%s\n", sub.Use, sub.Short))
+ b.WriteString(fmt.Sprintf(".TP\n\\fBdecoder %s\\fR\n%s\n", sub.Use, sub.Short))
}
// Slash Commands
@@ -99,7 +99,7 @@ func GenerateManPage() string {
{"/review", "Code review"},
{"/doctor", "Run diagnostics"},
{"/tools", "List enabled tools"},
- {"/quit", "Exit rho"},
+ {"/quit", "Exit decoder"},
}
for _, sc := range slashCmds {
b.WriteString(fmt.Sprintf(".TP\n\\fB%s\\fR\n%s\n", sc.cmd, sc.desc))
@@ -107,16 +107,16 @@ func GenerateManPage() string {
// Files
b.WriteString(".SH FILES\n")
- b.WriteString(".TP\n\\fBRho user config directory\\fR\nGlobal configuration files\n")
+ b.WriteString(".TP\n\\fBDecoder user config directory\\fR\nGlobal configuration files\n")
b.WriteString(".TP\n\\fBAGENTS.md\\fR\nProject instructions file\n")
- b.WriteString(".TP\n\\fBRho user state directory\\fR\nSaved session data, plans, skills, and runtime state\n")
+ b.WriteString(".TP\n\\fBDecoder user state directory\\fR\nSaved session data, plans, skills, and runtime state\n")
// Credentials
b.WriteString(".SH CREDENTIALS\n")
b.WriteString("API keys are stored in the OS secret service (macOS Keychain or Linux GNOME Keyring / KWallet).\n")
- b.WriteString("Use \\fBrho\\fR and \\fB/config\\fR to save keys; rho does not read API keys from .env files.\n")
- b.WriteString(".TP\n\\fBrho credentials status\\fR\nShow secure storage status\n")
- b.WriteString(".TP\n\\fBrho credentials remove \\fR\nRemove a stored API key from the OS secret store\n")
+ b.WriteString("Use \\fBdecoder\\fR and \\fB/config\\fR to save keys; decoder does not read API keys from .env files.\n")
+ b.WriteString(".TP\n\\fBdecoder credentials status\\fR\nShow secure storage status\n")
+ b.WriteString(".TP\n\\fBdecoder credentials remove \\fR\nRemove a stored API key from the OS secret store\n")
// Environment
b.WriteString(".SH ENVIRONMENT\n")
@@ -124,14 +124,14 @@ func GenerateManPage() string {
envVars := []struct{ env, desc string }{
{"OPENAI_MODEL", "Override default OpenAI model"},
{"OLLAMA_BASE_URL", "Ollama server URL (also saved via /config for Ollama)"},
- {"RHO_CONFIG_DIR", "Override rho config directory"},
+ {"DECODER_CONFIG_DIR", "Override decoder config directory"},
}
for _, ev := range envVars {
b.WriteString(fmt.Sprintf(".TP\n\\fB%s\\fR\n%s\n", ev.env, ev.desc))
}
// Authors
- b.WriteString(".SH AUTHORS\nGrayCode AI \n")
+ b.WriteString(".SH AUTHORS\nGrayCode AI \n")
return b.String()
}
diff --git a/cmd/manpage_test.go b/cmd/manpage_test.go
index 0174c5185..99f24927d 100644
--- a/cmd/manpage_test.go
+++ b/cmd/manpage_test.go
@@ -26,7 +26,7 @@ func TestGenerateManPage(t *testing.T) {
version = "1.0.0"
page := GenerateManPage()
- if !strings.Contains(page, ".TH RHO 1") {
+ if !strings.Contains(page, ".TH DECODER 1") {
t.Fatal("missing .TH header")
}
if !strings.Contains(page, "1.0.0") {
diff --git a/cmd/markdown.go b/cmd/markdown.go
index 91c7fabd2..77563a1b7 100644
--- a/cmd/markdown.go
+++ b/cmd/markdown.go
@@ -25,12 +25,12 @@ import (
// Markdown rendering styles using the project's purpose-named palette.
var (
- mdH1Style = lipgloss.NewStyle().Foreground(rhoColor).Bold(true).Underline(true)
+ mdH1Style = lipgloss.NewStyle().Foreground(decoderColor).Bold(true).Underline(true)
mdH2Style = lipgloss.NewStyle().Foreground(successTeal).Bold(true)
mdH3Style = lipgloss.NewStyle().Foreground(infoSky).Bold(true)
mdH4Style = lipgloss.NewStyle().Foreground(costViolet).Bold(true)
mdHeaderStyle = lipgloss.NewStyle().Foreground(textPrimary).Bold(true)
- mdBoldStyle = lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
+ mdBoldStyle = lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
mdItalicStyle = lipgloss.NewStyle().Italic(true)
mdInlineCodeStyle = lipgloss.NewStyle().Foreground(infoSky)
mdCodeBlockStyle = lipgloss.NewStyle().Background(bgCode)
@@ -621,13 +621,13 @@ func protectInlineCode(text string, render func(string) string) (string, func(st
if len(parts) < 2 {
return m
}
- placeholder := fmt.Sprintf("\x00RHO_INLINE_CODE_%d\x00", len(replacements))
+ placeholder := fmt.Sprintf("\x00DECODER_INLINE_CODE_%d\x00", len(replacements))
replacements = append(replacements, render(parts[1]))
return placeholder
})
restore := func(s string) string {
for i, repl := range replacements {
- s = strings.ReplaceAll(s, fmt.Sprintf("\x00RHO_INLINE_CODE_%d\x00", i), repl)
+ s = strings.ReplaceAll(s, fmt.Sprintf("\x00DECODER_INLINE_CODE_%d\x00", i), repl)
}
return s
}
diff --git a/cmd/markdown_test.go b/cmd/markdown_test.go
index 9836b31a3..c69ca495f 100644
--- a/cmd/markdown_test.go
+++ b/cmd/markdown_test.go
@@ -196,10 +196,10 @@ func TestRenderMarkdownOrderedList(t *testing.T) {
}
func TestRenderMarkdownLinks(t *testing.T) {
- input := "Visit [Rho](https://example.com) for info"
+ input := "Visit [Decoder](https://example.com) for info"
out := renderMarkdown(input, 80)
plain := stripAnsi(out)
- if !strings.Contains(plain, "Rho") {
+ if !strings.Contains(plain, "Decoder") {
t.Errorf("expected link text in output, got %q", plain)
}
if !strings.Contains(plain, "https://example.com") {
diff --git a/cmd/mcp_serve.go b/cmd/mcp_serve.go
index 4598bc6bb..e04e98a15 100644
--- a/cmd/mcp_serve.go
+++ b/cmd/mcp_serve.go
@@ -6,8 +6,8 @@ import (
"os/signal"
"syscall"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/mcp"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/mcp"
"github.com/spf13/cobra"
)
@@ -20,28 +20,28 @@ func init() {
mcpCmd.AddCommand(mcpConfigCmd)
}
-// mcpServeCmd runs rho itself as an MCP server over stdio, exposing rho's
+// mcpServeCmd runs decoder itself as an MCP server over stdio, exposing decoder's
// capabilities (chat, search, memory, review, scan, compress) to MCP clients
// such as Claude Desktop, Cursor, and Windsurf.
var mcpServeCmd = &cobra.Command{
Use: "serve",
- Short: "Run rho as an MCP server over stdio",
- Long: "Run rho as a Model Context Protocol server over stdio (JSON-RPC 2.0), " +
- "exposing rho's tools to MCP clients like Claude Desktop, Cursor, and Windsurf.\n\n" +
- "Use `rho mcp config` to print the JSON block that registers this command in a client.",
+ Short: "Run decoder as an MCP server over stdio",
+ Long: "Run decoder as a Model Context Protocol server over stdio (JSON-RPC 2.0), " +
+ "exposing decoder's tools to MCP clients like Claude Desktop, Cursor, and Windsurf.\n\n" +
+ "Use `decoder mcp config` to print the JSON block that registers this command in a client.",
RunE: runMCPServe,
}
func runMCPServe(cmd *cobra.Command, _ []string) error {
- settings := rhoconfig.LoadSettings()
+ settings := decoderconfig.LoadSettings()
serverVersion := version
if serverVersion == "" {
serverVersion = "dev"
}
- server := mcp.NewMCPServer(mcp.ServerInfo{Name: "rho", Version: serverVersion})
+ server := mcp.NewMCPServer(mcp.ServerInfo{Name: "decoder", Version: serverVersion})
- // Wire rho's tool registry in as the executor so delegating tools run for
+ // Wire decoder's tool registry in as the executor so delegating tools run for
// real; a registry build failure degrades to not-configured rather than
// aborting (the server still answers initialize/tools/list).
registry, err := defaultRegistry(settings)
@@ -56,24 +56,24 @@ func runMCPServe(cmd *cobra.Command, _ []string) error {
return server.ServeStdio(ctx)
}
-// mcpConfigCmd emits the JSON block that registers rho as an MCP server in a
+// mcpConfigCmd emits the JSON block that registers decoder as an MCP server in a
// client's config file, so users don't hand-edit JSON.
var mcpConfigCmd = &cobra.Command{
Use: "config",
- Short: "Print the MCP-server config block to register rho in a client",
- Long: "Print the JSON block that registers rho as an MCP server (pointing at " +
- "`rho mcp serve`) for clients like Claude Desktop, Cursor, and Windsurf.\n\n" +
+ Short: "Print the MCP-server config block to register decoder in a client",
+ Long: "Print the JSON block that registers decoder as an MCP server (pointing at " +
+ "`decoder mcp serve`) for clients like Claude Desktop, Cursor, and Windsurf.\n\n" +
"Pipe it to the client's config file, e.g.:\n" +
- " rho mcp config >> ~/Library/Application Support/Claude/claude_desktop_config.json",
+ " decoder mcp config >> ~/Library/Application Support/Claude/claude_desktop_config.json",
RunE: runMCPConfig,
}
func runMCPConfig(cmd *cobra.Command, _ []string) error {
- exe := rhoExecutablePath()
+ exe := decoderExecutablePath()
block := map[string]any{
"mcpServers": map[string]any{
- "rho": map[string]any{
+ "decoder": map[string]any{
"command": exe,
"args": []string{"mcp", "serve"},
},
@@ -85,7 +85,7 @@ func runMCPConfig(cmd *cobra.Command, _ []string) error {
}
if mcpConfigWrite {
- cmd.Println("# Add the \"rho\" entry below into the \"mcpServers\" object of your client config:")
+ cmd.Println("# Add the \"decoder\" entry below into the \"mcpServers\" object of your client config:")
cmd.Println("# Claude Desktop (macOS): ~/Library/Application Support/Claude/claude_desktop_config.json")
cmd.Println("# Cursor: ~/.cursor/mcp.json")
cmd.Println("# Windsurf: ~/.codeium/windsurf/mcp_config.json")
@@ -95,12 +95,12 @@ func runMCPConfig(cmd *cobra.Command, _ []string) error {
return nil
}
-// rhoExecutablePath returns the absolute path to the running rho binary, or
-// the bare name "rho" if it cannot be resolved (e.g. during `go run`), so the
+// decoderExecutablePath returns the absolute path to the running decoder binary, or
+// the bare name "decoder" if it cannot be resolved (e.g. during `go run`), so the
// emitted config is still copy-pasteable.
-func rhoExecutablePath() string {
+func decoderExecutablePath() string {
if exe, err := os.Executable(); err == nil && exe != "" {
return exe
}
- return "rho"
+ return "decoder"
}
diff --git a/cmd/mcp_serve_test.go b/cmd/mcp_serve_test.go
index 82995e16f..391a87843 100644
--- a/cmd/mcp_serve_test.go
+++ b/cmd/mcp_serve_test.go
@@ -30,15 +30,15 @@ func TestMCPConfigEmitsValidServerBlock(t *testing.T) {
t.Fatalf("emitted config is not valid JSON: %v\n%s", err, buf.String())
}
- rho, ok := cfg.MCPServers["rho"]
+ decoder, ok := cfg.MCPServers["decoder"]
if !ok {
- t.Fatal(`config missing "rho" server entry`)
+ t.Fatal(`config missing "decoder" server entry`)
}
- if rho.Command == "" {
- t.Error("rho server entry missing command")
+ if decoder.Command == "" {
+ t.Error("decoder server entry missing command")
}
- if len(rho.Args) != 2 || rho.Args[0] != "mcp" || rho.Args[1] != "serve" {
- t.Errorf(`args = %v, want ["mcp" "serve"]`, rho.Args)
+ if len(decoder.Args) != 2 || decoder.Args[0] != "mcp" || decoder.Args[1] != "serve" {
+ t.Errorf(`args = %v, want ["mcp" "serve"]`, decoder.Args)
}
}
diff --git a/cmd/mentions.go b/cmd/mentions.go
index a9c3f76dc..71a54aec8 100644
--- a/cmd/mentions.go
+++ b/cmd/mentions.go
@@ -6,8 +6,8 @@ import (
"strings"
"unicode/utf8"
- "github.com/GrayCodeAI/rho/internal/mention"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/mention"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
// handleMentions processes @-prefixed file mentions in user input.
diff --git a/cmd/mentions_test.go b/cmd/mentions_test.go
index 377387475..add9240e7 100644
--- a/cmd/mentions_test.go
+++ b/cmd/mentions_test.go
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
func TestHandleMentions_BlocksSensitivePaths(t *testing.T) {
diff --git a/cmd/mission.go b/cmd/mission.go
index 72dde9131..434c301e8 100644
--- a/cmd/mission.go
+++ b/cmd/mission.go
@@ -9,13 +9,13 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- mission "github.com/GrayCodeAI/rho/internal/multiagent"
- "github.com/GrayCodeAI/rho/internal/observability/logger"
- "github.com/GrayCodeAI/rho/internal/tool"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ mission "github.com/GrayCodeAI/decoder/internal/multiagent"
+ "github.com/GrayCodeAI/decoder/internal/observability/logger"
+ "github.com/GrayCodeAI/decoder/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
"github.com/spf13/cobra"
)
@@ -36,10 +36,10 @@ Each feature runs in its own worktree with a full engine session.
Results are committed on separate branches for review/merge.
Examples:
- rho mission "Add auth, rate limiting, and logging to the API"
- rho mission --workers 6 "Refactor the database layer into 3 services"
- rho mission --model claude-sonnet-4-6 "Add tests for all untested packages"
- rho mission --from-tasks`,
+ decoder mission "Add auth, rate limiting, and logging to the API"
+ decoder mission --workers 6 "Refactor the database layer into 3 services"
+ decoder mission --model claude-sonnet-4-6 "Add tests for all untested packages"
+ decoder mission --from-tasks`,
Args: cobra.ArbitraryArgs,
RunE: runMission,
}
@@ -61,7 +61,7 @@ func runMission(_ *cobra.Command, args []string) error {
cwd, _ := os.Getwd()
baseBranch := getCurrentBranch(cwd)
- settings := rhoconfig.LoadSettings()
+ settings := decoderconfig.LoadSettings()
effectiveModel, effectiveProvider := effectiveModelAndProvider(settings)
if missionModel != "" {
effectiveModel = missionModel
@@ -79,7 +79,7 @@ func runMission(_ *cobra.Command, args []string) error {
m := mission.New(prompt, cfg)
// Clean up the mission's temp directory when the command finishes,
- // whether it succeeded or failed. Without this, /tmp/rho-missions/
+ // whether it succeeded or failed. Without this, /tmp/decoder-missions/
// accumulates one directory per run indefinitely (C6 fix).
defer func() { _ = m.Cleanup() }()
@@ -175,7 +175,7 @@ func runMission(_ *cobra.Command, args []string) error {
// Propagate feature failures as a non-zero exit so CI sees a real
// failure instead of green: Mission.Run historically returned nil even
- // when every feature failed (H9), so `rho mission` exited 0.
+ // when every feature failed (H9), so `decoder mission` exited 0.
failed := 0
for _, f := range m.Features {
if f.Status == mission.FeatureFailed {
@@ -189,7 +189,7 @@ func runMission(_ *cobra.Command, args []string) error {
return nil
}
-func planWithLLM(ctx context.Context, prompt, provider, model string, settings rhoconfig.Settings) ([]mission.Feature, error) {
+func planWithLLM(ctx context.Context, prompt, provider, model string, settings decoderconfig.Settings) ([]mission.Feature, error) {
planPrompt := fmt.Sprintf(
"Decompose this task into independent features that can be implemented in parallel.\n\n"+
"Task: %s\n\n"+
@@ -202,7 +202,7 @@ func planWithLLM(ctx context.Context, prompt, provider, model string, settings r
)
registry, _ := defaultRegistry(settings)
- sess, err := newConfiguredRhoSession(settings, provider, model, planPrompt, registry, logger.New(io.Discard, logger.Error))
+ sess, err := newConfiguredDecoderSession(settings, provider, model, planPrompt, registry, logger.New(io.Discard, logger.Error))
if err != nil {
return nil, err
}
diff --git a/cmd/mission_graph.go b/cmd/mission_graph.go
index 6b30c7918..5976dd089 100644
--- a/cmd/mission_graph.go
+++ b/cmd/mission_graph.go
@@ -6,8 +6,8 @@ import (
"strings"
"time"
- mission "github.com/GrayCodeAI/rho/internal/multiagent"
- "github.com/GrayCodeAI/rho/internal/tool"
+ mission "github.com/GrayCodeAI/decoder/internal/multiagent"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
var missionFromTasks bool
@@ -57,7 +57,7 @@ func missionFeaturesFromTasks(store *tool.TaskStore, missionID string) ([]missio
ID: task.ID,
Description: task.Subject,
ExpectedBehavior: expected,
- Branch: fmt.Sprintf("rho-mission/%s/%s", missionID, task.ID),
+ Branch: fmt.Sprintf("decoder-mission/%s/%s", missionID, task.ID),
Status: status,
})
}
diff --git a/cmd/mission_graph_test.go b/cmd/mission_graph_test.go
index 5df0550f7..4f6ee271a 100644
--- a/cmd/mission_graph_test.go
+++ b/cmd/mission_graph_test.go
@@ -3,8 +3,8 @@ package cmd
import (
"testing"
- mission "github.com/GrayCodeAI/rho/internal/multiagent"
- "github.com/GrayCodeAI/rho/internal/tool"
+ mission "github.com/GrayCodeAI/decoder/internal/multiagent"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
func TestMissionFeaturesFromTasks(t *testing.T) {
@@ -26,7 +26,7 @@ func TestMissionFeaturesFromTasks(t *testing.T) {
if len(waves) != 2 || len(waves[0]) != 1 || waves[0][0] != root.ID || waves[1][0] != child.ID {
t.Fatalf("waves = %#v", waves)
}
- if features[0].Branch != "rho-mission/mission123/"+root.ID {
+ if features[0].Branch != "decoder-mission/mission123/"+root.ID {
t.Fatalf("branch = %q", features[0].Branch)
}
if features[0].Status != mission.FeaturePending {
diff --git a/cmd/model_table.go b/cmd/model_table.go
index 242437a41..c86f7a56a 100644
--- a/cmd/model_table.go
+++ b/cmd/model_table.go
@@ -6,8 +6,8 @@ import (
"strings"
lipgloss "charm.land/lipgloss/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
"github.com/mattn/go-runewidth"
)
@@ -119,17 +119,17 @@ func modelTableRowFromOption(o configModelOption) modelTableRow {
}
func formatModelThinkingCell(o configModelOption) string {
- supports := rhoconfig.ModelCapabilitySupportsThinking(o.Capabilities)
- settings := rhoconfig.LoadSettings()
- pref := rhoconfig.ThinkingPrefForModel(settings, o.ID)
+ supports := decoderconfig.ModelCapabilitySupportsThinking(o.Capabilities)
+ settings := decoderconfig.LoadSettings()
+ pref := decoderconfig.ThinkingPrefForModel(settings, o.ID)
if pref == nil && o.CanonicalID != "" && o.CanonicalID != o.ID {
- pref = rhoconfig.ThinkingPrefForModel(settings, o.CanonicalID)
+ pref = decoderconfig.ThinkingPrefForModel(settings, o.CanonicalID)
}
provider := strings.TrimSpace(o.GatewayID)
if provider == "" {
provider = strings.TrimSpace(o.ProviderID)
}
- return rhoconfig.FormatModelThinkingLabel(supports, pref, provider)
+ return decoderconfig.FormatModelThinkingLabel(supports, pref, provider)
}
func formatModelCapabilities(capabilities []string) string {
@@ -370,7 +370,7 @@ func modelTableFooter(total, scroll, end, allTotal int, muted lipgloss.Style) st
return muted.Render(fmt.Sprintf("%s%s · t toggle thinking · enter to select", prefix, label))
}
-func modelTableRowFromCatalogEntry(m rhoconfig.EngineModel) modelTableRow {
+func modelTableRowFromCatalogEntry(m decoderconfig.EngineModel) modelTableRow {
name := strings.TrimSpace(m.DisplayName)
if name == "" {
name = m.ID
@@ -401,7 +401,7 @@ func modelTableRowFromCatalogEntry(m rhoconfig.EngineModel) modelTableRow {
Model: name,
Provider: owner,
Caps: formatModelCapabilities(m.Capabilities),
- Think: rhoconfig.FormatModelThinkingLabel(rhoconfig.ModelCapabilitySupportsThinking(m.Capabilities), rhoconfig.ThinkingPrefForModel(rhoconfig.LoadSettings(), m.ID), provider),
+ Think: decoderconfig.FormatModelThinkingLabel(decoderconfig.ModelCapabilitySupportsThinking(m.Capabilities), decoderconfig.ThinkingPrefForModel(decoderconfig.LoadSettings(), m.ID), provider),
Price: price,
Context: formatModelTableContext(m.ContextWindow),
Free: free,
diff --git a/cmd/model_table_test.go b/cmd/model_table_test.go
index 504a6c403..84e309cb7 100644
--- a/cmd/model_table_test.go
+++ b/cmd/model_table_test.go
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func TestFormatModelTablePrice(t *testing.T) {
@@ -67,7 +67,7 @@ func TestFormatModelCapabilities(t *testing.T) {
}
func TestFormatModelThinkingCell(t *testing.T) {
- // Isolate from the developer's real rho settings (per-model thinking
+ // Isolate from the developer's real decoder settings (per-model thinking
// preferences would otherwise change the asserted defaults).
t.Setenv("HOME", t.TempDir())
row := modelTableRowFromOption(configModelOption{
@@ -109,7 +109,7 @@ func TestModelTableOwnerFallback(t *testing.T) {
if option.Provider != "deployment" {
t.Fatalf("option provider = %q, want deployment", option.Provider)
}
- entry := modelTableRowFromCatalogEntry(rhoconfig.EngineModel{GatewayID: "gateway"})
+ entry := modelTableRowFromCatalogEntry(decoderconfig.EngineModel{GatewayID: "gateway"})
if entry.Provider != "gateway" {
t.Fatalf("entry provider = %q, want gateway", entry.Provider)
}
diff --git a/cmd/models.go b/cmd/models.go
index c21da469b..2ba68a949 100644
--- a/cmd/models.go
+++ b/cmd/models.go
@@ -7,7 +7,7 @@ import (
"strings"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
"github.com/spf13/cobra"
)
@@ -19,18 +19,18 @@ var (
var modelsCmd = &cobra.Command{
Use: "models",
- Short: "Deployment-aware model catalog (via flux)",
- Long: `Manage the flux model catalog used by rho for models, pricing, and deployment routing.
+ Short: "Deployment-aware model catalog (via mux)",
+ Long: `Manage the mux model catalog used by decoder for models, pricing, and deployment routing.
-The catalog is stored at ~/.flux/model_catalog.json (override with FLUX_MODEL_CATALOG_PATH).
-Rho refreshes the catalog automatically on startup when the cache is missing, empty, or stale (disable with --no-auto-catalog-refresh or RHO_AUTO_REFRESH_CATALOG=0).
-Use 'rho models refresh' for a manual refresh or full discover report.`,
+The catalog is stored at ~/.mux/model_catalog.json (override with MUX_MODEL_CATALOG_PATH).
+Decoder refreshes the catalog automatically on startup when the cache is missing, empty, or stale (disable with --no-auto-catalog-refresh or DECODER_AUTO_REFRESH_CATALOG=0).
+Use 'decoder models refresh' for a manual refresh or full discover report.`,
}
var modelsRefreshCmd = &cobra.Command{
Use: "refresh",
Aliases: []string{"update"},
- Short: "Discover model catalog (flux remote + live provider APIs) into ~/.flux/model_catalog.json",
+ Short: "Discover model catalog (mux remote + live provider APIs) into ~/.mux/model_catalog.json",
RunE: func(cmd *cobra.Command, _ []string) error {
settings, err := loadEffectiveSettings()
if err != nil {
@@ -41,7 +41,7 @@ var modelsRefreshCmd = &cobra.Command{
prog := NewCLIProgress("Models", []string{"Discovering catalog"})
defer prog.Abort()
prog.StartStep(0)
- summary, err := rhoconfig.RefreshModelCatalogV1WithSettings(ctx, settings)
+ summary, err := decoderconfig.RefreshModelCatalogV1WithSettings(ctx, settings)
if err != nil {
prog.FailStep(0, err.Error())
return err
@@ -62,13 +62,13 @@ var modelsStatusCmd = &cobra.Command{
if err != nil {
return err
}
- cmd.Println(rhoconfig.FormatCatalogHealth(rhoconfig.CatalogHealthReport(ctx)))
+ cmd.Println(decoderconfig.FormatCatalogHealth(decoderconfig.CatalogHealthReport(ctx)))
cmd.Println()
modelName, _ := effectiveModelAndProvider(settings)
if len(args) > 0 {
modelName = args[0]
}
- report, err := rhoconfig.DeploymentStatusReportWithSettings(ctx, settings, modelName)
+ report, err := decoderconfig.DeploymentStatusReportWithSettings(ctx, settings, modelName)
if err != nil {
return err
}
@@ -87,7 +87,7 @@ var modelsRoutingPreviewCmd = &cobra.Command{
return err
}
modelName := args[0]
- out, err := rhoconfig.RoutingPreviewJSONWithSettings(cmd.Context(), settings, modelName)
+ out, err := decoderconfig.RoutingPreviewJSONWithSettings(cmd.Context(), settings, modelName)
if err != nil {
return err
}
@@ -98,7 +98,7 @@ var modelsRoutingPreviewCmd = &cobra.Command{
var modelsListCmd = &cobra.Command{
Use: "list [provider]",
- Short: "List models from the flux catalog cache (or live provider API)",
+ Short: "List models from the mux catalog cache (or live provider API)",
RunE: func(cmd *cobra.Command, args []string) error {
settings, err := loadEffectiveSettings()
if err != nil {
@@ -109,7 +109,7 @@ var modelsListCmd = &cobra.Command{
providerName = args[0]
}
ctx := cmd.Context()
- var models []rhoconfig.EngineModel
+ var models []decoderconfig.EngineModel
// Only the live provider fetch is slow enough to animate, and only when
// the output is a human table (JSON/raw must stay pure).
animate := modelsListLive && !modelsListJSON && !modelsListRaw
@@ -121,11 +121,11 @@ var modelsListCmd = &cobra.Command{
}
if modelsListLive {
if providerName == "" {
- return fmt.Errorf("provider required with --live (e.g. rho models list canopywave --live --json)")
+ return fmt.Errorf("provider required with --live (e.g. decoder models list canopywave --live --json)")
}
- models, err = rhoconfig.ListLiveEngineModelsWithSettings(ctx, settings, rhoconfig.ActiveProviderID(providerName))
+ models, err = decoderconfig.ListLiveEngineModelsWithSettings(ctx, settings, decoderconfig.ActiveProviderID(providerName))
} else {
- models, err = rhoconfig.FetchModelsForProviderWithSettings(ctx, settings, providerName)
+ models, err = decoderconfig.FetchModelsForProviderWithSettings(ctx, settings, providerName)
}
if err != nil {
if prog != nil {
@@ -159,9 +159,9 @@ var modelsListCmd = &cobra.Command{
},
}
-// modelListJSONEntry is Rho's versioned command-output contract. Keep this
-// separate from Flux's host-facing Model DTO so engine-only fields can evolve
-// without breaking users that consume `rho models list --json`.
+// modelListJSONEntry is Decoder's versioned command-output contract. Keep this
+// separate from Mux's host-facing Model DTO so engine-only fields can evolve
+// without breaking users that consume `decoder models list --json`.
type modelListJSONEntry struct {
ID string `json:"id"`
InputPricePer1M float64 `json:"input_price_per_1m"`
@@ -175,7 +175,7 @@ type modelListJSONEntry struct {
LiveMetadata json.RawMessage `json:"live_metadata,omitempty"`
}
-func modelListJSONEntryFromEngine(m rhoconfig.EngineModel) modelListJSONEntry {
+func modelListJSONEntryFromEngine(m decoderconfig.EngineModel) modelListJSONEntry {
return modelListJSONEntry{
ID: m.ID,
InputPricePer1M: m.InputPricePer1M,
@@ -198,7 +198,7 @@ func validModelLiveMetadata(raw json.RawMessage) json.RawMessage {
return append(json.RawMessage(nil), metadata...)
}
-func marshalModelListJSON(models []rhoconfig.EngineModel, rawOnly, live bool) ([]byte, error) {
+func marshalModelListJSON(models []decoderconfig.EngineModel, rawOnly, live bool) ([]byte, error) {
entries := make([]modelListJSONEntry, len(models))
for i, model := range models {
entries[i] = modelListJSONEntryFromEngine(model)
diff --git a/cmd/models_test.go b/cmd/models_test.go
index fb15b2984..07f834e8f 100644
--- a/cmd/models_test.go
+++ b/cmd/models_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
)
func TestMarshalModelListJSONCompatibilityGolden(t *testing.T) {
@@ -72,7 +72,7 @@ func TestMarshalModelListJSONCompatibilityGolden(t *testing.T) {
}
func TestModelListJSONEntryFromEnginePreservesLegacyFieldMapping(t *testing.T) {
- model := rhoconfig.EngineModel{
+ model := decoderconfig.EngineModel{
ID: "vendor/model",
DisplayName: "Model",
Description: "Description",
@@ -97,7 +97,7 @@ func TestModelListJSONEntryFromEnginePreservesLegacyFieldMapping(t *testing.T) {
t.Fatalf("ServerTools = %v, want %v", entry.ServerTools, model.Capabilities)
}
- out, err := marshalModelListJSON([]rhoconfig.EngineModel{model}, false, false)
+ out, err := marshalModelListJSON([]decoderconfig.EngineModel{model}, false, false)
if err != nil {
t.Fatalf("marshalModelListJSON() error = %v", err)
}
diff --git a/cmd/notifications.go b/cmd/notifications.go
index c438c6260..3a7c6a615 100644
--- a/cmd/notifications.go
+++ b/cmd/notifications.go
@@ -15,7 +15,7 @@ func notifyCompletion(duration time.Duration) {
return
}
- msg := "Rho query completed"
+ msg := "Decoder query completed"
switch runtime.GOOS {
case "darwin":
@@ -23,10 +23,10 @@ func notifyCompletion(duration time.Duration) {
_ = exec.CommandContext(
context.Background(),
"osascript", "-e",
- `display notification "`+msg+`" with title "Rho"`,
+ `display notification "`+msg+`" with title "Decoder"`,
).Start()
case "linux":
// Linux: use notify-send if available
- _ = exec.CommandContext(context.Background(), "notify-send", "Rho", msg).Start()
+ _ = exec.CommandContext(context.Background(), "notify-send", "Decoder", msg).Start()
}
}
diff --git a/cmd/notify.go b/cmd/notify.go
index 5f673310e..5413adc31 100644
--- a/cmd/notify.go
+++ b/cmd/notify.go
@@ -10,7 +10,7 @@ import (
"sync"
"time"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// Notification represents a single notification event.
@@ -23,7 +23,7 @@ type Notification struct {
Read bool
}
-// Notifier manages terminal notifications for rho events.
+// Notifier manages terminal notifications for decoder events.
type Notifier struct {
Enabled bool
Level string // "all", "important", "critical"
@@ -151,7 +151,7 @@ $textNodes = $template.GetElementsByTagName('text')
$textNodes.Item(0).AppendChild($template.CreateTextNode('%s')) | Out-Null
$textNodes.Item(1).AppendChild($template.CreateTextNode('%s')) | Out-Null
$toast = [Windows.UI.Notifications.ToastNotification]::new($template)
-[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('rho').Show($toast)`,
+[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('decoder').Show($toast)`,
escapePowerShell(title), escapePowerShell(message))
cmd := exec.CommandContext(context.Background(), "powershell", "-Command", script) // #nosec G204 -- fixed command 'powershell'; script built from escaped internal strings
return cmd.Run()
diff --git a/cmd/notify_test.go b/cmd/notify_test.go
index 38276703a..1e01db924 100644
--- a/cmd/notify_test.go
+++ b/cmd/notify_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"time"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func TestNewNotifier(t *testing.T) {
@@ -258,7 +258,7 @@ func TestSetTerminalTitle(t *testing.T) {
t.Fatal("expected Sound and Desktop to be disabled")
}
- n.SetTerminalTitle("rho: running")
+ n.SetTerminalTitle("decoder: running")
n.ClearTitle()
}
diff --git a/cmd/ocg_live_test.go b/cmd/ocg_live_test.go
index 4652069f7..4f00f3819 100644
--- a/cmd/ocg_live_test.go
+++ b/cmd/ocg_live_test.go
@@ -4,7 +4,7 @@
// Live integration test for the OpenCodeGo provider adapter end-to-end.
// Opt-in only — not run by default `go test ./...` or CI. Run with:
//
-// OPENCODEGO_API_KEY=... go test -tags=live_test -run TestLiveOpenCodeGoMiniMaxM3FullRhoPath ./cmd
+// OPENCODEGO_API_KEY=... go test -tags=live_test -run TestLiveOpenCodeGoMiniMaxM3FullDecoderPath ./cmd
//
// Or via `make test-live` in this repo.
package cmd
@@ -15,15 +15,15 @@ import (
"testing"
"time"
- fluxcfg "github.com/GrayCodeAI/flux/config"
- "github.com/GrayCodeAI/flux/credentials"
- "github.com/GrayCodeAI/flux/setup"
- "github.com/GrayCodeAI/rho/internal/observability/logger"
+ "github.com/GrayCodeAI/decoder/internal/observability/logger"
+ muxcfg "github.com/GrayCodeAI/mux/config"
+ "github.com/GrayCodeAI/mux/credentials"
+ "github.com/GrayCodeAI/mux/setup"
)
-func TestLiveOpenCodeGoMiniMaxM3FullRhoPath(t *testing.T) {
+func TestLiveOpenCodeGoMiniMaxM3FullDecoderPath(t *testing.T) {
if credentials.LookupSecret(context.Background(), "OPENCODEGO_API_KEY") == "" {
- t.Skip("OPENCODEGO_API_KEY not configured") // TODO: https://github.com/GrayCodeAI/rho/issues/29
+ t.Skip("OPENCODEGO_API_KEY not configured") // TODO: https://github.com/GrayCodeAI/decoder/issues/29
}
settings, err := loadEffectiveSettings()
if err != nil {
@@ -38,12 +38,12 @@ func TestLiveOpenCodeGoMiniMaxM3FullRhoPath(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- t.Logf("provider=%s model=%s tools=%d system_len=%d", effectiveProvider, effectiveModel, len(registry.FluxTools()), len(systemPrompt))
+ t.Logf("provider=%s model=%s tools=%d system_len=%d", effectiveProvider, effectiveModel, len(registry.MuxTools()), len(systemPrompt))
- adapter := setup.ConfiguredDeploymentAdapters(fluxcfg.LoadProviderConfig(""))["opencodego"]
+ adapter := setup.ConfiguredDeploymentAdapters(muxcfg.LoadProviderConfig(""))["opencodego"]
t.Logf("adapter_type=%T", adapter.Provider)
- sess := newRhoSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry)
+ sess := newDecoderSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry)
sess.SetLogger(logger.New(ioDiscard{}, logger.Info))
if cfgErr := configureSession(sess, settings); cfgErr != nil {
t.Fatal(cfgErr)
diff --git a/cmd/options.go b/cmd/options.go
index 80fa3390b..76e0b0803 100644
--- a/cmd/options.go
+++ b/cmd/options.go
@@ -9,24 +9,24 @@ import (
"os"
"strings"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
-
- "github.com/GrayCodeAI/rho/internal/engine/scaffold"
-
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- ctxrepomap "github.com/GrayCodeAI/rho/internal/context/repomap"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/engine/branching"
- "github.com/GrayCodeAI/rho/internal/engine/lifecycle"
- "github.com/GrayCodeAI/rho/internal/intelligence/memory"
- "github.com/GrayCodeAI/rho/internal/intelligence/repomap"
- "github.com/GrayCodeAI/rho/internal/observability/logger"
- "github.com/GrayCodeAI/rho/internal/permissions"
- "github.com/GrayCodeAI/rho/internal/prompt"
- "github.com/GrayCodeAI/rho/internal/prompts"
- rhomodel "github.com/GrayCodeAI/rho/internal/provider/routing"
- "github.com/GrayCodeAI/rho/internal/snapshot"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+
+ "github.com/GrayCodeAI/decoder/internal/engine/scaffold"
+
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ ctxrepomap "github.com/GrayCodeAI/decoder/internal/context/repomap"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine/branching"
+ "github.com/GrayCodeAI/decoder/internal/engine/lifecycle"
+ "github.com/GrayCodeAI/decoder/internal/intelligence/memory"
+ "github.com/GrayCodeAI/decoder/internal/intelligence/repomap"
+ "github.com/GrayCodeAI/decoder/internal/observability/logger"
+ "github.com/GrayCodeAI/decoder/internal/permissions"
+ "github.com/GrayCodeAI/decoder/internal/prompt"
+ "github.com/GrayCodeAI/decoder/internal/prompts"
+ decodermodel "github.com/GrayCodeAI/decoder/internal/provider/routing"
+ "github.com/GrayCodeAI/decoder/internal/snapshot"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
func buildSystemPrompt() (string, error) {
@@ -74,7 +74,7 @@ func buildSystemPromptWithOptions(includeWorkspaceContext, includeRepoMap bool)
modularPrompt = ""
}
- base := prompt.System() + "\n\n" + rhoconfig.BuildStartupContextWithDirs(addDirs)
+ base := prompt.System() + "\n\n" + decoderconfig.BuildStartupContextWithDirs(addDirs)
if modularPrompt != "" {
base += "\n\n" + modularPrompt
}
@@ -124,7 +124,7 @@ func buildDeferredWorkspacePromptContext() string {
return ""
}
var sections []string
- if deferred := strings.TrimSpace(rhoconfig.BuildDeferredContextWithDirs(addDirs)); deferred != "" {
+ if deferred := strings.TrimSpace(decoderconfig.BuildDeferredContextWithDirs(addDirs)); deferred != "" {
sections = append(sections, deferred)
}
if ws := prompts.GatherWorkspaceContext(cwd); ws != nil {
@@ -161,7 +161,7 @@ func injectRepoMap(base string) string {
return base
}
- settings := rhoconfig.LoadSettings()
+ settings := decoderconfig.LoadSettings()
if settings.RepoMap == nil || !*settings.RepoMap {
return base
}
@@ -187,43 +187,43 @@ func injectRepoMap(base string) string {
return base + "\n\n# Repository Map\n" + formatted
}
-func loadEffectiveSettings() (rhoconfig.Settings, error) {
- return rhoconfig.LoadSettingsWithOverride(settingsFlag)
+func loadEffectiveSettings() (decoderconfig.Settings, error) {
+ return decoderconfig.LoadSettingsWithOverride(settingsFlag)
}
-func resolveSelection(settings rhoconfig.Settings) rhoconfig.Selection {
- return rhoconfig.EffectiveSelectionWithSettings(context.Background(), settings, rhoconfig.SelectionOptions{
+func resolveSelection(settings decoderconfig.Settings) decoderconfig.Selection {
+ return decoderconfig.EffectiveSelectionWithSettings(context.Background(), settings, decoderconfig.SelectionOptions{
ProviderOverride: firstNonEmptyTrimmed(provider, settings.Provider),
ModelOverride: firstNonEmptyTrimmed(model, settings.Model),
})
}
-func startupSelection(settings rhoconfig.Settings) rhoconfig.Selection {
+func startupSelection(settings decoderconfig.Settings) decoderconfig.Selection {
providerOverride := firstNonEmptyTrimmed(provider, settings.Provider)
modelOverride := firstNonEmptyTrimmed(model, settings.Model)
explicitProvider, explicitModel := explicitSelection(context.Background())
- providerID := rhoconfig.ActiveProviderID(firstNonEmptyTrimmed(providerOverride, explicitProvider))
+ providerID := decoderconfig.ActiveProviderID(firstNonEmptyTrimmed(providerOverride, explicitProvider))
modelID := strings.TrimSpace(firstNonEmptyTrimmed(modelOverride, explicitModel))
if providerID == "" && modelID != "" {
- providerID = rhoconfig.ActiveProviderID(rhoconfig.ProviderOfModelWithSettings(settings, modelID))
+ providerID = decoderconfig.ActiveProviderID(decoderconfig.ProviderOfModelWithSettings(settings, modelID))
}
if modelID == "" && providerID != "" {
- modelID = strings.TrimSpace(rhoconfig.DefaultModelForProviderWithSettings(settings, providerID))
+ modelID = strings.TrimSpace(decoderconfig.DefaultModelForProviderWithSettings(settings, providerID))
}
if providerID == "" {
providerID = startupPlaceholderProvider
}
- return rhoconfig.Selection{
+ return decoderconfig.Selection{
Provider: providerID,
Model: modelID,
}
}
-func effectiveModelAndProvider(settings rhoconfig.Settings) (string, string) {
+func effectiveModelAndProvider(settings decoderconfig.Settings) (string, string) {
selection := resolveSelection(settings)
if !selection.HasConfiguredDeployment {
return "", ""
@@ -231,7 +231,7 @@ func effectiveModelAndProvider(settings rhoconfig.Settings) (string, string) {
return selection.Model, selection.Provider
}
-func newStartupRhoSession(selection rhoconfig.Selection, systemPrompt string, registry *tool.Registry) *engine.Session {
+func newStartupDecoderSession(selection decoderconfig.Selection, systemPrompt string, registry *tool.Registry) *engine.Session {
providerID := strings.TrimSpace(selection.Provider)
if providerID == "" {
providerID = startupPlaceholderProvider
@@ -239,7 +239,7 @@ func newStartupRhoSession(selection rhoconfig.Selection, systemPrompt string, re
return engine.NewSession(providerID, strings.TrimSpace(selection.Model), systemPrompt, registry)
}
-func newRhoSession(settings rhoconfig.Settings, effectiveProvider, effectiveModel, systemPrompt string, registry *tool.Registry) *engine.Session {
+func newDecoderSession(settings decoderconfig.Settings, effectiveProvider, effectiveModel, systemPrompt string, registry *tool.Registry) *engine.Session {
selection := resolveSelection(settings)
if strings.TrimSpace(selection.Provider) == "" {
selection.Provider = effectiveProvider
@@ -247,15 +247,15 @@ func newRhoSession(settings rhoconfig.Settings, effectiveProvider, effectiveMode
if strings.TrimSpace(selection.Model) == "" {
selection.Model = effectiveModel
}
- sess := engine.NewRhoSessionForSettings(context.Background(), settings, selection, selection.Provider, selection.Model, systemPrompt, registry)
+ sess := engine.NewDecoderSessionForSettings(context.Background(), settings, selection, selection.Provider, selection.Model, systemPrompt, registry)
return sess
}
-// newConfiguredRhoSession is the non-interactive command composition root.
+// newConfiguredDecoderSession is the non-interactive command composition root.
// Interactive chat intentionally keeps its lightweight startup and deferred
// heavy configuration split; batch/daemon/ACP callers use this atomic path.
-func newConfiguredRhoSession(settings rhoconfig.Settings, effectiveProvider, effectiveModel, systemPrompt string, registry *tool.Registry, sessionLogger *logger.Logger, maxTurnsOverride ...int) (*engine.Session, error) {
- sess := newRhoSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry)
+func newConfiguredDecoderSession(settings decoderconfig.Settings, effectiveProvider, effectiveModel, systemPrompt string, registry *tool.Registry, sessionLogger *logger.Logger, maxTurnsOverride ...int) (*engine.Session, error) {
+ sess := newDecoderSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry)
if sessionLogger != nil {
sess.SetLogger(sessionLogger)
}
@@ -265,11 +265,11 @@ func newConfiguredRhoSession(settings rhoconfig.Settings, effectiveProvider, eff
return sess, nil
}
-// newConfiguredRhoSessionFactory is the shared composition seam for
+// newConfiguredDecoderSessionFactory is the shared composition seam for
// non-interactive protocol/server entry points. It owns registry creation and
// settings-based model selection while allowing each protocol to provide its
// own prompt and optional model override.
-func newConfiguredRhoSessionFactory(settings rhoconfig.Settings, sessionLogger *logger.Logger) func(string, string, ...int) (*engine.Session, error) {
+func newConfiguredDecoderSessionFactory(settings decoderconfig.Settings, sessionLogger *logger.Logger) func(string, string, ...int) (*engine.Session, error) {
return func(systemPrompt, modelOverride string, maxTurnsOverride ...int) (*engine.Session, error) {
registry, err := defaultRegistry(settings)
if err != nil {
@@ -279,14 +279,14 @@ func newConfiguredRhoSessionFactory(settings rhoconfig.Settings, sessionLogger *
if strings.TrimSpace(modelOverride) != "" {
effectiveModel = modelOverride
}
- return newConfiguredRhoSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry, sessionLogger, maxTurnsOverride...)
+ return newConfiguredDecoderSession(settings, effectiveProvider, effectiveModel, systemPrompt, registry, sessionLogger, maxTurnsOverride...)
}
}
// prepareInteractiveSessionStartup applies only the cheap TUI startup slice.
// Transport rebuild and heavy memory setup remain deferred until the first
// real chat request in bootstrapSessionForChat.
-func prepareInteractiveSessionStartup(sess *engine.Session, settings rhoconfig.Settings) error {
+func prepareInteractiveSessionStartup(sess *engine.Session, settings decoderconfig.Settings) error {
syncSessionFromPersistedSelection(sess)
sess.SetLogger(logger.New(io.Discard, logger.Error))
return configureSessionStartup(sess, settings)
@@ -301,7 +301,7 @@ func firstNonEmptyTrimmed(values ...string) string {
return ""
}
-func configureSession(sess *engine.Session, settings rhoconfig.Settings, maxTurnsOverride ...int) error {
+func configureSession(sess *engine.Session, settings decoderconfig.Settings, maxTurnsOverride ...int) error {
if err := configureSessionStartup(sess, settings, maxTurnsOverride...); err != nil {
return err
}
@@ -309,7 +309,7 @@ func configureSession(sess *engine.Session, settings rhoconfig.Settings, maxTurn
return nil
}
-func configureSessionStartup(sess *engine.Session, settings rhoconfig.Settings, maxTurnsOverride ...int) error {
+func configureSessionStartup(sess *engine.Session, settings decoderconfig.Settings, maxTurnsOverride ...int) error {
sess.WireAgentTool()
sess.SetAllowedDirs(addDirs)
projectDir, err := os.Getwd()
@@ -363,7 +363,7 @@ func configureSessionStartup(sess *engine.Session, settings rhoconfig.Settings,
}
// Model cascade router: automatically routes tasks to optimal model tier
- roles := rhomodel.DefaultRoles(sess.Model())
+ roles := decodermodel.DefaultRoles(sess.Model())
if settings.ModelRoles != nil {
roles = *settings.ModelRoles
}
@@ -411,7 +411,7 @@ func configureSessionStartup(sess *engine.Session, settings rhoconfig.Settings,
// provider-specific defaults (e.g. LongCat off).
modelID := strings.TrimSpace(sess.Model())
providerID := strings.TrimSpace(sess.Provider())
- sess.SetThinkingEnabled(rhoconfig.ResolveThinkingForModel(settings, modelID, providerID))
+ sess.SetThinkingEnabled(decoderconfig.ResolveThinkingForModel(settings, modelID, providerID))
return nil
}
diff --git a/cmd/options_test.go b/cmd/options_test.go
index a17908826..ef9a91b9d 100644
--- a/cmd/options_test.go
+++ b/cmd/options_test.go
@@ -3,7 +3,7 @@ package cmd
import (
"testing"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
func TestParseToolListFromCLI(t *testing.T) {
diff --git a/cmd/options_welcome_test.go b/cmd/options_welcome_test.go
index f949a09ef..ab31b36e7 100644
--- a/cmd/options_welcome_test.go
+++ b/cmd/options_welcome_test.go
@@ -7,65 +7,65 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
)
func isolateCredentialHome(t *testing.T) {
t.Helper()
home := t.TempDir()
- rhoDir := filepath.Join(home, ".rho")
- _ = os.MkdirAll(rhoDir, 0o700)
+ decoderDir := filepath.Join(home, ".decoder")
+ _ = os.MkdirAll(decoderDir, 0o700)
t.Setenv("HOME", home)
- t.Setenv("RHO_CONFIG_DIR", rhoDir)
- t.Setenv("FLUX_CONFIG_DIR", filepath.Join(home, "flux"))
+ t.Setenv("DECODER_CONFIG_DIR", decoderDir)
+ t.Setenv("MUX_CONFIG_DIR", filepath.Join(home, "mux"))
}
func TestEffectiveModelAndProvider_ClearsWithoutCredentials(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
isolateCredentialHome(t)
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
- if err := rhoconfig.SetActiveProvider(ctx, "openrouter"); err != nil {
+ if err := decoderconfig.SetActiveProvider(ctx, "openrouter"); err != nil {
t.Fatal(err)
}
- if err := rhoconfig.SetActiveModel(ctx, "gpt-4o"); err != nil {
+ if err := decoderconfig.SetActiveModel(ctx, "gpt-4o"); err != nil {
t.Fatal(err)
}
- model, provider := effectiveModelAndProvider(rhoconfig.Settings{})
+ model, provider := effectiveModelAndProvider(decoderconfig.Settings{})
if model != "" || provider != "" {
t.Fatalf("expected empty selection without credentials, got model=%q provider=%q", model, provider)
}
}
func TestEffectiveModelAndProvider_KeepsWithCredentials(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
isolateCredentialHome(t)
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
_ = store.Set(ctx, gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890")
- rhoconfig.InvalidateConfigUICache()
- if err := rhoconfig.SetActiveProvider(ctx, "openrouter"); err != nil {
+ decoderconfig.InvalidateConfigUICache()
+ if err := decoderconfig.SetActiveProvider(ctx, "openrouter"); err != nil {
t.Fatal(err)
}
- if err := rhoconfig.SetActiveModel(ctx, "gpt-4o"); err != nil {
+ if err := decoderconfig.SetActiveModel(ctx, "gpt-4o"); err != nil {
t.Fatal(err)
}
- model, provider := effectiveModelAndProvider(rhoconfig.Settings{})
+ model, provider := effectiveModelAndProvider(decoderconfig.Settings{})
if provider == "" {
t.Fatalf("expected provider with credentials, got model=%q provider=%q", model, provider)
}
diff --git a/cmd/overlay_styles.go b/cmd/overlay_styles.go
index 9ffa43335..bb474f5e3 100644
--- a/cmd/overlay_styles.go
+++ b/cmd/overlay_styles.go
@@ -38,5 +38,5 @@ func overlaySearchValueStyle() lipgloss.Style {
}
func overlaySelectionMarkerStyle() lipgloss.Style {
- return lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
+ return lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
}
diff --git a/cmd/overlay_zero_value_test.go b/cmd/overlay_zero_value_test.go
index c5d9afd0d..4348af7b7 100644
--- a/cmd/overlay_zero_value_test.go
+++ b/cmd/overlay_zero_value_test.go
@@ -3,7 +3,7 @@ package cmd
import (
"testing"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
)
func TestInteractiveOverlaysZeroValuesRenderSafely(t *testing.T) {
diff --git a/cmd/pager.go b/cmd/pager.go
index ae1d3df91..53ced5585 100644
--- a/cmd/pager.go
+++ b/cmd/pager.go
@@ -95,7 +95,7 @@ func StopPager() {
// Returns "" if paging should be disabled.
func resolvePager() string {
// Disable paging via environment.
- if v := os.Getenv("RHO_PAGER"); v != "" {
+ if v := os.Getenv("DECODER_PAGER"); v != "" {
if v == "cat" || v == "none" {
return ""
}
diff --git a/cmd/path.go b/cmd/path.go
index 0313dd5b2..7c8995bef 100644
--- a/cmd/path.go
+++ b/cmd/path.go
@@ -5,7 +5,7 @@ import (
"encoding/json"
"fmt"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
"github.com/spf13/cobra"
)
@@ -17,16 +17,16 @@ var (
var pathCmd = &cobra.Command{
Use: "path",
Short: "Developer path readiness (setup, security, ecosystem)",
- Long: `Check whether rho is configured on the developer path:
+ Long: `Check whether decoder is configured on the developer path:
API keys in OS secret store, model selected, no secrets on disk,
-and flux integration.
+and mux integration.
Built for individual developers first — teams and enterprise later.
See docs/DEVELOPER-PATH.md and docs/SECURITY-DEVELOPER.md.`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
- report := rhoconfig.EvaluateDeveloperPath(ctx)
+ report := decoderconfig.EvaluateDeveloperPath(ctx)
if pathJSON {
enc := json.NewEncoder(cmd.OutOrStdout())
@@ -34,7 +34,7 @@ See docs/DEVELOPER-PATH.md and docs/SECURITY-DEVELOPER.md.`,
return enc.Encode(report)
}
- cmd.Println(rhoconfig.FormatDeveloperPathReport(ctx))
+ cmd.Println(decoderconfig.FormatDeveloperPathReport(ctx))
if !report.Ready {
return fmt.Errorf("developer path not ready — %s", report.NextStep)
diff --git a/cmd/path_test.go b/cmd/path_test.go
index 48a1dbda0..a766d9141 100644
--- a/cmd/path_test.go
+++ b/cmd/path_test.go
@@ -5,20 +5,20 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
)
func TestPathCmdRuns(t *testing.T) {
useInMemoryCredentials(t)
if err := pathCmd.RunE(pathCmd, nil); err == nil {
- t.Skip("machine has full developer path setup") // TODO: https://github.com/GrayCodeAI/rho/issues/30
+ t.Skip("machine has full developer path setup") // TODO: https://github.com/GrayCodeAI/decoder/issues/30
}
}
func TestPathCmdPrintsReport(t *testing.T) {
useInMemoryCredentials(t)
- out := rhoconfig.FormatDeveloperPathReport(context.Background())
+ out := decoderconfig.FormatDeveloperPathReport(context.Background())
if !strings.Contains(out, "Developer path") {
t.Fatalf("unexpected output: %s", out)
}
diff --git a/cmd/permissions.go b/cmd/permissions.go
index d5508e279..b28197523 100644
--- a/cmd/permissions.go
+++ b/cmd/permissions.go
@@ -8,10 +8,10 @@ import (
"strconv"
"strings"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
- "github.com/GrayCodeAI/rho/internal/permissions"
- "github.com/GrayCodeAI/rho/internal/permissions/stableid"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/permissions"
+ "github.com/GrayCodeAI/decoder/internal/permissions/stableid"
"github.com/spf13/cobra"
)
@@ -231,7 +231,7 @@ var permissionsInspectCmd = &cobra.Command{
// observational evaluator. It is the same resolver used before execution and
// never invokes a prompt, mutates remembered rules, or runs a tool.
func inspectPermission(kind stableid.Kind, identity, toolOverride string) (permissionInspectionOutput, error) {
- settings, err := rhoconfig.LoadSettingsWithOverride(settingsFlag)
+ settings, err := decoderconfig.LoadSettingsWithOverride(settingsFlag)
if err != nil {
return permissionInspectionOutput{}, err
}
@@ -276,7 +276,7 @@ func inspectPermission(kind stableid.Kind, identity, toolOverride string) (permi
// used by session startup, the TUI permission center, and CLI inspection.
// Keeping this at one boundary prevents a preview or UI rebuild from drifting
// away from the rules used by the executor.
-func applyConfiguredPermissionRules(mem *safety.PermissionMemory, settings rhoconfig.Settings, includeCLI bool) {
+func applyConfiguredPermissionRules(mem *safety.PermissionMemory, settings decoderconfig.Settings, includeCLI bool) {
if mem == nil {
return
}
diff --git a/cmd/permissions_center.go b/cmd/permissions_center.go
index be38a8f9b..e47309321 100644
--- a/cmd/permissions_center.go
+++ b/cmd/permissions_center.go
@@ -5,12 +5,12 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
- "github.com/GrayCodeAI/rho/internal/permissions/stableid"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/permissions/stableid"
tea "charm.land/bubbletea/v2"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
func normalizePermissionTier(raw string) (safety.AutonomyLevel, string, bool) {
@@ -362,7 +362,7 @@ func appendExactPermissionRules(b *strings.Builder, rules []stableid.RuleSnap) {
}
}
-func effectiveAllowRules(settings rhoconfig.Settings) []string {
+func effectiveAllowRules(settings decoderconfig.Settings) []string {
var rules []string
rules = append(rules, settings.AutoAllow...)
rules = append(rules, settings.AllowedTools...)
@@ -370,7 +370,7 @@ func effectiveAllowRules(settings rhoconfig.Settings) []string {
return dedupeStrings(rules)
}
-func effectiveDenyRules(settings rhoconfig.Settings) []string {
+func effectiveDenyRules(settings decoderconfig.Settings) []string {
rules := append([]string{}, settings.DisallowedTools...)
rules = append(rules, parseToolListFromCLI(disallowedToolsFlag)...)
return dedupeStrings(rules)
@@ -390,7 +390,7 @@ func dedupeStrings(values []string) []string {
return out
}
-func rebuildSessionPermissionRules(sess *engine.Session, settings rhoconfig.Settings) {
+func rebuildSessionPermissionRules(sess *engine.Session, settings decoderconfig.Settings) {
if sess == nil {
return
}
@@ -434,7 +434,7 @@ func (m *chatModel) updateAutonomyRule(parts []string, allow bool) {
m.messages = append(m.messages, displayMsg{role: "system", content: label + " rules updated.\n" + permissionRulesSummary(m)})
}
-func savePermissionSettings(scope string, settings rhoconfig.Settings, level safety.AutonomyLevel) (string, error) {
+func savePermissionSettings(scope string, settings decoderconfig.Settings, level safety.AutonomyLevel) (string, error) {
scope = strings.ToLower(strings.TrimSpace(scope))
if scope == "" {
scope = "global"
@@ -448,13 +448,13 @@ func savePermissionSettings(scope string, settings rhoconfig.Settings, level saf
case "project":
return "", fmt.Errorf("project-local settings writes are disabled; use scope \"global\" or an explicit --settings file")
case "global":
- target := rhoconfig.LoadGlobalSettings()
+ target := decoderconfig.LoadGlobalSettings()
target.AutoAllow = append([]string{}, settings.AutoAllow...)
target.AllowedTools = append([]string{}, settings.AllowedTools...)
target.DisallowedTools = append([]string{}, settings.DisallowedTools...)
target.Autonomy = settings.Autonomy
target.AutonomyExplicit = true
- if err := rhoconfig.SaveGlobal(target); err != nil {
+ if err := decoderconfig.SaveGlobal(target); err != nil {
return "", err
}
return "user settings", nil
@@ -754,7 +754,7 @@ func (m *chatModel) handleAutonomyCommand(parts []string) (chatModel, tea.Cmd) {
m.messages = append(m.messages, displayMsg{role: "system", content: m.session.PermSvc().PermissionMetrics()})
case "reset":
resetPermissionCenter(m)
- m.messages = append(m.messages, displayMsg{role: "system", content: "Session autonomy reset to defaults. Persisted exact rules were kept; use `rho permissions reset` to remove them with confirmation.\n" + autonomyCenterSummary(m)})
+ m.messages = append(m.messages, displayMsg{role: "system", content: "Session autonomy reset to defaults. Persisted exact rules were kept; use `decoder permissions reset` to remove them with confirmation.\n" + autonomyCenterSummary(m)})
default:
m.messages = append(m.messages, displayMsg{role: "system", content: autonomyCommandHelp()})
}
diff --git a/cmd/permissions_center_test.go b/cmd/permissions_center_test.go
index 046f61049..36572bbf1 100644
--- a/cmd/permissions_center_test.go
+++ b/cmd/permissions_center_test.go
@@ -6,12 +6,12 @@ import (
"testing"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/permissions"
- "github.com/GrayCodeAI/rho/internal/permissions/stableid"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/permissions"
+ "github.com/GrayCodeAI/decoder/internal/permissions/stableid"
)
func TestNormalizePermissionTier(t *testing.T) {
@@ -62,7 +62,7 @@ func TestParseBypassFlagsFailsClosed(t *testing.T) {
}
func TestEffectivePermissionRules(t *testing.T) {
- settings := rhoconfig.Settings{
+ settings := decoderconfig.Settings{
AutoAllow: []string{"Read"},
AllowedTools: []string{"Bash(git:*)", "Read"},
DisallowedTools: []string{"Bash(rm -rf *)"},
@@ -83,7 +83,7 @@ func TestAutonomyCenterSummary(t *testing.T) {
sess.PermSvc().SetSpecStage(safety.SpecStageSpecify)
model := &chatModel{
session: sess,
- settings: rhoconfig.Settings{
+ settings: decoderconfig.Settings{
AllowedTools: []string{"Bash(git:*)"},
DisallowedTools: []string{"Bash(rm -rf *)"},
},
@@ -230,7 +230,7 @@ func TestResetPermissionCenter(t *testing.T) {
sess.PermSvc().SetExactRuleStore(store)
model := &chatModel{
session: sess,
- settings: rhoconfig.Settings{
+ settings: decoderconfig.Settings{
Autonomy: permissionTierSettingValue(safety.AutonomyYOLO),
AutoAllow: []string{"Read"},
AllowedTools: []string{"Bash(git:*)"},
diff --git a/cmd/permissions_inspect_test.go b/cmd/permissions_inspect_test.go
index a67ee042d..77aa0cda2 100644
--- a/cmd/permissions_inspect_test.go
+++ b/cmd/permissions_inspect_test.go
@@ -3,8 +3,8 @@ package cmd
import (
"testing"
- "github.com/GrayCodeAI/rho/internal/permissions"
- "github.com/GrayCodeAI/rho/internal/permissions/stableid"
+ "github.com/GrayCodeAI/decoder/internal/permissions"
+ "github.com/GrayCodeAI/decoder/internal/permissions/stableid"
)
func TestInspectionToolCall_SelectsPowerShellRuntime(t *testing.T) {
diff --git a/cmd/plan.go b/cmd/plan.go
index 7a1731225..6e9ac4af9 100644
--- a/cmd/plan.go
+++ b/cmd/plan.go
@@ -8,8 +8,8 @@ import (
"strconv"
"strings"
- "github.com/GrayCodeAI/rho/internal/intelligence/planner"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/intelligence/planner"
+ "github.com/GrayCodeAI/decoder/internal/storage"
"github.com/spf13/cobra"
)
@@ -19,7 +19,7 @@ var planCmd = &cobra.Command{
Use: "plan",
Short: "Create and manage structured development plans",
Long: `plan helps you create, list, and track structured development plans.
-Plans are stored in Rho's user state directory, partitioned by project.
+Plans are stored in Decoder's user state directory, partitioned by project.
Subcommands:
create Create a new plan (generates a plan prompt)
@@ -38,13 +38,13 @@ var planCreateCmd = &cobra.Command{
// Generate the plan prompt (would normally be sent to an LLM).
prompt := planner.Generate(description, "")
cmd.Println(auditTint("Plan prompt generated. Send this to an LLM to produce a plan:", textMuted))
- cmd.Println(auditTint("--- System ---", rhoColor))
+ cmd.Println(auditTint("--- System ---", decoderColor))
cmd.Println(prompt.System)
cmd.Println()
- cmd.Println(auditTint("--- User ---", rhoColor))
+ cmd.Println(auditTint("--- User ---", decoderColor))
cmd.Println(prompt.User)
cmd.Println()
- cmd.Println(auditTint("Once you have the LLM response, save it with an explicit output path or import it into Rho plans.", textMuted))
+ cmd.Println(auditTint("Once you have the LLM response, save it with an explicit output path or import it into Decoder plans.", textMuted))
return nil
},
}
@@ -60,7 +60,7 @@ var planListCmd = &cobra.Command{
if planJSON {
fmt.Println("[]")
} else {
- cmd.Println(auditTint("No plans found. Create one with: rho plan create ", textMuted))
+ cmd.Println(auditTint("No plans found. Create one with: decoder plan create ", textMuted))
}
return nil
}
@@ -92,7 +92,7 @@ var planListCmd = &cobra.Command{
}
if len(plans) == 0 {
- cmd.Println(auditTint("No plans found. Create one with: rho plan create ", textMuted))
+ cmd.Println(auditTint("No plans found. Create one with: decoder plan create ", textMuted))
return nil
}
@@ -147,10 +147,10 @@ var planDoneCmd = &cobra.Command{
Use: "done ",
Short: "Mark a task as completed in the most recent plan",
Long: `Mark a task as done by its numeric ID. This operates on the most
-recently modified plan in Rho's user state directory for the current project.
+recently modified plan in Decoder's user state directory for the current project.
To target a specific plan, set the plan name as the first argument
-followed by the task ID: rho plan done `,
+followed by the task ID: decoder plan done `,
Args: cobra.RangeArgs(1, 2),
RunE: func(cmd *cobra.Command, args []string) error {
var planPath string
@@ -204,7 +204,7 @@ func init() {
planShowCmd.Flags().BoolVar(&planJSON, "json", false, "output plan as JSON")
}
-// resolvePlanPath converts a plan name to a file path in Rho's user state dir.
+// resolvePlanPath converts a plan name to a file path in Decoder's user state dir.
func resolvePlanPath(name string) string {
plansDir := currentProjectPlansDir()
// If the name already has a .json extension, use it directly.
diff --git a/cmd/plugin_dynamic.go b/cmd/plugin_dynamic.go
index f40bbb6a8..341f9217e 100644
--- a/cmd/plugin_dynamic.go
+++ b/cmd/plugin_dynamic.go
@@ -8,8 +8,8 @@ import (
"path/filepath"
"time"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/theme"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/theme"
"github.com/spf13/cobra"
)
@@ -90,7 +90,7 @@ var pluginStatusCmd = &cobra.Command{
statuses := dm.Status()
if len(statuses) == 0 {
- cmd.Println(auditTint("No plugins discovered. Run 'rho plugin install' to add plugins.", textMuted))
+ cmd.Println(auditTint("No plugins discovered. Run 'decoder plugin install' to add plugins.", textMuted))
return nil
}
@@ -209,7 +209,7 @@ var pluginCreateCmd = &cobra.Command{
manifest := &plugin.ManifestV2{
Name: name,
Version: "0.1.0",
- Description: fmt.Sprintf("A rho plugin: %s", name),
+ Description: fmt.Sprintf("A decoder plugin: %s", name),
Author: "",
Mode: "subprocess",
Tools: []plugin.ManifestTool{
@@ -281,12 +281,12 @@ func main() {
// Write README.md
readme := fmt.Sprintf(`# %s
-A rho plugin.
+A decoder plugin.
## Installation
`+"```bash"+`
-rho plugin install ./%s
+decoder plugin install ./%s
`+"```"+`
## Usage
@@ -339,8 +339,8 @@ See `+"`plugin.json`"+` for the full manifest configuration.
cmd.Println()
cmd.Printf("%s\n", auditTint("Next steps:", textPrimary))
cmd.Printf("%s\n", auditTint(" cd "+name+" && go mod init "+name, textMuted))
- cmd.Printf("%s\n", auditTint(" rho plugin install ./"+name, textMuted))
- cmd.Printf("%s\n", auditTint(" rho plugin activate "+name, textMuted))
+ cmd.Printf("%s\n", auditTint(" decoder plugin install ./"+name, textMuted))
+ cmd.Printf("%s\n", auditTint(" decoder plugin activate "+name, textMuted))
return nil
},
}
@@ -422,13 +422,13 @@ var pluginMarketplaceListCmd = &cobra.Command{
entries, err := mc.FetchAll()
if err != nil {
prog.Abort()
- return fmt.Errorf("fetch marketplace: %w (indexes may be unpublished; add a source with rho plugin marketplace add)", err)
+ return fmt.Errorf("fetch marketplace: %w (indexes may be unpublished; add a source with decoder plugin marketplace add)", err)
}
prog.CompleteStep(0)
prog.Done()
if len(entries) == 0 {
cmd.Println(auditTint("No marketplace plugins found.", textMuted))
- cmd.Println(auditTint("Add a source: rho plugin marketplace add ", textMuted))
+ cmd.Println(auditTint("Add a source: decoder plugin marketplace add ", textMuted))
return nil
}
rows := make([][]string, 0, len(entries))
diff --git a/cmd/power.go b/cmd/power.go
index 2a7b1adba..be285c303 100644
--- a/cmd/power.go
+++ b/cmd/power.go
@@ -3,10 +3,10 @@ package cmd
import (
"fmt"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/provider/routing"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/provider/routing"
)
// PowerConfig maps a power level (1-10) to all relevant settings.
diff --git a/cmd/pr.go b/cmd/pr.go
index 9aaf067b4..68aadab64 100644
--- a/cmd/pr.go
+++ b/cmd/pr.go
@@ -8,7 +8,7 @@ import (
"strconv"
"strings"
- enginediff "github.com/GrayCodeAI/rho/internal/engine/diff"
+ enginediff "github.com/GrayCodeAI/decoder/internal/engine/diff"
"github.com/spf13/cobra"
)
@@ -31,10 +31,10 @@ Subcommands:
describe Generate or update a PR description
Examples:
- rho pr review
- rho pr review 42 --post-comments
- rho pr create --base develop --draft
- rho pr describe 42 --update`,
+ decoder pr review
+ decoder pr review 42 --post-comments
+ decoder pr create --base develop --draft
+ decoder pr describe 42 --update`,
}
var prReviewCmd = &cobra.Command{
diff --git a/cmd/preflight_test.go b/cmd/preflight_test.go
index b8455d978..e43645cd4 100644
--- a/cmd/preflight_test.go
+++ b/cmd/preflight_test.go
@@ -9,7 +9,7 @@ import (
// preflightReportShape mirrors the JSON-tagged PreflightReport returned by
// EnginePreflightReportWithSettings. We assert against a local shape to
-// avoid coupling the test to the exact gateway/flux import path.
+// avoid coupling the test to the exact gateway/mux import path.
type preflightReportShape struct {
Ready bool `json:"ready"`
Checks []preflightCheckShape `json:"checks"`
@@ -23,7 +23,7 @@ type preflightCheckShape struct {
func TestPreflightJSON_Structure(t *testing.T) {
dir := t.TempDir()
- t.Setenv("RHO_STATE_DIR", filepath.Join(dir, "state"))
+ t.Setenv("DECODER_STATE_DIR", filepath.Join(dir, "state"))
old := preflightJSON
oldLive := preflightLiveFlag
@@ -59,7 +59,7 @@ func TestPreflightJSON_Structure(t *testing.T) {
func TestPreflightText_NotJSON(t *testing.T) {
dir := t.TempDir()
- t.Setenv("RHO_STATE_DIR", filepath.Join(dir, "state"))
+ t.Setenv("DECODER_STATE_DIR", filepath.Join(dir, "state"))
old := preflightJSON
oldLive := preflightLiveFlag
diff --git a/cmd/progress_cli.go b/cmd/progress_cli.go
index 767c524c5..7e1c7c3c2 100644
--- a/cmd/progress_cli.go
+++ b/cmd/progress_cli.go
@@ -9,7 +9,7 @@ import (
"time"
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// CLIProgress renders a ProgressTracker as live single-line progress for
@@ -36,7 +36,7 @@ func newCLIProgress(title string, steps []string, w io.Writer, tty bool) *CLIPro
for _, s := range steps {
pt.AddStep(s)
}
- return &CLIProgress{w: w, pt: pt, spinner: NewBrailleSpinner(SpinnerRho, ""), tty: tty}
+ return &CLIProgress{w: w, pt: pt, spinner: NewBrailleSpinner(SpinnerDecoder, ""), tty: tty}
}
// StartStep marks step i active and, on a TTY, starts animating it in place.
@@ -47,7 +47,7 @@ func (c *CLIProgress) StartStep(i int) {
if IsQuiet() || !c.tty || i < 0 || i >= len(c.pt.Steps) {
return
}
- c.spinner = NewBrailleSpinner(SpinnerRho, c.pt.Steps[i].Name)
+ c.spinner = NewBrailleSpinner(SpinnerDecoder, c.pt.Steps[i].Name)
c.spinner.Start(80*time.Millisecond, func(frame string) {
eta := ""
if remaining := c.pt.EstimateRemaining(); remaining > 0 {
diff --git a/cmd/progress_debug_test.go b/cmd/progress_debug_test.go
index e14b91b5f..f1efb9ca1 100644
--- a/cmd/progress_debug_test.go
+++ b/cmd/progress_debug_test.go
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func TestZDebugProgress(t *testing.T) {
diff --git a/cmd/progress_tracker.go b/cmd/progress_tracker.go
index f0957fcc1..d90b11081 100644
--- a/cmd/progress_tracker.go
+++ b/cmd/progress_tracker.go
@@ -6,7 +6,7 @@ import (
"sync"
"time"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// ProgressStep represents a single step in a multi-step task.
diff --git a/cmd/progress_tracker_test.go b/cmd/progress_tracker_test.go
index 87a2ab390..e06569e74 100644
--- a/cmd/progress_tracker_test.go
+++ b/cmd/progress_tracker_test.go
@@ -6,7 +6,7 @@ import (
"testing"
"time"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func TestNewProgressTracker(t *testing.T) {
diff --git a/cmd/progressive_disclosure.go b/cmd/progressive_disclosure.go
index b291d836d..a61b43a75 100644
--- a/cmd/progressive_disclosure.go
+++ b/cmd/progressive_disclosure.go
@@ -52,22 +52,22 @@ func DefaultDisclosureConfig() DisclosureConfig {
// BeginnerHelp returns a simplified help message for new users.
func BeginnerHelp() string {
- return `Getting Started with rho
+ return `Getting Started with decoder
- Type your question or task and rho will help.
- rho reads your project and understands your code.
+ Type your question or task and decoder will help.
+ decoder reads your project and understands your code.
Essential Commands:
/help Show all commands
/test Run your project's tests
/diff See what you've changed
/commit Save your work with a smart message
- /review Have rho review your code
+ /review Have decoder review your code
/clear Start a fresh conversation
Tips:
- Just describe what you want in plain English
- - rho will read files, run commands, and make changes
+ - decoder will read files, run commands, and make changes
- Use /help to discover more features as you get comfortable
Type anything to get started!`
@@ -75,7 +75,7 @@ Type anything to get started!`
// IntermediateHelp returns the standard help message.
func IntermediateHelp() string {
- return `rho Commands
+ return `decoder Commands
Workflow:
/test Run tests and fix failures
@@ -110,7 +110,7 @@ Use /help all for the complete list.`
// AdvancedHelp returns the full command reference.
func AdvancedHelp() string {
- return `rho Full Command Reference
+ return `decoder Full Command Reference
Workflow:
/test [cmd] Run tests (default: go test ./...)
diff --git a/cmd/prompt_input.go b/cmd/prompt_input.go
index 6bceb9552..d2293b914 100644
--- a/cmd/prompt_input.go
+++ b/cmd/prompt_input.go
@@ -7,9 +7,9 @@ import (
"os"
"strings"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
- "github.com/GrayCodeAI/rho/internal/permissions/stableid"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/permissions/stableid"
)
var errNoInteractivePromptInput = errors.New("no interactive terminal available for permission prompt")
diff --git a/cmd/prompt_input_test.go b/cmd/prompt_input_test.go
index 31ad81cf5..49fc90f26 100644
--- a/cmd/prompt_input_test.go
+++ b/cmd/prompt_input_test.go
@@ -5,11 +5,11 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/contracts/policy"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
- "github.com/GrayCodeAI/rho/internal/permissions"
- "github.com/GrayCodeAI/rho/internal/permissions/stableid"
+ "github.com/GrayCodeAI/decoder/internal/contracts/policy"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/permissions"
+ "github.com/GrayCodeAI/decoder/internal/permissions/stableid"
)
func TestConfigureInteractivePromptsSessionApprovalIsScoped(t *testing.T) {
diff --git a/cmd/record.go b/cmd/record.go
index f268d6824..e0505172f 100644
--- a/cmd/record.go
+++ b/cmd/record.go
@@ -4,7 +4,7 @@ import (
"io"
"os"
- "github.com/GrayCodeAI/rho/internal/terminal/tape"
+ "github.com/GrayCodeAI/decoder/internal/terminal/tape"
)
// recordPath is set by --record; when non-empty, interactive REPL output is
diff --git a/cmd/record_test.go b/cmd/record_test.go
index 7e505da9f..d946ae1f3 100644
--- a/cmd/record_test.go
+++ b/cmd/record_test.go
@@ -6,7 +6,7 @@ import (
"path/filepath"
"testing"
- "github.com/GrayCodeAI/rho/internal/terminal/tape"
+ "github.com/GrayCodeAI/decoder/internal/terminal/tape"
)
func TestStartRecordingCapturesOutput(t *testing.T) {
diff --git a/cmd/resize_unix.go b/cmd/resize_unix.go
index 514a6dcc8..2b33c1b18 100644
--- a/cmd/resize_unix.go
+++ b/cmd/resize_unix.go
@@ -7,7 +7,7 @@ import (
"os/signal"
"syscall"
- "github.com/GrayCodeAI/rho/internal/terminal/tape"
+ "github.com/GrayCodeAI/decoder/internal/terminal/tape"
)
// watchTerminalResize records terminal resize (SIGWINCH) events into the tape
diff --git a/cmd/resize_windows.go b/cmd/resize_windows.go
index e52743d7c..ca835e8b4 100644
--- a/cmd/resize_windows.go
+++ b/cmd/resize_windows.go
@@ -2,7 +2,7 @@
package cmd
-import "github.com/GrayCodeAI/rho/internal/terminal/tape"
+import "github.com/GrayCodeAI/decoder/internal/terminal/tape"
// watchTerminalResize is a no-op on Windows, where SIGWINCH is not defined.
func watchTerminalResize(rec *tape.Recorder) func() {
diff --git a/cmd/review.go b/cmd/review.go
index 44370a883..5e5ca9df8 100644
--- a/cmd/review.go
+++ b/cmd/review.go
@@ -10,17 +10,17 @@ import (
"github.com/spf13/cobra"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
var reviewCmd = &cobra.Command{
Use: "review",
Short: "Continuous AI code review on commits",
- Long: `rho review provides continuous background code review.
+ Long: `decoder review provides continuous background code review.
-Run 'rho review init' to install a post-commit hook, then every commit
-is automatically reviewed. View findings with 'rho review tui'
-or fix them with 'rho review fix'.`,
+Run 'decoder review init' to install a post-commit hook, then every commit
+is automatically reviewed. View findings with 'decoder review tui'
+or fix them with 'decoder review fix'.`,
}
var reviewInitCmd = &cobra.Command{
@@ -38,10 +38,10 @@ func init() {
}
const hookScript = `#!/bin/sh
-# rho review — continuous code review hook
-# Installed by 'rho review init'
+# decoder review — continuous code review hook
+# Installed by 'decoder review init'
SHA=$(git rev-parse HEAD)
-rho review run "$SHA" --background &
+decoder review run "$SHA" --background &
`
func runReviewInit(_ *cobra.Command, _ []string) error {
@@ -60,8 +60,8 @@ func runReviewInit(_ *cobra.Command, _ []string) error {
// Check for existing hook.
if _, err := os.Stat(hookPath); err == nil && !reviewInitForce {
existing, _ := os.ReadFile(hookPath) // #nosec G304 -- hookPath built from internal hooksDir constant, not external input
- if strings.Contains(string(existing), "rho review") {
- fmt.Println(auditTint(icons.CheckBold()+" ", doneGreen) + auditTint("rho review hook already installed", textPrimary))
+ if strings.Contains(string(existing), "decoder review") {
+ fmt.Println(auditTint(icons.CheckBold()+" ", doneGreen) + auditTint("decoder review hook already installed", textPrimary))
return nil
}
return fmt.Errorf("post-commit hook already exists at %s\nUse --force to overwrite, or manually add:\n %s", hookPath, strings.TrimSpace(hookScript))
@@ -74,8 +74,8 @@ func runReviewInit(_ *cobra.Command, _ []string) error {
fmt.Println(auditTint(icons.CheckBold()+" ", doneGreen) + auditTint("Installed post-commit hook at ", textPrimary) + auditTint(hookPath, textMuted))
fmt.Println(auditTint(" Every commit will now be reviewed automatically.", textMuted))
- fmt.Println(auditTint(" View reviews: rho review status", textMuted))
- fmt.Println(auditTint(" Interactive: rho review tui", textMuted))
+ fmt.Println(auditTint(" View reviews: decoder review status", textMuted))
+ fmt.Println(auditTint(" Interactive: decoder review tui", textMuted))
return nil
}
diff --git a/cmd/review_fix.go b/cmd/review_fix.go
index d74770569..e1c5c7d17 100644
--- a/cmd/review_fix.go
+++ b/cmd/review_fix.go
@@ -10,7 +10,7 @@ import (
"github.com/spf13/cobra"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
var (
@@ -21,8 +21,8 @@ var (
var reviewFixCmd = &cobra.Command{
Use: "fix [id...]",
- Short: "Auto-fix review findings using rho exec",
- Long: `Feeds review findings to rho's engine which applies fixes and commits.
+ Short: "Auto-fix review findings using decoder exec",
+ Long: `Feeds review findings to decoder's engine which applies fixes and commits.
Without arguments, fixes all open reviews. Specify IDs to fix specific ones.`,
RunE: runReviewFix,
}
@@ -82,7 +82,7 @@ func fixReview(store *ReviewStore, r *ReviewRecord) error {
prompt := buildFixPrompt(r)
- // Invoke rho exec with the fix prompt.
+ // Invoke decoder exec with the fix prompt.
execArgs := []string{"exec", "--auto", "full"}
if reviewFixWorktree {
execArgs = append(execArgs, "--worktree")
@@ -92,18 +92,18 @@ func fixReview(store *ReviewStore, r *ReviewRecord) error {
}
execArgs = append(execArgs, prompt)
- rhoBin, err := os.Executable()
+ decoderBin, err := os.Executable()
if err != nil {
- rhoBin = "rho"
+ decoderBin = "decoder"
}
- cmd := exec.CommandContext(context.Background(), rhoBin, execArgs...) // #nosec G204 -- rhoBin resolved via os.Executable() or literal 'rho'; args are internal flags
+ cmd := exec.CommandContext(context.Background(), decoderBin, execArgs...) // #nosec G204 -- decoderBin resolved via os.Executable() or literal 'decoder'; args are internal flags
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
if err := cmd.Run(); err != nil {
- return fmt.Errorf("rho exec: %w", err)
+ return fmt.Errorf("decoder exec: %w", err)
}
// Mark as fixed.
diff --git a/cmd/review_pipeline.go b/cmd/review_pipeline.go
index f1b559fa7..4abad8269 100644
--- a/cmd/review_pipeline.go
+++ b/cmd/review_pipeline.go
@@ -3,7 +3,7 @@ package cmd
import (
"context"
- reviewfeature "github.com/GrayCodeAI/rho/internal/features/review"
+ reviewfeature "github.com/GrayCodeAI/decoder/internal/features/review"
)
// Compatibility aliases keep existing command and workflow code stable while
diff --git a/cmd/review_read.go b/cmd/review_read.go
index 2d518d8f4..84fefd983 100644
--- a/cmd/review_read.go
+++ b/cmd/review_read.go
@@ -10,8 +10,8 @@ import (
"github.com/spf13/cobra"
- contracts "github.com/GrayCodeAI/rho/internal/contracts/types"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ contracts "github.com/GrayCodeAI/decoder/internal/contracts/types"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
var reviewStatusCmd = &cobra.Command{
@@ -72,7 +72,7 @@ func runReviewStatus(_ *cobra.Command, _ []string) error {
total += v
}
if total == 0 {
- fmt.Println(auditTint("No reviews yet. Run 'rho review init' to start.", textMuted))
+ fmt.Println(auditTint("No reviews yet. Run 'decoder review init' to start.", textMuted))
return nil
}
diff --git a/cmd/review_refine.go b/cmd/review_refine.go
index 3ff008546..b169f0dad 100644
--- a/cmd/review_refine.go
+++ b/cmd/review_refine.go
@@ -10,7 +10,7 @@ import (
"github.com/spf13/cobra"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
var (
@@ -69,7 +69,7 @@ func runReviewRefine(_ *cobra.Command, args []string) error {
fmt.Printf("%s\n\n", auditTint(fmt.Sprintf("Refining %d review(s), max %d iterations...", len(reviews), refineMaxIter), textPrimary))
for iter := 1; iter <= refineMaxIter; iter++ {
- fmt.Printf("%s\n", auditTint(fmt.Sprintf("── Iteration %d/%d ──", iter, refineMaxIter), rhoColor))
+ fmt.Printf("%s\n", auditTint(fmt.Sprintf("── Iteration %d/%d ──", iter, refineMaxIter), decoderColor))
// Fix all open reviews.
for _, r := range reviews {
@@ -129,7 +129,7 @@ func runReviewRefine(_ *cobra.Command, args []string) error {
}
if len(remaining) > 0 {
fmt.Printf("\n%s %s\n", auditTint(icons.Alert(), warnAmber), auditTint(fmt.Sprintf("%d review(s) still open after %d iterations.", len(remaining), refineMaxIter), textPrimary))
- fmt.Println(auditTint(" Run 'rho review show' to inspect, or increase --max-iterations.", textMuted))
+ fmt.Println(auditTint(" Run 'decoder review show' to inspect, or increase --max-iterations.", textMuted))
}
return nil
}
@@ -137,9 +137,9 @@ func runReviewRefine(_ *cobra.Command, args []string) error {
func fixReviewRefine(store *ReviewStore, r *ReviewRecord) error {
prompt := buildFixPrompt(r)
- rhoBin, err := os.Executable()
+ decoderBin, err := os.Executable()
if err != nil {
- rhoBin = "rho"
+ decoderBin = "decoder"
}
execArgs := []string{"exec", "--auto", "full"}
@@ -148,7 +148,7 @@ func fixReviewRefine(store *ReviewStore, r *ReviewRecord) error {
}
execArgs = append(execArgs, prompt)
- cmd := exec.CommandContext(context.Background(), rhoBin, execArgs...) // #nosec G204 -- rhoBin resolved via os.Executable() or literal 'rho'; args are internal flags
+ cmd := exec.CommandContext(context.Background(), decoderBin, execArgs...) // #nosec G204 -- decoderBin resolved via os.Executable() or literal 'decoder'; args are internal flags
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@@ -159,9 +159,9 @@ func fixReviewRefine(store *ReviewStore, r *ReviewRecord) error {
}
func runReviewOnSHA(store *ReviewStore, sha string) error {
- rhoBin, err := os.Executable()
+ decoderBin, err := os.Executable()
if err != nil {
- rhoBin = "rho"
+ decoderBin = "decoder"
}
args := []string{"review", "run", sha}
@@ -172,7 +172,7 @@ func runReviewOnSHA(store *ReviewStore, sha string) error {
args = append(args, "--model", refineModel)
}
- cmd := exec.CommandContext(context.Background(), rhoBin, args...) // #nosec G204 -- rhoBin resolved via os.Executable() or literal 'rho'; args are internal flags
+ cmd := exec.CommandContext(context.Background(), decoderBin, args...) // #nosec G204 -- decoderBin resolved via os.Executable() or literal 'decoder'; args are internal flags
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
diff --git a/cmd/review_run.go b/cmd/review_run.go
index 2b4424741..1172fc282 100644
--- a/cmd/review_run.go
+++ b/cmd/review_run.go
@@ -8,12 +8,12 @@ import (
"strings"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- reviewcontracts "github.com/GrayCodeAI/rho/internal/contracts/review"
- contracts "github.com/GrayCodeAI/rho/internal/contracts/types"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/types"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ reviewcontracts "github.com/GrayCodeAI/decoder/internal/contracts/review"
+ contracts "github.com/GrayCodeAI/decoder/internal/contracts/types"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/types"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
"github.com/spf13/cobra"
)
@@ -121,9 +121,9 @@ func runReviewRun(_ *cobra.Command, args []string) error {
}
}
- // Resolve the provider through Rho's Flux engine boundary.
+ // Resolve the provider through Decoder's Mux engine boundary.
ctx := context.Background()
- selection := rhoconfig.EffectiveSelection(ctx, rhoconfig.SelectionOptions{
+ selection := decoderconfig.EffectiveSelection(ctx, decoderconfig.SelectionOptions{
ProviderOverride: strings.TrimSpace(provider),
ModelOverride: strings.TrimSpace(reviewRunModel),
})
@@ -144,7 +144,7 @@ func runReviewRun(_ *cobra.Command, args []string) error {
defer cancel()
}
- // Run Rho's own multi-concern review pipeline through the provider.
+ // Run Decoder's own multi-concern review pipeline through the provider.
concerns := DefaultConcerns()
if strings.TrimSpace(reviewRunConcerns) != "" {
wanted := map[string]bool{}
@@ -169,7 +169,7 @@ func runReviewRun(_ *cobra.Command, args []string) error {
model = reviewRunModel
}
chatFn := func(chatCtx context.Context, prompt string) (string, error) {
- resp, chatErr := chatProvider.Chat(chatCtx, []types.FluxMessage{{Role: "user", Content: prompt}}, types.ChatOptions{
+ resp, chatErr := chatProvider.Chat(chatCtx, []types.MuxMessage{{Role: "user", Content: prompt}}, types.ChatOptions{
Provider: providerID,
Model: model,
})
diff --git a/cmd/review_store.go b/cmd/review_store.go
index 0d4bb8c9b..910a0b71e 100644
--- a/cmd/review_store.go
+++ b/cmd/review_store.go
@@ -10,8 +10,8 @@ import (
"sync"
"time"
- reviewcontracts "github.com/GrayCodeAI/rho/internal/contracts/review"
- "github.com/GrayCodeAI/rho/internal/storage"
+ reviewcontracts "github.com/GrayCodeAI/decoder/internal/contracts/review"
+ "github.com/GrayCodeAI/decoder/internal/storage"
)
// ReviewStatus represents the state of a review.
diff --git a/cmd/review_test.go b/cmd/review_test.go
index bd1e69853..d780790ab 100644
--- a/cmd/review_test.go
+++ b/cmd/review_test.go
@@ -6,11 +6,11 @@ import (
"strings"
"testing"
- reviewcontracts "github.com/GrayCodeAI/rho/internal/contracts/review"
- contracts "github.com/GrayCodeAI/rho/internal/contracts/types"
+ reviewcontracts "github.com/GrayCodeAI/decoder/internal/contracts/review"
+ contracts "github.com/GrayCodeAI/decoder/internal/contracts/types"
- "github.com/GrayCodeAI/rho/internal/storage"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
func setReviewTestDirs(t *testing.T) string {
@@ -22,7 +22,7 @@ func setReviewTestDirs(t *testing.T) string {
func TestReviewStore_CreateAndGet(t *testing.T) {
dir := setReviewTestDirs(t)
- os.MkdirAll(filepath.Join(dir, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(dir, ".decoder"), 0o755)
store, err := OpenReviewStore(dir)
if err != nil {
@@ -52,7 +52,7 @@ func TestReviewStore_CreateAndGet(t *testing.T) {
func TestReviewStore_Update(t *testing.T) {
dir := setReviewTestDirs(t)
- os.MkdirAll(filepath.Join(dir, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(dir, ".decoder"), 0o755)
store, err := OpenReviewStore(dir)
if err != nil {
@@ -92,7 +92,7 @@ func TestReviewStore_Update(t *testing.T) {
func TestReviewStore_GetBySHA(t *testing.T) {
dir := setReviewTestDirs(t)
- os.MkdirAll(filepath.Join(dir, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(dir, ".decoder"), 0o755)
store, err := OpenReviewStore(dir)
if err != nil {
@@ -114,7 +114,7 @@ func TestReviewStore_GetBySHA(t *testing.T) {
func TestReviewStore_ListOpen(t *testing.T) {
dir := setReviewTestDirs(t)
- os.MkdirAll(filepath.Join(dir, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(dir, ".decoder"), 0o755)
store, err := OpenReviewStore(dir)
if err != nil {
@@ -141,7 +141,7 @@ func TestReviewStore_ListOpen(t *testing.T) {
func TestReviewStore_Summary(t *testing.T) {
dir := setReviewTestDirs(t)
- os.MkdirAll(filepath.Join(dir, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(dir, ".decoder"), 0o755)
store, err := OpenReviewStore(dir)
if err != nil {
@@ -171,7 +171,7 @@ func TestReviewStore_Summary(t *testing.T) {
func TestReviewStore_SetStatus(t *testing.T) {
dir := setReviewTestDirs(t)
- os.MkdirAll(filepath.Join(dir, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(dir, ".decoder"), 0o755)
store, err := OpenReviewStore(dir)
if err != nil {
@@ -191,7 +191,7 @@ func TestReviewStore_SetStatus(t *testing.T) {
func TestReviewStore_ListAll(t *testing.T) {
dir := setReviewTestDirs(t)
- os.MkdirAll(filepath.Join(dir, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(dir, ".decoder"), 0o755)
store, err := OpenReviewStore(dir)
if err != nil {
@@ -222,7 +222,7 @@ func TestReviewStore_ListAll(t *testing.T) {
func TestReviewStore_GetMissing(t *testing.T) {
dir := setReviewTestDirs(t)
- os.MkdirAll(filepath.Join(dir, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(dir, ".decoder"), 0o755)
store, err := OpenReviewStore(dir)
if err != nil {
@@ -239,7 +239,7 @@ func TestReviewStore_GetMissing(t *testing.T) {
func TestReviewStore_EmptyDiffToPassedLifecycle(t *testing.T) {
// Mirrors runReviewRun's empty-diff path: create → set running → set passed.
dir := setReviewTestDirs(t)
- os.MkdirAll(filepath.Join(dir, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(dir, ".decoder"), 0o755)
store, err := OpenReviewStore(dir)
if err != nil {
@@ -278,7 +278,7 @@ func TestReviewStore_EmptyDiffToPassedLifecycle(t *testing.T) {
func TestReviewStore_CloseCheckpointsWAL(t *testing.T) {
dir := setReviewTestDirs(t)
- os.MkdirAll(filepath.Join(dir, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(dir, ".decoder"), 0o755)
store, err := OpenReviewStore(dir)
if err != nil {
@@ -356,9 +356,9 @@ func TestStatusIcon(t *testing.T) {
}
}
-func TestHookScript_ContainsRhoReview(t *testing.T) {
- if !strings.Contains(hookScript, "rho review") {
- t.Error("hook script should contain 'rho review'")
+func TestHookScript_ContainsDecoderReview(t *testing.T) {
+ if !strings.Contains(hookScript, "decoder review") {
+ t.Error("hook script should contain 'decoder review'")
}
if !strings.Contains(hookScript, "git rev-parse HEAD") {
t.Error("hook script should get HEAD sha")
diff --git a/cmd/review_tui.go b/cmd/review_tui.go
index 2922e4ae1..ac67691aa 100644
--- a/cmd/review_tui.go
+++ b/cmd/review_tui.go
@@ -9,7 +9,7 @@ import (
lipgloss "charm.land/lipgloss/v2"
"github.com/spf13/cobra"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
var reviewTUICmd = &cobra.Command{
@@ -122,16 +122,16 @@ func (m reviewTUIModel) View() tea.View {
return tea.View{}
}
- header := lipgloss.NewStyle().Bold(true).Foreground(rhoColor)
+ header := lipgloss.NewStyle().Bold(true).Foreground(decoderColor)
dim := lipgloss.NewStyle().Faint(true)
selected := lipgloss.NewStyle().Bold(true).Background(bgCode).Foreground(textPrimary)
var b strings.Builder
- b.WriteString(header.Render(" rho review") + dim.Render(" j/k:nav enter:expand c:close f:fix r:refresh q:quit") + "\n")
+ b.WriteString(header.Render(" decoder review") + dim.Render(" j/k:nav enter:expand c:close f:fix r:refresh q:quit") + "\n")
b.WriteString(strings.Repeat("─", reviewMin(m.width, 80)) + "\n")
if len(m.reviews) == 0 {
- b.WriteString("\n No reviews yet. Run 'rho review init' to get started.\n")
+ b.WriteString("\n No reviews yet. Run 'decoder review init' to get started.\n")
v := tea.View{Content: b.String()}
v.AltScreen = true
return v
diff --git a/cmd/root.go b/cmd/root.go
index 045d4f074..e09ea4d7e 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -12,13 +12,13 @@ import (
"sync"
"time"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/onboarding"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/tool"
- "github.com/GrayCodeAI/rho/internal/update"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/onboarding"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/update"
"github.com/spf13/cobra"
)
@@ -88,38 +88,38 @@ func SetBuildDate(d string) {
}
func registeredProviderCount() int {
- return rhoconfig.RegisteredProviderCount()
+ return decoderconfig.RegisteredProviderCount()
}
var rootCmd = &cobra.Command{
- Use: "rho [prompt]",
- Short: "AI coding agent powered by flux",
- Long: fmt.Sprintf(`rho is an AI coding agent that reads, writes, and runs code in your terminal.
+ Use: "decoder [prompt]",
+ Short: "AI coding agent powered by mux",
+ Long: fmt.Sprintf(`decoder is an AI coding agent that reads, writes, and runs code in your terminal.
-It connects to %d first-class LLM providers through flux, executes tools (file I/O, shell,
+It connects to %d first-class LLM providers through mux, executes tools (file I/O, shell,
git, web search), and manages sessions — all from a keyboard-driven TUI or
headless mode for scripts and CI.
Quick orientation:
- rho Start interactive TUI
- rho -p "prompt" One-shot: send prompt, print response, exit
- rho exec "task" Autonomous multi-turn execution
- rho path Check environment readiness
- rho doctor Run diagnostics
- rho config Manage settings and credentials
+ decoder Start interactive TUI
+ decoder -p "prompt" One-shot: send prompt, print response, exit
+ decoder exec "task" Autonomous multi-turn execution
+ decoder path Check environment readiness
+ decoder doctor Run diagnostics
+ decoder config Manage settings and credentials
API keys are stored in the OS keychain (macOS Keychain / Linux keyring).
-Run rho and use /config to set up your first provider.`, registeredProviderCount()),
- Example: ` rho
- rho -p "explain this repo"
- rho exec "fix failing tests"
- rho preflight
- rho path`,
+Run decoder and use /config to set up your first provider.`, registeredProviderCount()),
+ Example: ` decoder
+ decoder -p "explain this repo"
+ decoder exec "fix failing tests"
+ decoder preflight
+ decoder path`,
Args: cobra.ArbitraryArgs,
SilenceUsage: true,
SilenceErrors: true,
// --cwd is a persistent flag, so apply it before any subcommand runs —
- // not just the bare root command. This keeps `rho --cwd X ` working
+ // not just the bare root command. This keeps `decoder --cwd X ` working
// and validates the path once, early.
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return applyCwdFlag()
@@ -171,7 +171,7 @@ Run rho and use /config to set up your first provider.`, registeredProviderCount
// the TUI, so gate them identically: untrusted folders block
// project automation.
if tr := engine.ProjectTrust(""); tr.Blocked {
- return fmt.Errorf("cannot start: folder not trusted (%s)\nProject-scoped hooks, MCP servers, and custom specialists are blocked.\nRun 'rho trust add' to trust this folder before running rho", tr.Path)
+ return fmt.Errorf("cannot start: folder not trusted (%s)\nProject-scoped hooks, MCP servers, and custom specialists are blocked.\nRun 'decoder trust add' to trust this folder before running decoder", tr.Path)
}
if replFlag {
return runRepl()
@@ -220,7 +220,7 @@ Run rho and use /config to set up your first provider.`, registeredProviderCount
}
func init() {
- rootCmd.Flags().StringVarP(&model, "model", "m", "", "model to use (from flux catalog; see /models)")
+ rootCmd.Flags().StringVarP(&model, "model", "m", "", "model to use (from mux catalog; see /models)")
rootCmd.Flags().BoolVarP(&printMode, "print", "p", false, "print response and exit")
rootCmd.Flags().StringVar(&promptFlag, "prompt", "", "send a single prompt and exit (legacy alias for --print)")
rootCmd.Flags().StringVar(&outputFormat, "output-format", "text", `output format for --print: "text", "json", "stream-json", or "transcript"`)
@@ -260,7 +260,7 @@ func init() {
rootCmd.Flags().IntVar(&teachDepth, "teach-depth", 2, "explanation depth: 1=what, 2=why, 3=how")
rootCmd.Flags().BoolVar(&autoSkillFlag, "auto-skill", false, "auto-detect project and install matching skills")
rootCmd.Flags().BoolVarP(&versionFlag, "version", "v", false, "output the version number")
- rootCmd.Flags().BoolVar(&refreshCatalogFlag, "refresh-catalog", false, "refresh the flux model catalog before starting")
+ rootCmd.Flags().BoolVar(&refreshCatalogFlag, "refresh-catalog", false, "refresh the mux model catalog before starting")
rootCmd.Flags().BoolVar(&skipCatalogRefreshFlag, "no-auto-catalog-refresh", false, "disable automatic catalog refresh when cache is missing, empty, or stale")
rootCmd.Flags().BoolVar(&recoverFlag, "recover", false, "scan for interrupted sessions and offer to resume")
rootCmd.Flags().BoolVar(&startupProfileFlag, "startup-profile", false, "print startup performance profile")
@@ -431,7 +431,7 @@ func groupRootCommands() {
// In a terminal, it requires typing the full confirmation token (not a single
// key) so a stray keystroke or terminal-escape trickery cannot confirm it. In
// non-interactive mode (CI, scripts), it requires the
-// RHO_DANGEROUSLY_SKIP_PERMISSIONS=1 environment variable.
+// DECODER_DANGEROUSLY_SKIP_PERMISSIONS=1 environment variable.
func confirmDangerousSkipPermissions() error {
if isStdinTerminal() {
fmt.Fprintf(os.Stderr, "Type %s to confirm skipping permission prompts: ", dangerSkipConfirmToken)
@@ -446,8 +446,8 @@ func confirmDangerousSkipPermissions() error {
return nil
}
// Non-interactive: require explicit env var override.
- if os.Getenv("RHO_DANGEROUSLY_SKIP_PERMISSIONS") != "1" {
- return fmt.Errorf("--dangerously-skip-permissions requires RHO_DANGEROUSLY_SKIP_PERMISSIONS=1 in non-interactive mode")
+ if os.Getenv("DECODER_DANGEROUSLY_SKIP_PERMISSIONS") != "1" {
+ return fmt.Errorf("--dangerously-skip-permissions requires DECODER_DANGEROUSLY_SKIP_PERMISSIONS=1 in non-interactive mode")
}
return nil
}
@@ -471,31 +471,31 @@ var completionCmd = &cobra.Command{
Long: `To load completions:
Bash:
- source <(rho completion bash)
+ source <(decoder completion bash)
# To load completions for each session, execute once:
# Linux:
- rho completion bash > /etc/bash_completion.d/rho
+ decoder completion bash > /etc/bash_completion.d/decoder
# macOS:
- rho completion bash > /usr/local/etc/bash_completion.d/rho
+ decoder completion bash > /usr/local/etc/bash_completion.d/decoder
Zsh:
- source <(rho completion zsh)
+ source <(decoder completion zsh)
# To load completions for each session, execute once:
- rho completion zsh > "${fpath[1]}/_rho"
+ decoder completion zsh > "${fpath[1]}/_decoder"
Fish:
- rho completion fish | source
+ decoder completion fish | source
# To load completions for each session, execute once:
- rho completion fish > ~/.config/fish/completions/rho.fish
+ decoder completion fish > ~/.config/fish/completions/decoder.fish
PowerShell:
- rho completion powershell | Out-String | Invoke-Expression
+ decoder completion powershell | Out-String | Invoke-Expression
# To load completions for every new session, run:
- rho completion powershell > rho.ps1
+ decoder completion powershell > decoder.ps1
# and source this file from your PowerShell profile.
JSON:
- rho completion json
+ decoder completion json
# Print a machine-readable command/flag spec for IDE integration.
`,
DisableFlagsInUseLine: true,
@@ -529,17 +529,17 @@ var completionInstallCmd = &cobra.Command{
Long: `Install the shell completion script to the standard location for your OS.
Bash:
- rho completion install bash
- # Installs to ~/.local/share/bash-completion/completions/rho (Linux)
- # or /opt/homebrew/etc/bash_completion.d/rho (macOS Homebrew)
+ decoder completion install bash
+ # Installs to ~/.local/share/bash-completion/completions/decoder (Linux)
+ # or /opt/homebrew/etc/bash_completion.d/decoder (macOS Homebrew)
Zsh:
- rho completion install zsh
- # Installs to the first directory in $fpath (e.g. /usr/local/share/zsh/site-functions/_rho)
+ decoder completion install zsh
+ # Installs to the first directory in $fpath (e.g. /usr/local/share/zsh/site-functions/_decoder)
Fish:
- rho completion install fish
- # Installs to ~/.config/fish/completions/rho.fish`,
+ decoder completion install fish
+ # Installs to ~/.config/fish/completions/decoder.fish`,
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish"},
Args: cobra.ExactArgs(1),
@@ -581,11 +581,11 @@ Fish:
var updateCmd = &cobra.Command{
Use: "update",
- Short: "Check for rho updates",
- Long: "Check GitHub for a newer rho release and print upgrade instructions.",
+ Short: "Check for decoder updates",
+ Long: "Check GitHub for a newer decoder release and print upgrade instructions.",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
- // Same resolution as `rho --version`, so `go install ...@vX.Y.Z` and
+ // Same resolution as `decoder --version`, so `go install ...@vX.Y.Z` and
// source builds compare their real version instead of "dev".
ver := DisplayVersion()
prog := NewCLIProgress("Update check", []string{"Checking GitHub for updates"})
@@ -599,7 +599,7 @@ var updateCmd = &cobra.Command{
return nil
}
if release == nil {
- cmd.Println(auditTint("rho is up to date ("+ver+")", doneGreen))
+ cmd.Println(auditTint("decoder is up to date ("+ver+")", doneGreen))
return nil
}
cmd.Println(auditTint("Update available: ", warnAmber) + auditTint(ver+" -> "+release.TagName, textPrimary))
@@ -621,13 +621,13 @@ API keys and secrets are never included.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
var b strings.Builder
- b.WriteString("## rho bug report\n\n")
+ b.WriteString("## decoder bug report\n\n")
b.WriteString(fmt.Sprintf("- **Version:** %s\n", versionLine()))
b.WriteString(fmt.Sprintf("- **Platform:** %s\n", update.Platform()))
b.WriteString(fmt.Sprintf("- **Go:** %s\n", runtime.Version()))
b.WriteString(fmt.Sprintf("- **OS/Arch:** %s/%s\n", runtime.GOOS, runtime.GOARCH))
b.WriteString("\n## Doctor output\n\n```\n")
- settings := rhoconfig.LoadSettings()
+ settings := decoderconfig.LoadSettings()
b.WriteString(doctorReport(settings))
b.WriteString("\n```\n")
cmd.Print(b.String())
@@ -645,7 +645,7 @@ var versionJSON bool
var versionCmd = &cobra.Command{
Use: "version",
- Short: "Print rho version",
+ Short: "Print decoder version",
Run: func(cmd *cobra.Command, args []string) {
if versionJSON {
info := versionInfo{Version: DisplayVersion()}
@@ -682,7 +682,7 @@ var setupCmd = &cobra.Command{
var initCmd = &cobra.Command{
Use: "init",
Short: "Interactive onboarding wizard for first-time setup",
- Long: "Launch the interactive setup wizard to configure credentials, select providers/models, and initialize rho.",
+ Long: "Launch the interactive setup wizard to configure credentials, select providers/models, and initialize decoder.",
RunE: func(cmd *cobra.Command, args []string) error {
onboarding.Welcome(version)
return onboarding.RunSetup()
@@ -746,7 +746,7 @@ var preflightCmd = &cobra.Command{
defer prog.Abort()
prog.StartStep(0)
}
- r := rhoconfig.EnginePreflightReportWithSettings(ctx, settings, rhoconfig.EnginePreflightOptions{VerifyLive: preflightLiveFlag})
+ r := decoderconfig.EnginePreflightReportWithSettings(ctx, settings, decoderconfig.EnginePreflightOptions{VerifyLive: preflightLiveFlag})
if prog != nil {
prog.CompleteStep(0)
prog.Done()
@@ -758,14 +758,14 @@ var preflightCmd = &cobra.Command{
}
cmd.Println(string(out))
} else {
- out := rhoconfig.FormatEnginePreflight(r)
+ out := decoderconfig.FormatEnginePreflight(r)
cmd.Println(out)
}
if !r.Ready {
if preflightLiveFlag {
return fmt.Errorf("live preflight failed — check the selected provider credential and network access")
}
- return fmt.Errorf("preflight failed — run rho and complete /config")
+ return fmt.Errorf("preflight failed — run decoder and complete /config")
}
return nil
},
@@ -775,10 +775,10 @@ var preflightCmd = &cobra.Command{
// showing a modern old → new transition when the value actually changed.
// Settable keys are non-secret (API keys error out before reaching here),
// so displaying the prior value cannot leak a secret.
-func printConfigSetResult(cmd *cobra.Command, key, newVal string, settings rhoconfig.Settings) {
- oldVal, hadOld := rhoconfig.SettingValue(settings, key)
+func printConfigSetResult(cmd *cobra.Command, key, newVal string, settings decoderconfig.Settings) {
+ oldVal, hadOld := decoderconfig.SettingValue(settings, key)
if hadOld && oldVal != "" && oldVal != newVal {
- cmd.Println(auditTint(key, textPrimary) + auditTint(": ", textMuted) + auditTint(oldVal, textMuted) + auditTint(" → ", rhoColor) + auditTint(newVal, textPrimary) + auditTint(" (updated)", doneGreen))
+ cmd.Println(auditTint(key, textPrimary) + auditTint(": ", textMuted) + auditTint(oldVal, textMuted) + auditTint(" → ", decoderColor) + auditTint(newVal, textPrimary) + auditTint(" (updated)", doneGreen))
return
}
cmd.Println(auditTint("updated ", doneGreen) + auditTint(key, textPrimary))
@@ -792,13 +792,13 @@ var configCmd = &cobra.Command{
switch args[0] {
case "get":
if len(args) != 2 {
- return fmt.Errorf("usage: rho config get ")
+ return fmt.Errorf("usage: decoder config get ")
}
settings, err := loadEffectiveSettings()
if err != nil {
return err
}
- value, ok := rhoconfig.SettingValue(settings, args[1])
+ value, ok := decoderconfig.SettingValue(settings, args[1])
if !ok {
return fmt.Errorf("unsupported setting key %q", args[1])
}
@@ -810,7 +810,7 @@ var configCmd = &cobra.Command{
return nil
case "set":
if len(args) < 3 {
- return fmt.Errorf("usage: rho config set ")
+ return fmt.Errorf("usage: decoder config set ")
}
key := args[1]
newVal := strings.Join(args[2:], " ")
@@ -818,35 +818,35 @@ var configCmd = &cobra.Command{
if err != nil {
return err
}
- if err := rhoconfig.SetGlobalSetting(key, newVal); err != nil {
+ if err := decoderconfig.SetGlobalSetting(key, newVal); err != nil {
return err
}
printConfigSetResult(cmd, key, newVal, settings)
return nil
case "provider":
if len(args) < 2 {
- return fmt.Errorf("usage: rho config provider ")
+ return fmt.Errorf("usage: decoder config provider ")
}
newVal := strings.Join(args[1:], " ")
settings, err := loadEffectiveSettings()
if err != nil {
return err
}
- if err := rhoconfig.SetGlobalSetting("provider", newVal); err != nil {
+ if err := decoderconfig.SetGlobalSetting("provider", newVal); err != nil {
return err
}
printConfigSetResult(cmd, "provider", newVal, settings)
return nil
case "model":
if len(args) < 2 {
- return fmt.Errorf("usage: rho config model ")
+ return fmt.Errorf("usage: decoder config model ")
}
newVal := strings.Join(args[1:], " ")
settings, err := loadEffectiveSettings()
if err != nil {
return err
}
- if err := rhoconfig.SetGlobalSetting("model", newVal); err != nil {
+ if err := decoderconfig.SetGlobalSetting("model", newVal); err != nil {
return err
}
printConfigSetResult(cmd, "model", newVal, settings)
@@ -856,13 +856,13 @@ var configCmd = &cobra.Command{
return nil
case "routing-preview":
if len(args) < 2 {
- return fmt.Errorf("usage: rho config routing-preview ")
+ return fmt.Errorf("usage: decoder config routing-preview ")
}
settings, err := loadEffectiveSettings()
if err != nil {
return err
}
- out, err := rhoconfig.RoutingPreviewJSONWithSettings(cmd.Context(), settings, strings.Join(args[1:], " "))
+ out, err := decoderconfig.RoutingPreviewJSONWithSettings(cmd.Context(), settings, strings.Join(args[1:], " "))
if err != nil {
return err
}
@@ -883,10 +883,10 @@ var configCmd = &cobra.Command{
var mcpCmd = &cobra.Command{
Use: "mcp",
- Short: "Show MCP configuration; run or register rho as an MCP server",
- Long: "With no subcommand, summarizes the MCP servers rho connects to (consumes).\n" +
- " rho mcp serve — run rho itself as an MCP server over stdio\n" +
- " rho mcp config — print the JSON block to register rho in Claude Desktop/Cursor/Windsurf",
+ Short: "Show MCP configuration; run or register decoder as an MCP server",
+ Long: "With no subcommand, summarizes the MCP servers decoder connects to (consumes).\n" +
+ " decoder mcp serve — run decoder itself as an MCP server over stdio\n" +
+ " decoder mcp config — print the JSON block to register decoder in Claude Desktop/Cursor/Windsurf",
RunE: func(cmd *cobra.Command, args []string) error {
settings, err := loadEffectiveSettings()
if err != nil {
@@ -968,7 +968,7 @@ var (
var researchCmd = &cobra.Command{
Use: "research [flags] ",
Short: "Autonomous research loop (Karpathy autoresearch pattern)",
- Long: "rho research --grep '^val_bpb:' --direction lower 'uv run train.py'",
+ Long: "decoder research --grep '^val_bpb:' --direction lower 'uv run train.py'",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return fmt.Errorf("metric command is required")
@@ -1092,9 +1092,9 @@ var recoverCmd = &cobra.Command{
and offer to resume them. If a session-id is provided, resume that specific session.
Examples:
- rho recover # List interrupted sessions
- rho recover abc123 # Resume specific session
- rho --recover # Auto-resume most recent interrupted session`,
+ decoder recover # List interrupted sessions
+ decoder recover abc123 # Resume specific session
+ decoder --recover # Auto-resume most recent interrupted session`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
s, note, err := session.ResumeSession(args[0])
@@ -1111,8 +1111,8 @@ Examples:
cmd.Println(session.FormatRecoveryCandidates(candidates))
if len(candidates) > 0 {
- cmd.Println(auditTint("Resume with: rho recover ", textMuted))
- cmd.Println(auditTint("Or launch TUI with: rho --recover", textMuted))
+ cmd.Println(auditTint("Resume with: decoder recover ", textMuted))
+ cmd.Println(auditTint("Or launch TUI with: decoder --recover", textMuted))
}
return nil
},
diff --git a/cmd/rules.go b/cmd/rules.go
index 1a83d1581..6fe37d535 100644
--- a/cmd/rules.go
+++ b/cmd/rules.go
@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
- "github.com/GrayCodeAI/rho/internal/rules"
+ "github.com/GrayCodeAI/decoder/internal/rules"
"github.com/spf13/cobra"
)
@@ -18,7 +18,7 @@ var rulesCmd = &cobra.Command{
Use: "rules",
Short: "Detect, import, and export AI coding rules between tool formats",
Long: `rules manages AI coding rule files across different tools.
-Supported formats: rho, cursor, claudecode, copilot, gemini.
+Supported formats: decoder, cursor, claudecode, copilot, gemini.
Subcommands:
detect Show which AI tool rule files exist in the current directory
@@ -56,7 +56,7 @@ var rulesDetectCmd = &cobra.Command{
var rulesImportCmd = &cobra.Command{
Use: "import",
- Short: "Import rules from another tool's format into rho",
+ Short: "Import rules from another tool's format into decoder",
RunE: func(cmd *cobra.Command, args []string) error {
if rulesImportFrom == "" {
return fmt.Errorf("--from flag is required (e.g. --from cursor)")
@@ -73,9 +73,9 @@ var rulesImportCmd = &cobra.Command{
return nil
}
- // Export to rho format.
- if err := rules.Export(".", rules.FormatRho, imported); err != nil {
- return fmt.Errorf("export to rho format failed: %w", err)
+ // Export to decoder format.
+ if err := rules.Export(".", rules.FormatDecoder, imported); err != nil {
+ return fmt.Errorf("export to decoder format failed: %w", err)
}
cmd.Println(auditTint(fmt.Sprintf("Imported %d rule(s) from %s to .agents/rules/.", len(imported), rulesImportFrom), doneGreen))
@@ -88,30 +88,30 @@ var rulesImportCmd = &cobra.Command{
var rulesExportCmd = &cobra.Command{
Use: "export",
- Short: "Export rho rules to another tool's format",
+ Short: "Export decoder rules to another tool's format",
RunE: func(cmd *cobra.Command, args []string) error {
if rulesExportTo == "" {
return fmt.Errorf("--to flag is required (e.g. --to claudecode)")
}
- // Read rho rules.
- rhoRules, err := rules.Import(".", rules.FormatRho)
+ // Read decoder rules.
+ decoderRules, err := rules.Import(".", rules.FormatDecoder)
if err != nil {
- return fmt.Errorf("read rho rules failed: %w", err)
+ return fmt.Errorf("read decoder rules failed: %w", err)
}
- if len(rhoRules) == 0 {
- cmd.Println(auditTint("No rho rules found in .agents/rules/. Nothing to export.", textMuted))
+ if len(decoderRules) == 0 {
+ cmd.Println(auditTint("No decoder rules found in .agents/rules/. Nothing to export.", textMuted))
return nil
}
to := rules.Format(rulesExportTo)
- if err := rules.Export(".", to, rhoRules); err != nil {
+ if err := rules.Export(".", to, decoderRules); err != nil {
return fmt.Errorf("export to %s format failed: %w", rulesExportTo, err)
}
- cmd.Println(auditTint(fmt.Sprintf("Exported %d rule(s) to %s format.", len(rhoRules), rulesExportTo), doneGreen))
- for _, r := range rhoRules {
+ cmd.Println(auditTint(fmt.Sprintf("Exported %d rule(s) to %s format.", len(decoderRules), rulesExportTo), doneGreen))
+ for _, r := range decoderRules {
cmd.Println(auditTint(" - "+r.Name, textPrimary))
}
return nil
diff --git a/cmd/search.go b/cmd/search.go
index 50af517b1..6381f6108 100644
--- a/cmd/search.go
+++ b/cmd/search.go
@@ -5,8 +5,8 @@ import (
"os"
"strings"
- "github.com/GrayCodeAI/rho/internal/session"
- "github.com/GrayCodeAI/rho/internal/theme"
+ "github.com/GrayCodeAI/decoder/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/theme"
"github.com/spf13/cobra"
)
@@ -18,14 +18,14 @@ var (
var searchCmd = &cobra.Command{
Use: "search ",
Short: "Search across saved sessions",
- Long: `Full-text search across all saved rho sessions.
+ Long: `Full-text search across all saved decoder sessions.
Searches message content, tool results, and assistant responses.
Examples:
- rho search "authentication"
- rho search --limit 5 "database migration"
- rho search "func main"`,
+ decoder search "authentication"
+ decoder search --limit 5 "database migration"
+ decoder search "func main"`,
Args: cobra.ExactArgs(1),
RunE: runSearch,
}
diff --git a/cmd/security_verify_governance_cli_test.go b/cmd/security_verify_governance_cli_test.go
index 1d8ee2628..c66693a00 100644
--- a/cmd/security_verify_governance_cli_test.go
+++ b/cmd/security_verify_governance_cli_test.go
@@ -8,15 +8,15 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/securitylog"
+ "github.com/GrayCodeAI/decoder/internal/securitylog"
)
-// withTempState runs a cli test body with RHO_STATE_DIR pointed at a temp dir
+// withTempState runs a cli test body with DECODER_STATE_DIR pointed at a temp dir
// so the real user state is never touched.
func withTempState(t *testing.T, body func(stateDir string)) {
t.Helper()
dir := t.TempDir()
- t.Setenv("RHO_STATE_DIR", dir)
+ t.Setenv("DECODER_STATE_DIR", dir)
body(dir)
}
diff --git a/cmd/securitylog_cmd.go b/cmd/securitylog_cmd.go
index d971a13ed..673303230 100644
--- a/cmd/securitylog_cmd.go
+++ b/cmd/securitylog_cmd.go
@@ -5,7 +5,7 @@ import (
"fmt"
"time"
- "github.com/GrayCodeAI/rho/internal/securitylog"
+ "github.com/GrayCodeAI/decoder/internal/securitylog"
"github.com/spf13/cobra"
)
@@ -18,13 +18,13 @@ var (
var securitylogCmd = &cobra.Command{
Use: "securitylog",
Short: "Inspect the tamper-evident security event log",
- Long: `Rho records security-relevant events (permission denials, approval
+ Long: `Decoder records security-relevant events (permission denials, approval
denials) to an append-only, HMAC-chained log. Entries are linked so that
reordering, deletion, or alteration is detectable.
- rho securitylog Show a summary and recent events
- rho securitylog show List logged events
- rho securitylog verify Verify the hash chain has not been tampered with`,
+ decoder securitylog Show a summary and recent events
+ decoder securitylog show List logged events
+ decoder securitylog verify Verify the hash chain has not been tampered with`,
RunE: func(cmd *cobra.Command, args []string) error {
return runSecuritylogShow(cmd, 20, false)
},
diff --git a/cmd/session_export.go b/cmd/session_export.go
index 2f51d2e74..32f38d517 100644
--- a/cmd/session_export.go
+++ b/cmd/session_export.go
@@ -4,7 +4,7 @@ import (
"fmt"
"os"
- "github.com/GrayCodeAI/rho/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/session"
"github.com/spf13/cobra"
)
diff --git a/cmd/session_migrate.go b/cmd/session_migrate.go
index 9947017f2..e173eb349 100644
--- a/cmd/session_migrate.go
+++ b/cmd/session_migrate.go
@@ -5,7 +5,7 @@ import (
"fmt"
"strings"
- "github.com/GrayCodeAI/rho/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/session"
"github.com/spf13/cobra"
)
diff --git a/cmd/session_migrate_test.go b/cmd/session_migrate_test.go
index 7978e1bbe..402e51037 100644
--- a/cmd/session_migrate_test.go
+++ b/cmd/session_migrate_test.go
@@ -9,7 +9,7 @@ import (
func TestRunSessionMigrate(t *testing.T) {
state := t.TempDir()
- t.Setenv("RHO_STATE_DIR", state)
+ t.Setenv("DECODER_STATE_DIR", state)
id := "migrate-cmd-test"
sessDir := filepath.Join(state, "sessions")
if err := os.MkdirAll(sessDir, 0o700); err != nil {
@@ -40,7 +40,7 @@ func TestRunSessionMigrate(t *testing.T) {
func TestRunSessionMigrateJSON(t *testing.T) {
state := t.TempDir()
- t.Setenv("RHO_STATE_DIR", state)
+ t.Setenv("DECODER_STATE_DIR", state)
id := "migrate-cmd-json"
sessDir := filepath.Join(state, "sessions")
_ = os.MkdirAll(sessDir, 0o700)
diff --git a/cmd/session_share.go b/cmd/session_share.go
index b63c0cb82..372d31583 100644
--- a/cmd/session_share.go
+++ b/cmd/session_share.go
@@ -9,12 +9,12 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/session"
+ "github.com/GrayCodeAI/decoder/internal/session"
"github.com/spf13/cobra"
)
// sessionShareCmd shares a session. It uploads the export to a configured
-// hosted endpoint (RHO_SHARE_URL) when one is set, else falls back to the
+// hosted endpoint (DECODER_SHARE_URL) when one is set, else falls back to the
// local content-derived deeplink + export path.
var sessionShareCmd = &cobra.Command{
Use: "share [session-id]",
@@ -40,7 +40,7 @@ func runSessionShare(_ *cobra.Command, args []string) error {
return fmt.Errorf("export session: %w", err)
}
- host := strings.TrimSpace(os.Getenv("RHO_SHARE_URL"))
+ host := strings.TrimSpace(os.Getenv("DECODER_SHARE_URL"))
if host != "" {
url, err := uploadShare(context.Background(), host, s.ID, data)
if err != nil {
@@ -56,7 +56,7 @@ func runSessionShare(_ *cobra.Command, args []string) error {
return fmt.Errorf("could not generate a share link for session %q", s.ID)
}
fmt.Printf("Share deeplink: %s\n", link)
- fmt.Printf("(Set RHO_SHARE_URL to a share service that accepts POST /v1/shares for a hosted URL; GrayCode Cloud does not host session shares.)\n")
+ fmt.Printf("(Set DECODER_SHARE_URL to a share service that accepts POST /v1/shares for a hosted URL; GrayCode Cloud does not host session shares.)\n")
return nil
}
diff --git a/cmd/session_sync.go b/cmd/session_sync.go
index 39bd88bc8..8a08b849c 100644
--- a/cmd/session_sync.go
+++ b/cmd/session_sync.go
@@ -5,8 +5,8 @@ import (
"fmt"
"strings"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
func (m *chatModel) ensureDeferredSystemContext() {
@@ -32,12 +32,12 @@ func explicitSelection(ctx context.Context) (provider, model string) {
if ctx == nil {
ctx = context.Background()
}
- return strings.TrimSpace(rhoconfig.ActiveGateway(ctx)), strings.TrimSpace(rhoconfig.ActiveModel(ctx))
+ return strings.TrimSpace(decoderconfig.ActiveGateway(ctx)), strings.TrimSpace(decoderconfig.ActiveModel(ctx))
}
-// syncSessionFromPersistedSelection copies explicit flux provider.json
+// syncSessionFromPersistedSelection copies explicit mux provider.json
// selection into the live session when the session fields are empty.
-// It intentionally avoids runtime defaults so Rho can preserve the
+// It intentionally avoids runtime defaults so Decoder can preserve the
// "gateway selected, model still missing" setup state.
func syncSessionFromPersistedSelection(sess *engine.Session) {
if sess == nil {
diff --git a/cmd/session_sync_test.go b/cmd/session_sync_test.go
index 7f34f9109..18862c9fe 100644
--- a/cmd/session_sync_test.go
+++ b/cmd/session_sync_test.go
@@ -5,26 +5,26 @@ import (
"strings"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
)
func TestSyncSessionFromPersistedSelection_FillsEmptySessionModel(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
isolateCredentialHome(t)
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
_ = store.Set(ctx, gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890")
- rhoconfig.InvalidateConfigUICache()
- _ = rhoconfig.SetActiveProvider(ctx, "openrouter")
- _ = rhoconfig.SetActiveModel(ctx, "gpt-4o")
+ decoderconfig.InvalidateConfigUICache()
+ _ = decoderconfig.SetActiveProvider(ctx, "openrouter")
+ _ = decoderconfig.SetActiveModel(ctx, "gpt-4o")
sess := engine.NewSession("", "", "test", nil)
syncSessionFromPersistedSelection(sess)
@@ -38,20 +38,20 @@ func TestSyncSessionFromPersistedSelection_FillsEmptySessionModel(t *testing.T)
}
func TestEnsureSessionReadyForChat_UsesPersistedModel(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
isolateCredentialHome(t)
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
_ = store.Set(ctx, gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890")
- rhoconfig.InvalidateConfigUICache()
- _ = rhoconfig.SetActiveProvider(ctx, "openrouter")
- _ = rhoconfig.SetActiveModel(ctx, "gpt-4o")
+ decoderconfig.InvalidateConfigUICache()
+ _ = decoderconfig.SetActiveProvider(ctx, "openrouter")
+ _ = decoderconfig.SetActiveModel(ctx, "gpt-4o")
m := &chatModel{session: engine.NewSession("", "", "test", nil)}
if err := m.ensureSessionReadyForChat(); err != nil {
@@ -63,18 +63,18 @@ func TestEnsureSessionReadyForChat_UsesPersistedModel(t *testing.T) {
}
func TestEnsureSessionReadyForChat_NoModel(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
isolateCredentialHome(t)
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
- rhoconfig.InvalidateConfigUICache()
- _ = rhoconfig.ClearActiveSelection(ctx)
+ decoderconfig.InvalidateConfigUICache()
+ _ = decoderconfig.ClearActiveSelection(ctx)
m := &chatModel{session: engine.NewSession("", "", "test", nil)}
if err := m.ensureSessionReadyForChat(); err == nil {
@@ -83,20 +83,20 @@ func TestEnsureSessionReadyForChat_NoModel(t *testing.T) {
}
func TestEnsureSessionReadyForChat_AppliesDeferredSystemContextOnce(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
isolateCredentialHome(t)
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
ctx := context.Background()
_ = store.Set(ctx, gateway.AccountForEnv("OPENROUTER_API_KEY"), "sk-or-test-key-1234567890")
- rhoconfig.InvalidateConfigUICache()
- _ = rhoconfig.SetActiveProvider(ctx, "openrouter")
- _ = rhoconfig.SetActiveModel(ctx, "gpt-4o")
+ decoderconfig.InvalidateConfigUICache()
+ _ = decoderconfig.SetActiveProvider(ctx, "openrouter")
+ _ = decoderconfig.SetActiveModel(ctx, "gpt-4o")
m := &chatModel{
session: engine.NewSession("", "", "base", nil),
diff --git a/cmd/skills_cmd.go b/cmd/skills_cmd.go
index d43009047..435fe7b1a 100644
--- a/cmd/skills_cmd.go
+++ b/cmd/skills_cmd.go
@@ -8,8 +8,8 @@ import (
"strconv"
"strings"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/tool"
"github.com/spf13/cobra"
)
diff --git a/cmd/skills_create.go b/cmd/skills_create.go
index 730f38ad3..96004ad69 100644
--- a/cmd/skills_create.go
+++ b/cmd/skills_create.go
@@ -5,9 +5,9 @@ import (
"fmt"
"strings"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/tool"
- "github.com/GrayCodeAI/rho/internal/types"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/types"
"github.com/spf13/cobra"
)
@@ -30,10 +30,10 @@ func runSkillsCreate(_ *cobra.Command, args []string) error {
return err
}
model, provider := effectiveModelAndProvider(settings)
- sess := newRhoSession(settings, provider, model, "You are a skill author.", tool.NewRegistry())
+ sess := newDecoderSession(settings, provider, model, "You are a skill author.", tool.NewRegistry())
prompt := plugin.BuildNewSkillPrompt(desc)
- resp, err := sess.Chat(context.Background(), []types.FluxMessage{
+ resp, err := sess.Chat(context.Background(), []types.MuxMessage{
{Role: "user", Content: prompt},
}, types.ChatOptions{Model: model, MaxTokens: 4096})
if err != nil {
diff --git a/cmd/skills_curator_cmd.go b/cmd/skills_curator_cmd.go
index d5d0ef1d4..c1fb10586 100644
--- a/cmd/skills_curator_cmd.go
+++ b/cmd/skills_curator_cmd.go
@@ -5,14 +5,14 @@ import (
"image/color"
"path/filepath"
- "github.com/GrayCodeAI/rho/internal/intelligence/skillcurator"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/intelligence/skillcurator"
+ "github.com/GrayCodeAI/decoder/internal/storage"
"github.com/spf13/cobra"
)
// skillsCuratorCmd exposes the background skill curator (adopted from Hermes
// Agent) as a CLI surface: review/archive/pin/unpin over agent-created skills
-// in ~/.rho/skills.
+// in ~/.decoder/skills.
var skillsCuratorCmd = &cobra.Command{
Use: "curator [command]",
Short: "Skill lifecycle curation (status, run, pin, unpin, archive)",
diff --git a/cmd/slash_commands_test.go b/cmd/slash_commands_test.go
index 0bff63aa7..0b036c2a3 100644
--- a/cmd/slash_commands_test.go
+++ b/cmd/slash_commands_test.go
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
- commandfeature "github.com/GrayCodeAI/rho/internal/features/commands"
+ commandfeature "github.com/GrayCodeAI/decoder/internal/features/commands"
)
func TestSlashCommands_NotEmpty(t *testing.T) {
diff --git a/cmd/sleep_prevent.go b/cmd/sleep_prevent.go
index 39cdd1874..32ab959e3 100644
--- a/cmd/sleep_prevent.go
+++ b/cmd/sleep_prevent.go
@@ -43,7 +43,7 @@ func preventSleepLinux() func() {
"systemd-inhibit",
"--mode=block",
"--what=idle:sleep",
- "--who=rho",
+ "--who=decoder",
"--why=Agent turn in progress",
"sleep", "86400")
if err := cmd.Start(); err != nil {
diff --git a/cmd/snapshot_cmd.go b/cmd/snapshot_cmd.go
index 7825e31e3..1e979eb96 100644
--- a/cmd/snapshot_cmd.go
+++ b/cmd/snapshot_cmd.go
@@ -7,7 +7,7 @@ import (
"strings"
tea "charm.land/bubbletea/v2"
- "github.com/GrayCodeAI/rho/internal/snapshot"
+ "github.com/GrayCodeAI/decoder/internal/snapshot"
"github.com/spf13/cobra"
)
@@ -51,7 +51,7 @@ func (m chatModel) showSnapshotList() (tea.Model, tea.Cmd) {
history, err := t.History(15)
if err != nil || len(history) == 0 {
- m.messages = append(m.messages, displayMsg{role: "system", content: "No snapshots yet. Snapshots are created automatically when rho modifies files."})
+ m.messages = append(m.messages, displayMsg{role: "system", content: "No snapshots yet. Snapshots are created automatically when decoder modifies files."})
return m, nil
}
@@ -123,7 +123,7 @@ func (m chatModel) diffSnapshot(hash string) (tea.Model, tea.Cmd) {
var snapshotCmd = &cobra.Command{
Use: "snapshot",
Short: "Manage file snapshots (undo any change)",
- Long: "View, restore, and diff file snapshots. Rho automatically snapshots every file modification.",
+ Long: "View, restore, and diff file snapshots. Decoder automatically snapshots every file modification.",
}
var snapshotListCmd = &cobra.Command{
diff --git a/cmd/spec_picker.go b/cmd/spec_picker.go
index 3ec2fb8bb..ebdbf8b52 100644
--- a/cmd/spec_picker.go
+++ b/cmd/spec_picker.go
@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
"charm.land/bubbles/v2/textinput"
tea "charm.land/bubbletea/v2"
diff --git a/cmd/spec_picker_test.go b/cmd/spec_picker_test.go
index 6738584e4..de648d691 100644
--- a/cmd/spec_picker_test.go
+++ b/cmd/spec_picker_test.go
@@ -3,7 +3,7 @@ package cmd
import (
"testing"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
tea "charm.land/bubbletea/v2"
)
diff --git a/cmd/spinner_wave.go b/cmd/spinner_wave.go
index 3ea78ee3a..b981f8f7d 100644
--- a/cmd/spinner_wave.go
+++ b/cmd/spinner_wave.go
@@ -5,12 +5,12 @@ import (
"strings"
"unicode/utf8"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// spinnerWaveColors — 20 distinct hues; the wave flows glyph → verb → ▪▫▫.
var spinnerWaveColors = [20][3]int{
- {255, 215, 0}, // Talon Gold — anchor the wave in Rho's brand color.
+ {255, 215, 0}, // Talon Gold — anchor the wave in Decoder's brand color.
{255, 60, 60},
{255, 100, 80},
{255, 150, 60},
@@ -46,7 +46,7 @@ func ansiSpinnerWaveColor(index int) string {
// renderSpinnerWaveLine paints glyph + verb + ▪▫▫ as one flowing strip (20 colors).
func renderSpinnerWaveLine(glyph, verb string, wavePhase, dotPhase int) string {
verbRunes := utf8.RuneCountInString(verb)
- total := 1 + verbRunes + 1 + rhoTypingDots
+ total := 1 + verbRunes + 1 + decoderTypingDots
if verb == "" {
total = 1
}
@@ -66,10 +66,10 @@ func renderSpinnerWaveLine(glyph, verb string, wavePhase, dotPhase int) string {
}
b.WriteString(renderSpinnerWaveSlot(' ', wavePhase+pos, head == pos, false))
pos++
- for i := 0; i < rhoTypingDots; i++ {
+ for i := 0; i < decoderTypingDots; i++ {
g := icons.CircleOutline()
bold := false
- if i == dotPhase%rhoTypingDots {
+ if i == dotPhase%decoderTypingDots {
g = icons.CircleFilled()
bold = true
}
diff --git a/cmd/spinner_wave_test.go b/cmd/spinner_wave_test.go
index 085d8b852..e977cf5a4 100644
--- a/cmd/spinner_wave_test.go
+++ b/cmd/spinner_wave_test.go
@@ -5,7 +5,7 @@ import (
"strings"
"testing"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
// frameContainsSpinnerWave reports whether a rendered frame contains the
@@ -17,7 +17,7 @@ func frameContainsSpinnerWave(s string) bool {
}
func TestSpinnerWave_AdvancesOnTick(t *testing.T) {
- s := NewBrailleSpinner(SpinnerRho, "Hi")
+ s := NewBrailleSpinner(SpinnerDecoder, "Hi")
f1 := s.Frame()
s.Tick()
f2 := s.Frame()
@@ -57,7 +57,7 @@ func TestSpinnerWave_FlowsThroughGlyphVerbAndDots(t *testing.T) {
}
func TestSpinnerWave_GlyphUsesWaveColor(t *testing.T) {
- s := NewBrailleSpinner(SpinnerRho, "Go")
+ s := NewBrailleSpinner(SpinnerDecoder, "Go")
f := s.Frame()
if !strings.Contains(f, "◐") && !strings.Contains(f, "◓") && !strings.Contains(f, "◑") && !strings.Contains(f, "◒") {
t.Fatalf("expected compass spinner glyph, got %q", f)
diff --git a/cmd/stats.go b/cmd/stats.go
index d17c2169a..fc6bb281d 100644
--- a/cmd/stats.go
+++ b/cmd/stats.go
@@ -8,7 +8,7 @@ import (
"strings"
"time"
- analytics "github.com/GrayCodeAI/rho/internal/observability"
+ analytics "github.com/GrayCodeAI/decoder/internal/observability"
"github.com/spf13/cobra"
)
@@ -85,7 +85,7 @@ func runStats(cmd *cobra.Command, args []string) error {
if len(filtered) == 0 {
cmd.Println(auditTint("No session data found for the specified time period.", textMuted))
- cmd.Println(auditTint("Sessions are recorded automatically when you use rho.", textMuted))
+ cmd.Println(auditTint("Sessions are recorded automatically when you use decoder.", textMuted))
return nil
}
@@ -180,7 +180,7 @@ func printStatsText(cmd *cobra.Command, out *statsOutput) {
_, _ = fmt.Fprintf(w, "\n")
_, _ = fmt.Fprintf(w, "══════════════════════════════════════════════════\n")
- _, _ = fmt.Fprintf(w, " %s\n", auditTint(fmt.Sprintf("Rho Usage Statistics (%s)", out.Period), rhoColor))
+ _, _ = fmt.Fprintf(w, " %s\n", auditTint(fmt.Sprintf("Decoder Usage Statistics (%s)", out.Period), decoderColor))
_, _ = fmt.Fprintf(w, "══════════════════════════════════════════════════\n")
// Overview section
diff --git a/cmd/status_snapshot.go b/cmd/status_snapshot.go
index fc1ee6859..194a4d88c 100644
--- a/cmd/status_snapshot.go
+++ b/cmd/status_snapshot.go
@@ -5,10 +5,10 @@ import (
"fmt"
"strings"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/plugin"
- "github.com/GrayCodeAI/rho/internal/status"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/plugin"
+ "github.com/GrayCodeAI/decoder/internal/status"
"github.com/spf13/cobra"
)
@@ -34,11 +34,11 @@ var statusCmd = &cobra.Command{
func buildStatusSnapshot() status.Snapshot {
snapshot := status.New()
- snapshot.RhoVersion = version
+ snapshot.DecoderVersion = version
snapshot.Workspace = status.Workspace()
snapshot.GitBranch = engine.InspectGitBranch("").Branch
- settings := rhoconfig.LoadGlobalSettings()
- selection := rhoconfig.EffectiveSelection(context.Background(), rhoconfig.SelectionOptions{})
+ settings := decoderconfig.LoadGlobalSettings()
+ selection := decoderconfig.EffectiveSelection(context.Background(), decoderconfig.SelectionOptions{})
snapshot.Model = strings.TrimSpace(selection.Model)
snapshot.Provider = strings.TrimSpace(selection.Provider)
if snapshot.Model == "" {
@@ -77,7 +77,7 @@ func formatStatusSnapshot(s status.Snapshot) string {
return fmt.Sprintf("%s: %s\n", auditTint(label, textMuted), auditTint(val, textPrimary))
}
var b strings.Builder
- b.WriteString(auditTint("Rho status", rhoColor) + "\n")
+ b.WriteString(auditTint("Decoder status", decoderColor) + "\n")
b.WriteString(line("Schema", s.SchemaVersion))
b.WriteString(line("Workspace", s.Workspace))
b.WriteString(line("Git branch", s.GitBranch))
diff --git a/cmd/status_snapshot_test.go b/cmd/status_snapshot_test.go
index 9196fad69..65243a606 100644
--- a/cmd/status_snapshot_test.go
+++ b/cmd/status_snapshot_test.go
@@ -8,7 +8,7 @@ import (
func TestFormatStatusSnapshot(t *testing.T) {
snapshot := buildStatusSnapshot()
formatted := formatStatusSnapshot(snapshot)
- for _, expected := range []string{"Rho status", "Schema: 1", "Secrets redacted: true"} {
+ for _, expected := range []string{"Decoder status", "Schema: 1", "Secrets redacted: true"} {
if !strings.Contains(formatted, expected) {
t.Errorf("status output missing %q: %s", expected, formatted)
}
diff --git a/cmd/statusbar.go b/cmd/statusbar.go
index fcc4b283c..fd3cdc92b 100644
--- a/cmd/statusbar.go
+++ b/cmd/statusbar.go
@@ -7,18 +7,18 @@ import (
"sync"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
- "github.com/GrayCodeAI/rho/internal/engine"
- "github.com/GrayCodeAI/rho/internal/engine/cost"
+ "github.com/GrayCodeAI/decoder/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine/cost"
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
"golang.org/x/text/language"
"golang.org/x/text/message"
- "github.com/GrayCodeAI/rho/internal/engine/git"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ "github.com/GrayCodeAI/decoder/internal/engine/git"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
var (
diff --git a/cmd/statusbar_test.go b/cmd/statusbar_test.go
index b1245cd44..2f25bbcaf 100644
--- a/cmd/statusbar_test.go
+++ b/cmd/statusbar_test.go
@@ -5,10 +5,10 @@ import (
"testing"
"time"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
lipgloss "charm.land/lipgloss/v2"
- "github.com/GrayCodeAI/rho/internal/engine"
+ "github.com/GrayCodeAI/decoder/internal/engine"
)
func TestRenderStatusBar_SignatureExists(t *testing.T) {
@@ -120,8 +120,8 @@ func TestRenderStatusBarPrimaryLeft_UsesCachedState(t *testing.T) {
func TestShortenHomePath(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
- got := shortenHomePath(home + "/project/rho")
- if got != "~/project/rho" {
+ got := shortenHomePath(home + "/project/decoder")
+ if got != "~/project/decoder" {
t.Fatalf("got %q", got)
}
}
diff --git a/cmd/storage_policy_test.go b/cmd/storage_policy_test.go
index 7bd694163..72bd935a3 100644
--- a/cmd/storage_policy_test.go
+++ b/cmd/storage_policy_test.go
@@ -7,10 +7,10 @@ import (
"testing"
)
-func TestStoragePolicyHelpersDoNotCreateProjectRho(t *testing.T) {
+func TestStoragePolicyHelpersDoNotCreateProjectDecoder(t *testing.T) {
project := t.TempDir()
- t.Setenv("RHO_STATE_DIR", filepath.Join(t.TempDir(), "state"))
- t.Setenv("RHO_CACHE_DIR", filepath.Join(t.TempDir(), "cache"))
+ t.Setenv("DECODER_STATE_DIR", filepath.Join(t.TempDir(), "state"))
+ t.Setenv("DECODER_CACHE_DIR", filepath.Join(t.TempDir(), "cache"))
oldwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
@@ -21,13 +21,13 @@ func TestStoragePolicyHelpersDoNotCreateProjectRho(t *testing.T) {
}
planPath := resolvePlanPath("demo")
- if strings.Contains(planPath, filepath.Join(project, ".rho")) {
- t.Fatalf("resolvePlanPath leaked project .rho: %q", planPath)
+ if strings.Contains(planPath, filepath.Join(project, ".decoder")) {
+ t.Fatalf("resolvePlanPath leaked project .decoder: %q", planPath)
}
saveInputHistory([]string{"hello"})
recordTipShown("slash-help")
- if _, err := os.Stat(filepath.Join(project, ".rho")); !os.IsNotExist(err) {
- t.Fatalf("normal storage helpers created project .rho, stat err=%v", err)
+ if _, err := os.Stat(filepath.Join(project, ".decoder")); !os.IsNotExist(err) {
+ t.Fatalf("normal storage helpers created project .decoder, stat err=%v", err)
}
}
diff --git a/cmd/tabcomplete.go b/cmd/tabcomplete.go
index da9b9a6e6..2b7fa65e7 100644
--- a/cmd/tabcomplete.go
+++ b/cmd/tabcomplete.go
@@ -7,7 +7,7 @@ import (
"strings"
"sync"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
// lruCache is a simple fixed-size LRU cache for directory listing results.
diff --git a/cmd/tabcomplete_test.go b/cmd/tabcomplete_test.go
index 57a7655c9..56878b97e 100644
--- a/cmd/tabcomplete_test.go
+++ b/cmd/tabcomplete_test.go
@@ -5,7 +5,7 @@ import (
"path/filepath"
"testing"
- "github.com/GrayCodeAI/rho/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/tool"
)
func TestFilePathCompletions_CurrentDir(t *testing.T) {
diff --git a/cmd/taste.go b/cmd/taste.go
index b03be545a..7a56c5e3f 100644
--- a/cmd/taste.go
+++ b/cmd/taste.go
@@ -6,7 +6,7 @@ import (
"path/filepath"
"strings"
- "github.com/GrayCodeAI/rho/internal/features/taste"
+ "github.com/GrayCodeAI/decoder/internal/features/taste"
"github.com/spf13/cobra"
)
@@ -36,8 +36,8 @@ var tastePushCmd = &cobra.Command{
with teammates or used across machines.
Examples:
- rho taste push # Export to stdout
- rho taste push --file team.json # Export to file`,
+ decoder taste push # Export to stdout
+ decoder taste push --file team.json # Export to file`,
RunE: runTastePush,
}
@@ -48,8 +48,8 @@ var tastePullCmd = &cobra.Command{
will be merged with your existing profile (not replaced).
Examples:
- rho taste pull team.json
- cat team.json | rho taste pull -`,
+ decoder taste pull team.json
+ cat team.json | decoder taste pull -`,
Args: cobra.ExactArgs(1),
RunE: runTastePull,
}
diff --git a/cmd/terminal_notify.go b/cmd/terminal_notify.go
index 7bc213beb..07f55732e 100644
--- a/cmd/terminal_notify.go
+++ b/cmd/terminal_notify.go
@@ -46,7 +46,7 @@ func sendTerminalNotification(title, body string) {
_, _ = fmt.Fprintf(os.Stderr, "\033]9;%s\007", body)
case "kitty":
// Kitty OSC 99 notification
- _, _ = fmt.Fprintf(os.Stderr, "\033]99;i=rho:d=0;%s\033\\", body)
+ _, _ = fmt.Fprintf(os.Stderr, "\033]99;i=decoder:d=0;%s\033\\", body)
case "ghostty":
// Ghostty OSC 777 notification
_, _ = fmt.Fprintf(os.Stderr, "\033]777;notify;%s;%s\033\\", title, body)
diff --git a/cmd/testfirst_workflow.go b/cmd/testfirst_workflow.go
index 1415705a5..1a56cb89f 100644
--- a/cmd/testfirst_workflow.go
+++ b/cmd/testfirst_workflow.go
@@ -1,6 +1,6 @@
package cmd
-import executionfeature "github.com/GrayCodeAI/rho/internal/features/execution"
+import executionfeature "github.com/GrayCodeAI/decoder/internal/features/execution"
// Compatibility aliases keep callers stable while execution owns the
// test-first workflow implementation.
diff --git a/cmd/textutil_shim.go b/cmd/textutil_shim.go
index 09229a4df..08f29d0da 100644
--- a/cmd/textutil_shim.go
+++ b/cmd/textutil_shim.go
@@ -1,6 +1,6 @@
package cmd
-import "github.com/GrayCodeAI/rho/internal/textutil"
+import "github.com/GrayCodeAI/decoder/internal/textutil"
// truncateWithEllipsis truncates s to at most max runes, appending "..." when
// content is dropped. Rune-safe: never splits a multi-byte character.
diff --git a/cmd/theme.go b/cmd/theme.go
index 2f5aca857..72e7e0f79 100644
--- a/cmd/theme.go
+++ b/cmd/theme.go
@@ -1,11 +1,11 @@
package cmd
-// theme.go — the single source of truth for rho's visual identity.
+// theme.go — the single source of truth for decoder's visual identity.
//
// All color constants (24-bit RGB via lipgloss), raw ANSI escape codes
// (used by the spinner line), and glyph/icon constants live here. Every
// other file in the package references these names instead of repeating
-// hex codes or magic strings. To rebrand rho, edit this file; to audit
+// hex codes or magic strings. To rebrand decoder, edit this file; to audit
// what's used where, grep this file.
//
// Organization:
@@ -27,17 +27,17 @@ import (
lipgloss "charm.land/lipgloss/v2"
"charm.land/lipgloss/v2/compat"
- internaltheme "github.com/GrayCodeAI/rho/internal/theme"
+ internaltheme "github.com/GrayCodeAI/decoder/internal/theme"
)
// ---------------------------------------------------------------------------
// 1. Brand & identity
// ---------------------------------------------------------------------------
-// rhoColor is Talon Gold (#FFD700). Used for the RHO wordmark, rho,
+// decoderColor is Talon Gold (#FFD700). Used for the DECODER wordmark, decoder,
// ⛬ assistant prefix, prompt arrow, cursor, exit prompt, and
// any place that should "speak" as the brand.
-var rhoColor = lipgloss.Color(internaltheme.BrandPrimary)
+var decoderColor = lipgloss.Color(internaltheme.BrandPrimary)
// ---------------------------------------------------------------------------
// 2. UI state
@@ -217,7 +217,7 @@ func ansiFromHex(hex string) string {
// ---------------------------------------------------------------------------
// 10. Icons & glyphs
//
-// Rho's icon registry lives in internal/ui/icons. Every call site
+// Decoder's icon registry lives in internal/ui/icons. Every call site
// references icons.ChevronRight() / icons.Robot() / etc. directly; this
// file no longer holds any glyph constants. The audit test in
// internal/testaudit fails CI if any non-ASCII literal appears in
@@ -261,7 +261,7 @@ func ApplyTheme(name string) {
p := entry.Palette
// 1. Brand — fixed across themes; palette accents remain theme-specific.
- rhoColor = lipgloss.Color(internaltheme.BrandPrimary)
+ decoderColor = lipgloss.Color(internaltheme.BrandPrimary)
// 2. Semantic feedback.
successTeal = lipgloss.Color(p.Green)
@@ -338,12 +338,12 @@ var minimalChrome bool
// unsynchronized from View.
func refreshThemeStyles() {
// markdown.go
- mdH1Style = lipgloss.NewStyle().Foreground(rhoColor).Bold(true).Underline(true)
+ mdH1Style = lipgloss.NewStyle().Foreground(decoderColor).Bold(true).Underline(true)
mdH2Style = lipgloss.NewStyle().Foreground(successTeal).Bold(true)
mdH3Style = lipgloss.NewStyle().Foreground(infoSky).Bold(true)
mdH4Style = lipgloss.NewStyle().Foreground(costViolet).Bold(true)
mdHeaderStyle = lipgloss.NewStyle().Foreground(textPrimary).Bold(true)
- mdBoldStyle = lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
+ mdBoldStyle = lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
mdInlineCodeStyle = lipgloss.NewStyle().Foreground(infoSky)
mdCodeBlockStyle = lipgloss.NewStyle().Background(bgCode)
mdCodeLabelStyle = lipgloss.NewStyle().Foreground(textDisabled).Background(bgCode)
@@ -362,8 +362,8 @@ func refreshThemeStyles() {
toolDimStyle = lipgloss.NewStyle().Foreground(textDisabled)
slashCmdStyle = lipgloss.NewStyle().Foreground(textDisabled)
slashDescStyle = lipgloss.NewStyle().Foreground(textDisabled)
- slashSelCmdStyle = lipgloss.NewStyle().Foreground(rhoColor).Bold(true)
- slashSelDescStyle = lipgloss.NewStyle().Foreground(rhoColor)
+ slashSelCmdStyle = lipgloss.NewStyle().Foreground(decoderColor).Bold(true)
+ slashSelDescStyle = lipgloss.NewStyle().Foreground(decoderColor)
if minimalChrome {
// Tau-style: a single hairline rule under the input, no side borders.
inputBorderStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder(), false, false, true, false).BorderForeground(borderDim)
@@ -373,7 +373,7 @@ func refreshThemeStyles() {
dimColor = textDisabled
// agent_grid.go
- agentActiveStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).BorderForeground(rhoColor).Padding(0, 1)
+ agentActiveStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).BorderForeground(decoderColor).Padding(0, 1)
agentDoneStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).BorderForeground(doneGreen).Padding(0, 1)
agentFailStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).BorderForeground(errorCoral).Padding(0, 1)
agentIdleStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).BorderForeground(textDisabled).Padding(0, 1)
diff --git a/cmd/theme_picker.go b/cmd/theme_picker.go
index ce9356496..9ca9913c0 100644
--- a/cmd/theme_picker.go
+++ b/cmd/theme_picker.go
@@ -7,7 +7,7 @@ import (
tea "charm.land/bubbletea/v2"
lipgloss "charm.land/lipgloss/v2"
- internaltheme "github.com/GrayCodeAI/rho/internal/theme"
+ internaltheme "github.com/GrayCodeAI/decoder/internal/theme"
)
// detectAutoIsDark returns whether "auto" theme currently resolves to dark.
@@ -167,7 +167,7 @@ func (tp *ThemePicker) View() tea.View {
palette := themePickerPalette(tp.entries[tp.sel].Name)
titleStyle := lipgloss.NewStyle().
- Background(rhoColor).
+ Background(decoderColor).
Foreground(lipgloss.Color(palette.OnAccent)).
Bold(true).
Padding(0, 1)
diff --git a/cmd/tips.go b/cmd/tips.go
index 26a7a01c3..677ae37cf 100644
--- a/cmd/tips.go
+++ b/cmd/tips.go
@@ -8,10 +8,10 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/storage"
+ "github.com/GrayCodeAI/decoder/internal/storage"
)
-// Tip represents a single rho usage tip.
+// Tip represents a single decoder usage tip.
type Tip struct {
ID string `json:"id"`
Text string `json:"text"`
@@ -30,7 +30,7 @@ func allTips() []Tip {
{ID: "tab-complete", Text: "Press Tab to autocomplete slash commands.", Category: "shortcuts"},
{ID: "history-nav", Text: "Press Up/Down to navigate command history.", Category: "shortcuts"},
{ID: "esc-cancel", Text: "Press Esc to cancel a running query.", Category: "shortcuts"},
- {ID: "ctrl-c-quit", Text: "Press Ctrl+C twice to quit rho.", Category: "shortcuts"},
+ {ID: "ctrl-c-quit", Text: "Press Ctrl+C twice to quit decoder.", Category: "shortcuts"},
{ID: "copy-chat", Text: "Ctrl+Shift+C or /copy copies chat; /copy input copies your draft; /mouse off enables click-drag select.", Category: "shortcuts"},
{ID: "vim-mode", Text: "Use /vim to toggle vim-style keybindings.", Category: "editing"},
{ID: "model-switch", Text: "Use /model to switch LLM models on the fly.", Category: "config"},
@@ -44,14 +44,14 @@ func allTips() []Tip {
{ID: "slash-review", Text: "Use /review to get a code review of current changes.", Category: "workflow"},
{ID: "slash-init", Text: "Use /init to analyze a new project automatically.", Category: "project"},
{ID: "add-dir", Text: "Use /add-dir to add extra directories to context.", Category: "context"},
- {ID: "slash-memory", Text: "Use /memory for AGENTS.md; /learn for lessons; /ecosystem for flux and token-engine status.", Category: "context"},
+ {ID: "slash-memory", Text: "Use /memory for AGENTS.md; /learn for lessons; /ecosystem for mux and token-engine status.", Category: "context"},
{ID: "slash-rewind", Text: "Use /rewind to undo the last exchange.", Category: "session"},
{ID: "slash-fork", Text: "Use /fork to branch off the current conversation.", Category: "session"},
{ID: "slash-context", Text: "Use /context to see what the agent knows about your project.", Category: "context"},
{ID: "slash-start", Text: "Use /start for guided setup: trust, mode, branch, first tasks.", Category: "basics"},
{ID: "slash-mode-plan", Text: "Use /mode plan to research read-only, then /mode act to implement.", Category: "workflow"},
{ID: "slash-trust", Text: "Use /trust add so project hooks and MCP can load (folder trust).", Category: "safety"},
- {ID: "slash-branch-agent", Text: "Use /branch-agent before big edits on main — creates rho/agent-* branch.", Category: "git"},
+ {ID: "slash-branch-agent", Text: "Use /branch-agent before big edits on main — creates decoder/agent-* branch.", Category: "git"},
{ID: "tool-search-select", Text: "Use ToolSearch select:Impact (etc.) to unlock optional tools on the lazy surface.", Category: "tools"},
{ID: "slash-auto-commit", Text: "Use /auto-commit on so Write/Edit create git commits automatically.", Category: "git"},
}
diff --git a/cmd/tips_test.go b/cmd/tips_test.go
index a9595ac70..95a553717 100644
--- a/cmd/tips_test.go
+++ b/cmd/tips_test.go
@@ -34,7 +34,7 @@ func TestNextTip_ReturnsNonEmpty(t *testing.T) {
orig := os.Getenv("HOME")
tmp := t.TempDir()
os.Setenv("HOME", tmp)
- os.MkdirAll(filepath.Join(tmp, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(tmp, ".decoder"), 0o755)
defer os.Setenv("HOME", orig)
tip := nextTip("")
@@ -47,7 +47,7 @@ func TestRecordTipShown(t *testing.T) {
orig := os.Getenv("HOME")
tmp := t.TempDir()
os.Setenv("HOME", tmp)
- os.MkdirAll(filepath.Join(tmp, ".rho"), 0o755)
+ os.MkdirAll(filepath.Join(tmp, ".decoder"), 0o755)
defer os.Setenv("HOME", orig)
recordTipShown("slash-help")
diff --git a/cmd/tool_policy_catalog_test.go b/cmd/tool_policy_catalog_test.go
index d753d4342..40486b74f 100644
--- a/cmd/tool_policy_catalog_test.go
+++ b/cmd/tool_policy_catalog_test.go
@@ -3,7 +3,7 @@ package cmd
import (
"testing"
- "github.com/GrayCodeAI/rho/internal/engine/safety"
+ "github.com/GrayCodeAI/decoder/internal/engine/safety"
)
// Every built-in tool must have explicit capability metadata. Without this
diff --git a/cmd/toolset_cmd.go b/cmd/toolset_cmd.go
index 8376b5d6f..cc2b833fe 100644
--- a/cmd/toolset_cmd.go
+++ b/cmd/toolset_cmd.go
@@ -5,7 +5,7 @@ import (
"fmt"
"strings"
- "github.com/GrayCodeAI/rho/internal/toolset"
+ "github.com/GrayCodeAI/decoder/internal/toolset"
"github.com/spf13/cobra"
)
@@ -17,8 +17,8 @@ var toolsetCmd = &cobra.Command{
Short: "List or resolve composable tool groups",
Long: `Named, composable tool groups for scoping an agent's tool surface.
- rho toolset List available toolsets
- rho toolset research Resolve 'research' to its concrete tool list
+ decoder toolset List available toolsets
+ decoder toolset research Resolve 'research' to its concrete tool list
Toolsets compose from other toolsets; resolving expands Requires
transitively (cycle-safe) and de-duplicates.`,
diff --git a/cmd/trust.go b/cmd/trust.go
index e4fff9e92..cb7bf9c95 100644
--- a/cmd/trust.go
+++ b/cmd/trust.go
@@ -5,10 +5,10 @@ import (
"fmt"
"os"
- "github.com/GrayCodeAI/rho/internal/theme"
+ "github.com/GrayCodeAI/decoder/internal/theme"
- "github.com/GrayCodeAI/rho/internal/flags"
- "github.com/GrayCodeAI/rho/internal/trust"
+ "github.com/GrayCodeAI/decoder/internal/flags"
+ "github.com/GrayCodeAI/decoder/internal/trust"
"github.com/spf13/cobra"
)
@@ -18,10 +18,10 @@ var trustCmd = &cobra.Command{
Long: `Folder trust controls whether project-scoped hooks, MCP servers, LSP
configs, and plugins may load from a repository.
-When RHO_Y0_FOLDER_TRUST is enabled (default after Year 0 PACK-03),
+When DECODER_Y0_FOLDER_TRUST is enabled (default after Year 0 PACK-03),
untrusted projects cannot run project automation (RCE mitigation).
-User-global plugins under the Rho state directory always load.`,
+User-global plugins under the Decoder state directory always load.`,
}
var trustAddCmd = &cobra.Command{
@@ -107,7 +107,7 @@ var trustListCmd = &cobra.Command{
fmt.Println("[]")
} else {
cmd.Println(auditTint("No trusted directories.", textMuted))
- cmd.Printf("%s\n", auditTint(fmt.Sprintf("Folder trust enforcement: %v (RHO_Y0_FOLDER_TRUST)", flags.FolderTrust()), textMuted))
+ cmd.Printf("%s\n", auditTint(fmt.Sprintf("Folder trust enforcement: %v (DECODER_Y0_FOLDER_TRUST)", flags.FolderTrust()), textMuted))
}
return nil
}
diff --git a/cmd/usage.go b/cmd/usage.go
index 4ec3429c1..ea2682e12 100644
--- a/cmd/usage.go
+++ b/cmd/usage.go
@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
- "github.com/GrayCodeAI/rho/internal/usage"
+ "github.com/GrayCodeAI/decoder/internal/usage"
"github.com/spf13/cobra"
)
@@ -65,7 +65,7 @@ func runUsage(cmd *cobra.Command, _ []string) error {
return nil
}
- cmd.Println(auditTint(fmt.Sprintf("Usage (last %s)", usagePeriod), rhoColor))
+ cmd.Println(auditTint(fmt.Sprintf("Usage (last %s)", usagePeriod), decoderColor))
cmd.Println(auditTint(fmt.Sprintf("%-28s %10s %10s %8s %12s", "model", "in", "out", "gen", "cost"), textMuted))
for _, m := range sum.ByModel {
// Pad the cost to its column width first, then colorize, so the
diff --git a/cmd/verify_cmd.go b/cmd/verify_cmd.go
index 45559f29a..18493084c 100644
--- a/cmd/verify_cmd.go
+++ b/cmd/verify_cmd.go
@@ -8,9 +8,9 @@ import (
"strings"
"time"
- "github.com/GrayCodeAI/rho/internal/governance"
- "github.com/GrayCodeAI/rho/internal/securitylog"
- "github.com/GrayCodeAI/rho/internal/testrunner"
+ "github.com/GrayCodeAI/decoder/internal/governance"
+ "github.com/GrayCodeAI/decoder/internal/securitylog"
+ "github.com/GrayCodeAI/decoder/internal/testrunner"
"github.com/spf13/cobra"
)
@@ -19,7 +19,7 @@ import (
var verifyCmd = &cobra.Command{
Use: "verify",
Short: "Run local self-verification (security log, governance policy)",
- Long: `Run rho's self-verification checks without a model:
+ Long: `Run decoder's self-verification checks without a model:
1. The tamper-evident security event log hash chain is intact.
2. The managed governance policy (if installed) parses and validates.
diff --git a/cmd/version_display.go b/cmd/version_display.go
index d18ffc71d..56dbf1d8f 100644
--- a/cmd/version_display.go
+++ b/cmd/version_display.go
@@ -11,13 +11,13 @@ import (
)
// versionLine is the single user-facing version format shared by
-// `rho --version` and `rho version`.
+// `decoder --version` and `decoder version`.
func versionLine() string {
ver := DisplayVersion()
if ver != "" && !strings.HasPrefix(ver, "v") && !strings.HasPrefix(ver, "V") {
ver = "v" + ver
}
- line := auditTint("rho", textPrimary) + " " + auditTint(ver, rhoColor)
+ line := auditTint("decoder", textPrimary) + " " + auditTint(ver, decoderColor)
if d := strings.TrimSpace(buildDate); d != "" && d != "unknown" {
line += auditTint(" (built "+d+")", textMuted)
}
@@ -28,7 +28,7 @@ func versionLine() string {
//
// In order of preference:
// 1. the version injected via ldflags (release archives, `make build`);
-// 2. the module version recorded by `go install .../cmd/rho@vX.Y.Z`;
+// 2. the module version recorded by `go install .../cmd/decoder@vX.Y.Z`;
// 3. the repository VERSION file (local `go build` / `go run` checkouts);
// 4. "dev".
func DisplayVersion() string {
@@ -53,7 +53,7 @@ var readBuildInfo = debug.ReadBuildInfo
// releaseModuleVersion returns the main module's version without the leading
// "v" when the binary was built from a tagged module (`go install
-// github.com/GrayCodeAI/rho/cmd/rho@v0.3.0`), and "" for development builds:
+// github.com/GrayCodeAI/decoder/cmd/decoder@v0.3.0`), and "" for development builds:
// "(devel)", pseudo-versions (untagged commits such as @main) and versions
// with build metadata (e.g. "+dirty" from a modified checkout).
func releaseModuleVersion() string {
diff --git a/cmd/version_display_test.go b/cmd/version_display_test.go
index 622468024..cb1941589 100644
--- a/cmd/version_display_test.go
+++ b/cmd/version_display_test.go
@@ -6,8 +6,8 @@ import (
"runtime/debug"
"testing"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/provider/gateway"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/provider/gateway"
)
func TestDisplayVersion_FromVERSIONFile(t *testing.T) {
@@ -26,7 +26,7 @@ func stubBuildInfo(t *testing.T, mainVersion string) {
t.Helper()
prev := readBuildInfo
readBuildInfo = func() (*debug.BuildInfo, bool) {
- return &debug.BuildInfo{Main: debug.Module{Path: "github.com/GrayCodeAI/rho", Version: mainVersion}}, true
+ return &debug.BuildInfo{Main: debug.Module{Path: "github.com/GrayCodeAI/decoder", Version: mainVersion}}, true
}
t.Cleanup(func() { readBuildInfo = prev })
}
@@ -80,12 +80,12 @@ func TestDisplayVersion_ReleaseBuild(t *testing.T) {
}
func TestChatConnectionStatus_NoCredentials(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
m := chatModel{session: nil}
@@ -96,12 +96,12 @@ func TestChatConnectionStatus_NoCredentials(t *testing.T) {
}
func TestChatBottomRightStatus_NoCredentials(t *testing.T) {
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
store := &gateway.MapStore{}
gateway.SetDefaultStore(store)
t.Cleanup(func() {
gateway.SetDefaultStore(nil)
- rhoconfig.InvalidateConfigUICache()
+ decoderconfig.InvalidateConfigUICache()
})
m := chatModel{inputIndicator: &InputIndicator{}}
diff --git a/cmd/visual_diff.go b/cmd/visual_diff.go
index 42ffa6650..3404fe3b3 100644
--- a/cmd/visual_diff.go
+++ b/cmd/visual_diff.go
@@ -35,7 +35,7 @@ type DiffTheme struct {
Reset string
}
-// DefaultDiffTheme returns a DiffTheme using rho's semantic palette so diff
+// DefaultDiffTheme returns a DiffTheme using decoder's semantic palette so diff
// output reads consistently with the rest of the UI: additions in doneGreen,
// deletions in errorCoral, hunk markers in infoSky, file headers in
// fileHeaderBlue — each color mapped to one meaning, never reused for another.
diff --git a/cmd/watch.go b/cmd/watch.go
index 88f4a3ddc..104edbc5c 100644
--- a/cmd/watch.go
+++ b/cmd/watch.go
@@ -7,7 +7,7 @@ import (
"sync"
"time"
- "github.com/GrayCodeAI/rho/internal/gitcmd"
+ "github.com/GrayCodeAI/decoder/internal/gitcmd"
"github.com/fsnotify/fsnotify"
)
diff --git a/cmd/welcome_banner.go b/cmd/welcome_banner.go
index ab202ab20..91c7e7515 100644
--- a/cmd/welcome_banner.go
+++ b/cmd/welcome_banner.go
@@ -6,8 +6,8 @@ import (
"github.com/mattn/go-runewidth"
)
-// rhoBlockGlyphs — fixed 8-column ██ font used by the welcome gate banners.
-var rhoBlockGlyphs = map[rune][5]string{
+// decoderBlockGlyphs — fixed 8-column ██ font used by the welcome gate banners.
+var decoderBlockGlyphs = map[rune][5]string{
'H': {"██ ██ ", "██ ██ ", "███████ ", "██ ██ ", "██ ██ "},
'A': {" ███ ", " █████ ", "███████ ", "██ ██ ", "██ ██ "},
'W': {"██ ██ ", "██ ██ ", "██ █ ██ ", "███ ███ ", "██ ██ "},
@@ -20,40 +20,29 @@ var rhoBlockGlyphs = map[rune][5]string{
'T': {"████████", " ██ ", " ██ ", " ██ ", " ██ "},
}
-/* legacyRhoLogoArtLines is retained only as a migration reference.
-var legacyRhoLogoArtLines = []string{
- "| ___ | | ___ | (\\ /) | \\",
- "| | | | | | | | \\ \\/ / | |\\ \\",
- "|___| |___| |___| |___| \\____/\\/\\____/ |___| \\___\\",
- " |0\\/0|",
- " \\/\\/",
- " \\/",
-}
-*/
-
-// rhoLogoArtLines is the canonical portable ASCII RHO wordmark.
-var rhoLogoArtLines = []string{
- " ____ _ _ ___ ",
- "| _ \\| | | |/ _ \\ ",
- "| |_) | |_| | | | |",
- "| _ <| _ | |_| |",
- "|_| \\_\\_| |_|\\___/",
+// decoderLogoArtLines is the canonical portable ASCII DECODER wordmark.
+var decoderLogoArtLines = []string{
+ " ____ _____ ____ ___ ____ _____ ____ ",
+ "| _ \\| ____/ ___/ _ \\| _ \\| ____| _ \\ ",
+ "| | | | _|| | | | | | | | | _| | |_) |",
+ "| |_| | |__| |__| |_| | |_| | |___| _ < ",
+ "|____/|_____\\____\\___/|____/|_____|_| \\_\\",
}
const (
- rhoBlockCellW = 8
- rhoBlockLetterGap = 1
- rhoBlockWordGap = 4
+ decoderBlockCellW = 8
+ decoderBlockLetterGap = 1
+ decoderBlockWordGap = 4
)
// welcomeWordLines — "WELCOME" block (row-aligned, fixed grid).
-var welcomeWordLines = composeRhoBlockLines("WELCOME")
+var welcomeWordLines = composeDecoderBlockLines("WELCOME")
// welcomeToWordLines — "TO" block, centered under WELCOME on the gate.
-var welcomeToWordLines = composeRhoBlockLines("TO")
+var welcomeToWordLines = composeDecoderBlockLines("TO")
// welcomeToPhraseLines — "WELCOME TO" block for wide welcome gates.
-var welcomeToPhraseLines = composeRhoBlockLines("WELCOME TO")
+var welcomeToPhraseLines = composeDecoderBlockLines("WELCOME TO")
// welcomeToBannerMinWidth is the visible width for the WELCOME block.
const welcomeToBannerMinWidth = 61
@@ -61,24 +50,24 @@ const welcomeToBannerMinWidth = 61
// welcomeToPhraseMinWidth is the visible width for the combined "WELCOME TO" block.
var welcomeToPhraseMinWidth = blockLinesWidth(welcomeToPhraseLines)
-func composeRhoBlockLines(text string) []string {
+func composeDecoderBlockLines(text string) []string {
rows := make([]string, 5)
words := strings.Fields(text)
for wi, word := range words {
for ci, ch := range word {
- glyph, ok := rhoBlockGlyphs[ch]
+ glyph, ok := decoderBlockGlyphs[ch]
if !ok {
continue
}
for i := range rows {
if rows[i] != "" {
if ci == 0 && wi > 0 {
- rows[i] += strings.Repeat(" ", rhoBlockWordGap)
+ rows[i] += strings.Repeat(" ", decoderBlockWordGap)
} else {
- rows[i] += strings.Repeat(" ", rhoBlockLetterGap)
+ rows[i] += strings.Repeat(" ", decoderBlockLetterGap)
}
}
- cell := padBlockCell(glyph[i], rhoBlockCellW)
+ cell := padBlockCell(glyph[i], decoderBlockCellW)
rows[i] += cell
}
}
diff --git a/cmd/welcome_banner_test.go b/cmd/welcome_banner_test.go
index d87d359c5..332343ab9 100644
--- a/cmd/welcome_banner_test.go
+++ b/cmd/welcome_banner_test.go
@@ -8,7 +8,7 @@ import (
)
func TestWelcomeToBanner_TOAligned(t *testing.T) {
- to := composeRhoBlockLines("TO")
+ to := composeDecoderBlockLines("TO")
if len(to) != 5 {
t.Fatalf("expected 5 rows, got %d", len(to))
}
@@ -48,10 +48,10 @@ func TestWelcomeToPhraseLinesContainSingleRowPhrase(t *testing.T) {
}
}
-func TestWelcomeWordLines_SameWGlyphAsRHO(t *testing.T) {
- w := strings.TrimRight(rhoBlockGlyphs['W'][0], " ")
+func TestWelcomeWordLines_SameWGlyphAsDECODER(t *testing.T) {
+ w := strings.TrimRight(decoderBlockGlyphs['W'][0], " ")
if !strings.HasPrefix(welcomeWordLines[0], w) {
- t.Fatalf("W row should start with rho logo glyph:\nwelcome: %q\nrho W: %q",
+ t.Fatalf("W row should start with decoder logo glyph:\nwelcome: %q\ndecoder W: %q",
welcomeWordLines[0], w)
}
}
diff --git a/cmd/welcome_inline_test.go b/cmd/welcome_inline_test.go
index 5374c921d..c9bfe6e19 100644
--- a/cmd/welcome_inline_test.go
+++ b/cmd/welcome_inline_test.go
@@ -8,9 +8,9 @@ import (
"charm.land/bubbles/v2/textarea"
- rhoconfig "github.com/GrayCodeAI/rho/internal/config"
- "github.com/GrayCodeAI/rho/internal/tool"
- "github.com/GrayCodeAI/rho/internal/ui/icons"
+ decoderconfig "github.com/GrayCodeAI/decoder/internal/config"
+ "github.com/GrayCodeAI/decoder/internal/tool"
+ "github.com/GrayCodeAI/decoder/internal/ui/icons"
)
type welcomeMCPStub struct {
@@ -26,7 +26,7 @@ func TestWelcomeScreenNerdIconsUnique(t *testing.T) {
icons.SetMode(icons.ModeNerd)
defer icons.SetMode(icons.ModeASCII)
- out := buildWelcomeMessage(nil, "", nil, nil, rhoconfig.Settings{}, 0, false, 100, 24)
+ out := buildWelcomeMessage(nil, "", nil, nil, decoderconfig.Settings{}, 0, false, 100, 24)
seen := make(map[rune]struct{})
for _, r := range out {
if r < 0xE000 || r > 0xF8FF {
@@ -48,7 +48,7 @@ func (s welcomeMCPStub) Execute(context.Context, json.RawMessage) (string, error
func (s welcomeMCPStub) MCPServerName() string { return s.server }
func TestBuildWelcomeMessage_InlineShowsSetupGuidance(t *testing.T) {
- out := buildWelcomeMessage(nil, "", nil, nil, rhoconfig.Settings{}, 0, false, 100, 24)
+ out := buildWelcomeMessage(nil, "", nil, nil, decoderconfig.Settings{}, 0, false, 100, 24)
if !strings.Contains(out, "v") {
t.Fatalf("inline welcome should show version, got:\n%s", out)
}
@@ -58,7 +58,7 @@ func TestBuildWelcomeMessage_InlineShowsSetupGuidance(t *testing.T) {
}
func TestBuildWelcomeMessage_InlineShowsGuidance(t *testing.T) {
- out := buildWelcomeMessage(nil, "", nil, nil, rhoconfig.Settings{}, 0, false, 100, 24)
+ out := buildWelcomeMessage(nil, "", nil, nil, decoderconfig.Settings{}, 0, false, 100, 24)
for _, want := range []string{"Skills (0)", "AGENTS.md", "MCPs (0)"} {
if !strings.Contains(out, want) {
t.Fatalf("minimal welcome missing %q in:\n%s", want, out)
@@ -97,7 +97,7 @@ func TestBuildWelcomeMessage_InlineShowsGuidance(t *testing.T) {
t.Fatalf("minimal welcome should omit %q, got:\n%s", noise, out)
}
}
- for _, guidance := range []string{"Inspect, change, or test this codebase with rho.", `Try: "explain this repo"`} {
+ for _, guidance := range []string{"Inspect, change, or test this codebase with decoder.", `Try: "explain this repo"`} {
if !strings.Contains(out, guidance) {
t.Fatalf("minimal welcome missing first-run guidance %q in:\n%s", guidance, out)
}
@@ -105,7 +105,7 @@ func TestBuildWelcomeMessage_InlineShowsGuidance(t *testing.T) {
}
func TestBuildWelcomeMessage_ShortTerminalUsesCompactCopy(t *testing.T) {
- out := buildWelcomeMessage(nil, "", nil, nil, rhoconfig.Settings{}, 0, false, 72, 20)
+ out := buildWelcomeMessage(nil, "", nil, nil, decoderconfig.Settings{}, 0, false, 72, 20)
if strings.Contains(out, "PgUp/Dn scroll chat") || strings.Contains(out, "for new session") {
t.Fatalf("compact welcome should drop verbose descriptions, got:\n%s", out)
}
@@ -114,29 +114,29 @@ func TestBuildWelcomeMessage_ShortTerminalUsesCompactCopy(t *testing.T) {
}
}
-func TestBuildWelcomeMessage_WideTerminalUsesRhoWordmark(t *testing.T) {
- out := buildWelcomeMessage(nil, "", nil, nil, rhoconfig.Settings{}, 0, false, 120, 40)
+func TestBuildWelcomeMessage_WideTerminalUsesDecoderWordmark(t *testing.T) {
+ out := buildWelcomeMessage(nil, "", nil, nil, decoderconfig.Settings{}, 0, false, 120, 40)
for _, want := range []string{
- " ____ _ _ ___ ",
- "| _ \\| | | |/ _ \\ ",
- "|_| \\_\\_| |_|\\___/",
+ " ____ _____ ____ ___ ____ _____ ____ ",
+ "| _ \\| ____/ ___/ _ \\| _ \\| ____| _ \\ ",
+ "|____/|_____\\____\\___/|____/|_____|_| \\_\\",
} {
if !strings.Contains(out, want) {
- t.Fatalf("wide welcome missing rho wordmark line %q in:\n%s", want, out)
+ t.Fatalf("wide welcome missing decoder wordmark line %q in:\n%s", want, out)
}
}
}
-func TestBuildWelcomeMessage_RhoWordmarkIsStatic(t *testing.T) {
- out := buildWelcomeMessage(nil, "", nil, nil, rhoconfig.Settings{}, 0, true, 120, 40)
- if !strings.Contains(out, " ____ _ _ ___ ") {
- t.Fatalf("blinking welcome should retain the RHO wordmark, got:\n%s", out)
+func TestBuildWelcomeMessage_DecoderWordmarkIsStatic(t *testing.T) {
+ out := buildWelcomeMessage(nil, "", nil, nil, decoderconfig.Settings{}, 0, true, 120, 40)
+ if !strings.Contains(out, " ____ _____ ____ ___ ____ _____ ____ ") {
+ t.Fatalf("blinking welcome should retain the DECODER wordmark, got:\n%s", out)
}
}
func TestBuildWelcomeMessage_GraphicalMascotKeepsTextFallback(t *testing.T) {
- out := buildWelcomeMessageWithSnapshotAndMascot(nil, "", nil, nil, rhoconfig.Settings{}, 0, 0, 0, 120, 40, welcomeStatusSnapshot{}, "", true)
- if !strings.Contains(out, " ____ _ _ ___ ") {
+ out := buildWelcomeMessageWithSnapshotAndMascot(nil, "", nil, nil, decoderconfig.Settings{}, 0, 0, 0, 120, 40, welcomeStatusSnapshot{}, "", true)
+ if !strings.Contains(out, " ____ _____ ____ ___ ____ _____ ____ ") {
t.Fatalf("graphical mascot mode must retain the text wordmark fallback, got:\n%s", out)
}
}
diff --git a/docs/BENCHMARKS.md b/docs/BENCHMARKS.md
index aa24a9210..d0272abd0 100644
--- a/docs/BENCHMARKS.md
+++ b/docs/BENCHMARKS.md
@@ -1,6 +1,6 @@
# Benchmarks
-Published, reproducible CPU benchmarks for rho. These are TUI-independent
+Published, reproducible CPU benchmarks for decoder. These are TUI-independent
measurements (no latency theater) run with existing `go test -bench` targets; they
exist so performance is documented and regressions are visible, not to make
marketing claims.
diff --git a/docs/COMPETITIVE.md b/docs/COMPETITIVE.md
index 7b54fc6f2..0fe5482c0 100644
--- a/docs/COMPETITIVE.md
+++ b/docs/COMPETITIVE.md
@@ -1,7 +1,7 @@
-# rho vs Top 20 OSS — Competitive Analysis
+# decoder vs Top 20 OSS — Competitive Analysis
Status: Implemented (branch `feat/competitive-analysis-top20`, 2026-09-09)
-Scope: rho (this repo) vs 10 AI coding CLIs + 6 dev CLIs + 4 terminals (incl. `herdr` multiplexer)
+Scope: decoder (this repo) vs 10 AI coding CLIs + 6 dev CLIs + 4 terminals (incl. `herdr` multiplexer)
Related: `docs/plans/toolbench-comparison-vs-top20.md` (tool-count parity), `docs/SECURITY-DEVELOPER.md` (permission model), `docs/plans/pi-adoption-plan.md` (Kitty graphics already proposed), `docs/RESEARCH.md` (top-20 research-paper comparison + implementation record)
## Methodology (no assumptions)
@@ -12,13 +12,13 @@ Verified from source in this repo:
- Browser/Screenshot: `tool.BrowserTool{}`, `tool.ScreenshotTool{}` in essential set (`cmd/chat_tools.go:75-76`); headless Chrome via chromedp per prior plan.
- Execution: direct host execution behind the permission engine and path guard; no container backend.
- Creds: OS secret store only, no `.env`/env read — `docs/SECURITY-DEVELOPER.md:7-12`.
-- Share: local deeplink only — `internal/session/export.go:801-819` returns `rho://share/`, no hosted URL.
+- Share: local deeplink only — `internal/session/export.go:801-819` returns `decoder://share/`, no hosted URL.
- Custom providers: supported — `internal/config/settings.go:50` (`custom_providers`), `internal/config/engine.go:32-50`.
- Unwired backends: `internal/tool/computer_use.go:67-94` (`SetComputerBackend`, nil default), `internal/tool/media_generation.go:69-71` (`SetMediaEngine`, nil default).
- Terminal detect covers kitty/ghostty/wezterm/alacritty names (`internal/ui/icons/detect_test.go:56`); Kitty graphics protocol not implemented (see `docs/plans/pi-adoption-plan.md:25`).
- Bench infra exists (`internal/features/eval/`, `make bench`) but README publishes no numbers.
-External star counts below are approximate web-search snapshots (2026-09-08), not repo-verified. Treat as order-of-magnitude traction, not exact rankings. rho is pre-release (`VERSION`: `0.0.1`, `README.md:40-44` source-build primary) — it competes on architecture, not stars.
+External star counts below are approximate web-search snapshots (2026-09-08), not repo-verified. Treat as order-of-magnitude traction, not exact rankings. decoder is pre-release (`VERSION`: `0.0.1`, `README.md:40-44` source-build primary) — it competes on architecture, not stars.
## The 20
@@ -41,7 +41,7 @@ External star counts below are approximate web-search snapshots (2026-09-08), no
### B. Dev CLIs (substrate + UX bar)
-| # | Repo | Stars~ | Lang / Lic | Lesson for rho |
+| # | Repo | Stars~ | Lang / Lic | Lesson for decoder |
|---|---|---|---|---|
| B1 | `junegunn/fzf` | ~82k | Go, MIT | Pipe-first Unix design; zero-config speed |
| B2 | `jesseduffield/lazygit` | ~82k | Go, MIT | Keyboard TUI that makes hard git trivial; closest Go-TUI comp |
@@ -61,10 +61,10 @@ External star counts below are approximate web-search snapshots (2026-09-08), no
## Deep dimensions
-1. **Traction.** rho has no star-moat (pre-release). Leaders won via day-1 provider-agnostic + one-liner install + Web/Desktop alongside TUI. rho already ships script/brew/npm paths (`README.md:48-59`) — keep, don't add Desktop.
-2. **Language/distro.** Go+MIT+zero-CGO (`Makefile:54`, `go.mod:3`) matches `gh/fzf/lazygit` enterprise-safe profile. Avoid GPL/EUPL patterns (kitty/eza). Rust wave wins on published benchmarks — rho has `make bench` but publishes none (Gap-04).
-3. **Providers.** rho routes only via `flux/engine` facade (`docs/SECURITY-DEVELOPER.md:51-56`; facade declared in `GrayCodeAI/graycode-eco/ecosystem.yaml`); custom OpenAI-compat supported (`internal/config/settings.go:50`). Count messaging ("28 first-class" per README) trails OpenCode 75+ / Hermes 300+ — fix by exposing catalog count dynamically, not by forking providers into CLI (ownership lives in router per AGENTS.md).
-4. **TUI/UX.** Bubble Tea v2 + vim keys + `/autonomy` + `/spec` + watch `AI!`/`AI?` + visual diff is competitive. Missing vs field: hosted share-link (ours is local `rho://` deeplink), multi-session grid (we have `mission` worktrees + daemon — unsurfaced like herdr/cmux). Gap-02.
+1. **Traction.** decoder has no star-moat (pre-release). Leaders won via day-1 provider-agnostic + one-liner install + Web/Desktop alongside TUI. decoder already ships script/brew/npm paths (`README.md:48-59`) — keep, don't add Desktop.
+2. **Language/distro.** Go+MIT+zero-CGO (`Makefile:54`, `go.mod:3`) matches `gh/fzf/lazygit` enterprise-safe profile. Avoid GPL/EUPL patterns (kitty/eza). Rust wave wins on published benchmarks — decoder has `make bench` but publishes none (Gap-04).
+3. **Providers.** decoder routes only via `mux/engine` facade (`docs/SECURITY-DEVELOPER.md:51-56`; facade declared in `GrayCodeAI/graycode-eco/ecosystem.yaml`); custom OpenAI-compat supported (`internal/config/settings.go:50`). Count messaging ("28 first-class" per README) trails OpenCode 75+ / Hermes 300+ — fix by exposing catalog count dynamically, not by forking providers into CLI (ownership lives in router per AGENTS.md).
+4. **TUI/UX.** Bubble Tea v2 + vim keys + `/autonomy` + `/spec` + watch `AI!`/`AI?` + visual diff is competitive. Missing vs field: hosted share-link (ours is local `decoder://` deeplink), multi-session grid (we have `mission` worktrees + daemon — unsurfaced like herdr/cmux). Gap-02.
5. **Execution safety.** Host execution keeps onboarding simple, but requires strong permission, path, approval, and audit controls. Keep those controls explicit and testable; do not add a hidden execution backend.
6. **Memory/context.** AST repomap + Harrier graph + compaction segments + relevance-prune + conversation-arc + 80% tool-result clearing exceeds most. Missing: Hermes-style auto-skill learning loop (we have curator archive + harness — surface it).
7. **Multi-agent.** `mission` worktrees + family messenger + path reservations + budgets + portable `mission-graph.json` + `graph export` (hashes only) is unique verifiable-execution story. Surface it; no new runtime needed.
diff --git a/docs/DAEMON-PORT-THREAT-MODEL.md b/docs/DAEMON-PORT-THREAT-MODEL.md
index 3c0d74e17..2253d92ac 100644
--- a/docs/DAEMON-PORT-THREAT-MODEL.md
+++ b/docs/DAEMON-PORT-THREAT-MODEL.md
@@ -1,6 +1,6 @@
-# Rho Daemon — Port 4590 Threat Model
+# Decoder Daemon — Port 4590 Threat Model
-The Rho daemon (`rho daemon`) binds an HTTP server on port **4590** (default)
+The Decoder daemon (`decoder daemon`) binds an HTTP server on port **4590** (default)
of the **loopback interface only** (`127.0.0.1:4590`). This document describes
the threat model, attack surface, and mitigation controls.
@@ -33,19 +33,19 @@ A malicious local process (malware, compromised script) can send HTTP requests
to `127.0.0.1:4590` without any network privilege.
**Mitigation:**
-- Set `RHO_DAEMON_API_KEY` and configure the daemon with `--api-key` to
+- Set `DECODER_DAEMON_API_KEY` and configure the daemon with `--api-key` to
require `Authorization: Bearer ` on all non-readiness endpoints.
- The key is validated per-request; the daemon does not issue tokens.
#### T3 — Port scanning / fingerprinting
-Any local process can detect that port 4590 is open and identify rho.
+Any local process can detect that port 4590 is open and identify decoder.
**Mitigation:** Low severity — this is unavoidable for a local HTTP service.
The daemon does not expose version information on unauthenticated endpoints.
#### T4 — Session data exfiltration
Session data (conversation history, tool outputs) is stored in SQLite at
-`~/.rho/sessions/rho.db`. A local attacker with filesystem read access can
+`~/.decoder/sessions/decoder.db`. A local attacker with filesystem read access can
read this file directly regardless of the daemon's auth.
**Mitigation:**
@@ -59,7 +59,7 @@ credits.
**Mitigation:**
- A global concurrency cap bounds in-flight generations (default **4**, tuned
- via `RHO_DAEMON_MAX_CONCURRENT`). When the cap is hit, new `/v1/chat`
+ via `DECODER_DAEMON_MAX_CONCURRENT`). When the cap is hit, new `/v1/chat`
requests are refused with `503` instead of queuing unboundedly.
- Per-IP token-bucket rate limiting: `/v1/chat` is limited to ~30 req/min
(burst 6) and other authenticated endpoints to ~10 req/min (burst 4).
@@ -73,7 +73,7 @@ credits.
- **Remote network attackers**: the daemon does not bind to `0.0.0.0`; remote
access is architecturally blocked.
-- **Process privilege escalation**: rho does not run as root and does not use
+- **Process privilege escalation**: decoder does not run as root and does not use
`setuid`/`setgid`.
---
@@ -84,11 +84,11 @@ Set the daemon API key before starting the daemon:
```bash
# Option 1: environment variable (recommended for CI/automation)
-export RHO_DAEMON_API_KEY="your-random-secret-here"
-rho daemon
+export DECODER_DAEMON_API_KEY="your-random-secret-here"
+decoder daemon
# Option 2: CLI flag
-rho daemon --api-key "your-random-secret-here"
+decoder daemon --api-key "your-random-secret-here"
```
All clients must then pass:
@@ -96,7 +96,7 @@ All clients must then pass:
Authorization: Bearer your-random-secret-here
```
-The SDK reads this from `RHO_DAEMON_API_KEY` automatically if the env var is
+The SDK reads this from `DECODER_DAEMON_API_KEY` automatically if the env var is
set.
---
@@ -104,10 +104,10 @@ set.
## Changing the port
```bash
-rho daemon --port 9000
+decoder daemon --port 9000
```
-Or in `~/.rho/settings.json`:
+Or in `~/.decoder/settings.json`:
```json
{
"daemon": {
@@ -120,13 +120,13 @@ Or in `~/.rho/settings.json`:
## Shared machine considerations
-If rho is running on a machine shared by multiple OS users (e.g., a dev
+If decoder is running on a machine shared by multiple OS users (e.g., a dev
server), set the API key **and** use OS firewall rules to restrict which local
users can connect to port 4590:
```bash
# macOS — pf: allow only current user's processes (requires pf.conf editing)
-# Linux — iptables: allow only the rho-owner UID
+# Linux — iptables: allow only the decoder-owner UID
sudo iptables -A OUTPUT -p tcp --dport 4590 -m owner ! --uid-owner $UID -j REJECT
```
diff --git a/docs/DEVELOPER-PATH.md b/docs/DEVELOPER-PATH.md
index 4766fb0ab..8825b96be 100644
--- a/docs/DEVELOPER-PATH.md
+++ b/docs/DEVELOPER-PATH.md
@@ -1,120 +1,120 @@
-# Rho Developer Path
+# Decoder Developer Path
-This guide explains what `rho path` checks and how to get a fresh developer machine ready to use Rho safely.
+This guide explains what `decoder path` checks and how to get a fresh developer machine ready to use Decoder safely.
## What "developer path" means
-For Rho, the developer path is the minimum local setup required to chat, edit code, and keep credentials off disk:
+For Decoder, the developer path is the minimum local setup required to chat, edit code, and keep credentials off disk:
- A provider credential stored in the OS secret store
-- A model selected in Rho settings
-- A local model catalog available through flux
-- No plaintext API keys left in Flux's configured `provider.json` or legacy env files
+- A model selected in Decoder settings
+- A local model catalog available through mux
+- No plaintext API keys left in Mux's configured `provider.json` or legacy env files
- Safe defaults for Bash execution and filesystem access
- Optional but healthy local memory and token-pipeline state
Run the report at any time:
```bash
-rho path
-rho path --strict
-rho doctor
-rho preflight
+decoder path
+decoder path --strict
+decoder doctor
+decoder preflight
```
## Setup checklist
### 1. Build and workspace setup
-If you are contributing from source, clone Rho as the main CLI. The support
+If you are contributing from source, clone Decoder as the main CLI. The support
repositories are independent sibling checkouts when you need the full local
-workspace; they are not nested under Rho:
+workspace; they are not nested under Decoder:
```bash
mkdir graycode-eco && cd graycode-eco
-git clone https://github.com/GrayCodeAI/rho
-git clone https://github.com/GrayCodeAI/flux
-cd rho
+git clone https://github.com/GrayCodeAI/decoder
+git clone https://github.com/GrayCodeAI/mux
+cd decoder
make setup
-go build -o rho ./cmd/rho
+go build -o decoder ./cmd/decoder
```
`make setup` validates the canonical repository manifest and regenerates the
parent `../go.work` from the local Go repositories marked `workspace: true`.
-Rho can also be built as a standalone checkout with `GOWORK=off go build ./cmd/rho`;
+Decoder can also be built as a standalone checkout with `GOWORK=off go build ./cmd/decoder`;
the sibling workspace is only required for cross-repository development and
boundary checks.
### 2. Configure credentials
-Start Rho and use `/config` to paste an API key or configure a local provider like Ollama.
+Start Decoder and use `/config` to paste an API key or configure a local provider like Ollama.
-Rho stores credentials in the macOS Keychain or Linux secret store. It should not rely on shell env vars, `.env`, or plaintext config files for provider secrets.
+Decoder stores credentials in the macOS Keychain or Linux secret store. It should not rely on shell env vars, `.env`, or plaintext config files for provider secrets.
Useful checks:
```bash
-rho credentials status
-rho preflight
+decoder credentials status
+decoder preflight
```
-`rho preflight` is a local-ready check; it does not contact a provider. To
+`decoder preflight` is a local-ready check; it does not contact a provider. To
live-verify the selected provider credential and connectivity, use `/config`
-validation or `rho models list --live`.
+validation or `decoder models list --live`.
### 3. Select a model
-Pick a model in `/config`. Rho stores the selected model in settings and uses flux for provider routing and catalog resolution.
+Pick a model in `/config`. Decoder stores the selected model in settings and uses mux for provider routing and catalog resolution.
If the catalog is missing or empty:
```bash
-rho models refresh
+decoder models refresh
```
## Security checks
-`rho path` treats these as important security conditions:
+`decoder path` treats these as important security conditions:
-- Flux's resolved `provider.json` must not contain secret fields
+- Mux's resolved `provider.json` must not contain secret fields
- sensitive files like provider config and SSH paths should be blocked from agent reads
-Flux resolves provider state from `FLUX_CONFIG_DIR` first, then the
+Mux resolves provider state from `MUX_CONFIG_DIR` first, then the
platform user-config directory.
-Rho protects that resolved path even when it is customized or symlinked.
+Decoder protects that resolved path even when it is customized or symlinked.
-If Rho detects secret fields in `provider.json`, back up the file, remove those fields manually, and save your keys again through `/config`.
+If Decoder detects secret fields in `provider.json`, back up the file, remove those fields manually, and save your keys again through `/config`.
Read the full credential and isolation model in [SECURITY-DEVELOPER.md](./SECURITY-DEVELOPER.md).
## Execution model
-Rho executes agent commands directly on the host. No Docker daemon or
+Decoder executes agent commands directly on the host. No Docker daemon or
container runtime is required, and there is no container fallback to configure.
## Ecosystem checks
-`rho path` also verifies the provider layer behind Rho:
+`decoder path` also verifies the provider layer behind Decoder:
-- `flux` for provider routing and local preflight readiness
+- `mux` for provider routing and local preflight readiness
- the embedded token pipeline for estimation and compression
If you want the broader status summary:
```bash
-rho ecosystem
-rho doctor
+decoder ecosystem
+decoder doctor
```
## Typical recovery path
-If `rho path` says you are not ready, this is the intended order:
+If `decoder path` says you are not ready, this is the intended order:
-1. Run `rho`
+1. Run `decoder`
2. Open `/config`
3. Paste an API key or configure Ollama
4. Pick a model
-5. Re-run `rho preflight`
-6. Re-run `rho path`
+5. Re-run `decoder preflight`
+6. Re-run `decoder path`
If security items still fail, fix those before treating the machine as ready.
diff --git a/docs/DYNAMIC-MODELS.md b/docs/DYNAMIC-MODELS.md
index 214728d9f..25a3066d3 100644
--- a/docs/DYNAMIC-MODELS.md
+++ b/docs/DYNAMIC-MODELS.md
@@ -1,10 +1,10 @@
-# Dynamic Model Discovery — Rho Developer Guide
+# Dynamic Model Discovery — Decoder Developer Guide
## Ownership and flow
-Rho is the product face; Flux is the provider engine. Rho owns the CLI/TUI,
+Decoder is the product face; Mux is the provider engine. Decoder owns the CLI/TUI,
model-picker presentation, user intent, and output compatibility. The
-`flux/engine` facade alone owns provider registry details, credentials,
+`mux/engine` facade alone owns provider registry details, credentials,
discovery, catalog/cache policy, model aliases, deployment routing, and chat
transport.
@@ -12,23 +12,23 @@ transport.
provider APIs / remote catalog / local cache
|
v
- flux/engine.Engine
+ mux/engine.Engine
catalog + credentials + routing
|
stable host DTOs and methods
v
- Rho composition and presentation
+ Decoder composition and presentation
/config | models | conversation
```
-Production Rho packages must not import Flux packages below
-`github.com/GrayCodeAI/flux/engine`. Shell and AST guards enforce a
+Production Decoder packages must not import Mux packages below
+`github.com/GrayCodeAI/mux/engine`. Shell and AST guards enforce a
zero-exception boundary.
-## Rho composition boundary
+## Decoder composition boundary
-`internal/config` is Rho's control-plane composition root. It creates an
-Flux engine and projects engine models into Rho UI and command contracts:
+`internal/config` is Decoder's control-plane composition root. It creates an
+Mux engine and projects engine models into Decoder UI and command contracts:
```go
models, err := config.ListEngineModels(ctx, "anthropic", false)
@@ -36,36 +36,36 @@ live, err := config.ListEngineModels(ctx, "anthropic", true)
public, err := config.ListPublicEngineModels(ctx, "xiaomi_mimo_payg")
```
-Conversation construction goes through Rho's `internal/engine` adapter. The
-adapter translates Rho-owned message, tool, usage, and stream DTOs to the
-Flux engine facade; conversation history, WAL, resume, approvals, and tool
-execution remain Rho-owned.
+Conversation construction goes through Decoder's `internal/engine` adapter. The
+adapter translates Decoder-owned message, tool, usage, and stream DTOs to the
+Mux engine facade; conversation history, WAL, resume, approvals, and tool
+execution remain Decoder-owned.
## Catalog and live discovery
-The Flux engine combines its provider registry, provider-scoped live
-discovery, and the cache at `~/.flux/model_catalog.json` by default. Override
-the cache with `FLUX_MODEL_CATALOG_PATH`. Credential and state dependencies
+The Mux engine combines its provider registry, provider-scoped live
+discovery, and the cache at `~/.mux/model_catalog.json` by default. Override
+the cache with `MUX_MODEL_CATALOG_PATH`. Credential and state dependencies
are injected into each Engine instance, so discovery does not need hidden
process-global credentials.
Use the normal cache-backed path for repeatable UI and automation:
```bash
-rho models list anthropic
-rho models list anthropic --json
+decoder models list anthropic
+decoder models list anthropic --json
```
Use a provider-scoped live request when current connectivity and credentials
must be checked:
```bash
-rho models list anthropic --live
-rho models list anthropic --live --json
-rho models list anthropic --live --raw
+decoder models list anthropic --live
+decoder models list anthropic --live --json
+decoder models list anthropic --live --raw
```
-`rho preflight` reports **local readiness**: usable local state, a selected
+`decoder preflight` reports **local readiness**: usable local state, a selected
model, and presence of the required stored credential. It is intentionally
cheap and does not prove that a remote provider accepts that credential.
Treat a successful provider-scoped `--live` request (or `/config` live
@@ -73,8 +73,8 @@ validation) as **live verified**.
## Stable command output
-`rho models list --json` is a Rho-owned compatibility contract, not a direct
-serialization of Flux's evolving `engine.Model` DTO. Its stable fields are:
+`decoder models list --json` is a Decoder-owned compatibility contract, not a direct
+serialization of Mux's evolving `engine.Model` DTO. Its stable fields are:
```text
id, input_price_per_1m, output_price_per_1m, context_window, max_output,
@@ -83,37 +83,37 @@ server_tools, display_name, description, owner, live_metadata
New fields must be additive. `--raw` returns provider-native
`live_metadata` objects when available; for cache/public rows without native
-metadata, it returns the stable Rho compatibility row instead of `null`.
+metadata, it returns the stable Decoder compatibility row instead of `null`.
## Custom gateways
-Rho converts effective `custom_providers` settings into
+Decoder converts effective `custom_providers` settings into
`engine.Options.CustomGateways` at its composition root. Custom gateway
metadata is snapshotted per Engine instance. Do not register custom gateways
-in Flux process-global state: tests, parallel sessions, and future multi-tenant
+in Mux process-global state: tests, parallel sessions, and future multi-tenant
hosts must be isolated from one another.
## Adding or changing a provider
1. Implement registry, discovery, credentials, aliases, and transport behavior
- behind Flux's engine facade.
-2. Add Flux tests for cache and live discovery, credential status, selection,
+ behind Mux's engine facade.
+2. Add Mux tests for cache and live discovery, credential status, selection,
and generation/streaming.
-3. Commit and verify standalone Flux.
-4. Advance Rho's `../flux` sibling checkout to that exact commit, then update
- Rho's module version when the Flux revision is published.
+3. Commit and verify standalone Mux.
+4. Advance Decoder's `../mux` sibling checkout to that exact commit, then update
+ Decoder's module version when the Mux revision is published.
5. Verify both the workspace (`go.work`) and published-module
(`GOWORK=off`) build modes.
-Rho changes are needed only for a new product behavior or an additive
-Rho-owned presentation field—not for provider-specific mechanics.
+Decoder changes are needed only for a new product behavior or an additive
+Decoder-owned presentation field—not for provider-specific mechanics.
## Checks
```bash
-rho models refresh
-rho models status
-rho preflight
-make flux-engine-guard
+decoder models refresh
+decoder models status
+decoder preflight
+make mux-engine-guard
go test ./cmd ./internal/config ./internal/engine -count=1
```
diff --git a/docs/ECOSYSTEM-CONFIG.md b/docs/ECOSYSTEM-CONFIG.md
index 72e33b32b..5020cfa23 100644
--- a/docs/ECOSYSTEM-CONFIG.md
+++ b/docs/ECOSYSTEM-CONFIG.md
@@ -3,9 +3,9 @@
Status: Draft / historical spec (aspirational; not implemented)
Applies to: the wider graycode-eco ecosystem
-> Note: Rho now depends only on flux and embeds its own token engine.
+> Note: Decoder now depends only on mux and embeds its own token engine.
> References below to harrier, shrike, and swift describe a proposed
-> ecosystem-wide schema, not Rho's current runtime.
+> ecosystem-wide schema, not Decoder's current runtime.
This document specifies a **single, unified configuration schema** for the
graycode-eco ecosystem: one declarative file (`graycode-eco.yaml`, with an equivalent
@@ -15,7 +15,7 @@ file is the source of truth, version-controlled alongside a project, and each
repo reads the slice of the schema it owns.
Today each repo configures itself independently through its own env vars,
-flags, and config files (rho: `config.json` + `RHO_*`/`RHO_*` env; flux:
+flags, and config files (decoder: `config.json` + `DECODER_*`/`DECODER_*` env; mux:
provider env vars; harrier: `~/.harrier/config.toml`; shrike: `TOK_*` env; swift:
`SWIFT_*` env). This spec does **not** replace those mechanisms — it defines a
superset schema and maps every setting back to the repo + existing env
@@ -31,7 +31,7 @@ any runtime behavior.
`graycode-eco.yaml` value > repo default. This preserves current behavior where
env/flags are authoritative.
3. **Repo-owned sections.** Each top-level section is owned by one repo (with
- `model`/`providers` shared by rho + flux). A repo only reads its sections.
+ `model`/`providers` shared by decoder + mux). A repo only reads its sections.
4. **Two encodings, one schema.** YAML is canonical for humans; the identical
structure is valid JSON for machine generation. (harrier's on-disk format is
TOML; its section maps 1:1 to `~/.harrier/config.toml`.)
@@ -44,7 +44,7 @@ Search order (first found wins for the file itself; values still follow the
runtime precedence above):
1. `--config ` flag (where a repo's CLI supports it)
-2. `$RHO_ECO_CONFIG`
+2. `$DECODER_ECO_CONFIG`
3. `./graycode-eco.yaml` (project root)
4. `~/.config/graycode-eco/config.yaml`
@@ -53,7 +53,7 @@ runtime precedence above):
```yaml
version: 1
-# ─── Shared: model + providers (rho + flux) ───────────────────────────────
+# ─── Shared: model + providers (decoder + mux) ───────────────────────────────
model:
default: anthropic/claude-sonnet-4-5 # provider/model the agent uses
small_fast: anthropic/claude-haiku # cheap model for trivial steps
@@ -70,16 +70,16 @@ providers:
api_key_env: GEMINI_API_KEY
model: gemini-2.0-flash
-# ─── flux: gateway / runtime ───────────────────────────────────────────────
+# ─── mux: gateway / runtime ───────────────────────────────────────────────
gateway:
- base_url: http://localhost:8080 # flux endpoint rho talks to
- api_key_env: FLUX_API_KEY
+ base_url: http://localhost:8080 # mux endpoint decoder talks to
+ api_key_env: MUX_API_KEY
allow_insecure_public_api: false
- deployment_routing: "" # FLUX_DEPLOYMENT_ROUTING
+ deployment_routing: "" # MUX_DEPLOYMENT_ROUTING
model_catalog:
- path_env: FLUX_MODEL_CATALOG_PATH
- url_env: FLUX_MODEL_CATALOG_URL
- refresh: FLUX_MODEL_CATALOG_REFRESH
+ path_env: MUX_MODEL_CATALOG_PATH
+ url_env: MUX_MODEL_CATALOG_URL
+ refresh: MUX_MODEL_CATALOG_REFRESH
# ─── harrier: memory ───────────────────────────────────────────────────────────
memory:
@@ -123,9 +123,9 @@ swift:
telemetry:
# OTel exporter settings shared by all repos. Span attribute keys follow
# docs/OTEL-CONVENTIONS.md.
- enabled: false # rho: RHO_ENABLE_TELEMETRY
+ enabled: false # decoder: DECODER_ENABLE_TELEMETRY
otlp_endpoint: "" # OTEL_EXPORTER_OTLP_ENDPOINT
- shutdown_timeout_ms: 0 # RHO_OTEL_SHUTDOWN_TIMEOUT_MS
+ shutdown_timeout_ms: 0 # DECODER_OTEL_SHUTDOWN_TIMEOUT_MS
```
## Setting → repo → existing mechanism
@@ -133,30 +133,30 @@ telemetry:
The authoritative mapping. "Mechanism today" is what already implements the
setting; the unified key is rendered down to it.
-### Shared: model / providers (rho + flux)
+### Shared: model / providers (decoder + mux)
| Unified key | Repo | Mechanism today |
|---------------------------------|-------------|--------------------------------------------------|
-| `model.default` | rho | `RHO_MODEL` env / `config.json` |
-| `model.small_fast` | rho | `RHO_SMALL_FAST_MODEL` env |
-| `providers[].api_key_env` | flux/rho | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, `XAI_API_KEY`, `ZAI_API_KEY`, `CANOPYWAVE_API_KEY`, `FIREWORKS_API_KEY` |
-| `providers[].base_url_env` | flux | `ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL` / `OPENAI_API_BASE`, `OLLAMA_BASE_URL`, `FIREWORKS_BASE_URL` |
-| `providers[].model` (openai) | flux | `OPENAI_MODEL` env |
-| `providers[].model` (gemini) | flux | `GEMINI_MODEL` env |
-| `providers[].model` (anthropic) | flux | `ANTHROPIC_MODEL` env |
+| `model.default` | decoder | `DECODER_MODEL` env / `config.json` |
+| `model.small_fast` | decoder | `DECODER_SMALL_FAST_MODEL` env |
+| `providers[].api_key_env` | mux/decoder | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, `XAI_API_KEY`, `ZAI_API_KEY`, `CANOPYWAVE_API_KEY`, `FIREWORKS_API_KEY` |
+| `providers[].base_url_env` | mux | `ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL` / `OPENAI_API_BASE`, `OLLAMA_BASE_URL`, `FIREWORKS_BASE_URL` |
+| `providers[].model` (openai) | mux | `OPENAI_MODEL` env |
+| `providers[].model` (gemini) | mux | `GEMINI_MODEL` env |
+| `providers[].model` (anthropic) | mux | `ANTHROPIC_MODEL` env |
-### flux: gateway / runtime
+### mux: gateway / runtime
-| Unified key | Mechanism today (flux) |
+| Unified key | Mechanism today (mux) |
|--------------------------------------|--------------------------------------|
-| `gateway.base_url` | `FLUX_BASE_URL` (rho→flux link) |
-| `gateway.api_key_env` | `FLUX_API_KEY` |
-| `gateway.allow_insecure_public_api` | `FLUX_ALLOW_INSECURE_PUBLIC_API` |
-| `gateway.deployment_routing` | `FLUX_DEPLOYMENT_ROUTING` (also `RHO_DEPLOYMENT_ROUTING`) |
-| `gateway.model_catalog.path_env` | `FLUX_MODEL_CATALOG_PATH` |
-| `gateway.model_catalog.url_env` | `FLUX_MODEL_CATALOG_URL` |
-| `gateway.model_catalog.refresh` | `FLUX_MODEL_CATALOG_REFRESH` / `RHO_AUTO_REFRESH_CATALOG` / `RHO_CATALOG_REFRESH_ALWAYS` |
-| `gateway` config dir | `FLUX_CONFIG_DIR` (default `/flux`) |
+| `gateway.base_url` | `MUX_BASE_URL` (decoder→mux link) |
+| `gateway.api_key_env` | `MUX_API_KEY` |
+| `gateway.allow_insecure_public_api` | `MUX_ALLOW_INSECURE_PUBLIC_API` |
+| `gateway.deployment_routing` | `MUX_DEPLOYMENT_ROUTING` (also `DECODER_DEPLOYMENT_ROUTING`) |
+| `gateway.model_catalog.path_env` | `MUX_MODEL_CATALOG_PATH` |
+| `gateway.model_catalog.url_env` | `MUX_MODEL_CATALOG_URL` |
+| `gateway.model_catalog.refresh` | `MUX_MODEL_CATALOG_REFRESH` / `DECODER_AUTO_REFRESH_CATALOG` / `DECODER_CATALOG_REFRESH_ALWAYS` |
+| `gateway` config dir | `MUX_CONFIG_DIR` (default `/mux`) |
### harrier: memory
@@ -197,22 +197,22 @@ few env vars.
### swift + telemetry
-| Unified key | Mechanism today (swift / rho) |
+| Unified key | Mechanism today (swift / decoder) |
|-----------------------------------|-------------------------------------------------|
| `swift.search_url` | `SWIFT_SEARCH_URL` env |
| `swift.log_level` | `SWIFT_LOG_LEVEL` env |
| `swift.telemetry_optout` | `SWIFT_TELEMETRY_OPTOUT` / `SWIFT_NO_TELEMETRY` env |
| `swift.posthog.api_key_env` | `POSTHOG_API_KEY` env |
| `swift.posthog.endpoint` | `POSTHOG_ENDPOINT` env |
-| `telemetry.enabled` | `RHO_ENABLE_TELEMETRY` env (rho) |
-| `telemetry.shutdown_timeout_ms` | `RHO_OTEL_SHUTDOWN_TIMEOUT_MS` env (rho) |
+| `telemetry.enabled` | `DECODER_ENABLE_TELEMETRY` env (decoder) |
+| `telemetry.shutdown_timeout_ms` | `DECODER_OTEL_SHUTDOWN_TIMEOUT_MS` env (decoder) |
| `telemetry.otlp_endpoint` | `OTEL_EXPORTER_OTLP_ENDPOINT` (standard OTel) |
## Rendering down to per-repo config
The unified file is designed to be **resolved** into the existing mechanisms:
-- **env-based repos** (rho, flux, shrike, swift): export the mapped env var for
+- **env-based repos** (decoder, mux, shrike, swift): export the mapped env var for
any key set in `graycode-eco.yaml` that is not already present in the process
environment (preserving "env wins" precedence).
- **file-based repos** (harrier): write/merge the `memory.*` section into
@@ -234,7 +234,7 @@ The schema is encoding-agnostic. The YAML above is identical in structure to:
"providers": [
{ "name": "anthropic", "api_key_env": "ANTHROPIC_API_KEY" }
],
- "gateway": { "base_url": "http://localhost:8080", "api_key_env": "FLUX_API_KEY" },
+ "gateway": { "base_url": "http://localhost:8080", "api_key_env": "MUX_API_KEY" },
"memory": { "addr": "127.0.0.1:3456", "data_dir": "~/.harrier" },
"compression": { "enabled": true, "db_path": "~/.shrike/usage.db" },
"swift": { "telemetry_optout": false },
@@ -246,5 +246,5 @@ The schema is encoding-agnostic. The YAML above is identical in structure to:
The `telemetry` and `swift` sections only configure *transport/opt-out*. The
*attribute vocabulary* emitted on spans is defined separately in
-[`OTEL-CONVENTIONS.md`](./OTEL-CONVENTIONS.md), with flux's
+[`OTEL-CONVENTIONS.md`](./OTEL-CONVENTIONS.md), with mux's
`internal/observability` package as the reference implementation.
diff --git a/docs/ECOSYSTEM-ROADMAP.md b/docs/ECOSYSTEM-ROADMAP.md
index b299cc794..24c4cd317 100644
--- a/docs/ECOSYSTEM-ROADMAP.md
+++ b/docs/ECOSYSTEM-ROADMAP.md
@@ -1,7 +1,7 @@
# GrayCode Ecosystem Roadmap (2026)
**Status:** Active · **Last updated:** 2026-09-09
-**Scope:** the 4 in-workspace repos — `rho`, `flux`,
+**Scope:** the 4 in-workspace repos — `decoder`, `mux`,
`graycode-skills`, `graycode-platform` — plus the 5 external engine repos they
depend on.
**Evidence base:** `docs/RESEARCH.md`, `docs/COMPETITIVE.md`, `docs/plans/competitive-gap-*.md`
@@ -30,7 +30,7 @@ load-bearing bets:
3. **Portable execution graph** — every agent run is exported as a verifiable,
hash-addressed graph (provenance for replay/audit).
4. **Router-facade-only provider access** — the CLI never talks to an LLM API
- directly; `flux/engine` is the sole boundary.
+ directly; `mux/engine` is the sole boundary.
The roadmap is organized around making those bets *true and honest* end-to-end,
then extending the surface where the field (Codex, OpenCode, Gemini CLI, Goose,
@@ -38,7 +38,7 @@ Claude Code) has proven demand.
### The single most important fact (historical)
-`rho` imports **5 engine modules** — `harrier` (memory graph),
+`decoder` imports **5 engine modules** — `harrier` (memory graph),
`shrike` (token/compress), `kestrel` (code review), `merlin` (site audit),
`swift` (session correlation) — that were **absent from this workspace and 404
on GitHub**. They were replaced in `go.mod` by no-op stubs, so the CLI compiled
@@ -56,12 +56,12 @@ dropped.
| Repo | Role | Build | Tests | Health |
|---|---|---|---|---|
-| `rho` | Product face (Go, Bubble Tea v2) | ✅ `go build ./...` | ✅ 179 pkgs green | Engines restored; memory/token/review/audit/correlation live |
-| `flux` | Provider runtime (Go) | ✅ | ✅ 37 pkgs green | Healthy; 28 providers; gRPC ChatService wired |
+| `decoder` | Product face (Go, Bubble Tea v2) | ✅ `go build ./...` | ✅ 179 pkgs green | Engines restored; memory/token/review/audit/correlation live |
+| `mux` | Provider runtime (Go) | ✅ | ✅ 37 pkgs green | Healthy; 28 providers; gRPC ChatService wired |
| `graycode-skills` | Skill marketplace (Python) | ✅ | ✅ 382/382 | Healthy; single parsed schema |
| `graycode-platform` | Web + Cloud control plane (TS) | ✅ | ✅ 320 worker / 33 web | Healthy; worker+bff routes added; migration deduped |
-### 2.1 rho
+### 2.1 decoder
- Builds and vets clean **only because** the 5 engines are stubbed.
- **5 failing tests:** `internal/token/shrike_test.go` asserts real token counts
@@ -70,10 +70,10 @@ dropped.
- `internal/token/shrike.go` — token counting/compression → 0 / identity.
- `internal/intelligence/memory/harrier_bridge.go` — `Ready()` is true but
nothing persists (stub store returns nil DB).
- - `internal/bridge/kestrel/bridge.go` — `rho review run|analyze` always
+ - `internal/bridge/kestrel/bridge.go` — `decoder review run|analyze` always
report "no issues found" / status `Passed`.
- `internal/bridge/merlin/bridge.go` — site audits return 0 pages/findings.
- - `cmd/swift.go` / `cmd/swift_correlation.go` — `rho swift` has no
+ - `cmd/swift.go` / `cmd/swift_correlation.go` — `decoder swift` has no
working subcommands; correlation silently errors.
- `internal/engine/compact.go` etc. — context compaction depends on shrike.
- **Orphaned code:** `cmd/merlin_pipeline.go` defines + unit-tests
@@ -84,7 +84,7 @@ dropped.
`shrike: embedded · token/compress pipeline OK (sample=0 tokens)` — sample 0
should be a red flag, not OK.
-### 2.2 flux
+### 2.2 mux
- Healthy and self-contained. 28 `ProviderSpec`s, ~25 adapters, weighted/strategy
LB, retries, semantic cache, circuit breakers, deployment router, OpenAI-compat
@@ -188,7 +188,7 @@ Make the current state truthful and green. **No new user-facing features.**
| # | Repo | Task | Acceptance | Effort |
|---|---|---|---|---|
| 0.1 | cli | Add `token.ShrikeAvailable()` functional probe; guard the 5 shrike boundary tests to skip when the engine is the stub | `go test ./internal/token/...` green; stub detected as unavailable | 0.5d ✅ |
-| 0.2 | cli | Report shrike honestly in `ecosystem` / `doctor` (unavailable when stub, not "pipeline OK (sample=0)") | `rho ecosystem` flags stub; JSON `shrike.embedded=false` | 0.5d ✅ |
+| 0.2 | cli | Report shrike honestly in `ecosystem` / `doctor` (unavailable when stub, not "pipeline OK (sample=0)") | `decoder ecosystem` flags stub; JSON `shrike.embedded=false` | 0.5d ✅ |
| 0.3 | skills | Make `manifest-schema.toml` the single source of truth; wire a validator into CI that enforces the *enforced* schema (not the aspirational one) | schema parsed by tooling; CI gate matches reality; corpus still 0-warning | 1-2d ✅ |
| 0.4 | skills | Add a declared dev/test dependency group so `pytest`/`ruff`/`pytest-cov` install reproducibly | `pip install -e '.[dev]'` then `pytest` green | 0.5d ✅ |
| 0.5 | platform | Renumber duplicate migration `0022_identity_ui.sql` → `0023`; dedupe identity schema note | migrations apply in deterministic order; tests green | 0.5d ✅ |
@@ -210,14 +210,14 @@ memory, token, review, audit, and correlation features are dead.
| 1.5 | `swift` | session correlation / checkpoint linking | `graph correlation` subcommand the CLI shells into |
**Acceptance:** `go.mod` `replace` directives removed; `make check-replace`
-passes; `rho path` shows all engines genuinely ready; `go test ./...`
+passes; `decoder path` shows all engines genuinely ready; `go test ./...`
green with real engines. **Effort:** 4-8 weeks total across the 5 repos.
### Phase 2 — Product honesty + verification surface (P1)
| # | Repo | Task | Acceptance |
|---|---|---|---|
-| 2.1 | cli | Wire `RunMerlinPipeline` into a `rho audit`/`merlin` command (orphaned code) | command runs the pipeline end-to-end with a real merlin |
+| 2.1 | cli | Wire `RunMerlinPipeline` into a `decoder audit`/`merlin` command (orphaned code) | command runs the pipeline end-to-end with a real merlin |
| 2.2 | cli | Wire `BeamSearch` into the live agent loop as scorer/expander | tree-search used for planning with real model outputs |
| 2.3 | cli | Publish benchmark numbers in README (Gap-04 follow-through) | `make bench` numbers in README, cited |
| 2.4 | router | Wire the gRPC `ChatService` behind the `grpc` build tag | `grpc`-tagged build serves Chat; unit-tested |
@@ -242,7 +242,7 @@ green with real engines. **Effort:** 4-8 weeks total across the 5 repos.
- IDE integration (VS Code extension) — only after engines restored.
- Hosted share links / multi-session grid (herdr-style) — Gap-02 follow-through.
-- Provider-count messaging: expose `flux` catalog count dynamically.
+- Provider-count messaging: expose `mux` catalog count dynamically.
- OpenTelemetry/metrics consolidation across engines (per `OTEL-CONVENTIONS.md`).
---
@@ -271,7 +271,7 @@ green with real engines. **Effort:** 4-8 weeks total across the 5 repos.
## 7. Metrics
- `go test ./...` green in all Go repos; `make ci` green.
-- `rho path` / `rho ecosystem` report engine availability honestly.
+- `decoder path` / `decoder ecosystem` report engine availability honestly.
- Skills: 0-warning corpus maintained; single parsed schema.
- Platform: worker reachable at a stable domain; migrations deterministic.
- Benchmarks published (per Gap-04).
diff --git a/docs/ECOSYSTEM-WIRING.md b/docs/ECOSYSTEM-WIRING.md
index 50c5d3027..022ece72d 100644
--- a/docs/ECOSYSTEM-WIRING.md
+++ b/docs/ECOSYSTEM-WIRING.md
@@ -1,7 +1,7 @@
# GrayCode ecosystem wiring
> **STALE (2026-09-18):** Diagrams below predate `eagle` removal (2026-09-04) and list 14 repos / 6 engines.
-> NOTE (2026-09-04): `eagle` contracts vendored into `rho/internal/contracts`.
+> NOTE (2026-09-04): `eagle` contracts vendored into `decoder/internal/contracts`.
> **INVENTORY MOVED (2026-10-02):** the canonical machine-readable inventory is
> [`GrayCodeAI/graycode-eco/ecosystem.yaml`](https://github.com/GrayCodeAI/graycode-eco/blob/main/ecosystem.yaml)
> (10 products, including `beam`). The `ecosystem.yaml` in this repo is
@@ -18,23 +18,23 @@ flowchart LR
Lists --> Scripts[Workspace and release scripts]
Lists --> Owl[Owl catalog]
- Rho[Rho product] --> Engines[Six engine repositories]
+ Decoder[Decoder product] --> Engines[Six engine repositories]
Engines --> Eagle[Eagle contracts]
- Rho --> Eagle
+ Decoder --> Eagle
- RhoSpec[Rho OpenAPI] -. manual snapshots .-> Sparrow
- RhoSpec -. manual snapshots .-> Robin
- RhoSpec -. no snapshot .-> Wren
+ DecoderSpec[Decoder OpenAPI] -. manual snapshots .-> Sparrow
+ DecoderSpec -. manual snapshots .-> Robin
+ DecoderSpec -. no snapshot .-> Wren
Browser[GrayCode browser] --> Mixed[One mixed Worker]
Mixed --> Identity[(Identity tables)]
- Mixed --> Cloud[(Rho Cloud tables)]
+ Mixed --> Cloud[(Decoder Cloud tables)]
Mixed -. fire-and-forget .-> Queue[Usage Queue]
```
The runtime engine integrations were mostly sound, but the surrounding wiring
could drift: repository names appeared independently in shell scripts and Owl,
-SDK contracts were inconsistent, browser identity and the Rho control plane
+SDK contracts were inconsistent, browser identity and the Decoder control plane
shared a Worker and D1 binding, and a successful usage write did not guarantee a
durable Queue-delivery intent.
@@ -48,15 +48,15 @@ flowchart TB
Manifest --> OwlSnapshot[owl/ecosystem.json]
subgraph Local[Local-first runtime]
- User[CLI / daemon user] --> Rho[Rho composition root]
- Rho --> Flux[Flux facade]
- Rho --> Harrier[Harrier / Harrier facade]
- Rho --> Shrike[Shrike / Shrike facade]
- Rho --> Swift[Swift / Swift facade]
- Rho --> Kestrel[Kestrel / Kestrel facade]
- Rho --> Merlin[Merlin / Merlin facade]
- Rho --> Eagle[Eagle neutral contracts]
- Flux --> Eagle
+ User[CLI / daemon user] --> Decoder[Decoder composition root]
+ Decoder --> Mux[Mux facade]
+ Decoder --> Harrier[Harrier / Harrier facade]
+ Decoder --> Shrike[Shrike / Shrike facade]
+ Decoder --> Swift[Swift / Swift facade]
+ Decoder --> Kestrel[Kestrel / Kestrel facade]
+ Decoder --> Merlin[Merlin / Merlin facade]
+ Decoder --> Eagle[Eagle neutral contracts]
+ Mux --> Eagle
Harrier --> Eagle
Shrike --> Eagle
Swift --> Eagle
@@ -64,7 +64,7 @@ flowchart TB
Merlin --> Eagle
end
- Rho --> Daemon[Rho daemon API]
+ Decoder --> Daemon[Decoder daemon API]
Daemon --> OpenAPI[api/openapi.yaml]
OpenAPI --> Sparrow[Sparrow Go SDK snapshot]
OpenAPI --> Robin[Robin Python SDK snapshot]
@@ -73,7 +73,7 @@ flowchart TB
subgraph Hosted[Optional hosted plane]
Browser[GrayCode browser] --> BFF[GrayCode identity/BFF Worker]
BFF --> Identity[(Identity D1)]
- BFF -->|private typed Service Binding| Cloud[Rho Cloud Worker]
+ BFF -->|private typed Service Binding| Cloud[Decoder Cloud Worker]
Cloud --> Control[(Control-plane D1)]
Cloud -->|same D1 transaction| Outbox[(Usage outbox)]
Outbox -->|immediate + scheduled retry| Queue[Cloudflare Queue]
@@ -81,28 +81,28 @@ flowchart TB
Queue --> Archive[(R2 archive)]
end
- Rho -. explicit opt-in; fail-open .-> Cloud
+ Decoder -. explicit opt-in; fail-open .-> Cloud
```
## Ownership rules
| Boundary | Owner | Rule |
|---|---|---|
-| Product orchestration | Rho | Engines never orchestrate Rho or one another. |
-| Provider runtime | Flux | Rho imports its supported `engine` facade. |
+| Product orchestration | Decoder | Engines never orchestrate Decoder or one another. |
+| Provider runtime | Mux | Decoder imports its supported `engine` facade. |
| Shared data contracts | Eagle | Neutral types only; no product behavior. |
-| Portable local graph | Source engine/Rho | Emit bounded `rho.graph/v1` facts without raw secrets or prompts. |
-| Daemon HTTP API | Rho | `rho/api/openapi.yaml` is authoritative. |
+| Portable local graph | Source engine/Decoder | Emit bounded `decoder.graph/v1` facts without raw secrets or prompts. |
+| Daemon HTTP API | Decoder | `decoder/api/openapi.yaml` is authoritative. |
| SDK endpoint support | Each SDK | Exact contract snapshot plus an explicit decision for every path. |
| Browser identity | GrayCode BFF | Users, sessions, email, API keys, and UI activity remain in identity D1. |
-| Hosted control plane | Rho Cloud | Organizations, projects, devices, usage, billing, graph ledger, and audit. |
+| Hosted control plane | Decoder Cloud | Organizations, projects, devices, usage, billing, graph ledger, and audit. |
| Cloud delivery | D1 outbox + Queue | Business state and delivery intent commit together; consumers are idempotent. |
| Architecture discovery | Owl | Generated projection of the canonical manifest, never a second inventory. |
## Repository identity
Repository directories are repository and Go module identities. Product names
-remain the user-facing labels. In particular, `flux` is Flux. Scripts and CI
+remain the user-facing labels. In particular, `mux` is Mux. Scripts and CI
must use `directory`/`github_repo`; UI copy may use `product_name`.
## Contract and event flow
@@ -113,7 +113,7 @@ must use `directory`/`github_repo`; UI copy may use `product_name`.
2. Eagle commit `9d358dde4ad8` is the cross-repository contract revision, pinned
through its reachable Go pseudo-version until the next semver tag is published;
the parity gate checks every declared consumer.
-3. Local graph projections use `rho.graph/v1`. Rho Cloud independently
+3. Local graph projections use `decoder.graph/v1`. Decoder Cloud independently
validates and privacy-normalizes them into `graycode-cloud.graph/v1`.
4. Usage ingestion commits its idempotency claim, budget counter, event,
billing ledger row, daily activity projection, and `usage.recorded.v1`
@@ -124,12 +124,12 @@ must use `directory`/`github_repo`; UI copy may use `product_name`.
## Release and development workflow
-- Run `make workspace` in Rho to regenerate the parent `go.work`.
+- Run `make workspace` in Decoder to regenerate the parent `go.work`.
- Run `make boundaries` to validate the inventory, module isolation, Eagle
parity, facade locations, and support-repository coupling.
- Root `go.mod` files never contain local `replace` directives. Local sibling
substitutions exist only in the generated, uncommitted parent workspace.
-- SDK CI checks its snapshot byte-for-byte against Rho and separately checks
+- SDK CI checks its snapshot byte-for-byte against Decoder and separately checks
that every OpenAPI path has a support decision.
- Run `owl/scripts/sync-ecosystem.sh` after changing the canonical inventory;
Owl CI rejects drift.
@@ -138,33 +138,33 @@ must use `directory`/`github_repo`; UI copy may use `product_name`.
### Coordinated Go publication gate
-The compatible Eagle-migrated Flux source is currently ahead of Flux's
-published `origin/main`. Do not merge or release Rho against the older Flux
-pseudo-version: it still exposes the retired `rho-core-contracts` types and is
-not type-compatible with Rho's Eagle boundary.
+The compatible Eagle-migrated Mux source is currently ahead of Mux's
+published `origin/main`. Do not merge or release Decoder against the older Mux
+pseudo-version: it still exposes the retired `decoder-core-contracts` types and is
+not type-compatible with Decoder's Eagle boundary.
-1. Merge and publish the Flux ecosystem-wiring branch first.
+1. Merge and publish the Mux ecosystem-wiring branch first.
2. Resolve that final remote commit to its canonical Go pseudo-version with
- `go list -m github.com/GrayCodeAI/flux@`.
-3. Update Rho's Flux requirement, run `GOWORK=off go mod tidy`, and remove any
+ `go list -m github.com/GrayCodeAI/mux@`.
+3. Update Decoder's Mux requirement, run `GOWORK=off go mod tidy`, and remove any
transition excludes no longer required by the published engine graphs.
-4. Require Rho's `public-modules` and `release-parity` CI jobs to pass before
- merging or tagging Rho.
+4. Require Decoder's `public-modules` and `release-parity` CI jobs to pass before
+ merging or tagging Decoder.
This publication is intentionally not performed by the source implementation:
remote branch merges and tags are externally visible release operations.
## Deployment sequence for the Worker split
-1. Create or automatically provision the `rho-identity` D1 database and
+1. Create or automatically provision the `decoder-identity` D1 database and
confirm its binding in `apps/bff/wrangler.jsonc`.
2. Export the existing identity tables from the legacy mixed database and
import them into the identity database; verify row counts and login flows.
-3. Deploy `graycode-cloud` with the named `RhoCloudService` entrypoint and
+3. Deploy `graycode-cloud` with the named `DecoderCloudService` entrypoint and
apply migration `0023_usage_outbox.sql`.
-4. Deploy `rho-bff` with its D1 binding and private service binding.
-5. Point the web frontend API hostname at the BFF. Rho/CLI device start and
- poll traffic continues to target Rho Cloud.
+4. Deploy `decoder-bff` with its D1 binding and private service binding.
+5. Point the web frontend API hostname at the BFF. Decoder/CLI device start and
+ poll traffic continues to target Decoder Cloud.
6. After a rollback window, remove the legacy identity tables from the old
cloud D1 using a separately reviewed data-retirement migration.
diff --git a/docs/IMPLEMENTATION-ROADMAP.md b/docs/IMPLEMENTATION-ROADMAP.md
index 4ff1688e0..fbcdb9911 100644
--- a/docs/IMPLEMENTATION-ROADMAP.md
+++ b/docs/IMPLEMENTATION-ROADMAP.md
@@ -5,7 +5,7 @@
**Date:** 2026-07-05
**Source:** Historical comparison document; feature and market claims require
independent revalidation. Architecture status is tracked in
-`docs/architecture/rho-architecture-baseline.md`.
+`docs/architecture/decoder-architecture-baseline.md`.
---
@@ -27,14 +27,14 @@ Numeric scores are intentionally not used as current architecture evidence.
## Phase 1: High Priority (Immediate - Score Impact: +0.5)
-### 1. Add VS Code Extension Integration (rho repo)
+### 1. Add VS Code Extension Integration (decoder repo)
**Effort:** Large (2-3 weeks)
**Priority:** HIGH
**What:**
-- Create `rho-vscode` repo for VS Code extension
-- Use Rho SDK for communication
+- Create `decoder-vscode` repo for VS Code extension
+- Use Decoder SDK for communication
- Add WebSocket transport for real-time updates
**Why:**
@@ -45,12 +45,12 @@ Numeric scores are intentionally not used as current architecture evidence.
**Implementation Plan:**
```bash
# Create new repo
-mkdir rho-vscode
-cd rho-vscode
+mkdir decoder-vscode
+cd decoder-vscode
# Initialize
git init
-go mod init github.com/GrayCodeAI/rho-vscode
+go mod init github.com/GrayCodeAI/decoder-vscode
# Add extension scaffold
mkdir -p cmd extension/src
@@ -64,8 +64,8 @@ go get golang.org/x/net/websocket
# Create extension files
cat > extension/package.json << 'EOF'
{
- "name": "rho",
- "displayName": "Rho",
+ "name": "decoder",
+ "displayName": "Decoder",
"description": "AI coding assistant in terminal",
"version": "0.1.0",
"engines": { "vscode": "^1.90.0" },
@@ -75,14 +75,14 @@ cat > extension/package.json << 'EOF'
"contributes": {
"commands": [
{
- "command": "rho.activate",
- "title": "Activate Rho"
+ "command": "decoder.activate",
+ "title": "Activate Decoder"
}
],
"menus": {
"commandPalette": [
{
- "command": "rho.activate",
+ "command": "decoder.activate",
"when": "editorLangId"
}
]
@@ -94,22 +94,22 @@ EOF
# Add extension scaffold
cat > extension/src/extension.ts << 'EOF'
import * as vscode from 'vscode';
-import * as rhosdk from '@graycodeai/rhosdk';
+import * as decodersdk from '@graycodeai/decodersdk';
export function activate(context: vscode.ExtensionContext) {
- const client = new rhosdk.Client();
+ const client = new decodersdk.Client();
// Register completion provider
vscode.languages.registerCompletionItemProvider(
'go',
- new RhoCompletionProvider(client),
+ new DecoderCompletionProvider(client),
'g', 'h'
);
// Register hover provider
vscode.languages.registerHoverProvider(
'go',
- new RhoHoverProvider(client)
+ new DecoderHoverProvider(client)
);
}
EOF
@@ -123,7 +123,7 @@ vsce publish
**Repository Structure:**
```
-rho-vscode/
+decoder-vscode/
├── extension/ # VS Code extension code
│ ├── src/
│ │ ├── extension.ts
@@ -140,25 +140,25 @@ rho-vscode/
---
-### 2. Add Extension Marketplace (rho repo)
+### 2. Add Extension Marketplace (decoder repo)
**Effort:** Medium (1-2 weeks)
**Priority:** HIGH
**What:**
- Create marketplace for community extensions
-- Add extension discovery endpoint to rho
+- Add extension discovery endpoint to decoder
- Create `starling` integration
- Add version compatibility checking
**Why:**
- Top agents have 100+ extensions
-- Build ecosystem around Rho
+- Build ecosystem around Decoder
- Increase adoption
**Implementation Plan:**
```go
-// Add to rho
+// Add to decoder
package marketplace
// Extension represents a community extension
@@ -305,12 +305,12 @@ cat >> SKILL.md << 'EOF'
To discover available extensions, use:
```
-rho extensions list
+decoder extensions list
```
To install an extension:
```
-rho extensions install
+decoder extensions install
```
EOF
```
@@ -431,7 +431,7 @@ go build forum.go
---
-### 5. Add More Extension Points (rho)
+### 5. Add More Extension Points (decoder)
**Effort:** Small (3-5 days)
**Priority:** MEDIUM
@@ -499,7 +499,7 @@ func main() {
## Phase 3: Low Priority (Backlog - Score Impact: +0.2)
-### 6. Add AI Code Completion (flux)
+### 6. Add AI Code Completion (mux)
**Effort:** Medium (1-2 weeks)
**Priority:** LOW
@@ -514,7 +514,7 @@ func main() {
---
-### 7. Add Debugging Support (rho)
+### 7. Add Debugging Support (decoder)
**Effort:** Large (2-3 weeks)
**Priority:** LOW
@@ -530,7 +530,7 @@ func main() {
---
-### 8. Add Web UI for Monitoring (rho)
+### 8. Add Web UI for Monitoring (decoder)
**Effort:** Small (3-5 days)
**Priority:** LOW
@@ -562,7 +562,7 @@ func main() {
---
-### 10. Add Completion Endpoint to flux
+### 10. Add Completion Endpoint to mux
**Effort:** Medium (1 week)
**Priority:** LOW
@@ -579,7 +579,7 @@ func main() {
## Detailed Repo-Specific Roadmap
-### **rho** (Main Repo) - Primary Product
+### **decoder** (Main Repo) - Primary Product
| Phase | Improvement | Effort | Impact | Status |
|-------|--------------|--------|--------|--------|
@@ -590,7 +590,7 @@ func main() {
| 3 | Add Web UI for monitoring | Small | +0.2 | Planned |
| 3 | Add SDK analytics | Small | +0.1 | Planned |
-Current architecture status: see `docs/architecture/rho-architecture-baseline.md`.
+Current architecture status: see `docs/architecture/decoder-architecture-baseline.md`.
---
@@ -628,7 +628,7 @@ Current architecture status: see `docs/architecture/rho-architecture-baseline.md
---
-### **flux** (LLM Runtime)
+### **mux** (LLM Runtime)
| Phase | Improvement | Effort | Impact | Status |
|-------|--------------|--------|--------|--------|
@@ -657,7 +657,7 @@ Current architecture status: see `docs/architecture/rho-architecture-baseline.md
The roadmap is sequenced by product value and implementation effort. It does
not assign target architecture scores. Current architecture status is tracked
-in `docs/architecture/rho-architecture-baseline.md`.
+in `docs/architecture/decoder-architecture-baseline.md`.
---
@@ -667,7 +667,7 @@ in `docs/architecture/rho-architecture-baseline.md`.
|------|--------|------------|
| Marketplace competition | High | Focus on quality extensions |
| Community building | Medium | Active engagement, good docs |
-| Development velocity | Medium | Prioritize rho SDK first |
+| Development velocity | Medium | Prioritize decoder SDK first |
| Adoption curve | Medium | VS Code extension is key |
---
diff --git a/docs/OTEL-CONVENTIONS.md b/docs/OTEL-CONVENTIONS.md
index 196b37d10..a64defec5 100644
--- a/docs/OTEL-CONVENTIONS.md
+++ b/docs/OTEL-CONVENTIONS.md
@@ -1,10 +1,10 @@
# graycode-eco OpenTelemetry Semantic Conventions for AI Agent Spans
Status: Draft / shared spec
-Applies to: rho, flux
+Applies to: decoder, mux
-This document defines the OpenTelemetry (OTel) semantic conventions Rho and
-Flux should follow when emitting spans for AI agent and LLM operations. The
+This document defines the OpenTelemetry (OTel) semantic conventions Decoder and
+Mux should follow when emitting spans for AI agent and LLM operations. The
goal is that a single tracing backend (Jaeger, Tempo, Honeycomb, an OTLP
collector, etc.) can correlate model calls, tool invocations, token usage, and
cost across both repos using one common attribute vocabulary.
@@ -18,24 +18,24 @@ concerns that the GenAI spec does not yet standardize.
## Reference ownership
-Flux owns provider-call instrumentation behind its `flux/engine` facade.
+Mux owns provider-call instrumentation behind its `mux/engine` facade.
Its lower provider layer contains the reference OTel decorator for chat and
stream calls: it starts a client span, records provider/model/usage attributes,
sets status from the result, and ends a streamed span on completion. That
-decorator is an Flux implementation detail; Rho must not import or compose it
+decorator is an Mux implementation detail; Decoder must not import or compose it
directly.
-- `flux/internal/observability/observability.go` provides a stdlib-only,
+- `mux/internal/observability/observability.go` provides a stdlib-only,
zero-dependency telemetry/metrics layer (spans, latency histograms,
Prometheus + JSON export) for environments that cannot pull in the OTel SDK.
-- `flux/internal/observability/genai_semconv.go` exports the canonical
+- `mux/internal/observability/genai_semconv.go` exports the canonical
attribute-key constants defined below, so Go code can reference them instead
of hard-coding strings. A pinning test
(`genai_semconv_test.go`) guards the exact key values.
-When adding tracing to Rho, propagate trace context through the Engine call
-and use the attribute keys in this document. Flux wraps provider operations;
-Rho wraps product turns, tools, and the embedded token engine.
+When adding tracing to Decoder, propagate trace context through the Engine call
+and use the attribute keys in this document. Mux wraps provider operations;
+Decoder wraps product turns, tools, and the embedded token engine.
## Span kinds and names
@@ -50,7 +50,7 @@ Rho wraps product turns, tools, and the embedded token engine.
LLM/provider request spans SHOULD use span kind `CLIENT`. Tool invocations and
agent steps that represent internal work SHOULD use span kind `INTERNAL`.
-flux's existing stdlib layer also defines short span names
+mux's existing stdlib layer also defines short span names
(`llm.chat`, `llm.stream`, `llm.retry`, `llm.cache_hit`) — these remain valid
for the internal metrics collector; the names above are the cross-repo
convention for OTLP-exported spans.
@@ -58,10 +58,10 @@ convention for OTLP-exported spans.
## Required / recommended attributes
The required attribute set for any AI agent span. Keys are exported as Go
-constants in `flux/internal/observability/genai_semconv.go` (constant name in
+constants in `mux/internal/observability/genai_semconv.go` (constant name in
parentheses).
-| Attribute key | Go const (`flux` observability) | Type | Required | Meaning |
+| Attribute key | Go const (`mux` observability) | Type | Required | Meaning |
|---------------------------------|------------------------------------|--------|----------|----------------------------------------------------------------|
| `gen_ai.system` | `AttrGenAISystem` | string | yes | Provider/system: `openai`, `anthropic`, `gemini`, etc. |
| `gen_ai.request.model` | `AttrGenAIRequestModel` | string | yes | Model requested by the caller, e.g. `gpt-4o`. |
@@ -77,13 +77,13 @@ parentheses).
### Notes
- **Tokens as integers.** Emit `gen_ai.usage.input_tokens` /
- `gen_ai.usage.output_tokens` as OTel integer attributes. flux's stdlib
+ `gen_ai.usage.output_tokens` as OTel integer attributes. mux's stdlib
`Span.Attributes` is `map[string]string`; when bridging that layer to OTLP,
convert to integer attributes.
- **Cost is a double in USD.** `cost.usd` is the ecosystem standard.
- flux's metrics collector stores cost internally in micro-USD for precision
+ mux's metrics collector stores cost internally in micro-USD for precision
(`costMicroUSD`) but exports USD; emit the USD value on spans.
-- **No prompt/response bodies by default.** Following flux's audit design
+- **No prompt/response bodies by default.** Following mux's audit design
(`observability/audit.go`), spans MUST NOT carry raw prompt/response text by
default. If content capture is enabled, use the OTel GenAI event/log channel,
not span attributes, and gate it behind explicit opt-in.
@@ -92,7 +92,7 @@ parentheses).
## Legacy attribute mapping
-flux's older stdlib constants (`AttrLLMProvider`, `AttrLLMModel`,
+mux's older stdlib constants (`AttrLLMProvider`, `AttrLLMModel`,
`AttrLLMInputTokens`, …, keyed `llm.*`) predate this spec and remain for
backwards compatibility. New instrumentation should use the `gen_ai.*` keys.
Mapping:
@@ -109,12 +109,12 @@ Mapping:
## Per-repo guidance
-- **flux** — owns provider/model/usage spans behind `flux/engine`; align
+- **mux** — owns provider/model/usage spans behind `mux/engine`; align
attribute keys to `gen_ai.*` over time.
-- **rho** — daemon/orchestrator. Already has OTel hooks
- (`RHO_ENABLE_TELEMETRY`, `RHO_OTEL_SHUTDOWN_TIMEOUT_MS`). Emit
+- **decoder** — daemon/orchestrator. Already has OTel hooks
+ (`DECODER_ENABLE_TELEMETRY`, `DECODER_OTEL_SHUTDOWN_TIMEOUT_MS`). Emit
`agent.id` and `session.id` on agent-turn spans; propagate them downstream to
- flux via context so provider spans inherit the same IDs.
+ mux via context so provider spans inherit the same IDs.
- **internal/token** — embedded token engine. Token accounting is its domain;
when it emits spans, populate `gen_ai.usage.input_tokens` / `output_tokens`
and `cost.usd` so compression savings are visible in the same trace.
@@ -122,5 +122,5 @@ Mapping:
## Versioning
This spec tracks OTel GenAI conventions, which are still evolving. Pin changes
-to the constants via `genai_semconv_test.go` in flux and update this table in
+to the constants via `genai_semconv_test.go` in mux and update this table in
the same change.
diff --git a/docs/PERMISSION-MODEL-IMPROVEMENTS.md b/docs/PERMISSION-MODEL-IMPROVEMENTS.md
index 0aa1f2e58..0e123c1e2 100644
--- a/docs/PERMISSION-MODEL-IMPROVEMENTS.md
+++ b/docs/PERMISSION-MODEL-IMPROVEMENTS.md
@@ -1,6 +1,6 @@
-# Rho permission model
+# Decoder permission model
-Rho executes tools directly on the host. There is no Docker-backed execution
+Decoder executes tools directly on the host. There is no Docker-backed execution
path and no product sandbox runtime. Safety comes from a layered, fail-closed
policy pipeline, path guards, trust checks, tool-level hard stops, and explicit
human approval.
@@ -47,11 +47,11 @@ auto-mode learner and never silently becomes a rule.
Durable project rules require an explicit command:
```bash
-rho permissions list
-rho permissions add allow command 'git status'
-rho permissions add deny file '.env'
-rho permissions revoke
-rho permissions reset
+decoder permissions list
+decoder permissions add allow command 'git status'
+decoder permissions add deny file '.env'
+decoder permissions revoke
+decoder permissions reset
```
The reset command asks for confirmation before mutating the rule store.
@@ -88,7 +88,7 @@ local rule cannot widen an administrator ceiling.
## Host-native boundaries
-Rho does not pretend that a host permission prompt is an operating-system
+Decoder does not pretend that a host permission prompt is an operating-system
containment boundary. The following are separate defenses:
- Path tools enforce project and protected-path rules.
@@ -99,8 +99,8 @@ containment boundary. The following are separate defenses:
- Dry-run provides a deterministic preview mode for CI and review.
If a task requires stronger process or filesystem containment than these host
-controls provide, run Rho inside an environment chosen by the operator. That
-deployment decision is intentionally outside Rho's product runtime.
+controls provide, run Decoder inside an environment chosen by the operator. That
+deployment decision is intentionally outside Decoder's product runtime.
## Verification
@@ -117,7 +117,7 @@ The actual binary should also be smoke-tested:
```bash
make build
-bin/rho --help
-bin/rho permissions list --json
-bin/rho completion json
+bin/decoder --help
+bin/decoder permissions list --json
+bin/decoder completion json
```
diff --git a/docs/README.md b/docs/README.md
index 94ed11d27..9ae63d035 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,6 +1,6 @@
-# Rho Documentation
+# Decoder Documentation
-Index for `rho/docs/`. The canonical repo inventory is
+Index for `decoder/docs/`. The canonical repo inventory is
[`GrayCodeAI/graycode-eco/ecosystem.yaml`](https://github.com/GrayCodeAI/graycode-eco/blob/main/ecosystem.yaml)
— the `ecosystem.yaml` in this repo is deprecated and incomplete, and
`ECOSYSTEM-WIRING.md` is historical.
diff --git a/docs/RELEASING.md b/docs/RELEASING.md
index b6aa8dde6..0ec503960 100644
--- a/docs/RELEASING.md
+++ b/docs/RELEASING.md
@@ -1,13 +1,13 @@
-# Releasing rho
+# Releasing decoder
-Rho is pre-1.0. Releases are cut by hand: a maintainer merges a release PR
+Decoder is pre-1.0. Releases are cut by hand: a maintainer merges a release PR
that sets `VERSION` and the `CHANGELOG.md` section, then pushes the matching
`v` tag. The tag triggers
[`.github/workflows/release.yml`](../.github/workflows/release.yml), which
builds, signs and publishes the GitHub release. There is no release-please or
other bot: nothing bumps `VERSION` or writes `CHANGELOG.md` automatically.
-The first release under the `rho` name is **v0.3.0**.
+The first release under the `decoder` name is **v0.3.0**.
## Tag protection
@@ -19,7 +19,7 @@ actor. A push of a `v*` tag by anyone else is rejected, so a write-access
account cannot trigger a signed release. Inspect it with:
```bash
-gh api repos/GrayCodeAI/rho/rulesets/24053191
+gh api repos/GrayCodeAI/decoder/rulesets/24053191
```
The `main` branch is separately protected (required status checks, no force
@@ -32,8 +32,8 @@ pushes).
- `CHANGELOG.md`: rename `## [Unreleased]` to `## [X.Y.Z] — YYYY-MM-DD`
and add a new, empty `## [Unreleased]` above it. This section becomes the
GitHub release notes verbatim.
- - `testdata/compatibility-matrix.json`: set the `stable` matrix to rho
- `X.Y.Z` and the flux version pinned in `go.mod`.
+ - `testdata/compatibility-matrix.json`: set the `stable` matrix to decoder
+ `X.Y.Z` and the mux version pinned in `go.mod`.
- `README.md` install section: point the `install.sh` URL at the new tag.
- Run locally:
@@ -47,15 +47,15 @@ pushes).
```bash
git fetch origin
- git tag -s vX.Y.Z -m "rho vX.Y.Z"
+ git tag -s vX.Y.Z -m "decoder vX.Y.Z"
git push origin vX.Y.Z
```
4. **Watch** the `release` workflow run to completion (next section).
5. **Verify** the published release as a user would (see
[Verifying a release](#verifying-a-release)), including
- `curl -fsSL https://raw.githubusercontent.com/GrayCodeAI/rho/vX.Y.Z/install.sh | RHO_REQUIRE_COSIGN=1 sh`
- and `go install github.com/GrayCodeAI/rho/cmd/rho@vX.Y.Z`.
+ `curl -fsSL https://raw.githubusercontent.com/GrayCodeAI/decoder/vX.Y.Z/install.sh | DECODER_REQUIRE_COSIGN=1 sh`
+ and `go install github.com/GrayCodeAI/decoder/cmd/decoder@vX.Y.Z`.
`make release` deliberately refuses to publish from a workstation: releases are
signed with the workflow's GitHub OIDC identity, which a local run cannot have.
@@ -68,15 +68,15 @@ On a pushed `v*` tag, with `permissions: contents: write, id-token: write`:
`v` + `VERSION` and `CHANGELOG.md` has a non-empty `## []`
section; that section is extracted as the release notes.
2. `scripts/check-no-replace-directives.sh` refuses local `replace`
- directives. The job sets `GOWORK=off`, so dependencies (including flux)
+ directives. The job sets `GOWORK=off`, so dependencies (including mux)
come only from `go.mod`/`go.sum` via the public proxy.
3. syft (`anchore/sbom-action/download-syft`) and cosign
(`sigstore/cosign-installer`) are installed; both actions are pinned by
commit SHA.
4. GoReleaser v2.17.0 (`.goreleaser.yml`) builds and publishes:
- - `rho___.tar.gz` for linux and darwin and `.zip` for
+ - `decoder___.tar.gz` for linux and darwin and `.zip` for
windows, each on amd64 and arm64 (six archives, `-trimpath`, `CGO_ENABLED=0`);
- - `rho__source.tar.gz`;
+ - `decoder__source.tar.gz`;
- one SPDX SBOM per archive (`.spdx.sbom.json`);
- `checksums.txt` (SHA-256 of every asset above);
- `checksums.txt.sigstore.json`, a cosign keyless Sigstore bundle
@@ -89,11 +89,11 @@ On a pushed `v*` tag, with `permissions: contents: write, id-token: write`:
```bash
tag=vX.Y.Z
-gh release download "$tag" --repo GrayCodeAI/rho \
+gh release download "$tag" --repo GrayCodeAI/decoder \
--pattern checksums.txt --pattern checksums.txt.sigstore.json \
- --pattern "rho_${tag#v}_linux_amd64.tar.gz"
+ --pattern "decoder_${tag#v}_linux_amd64.tar.gz"
cosign verify-blob --bundle checksums.txt.sigstore.json \
- --certificate-identity "https://github.com/GrayCodeAI/rho/.github/workflows/release.yml@refs/tags/$tag" \
+ --certificate-identity "https://github.com/GrayCodeAI/decoder/.github/workflows/release.yml@refs/tags/$tag" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
checksums.txt
sha256sum --ignore-missing -c checksums.txt
@@ -102,7 +102,7 @@ sha256sum --ignore-missing -c checksums.txt
`install.sh` performs the same checks: it always verifies the SHA-256, verifies
the bundle when cosign (v2.4 or later; v3 recommended) is installed, says so
plainly when it is not, and refuses to install without cosign when
-`RHO_REQUIRE_COSIGN=1`.
+`DECODER_REQUIRE_COSIGN=1`.
## Distribution channels
@@ -110,9 +110,9 @@ plainly when it is not, and refuses to install without cosign when
|---|---|
| GitHub release archives | From v0.3.0. |
| `install.sh` | From v0.3.0; refuses older (hawk-era) versions. |
-| `go install github.com/GrayCodeAI/rho/cmd/rho@latest` | From v0.3.0. Until then `@main` works; `@latest` resolves to the hawk-era v0.2.0. |
-| GitHub Action (`.github/actions/rho`) | From v0.3.0; installs through `install.sh` with cosign required. |
-| systemd unit (`packaging/systemd/rho-daemon.service`) | Template for running `rho daemon`; see the troubleshooting guide. |
+| `go install github.com/GrayCodeAI/decoder/cmd/decoder@latest` | From v0.3.0. Until then `@main` works; `@latest` resolves to the hawk-era v0.2.0. |
+| GitHub Action (`.github/actions/decoder`) | From v0.3.0; installs through `install.sh` with cosign required. |
+| systemd unit (`packaging/systemd/decoder-daemon.service`) | Template for running `decoder daemon`; see the troubleshooting guide. |
| Homebrew | **Not available.** Needs a `GrayCodeAI/homebrew-tap` repository, a fine-grained token with write access to it stored as a secret, and a `homebrew_casks` stanza in `.goreleaser.yml`. |
| npm | **Not available.** The scaffolding in `npm/` is marked private; see [`npm/README.md`](../npm/README.md). |
| Nix | **Not available.** The old flake could not evaluate and was removed; a new one needs a computed `vendorHash`, a committed `flake.lock` and `nix flake check` in CI. |
@@ -120,7 +120,7 @@ plainly when it is not, and refuses to install without cosign when
Add a channel to the README only after it has worked end to end for a real
release.
-## Notes for v0.3.0 (first rho release)
+## Notes for v0.3.0 (first decoder release)
- Tags `v0.1.0`, `v0.1.1` and `v0.2.0` were published under the previous
module path `github.com/GrayCodeAI/hawk`; their assets are `hawk_*` archives
@@ -132,4 +132,4 @@ release.
omitted.
- v0.2.0 is the current "Latest" release. Once v0.3.0 is published it becomes
Latest. Consider editing the v0.2.0 release notes to say it is the legacy
- hawk build and cannot be installed as rho.
+ hawk build and cannot be installed as decoder.
diff --git a/docs/RESEARCH.md b/docs/RESEARCH.md
index 37b689a3c..4bfe6a6b3 100644
--- a/docs/RESEARCH.md
+++ b/docs/RESEARCH.md
@@ -1,7 +1,7 @@
# Research & Competitive Comparison — graycode-eco
Status: Implemented (branch `feat/competitive-analysis-top20`, 2026-09-09)
-Scope: 4 repos (`rho`, `flux`, `graycode-platform`, `graycode-skills`) vs
+Scope: 4 repos (`decoder`, `mux`, `graycode-platform`, `graycode-skills`) vs
top-20 OSS competitors and top-20 AI-coding-agent research papers.
This document maps the field (competitors + research) to our repos, records what
@@ -12,15 +12,15 @@ plans in `docs/plans/competitive-gap-*.md` and the extra fixes they surfaced.
- Competitors: `docs/COMPETITIVE.md` (20 OSS tools, source-cited).
- Research: 20 papers read via arXiv (abstracts) 2026-09-09 — listed below.
-- Repo capability inventory: `rho/README.md`, `flux/README.md`,
+- Repo capability inventory: `decoder/README.md`, `mux/README.md`,
`graycode-platform/README.md`, `graycode-skills/README.md`, plus source audits.
## Our repos at a glance
| Repo | Role | Key strengths |
|---|---|---|
-| rho | Product face (Go, Bubble Tea v2) | 120+ tools, host permission/path controls, `/autonomy`+`/spec` gates, `mission` multi-agent, execution-graph export, AST repomap + Harrier memory, MCP/LSP |
-| flux | Provider engine facade | 22 gateways, routing/retry/caching/compaction, OpenAI-compat proxy, model catalog |
+| decoder | Product face (Go, Bubble Tea v2) | 120+ tools, host permission/path controls, `/autonomy`+`/spec` gates, `mission` multi-agent, execution-graph export, AST repomap + Harrier memory, MCP/LSP |
+| mux | Provider engine facade | 22 gateways, routing/retry/caching/compaction, OpenAI-compat proxy, model catalog |
| graycode-platform | Optional cloud/BFF plane | web + identity BFF + control-plane worker (not a runtime dep) |
| graycode-skills | Skill marketplace | 14,015 skills, 27 categories, SKILL.md frontmatter + validation |
diff --git a/docs/SECURITY-DEVELOPER.md b/docs/SECURITY-DEVELOPER.md
index 59a4445a0..7be706a96 100644
--- a/docs/SECURITY-DEVELOPER.md
+++ b/docs/SECURITY-DEVELOPER.md
@@ -1,13 +1,13 @@
-# Rho developer security model
+# Decoder developer security model
-This document describes how rho and flux handle API keys and agent isolation for an individual developer on macOS or Linux (no Vault, no proxy). Teams and enterprise deployment models come later.
+This document describes how decoder and mux handle API keys and agent isolation for an individual developer on macOS or Linux (no Vault, no proxy). Teams and enterprise deployment models come later.
## Goals
- API keys live only in the OS secret store (macOS Keychain / Linux GNOME Keyring or KWallet).
-- Rho does not read API keys from `.env`, shell env, or plaintext files.
-- Flux's `provider.json` holds routing and deployment metadata only — never secrets on disk.
-- Rho talks to flux without putting keys in JSON or chat messages.
+- Decoder does not read API keys from `.env`, shell env, or plaintext files.
+- Mux's `provider.json` holds routing and deployment metadata only — never secrets on disk.
+- Decoder talks to mux without putting keys in JSON or chat messages.
- Agent commands run on the host under the permission engine; file tools cannot
read credential paths.
@@ -15,12 +15,12 @@ This document describes how rho and flux handle API keys and agent isolation for
| Write | Read | Remove |
|-------|------|--------|
-| `/config` paste flow → `flux/engine.Engine.SaveCredential` | `Engine.ResolveCredential` (secret store only) | `/config key remove` or `rho credentials remove` |
+| `/config` paste flow → `mux/engine.Engine.SaveCredential` | `Engine.ResolveCredential` (secret store only) | `/config key remove` or `decoder credentials remove` |
-Rho does not import keys from legacy `~/.rho/env` / `~/.rho/.env` files or
+Decoder does not import keys from legacy `~/.decoder/env` / `~/.decoder/.env` files or
from secret fields in `provider.json`. Save every key through `/config`.
-Check status: `rho credentials status`, `rho path`, or `rho preflight`.
+Check status: `decoder credentials status`, `decoder path`, or `decoder preflight`.
## First-run flow (`/config`)
@@ -28,34 +28,34 @@ Check status: `rho credentials status`, `rho path`, or `rho preflight`.
User pastes API key in /config
|
v
-Rho /config -> Flux engine credential service (OS secret store)
+Decoder /config -> Mux engine credential service (OS secret store)
|
v
-Flux engine discover/apply (credentials from store, not JSON body)
+Mux engine discover/apply (credentials from store, not JSON body)
|
v
SetupUI JSON (display_name + canonical_id per model)
|
v
-User picks model -> Flux provider.json (canonical id only)
+User picks model -> Mux provider.json (canonical id only)
```
Remove a stored key: `/config key remove` (interactive picker).
-## Rho to Flux
+## Decoder to Mux
-- **Control plane**: Rho calls only `flux/engine`; no lower Flux package is a
+- **Control plane**: Decoder calls only `mux/engine`; no lower Mux package is a
production import.
- **Discovery/apply**: credentials are resolved from the Engine's injected
secret store; provider state and request bodies remain sanitized.
-- **Chat**: Rho sends model intent, messages, and tool definitions; Flux
+- **Chat**: Decoder sends model intent, messages, and tool definitions; Mux
resolves the gateway and reads secrets internally.
## Agent execution
```
+------------------+
-| Rho TUI/host |
+| Decoder TUI/host |
| Keychain access |
| /config paste |
+------------------+
@@ -65,51 +65,51 @@ Remove a stored key: `/config key remove` (interactive picker).
Host command execution
```
-Rho executes agent commands directly on the host. Every tool call passes
+Decoder executes agent commands directly on the host. Every tool call passes
through the permission engine (autonomy tier, allow/deny rules, approval gate,
and dry-run kill switch) before it runs. No Docker daemon or container runtime
is required.
### Blocked for agents
-- **Read** tool: legacy Rho env files, Flux's configured `provider.json`,
+- **Read** tool: legacy Decoder env files, Mux's configured `provider.json`,
`~/.ssh/*`, etc.
-- **Bash**: `printenv`, `env`, reading rho env paths, echoing `*_API_KEY` variables.
+- **Bash**: `printenv`, `env`, reading decoder env paths, echoing `*_API_KEY` variables.
## Secrets left on disk
-- **provider.json secrets**: `rho path` fails its `provider.json` security
- check when the file still holds secret fields. Rho does not remove them
+- **provider.json secrets**: `decoder path` fails its `provider.json` security
+ check when the file still holds secret fields. Decoder does not remove them
automatically: back up the file, delete the secret fields, and save the keys
again through `/config`.
-- **Provider state writes**: the Flux engine sanitizes provider state and
+- **Provider state writes**: the Mux engine sanitizes provider state and
writes it atomically, so secret fields are never written back to disk.
## Provider state path
-Flux owns the provider-state path. Resolution order is:
+Mux owns the provider-state path. Resolution order is:
-1. `FLUX_CONFIG_DIR/provider.json`
-2. the platform user-config directory under `flux/provider.json`
+1. `MUX_CONFIG_DIR/provider.json`
+2. the platform user-config directory under `mux/provider.json`
-Rho's Read/Edit/Write and Bash safety checks protect the resolved path,
-including a custom or symlinked `FLUX_CONFIG_DIR`; protection is not limited
+Decoder's Read/Edit/Write and Bash safety checks protect the resolved path,
+including a custom or symlinked `MUX_CONFIG_DIR`; protection is not limited
to the historical default provider-state location.
## Environment variables
-Non-secret overrides only (rho does not load provider API keys from env):
+Non-secret overrides only (decoder does not load provider API keys from env):
| Variable | Meaning |
|----------|---------|
-| `RHO_CONFIG_DIR` | Override rho config directory |
-| `FLUX_CONFIG_DIR` | Override Flux provider-state directory; takes precedence for `provider.json` |
+| `DECODER_CONFIG_DIR` | Override decoder config directory |
+| `MUX_CONFIG_DIR` | Override Mux provider-state directory; takes precedence for `provider.json` |
| `OPENAI_MODEL` | Override default OpenAI model |
| `OLLAMA_BASE_URL` | Ollama server URL (also saved via `/config` for Ollama) |
## Related code
-- Rho: `internal/config/engine.go`, `internal/tool/safety.go`,
+- Decoder: `internal/config/engine.go`, `internal/tool/safety.go`,
`internal/storage/paths.go`, `cmd/credentials.go`
-- Flux public host boundary: `engine/`
+- Mux public host boundary: `engine/`
- Daemon HTTP surface: [`docs/DAEMON-PORT-THREAT-MODEL.md`](DAEMON-PORT-THREAT-MODEL.md)
diff --git a/docs/architecture.md b/docs/architecture.md
index 27cd98788..43d2d64e6 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -1,10 +1,10 @@
-# rho Architecture
+# decoder Architecture
**AI Coding Agent for Your Terminal**
-[](https://go.dev/)
+[](https://go.dev/)
[](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml)
[](https://swagger.io/specification/)
@@ -14,19 +14,19 @@
## Overview
-rho is an AI-powered coding agent for the terminal. It reads codebases, writes and edits files, runs tests, and manages git — all through natural language. Zero CGO, single static binary for linux/darwin/windows on amd64/arm64.
+decoder is an AI-powered coding agent for the terminal. It reads codebases, writes and edits files, runs tests, and manages git — all through natural language. Zero CGO, single static binary for linux/darwin/windows on amd64/arm64.
-Detailed planning docs for the Rho product architecture live in [`docs/architecture/`](architecture/README.md).
+Detailed planning docs for the Decoder product architecture live in [`docs/architecture/`](architecture/README.md).
---
## Layered Architecture
```
-rho/
+decoder/
├── api/openapi.yaml Daemon REST API contract (OpenAPI 3.1)
├── cmd/ Cobra CLI commands (200+ files)
-│ ├── rho/main.go Entry point — calls cmd.Execute()
+│ ├── decoder/main.go Entry point — calls cmd.Execute()
│ ├── root.go Root command, flag definitions
│ ├── daemon.go Daemon start/stop/status
│ ├── chat.go Interactive TUI chat
@@ -61,8 +61,8 @@ rho/
| | |
|---|---|
| **Contract** | [`api/openapi.yaml`](../api/openapi.yaml) |
-| **Port** | `:4590` (default). Override: `RHO_DAEMON_PORT` |
-| **Auth** | Bearer token or `X-API-Key`. Set via `RHO_DAEMON_API_KEY` |
+| **Port** | `:4590` (default). Override: `DECODER_DAEMON_PORT` |
+| **Auth** | Bearer token or `X-API-Key`. Set via `DECODER_DAEMON_API_KEY` |
Endpoint Summary
@@ -86,7 +86,7 @@ rho/
| Service | Role | Connection |
|---------|------|------------|
-| **flux** | LLM provider runtime | Library — all LLM calls routed through its engine facade |
+| **mux** | LLM provider runtime | Library — all LLM calls routed through its engine facade |
| **token** | Token optimization | Embedded — counting, compression, secrets, usage tracking |
### Client SDKs
@@ -99,7 +99,7 @@ rho/
All three SDKs share types from **eagle** and consume the daemon REST API (:4590).
-> **rho never talks to LLM APIs directly** — all calls go through flux.
+> **decoder never talks to LLM APIs directly** — all calls go through mux.
---
@@ -117,9 +117,9 @@ Tool Call → ` — persisted Rho session;
-- `rho/task-request//` — user task request, content represented by
+- `decoder/session/` — persisted Decoder session;
+- `decoder/task-request//` — user task request, content represented by
SHA-256 only;
-- `rho/task/` — structured task;
-- `rho/runtime-task/` — background agent, shell, or monitor task;
-- `rho/tool-call//` — tool invocation metadata;
-- `rho/policy/` — permission verdict;
-- `rho/verification/` — neutral verification result;
-- `flux/route/` and `flux/generation/` — model route and
+- `decoder/task/` — structured task;
+- `decoder/runtime-task/` — background agent, shell, or monitor task;
+- `decoder/tool-call//` — tool invocation metadata;
+- `decoder/policy/` — permission verdict;
+- `decoder/verification/` — neutral verification result;
+- `mux/route/` and `mux/generation/` — model route and
normalized generation operations.
Edges:
@@ -120,15 +120,15 @@ The export deliberately excludes:
Where correlation is useful, sensitive values are represented by SHA-256
digests. Every node declares `data_classification=metadata_only`.
-Rho writes runtime observations to a per-session append-only JSONL journal.
-The journal is stored with mode `0600` under Rho's state directory and contains
+Decoder writes runtime observations to a per-session append-only JSONL journal.
+The journal is stored with mode `0600` under Decoder's state directory and contains
only verdict metadata, aggregate verification counts, and SHA-256 digests. A
journal failure is logged and never changes a permission, approval, or tool
result.
Mission-mode graph execution persists a separate `mission-graph.json` artifact
beside `mission.json` in the mission directory. The artifact uses the same
-portable `rho.graph/v1` envelope, but it is mission-scoped rather than
+portable `decoder.graph/v1` envelope, but it is mission-scoped rather than
session-scoped: mission node, feature nodes, and wave-join operations nodes are
rewritten after each mission run or wave join using only metadata and SHA-256
digests.
@@ -136,7 +136,7 @@ digests.
## CLI
```bash
-rho graph export [session-id]
+decoder graph export [session-id]
--repository
```
@@ -155,18 +155,18 @@ GET /v1/sessions/{id}/graph
The endpoint uses the daemon's normal Bearer or `X-API-Key` authentication,
validates session and repository inputs before projection, and
-returns the typed `rho.graph/v1` envelope. The handler owns transport concerns
-only; the Rho composition root injects the existing graph builder, so CLI,
+returns the typed `decoder.graph/v1` envelope. The handler owns transport concerns
+only; the Decoder composition root injects the existing graph builder, so CLI,
Cloud sync, and HTTP projections share one construction path.
The Go, Python sync/async, and TypeScript SDK clients expose this endpoint and
validate the returned graph topology before returning it to callers.
-After connecting a project with `rho cloud login` or `rho cloud connect`, a
+After connecting a project with `decoder cloud login` or `decoder cloud connect`, a
completed session snapshot can be uploaded explicitly:
```bash
-rho cloud graph sync [session-id]
+decoder cloud graph sync [session-id]
--repository
```
@@ -175,18 +175,18 @@ keys to `*_sha256`, enforces the 250-node/500-edge/500-event/900-total-fact and
1 MiB limits, and derives the sync ID from the prepared graph. Repeating the
same completed snapshot is therefore idempotent. Upload errors are reported to
the explicit command, but cloud availability never affects local execution.
-Rho does not upload prompt bodies, response bodies, tool arguments, tool
+Decoder does not upload prompt bodies, response bodies, tool arguments, tool
results, or other large artifacts.
Mission-scoped graph artifacts can use the same explicit path without being
-pretended to be a Rho session:
+pretended to be a Decoder session:
```bash
-rho graph export --mission-dir
-rho cloud graph sync --mission-dir
+decoder graph export --mission-dir
+decoder cloud graph sync --mission-dir
```
-The CLI reads only `mission-graph.json`, validates its `rho.graph/v1` schema
+The CLI reads only `mission-graph.json`, validates its `decoder.graph/v1` schema
and all edge/event references, then applies the same privacy normalization and
Cloud limits. Mission graphs intentionally omit `sessionId`; they are durable
mission facts, not Cloud session telemetry.
@@ -202,15 +202,15 @@ The central tool-execution seam automatically records:
- secret matches removed from persisted-session responses;
- token usage summaries and budget decisions emitted from the central,
deduplicated provider-accounting seam;
-- Flux model route and usage reported for persisted-session turns.
+- Mux model route and usage reported for persisted-session turns.
Mission execution now also persists a portable graph artifact for local mission
-runs. Plain `rho mission` runs emit mission and feature execution nodes; the
-graph-driven `rho mission --from-tasks` path additionally emits operations
+runs. Plain `decoder mission` runs emit mission and feature execution nodes; the
+graph-driven `decoder mission --from-tasks` path additionally emits operations
nodes for each deterministic wave join, including bounded completion, failure,
and blocked-downstream counts.
The embedded token-pipeline tracker contributes hourly, daily, session, and cost
-limits to the pre-turn guard. Existing Rho cost accounting and limits remain
+limits to the pre-turn guard. Existing Decoder cost accounting and limits remain
authoritative and are updated first; the tracker observes the same deduplicated
request usage and provides the additional token-window decision.
diff --git a/docs/architecture/frontend-contract.md b/docs/architecture/frontend-contract.md
index 526c1cef6..a2fa4d170 100644
--- a/docs/architecture/frontend-contract.md
+++ b/docs/architecture/frontend-contract.md
@@ -1,6 +1,6 @@
# Frontend contract
-Rho has one agent brain and several frontends. They meet at a single typed
+Decoder has one agent brain and several frontends. They meet at a single typed
channel: `engine.StreamEvent`. This document defines that boundary so the TUI,
daemon, ACP server, and print mode stay swappable — the discipline Tau calls
"events are the contract."
diff --git a/docs/architecture/graycode-ecosystem-summary.md b/docs/architecture/graycode-ecosystem-summary.md
index e1725dca5..ffc3c0c0f 100644
--- a/docs/architecture/graycode-ecosystem-summary.md
+++ b/docs/architecture/graycode-ecosystem-summary.md
@@ -1,12 +1,12 @@
# GrayCode Ecosystem Summary
> **Historical.** This document describes the pre-2026-09 multi-engine
-> ecosystem. Rho now depends only on `flux` and embeds its own token engine;
+> ecosystem. Decoder now depends only on `mux` and embeds its own token engine;
> the harrier, kestrel, merlin, shrike, and swift integrations have been
> removed. Kept for record.
-`graycode-eco` is only a local parent folder. `rho` is the main CLI and the
-only primary Rho product; the other repositories provide capabilities,
+`graycode-eco` is only a local parent folder. `decoder` is the main CLI and the
+only primary Decoder product; the other repositories provide capabilities,
contracts, integrations, tooling, or optional platform services.
## Repository layers
@@ -15,18 +15,18 @@ contracts, integrations, tooling, or optional platform services.
API consumers/extensions
sparrow robin wren starling
\ | | /
- rho
+ decoder
(main CLI and daemon)
|
Support engines
- flux harrier shrike swift kestrel merlin
+ mux harrier shrike swift kestrel merlin
|
Foundations
eagle falcon
Outside the Go runtime graph
owl architecture tooling
- graycode-platform web, BFF, and Rho Cloud Worker
+ graycode-platform web, BFF, and Decoder Cloud Worker
```
Product labels map to directories as follows: `harrier`/Harrier, `shrike`/Shrike,
@@ -35,42 +35,42 @@ Product labels map to directories as follows: `harrier`/Harrier, `shrike`/Shrike
## Dependency direction
```text
-rho -> flux / harrier / shrike / swift / kestrel / merlin / eagle
+decoder -> mux / harrier / shrike / swift / kestrel / merlin / eagle
engines -> eagle # when shared contracts are needed
harrier / kestrel / merlin -> falcon
-sparrow / robin / wren -> Rho daemon API
-starling -> Rho skill/plugin API
+sparrow / robin / wren -> Decoder daemon API
+starling -> Decoder skill/plugin API
```
-Forbidden edges are engine-to-engine, engine-to-Rho-internal, SDK-to-engine,
+Forbidden edges are engine-to-engine, engine-to-Decoder-internal, SDK-to-engine,
skills-to-engine, and any Go-module dependency on GrayCode Platform.
## Runtime and hosted plane
```text
-Rho main CLI
- ├── Flux provider execution
+Decoder main CLI
+ ├── Mux provider execution
├── Harrier memory
├── Shrike token/context management
├── Swift swift/provenance
├── Kestrel review
└── Merlin verification
-rho ── optional authenticated HTTP ──> graycode-platform/apps/worker
+decoder ── optional authenticated HTTP ──> graycode-platform/apps/worker
web ──> graycode-platform/apps/bff ── private Service Binding ──> worker
worker ──> control-plane D1 + usage Queue + R2
```
The Worker is deployed as `graycode-cloud`, but that is an application name,
-not a repository. GrayCode Platform remains outside the Rho Go module graph.
-Rho's cloud usage path is fail-open; graph synchronization is explicit.
+not a repository. GrayCode Platform remains outside the Decoder Go module graph.
+Decoder's cloud usage path is fail-open; graph synchronization is explicit.
## Repository roles
| Repository | Role | Direct dependency rule |
|---|---|---|
-| `rho` | Main CLI, daemon, orchestration, policy | Integrates engines and contracts |
-| `flux` | Provider runtime | Uses Eagle contracts; exposes `engine` |
+| `decoder` | Main CLI, daemon, orchestration, policy | Integrates engines and contracts |
+| `mux` | Provider runtime | Uses Eagle contracts; exposes `engine` |
| `harrier` | Harrier memory | Uses Eagle/Falcon where required |
| `shrike` | Shrike context engine | Uses Eagle where required |
| `swift` | Swift/provenance | Uses Eagle where required |
@@ -78,10 +78,10 @@ Rho's cloud usage path is fail-open; graph synchronization is explicit.
| `merlin` | Merlin verification | Uses Eagle and Falcon |
| `eagle` | Neutral shared contracts | Leaf module |
| `falcon` | MCP kit | Upstream MCP library only |
-| `sparrow` | Go SDK | Rho API contract |
-| `robin` | Python SDK | Rho API contract |
-| `wren` | TypeScript SDK | Rho API contract |
-| `starling` | Skills/extensions | Rho skill surface |
+| `sparrow` | Go SDK | Decoder API contract |
+| `robin` | Python SDK | Decoder API contract |
+| `wren` | TypeScript SDK | Decoder API contract |
+| `starling` | Skills/extensions | Decoder skill surface |
| `owl` | Architecture explorer | Generated read-only projection |
| `graycode-platform` | Web/BFF/cloud | HTTP and Service Binding only |
@@ -90,6 +90,6 @@ Rho's cloud usage path is fail-open; graph synchronization is explicit.
The repository-level target is implemented: independent Git repositories,
canonical manifest, generated Owl inventory, sibling Go workspace, Eagle parity,
and dependency boundary checks are all present. Remaining work is to publish
-the Eagle-compatible Flux revision, remove the transitional
-`rho-core-contracts` dependency from the standalone graph, and decide whether
-Rho's graph/projection packages need additional engine-owned facades.
+the Eagle-compatible Mux revision, remove the transitional
+`decoder-core-contracts` dependency from the standalone graph, and decide whether
+Decoder's graph/projection packages need additional engine-owned facades.
diff --git a/docs/architecture/plan.md b/docs/architecture/plan.md
index ac343cf3f..31daab6c3 100644
--- a/docs/architecture/plan.md
+++ b/docs/architecture/plan.md
@@ -1,8 +1,8 @@
-# Rho Architecture - Technical Plan
+# Decoder Architecture - Technical Plan
## Overview
-This plan defines the technical approach for implementing the rho architecture specification. The architecture is already largely implemented; this plan documents the existing design decisions and identifies gaps.
+This plan defines the technical approach for implementing the decoder architecture specification. The architecture is already largely implemented; this plan documents the existing design decisions and identifies gaps.
## Architecture Decisions
@@ -151,7 +151,7 @@ services; it is not a claim that those fields have already moved.
## Dependencies
-- **flux:** LLM provider engine behind `flux/engine` (workspace sibling)
+- **mux:** LLM provider engine behind `mux/engine` (workspace sibling)
- **harrier:** Graph-based persistent memory (workspace sibling)
- **shrike:** Tokenizer, compression (workspace sibling)
- **eagle:** Shared types (workspace sibling)
diff --git a/docs/architecture/spec.md b/docs/architecture/spec.md
index 420952949..6296bbcea 100644
--- a/docs/architecture/spec.md
+++ b/docs/architecture/spec.md
@@ -1,8 +1,8 @@
-# Rho Architecture Specification
+# Decoder Architecture Specification
## Problem Statement
-Rho is an AI-powered coding agent for the terminal. This specification defines the complete architecture: repository structure, agent loop, agile workflow, feedback loops, and edge case handling. It serves as the authoritative reference for how rho works.
+Decoder is an AI-powered coding agent for the terminal. This specification defines the complete architecture: repository structure, agent loop, agile workflow, feedback loops, and edge case handling. It serves as the authoritative reference for how decoder works.
## Scope
@@ -20,15 +20,15 @@ Rho is an AI-powered coding agent for the terminal. This specification defines t
### REQ-1: Repository Structure
-Rho SHALL be organized as a Go repository and workspace entry point within a
-multi-repository ecosystem. The Rho repository has the following top-level
+Decoder SHALL be organized as a Go repository and workspace entry point within a
+multi-repository ecosystem. The Decoder repository has the following top-level
layout:
| Directory | Purpose |
|-----------|---------|
| `cmd/` | CLI entry point (Cobra) and TUI (Bubble Tea) |
| `internal/` | Private Go packages (not importable by external repos) |
-| Parent `go.work` | Resolves the nine local Go siblings: rho, eagle, falcon, flux, harrier (Harrier), shrike (Shrike), swift (Swift), kestrel (Kestrel), and merlin (Merlin) |
+| Parent `go.work` | Resolves the nine local Go siblings: decoder, eagle, falcon, mux, harrier (Harrier), shrike (Shrike), swift (Swift), kestrel (Kestrel), and merlin (Merlin) |
| `spec/` | OpenSpec schema consumed by `internal/spec` |
| `docs/` | Architecture docs, design docs, plans |
| `rules/` | User-defined rules |
@@ -44,7 +44,7 @@ The `internal/` directory SHALL contain the following packages:
| `tool/` | 40+ built-in tools (file edit, git, codegen, spec tools, etc.) |
| `permissions/` | Guardian, rules DSL, boundary checker |
| `plugin/` | Skills loader, registry, auto-skill, marketplace install |
-| `config/` | Product settings, Flux composition, state migration |
+| `config/` | Product settings, Mux composition, state migration |
| `session/` | SQLite persistence, search, export, replay |
| `hooks/` | Event-driven plugin system |
| `mcp/` | Model Context Protocol client/server |
@@ -73,7 +73,7 @@ The `internal/engine/` package SHALL contain the following sub-systems:
|------------|---------|
| `stream.go` | The agent loop (agentLoop) - main orchestration |
| `session.go` | Session struct and sub-services |
-| `chat_service.go` | Rho ChatClient port, engine adapter coordination, compact |
+| `chat_service.go` | Decoder ChatClient port, engine adapter coordination, compact |
| `safety/` | Permission engine, trust tiers, spec gate |
| `compact/` | Context compaction (collapse, micro, smart, truncate) |
| `ctxmgr/` | Context providers, packing, visualization |
@@ -93,17 +93,17 @@ The `internal/engine/` package SHALL contain the following sub-systems:
Provider boundary invariant:
```text
-Rho CLI/TUI + conversation + tools
+Decoder CLI/TUI + conversation + tools
|
- Rho-owned ports/DTOs
+ Decoder-owned ports/DTOs
|
v
- flux/engine
+ mux/engine
credentials -> catalog -> routing -> generate/stream
```
-No production Rho package may import a lower Flux package. Custom gateways
-are supplied per Engine instance, and Flux DTOs are not Rho persistence or
+No production Decoder package may import a lower Mux package. Custom gateways
+are supplied per Engine instance, and Mux DTOs are not Decoder persistence or
CLI output schemas.
### REQ-4: Agent Loop Lifecycle
@@ -128,7 +128,7 @@ The agent loop in `stream.go` SHALL execute the following phases:
6. Refresh Harrier memories
7. Build LLM ChatOptions (system prompt, tools, model)
8. Inject ephemeral context (beliefs, matched skills, spec stage)
-9. Execute the LLM call via `ChatService.Stream()` and the `flux/engine` adapter
+9. Execute the LLM call via `ChatService.Stream()` and the `mux/engine` adapter
10. Process response (tool calls, messages, cost tracking)
11. Check termination conditions
diff --git a/docs/architecture/tasks.md b/docs/architecture/tasks.md
index 0a5193e6e..21ff441b3 100644
--- a/docs/architecture/tasks.md
+++ b/docs/architecture/tasks.md
@@ -1,7 +1,7 @@
-# Rho Architecture - Implementation Tasks
+# Decoder Architecture - Implementation Tasks
> **Historical.** This was the initial architecture implementation checklist.
-> It is superseded by `rho-architecture-v1-definition-of-done.md`, which
+> It is superseded by `decoder-architecture-v1-definition-of-done.md`, which
> reflects the current shipping bar. Kept for record; do not use as a
> current TODO list.
diff --git a/docs/compatibility.md b/docs/compatibility.md
index ccc9e627e..5f675e689 100644
--- a/docs/compatibility.md
+++ b/docs/compatibility.md
@@ -12,19 +12,20 @@ Platform/provider capability metadata is separate: [`platform-capabilities.json`
```jsonc
{
- "components": ["rho", "flux", ...], // canonical eco roster
- "dependencies": { "rho": ["flux", ...] }, // who depends on who
+ "components": ["decoder", "mux", ...], // canonical eco roster
+ "dependencies": { "decoder": ["mux", ...] }, // who depends on who
"matrices": [
- { "name": "stable", "components": { "rho": "0.1.0", "flux": "0.1.0", ... } },
- { "name": "next", "components": { "rho": "main", "flux": "main", ... } }
+ { "name": "stable", "components": { "decoder": "0.1.0", "mux": "0.1.0", ... } },
+ { "name": "next", "components": { "decoder": "main", "mux": "main", ... } }
]
}
```
-Two named matrices:
+Supported matrix names:
-- **`stable`** — the most recent combination of released versions that has
- been tested end-to-end. New users getting "the eco" install these versions.
+- **`stable`** — reserved for the most recent combination of released versions
+ tested end-to-end. It is currently omitted because the existing tags declare
+ different module paths; add it after both renamed modules have releases.
- **`next`** — the bleeding edge: the latest commit on each repo's `main`
branch. CI runs the integration tests against this matrix on every PR to
any eco repo.
@@ -48,7 +49,7 @@ existing consumers.
`.shared-templates/workflows/compatibility-test.yml.tmpl` is a reusable
workflow that:
-1. Reads `testdata/compatibility-matrix.json` from the rho repo.
+1. Reads `testdata/compatibility-matrix.json` from the decoder repo.
2. Checks out each component at the version listed in the named matrix.
3. Builds + tests the cross-repo integration scenarios.
@@ -59,7 +60,7 @@ It runs on:
## Why bother
-- **Bug reports become triageable.** "I ran rho 0.4 with flux 0.2" — you
+- **Bug reports become triageable.** "I ran decoder 0.4 with mux 0.2" — you
immediately know whether that combination was ever tested.
- **Consumers can pin reliably.** Downstream projects that vendor multiple
eco packages can pin to a known-good stable matrix instead of guessing.
@@ -70,17 +71,17 @@ It runs on:
## Pin freshness (advisory)
-Separate from the matrix above: `rho`'s own `go.mod` directly pins shared
+Separate from the matrix above: `decoder`'s own `go.mod` directly pins shared
leaf dependencies, and sibling-repository consumers can pin the *same*
dependencies independently in their own `go.mod`. Go's minimal version
-selection means whatever `rho` pins wins in `rho`'s own build — but if a
+selection means whatever `decoder` pins wins in `decoder`'s own build — but if a
consumer's own pin is older, that consumer's CI has never actually tested the
version that ships. This is exactly the kind of drift that let a real bug
through in July 2026 (a stale goreleaser pin sat unnoticed until the first
tag push exercised it).
`make compat-drift` (wired into this workflow as an advisory, non-blocking
-step) reports any such mismatch by comparing `rho/go.mod` against each
+step) reports any such mismatch by comparing `decoder/go.mod` against each
`..//go.mod`:
```bash
@@ -89,7 +90,7 @@ make compat-drift
This **never fails the build** — it's a signal for humans to notice and
re-pin the consumer, not a gate. It checks sibling repositories when they are
-present; a Rho-only checkout simply reports no local consumers to compare.
+present; a Decoder-only checkout simply reports no local consumers to compare.
## Validating the file
diff --git a/docs/design/RHO-CLOUD-SAAS.md b/docs/design/DECODER-CLOUD-SAAS.md
similarity index 89%
rename from docs/design/RHO-CLOUD-SAAS.md
rename to docs/design/DECODER-CLOUD-SAAS.md
index ba1ce97cf..1342310c2 100644
--- a/docs/design/RHO-CLOUD-SAAS.md
+++ b/docs/design/DECODER-CLOUD-SAAS.md
@@ -1,4 +1,4 @@
-# Rho Cloud — Hosted Execution Plane (Design Doc)
+# Decoder Cloud — Hosted Execution Plane (Design Doc)
**Status:** Draft / Proposal
**Author:** Platform team
@@ -9,17 +9,17 @@
## 1. Overview & Competitive Context
-Rho today is a terminal-native, single-user, privacy-first Go binary. The daemon
-(`rho/internal/daemon/daemon.go`) exposes a small HTTP API — `POST /v1/chat`
+Decoder today is a terminal-native, single-user, privacy-first Go binary. The daemon
+(`decoder/internal/daemon/daemon.go`) exposes a small HTTP API — `POST /v1/chat`
with optional SSE streaming, plus session CRUD — bound to loopback
(`netutil.LoopbackHost`, port `4590` by default) and protected by a single
optional shared API key (`Server.apiKey`, compared in `daemon.go:185-205`). There
is no notion of a user, an org, a tenant, a credit balance, or remote isolated
-execution. Rho does not provide a container or OS sandbox runtime; commands
+execution. Decoder does not provide a container or OS sandbox runtime; commands
run on the host behind the permission engine and tool-level path guards.
-This doc designs **Rho Cloud**: a hosted, multi-tenant execution plane that runs
-the rho agent as a managed service, authenticated by OAuth and API keys, metered
+This doc designs **Decoder Cloud**: a hosted, multi-tenant execution plane that runs
+the decoder agent as a managed service, authenticated by OAuth and API keys, metered
and billed by credits, organized into team workspaces with org RBAC, and backed by
cloud sandboxed execution (E2B-/Daytona-style microVMs) instead of the user's
local Docker. It also covers the two surfaces that depend on this plane: a
@@ -28,7 +28,7 @@ browser/web chat-editing UI served from the daemon, and IDE extensions
### Which Top-20 repos ship this
-From `TOP20_COMPARISON.md`, the rho P0 table (lines 27-37) and P2 table
+From `TOP20_COMPARISON.md`, the decoder P0 table (lines 27-37) and P2 table
(lines 70-86) name these directly:
| Capability | Top-20 repos that ship it | Comparison ref |
@@ -43,11 +43,11 @@ From `TOP20_COMPARISON.md`, the rho P0 table (lines 27-37) and P2 table
The comparison doc is blunt that this is a **fundamental product-tier gap**
(`TOP20_COMPARISON.md:33`) — the single largest item in the report — and that org
RBAC "requires a multi-tenant SaaS backend ... beyond the current single-user
-token store at `/rho/internal/auth/auth.go`" (`TOP20_COMPARISON.md:72`).
+token store at `/decoder/internal/auth/auth.go`" (`TOP20_COMPARISON.md:72`).
-The flux side of the house has the parallel gaps: a LiteLLM-compatible proxy
+The mux side of the house has the parallel gaps: a LiteLLM-compatible proxy
endpoint and "multi-tenant team/project management with SSO/RBAC" with per-key
-budgets (`TOP20_COMPARISON.md:95-96`). Rho Cloud and flux multi-tenancy share
+budgets (`TOP20_COMPARISON.md:95-96`). Decoder Cloud and mux multi-tenancy share
the same identity, billing, and RBAC substrate; this doc designs that substrate
once and shows how both consume it.
@@ -68,13 +68,13 @@ once and shows how both consume it.
`sync.Map` (`daemon.go:35`). Net-new: a routing layer that maps tenant → session
→ execution worker.
4. **Billing / credit system.** Meter token spend and sandbox-minutes per tenant,
- price normalized usage with Rho Cloud's versioned server catalog, enforce
+ price normalized usage with Decoder Cloud's versioned server catalog, enforce
hard limits, and bill from the authoritative cloud ledger.
5. **Team workspaces & conversation sharing.** Shared, permissioned session state;
read-only and continue-able shares.
6. **Org RBAC** with Member / Admin / Owner tiers, invitations, and org-scoped
credit pools and provider config.
-7. **Cloud-isolated execution.** Keep local rho host-native and, if this
+7. **Cloud-isolated execution.** Keep local decoder host-native and, if this
proposal is implemented, run cloud workers in on-demand isolated microVMs
(E2B/Daytona/Firecracker) behind a new cloud-only boundary.
8. **Browser/web UI** for chat-driven editing, served from the plane, consuming
@@ -83,14 +83,14 @@ once and shows how both consume it.
### Non-Goals
-- **Not** replacing the local/offline single-binary mode. Local rho remains
+- **Not** replacing the local/offline single-binary mode. Local decoder remains
fully functional with zero cloud dependency; cloud is strictly additive. The
privacy-first posture (`TOP20_COMPARISON.md:20`) is preserved — cloud is opt-in.
- **Not** building our own microVM hypervisor. We integrate E2B/Daytona (build-vs-buy
in §6), not write Firecracker orchestration from scratch.
-- **Not** an LLM gateway rewrite. Flux remains the provider engine behind
- Rho's `flux/engine` integration; the plane calls a Rho agent worker, which
- composes Flux. The plane does not re-implement routing, caching, or provider
+- **Not** an LLM gateway rewrite. Mux remains the provider engine behind
+ Decoder's `mux/engine` integration; the plane calls a Decoder agent worker, which
+ composes Mux. The plane does not re-implement routing, caching, or provider
adapters.
- **Not** SSO/SAML in P0 (deferred to P2; OIDC social login + API keys first).
- **Not** on-prem/self-hosted enterprise distribution in P0 (P2).
@@ -104,7 +104,7 @@ once and shows how both consume it.
```
┌────────────────────────────────────────┐
- Browser UI ──┐ │ Rho Cloud │
+ Browser UI ──┐ │ Decoder Cloud │
IDE (ACP) ──┼──TLS──▶│ │
CLI (token)──┘ │ ┌──────────────┐ ┌────────────────┐ │
│ │ Edge / API │ │ Identity svc │ │
@@ -122,7 +122,7 @@ once and shows how both consume it.
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌─────────────┐ │
- │ │ Agent Worker │─────▶│ flux │ │
+ │ │ Agent Worker │─────▶│ mux │ │
│ │ (engine. │ │ (model │ │
│ │ Session) │ │ runtime) │ │
│ └──────┬───────┘ └─────────────┘ │
@@ -144,8 +144,8 @@ middleware (`daemon.go:185`) and `routes()` table (`daemon.go:174-183`).
Net-new. Wraps/extends `internal/auth` (see §4).
**Billing service** — credit ledger, metering ingestion, server-side pricing,
-hard-limit enforcement, and invoicing. Rho Cloud owns this authority; Flux
-supplies normalized model and token usage through Rho's Engine boundary.
+hard-limit enforcement, and invoicing. Decoder Cloud owns this authority; Mux
+supplies normalized model and token usage through Decoder's Engine boundary.
**Workspace service** — workspace membership, shared session state, share links,
permission checks for view/continue.
@@ -156,13 +156,13 @@ of the daemon's `sessions sync.Map` (`daemon.go:35`).
**Agent Worker** — a process (or pod) running `engine.NewSessionWithClient(...)`
(`internal/engine/session.go:137`) and driving `Session.Stream(ctx)`
-(`internal/engine/stream.go:20`). This is the existing rho agent loop, unchanged,
+(`internal/engine/stream.go:20`). This is the existing decoder agent loop, unchanged,
running server-side. One worker handles one active session at a time (worktree-per-
session isolation), matching the existing single-user model — we scale by running
many workers, not by making one worker multi-tenant.
**Cloud execution provider** — a future `CloudSandbox` boundary backed by
-E2B/Daytona. This is intentionally net-new cloud code; local rho has no
+E2B/Daytona. This is intentionally net-new cloud code; local decoder has no
container executor or sandbox backend to reuse.
### 3.2 Data Model
@@ -197,11 +197,11 @@ credit_ledger(id, org_id, ts, delta_credits, reason, ref_session_id, ref_meter_i
meter_events(id, org_id, workspace_id, session_id, ts, kind,
tokens_in, tokens_out, model, sandbox_ms, cost_usd, credits,
pricing_catalog_version)
- -- kind ∈ {llm, sandbox}; cost_usd is priced by Rho Cloud
+ -- kind ∈ {llm, sandbox}; cost_usd is priced by Decoder Cloud
```
`meter_events.cost_usd` is computed from normalized model/token dimensions by
-Rho Cloud's versioned pricing catalog. Client-side estimates may be displayed
+Decoder Cloud's versioned pricing catalog. Client-side estimates may be displayed
or audited, but never affect credits or invoices.
### 3.3 API Surface
@@ -257,7 +257,7 @@ Edge: check credit balance(org) > floor [Billing svc] ← rejec
Edge → Router: route(org, ws, user, session_id?)
Router → Worker: acquire/lease Agent Worker (+ Sandbox)
Worker: engine.Session.Stream(ctx) [stream.go:20]
-Worker → flux: Chat/StreamChat with ctx carrying virtual key
+Worker → mux: Chat/StreamChat with ctx carrying virtual key
(WithVirtualKey, budget_provider.go:23)
Worker → Edge: SSE content events (daemon.go:321-337, reused verbatim)
Edge → Client: SSE relay
@@ -268,9 +268,9 @@ Billing: append credit_ledger debit; if balance ≤ 0 → signal Worker
**B. OAuth login (browser UI / IDE)**
PKCE authorization-code grant for the web UI; **device grant for the CLI/IDE** —
-rho already implements RFC 8628 device flow end-to-end
+decoder already implements RFC 8628 device flow end-to-end
(`internal/auth/device_flow.go`: `RequestCode`, `PollForToken`,
-`exchangeCode`). Rho Cloud stands up the *server* side of these grants; the
+`exchangeCode`). Decoder Cloud stands up the *server* side of these grants; the
client side is largely present.
**C. Share a conversation**
@@ -304,7 +304,7 @@ This is the crux: **what is reusable today vs. net-new.**
### Reusable today (high leverage)
-| Existing asset | File | How Rho Cloud reuses it |
+| Existing asset | File | How Decoder Cloud reuses it |
|---|---|---|
| Engine session + agent loop | `internal/engine/session.go:42,132,137`, `internal/engine/stream.go:20` | The Agent Worker *is* `engine.Session.Stream`. No change to the agent loop — it already runs headless with a `SessionFactory` (`daemon.go:27`). |
| HTTP daemon + routes + SSE | `internal/daemon/daemon.go:174-183, 315-337` | The Edge/API gateway is the daemon's `routes()`/`handleChat` generalized. SSE framing (per-line `data:` escaping, `daemon.go:326-329`) is correct and reused verbatim. |
@@ -312,10 +312,10 @@ This is the crux: **what is reusable today vs. net-new.**
| Autonomy / permission gating | `daemon.go:286-298` (`PresetConfig`, `NeedsPermission`) | Server-side auto-approval policy already exists for non-interactive runs; cloud reuses it per-workspace policy. |
| Auth primitives | `internal/auth/auth.go` (`TokenStore`, `SecureStorage`), `device_flow.go` (full RFC 8628) | Device-grant **client** is done. `SecureStorage` (macOS keychain + file fallback, `auth.go:54-121`) stays for local credential caching of cloud tokens. `GenerateNonce` (`auth.go:124`) for OAuth state/PKCE. |
| Constant-time key compare | `daemon.go:207-224` | API-key verification logic carries over (but keys move to hashed storage; see net-new). |
-| Flux normalized usage | `flux/engine` response and stream usage DTOs through Rho's adapter | Reuse model/token dimensions as metering input. Do not import lower Flux packages or trust client-computed prices for billing. |
+| Mux normalized usage | `mux/engine` response and stream usage DTOs through Decoder's adapter | Reuse model/token dimensions as metering input. Do not import lower Mux packages or trust client-computed prices for billing. |
| Remote execution interface | Planned cloud execution boundary | A future `CloudSandbox` would be isolated from the local host runtime behind an explicit provider interface. |
-| Sandbox lifecycle manager | Net-new cloud component | E2B/Daytona pause/resume/snapshot semantics should be designed at the cloud boundary; local rho has no sandbox lifecycle manager. |
-| Messaging gateways | `internal/daemon/gateway.go`, `telegram.go`, `discord.go`, `slack.go` | Already forward to `/v1/chat` via `forwardToRho` (`gateway.go:17`) with bearer auth. In cloud they forward to the tenant-scoped chat endpoint with the org's key — minimal change. |
+| Sandbox lifecycle manager | Net-new cloud component | E2B/Daytona pause/resume/snapshot semantics should be designed at the cloud boundary; local decoder has no sandbox lifecycle manager. |
+| Messaging gateways | `internal/daemon/gateway.go`, `telegram.go`, `discord.go`, `slack.go` | Already forward to `/v1/chat` via `forwardToDecoder` (`gateway.go:17`) with bearer auth. In cloud they forward to the tenant-scoped chat endpoint with the org's key — minimal change. |
| Cron engine | (not yet implemented) | Cloud scheduled runs (Routines) are planned, per `TOP20_COMPARISON.md:48`. Out of scope here but shares the worker plane. |
### Net-new (must build)
@@ -340,7 +340,7 @@ This is the crux: **what is reusable today vs. net-new.**
in-process engine. Net-new control loop.
6. **`CloudSandbox`** — E2B/Daytona-backed cloud-only execution provider.
The interface and call sites exist; the cloud backend does not.
-7. **Billing/credit ledger + invoicing + Stripe integration** — flux gives
+7. **Billing/credit ledger + invoicing + Stripe integration** — mux gives
enforcement and cost math; the ledger, top-ups, plans, and payment processor are
net-new.
8. **Workspace sharing** — `session_shares` and the share/continue flows.
@@ -363,11 +363,11 @@ This is the crux: **what is reusable today vs. net-new.**
- **M0.5** Single-region Agent Worker pool (1 session/worker, worktree isolation).
- **M0.6** `CloudSandbox` (E2B *or* Daytona — pick one) implementing `containerExecutor` (`container.go:18`).
- **M0.7** Metering: ingest normalized model/token dimensions, price them with
- the versioned Rho Cloud catalog, persist the Postgres credit ledger, and
+ the versioned Decoder Cloud catalog, persist the Postgres credit ledger, and
return HTTP 402 at the hard credit floor.
- **M0.8** Minimal web UI (single `go:embed` page) for chat + diff view.
-**Exit criteria:** a paying single team can log in via OAuth, run rho against a
+**Exit criteria:** a paying single team can log in via OAuth, run decoder against a
cloud sandbox, see streamed output and diffs in the browser, and get cut off when
credits hit zero.
@@ -386,7 +386,7 @@ credits hit zero.
- **M2.1** SSO/SAML + SCIM provisioning.
- **M2.2** Multi-region worker pools + autoscaling; second sandbox provider for redundancy.
- **M2.3** JetBrains extension (ACP).
-- **M2.4** Org-scoped provider config (BYO keys / BYO model endpoints), aligning with flux multi-tenant proxy (`TOP20_COMPARISON.md:96`).
+- **M2.4** Org-scoped provider config (BYO keys / BYO model endpoints), aligning with mux multi-tenant proxy (`TOP20_COMPARISON.md:96`).
- **M2.5** Audit logging, IT-managed policy tiers, self-hosted/on-prem distribution.
- **M2.6** Cloud Routines (scheduled/triggered runs) on the worker plane (`TOP20_COMPARISON.md:48`).
@@ -398,9 +398,9 @@ credits hit zero.
|---|---|---|
| MicroVM sandboxing | **Buy/integrate** E2B (P0) + Daytona (P2 redundancy) | Building Firecracker orchestration is a multi-quarter effort orthogonal to product value. E2B SDK is open source (Apache-2.0/MIT family); Daytona is Apache-2.0. Both have hosted offerings; we can also self-host E2B later. The `containerExecutor` seam (`container.go:18`) keeps us provider-agnostic. |
| Identity / OAuth server | **Buy** (Ory Hydra/Kratos, Auth0, or WorkOS) for P0; revisit P2 | Writing a compliant OAuth2/OIDC AS is risky. Ory is Apache-2.0 (self-hostable, privacy-aligned). WorkOS/Auth0 are SaaS — faster but introduce a third party in the auth path (weigh against privacy posture). Prefer **Ory self-hosted** to keep the privacy-first promise. |
-| Billing / payments | **Buy** Stripe for payment + invoicing; **build** the credit ledger | Never build a card processor. The ledger and metering are ours (and partly exist in flux). Stripe SDK is permissive. |
+| Billing / payments | **Buy** Stripe for payment + invoicing; **build** the credit ledger | Never build a card processor. The ledger and metering are ours (and partly exist in mux). Stripe SDK is permissive. |
| Database | **Buy** managed Postgres | Standard. |
-| Metering enforcement | **Build in Rho Cloud** on normalized Engine usage | Billing authority must be server-owned and versioned; lower Flux packages remain engine implementation details. |
+| Metering enforcement | **Build in Decoder Cloud** on normalized Engine usage | Billing authority must be server-owned and versioned; lower Mux packages remain engine implementation details. |
| Web UI framework | **Build** small React SPA, `go:embed` served (Aider/OpenHands pattern) | Keeps deployment a single binary; matches `TOP20_COMPARISON.md:31`. |
| IDE protocol | **Adopt** ACP (Agent Client Protocol) | Industry trajectory (Gemini CLI, Zed, JetBrains), `TOP20_COMPARISON.md:32,36`. Avoid bespoke per-IDE protocols. |
@@ -416,14 +416,14 @@ service, so AGPL deps would create source-disclosure obligations — avoid them.
These repos are privacy-first (`TOP20_COMPARISON.md:20`); the cloud plane must not
erode that.
-1. **Cloud is opt-in and isolated from local mode.** Local rho never phones home;
+1. **Cloud is opt-in and isolated from local mode.** Local decoder never phones home;
nothing in `internal/engine` gains a cloud dependency. The
plane is a separate deployable.
2. **Tenant isolation by construction.** One session ↔ one Agent Worker ↔ one
microVM; no shared filesystem or process between tenants. Worktree-per-session
- (already rho's isolation model) carries over. Cloud microVMs should default to
+ (already decoder's isolation model) carries over. Cloud microVMs should default to
no network egress unless a workspace explicitly grants it through a cloud-owned
- allowlist. Local host execution remains governed by rho's permission and path
+ allowlist. Local host execution remains governed by decoder's permission and path
policies, not by this cloud design.
3. **Secrets never stored raw.** API keys stored as hashes only (the constant-time
compare in `daemon.go:207` becomes hash-compare). OAuth refresh tokens encrypted
@@ -431,7 +431,7 @@ erode that.
4. **Per-line SSE escaping is a real injection defense** already present
(`daemon.go:324-329`) and must be preserved in the relay path — LLM output can
contain newlines that would otherwise forge SSE events.
-5. **Credit enforcement is a DoS control too.** Hard floors (HTTP 402) via flux
+5. **Credit enforcement is a DoS control too.** Hard floors (HTTP 402) via mux
`CheckBudget` (`budget_provider.go:181`) bound runaway agent spend per tenant.
6. **Code privacy.** Customer code lives only in the ephemeral microVM and the
session store; offer per-org data-retention controls and a "no-retention" mode
@@ -455,13 +455,13 @@ erode that.
single-user — `daemon.go` keys one `apiKey`, sessions share a process). Leaning
process/pod-per-session for isolation; needs a cost model.
2. **Sandbox provider:** E2B vs. Daytona for P0. E2B = fastest microVM cold start;
- Daytona = richer dev-environment model. Which maps better onto rho's
+ Daytona = richer dev-environment model. Which maps better onto decoder's
pause/resume/snapshot (`snapshot_sandbox.go`)?
3. **Credit unit:** bill in $-equivalent credits (1 credit = $0.01?) covering both
server-priced LLM usage and sandbox-minutes — what's the blended margin?
4. **BYO keys vs. managed keys:** if an org brings its own provider keys, do their
LLM tokens still consume credits (we only charge sandbox/orchestration), or run
- free? Affects flux provider-config plumbing (`TOP20_COMPARISON.md:96`).
+ free? Affects mux provider-config plumbing (`TOP20_COMPARISON.md:96`).
5. **Identity build-vs-buy:** Ory self-hosted (privacy, ops burden) vs. WorkOS/Auth0
(speed, third party in auth path). Privacy posture argues for Ory.
6. **Session store backend:** Postgres for everything vs. Postgres (metadata) +
@@ -498,7 +498,7 @@ Assumes a small senior team (3-4 engineers). Estimates are for engineering only
with P0 a hard ~8-10 calendar weeks for a usable single-team beta.**
Leverage note: the agent loop, SSE, sandbox interface, device-flow client, and
-flux budget machinery are **already built** — they collapse what would otherwise
+mux budget machinery are **already built** — they collapse what would otherwise
be the most expensive parts (the agent runtime and the metering enforcement engine)
into integration work. The genuinely greenfield cost is identity/multi-tenancy,
worker orchestration, and the cloud sandbox backend.
diff --git a/docs/design/ECOSYSTEM-MARKETPLACE.md b/docs/design/ECOSYSTEM-MARKETPLACE.md
index be88c788b..12c0d52aa 100644
--- a/docs/design/ECOSYSTEM-MARKETPLACE.md
+++ b/docs/design/ECOSYSTEM-MARKETPLACE.md
@@ -3,7 +3,7 @@
**Status:** Draft
**Author:** Ecosystem / DX working group
**Last updated:** 2026-06-06
-**Scope:** Multi-month effort spanning all 5 repos (rho, flux, harrier, shrike, swift) + a new gallery web property + a unified docs site.
+**Scope:** Multi-month effort spanning all 5 repos (decoder, mux, harrier, shrike, swift) + a new gallery web property + a unified docs site.
> This is a design a team executes against, not a code-session deliverable. It grounds every claim in the actual graycode-eco codebase (cited as `path:line`) and reuses what already exists rather than greenfielding.
@@ -13,7 +13,7 @@
Two adjacent gaps from `TOP20_COMPARISON.md` are addressed together because they share infrastructure (a registry index, a content format, a web property):
-1. **Centralized extension gallery / plugin marketplace** — `TOP20_COMPARISON.md:65` (rho P1) and `TOP20_COMPARISON.md:227` (cross-cutting P1).
+1. **Centralized extension gallery / plugin marketplace** — `TOP20_COMPARISON.md:65` (decoder P1) and `TOP20_COMPARISON.md:227` (cross-cutting P1).
2. **Documentation site (Docusaurus/Mintlify) for the graycode-eco ecosystem** — `TOP20_COMPARISON.md:232` (cross-cutting P1).
### Who ships this in the Top 20
@@ -29,14 +29,14 @@ Two adjacent gaps from `TOP20_COMPARISON.md` are addressed together because they
graycode-eco is **not** starting from zero. A large fraction of the marketplace already exists as working Go and a populated registry:
-- **A populated registry already ships.** `starling/registry.json` is a 4.3 MB JSON array of skill entries with `name`, `description`, `category`, `tags`, `path`, `file_count`, `has_scripts` (see file head). It is served raw from GitHub and consumed by rho at `rho/internal/plugin/registry.go:18` (`defaultIndexURL = https://raw.githubusercontent.com/GrayCodeAI/starling/main/registry.json`).
-- **A registry client already works.** `rho/internal/plugin/registry.go` defines `SkillEntry`/`SkillIndex` (`:21`, `:36`), `FetchIndex` with a 1-hour cache (`:60`), and `Install/Remove/InstalledSkillInfo` (`:196`, `:289`, `:309`).
-- **CLI surface already exists.** `rho skills {list,search,install,remove,info,trending,audit}` is wired in `rho/cmd/skills_cmd.go:16-211`.
+- **A populated registry already ships.** `starling/registry.json` is a 4.3 MB JSON array of skill entries with `name`, `description`, `category`, `tags`, `path`, `file_count`, `has_scripts` (see file head). It is served raw from GitHub and consumed by decoder at `decoder/internal/plugin/registry.go:18` (`defaultIndexURL = https://raw.githubusercontent.com/GrayCodeAI/starling/main/registry.json`).
+- **A registry client already works.** `decoder/internal/plugin/registry.go` defines `SkillEntry`/`SkillIndex` (`:21`, `:36`), `FetchIndex` with a 1-hour cache (`:60`), and `Install/Remove/InstalledSkillInfo` (`:196`, `:289`, `:309`).
+- **CLI surface already exists.** `decoder skills {list,search,install,remove,info,trending,audit}` is wired in `decoder/cmd/skills_cmd.go:16-211`.
- **The extension format is partially standardized.** `SKILL.md` files carry YAML frontmatter (`name`, `description`, `license`, `tags`, `version`) — see `starling/api/openapi.yaml` `x-skill-format` and `categories/testing/ab-test-setup/SKILL.md` frontmatter.
-- **A V2 manifest already supports MCP-adjacent bundles.** `rho/internal/plugin/manifest_v2.go:11` (`ManifestV2`) carries `Tools`, `Permissions`, `Hooks` (`:32` `ManifestHook` with `Event`/`Command`/`Priority`), `Config`, `Dependencies`, `Mode` (subprocess/daemon).
-- **Trust scaffolding already exists.** `rho/internal/plugin/malware_check.go:19` blocks `eval()`, pipe-to-shell, reverse shells; `rho/internal/plugin/audit.go` flags hidden-Unicode / homoglyph attacks (`rho skills audit`).
+- **A V2 manifest already supports MCP-adjacent bundles.** `decoder/internal/plugin/manifest_v2.go:11` (`ManifestV2`) carries `Tools`, `Permissions`, `Hooks` (`:32` `ManifestHook` with `Event`/`Command`/`Priority`), `Config`, `Dependencies`, `Mode` (subprocess/daemon).
+- **Trust scaffolding already exists.** `decoder/internal/plugin/malware_check.go:19` blocks `eval()`, pipe-to-shell, reverse shells; `decoder/internal/plugin/audit.go` flags hidden-Unicode / homoglyph attacks (`decoder skills audit`).
-The gap is therefore **consolidation and elevation**, not invention: (a) a *standardized, multi-asset* extension format (today's registry is skills-only); (b) a *browsable web gallery*; (c) a *trust/signing* story beyond static malware regexes; and (d) a *unified docs site* that today is five disconnected `README.md`/`ARCHITECTURE.md` trees (`rho/docs/`, `flux/docs/`, `harrier/`, `shrike/docs/`, `swift/docs/`).
+The gap is therefore **consolidation and elevation**, not invention: (a) a *standardized, multi-asset* extension format (today's registry is skills-only); (b) a *browsable web gallery*; (c) a *trust/signing* story beyond static malware regexes; and (d) a *unified docs site* that today is five disconnected `README.md`/`ARCHITECTURE.md` trees (`decoder/docs/`, `mux/docs/`, `harrier/`, `shrike/docs/`, `swift/docs/`).
---
@@ -44,9 +44,9 @@ The gap is therefore **consolidation and elevation**, not invention: (a) a *stan
### Goals
-- **G1.** A single standardized **Rho Extension** format: a directory with `extension.yaml` (or extended `SKILL.md` frontmatter) that can bundle any subset of: MCP servers, slash commands, prompts, hooks, themes, sub-agents (personas), and skills.
-- **G2.** A **browsable gallery** (rhoskills.dev-style) generated from the registry index, with search, categories, per-extension detail pages, and copy-paste install commands.
-- **G3.** A versioned, machine-readable **registry index format** (v2) that is a superset of today's `registry.json` and remains backward compatible with `rho/internal/plugin/registry.go`.
+- **G1.** A single standardized **Decoder Extension** format: a directory with `extension.yaml` (or extended `SKILL.md` frontmatter) that can bundle any subset of: MCP servers, slash commands, prompts, hooks, themes, sub-agents (personas), and skills.
+- **G2.** A **browsable gallery** (decoderskills.dev-style) generated from the registry index, with search, categories, per-extension detail pages, and copy-paste install commands.
+- **G3.** A versioned, machine-readable **registry index format** (v2) that is a superset of today's `registry.json` and remains backward compatible with `decoder/internal/plugin/registry.go`.
- **G4.** An **install / update / remove flow** with **signing & trust verification** (provenance + signature check, not just regex malware scan).
- **G5.** A **unified documentation site** spanning all 5 repos: getting-started, per-repo API reference, architecture diagrams, cookbook recipes, and the competitor comparison tables — with the gallery either embedded in or cross-linked from it.
- **G6.** Privacy-first throughout: no telemetry-by-default, no account required to browse/install, install is auditable and offline-capable.
@@ -56,7 +56,7 @@ The gap is therefore **consolidation and elevation**, not invention: (a) a *stan
- **NG1.** A hosted, multi-tenant SaaS backend with accounts, billing, or org RBAC (those are separate P0/P2 gaps at `TOP20_COMPARISON.md:33`, `:72`). The gallery is a **static, build-time-generated site backed by a git repo**, not a dynamic app server.
- **NG2.** Paid/commercial extensions, license-key enforcement, or DRM.
- **NG3.** Replacing per-repo deep-dive docs; the unified site **aggregates and cross-links**, it does not fork content.
-- **NG4.** A new package manager. We reuse `git clone`-based install (`registry.go:215`) and the `~/.rho/skills` / `.rho/skills` layout (`registry.go:201-203`).
+- **NG4.** A new package manager. We reuse `git clone`-based install (`registry.go:215`) and the `~/.decoder/skills` / `.decoder/skills` layout (`registry.go:201-203`).
- **NG5.** Runtime arbitrary-code execution in the browser gallery (it renders metadata only; nothing executes client-side).
---
@@ -78,10 +78,10 @@ The gap is therefore **consolidation and elevation**, not invention: (a) a *stan
│ raw.githubusercontent (index + sigs) │ build inputs
▼ ▼
┌───────────────────────────────┐ ┌──────────────────────────────┐
-│ rho CLI (Go) │ │ Gallery + Docs site (static) │
+│ decoder CLI (Go) │ │ Gallery + Docs site (static) │
│ internal/plugin/registry.go │ │ Docusaurus or Mintlify │
│ + new: trust.go, extman.go │ │ - /extensions (gallery) │
-│ cmd/skills_cmd.go (+ ext cmd)│ │ - /docs/{rho,flux,...} │
+│ cmd/skills_cmd.go (+ ext cmd)│ │ - /docs/{decoder,mux,...} │
│ internal/plugin/manifest_v2 │ │ - generated from registry.v2 │
└───────────────────────────────┘ └──────────────────────────────┘
```
@@ -91,22 +91,22 @@ The gap is therefore **consolidation and elevation**, not invention: (a) a *stan
Two interoperable representations, chosen so we **do not break** today's skills-only registry:
**(a) Minimal — extended `SKILL.md` frontmatter** (for single-asset skills, unchanged path):
-Already parsed at `rho/internal/plugin/skill_loader.go:51` (`parseSkillFrontMatter`) and discovered at `rho/internal/tool/skill.go:62` (`discoverSkills`). We keep this working verbatim.
+Already parsed at `decoder/internal/plugin/skill_loader.go:51` (`parseSkillFrontMatter`) and discovered at `decoder/internal/tool/skill.go:62` (`discoverSkills`). We keep this working verbatim.
**(b) Full — `extension.yaml`** (new, for multi-asset bundles):
```yaml
-apiVersion: rho.extension/v1
+apiVersion: decoder.extension/v1
kind: Extension
name: terraform-pro
version: 1.4.0
description: Terraform authoring — skills, an MCP server, slash commands, and a theme.
license: MIT
author: { name: GrayCode AI, url: https://github.com/GrayCodeAI }
-homepage: https://rhoskills.dev/extensions/terraform-pro
+homepage: https://decoderskills.dev/extensions/terraform-pro
keywords: [terraform, iac, devops]
compat:
- minRhoVersion: "1.2.0" # maps to ManifestV2.MinRhoVersion (manifest_v2.go:20)
+ minDecoderVersion: "1.2.0" # maps to ManifestV2.MinDecoderVersion (manifest_v2.go:20)
provides:
skills: [ ./SKILL.md ]
commands: [ ./commands/plan.md, ./commands/apply.md ] # slash commands
@@ -121,11 +121,11 @@ provides:
subagents: [ ./agents/iac-reviewer.md ] # personas (internal/multiagent)
permissions: [ run_shell, network ] # ManifestV2.Permissions
signing:
- publisher: "rho"
+ publisher: "decoder"
signature: "signatures/terraform-pro.sig"
```
-The `provides` block is intentionally a **strict superset of the existing assets rho already loads**: skills (`tool/skill.go`), hooks (`manifest_v2.go:32`), MCP servers (`internal/mcp/mcp.go`), and personas/sub-agents (`internal/multiagent/agents/`, cited at `TOP20_COMPARISON.md:62`). No new runtime concept is invented — `extension.yaml` is a *bundling manifest* over existing loaders.
+The `provides` block is intentionally a **strict superset of the existing assets decoder already loads**: skills (`tool/skill.go`), hooks (`manifest_v2.go:32`), MCP servers (`internal/mcp/mcp.go`), and personas/sub-agents (`internal/multiagent/agents/`, cited at `TOP20_COMPARISON.md:62`). No new runtime concept is invented — `extension.yaml` is a *bundling manifest* over existing loaders.
### 3.3 Registry index format v2 (G3)
@@ -149,7 +149,7 @@ Today's `SkillEntry` (`registry.go:21`) already has most fields. v2 adds a `kind
"repo": "GrayCodeAI/starling",
"provides": { "skills":1, "commands":2, "hooks":1, "mcpServers":1, "themes":1, "subagents":1 },
"signed": true,
- "publisher": "rho",
+ "publisher": "decoder",
"installs": 0,
"updated_at": "..."
}
@@ -157,16 +157,16 @@ Today's `SkillEntry` (`registry.go:21`) already has most fields. v2 adds a `kind
}
```
-Backward compatibility: `registry.go`'s `SkillIndex.Skills` (`:36`) keeps reading `registry.json`. A small shim maps v2 `extensions[]` → `SkillEntry` so older rho binaries keep working; new binaries prefer `registry.v2.json` and fall back. The existing `tools/update_registry.py` / `tools/registry_schema.py` generators (in `starling/tools/`) are extended to emit both.
+Backward compatibility: `registry.go`'s `SkillIndex.Skills` (`:36`) keeps reading `registry.json`. A small shim maps v2 `extensions[]` → `SkillEntry` so older decoder binaries keep working; new binaries prefer `registry.v2.json` and fall back. The existing `tools/update_registry.py` / `tools/registry_schema.py` generators (in `starling/tools/`) are extended to emit both.
### 3.4 API surface
The marketplace has **no HTTP API server** (per NG1). Its "API" is:
1. **The static index files** over `raw.githubusercontent.com` (already the contract — `registry.go:18`).
-2. **The rho CLI**, extended:
- - Existing: `rho skills {list,search,install,remove,info,trending,audit}` (`cmd/skills_cmd.go`).
- - New: `rho ext {search,install,update,verify,info,publish}` for multi-asset extensions, plus `rho ext install --verify` (signature-checked by default).
+2. **The decoder CLI**, extended:
+ - Existing: `decoder skills {list,search,install,remove,info,trending,audit}` (`cmd/skills_cmd.go`).
+ - New: `decoder ext {search,install,update,verify,info,publish}` for multi-asset extensions, plus `decoder ext install --verify` (signature-checked by default).
3. **The gallery's generated JSON** (`/extensions/index.json`) for the site's client-side search (build-time, no server).
### 3.5 Key flows (sequences)
@@ -174,7 +174,7 @@ The marketplace has **no HTTP API server** (per NG1). Its "API" is:
**Flow A — Install with trust verification**
```
-user: rho ext install GrayCodeAI/starling terraform-pro
+user: decoder ext install GrayCodeAI/starling terraform-pro
→ RegistryClient.FetchIndex() registry.go:60 (cache <1h)
→ resolve entry, get repo+path+publisher+signature
→ git clone --depth 1 (existing) registry.go:215
@@ -184,7 +184,7 @@ user: rho ext install GrayCodeAI/starling terraform-pro
→ audit.go (hidden-unicode) + malware_check.go (regex) on every file
blocked pattern → abort malware_check.go:19
→ parse extension.yaml → ManifestV2 manifest_v2.go:42
- → copy assets to ~/.rho/skills/ (and commands/hooks/mcp dirs)
+ → copy assets to ~/.decoder/skills/ (and commands/hooks/mcp dirs)
scope user|project registry.go:201-203
→ inject source-tracking metadata registry.go (injectSourceMetadata)
→ print: installed N assets (skills, 1 mcp, 1 theme, ...)
@@ -192,18 +192,18 @@ user: rho ext install GrayCodeAI/starling terraform-pro
**Flow B — Gallery browse & install (no account, no server)**
```
-browser → rhoskills.dev/extensions (static Docusaurus/Mintlify page)
+browser → decoderskills.dev/extensions (static Docusaurus/Mintlify page)
→ client loads /extensions/index.json (generated from registry.v2.json)
→ user filters by category/tag/capability badge (skills, MCP, hooks, theme)
→ detail page renders extension.yaml metadata + README + capability list
- → "Install" shows: rho ext install (copy button)
+ → "Install" shows: decoder ext install (copy button)
→ nothing executes in browser; install happens locally via CLI
```
**Flow C — Docs build (unified site, all 5 repos)**
```
CI (docs repo) →
- pull README.md / ARCHITECTURE.md / docs/** from each of rho, flux,
+ pull README.md / ARCHITECTURE.md / docs/** from each of decoder, mux,
harrier (Harrier), shrike (Shrike), swift (Swift) (independent checkouts or sparse checkout)
→ transform: inject sidebars, rewrite intra-repo links
→ generate /extensions/* from registry.v2.json
@@ -219,36 +219,36 @@ Concrete reuse map — what is *already there* and what each piece becomes:
| New capability | Reuse today | File:line |
|---|---|---|
-| Registry fetch + 1h cache | `RegistryClient.FetchIndex` | `rho/internal/plugin/registry.go:60` |
+| Registry fetch + 1h cache | `RegistryClient.FetchIndex` | `decoder/internal/plugin/registry.go:60` |
| Index URL contract | `defaultIndexURL` | `registry.go:18` |
| Entry/index schema | `SkillEntry`, `SkillIndex` | `registry.go:21`, `:36` |
| git-clone install + scopes | `RegistryClient.Install` | `registry.go:196-215`, `:201-203` |
| Remove / info | `Remove`, `InstalledSkillInfo` | `registry.go:289`, `:309` |
-| CLI command tree | `skillsCmd` + subcommands | `rho/cmd/skills_cmd.go:16-211` |
-| Skill discovery roots | `discoverSkills`, `skillRoots` | `rho/internal/tool/skill.go:62`, `:91` |
-| Frontmatter parsing | `parseSkillFrontMatter` | `rho/internal/plugin/skill_loader.go:51` |
-| Multi-asset manifest | `ManifestV2` (+`Hooks`,`Config`,`Dependencies`,`Mode`) | `rho/internal/plugin/manifest_v2.go:11`, `:32` |
+| CLI command tree | `skillsCmd` + subcommands | `decoder/cmd/skills_cmd.go:16-211` |
+| Skill discovery roots | `discoverSkills`, `skillRoots` | `decoder/internal/tool/skill.go:62`, `:91` |
+| Frontmatter parsing | `parseSkillFrontMatter` | `decoder/internal/plugin/skill_loader.go:51` |
+| Multi-asset manifest | `ManifestV2` (+`Hooks`,`Config`,`Dependencies`,`Mode`) | `decoder/internal/plugin/manifest_v2.go:11`, `:32` |
| Hook bundling | `ManifestHook{Event,Command,Priority}` | `manifest_v2.go:32` |
-| MCP server bundling | MCP client/loader | `rho/internal/mcp/mcp.go`, `rho/internal/tool/mcp_tool.go` |
-| Sub-agent bundling | Persona system (YAML frontmatter MD) | `rho/internal/multiagent/agents/` (cf. `TOP20_COMPARISON.md:62`) |
-| Rule/skill discovery precedence | `DefaultRuleSources`, `RuleDiscoverer` | `rho/internal/plugin/` rule discovery |
-| Trust — static scan | `malware_check.go` (blocked/suspicious regex) | `rho/internal/plugin/malware_check.go:19` |
-| Trust — unicode/homoglyph | `audit.go` (`AuditFinding`, severities) | `rho/internal/plugin/audit.go:12-22` |
+| MCP server bundling | MCP client/loader | `decoder/internal/mcp/mcp.go`, `decoder/internal/tool/mcp_tool.go` |
+| Sub-agent bundling | Persona system (YAML frontmatter MD) | `decoder/internal/multiagent/agents/` (cf. `TOP20_COMPARISON.md:62`) |
+| Rule/skill discovery precedence | `DefaultRuleSources`, `RuleDiscoverer` | `decoder/internal/plugin/` rule discovery |
+| Trust — static scan | `malware_check.go` (blocked/suspicious regex) | `decoder/internal/plugin/malware_check.go:19` |
+| Trust — unicode/homoglyph | `audit.go` (`AuditFinding`, severities) | `decoder/internal/plugin/audit.go:12-22` |
| Registry generators/validators | Python tooling | `starling/tools/{update_registry,registry_schema,validate_skill,package_skill,sync_marketplace}.py` |
| Format reference | OpenAPI skill-format spec | `starling/api/openapi.yaml` (`x-skill-format`) |
| IDE/agent plugin manifests | `.claude-plugin/{plugin,marketplace}.json` | `starling/.claude-plugin/` |
**Net-new Go (small, additive):**
-- `rho/internal/plugin/trust.go` — signature verification (Flow A) and a `trustdb` of publisher public keys.
-- `rho/internal/plugin/extension.go` — parse `extension.yaml`, expand `provides` into the existing loaders.
-- `rho/cmd/ext_cmd.go` — `rho ext` command tree mirroring `skills_cmd.go`.
+- `decoder/internal/plugin/trust.go` — signature verification (Flow A) and a `trustdb` of publisher public keys.
+- `decoder/internal/plugin/extension.go` — parse `extension.yaml`, expand `provides` into the existing loaders.
+- `decoder/cmd/ext_cmd.go` — `decoder ext` command tree mirroring `skills_cmd.go`.
- Extend `manifest_v2.go` with a `Signing` struct and a `Provides` map (or a thin adapter from `extension.yaml`).
**Net-new outside Go:**
- `registry.v2.json` generator (extend `tools/update_registry.py`).
-- The gallery + docs site (new repo, e.g. `rho-docs`).
+- The gallery + docs site (new repo, e.g. `decoder-docs`).
-The discovery-precedence engine (`rules.go:20` `DefaultRuleSources`, walk-up + local/global/distance/priority sort at `rules.go:97-108`) is reused unchanged for *where* installed extension assets are found — installed extensions land in `.rho/skills` / `~/.rho/skills` (project then user), exactly the precedence `RuleDiscoverer` already honors.
+The discovery-precedence engine (`rules.go:20` `DefaultRuleSources`, walk-up + local/global/distance/priority sort at `rules.go:97-108`) is reused unchanged for *where* installed extension assets are found — installed extensions land in `.decoder/skills` / `~/.decoder/skills` (project then user), exactly the precedence `RuleDiscoverer` already honors.
---
@@ -257,22 +257,22 @@ The discovery-precedence engine (`rules.go:20` `DefaultRuleSources`, walk-up + l
### P0 — Foundation (format + index + trust core)
- **M0.1** Specify and freeze the `extension.yaml` schema; publish as `x-extension-format` alongside the existing `x-skill-format` in `starling/api/openapi.yaml`.
- **M0.2** `registry.v2.json` generator in `tools/update_registry.py`; emit both v1 and v2; v1 stays the default `defaultIndexURL` consumer for older binaries.
-- **M0.3** `extension.go` parser + adapter into `ManifestV2`; `rho ext install` reuses `registry.go:196` clone path; multi-asset copy (skills/commands/hooks/mcp/themes/subagents).
-- **M0.4** Trust v1: detached **minisign/cosign** signatures (`signatures/.sig`), publisher pubkey bundled in rho; `--allow-unsigned` escape hatch; wire `malware_check.go` + `audit.go` into the install path as hard gates.
-- **Exit:** `rho ext install` works for at least 5 multi-asset extensions, signature-verified, on a v2 index.
+- **M0.3** `extension.go` parser + adapter into `ManifestV2`; `decoder ext install` reuses `registry.go:196` clone path; multi-asset copy (skills/commands/hooks/mcp/themes/subagents).
+- **M0.4** Trust v1: detached **minisign/cosign** signatures (`signatures/.sig`), publisher pubkey bundled in decoder; `--allow-unsigned` escape hatch; wire `malware_check.go` + `audit.go` into the install path as hard gates.
+- **Exit:** `decoder ext install` works for at least 5 multi-asset extensions, signature-verified, on a v2 index.
### P1 — Gallery + Docs site (the visible surface)
-- **M1.1** Stand up the static site (decision in §6). Pages: `/extensions` (gallery), per-extension detail, `/docs/{rho,flux,harrier,shrike,swift}` (getting-started + API ref + architecture), `/comparison` (rendered from `TOP20_COMPARISON.md`).
+- **M1.1** Stand up the static site (decision in §6). Pages: `/extensions` (gallery), per-extension detail, `/docs/{decoder,mux,harrier,shrike,swift}` (getting-started + API ref + architecture), `/comparison` (rendered from `TOP20_COMPARISON.md`).
- **M1.2** Build-time generation of `/extensions/index.json` from `registry.v2.json`; client-side fuzzy search, category + capability-badge filters.
- **M1.3** Aggregate the 5 independent repositories' docs via checkout or sparse checkout in CI (Flow C); link-rewriting + unified sidebar.
-- **M1.4** `rho ext update` (diff installed version vs index, re-verify, atomic replace) and `rho ext verify ` (re-check signature/audit of an installed extension).
-- **Exit:** rhoskills.dev (or chosen domain) live; gallery browseable; one-line install copy works; docs cover all 5 repos with getting-started + API ref.
+- **M1.4** `decoder ext update` (diff installed version vs index, re-verify, atomic replace) and `decoder ext verify ` (re-check signature/audit of an installed extension).
+- **Exit:** decoderskills.dev (or chosen domain) live; gallery browseable; one-line install copy works; docs cover all 5 repos with getting-started + API ref.
### P2 — Ecosystem maturity & publisher self-service
-- **M2.1** `rho ext publish` — scaffolds `extension.yaml`, runs validators (`tools/validate_skill.py` extended), signs locally, opens a PR to `starling`.
-- **M2.2** Publisher trust tiers: verified-publisher badge (key in rho's bundled trust DB) vs community (signed but unverified) vs unsigned.
+- **M2.1** `decoder ext publish` — scaffolds `extension.yaml`, runs validators (`tools/validate_skill.py` extended), signs locally, opens a PR to `starling`.
+- **M2.2** Publisher trust tiers: verified-publisher badge (key in decoder's bundled trust DB) vs community (signed but unverified) vs unsigned.
- **M2.3** Trending/installs analytics — privacy-preserving (aggregate counts from PR-based opt-in pings or GitHub stars only; **no per-user tracking**, see §7).
-- **M2.4** Cross-repo extension kinds: flux provider plug-ins, shrike compression profiles (`TOP20_COMPARISON.md:181` team profiles), swift exporters — registered through the same `extension.yaml` `provides` mechanism with new `kind`s.
+- **M2.4** Cross-repo extension kinds: mux provider plug-ins, shrike compression profiles (`TOP20_COMPARISON.md:181` team profiles), swift exporters — registered through the same `extension.yaml` `provides` mechanism with new `kind`s.
- **Exit:** External contributors can publish a verified, multi-asset extension end-to-end; gallery shows mixed-kind extensions across the ecosystem.
---
@@ -297,13 +297,13 @@ The discovery-precedence engine (`rules.go:20` `DefaultRuleSources`, walk-up + l
minisign is the lighter P0 choice (single keypair, no external infra). cosign/sigstore is the P2 upgrade if we want keyless, transparency-log-backed provenance (which also dovetails with the SBOM/Cosign work at `TOP20_COMPARISON.md:240`).
-### New runtime dependencies for rho
+### New runtime dependencies for decoder
- A minisign/Ed25519 verify path: Go stdlib `crypto/ed25519` is sufficient — **no new dependency** for verification; only key management is new.
- No new dependency for install: `git` is already required (`registry.go:215`).
### Licensing implications
- Every extension's `extension.yaml` **must** carry a `license` field (already required for skills — `openapi.yaml` `required_frontmatter`). The gallery surfaces it; the validator rejects missing/unknown licenses.
-- The community repo is **MIT** (`starling/LICENSE`). Contributed extensions retain their own license but must be OSI-approved; a CI check (extend `tools/validate_skill.py`) flags GPL/AGPL bundled binaries that would conflict with rho's distribution model (mirrors `TOP20_COMPARISON.md:241`).
+- The community repo is **MIT** (`starling/LICENSE`). Contributed extensions retain their own license but must be OSI-approved; a CI check (extend `tools/validate_skill.py`) flags GPL/AGPL bundled binaries that would conflict with decoder's distribution model (mirrors `TOP20_COMPARISON.md:241`).
- Docusaurus (MIT) and minisign (ISC) impose no copyleft obligations.
---
@@ -316,24 +316,24 @@ These repos are privacy-first; the marketplace must not regress that.
- **Supply-chain trust (the core new risk).** Installing an extension means importing executable assets (hooks `manifest_v2.go:32`, MCP server binaries, scripts). Mitigations, in order of enforcement at install time (Flow A):
1. **Signature verification** (`trust.go`): detached signature over the extension tree hash, verified against a bundled/known publisher key. Unsigned → blocked unless `--allow-unsigned`.
2. **Static malware scan** (`malware_check.go:19`): blocks `eval(`, pipe-to-shell, base64-to-shell, reverse shells, netcat `-e`.
- 3. **Hidden-Unicode / homoglyph audit** (`audit.go`): catches prompt-injection-via-invisible-characters in `SKILL.md`/prompts (already `rho skills audit`).
+ 3. **Hidden-Unicode / homoglyph audit** (`audit.go`): catches prompt-injection-via-invisible-characters in `SKILL.md`/prompts (already `decoder skills audit`).
4. **Permission disclosure:** `extension.yaml` `permissions` (mapped to `ManifestV2.Permissions`, `manifest_v2.go:18`) are shown to the user before install; `run_shell`/`network` require explicit confirmation.
- **MCP server execution is the highest-risk asset.** Bundled MCP servers run as subprocesses. P0 ships them as **opt-in** (the extension installs the *definition*; the user must explicitly enable the server), and prefers `stdio` transport with no inbound network surface.
- **Prompt-injection through extension content.** Skills/prompts are injected into the system prompt via the same path as rules (`rules.go`). The audit (3) plus the existing HTML-comment-stripping concern (`TOP20_COMPARISON.md:74`) apply; the validator strips/flags suspicious frontmatter.
- **Offline/air-gapped install.** Because install is `git clone` + local copy with local signature verification, an org can mirror `starling` internally and point `defaultIndexURL`/`--index` at it — no call to GitHub required.
- **No third-party doc analytics.** Self-hosted Docusaurus (§6) avoids shipping user reading data to a SaaS. Any "installs" metric (P2) is aggregate-only and opt-in.
-- **Signing key custody.** Verified-publisher keys ship in rho's binary; rotation requires a rho release. P2 cosign/sigstore would move trust to a transparency log, reducing reliance on bundled keys.
+- **Signing key custody.** Verified-publisher keys ship in decoder's binary; rotation requires a decoder release. P2 cosign/sigstore would move trust to a transparency log, reducing reliance on bundled keys.
---
## 8. Open Questions
1. **Signing backend:** minisign (simple, key-in-binary) for P0, or go straight to sigstore/cosign keyless (transparency log, no key custody) and align with the SBOM effort (`TOP20_COMPARISON.md:240`)? Tradeoff: operational simplicity now vs. provenance rigor later.
-2. **One repo or two?** Keep gallery + docs in `starling`, or split docs into a new `rho-docs` repo with the 5 repos as submodules? (Submodules complicate contributor flow but isolate doc build from skill content.)
-3. **Cross-repo extension kinds (P2):** do flux/shrike/swift assets (provider plugins, compression profiles, exporters) belong in the *same* `starling` registry, or a per-repo registry federated into one gallery index?
-4. **Versioning & compat matrix:** `compat.minRhoVersion` exists (`manifest_v2.go:20`), but do we also need per-asset compat (e.g., an MCP server needing a specific transport rho supports)? Tie-in to the tri-modal MCP transport gap (`TOP20_COMPARISON.md:83`).
-5. **Install integrity for non-skill assets:** today install only copies `SKILL.md` trees (`registry.go` discovers `SKILL.md`); multi-asset copy (commands/hooks/mcp/themes/subagents) needs a defined on-disk layout under `~/.rho/`. What are the canonical install dirs for each asset kind?
-6. **Domain & hosting:** confirm `rhoskills.dev` (referenced `TOP20_COMPARISON.md:65`) ownership and Pages target (GitHub vs Cloudflare).
+2. **One repo or two?** Keep gallery + docs in `starling`, or split docs into a new `decoder-docs` repo with the 5 repos as submodules? (Submodules complicate contributor flow but isolate doc build from skill content.)
+3. **Cross-repo extension kinds (P2):** do mux/shrike/swift assets (provider plugins, compression profiles, exporters) belong in the *same* `starling` registry, or a per-repo registry federated into one gallery index?
+4. **Versioning & compat matrix:** `compat.minDecoderVersion` exists (`manifest_v2.go:20`), but do we also need per-asset compat (e.g., an MCP server needing a specific transport decoder supports)? Tie-in to the tri-modal MCP transport gap (`TOP20_COMPARISON.md:83`).
+5. **Install integrity for non-skill assets:** today install only copies `SKILL.md` trees (`registry.go` discovers `SKILL.md`); multi-asset copy (commands/hooks/mcp/themes/subagents) needs a defined on-disk layout under `~/.decoder/`. What are the canonical install dirs for each asset kind?
+6. **Domain & hosting:** confirm `decoderskills.dev` (referenced `TOP20_COMPARISON.md:65`) ownership and Pages target (GitHub vs Cloudflare).
7. **Docs source of truth:** auto-aggregate from each repo's `README.md`/`ARCHITECTURE.md` (drift-free but messy formatting) vs. hand-curated landing pages that link into per-repo docs (cleaner but duplicative)?
---
@@ -342,14 +342,14 @@ These repos are privacy-first; the marketplace must not regress that.
| Workstream | Scope | Est. |
|---|---|---|
-| **P0 — format + index v2** | `extension.yaml` spec, v2 generator in `tools/`, `extension.go` parser + `ManifestV2` adapter, multi-asset install layout, `rho ext` command tree | **4–5 ew** |
+| **P0 — format + index v2** | `extension.yaml` spec, v2 generator in `tools/`, `extension.go` parser + `ManifestV2` adapter, multi-asset install layout, `decoder ext` command tree | **4–5 ew** |
| **P0 — trust core** | `trust.go` (Ed25519/minisign verify), publisher key bundling, wire `malware_check`/`audit` as install gates, permission-disclosure UX | **3–4 ew** |
| **P1 — gallery** | Docusaurus setup, `/extensions` React route, build-time `index.json`, search + filters + detail pages | **4–5 ew** |
| **P1 — unified docs** | Aggregate 5 independent repositories (checkout/sparse-checkout CI), sidebars + link rewrite, getting-started + API-ref scaffolding per repo, comparison tables from `TOP20_COMPARISON.md` | **5–7 ew** |
-| **P1 — CLI update/verify** | `rho ext update`, `rho ext verify`, atomic replace | **2 ew** |
-| **P2 — publisher self-service** | `rho ext publish` scaffolder + validators, PR automation | **3 ew** |
+| **P1 — CLI update/verify** | `decoder ext update`, `decoder ext verify`, atomic replace | **2 ew** |
+| **P2 — publisher self-service** | `decoder ext publish` scaffolder + validators, PR automation | **3 ew** |
| **P2 — trust tiers + sigstore upgrade** | verified-publisher badges, optional cosign/sigstore keyless + transparency log | **3–4 ew** |
-| **P2 — cross-repo kinds** | flux/shrike/swift extension kinds + federated index | **3–4 ew** |
+| **P2 — cross-repo kinds** | mux/shrike/swift extension kinds + federated index | **3–4 ew** |
| **Cross-cutting** | docs writing (content, not framework), security review, CI, design iteration | **4–6 ew** |
| **Total** | | **≈ 31–44 eng-weeks** (~7.5–11 eng-months; 2 engineers ~4–5 calendar months) |
@@ -360,13 +360,13 @@ The estimate is bounded on the low side because the hardest plumbing — the reg
### Appendix: grounding index (real files cited)
- `starling/registry.json`, `registry.json` head (schema), `tools/*.py`, `api/openapi.yaml`, `.claude-plugin/{plugin,marketplace}.json`, `categories/testing/ab-test-setup/SKILL.md`, `LICENSE`
-- `rho/internal/plugin/registry.go:18,21,36,60,196,201,215,289,309`
-- `rho/internal/plugin/manifest_v2.go:11,18,20,32,42`
-- `rho/internal/plugin/skill_loader.go:51`
-- `rho/internal/plugin/malware_check.go:19`
-- `rho/internal/plugin/audit.go:12`
-- `rho/internal/tool/skill.go:62,91`
-- `rho/internal/plugin/` rule discovery
-- `rho/cmd/skills_cmd.go:16-211`
-- `rho/internal/mcp/mcp.go`, `rho/internal/tool/mcp_tool.go`
+- `decoder/internal/plugin/registry.go:18,21,36,60,196,201,215,289,309`
+- `decoder/internal/plugin/manifest_v2.go:11,18,20,32,42`
+- `decoder/internal/plugin/skill_loader.go:51`
+- `decoder/internal/plugin/malware_check.go:19`
+- `decoder/internal/plugin/audit.go:12`
+- `decoder/internal/tool/skill.go:62,91`
+- `decoder/internal/plugin/` rule discovery
+- `decoder/cmd/skills_cmd.go:16-211`
+- `decoder/internal/mcp/mcp.go`, `decoder/internal/tool/mcp_tool.go`
- `TOP20_COMPARISON.md:65,74,83,181,227,232,240,241`
diff --git a/docs/design/three-repo-architecture.md b/docs/design/three-repo-architecture.md
index 290fd04d8..f0bb84e6e 100644
--- a/docs/design/three-repo-architecture.md
+++ b/docs/design/three-repo-architecture.md
@@ -8,12 +8,12 @@ proposal. See also `gateway-architecture.md` (human-readable version),
```mermaid
flowchart LR
- subgraph CLI["rho"]
+ subgraph CLI["decoder"]
TUI["chat · exec · review\nagent loop · sessions"]
- ENG["flux engine\n(compiled in)"]
+ ENG["mux engine\n(compiled in)"]
end
- subgraph ROUTER["flux"]
+ subgraph ROUTER["mux"]
LIB["engine library\n(router, adapters)"]
SRV["HTTP server (skeleton)\ninternal/api + openapi.yaml"]
end
@@ -32,18 +32,18 @@ Wires, with evidence:
| From → To | Mechanism | Evidence |
|---|---|---|
-| CLI → Router | Go module dep, in-process construction | `go.mod` requires `github.com/GrayCodeAI/flux`; `internal/provider/gateway/gateway.go` is the sole importer |
+| CLI → Router | Go module dep, in-process construction | `go.mod` requires `github.com/GrayCodeAI/mux`; `internal/provider/gateway/gateway.go` is the sole importer |
| CLI → Platform | Opt-in HTTPS (login, usage, graph sync) | `internal/platform/cloud/client.go`; `Enabled()` requires endpoint + token; no default URL |
-| Router → CLI | none | router `go.mod`/`go.sum` contain zero rho refs |
+| Router → CLI | none | router `go.mod`/`go.sum` contain zero decoder refs |
| Router ↔ Platform | none | no imports, package deps, or API calls either direction |
## Target state (proposal)
```mermaid
flowchart LR
- CLI2["rho\n(default: in-process)"] -. "opt-in --model-gateway" .-> GW
+ CLI2["decoder\n(default: in-process)"] -. "opt-in --model-gateway" .-> GW
WEB2["platform web/BFF"] -->|per-user keys| GW
- subgraph GW["flux: common service"]
+ subgraph GW["mux: common service"]
API["OpenAI-compatible API\n/v1/chat/completions + SSE"]
POL["routing · retry · guardrails\nspend tracking"]
end
diff --git a/docs/ecosystem-message-flow.md b/docs/ecosystem-message-flow.md
index 43bf54819..963387331 100644
--- a/docs/ecosystem-message-flow.md
+++ b/docs/ecosystem-message-flow.md
@@ -1,11 +1,11 @@
-# Message flow (flux + embedded token engine)
+# Message flow (mux + embedded token engine)
-How one user message travels through rho.
+How one user message travels through decoder.
## Overview
```
-User prompt (TUI or rho exec)
+User prompt (TUI or decoder exec)
│
▼
┌───────────────────┐
@@ -14,7 +14,7 @@ User prompt (TUI or rho exec)
│
▼
┌───────────────────┐ ┌─────────────┐
-│ local memory │◄────│ ~/.rho/ │ conventions, decisions, lessons
+│ local memory │◄────│ ~/.decoder/ │ conventions, decisions, lessons
│ recall │ │ memories │
└─────────┬─────────┘ └─────────────┘
│
@@ -26,7 +26,7 @@ User prompt (TUI or rho exec)
│
▼
┌───────────────────┐ ┌─────────────┐
-│ Rho ChatClient │────►│ flux/engine│ catalog, credentials, routing
+│ Decoder ChatClient │────►│ mux/engine│ catalog, credentials, routing
│ port + adapter │ │ generate/ │────► provider API
└─────────┬─────────┘ │ stream │
└─────────────┘
@@ -40,27 +40,27 @@ User prompt (TUI or rho exec)
▼ (when context grows)
┌───────────────────┐
│ token Compress │ fast path before LLM summarization
-│ + flux compact │
+│ + mux compact │
└───────────────────┘
```
## Step by step
-### 1. Session start (`rho` or `rho exec`)
+### 1. Session start (`decoder` or `decoder exec`)
-- **flux**: The Rho composition root creates an `flux/engine.Engine` with
- Flux-owned state paths, an injected secret store, and per-engine custom
+- **mux**: The Decoder composition root creates an `mux/engine.Engine` with
+ Mux-owned state paths, an injected secret store, and per-engine custom
gateway metadata. The engine loads provider state and the model catalog, then
- builds transport behind Rho's `ChatClient` port.
+ builds transport behind Decoder's `ChatClient` port.
- **memory**: `configureSession` initializes the local memory manager
(core, auto, evolving, zen, retrieval metrics, continuity). If the state
- directory is unavailable, rho runs without persistent memory.
+ directory is unavailable, decoder runs without persistent memory.
- **token**: No startup step — embedded at compile time.
### 2. System prompt assembly
-- Rho templates (`internal/prompts/templates/*.md`) define behavior, tools, and practices.
-- Project `AGENTS.md` is appended via `rhoconfig.BuildContextWithDirs`.
+- Decoder templates (`internal/prompts/templates/*.md`) define behavior, tools, and practices.
+- Project `AGENTS.md` is appended via `decoderconfig.BuildContextWithDirs`.
- **memory**: `Memory.Recall` injects relevant stored memories into the system prompt.
### 3. User message → agent loop (`internal/engine/stream.go`)
@@ -68,8 +68,8 @@ User prompt (TUI or rho exec)
Each turn:
1. **memory** — recall memories matching the latest user message (token budget ~2000).
-2. **flux** — Rho's adapter calls engine generate/stream with Rho-owned tool
- definitions; Flux normalizes provider events and tool requests.
+2. **mux** — Decoder's adapter calls engine generate/stream with Decoder-owned tool
+ definitions; Mux normalizes provider events and tool requests.
3. Tools run with the session's memory service in context.
4. **memory** — post-session bookkeeping records the session goal and outcome.
@@ -78,7 +78,7 @@ Each turn:
When messages exceed limits (`internal/engine/compact.go`):
1. **token** — `token.Compress()` tries a fast compression path for summaries.
-2. **flux** — if token reduction is insufficient, rho calls the LLM to summarize, then keeps recent messages.
+2. **mux** — if token reduction is insufficient, decoder calls the LLM to summarize, then keeps recent messages.
### 5. Token accounting
@@ -88,21 +88,21 @@ When messages exceed limits (`internal/engine/compact.go`):
## Verify locally
```bash
-rho doctor # ecosystem panel + flux preflight
-./scripts/smoke-rho.sh # build + quick tests
+decoder doctor # ecosystem panel + mux preflight
+./scripts/smoke-decoder.sh # build + quick tests
```
## Module layout
-| Module | Role in rho | Required? |
+| Module | Role in decoder | Required? |
|--------|----------------|-----------|
-| **flux** | LLM APIs, catalog, credentials, routing | Yes |
+| **mux** | LLM APIs, catalog, credentials, routing | Yes |
| **internal/token** | Token estimate + context compression + secrets + usage | Yes (embedded, no config) |
-`flux` is an independent sibling checkout; the parent `go.work` wires the
+`mux` is an independent sibling checkout; the parent `go.work` wires the
local Go workspace.
-Production Rho code imports Flux only through `flux/engine`. Conversation
-history, WAL/resume, permissions, tool execution, and memory remain in Rho;
+Production Decoder code imports Mux only through `mux/engine`. Conversation
+history, WAL/resume, permissions, tool execution, and memory remain in Decoder;
provider credentials, discovery, selection, transport, resilience, and
-normalized streaming remain in Flux.
\ No newline at end of file
+normalized streaming remain in Mux.
\ No newline at end of file
diff --git a/docs/ecosystem-remediation-plan.md b/docs/ecosystem-remediation-plan.md
index e594bc66f..78454dc46 100644
--- a/docs/ecosystem-remediation-plan.md
+++ b/docs/ecosystem-remediation-plan.md
@@ -4,21 +4,21 @@ This document captures the improvement recommendations from the 2026-07-11
full-ecosystem audit that require significant refactoring and are documented
here for scheduled execution rather than immediate implementation.
-## 1. charmbracelet v1/v2 Dependency Duplication (rho + swift)
+## 1. charmbracelet v1/v2 Dependency Duplication (decoder + swift)
**Status:** ✅ Done (2026-07-11)
-**Impact:** High — contributed ~20-30MB to rho binary size
+**Impact:** High — contributed ~20-30MB to decoder binary size
### Outcome
-- Rho and Swift imports migrated to `charm.land/*/v2` (`bubbles`, `bubbletea`,
+- Decoder and Swift imports migrated to `charm.land/*/v2` (`bubbles`, `bubbletea`,
`lipgloss`, `huh`, `glamour`).
- Direct `github.com/charmbracelet/{bubbles,bubbletea,lipgloss}` requires removed
- from rho/swift `go.mod`.
+ from decoder/swift `go.mod`.
- Binary size gate tightened: **110MB → 80MB** (`make size-check`).
-- Verified build: rho binary **~75 MB** (under gate) after migration.
+- Verified build: decoder binary **~75 MB** (under gate) after migration.
-Commits (rho): `2890c74` (migrate), `ccfa286` (API fixups), `7a42c1e` (size gate).
+Commits (decoder): `2890c74` (migrate), `ccfa286` (API fixups), `7a42c1e` (size gate).
### Residual notes
@@ -38,13 +38,13 @@ Commits (rho): `2890c74` (migrate), `ccfa286` (API fixups), `7a42c1e` (size gate
(`replace github.com/GrayCodeAI/harrier => ../..`).
- Core `github.com/GrayCodeAI/harrier` no longer requires
`charmbracelet/{bubbles,bubbletea,lipgloss}`.
-- Rho embeds only the library packages (`engine`, `storage`, `graph`, …), so
- the default rho binary does not pull the demo TUI module.
+- Decoder embeds only the library packages (`engine`, `storage`, `graph`, …), so
+ the default decoder binary does not pull the demo TUI module.
- Verify: `cd harrier && go test ./...`; `cd harrier/cmd/harrier-tui && go test ./...`.
### Residual notes
-- The local `harrier` (Harrier) checkout and Rho's `go.mod` must resolve to a
+- The local `harrier` (Harrier) checkout and Decoder's `go.mod` must resolve to a
published matching commit. **Publish Harrier before** relying on
`GOWORK=off` / module-release parity (the Go proxy must see the commit for
sumdb download).
@@ -98,13 +98,13 @@ large diffs and bloats the repo.
`.gitignore`.
2. **Generate at build/publish time:** Run `python tools/update_registry.py`
in CI before publishing artifacts.
-3. **Runtime fetch:** Have `rho` fetch the registry from a CDN or GitHub
+3. **Runtime fetch:** Have `decoder` fetch the registry from a CDN or GitHub
raw URL rather than embedding it.
### Risk
-If `registry.json` is read offline by rho, removing it requires adding a
-fetch-or-cache mechanism. Verify how rho consumes the registry before
+If `registry.json` is read offline by decoder, removing it requires adding a
+fetch-or-cache mechanism. Verify how decoder consumes the registry before
removing from git.
---
diff --git a/docs/intelligent-cli.md b/docs/intelligent-cli.md
index 46f0a55c2..06f29ad2c 100644
--- a/docs/intelligent-cli.md
+++ b/docs/intelligent-cli.md
@@ -1,6 +1,6 @@
# Intelligent CLI capabilities
-Rho keeps the startup tool schema small while making the full capability
+Decoder keeps the startup tool schema small while making the full capability
surface discoverable on demand. The registry currently contains core tools,
lazy tools, and MCP tools; intent routing promotes only the tools relevant to
the current request.
@@ -37,8 +37,8 @@ Dependency and GitHub operations are network-gated and read-only by default.
## Inspecting the registry
```bash
-rho tools
-rho tools --json
+decoder tools
+decoder tools --json
```
The JSON form includes risk level, read-only status, aliases, and intent
diff --git a/docs/mcp-servers.md b/docs/mcp-servers.md
index 18f47b390..f606cd49a 100644
--- a/docs/mcp-servers.md
+++ b/docs/mcp-servers.md
@@ -1,10 +1,10 @@
# MCP Server Configuration
-rho supports connecting to external MCP (Model Context Protocol) servers to extend its capabilities with additional tools, resources, and prompts.
+decoder supports connecting to external MCP (Model Context Protocol) servers to extend its capabilities with additional tools, resources, and prompts.
## Configuration
-MCP servers are configured in `settings.json` (global: `~/.rho/settings.json`, project: `.rho/settings.json`).
+MCP servers are configured in `settings.json` (global: `~/.decoder/settings.json`, project: `.decoder/settings.json`).
```json
{
@@ -42,7 +42,7 @@ My-Jogyo provides 12 MCP tools for scientific research workflows, including Pyth
# Install My-Jogyo
npm install -g my-jogyo
-# Add to rho settings
+# Add to decoder settings
```
**settings.json:**
@@ -78,16 +78,16 @@ npm install -g my-jogyo
```bash
# Add an MCP server
-rho mcp add [args...]
+decoder mcp add [args...]
# List configured servers
-rho mcp list
+decoder mcp list
# Remove a server
-rho mcp remove
+decoder mcp remove
# Test a server connection
-rho mcp test
+decoder mcp test
```
## Troubleshooting
@@ -98,8 +98,8 @@ rho mcp test
- Run the command manually to check for errors
**Tools not appearing:**
-- Restart rho after adding a new server
-- Check `rho mcp test ` for connection errors
+- Restart decoder after adding a new server
+- Check `decoder mcp test ` for connection errors
- Verify the server's tools/list response is valid JSON-RPC
**Timeout errors:**
diff --git a/docs/monitoring-guide.md b/docs/monitoring-guide.md
index 5f6499051..478170c3a 100644
--- a/docs/monitoring-guide.md
+++ b/docs/monitoring-guide.md
@@ -1,6 +1,6 @@
# Monitoring Guide
-This guide covers how to monitor rho's daemon and CLI for production health,
+This guide covers how to monitor decoder's daemon and CLI for production health,
performance, and security.
## 1. Daemon Health & Readiness
@@ -18,7 +18,7 @@ curl -sf http://localhost:4590/v1/health
### `GET /v1/ready` — Readiness probe
Returns 200 when the daemon is fully ready to serve traffic (session factory
-configured, Flux preflight checks pass). Returns 503 with the failed
+configured, Mux preflight checks pass). Returns 503 with the failed
dependency during startup or when dependencies are unavailable.
```bash
@@ -31,7 +31,7 @@ Returns aggregated usage statistics (sessions, messages, tool calls, cost)
for the last N days (default 30, `?days=30`).
```bash
-curl -H "X-API-Key: $RHO_DAEMON_API_KEY" \
+curl -H "X-API-Key: $DECODER_DAEMON_API_KEY" \
http://localhost:4590/v1/stats
```
@@ -43,7 +43,7 @@ The daemon exposes metrics in Prometheus text exposition format at
`GET /v1/metrics`. This endpoint requires authentication.
```bash
-curl -H "X-API-Key: $RHO_DAEMON_API_KEY" \
+curl -H "X-API-Key: $DECODER_DAEMON_API_KEY" \
http://localhost:4590/v1/metrics
```
@@ -51,9 +51,9 @@ Available metrics:
| Metric | Type | Description |
|--------|------|-------------|
-| `rho_daemon_active_sessions` | gauge | Number of active daemon sessions |
-| `rho_daemon_chat_concurrency_used` | gauge | Number of in-use chat concurrency slots |
-| `rho_daemon_uptime_seconds` | gauge | Daemon uptime in seconds |
+| `decoder_daemon_active_sessions` | gauge | Number of active daemon sessions |
+| `decoder_daemon_chat_concurrency_used` | gauge | Number of in-use chat concurrency slots |
+| `decoder_daemon_uptime_seconds` | gauge | Daemon uptime in seconds |
| `http_requests_total` | counter | Total HTTP requests received |
| `http_request_duration_ms` | histogram | HTTP request duration in milliseconds |
| `http_rate_limited_total` | counter | Number of requests rejected by rate limiter |
@@ -70,9 +70,9 @@ text format.
Telemetry is **opt-in**. Enable it by setting:
```bash
-export RHO_ENABLE_TELEMETRY=1
+export DECODER_ENABLE_TELEMETRY=1
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
-rho daemon start
+decoder daemon start
```
The daemon will automatically:
@@ -80,31 +80,31 @@ The daemon will automatically:
- Initialize the OTel SDK with a batch span processor (5s batch interval).
- Export traces to the OTLP endpoint (`OTEL_EXPORTER_OTLP_ENDPOINT`).
- Send trace headers from `OTEL_EXPORTER_OTLP_HEADERS`.
-- Set the service name (default: `rho`) and version.
+- Set the service name (default: `decoder`) and version.
### Configuration
| Environment Variable | Default | Description |
|---------------------|---------|-------------|
-| `RHO_ENABLE_TELEMETRY` | `0` | Set to `1` to enable OTP telemetry |
+| `DECODER_ENABLE_TELEMETRY` | `0` | Set to `1` to enable OTP telemetry |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | _(empty)_ | OTLP collector endpoint |
| `OTEL_EXPORTER_OTLP_PROTOCOL` | `http/protobuf` | OTLP transport protocol |
| `OTEL_EXPORTER_OTLP_HEADERS` | _(empty)_ | Comma-separated `key=value` headers |
-| `RHO_OTEL_SHUTDOWN_TIMEOUT_MS` | `2000` | Shutdown timeout in milliseconds |
+| `DECODER_OTEL_SHUTDOWN_TIMEOUT_MS` | `2000` | Shutdown timeout in milliseconds |
### OTel Conventions
-rho follows the OpenTelemetry semantic conventions for traces. See
+decoder follows the OpenTelemetry semantic conventions for traces. See
[docs/OTEL-CONVENTIONS.md](OTEL-CONVENTIONS.md) for span naming and attribute
details.
## 4. Structured Logging
-The daemon writes structured SLOG logs to `~/.rho/state/daemon.log` by
+The daemon writes structured SLOG logs to `~/.decoder/state/daemon.log` by
default. Control the log level via:
```bash
-rho daemon start --log-level DEBUG
+decoder daemon start --log-level DEBUG
```
Or via environment variable:
@@ -127,13 +127,13 @@ All daemon log entries include:
### Audit log
Security-relevant events (auth failures, tool executions) are written to a
-tamper-evident log at `~/.rho/state/securitylog/security_events.jsonl`.
+tamper-evident log at `~/.decoder/state/securitylog/security_events.jsonl`.
Verify the audit log integrity:
```bash
# The securitylog package provides a verify command
-go run ./cmd/rho securitylog verify
+go run ./cmd/decoder securitylog verify
```
## 5. Prometheus Scraping
@@ -144,14 +144,14 @@ go run ./cmd/rho securitylog verify
apiVersion: v1
kind: Service
metadata:
- name: rho-daemon
+ name: decoder-daemon
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "4590"
prometheus.io/path: "/v1/metrics"
spec:
selector:
- app: rho-daemon
+ app: decoder-daemon
ports:
- port: 4590
targetPort: 4590
@@ -159,18 +159,18 @@ spec:
apiVersion: apps/v1
kind: Deployment
metadata:
- name: rho-daemon
+ name: decoder-daemon
spec:
template:
spec:
containers:
- - name: rho
- image: ghcr.io/graycodeai/rho-daemon:latest
+ - name: decoder
+ image: ghcr.io/graycodeai/decoder-daemon:latest
env:
- - name: RHO_DAEMON_API_KEY
+ - name: DECODER_DAEMON_API_KEY
valueFrom:
secretKeyRef:
- name: rho-secret
+ name: decoder-secret
key: api-key
ports:
- containerPort: 4590
@@ -192,26 +192,26 @@ spec:
| Alert | Condition | Severity |
|-------|-----------|----------|
-| Daemon down | `rho_daemon_uptime_seconds` does not increase for 2+ minutes | critical |
+| Daemon down | `decoder_daemon_uptime_seconds` does not increase for 2+ minutes | critical |
| High request latency | `histogram_quantile(0.95, http_request_duration_ms)` > 10000ms for 5 minutes | warning |
| Rate limit saturation | `rate(http_rate_limited_total[5m])` > 10/s | warning |
| Auth failures | `rate(auth_denied_total[5m])` > 5/s | critical (possible brute force) |
-| High concurrency | `rho_daemon_chat_concurrency_used` sustained at max for 5+ minutes | warning |
-| No active sessions | `rho_daemon_active_sessions` = 0 during business hours | warning |
+| High concurrency | `decoder_daemon_chat_concurrency_used` sustained at max for 5+ minutes | warning |
+| No active sessions | `decoder_daemon_active_sessions` = 0 during business hours | warning |
## 7. Systemd Logging
When running under systemd, logs from stderr/stdout are captured by journald:
```bash
-journalctl -u rho-daemon -f
+journalctl -u decoder-daemon -f
```
The daemon also writes its own structured log to
-`~/.rho/state/daemon.log`:
+`~/.decoder/state/daemon.log`:
```bash
-tail -f ~/.rho/state/daemon.log
+tail -f ~/.decoder/state/daemon.log
```
## 8. Feature Flags
@@ -220,7 +220,7 @@ Feature flags allow runtime configuration without restarts. They are
controlled via environment variables:
```bash
-export RHO_FEATURE_=1
+export DECODER_FEATURE_=1
```
| Flag | Default | Description |
@@ -234,5 +234,5 @@ export RHO_FEATURE_=1
List all registered flags:
```bash
-rho features
+decoder features
```
diff --git a/docs/operations-checklist.md b/docs/operations-checklist.md
index c979c7089..5d9c931ac 100644
--- a/docs/operations-checklist.md
+++ b/docs/operations-checklist.md
@@ -1,22 +1,22 @@
# Production Operations Checklist
-Use this checklist when deploying or upgrading rho in a production
+Use this checklist when deploying or upgrading decoder in a production
environment. Each item links to the relevant configuration option or
documentation section.
## Pre-Deployment
-- [ ] **API key is set** — `RHO_DAEMON_API_KEY` environment variable is
+- [ ] **API key is set** — `DECODER_DAEMON_API_KEY` environment variable is
configured to a cryptographically random value (≥ 32 bytes). Do **not**
rely on the auto-generated key for production.
```bash
- export RHO_DAEMON_API_KEY=$(openssl rand -base64 32)
+ export DECODER_DAEMON_API_KEY=$(openssl rand -base64 32)
```
- [ ] **Bind address** — Daemon binds to `0.0.0.0` (not just loopback) only
when remote access is needed. A non-loopback bind requires an API key and
native TLS; otherwise startup fails closed.
- [ ] **TLS configured** — Enable native TLS with `--tls-cert` / `--tls-key`
- flags. If a reverse proxy terminates TLS, keep Rho bound to loopback or
+ flags. If a reverse proxy terminates TLS, keep Decoder bound to loopback or
an internal-only interface and restrict that network path at the firewall;
the daemon does not treat `X-Forwarded-Proto` as transport encryption.
- [ ] **CORS configured** — If serving browser-based clients, set
@@ -24,14 +24,14 @@ documentation section.
trusted origins only. Use `--cors '*'` only for development.
- [ ] **Rate limits reviewed** — Default: 10 req/min for general API, 30 req/min
for chat, 4 concurrent chat sessions. Tune via
- `RHO_DAEMON_MAX_CONCURRENT`.
+ `DECODER_DAEMON_MAX_CONCURRENT`.
- [ ] **Resource limits set** — Configure CPU/memory limits in systemd
(`MemoryMax`, `CPUQuota`) or Kubernetes. Defaults in the systemd unit file:
`MemoryMax=4G`, `CPUQuota=200%`.
-- [ ] **Log retention** — Daemon logs at `~/.rho/state/daemon.log`.
+- [ ] **Log retention** — Daemon logs at `~/.decoder/state/daemon.log`.
Configure log rotation (logrotate, journald retention) to prevent disk
exhaustion.
-- [ ] **State directory backed up** — The `~/.rho/state/` directory contains
+- [ ] **State directory backed up** — The `~/.decoder/state/` directory contains
the PID file, API key pin file, audit log, and session state. Back up the
audit log key (`securitylog/sel.key`) — **losing it makes all historical
audit entries unverifiable**.
@@ -40,17 +40,17 @@ documentation section.
## Observability
-- [ ] **Telemetry enabled (optional)** — Set `RHO_ENABLE_TELEMETRY=1`
+- [ ] **Telemetry enabled (optional)** — Set `DECODER_ENABLE_TELEMETRY=1`
and configure `OTEL_EXPORTER_OTLP_ENDPOINT` to send traces to your OTLP
collector. Telemetry is opt-in by default.
- [ ] **Prometheus scraping** — If using Prometheus, configure a scrape
target for `http://:4590/v1/metrics` with authentication:
```yaml
scrape_configs:
- - job_name: 'rho-daemon'
- bearer_token: ''
+ - job_name: 'decoder-daemon'
+ bearer_token: ''
static_configs:
- - targets: ['rho-daemon:4590']
+ - targets: ['decoder-daemon:4590']
metrics_path: '/v1/metrics'
```
- [ ] **Health/readiness probes** — Configure in your orchestrator:
@@ -62,24 +62,24 @@ documentation section.
## Security Hardening
- [ ] **API key rotated** — The API key is written to a pinned file at
- `~/.rho/state/daemon.key` for convenience. **Remove this file in
+ `~/.decoder/state/daemon.key` for convenience. **Remove this file in
production** or ensure it has `0600` permissions and is not world-readable.
- [ ] **Audit log verification** — Periodically verify the audit log
integrity:
```bash
# The Verify function checks the HMAC chain
- go run ./cmd/rho securitylog verify
+ go run ./cmd/decoder securitylog verify
```
- [ ] **Security headers** — Verify `X-Content-Type-Options`,
`X-Frame-Options`, and `Content-Security-Policy` headers are present
(enabled by default via the `security-headers` feature flag).
-- [x] **Execution model** — Rho runs tools directly on the host under its
+- [x] **Execution model** — Decoder runs tools directly on the host under its
permission, path-safety, trust, and worktree controls. Docker/Podman is not
required and is not an execution backend for the CLI.
- [ ] **No CGO** — The binary is built with `CGO_ENABLED=0` for a static binary.
Verify the deployed binary has no dynamic library dependencies:
```bash
- ldd /usr/local/bin/rho # should say "not a dynamic executable"
+ ldd /usr/local/bin/decoder # should say "not a dynamic executable"
```
## Post-Deployment
@@ -97,7 +97,7 @@ documentation section.
```
- [ ] **Metrics test** — Verify the metrics endpoint:
```bash
- curl -H "X-API-Key: $RHO_DAEMON_API_KEY" http://localhost:4590/v1/metrics
+ curl -H "X-API-Key: $DECODER_DAEMON_API_KEY" http://localhost:4590/v1/metrics
```
- [ ] **Version check** — Verify the deployed version matches expectations:
```bash
@@ -106,10 +106,10 @@ documentation section.
## Upgrade Procedure
-1. **Back up state** — Copy `~/.rho/state/` to a safe location.
+1. **Back up state** — Copy `~/.decoder/state/` to a safe location.
2. **Drain traffic** — Remove the daemon from load balancer rotation or
stop sending new requests.
-3. **Install new binary** — Replace the binary and run `rho daemon start`
+3. **Install new binary** — Replace the binary and run `decoder daemon start`
with the same configuration.
4. **Verify health** — Check `GET /v1/health` and `GET /v1/ready`.
5. **Verify metrics** — Check `GET /v1/metrics` for expected counters.
diff --git a/docs/plans/FULL-GROK-ECO-TO-RHO-ECO-PORT-PLAN.md b/docs/plans/FULL-GROK-ECO-TO-DECODER-ECO-PORT-PLAN.md
similarity index 74%
rename from docs/plans/FULL-GROK-ECO-TO-RHO-ECO-PORT-PLAN.md
rename to docs/plans/FULL-GROK-ECO-TO-DECODER-ECO-PORT-PLAN.md
index bb04c0333..ccea97bcc 100644
--- a/docs/plans/FULL-GROK-ECO-TO-RHO-ECO-PORT-PLAN.md
+++ b/docs/plans/FULL-GROK-ECO-TO-DECODER-ECO-PORT-PLAN.md
@@ -5,7 +5,7 @@
**Active execution:** [YEAR-0-ACTIVE.md](./YEAR-0-ACTIVE.md) (Year 0 control-plane track)
**ADR:** [ADR-0003](../architecture/adr/ADR-0003-grok-behavioral-port-go-multirepo.md)
**Meaning of “port”:** Reimplement **every Grok Build capability** in idiomatic **Go** across graycode-eco repos.
-**Not meaning:** Copy Rust crates, depend on Grok binaries, or collapse rho into a Rust monorepo.
+**Not meaning:** Copy Rust crates, depend on Grok binaries, or collapse decoder into a Rust monorepo.
**Source tree:** `grok-eco/grok-build` (~1.35M LOC Rust, 1 product monorepo)
**Target tree:** `graycode-eco/*` (multi-repo Go platform + cloud/TS/Python)
@@ -18,10 +18,10 @@
## 0. Port principles
1. **Behavior parity over code structure** — same user-visible contracts, not same file tree.
-2. **Go multi-repo stays** — map Grok crates into rho / engines / contracts / cloud / skills.
-3. **Prefer wire-first** — Rho already has partial types; complete wiring before greenfield.
+2. **Go multi-repo stays** — map Grok crates into decoder / engines / contracts / cloud / skills.
+3. **Prefer wire-first** — Decoder already has partial types; complete wiring before greenfield.
4. **Privacy-first defaults** — Grok Mixpanel/Sentry defaults become **opt-in** OTEL/privacy-safe telemetry.
-5. **Multi-provider stays** — Grok sampler/auth maps to **flux**, not a single-vendor clone.
+5. **Multi-provider stays** — Grok sampler/auth maps to **mux**, not a single-vendor clone.
6. **Memory stays harrier** — Grok markdown memory maps to **harrier APIs + UX**, not a second store.
7. **Tokens stay shrike** — Grok `xai-token-estimation` is obsolete relative to shrike.
8. **Track everything** — even 70-line crates appear in the matrix (Done / Partial / Port / Skip / N/A).
@@ -67,9 +67,9 @@ Critical path remains **months**; **complete parity** including TUI polish and e
```text
grok-eco/grok-build (one Rust workspace)
│
- ├─► rho product CLI/TUI/engine/tools/hooks/plugins/ACP
+ ├─► decoder product CLI/TUI/engine/tools/hooks/plugins/ACP
├─► eagle pure DTOs (tool/spawn/hooks/policy)
- ├─► flux LLM routing/stream/retry/catalog/auth credentials
+ ├─► mux LLM routing/stream/retry/catalog/auth credentials
├─► harrier memory graph + dream UX
├─► shrike compression / secrets / token cost
├─► swift session capture/import/replay
@@ -92,87 +92,87 @@ grok-eco/grok-build (one Rust workspace)
| Grok crate | ~LOC | Capability | Target repo | Status | Effort | Notes |
|------------|-----:|------------|-------------|--------|--------|-------|
-| `xai-grok-pager` | 415k | Full TUI | rho `cmd/` | Partial | XXL | Bubble Tea already; parity of panes/modals/slash is multi-year |
-| `xai-grok-pager-render` | 35k | Render pipeline | rho | Partial | L | Streaming render, blocks, media |
-| `xai-grok-pager-minimal` | 5.6k | `--minimal` native scrollback | rho | Partial | M | `rho --repl` / print modes exist |
-| `xai-grok-pager-bin` | 2.9k | Binary composition root | rho `cmd/rho` | Done | — | |
-| `xai-grok-pager-pty-harness` | 10k | PTY test harness | rho tests | Partial | M | Test infra |
-| `xai-grok-shell` | 336k | Agent runtime host | rho `internal/engine` | Partial | XXL | Largest runtime port |
-| `xai-grok-shell-base` | 2.7k | Shared shell foundation | rho | Partial | S | Absorb |
-| `xai-grok-shell-session-support` | 1.5k | Session support extract | rho `session` | Partial | S | Absorb |
-| `xai-grok-tools` | 112k | Tool implementations | rho `internal/tool` | Partial | XL | See tool matrix §3 |
-| `xai-grok-tools-api` | 0.7k | Tool API / slash wording | rho + contracts | Partial | S | |
-| `xai-grok-workspace` | 77k | FS/VCS/permissions/hub | rho + sandbox + session | Partial | XL | |
+| `xai-grok-pager` | 415k | Full TUI | decoder `cmd/` | Partial | XXL | Bubble Tea already; parity of panes/modals/slash is multi-year |
+| `xai-grok-pager-render` | 35k | Render pipeline | decoder | Partial | L | Streaming render, blocks, media |
+| `xai-grok-pager-minimal` | 5.6k | `--minimal` native scrollback | decoder | Partial | M | `decoder --repl` / print modes exist |
+| `xai-grok-pager-bin` | 2.9k | Binary composition root | decoder `cmd/decoder` | Done | — | |
+| `xai-grok-pager-pty-harness` | 10k | PTY test harness | decoder tests | Partial | M | Test infra |
+| `xai-grok-shell` | 336k | Agent runtime host | decoder `internal/engine` | Partial | XXL | Largest runtime port |
+| `xai-grok-shell-base` | 2.7k | Shared shell foundation | decoder | Partial | S | Absorb |
+| `xai-grok-shell-session-support` | 1.5k | Session support extract | decoder `session` | Partial | S | Absorb |
+| `xai-grok-tools` | 112k | Tool implementations | decoder `internal/tool` | Partial | XL | See tool matrix §3 |
+| `xai-grok-tools-api` | 0.7k | Tool API / slash wording | decoder + contracts | Partial | S | |
+| `xai-grok-workspace` | 77k | FS/VCS/permissions/hub | decoder + sandbox + session | Partial | XL | |
| `xai-grok-workspace-types` | 9.2k | Workspace wire types | contracts | Partial | M | |
-| `xai-grok-workspace-client` | 0.8k | Workspace RPC client | rho (if hub) | Port | M | Only if computer-hub ported |
-| `xai-grok-agent` | 21k | Agent defs + system prompt | rho agent/personas | Partial | L | |
-| `xai-grok-subagent-resolution` | 2.6k | Capability/isolation resolve | rho + contracts | Port | M | Critical |
-| `xai-chat-state` | 13k | Chat state actor | rho session/engine | Partial | L | |
-| `xai-grok-markdown` | 22k | Streaming MD TUI | rho markdown | Partial | L | |
-| `xai-grok-markdown-core` | 1.1k | Headless MD analysis | rho | Partial | S | |
-| `xai-ratatui-textarea` | 12k | Input widget | rho (Bubble Tea) | N/A | — | Different UI stack |
-| `xai-ratatui-inline` | 3.7k | Inline render | rho | N/A | — | UI stack |
-| `xai-fast-worktree` | 19k | CoW worktree speed | rho worktree | Port | L | Perf enhancement |
-| `xai-file-utils` | 15k | Event tracking / upload | rho observability | Partial | M | Privacy opt-in |
-| `xai-grok-telemetry` | 14k | Events + OTEL + Mixpanel + Sentry | rho observability | Partial | L | **Skip Mixpanel default**; keep OTEL |
-| `xai-hunk-tracker` | 13k | Agent vs external hunks | rho | Port | L | |
-| `xai-grok-sampling-types` | 13k | Chat API types | **flux** | Done* | — | Different shape; flux owns |
-| `xai-grok-sampler` | 11k | HTTP stream + retry | **flux** | Done* | — | Do not replace flux |
-| `xai-grok-update` | 11k | Auto-update | rho | Partial | M | |
-| `xai-grok-mcp` | 10k | MCP client (oauth, wire) | rho `mcp` | Partial | L | |
-| `xai-codebase-graph` | 9.7k | Tree-sitter graph | rho codegraph/repomap | Partial | L | |
+| `xai-grok-workspace-client` | 0.8k | Workspace RPC client | decoder (if hub) | Port | M | Only if computer-hub ported |
+| `xai-grok-agent` | 21k | Agent defs + system prompt | decoder agent/personas | Partial | L | |
+| `xai-grok-subagent-resolution` | 2.6k | Capability/isolation resolve | decoder + contracts | Port | M | Critical |
+| `xai-chat-state` | 13k | Chat state actor | decoder session/engine | Partial | L | |
+| `xai-grok-markdown` | 22k | Streaming MD TUI | decoder markdown | Partial | L | |
+| `xai-grok-markdown-core` | 1.1k | Headless MD analysis | decoder | Partial | S | |
+| `xai-ratatui-textarea` | 12k | Input widget | decoder (Bubble Tea) | N/A | — | Different UI stack |
+| `xai-ratatui-inline` | 3.7k | Inline render | decoder | N/A | — | UI stack |
+| `xai-fast-worktree` | 19k | CoW worktree speed | decoder worktree | Port | L | Perf enhancement |
+| `xai-file-utils` | 15k | Event tracking / upload | decoder observability | Partial | M | Privacy opt-in |
+| `xai-grok-telemetry` | 14k | Events + OTEL + Mixpanel + Sentry | decoder observability | Partial | L | **Skip Mixpanel default**; keep OTEL |
+| `xai-hunk-tracker` | 13k | Agent vs external hunks | decoder | Port | L | |
+| `xai-grok-sampling-types` | 13k | Chat API types | **mux** | Done* | — | Different shape; mux owns |
+| `xai-grok-sampler` | 11k | HTTP stream + retry | **mux** | Done* | — | Do not replace mux |
+| `xai-grok-update` | 11k | Auto-update | decoder | Partial | M | |
+| `xai-grok-mcp` | 10k | MCP client (oauth, wire) | decoder `mcp` | Partial | L | |
+| `xai-codebase-graph` | 9.7k | Tree-sitter graph | decoder codegraph/repomap | Partial | L | |
| `xai-grok-memory` | 9.7k | Cross-session memory | **harrier** | Done* | M | Port UX only |
-| `xai-grok-hooks` | 8.3k | File/HTTP hooks | rho hooks | Port | L | |
-| `xai-fsnotify` | 6.7k | FS events | rho (fsnotify) | Partial | S | |
-| `xai-grok-config` | 6k | Config layers + managed | rho config + cloud | Port | L | |
+| `xai-grok-hooks` | 8.3k | File/HTTP hooks | decoder hooks | Port | L | |
+| `xai-fsnotify` | 6.7k | FS events | decoder (fsnotify) | Partial | S | |
+| `xai-grok-config` | 6k | Config layers + managed | decoder config + cloud | Port | L | |
| `xai-grok-config-types` | 2.7k | Config DTOs | contracts/config | Partial | S | |
-| `xai-grok-plugin-marketplace` | 5.3k | Marketplace | rho + community-skills | Port | L | |
-| `xai-grok-shared` | 5.2k | Shared utils | rho | N/A | — | Absorb |
-| `xai-grok-test-support` | 4.6k | Test harness | rho testutil | Partial | M | |
-| `xai-grok-sandbox` | 3.9k | OS sandbox profiles | rho host permissions | Port | L | |
-| `xai-grok-voice` | 2.7k | Streaming STT | rho | Partial | M | whisper path exists |
-| `xai-acp-lib` | 2.3k | ACP protocol | rho acp | Port | L | |
-| `xai-grok-mermaid` | 2.2k | Mermaid→PNG | rho | Port | M | |
-| `xai-crash-handler` | 1.9k | Crash + startup detect | rho | Port | S | |
-| `ptyctl` | 2.3k | Headless PTY control | rho | Port | M | |
-| `ptyctl-cli` | 0.8k | PTY CLI | rho tests/tools | Optional | S | |
-| `xai-tty-utils` | 1.2k | TTY-safe spawn | rho | Port | S | |
+| `xai-grok-plugin-marketplace` | 5.3k | Marketplace | decoder + community-skills | Port | L | |
+| `xai-grok-shared` | 5.2k | Shared utils | decoder | N/A | — | Absorb |
+| `xai-grok-test-support` | 4.6k | Test harness | decoder testutil | Partial | M | |
+| `xai-grok-sandbox` | 3.9k | OS sandbox profiles | decoder host permissions | Port | L | |
+| `xai-grok-voice` | 2.7k | Streaming STT | decoder | Partial | M | whisper path exists |
+| `xai-acp-lib` | 2.3k | ACP protocol | decoder acp | Port | L | |
+| `xai-grok-mermaid` | 2.2k | Mermaid→PNG | decoder | Port | M | |
+| `xai-crash-handler` | 1.9k | Crash + startup detect | decoder | Port | S | |
+| `ptyctl` | 2.3k | Headless PTY control | decoder | Port | M | |
+| `ptyctl-cli` | 0.8k | PTY CLI | decoder tests/tools | Optional | S | |
+| `xai-tty-utils` | 1.2k | TTY-safe spawn | decoder | Port | S | |
| `xai-hooks-plugins-types` | 1.2k | Hooks/plugins ACP DTOs | contracts | Port | S | |
-| `xai-sqlite-journal` | 0.8k | SQLite journal mode | rho/harrier/shrike | Partial | XS | |
-| `xai-system-power` | 0.7k | Sleep/wake notify | rho sleep_prevent | Partial | S | |
-| `xai-grok-http` | 0.6k | Shared HTTP client | rho/netutil | Partial | XS | |
-| `xai-agent-lifecycle` | 0.6k | Lifecycle hooks data | rho hooks/engine | Partial | S | |
-| `xai-gix-status` | 0.6k | Fast git status | rho git tools | Partial | S | |
-| `xai-grok-paths` | 0.6k | AbsPath types | rho | N/A | XS | Go path.Clean enough |
-| `xai-grok-secrets` | 0.6k | Secrets helpers | shrike + flux | Partial | S | |
-| `xai-grok-announcements` | 0.4k | Release announcements | rho tips/notify | Port | S | |
-| `xai-grok-auth` | 0.4k | Auth seam | flux + rho auth | Partial | M | Browser OAuth optional |
+| `xai-sqlite-journal` | 0.8k | SQLite journal mode | decoder/harrier/shrike | Partial | XS | |
+| `xai-system-power` | 0.7k | Sleep/wake notify | decoder sleep_prevent | Partial | S | |
+| `xai-grok-http` | 0.6k | Shared HTTP client | decoder/netutil | Partial | XS | |
+| `xai-agent-lifecycle` | 0.6k | Lifecycle hooks data | decoder hooks/engine | Partial | S | |
+| `xai-gix-status` | 0.6k | Fast git status | decoder git tools | Partial | S | |
+| `xai-grok-paths` | 0.6k | AbsPath types | decoder | N/A | XS | Go path.Clean enough |
+| `xai-grok-secrets` | 0.6k | Secrets helpers | shrike + mux | Partial | S | |
+| `xai-grok-announcements` | 0.4k | Release announcements | decoder tips/notify | Port | S | |
+| `xai-grok-auth` | 0.4k | Auth seam | mux + decoder auth | Partial | M | Browser OAuth optional |
| `xai-token-estimation` | 0.3k | Bytes/4 heuristic | **shrike** | Skip | — | shrike superior |
-| `xai-tracing-macros` | 0.2k | Log macros | rho observability | N/A | XS | |
-| `xai-grok-env` | 0.2k | Backend env presets | flux/rho | Partial | XS | |
-| `xai-prompt-queue` | 0.2k | Prompt queue types | rho | Port | S | |
+| `xai-tracing-macros` | 0.2k | Log macros | decoder observability | N/A | XS | |
+| `xai-grok-env` | 0.2k | Backend env presets | mux/decoder | Partial | XS | |
+| `xai-prompt-queue` | 0.2k | Prompt queue types | decoder | Port | S | |
| `xai-mixpanel` | 0.1k | Mixpanel client | — | **Skip** | — | Privacy; OTEL opt-in |
-| `xai-grok-version` | 0.1k | Version | rho VERSION | Done | — | |
-| `xai-grok-models` | 0.1k | Default model IDs | flux catalog | Done* | — | |
+| `xai-grok-version` | 0.1k | Version | decoder VERSION | Done | — | |
+| `xai-grok-models` | 0.1k | Default model IDs | mux catalog | Done* | — | |
### 2.2 Common crates (tool protocol / hub / compaction)
| Grok crate | ~LOC | Capability | Target | Status | Effort | Notes |
|------------|-----:|------------|--------|--------|--------|-------|
-| `xai-computer-hub-sdk` | 14k | Remote tool server SDK | new or rho | Port (Y2+) | XL | Only if multi-host tools wanted |
+| `xai-computer-hub-sdk` | 14k | Remote tool server SDK | new or decoder | Port (Y2+) | XL | Only if multi-host tools wanted |
| `xai-computer-hub-core` | 4.2k | Transport/registry | same | Port (Y2+) | L | |
| `xai-computer-hub-mcp-adapter` | 1k | MCP into hub | falcon | Port (Y2+) | M | |
-| `xai-tool-protocol` | 6.6k | Wire protocol | contracts + rho | Port (Y2) | L | |
-| `xai-tool-runtime` | 5.4k | Tool trait runtime | rho tool | Partial | L | |
+| `xai-tool-protocol` | 6.6k | Wire protocol | contracts + decoder | Port (Y2) | L | |
+| `xai-tool-runtime` | 5.4k | Tool trait runtime | decoder tool | Partial | L | |
| `xai-tool-types` | 3.6k | Spawn/task types | **contracts** | Port | M | **P0** |
-| `xai-grok-compaction` | 6.8k | Compaction engine | rho engine + shrike | Partial | L | |
-| `xai-circuit-breaker` | 2.2k | HTTP breaker | flux/resilience | Partial | S | |
-| `xai-tracing` | 0.8k | Tracing | rho OTEL | Partial | S | |
-| `xai-test-utils` | 0.4k | Hermetic git tests | rho testutil | Partial | S | |
-| `xai-interjection-core` | 0.3k | Interjection messaging | rho | Port | S | Mid-turn user inject |
+| `xai-grok-compaction` | 6.8k | Compaction engine | decoder engine + shrike | Partial | L | |
+| `xai-circuit-breaker` | 2.2k | HTTP breaker | mux/resilience | Partial | S | |
+| `xai-tracing` | 0.8k | Tracing | decoder OTEL | Partial | S | |
+| `xai-test-utils` | 0.4k | Hermetic git tests | decoder testutil | Partial | S | |
+| `xai-interjection-core` | 0.3k | Interjection messaging | decoder | Port | S | Mid-turn user inject |
| `xai-proto-build` | — | Build tooling | — | Skip | — | Rust build |
-\*Done* = domain covered by rho engine with different API.
+\*Done* = domain covered by decoder engine with different API.
---
@@ -180,7 +180,7 @@ grok-eco/grok-build (one Rust workspace)
### 3.1 Grok Build native tools
-| Grok tool | Rho equivalent | Status | Port work |
+| Grok tool | Decoder equivalent | Status | Port work |
|-----------|-----------------|--------|-----------|
| `bash` / `run_terminal_command` | `Bash` | Partial | background flag, timeout, safe-bash, kill |
| `read_file` | `Read` | Partial | media/PDF page ranges parity |
@@ -210,20 +210,20 @@ grok-eco/grok-build (one Rust workspace)
Grok vendors codex/opencode tool implementations for compatibility profiles.
-| Compat surface | Rho | Action |
+| Compat surface | Decoder | Action |
|----------------|------|--------|
-| Codex apply_patch / read / list / grep | rho tools | Optional compat profile |
-| OpenCode read/write/edit/bash/glob/grep/todo/skill | rho | Optional `compat.opencode` |
-| Claude import | missing | **Port** into swift/rho |
+| Codex apply_patch / read / list / grep | decoder tools | Optional compat profile |
+| OpenCode read/write/edit/bash/glob/grep/todo/skill | decoder | Optional `compat.opencode` |
+| Claude import | missing | **Port** into swift/decoder |
| Cursor skills scan | missing | **Port** |
---
## 4. Slash commands & UX (pager)
-Grok slash modules (port checklist → rho `/` commands or CLI):
+Grok slash modules (port checklist → decoder `/` commands or CLI):
-| Grok slash | Status in rho | Action |
+| Grok slash | Status in decoder | Action |
|------------|----------------|--------|
| help | Partial | Port completeness |
| model / effort | Partial | Port effort levels |
@@ -259,17 +259,17 @@ Grok slash modules (port checklist → rho `/` commands or CLI):
---
-## 5. User-guide docs (port as rho user-guide)
+## 5. User-guide docs (port as decoder user-guide)
| Grok doc | Port to |
|----------|---------|
-| 01–05 essentials | `rho/docs/user-guide/` |
+| 01–05 essentials | `decoder/docs/user-guide/` |
| 06 theming | same |
| 07 MCP | same + mcp-servers.md merge |
| 08 skills | same |
| 09 plugins | same |
| 10 hooks | same |
-| 11 custom models | flux + rho |
+| 11 custom models | mux + decoder |
| 12 project rules AGENTS.md | exists Partial |
| 13 memory | harrier UX |
| 14 headless | CLI flags doc |
@@ -292,7 +292,7 @@ Grok slash modules (port checklist → rho `/` commands or CLI):
These are “small” crates/modules but required for **full** port claims:
-| Item | Grok home | Rho action | Effort |
+| Item | Grok home | Decoder action | Effort |
|------|-----------|-------------|--------|
| Folder trust | `workspace/folder_trust.rs` | **Port** `internal/trust` | M |
| envrc / direnv load | `workspace/envrc.rs` | **Port** | S |
@@ -332,7 +332,7 @@ These are “small” crates/modules but required for **full** port claims:
| Hyperlink routing | pager | Port | S |
| Config TOML live edit | pager | Port | S |
| Goal classifier | shell session | Port | S |
-| Swift classifier | shell | map to rho swift | S |
+| Swift classifier | shell | map to decoder swift | S |
| Repo changes tracking | shell session | Partial | M |
| Active sessions multi | shell | Partial | M |
| MCP doctor | shell mcp_doctor | Port | S |
@@ -349,10 +349,10 @@ These are “small” crates/modules but required for **full** port claims:
| Quarter | Deliverables | Repos |
|---------|--------------|-------|
-| **Q1** | Contracts spawn DTOs; wire explore/plan/general; stop hardcoded explore; explore bash hard gate; unify taskruntime; structured SpawnResult | contracts, rho |
-| **Q2** | sandbox.toml; folder trust; safe-bash; permission pipeline hooks-first; PreToolUse deny | rho |
-| **Q3** | File+HTTP hooks; vendor aliases; multi-harness skills; multi-component plugins; marketplace MVP | rho, community-skills |
-| **Q4** | Monitor/Wait/Kill; /loop; structured AskUser; plan/spec alignment; user-guide 01–12; crash handler; announcements; prompt queue; interjection | rho |
+| **Q1** | Contracts spawn DTOs; wire explore/plan/general; stop hardcoded explore; explore bash hard gate; unify taskruntime; structured SpawnResult | contracts, decoder |
+| **Q2** | sandbox.toml; folder trust; safe-bash; permission pipeline hooks-first; PreToolUse deny | decoder |
+| **Q3** | File+HTTP hooks; vendor aliases; multi-harness skills; multi-component plugins; marketplace MVP | decoder, community-skills |
+| **Q4** | Monitor/Wait/Kill; /loop; structured AskUser; plan/spec alignment; user-guide 01–12; crash handler; announcements; prompt queue; interjection | decoder |
**Exit Year 0:** Contributor-ready “Grok-class agent controls” without claiming full TUI parity.
@@ -361,7 +361,7 @@ These are “small” crates/modules but required for **full** port claims:
| Quarter | Deliverables |
|---------|--------------|
| **Q5** | ACP session/load/resume; richer updates; OpenAPI; sdk-go/python fields |
-| **Q6** | Managed policy (signed) graycode-cloud → rho; IT tier; config layer order |
+| **Q6** | Managed policy (signed) graycode-cloud → decoder; IT tier; config layer order |
| **Q7** | Foreign session import (Claude/Codex); envrc; hunk tracker; fast worktree; mermaid render |
| **Q8** | Voice streaming upgrade; update checker parity; MCP doctor; slash parity batch 1; user-guide 13–24 |
@@ -378,7 +378,7 @@ These are “small” crates/modules but required for **full** port claims:
### Year 3–5 — Continuous parity
-- Diff audit bot: scan Grok public releases → open rho issues
+- Diff audit bot: scan Grok public releases → open decoder issues
- Enterprise: MDM, SCIM (cloud), fleet policies
- Full editor suite (VS Code/Zed via ACP)
- Hardening, fuzz, SLSA releases
@@ -406,11 +406,11 @@ Each pack is a shippable program of work with Definition of Done.
- [ ] Tests for aliases and validation
- [ ] Version release
-**DoD:** rho can import types; no engine deps.
+**DoD:** decoder can import types; no engine deps.
### PACK-02: Spawn control plane (6–8 weeks)
-**Repo:** `rho`
+**Repo:** `decoder`
- [ ] Change `AgentSpawnFn` to SpawnRequest/Result
- [ ] Agent tool full schema (type, capability, isolation, resume, cwd, model, thoroughness, description, background)
@@ -440,7 +440,7 @@ Each pack is a shippable program of work with Definition of Done.
- [ ] File discovery paths
- [ ] HTTP runner
- [ ] Inject into PermissionEngine before autonomy
-- [ ] Plugin env RHO_PLUGIN_ROOT/DATA
+- [ ] Plugin env DECODER_PLUGIN_ROOT/DATA
### PACK-05: Extensions (8–10 weeks)
@@ -484,7 +484,7 @@ Each pack is a shippable program of work with Definition of Done.
### PACK-10: Enterprise policy (6 weeks)
- [ ] Signed managed policy schema (cloud)
-- [ ] rho apply layers
+- [ ] decoder apply layers
- [ ] fail-open vs fail-closed
- [ ] IT non-excludable tier end-to-end
@@ -510,7 +510,7 @@ Each pack is a shippable program of work with Definition of Done.
### PACK-14: TUI parity program (ongoing XL)
-Track Grok pager features against rho Bubble Tea:
+Track Grok pager features against decoder Bubble Tea:
- [ ] Dashboard view parity
- [ ] Agents/personas modal
@@ -545,7 +545,7 @@ Only if product requires remote tool hosts:
## 9. Per graycode-eco repo full ownership checklist
-### `rho` (majority)
+### `decoder` (majority)
Port/finish: spawn, tools, sandbox, trust, hooks, plugins, marketplace client, TUI, ACP, headless, slash, taskruntime, hunks, mermaid, voice, crash, announcements, queue, interjection, plan, ask user, update, PTY harness, envrc, permissions pipeline, user-guide.
@@ -553,7 +553,7 @@ Port/finish: spawn, tools, sandbox, trust, hooks, plugins, marketplace client, T
Port: spawn/capability/isolation types, hook events, optional sandbox policy DTO, tool protocol types (later).
-### `flux`
+### `mux`
Absorb: sampling/stream/retry/circuit-breaker lessons; catalog already ahead; managed deployment hooks; **do not** become Grok-only auth.
@@ -571,7 +571,7 @@ Foreign session import; share/export; session indexing parity with Grok session
### `kestrel` / `merlin`
-No direct Grok crates; keep peer engines; ensure rho composition matches Grok “review/merlin” product moments if any.
+No direct Grok crates; keep peer engines; ensure decoder composition matches Grok “review/merlin” product moments if any.
### `falcon`
@@ -605,10 +605,10 @@ Dashboard/usage/marketplace web UI only.
| SpaceXAI-only browser auth as sole path | Multi-provider + keychain |
| `xai-token-estimation` | shrike wins |
| Replace harrier with markdown memory files | Graph better |
-| Replace flux with xai-grok-sampler | Multi-provider better |
+| Replace mux with xai-grok-sampler | Multi-provider better |
| ratatui widgets | Bubble Tea stack |
| `xai-proto-build` | Rust build |
-| Closed contribution policy | Rho is open |
+| Closed contribution policy | Decoder is open |
Skipping is **documented completion**, not unfinished work.
@@ -650,7 +650,7 @@ Declare complete when:
6. Folder trust + sandbox deny globs pass security tests on macOS+Linux.
7. Marketplace can install a multi-component plugin.
8. Subagent explore/plan/general + resume + worktree isolation work.
-9. No second memory/token/provider stack duplicated against harrier/shrike/flux.
+9. No second memory/token/provider stack duplicated against harrier/shrike/mux.
10. Continuous parity process (PACK-17) running for 2 releases.
---
@@ -692,7 +692,7 @@ Execute shorter plan as **Year 0** of this master plan.
## 16. One-line summary
-**Port all of grok-eco into graycode-eco = reimplement Grok Build’s full capability surface in Go across graycode-eco repos, map each crate to an owner engine, skip vendor/privacy conflicts, wire Rho’s existing partial systems first, and run a multi-year program ending in behavioral parity—not a Rust code transplant.**
+**Port all of grok-eco into graycode-eco = reimplement Grok Build’s full capability surface in Go across graycode-eco repos, map each crate to an owner engine, skip vendor/privacy conflicts, wire Decoder’s existing partial systems first, and run a multi-year program ending in behavioral parity—not a Rust code transplant.**
---
diff --git a/docs/plans/GROK-CLASS-CAPABILITY-LONG-HORIZON-PLAN.md b/docs/plans/GROK-CLASS-CAPABILITY-LONG-HORIZON-PLAN.md
index 0677beccc..f810e85fe 100644
--- a/docs/plans/GROK-CLASS-CAPABILITY-LONG-HORIZON-PLAN.md
+++ b/docs/plans/GROK-CLASS-CAPABILITY-LONG-HORIZON-PLAN.md
@@ -4,8 +4,8 @@
**Date:** 2026-07-16
**Horizon:** ~12–18 months (phased; can compress with parallel teams)
**Language:** Go only (no Rust ports; reimplement contracts and behavior)
-**Primary product:** `rho`
-**Supporting repositories:** `eagle`, `flux`, `harrier` (Harrier), `shrike` (Shrike), `swift` (Swift), `kestrel` (Kestrel), `merlin` (Merlin), `falcon`, `starling`, `sparrow`, `robin`, `wren`, `owl`, and `graycode-platform` (web/BFF/Rho Cloud; outside the Rho Go runtime graph)
+**Primary product:** `decoder`
+**Supporting repositories:** `eagle`, `mux`, `harrier` (Harrier), `shrike` (Shrike), `swift` (Swift), `kestrel` (Kestrel), `merlin` (Merlin), `falcon`, `starling`, `sparrow`, `robin`, `wren`, `owl`, and `graycode-platform` (web/BFF/Decoder Cloud; outside the Decoder Go runtime graph)
---
@@ -13,21 +13,21 @@
### Goal
-Bring Rho to **Grok-class agent control-plane quality** (typed subagents, sandbox profiles, folder trust, hooks, plugins/marketplace, ACP depth, monitor/scheduler, enterprise managed policy) **without** abandoning Rho’s multi-repo Go platform advantages (flux multi-provider, harrier graph memory, shrike compression, mission mode, contracts, cloud ledger).
+Bring Decoder to **Grok-class agent control-plane quality** (typed subagents, sandbox profiles, folder trust, hooks, plugins/marketplace, ACP depth, monitor/scheduler, enterprise managed policy) **without** abandoning Decoder’s multi-repo Go platform advantages (mux multi-provider, harrier graph memory, shrike compression, mission mode, contracts, cloud ledger).
### Non-goals
-- Rewrite Rho in Rust or monorepo-collapse engines into rho.
+- Rewrite Decoder in Rust or monorepo-collapse engines into decoder.
- Vendor lock-in to a single LLM host auth model.
-- Replace flux/harrier/shrike/swift with Grok-shaped internal crates.
+- Replace mux/harrier/shrike/swift with Grok-shaped internal crates.
- Default opt-in product telemetry that violates privacy-first posture.
### Strategy
-1. **Close wiring gaps first** — Rho already has many *types* and *partial systems* that are not exposed on the Agent tool or unified.
+1. **Close wiring gaps first** — Decoder already has many *types* and *partial systems* that are not exposed on the Agent tool or unified.
2. **Stabilize contracts** in `eagle` before multi-repo consumers.
3. **Ship vertical slices** (end-to-end user value) every quarter.
-4. **Keep engines peer-independent**; rho remains the only product orchestrator.
+4. **Keep engines peer-independent**; decoder remains the only product orchestrator.
---
@@ -110,7 +110,7 @@ This is the single highest-ROI fix: **wire what already exists**, then extend.
```text
┌──────────────────────────────┐
- │ rho TUI / CLI / daemon/ACP │
+ │ decoder TUI / CLI / daemon/ACP │
└──────────────┬───────────────┘
│
┌─────────────────────────┼─────────────────────────┐
@@ -130,10 +130,10 @@ This is the single highest-ROI fix: **wire what already exists**, then extend.
│
┌────┴────┬──────────┬──────────┬──────────┐
▼ ▼ ▼ ▼ ▼
- flux harrier shrike swift kestrel/merlin
+ mux harrier shrike swift kestrel/merlin
```
-**New core package (proposed):** `rho/internal/spawn` (or expand `engine/agent`) owning:
+**New core package (proposed):** `decoder/internal/spawn` (or expand `engine/agent`) owning:
- `SpawnRequest` / `SpawnResult` (Go structs aligned with contracts)
- capability filter, isolation worktree lifecycle
@@ -186,7 +186,7 @@ Legend: **Done** | **Partial** | **Missing** | **N/A (keep engine)**
| C2 | Vendor event aliases | Missing | Full |
| C3 | File-discovered hooks | Partial (in-process) | Full |
| C4 | HTTP hooks | Missing | Full |
-| C5 | Plugin env RHO_PLUGIN_ROOT/DATA | Missing | Full |
+| C5 | Plugin env DECODER_PLUGIN_ROOT/DATA | Missing | Full |
| C6 | PreToolUse can deny in CheckTool path | Missing | Full |
### Wave D — Plugins & marketplace (P3)
@@ -261,7 +261,7 @@ Legend: **Done** | **Partial** | **Missing** | **N/A (keep engine)**
## 4. Multi-quarter roadmap (long horizon)
-Assumes ~1–2 senior Go engineers on rho core + fractional engine/cloud; scale parallelizes quarters.
+Assumes ~1–2 senior Go engineers on decoder core + fractional engine/cloud; scale parallelizes quarters.
```text
Q1 Foundation: contracts + spawn wiring + background unify
@@ -370,13 +370,13 @@ type SpawnResult struct {
**Exit criteria**
-- `go test ./...` green; rho can depend on new pseudo-version without engine imports.
+- `go test ./...` green; decoder can depend on new pseudo-version without engine imports.
---
### Phase 2 — Spawn controller & Agent tool (4–6 weeks) ★ highest ROI
-**Repo:** `rho`
+**Repo:** `decoder`
**Packages:** `internal/engine/agent`, `internal/engine`, `internal/tool`
#### 2.1 Change `AgentSpawnFn` signature
@@ -403,8 +403,8 @@ Migration: temporary adapter for one release if needed; prefer single breaking c
| 2 | Map `subagent_type` → `SubAgentMode` (+ thoroughness) |
| 3 | Default capability from mode; allow override |
| 4 | Apply `FilterToolsForMode` **and** capability filter |
-| 5 | Isolation worktree: create under `.rho/worktrees/` using shared helper from mission worker |
-| 6 | Persist child session transcript under `~/.rho/subagents//` |
+| 5 | Isolation worktree: create under `.decoder/worktrees/` using shared helper from mission worker |
+| 6 | Persist child session transcript under `~/.decoder/subagents//` |
| 7 | `resume_from`: load transcript, append prompt, re-spawn with same type |
| 8 | Return structured `SpawnResult` JSON to model |
@@ -449,7 +449,7 @@ Deprecate:
#### 2.6 PR stack (Graphite-friendly)
-1. Contracts bump in rho
+1. Contracts bump in decoder
2. `SpawnRequest` internal + adapter
3. Agent tool schema + parse
4. Wire modes plan/general/explore
@@ -474,13 +474,13 @@ Deprecate:
### Phase 3 — Sandbox profiles + folder trust (4–5 weeks)
-**Repo:** `rho`
+**Repo:** `decoder`
**Packages:** `internal/sandbox`, `internal/trust` (new), `internal/mcp`, `internal/hooks`, `internal/plugin`
#### 3.1 sandbox.toml
```toml
-# ~/.rho/sandbox.toml
+# ~/.decoder/sandbox.toml
[profiles.ci]
extends = "strict"
restrict_network = true
@@ -490,7 +490,7 @@ deny = ["**/.env", "**/*.pem", "**/*credentials*"]
**Loader rules (security-critical):**
1. Load user global.
-2. Load project `.rho/sandbox.toml` **additive only** (new names only).
+2. Load project `.decoder/sandbox.toml` **additive only** (new names only).
3. Warn on conflicting redefinition; ignore project redefinition.
4. Deny globs applied on top of backend (seatbelt/landlock/bwrap-equivalent).
5. Fail closed when deny requested but OS cannot enforce.
@@ -508,7 +508,7 @@ deny = ["**/.env", "**/*.pem", "**/*credentials*"]
#### 3.3 Folder trust
-**Store:** `~/.rho/trusted_folders.toml`
+**Store:** `~/.decoder/trusted_folders.toml`
```toml
[[folders]]
@@ -538,7 +538,7 @@ trusted_at = "2026-07-16T00:00:00Z"
### Phase 4 — Hooks pipeline completion (3–4 weeks)
-**Repo:** `rho`
+**Repo:** `decoder`
**Package:** `internal/hooks`
#### 4.1 Event model expansion
@@ -550,7 +550,7 @@ Keep existing; alias map for Claude/Cursor names.
| Type | Behavior |
|------|----------|
-| command | shell with timeout, env RHO_* |
+| command | shell with timeout, env DECODER_* |
| http | POST JSON, timeout, optional deny on non-2xx for pre_tool |
#### 4.3 Integration into PermissionEngine
@@ -566,8 +566,8 @@ CheckTool:
#### 4.4 File discovery
-- `~/.rho/hooks/*.json`
-- `.rho/hooks/*.json` (trust required)
+- `~/.decoder/hooks/*.json`
+- `.decoder/hooks/*.json` (trust required)
- Compat: `.claude/settings.json` hooks, `.cursor/hooks.json` behind flags
**Exit criteria**
@@ -582,7 +582,7 @@ CheckTool:
### Phase 5 — Plugins multi-component + marketplace MVP (6–8 weeks)
-**Repos:** `rho`, `starling`
+**Repos:** `decoder`, `starling`
#### 5.1 Plugin layout (convention)
@@ -603,19 +603,19 @@ Loader merges components; tools optional.
1. Session meta / SDK
2. `--plugin-dir`
-3. Project `.rho/plugins` (trust)
-4. User `~/.rho/plugins`
+3. Project `.decoder/plugins` (trust)
+4. User `~/.decoder/plugins`
5. Config extra paths
#### 5.3 Marketplace
| Component | Owner |
|-----------|--------|
-| Source list config | rho |
-| Index schema | community-skills + rho |
-| Install resolve (git) | rho |
-| Audit | rho plugin malware_check (extend) |
-| CLI `rho plugins` / TUI tab | rho |
+| Source list config | decoder |
+| Index schema | community-skills + decoder |
+| Install resolve (git) | decoder |
+| Audit | decoder plugin malware_check (extend) |
+| CLI `decoder plugins` / TUI tab | decoder |
| Optional web gallery | graycode-platform later |
#### 5.4 Multi-harness skills
@@ -661,7 +661,7 @@ Depends on Phase 2 unified `taskruntime`.
| Work | Detail |
|------|--------|
-| Plan subagent | Default tool for “design only”; writes plan file under `.rho/plans/` or specs |
+| Plan subagent | Default tool for “design only”; writes plan file under `.decoder/plans/` or specs |
| Spec workflow | Document mapping: plan agent → `/spec` stages; avoid double systems |
| AskUserQuestion | questions[], options, multi_select, other, cancel message |
| TUI | Reuse autonomy/spec pickers |
@@ -677,7 +677,7 @@ Depends on Phase 2 unified `taskruntime`.
### Phase 8 — ACP phase-2 + SDKs + OpenAPI (5–7 weeks)
-**Repos:** `rho`, `sparrow`, `robin`
+**Repos:** `decoder`, `sparrow`, `robin`
| Milestone | Scope |
|-----------|--------|
@@ -686,11 +686,11 @@ Depends on Phase 2 unified `taskruntime`.
| ACP-3 | permission round-trip hardened |
| API | OpenAPI fields: spawn options, sandbox, autonomy, plugins meta |
| SDK | AgentConfig + ChatRequest fields; plugin dirs |
-| Optional | `rho agent serve --bind` WS |
+| Optional | `decoder agent serve --bind` WS |
**Exit criteria**
-- Zed/VS Code can drive rho ACP for multi-turn with permissions.
+- Zed/VS Code can drive decoder ACP for multi-turn with permissions.
- SDK e2e against daemon contract snapshot tests.
**Effort:** ~7 eng-weeks (+ extension work separate).
@@ -699,13 +699,13 @@ Depends on Phase 2 unified `taskruntime`.
### Phase 9 — Enterprise managed policy (4–6 weeks)
-**Repos:** `graycode-platform/apps/worker` (deployed as `graycode-cloud`), `rho`, optional `flux`
+**Repos:** `graycode-platform/apps/worker` (deployed as `graycode-cloud`), `decoder`, optional `mux`
| Piece | Detail |
|-------|--------|
| Policy document | models allow/deny, capabilities, sandbox deny, max budget, tool denylist |
-| Signing | Ed25519 envelope; rho verifies before apply |
-| Apply path | `~/.rho/managed_policy.json` layers under user config |
+| Signing | Ed25519 envelope; decoder verifies before apply |
+| Apply path | `~/.decoder/managed_policy.json` layers under user config |
| Default | fail-open for individual; org can require fail-closed |
| IT tier | non-excludable rules (already sketched in product — finish) |
| Cloud UI | graycode-platform admin later |
@@ -726,10 +726,10 @@ Build on existing enterprise policyInput (model/capability lists).
| Item | Repo | Detail |
|------|------|--------|
-| Foreign import | swift + rho CLI | Claude/Codex session metadata → index |
-| Hunk attribution | rho | agent vs external edits via fsnotify |
-| Memory UX | harrier + rho | toggle priority, `/dream` consolidate |
-| Mermaid optional | rho | sandbox render path |
+| Foreign import | swift + decoder CLI | Claude/Codex session metadata → index |
+| Hunk attribution | decoder | agent vs external edits via fsnotify |
+| Memory UX | harrier + decoder | toggle priority, `/dream` consolidate |
+| Mermaid optional | decoder | sandbox render path |
**Exit criteria**
@@ -756,20 +756,20 @@ Build on existing enterprise policyInput (model/capability lists).
| Concept family | Primary | Secondary | Contracts? |
|----------------|---------|-----------|------------|
-| Spawn / capability / isolation | rho | — | yes |
-| Sandbox profiles | rho | — | optional DTO |
-| Folder trust | rho | — | no |
-| Hooks | rho | — | event names yes |
-| Plugins / marketplace | rho | community-skills | manifest schema |
-| Multi-harness skills | rho | community-skills | no |
-| Monitor/tasks | rho | — | optional |
-| ACP | rho | sdk-go/python | OpenAPI |
-| Managed policy | graycode-platform/apps/worker (deployed as `graycode-cloud`) | rho, graycode-platform/apps/bff | yes DTO |
-| Foreign import | swift | rho | optional |
-| Memory dream UX | harrier | rho | no |
+| Spawn / capability / isolation | decoder | — | yes |
+| Sandbox profiles | decoder | — | optional DTO |
+| Folder trust | decoder | — | no |
+| Hooks | decoder | — | event names yes |
+| Plugins / marketplace | decoder | community-skills | manifest schema |
+| Multi-harness skills | decoder | community-skills | no |
+| Monitor/tasks | decoder | — | optional |
+| ACP | decoder | sdk-go/python | OpenAPI |
+| Managed policy | graycode-platform/apps/worker (deployed as `graycode-cloud`) | decoder, graycode-platform/apps/bff | yes DTO |
+| Foreign import | swift | decoder | optional |
+| Memory dream UX | harrier | decoder | no |
| Token | shrike | — | no change |
-| Providers | flux | rho | no change |
-| Review engines | kestrel/merlin | rho | findings already |
+| Providers | mux | decoder | no change |
+| Review engines | kestrel/merlin | decoder | findings already |
---
@@ -835,7 +835,7 @@ Prefer **secure defaults** (folder trust on) even if noisy.
| Risk | Impact | Mitigation |
|------|--------|------------|
-| Signature change of AgentSpawnFn breaks plugins | High | Adapter release; version min_rho |
+| Signature change of AgentSpawnFn breaks plugins | High | Adapter release; version min_decoder |
| Worktree disk bloat | Med | GC old worktrees; symlink shared dirs (already pattern) |
| Explore still escapes via Bash | High | AST allowlist + sandbox |
| Marketplace supply chain | High | audit, pin commit SHAs, signatures later |
@@ -886,7 +886,7 @@ docs(user-guide): 01-getting-started …
| Role | Q1–Q2 | Q3–Q4 | Q5–Q8 |
|------|-------|-------|-------|
-| Rho core (Go) | 1.5 FTE | 1.5 FTE | 1 FTE |
+| Decoder core (Go) | 1.5 FTE | 1.5 FTE | 1 FTE |
| Security-minded sandbox | 0.5 FTE | 0.5 FTE | 0.25 FTE |
| Community-skills / marketplace content | 0.25 | 0.75 | 0.5 |
| Cloud (TS) | 0 | 0.25 | 0.75 |
@@ -920,21 +920,21 @@ Background:
---
-## 14. Appendix B — Mapping Grok names → Rho names
+## 14. Appendix B — Mapping Grok names → Decoder names
-| Grok | Rho |
+| Grok | Decoder |
|------|------|
| `task` tool | `Agent` / `Task` alias |
| `general-purpose` | `general` / `general-purpose` |
| `capability_mode` | same |
| `isolation: worktree` | same |
| `resume_from` | same (replace weak `agent_id` semantics) |
-| `sandbox.toml` | `~/.rho/sandbox.toml` |
-| folder trust | `~/.rho/trusted_folders.toml` |
+| `sandbox.toml` | `~/.decoder/sandbox.toml` |
+| folder trust | `~/.decoder/trusted_folders.toml` |
| `/loop` | `/loop` over CronScheduler |
-| plugin marketplace | `rho plugins` + community registry |
+| plugin marketplace | `decoder plugins` + community registry |
| managed_config | managed policy via graycode-cloud |
-| ACP | `rho acp` |
+| ACP | `decoder acp` |
---
@@ -976,7 +976,7 @@ Week 4
| Trust default | On | Security |
| Marketplace before trust? | No | Supply chain |
| Replace harrier? | No | Graph memory superior |
-| Replace flux? | No | Multi-provider is differentiator |
+| Replace mux? | No | Multi-provider is differentiator |
| Three bg systems | Unify early | Blocks monitor/wait |
---
diff --git a/docs/plans/SPEC_DRIVEN_PHASE2_PLAN.md b/docs/plans/SPEC_DRIVEN_PHASE2_PLAN.md
index 29e1dffa3..a290602c6 100644
--- a/docs/plans/SPEC_DRIVEN_PHASE2_PLAN.md
+++ b/docs/plans/SPEC_DRIVEN_PHASE2_PLAN.md
@@ -69,7 +69,7 @@
**Changes:**
1. Create `internal/tool/spec_version.go` — SpecVersionTool
- - Stage .rho/specs/ changes
+ - Stage .decoder/specs/ changes
- Generate commit message referencing REQ IDs
- Link code commits to spec requirements
diff --git a/docs/plans/YEAR-0-ACTIVE.md b/docs/plans/YEAR-0-ACTIVE.md
index aaf9be48d..7f91cfb43 100644
--- a/docs/plans/YEAR-0-ACTIVE.md
+++ b/docs/plans/YEAR-0-ACTIVE.md
@@ -1,13 +1,13 @@
-# Year 0 Active Track (Grok → Rho)
+# Year 0 Active Track (Grok → Decoder)
> **Historical.** This track predates the removal of the harrier, kestrel,
-> merlin, shrike, and swift engines. Rho now depends only on `flux` and
+> merlin, shrike, and swift engines. Decoder now depends only on `mux` and
> embeds its own token engine. Kept for record.
**Status:** Superseded
**Date:** 2026-07-16
**ADR:** [ADR-0003](../architecture/adr/ADR-0003-grok-behavioral-port-go-multirepo.md)
-**Full matrices:** [FULL-GROK-ECO-TO-RHO-ECO-PORT-PLAN.md](./FULL-GROK-ECO-TO-RHO-ECO-PORT-PLAN.md),
+**Full matrices:** [FULL-GROK-ECO-TO-DECODER-ECO-PORT-PLAN.md](./FULL-GROK-ECO-TO-DECODER-ECO-PORT-PLAN.md),
[GROK-CLASS-CAPABILITY-LONG-HORIZON-PLAN.md](./GROK-CLASS-CAPABILITY-LONG-HORIZON-PLAN.md)
This is the **executable Year 0 program**. It does not replace the full
@@ -18,8 +18,8 @@ port matrices; it freezes what “Year 0 done” means and tracks pack status.
| Do | Do not |
|----|--------|
| Reimplement Grok **behavior** in Go | Copy Rust crates or depend on Grok |
-| Map capabilities to graycode-eco repos | Collapse engines into rho monorepo |
-| Wire existing modes/budgets first | Rebuild flux/harrier/shrike as Grok clones |
+| Map capabilities to graycode-eco repos | Collapse engines into decoder monorepo |
+| Wire existing modes/budgets first | Rebuild mux/harrier/shrike as Grok clones |
| Privacy-first telemetry (OTEL opt-in) | Port Mixpanel defaults |
## Pack status
@@ -42,13 +42,13 @@ port matrices; it freezes what “Year 0 done” means and tracks pack status.
- [x] Model can spawn `explore` \| `plan` \| `general-purpose` via Agent tool schema (isolation=worktree works; resume still stub)
- [x] Explore bash cannot mutate (`ExploreBashAllowed` segment allowlist + `ReadOnlyBash` on subagents)
- [x] Unified agent taskruntime (`internal/taskruntime`; shell TaskOutput merge is PACK-06)
-- [x] Folder trust gates project hooks / plugins (`.rho/plugins`, `.rho/hooks`; MCP/LSP follow same AllowLoadPath)
+- [x] Folder trust gates project hooks / plugins (`.decoder/plugins`, `.decoder/hooks`; MCP/LSP follow same AllowLoadPath)
- [x] `sandbox.toml` profiles + project additive merge; deny globs fail-closed
- [x] PreToolUse hooks can deny inside `PermissionEngine` before autonomy
- [x] Multi-component plugins + marketplace MVP install path
- [x] Monitor + Wait/Kill + `/loop` tools implemented and working
- [~] Crash handler, announcements, prompt queue, interjection — crash handler exists in cmd/errors.go; `/btw` (interjection) implemented; announcements and prompt queue still missing
-- [x] User-guide docs `01`–`24` under `rho/docs/user-guide/` (completed July 2026)
+- [x] User-guide docs `01`–`24` under `decoder/docs/user-guide/` (completed July 2026)
- [x] ADR-0003 published
- [x] PACK-00 inventory + flags + spawn matrix template complete
@@ -62,9 +62,9 @@ computer hub, full slash/TUI pixel parity, Mixpanel.
| Env | Default | Purpose |
|-----|---------|---------|
-| `RHO_Y0_SPAWN_V2` | `1` once PACK-02 ships; `0` during dual path | Typed SpawnRequest path |
-| `RHO_Y0_FOLDER_TRUST` | `1` recommended after PACK-03 | Gate project automation |
-| `RHO_Y0_MARKETPLACE` | `0` until PACK-05 + trust | Marketplace install path |
+| `DECODER_Y0_SPAWN_V2` | `1` once PACK-02 ships; `0` during dual path | Typed SpawnRequest path |
+| `DECODER_Y0_FOLDER_TRUST` | `1` recommended after PACK-03 | Gate project automation |
+| `DECODER_Y0_MARKETPLACE` | `0` until PACK-05 + trust | Marketplace install path |
Implementation: `internal/flags/y0.go`.
diff --git a/docs/plans/codex-adoption-plan.md b/docs/plans/codex-adoption-plan.md
index 66ad9a4ae..500522875 100644
--- a/docs/plans/codex-adoption-plan.md
+++ b/docs/plans/codex-adoption-plan.md
@@ -1,9 +1,9 @@
# OpenAI Codex CLI Adoption Plan
-Status: Audited. Core ideas already implemented natively in rho; remaining
+Status: Audited. Core ideas already implemented natively in decoder; remaining
deltas recorded as future RFCs.
-> **Superseded runtime assumptions (2026-09-20):** Rho no longer ships a
+> **Superseded runtime assumptions (2026-09-20):** Decoder no longer ships a
> native OS/container sandbox or a Docker execution backend. The permission
> engine, path guard, trust policy, and destructive-command hard blocks are
> the current local safety boundary. Sandbox rows below are historical design
@@ -14,9 +14,9 @@ Source: `https://github.com/openai/codex` (Apache-2.0, Rust workspace
## Executive Decision
-The audit found that every codex-rs capability relevant to rho's security and
+The audit found that every codex-rs capability relevant to decoder's security and
runtime model already has a native Go implementation, several of them deeper
-than codex's equivalents because they build on Rho's independent ecosystem
+than codex's equivalents because they build on Decoder's independent ecosystem
repositories.
No second runtime, sandbox layer, or policy engine was created.
@@ -27,18 +27,18 @@ Three codex ideas are deliberately deferred as future RFCs; see
## Capability Audit
-| codex-rs crate/concept | rho implementation | Decision |
+| codex-rs crate/concept | decoder implementation | Decision |
|---|---|---|
-| `core` agent loop | `internal/engine` | Keep rho |
-| `tui`, `ansi-escape`, `terminal-detection` | Bubble Tea/Lipgloss TUI | Keep rho |
-| `rollout`, `thread-store`, `history` JSONL sessions with resume/fork | `internal/session` JSONL + WAL + named checkpoints + fork + recovery + handover | Keep rho (richer) |
-| `app-server-daemon`, `app-server-protocol` (JSON-RPC for IDE/desktop) | `internal/daemon` HTTP/SSE on 4590 + `internal/acp` | Keep rho |
-| `mcp-server`, `codex-mcp`, `rmcp-client`, `connectors` | `internal/mcp` client+server, sibling `falcon` scaffolding | Keep rho |
-| `skills`, `plugin`, `hooks` | community skill registry + structural validator, plugins, expanded lifecycle hook events | Keep rho |
-| `login`, `keyring-store`, `aws-auth` | flux credential store in OS keychain across 28 providers | Keep rho (broader) |
-| `model-provider(-info)`, `models-manager`, `ollama`, `lmstudio` | sibling `flux` adapters, catalog, cascade routing | Keep rho (much broader) |
-| `memories`, `agent-graph-store`, `context-fragments` | sibling `harrier` (Harrier) graph memory; eventlog/graphjournal projections | Keep rho |
-| `apply-patch`, `file-search`, `file-watcher`, `git-utils` | edit tools, codegraph, git tooling, watcher hooks | Keep rho |
+| `core` agent loop | `internal/engine` | Keep decoder |
+| `tui`, `ansi-escape`, `terminal-detection` | Bubble Tea/Lipgloss TUI | Keep decoder |
+| `rollout`, `thread-store`, `history` JSONL sessions with resume/fork | `internal/session` JSONL + WAL + named checkpoints + fork + recovery + handover | Keep decoder (richer) |
+| `app-server-daemon`, `app-server-protocol` (JSON-RPC for IDE/desktop) | `internal/daemon` HTTP/SSE on 4590 + `internal/acp` | Keep decoder |
+| `mcp-server`, `codex-mcp`, `rmcp-client`, `connectors` | `internal/mcp` client+server, sibling `falcon` scaffolding | Keep decoder |
+| `skills`, `plugin`, `hooks` | community skill registry + structural validator, plugins, expanded lifecycle hook events | Keep decoder |
+| `login`, `keyring-store`, `aws-auth` | mux credential store in OS keychain across 28 providers | Keep decoder (broader) |
+| `model-provider(-info)`, `models-manager`, `ollama`, `lmstudio` | sibling `mux` adapters, catalog, cascade routing | Keep decoder (much broader) |
+| `memories`, `agent-graph-store`, `context-fragments` | sibling `harrier` (Harrier) graph memory; eventlog/graphjournal projections | Keep decoder |
+| `apply-patch`, `file-search`, `file-watcher`, `git-utils` | edit tools, codegraph, git tooling, watcher hooks | Keep decoder |
| `external-agent-migration` | swift reads Claude Code / Codex / Gemini CLI / OpenCode / Cursor sessions | Parity |
| **`linux-sandbox`** (Landlock + seccomp-bpf) | Removed from the local product runtime | Removed |
| **macOS Seatbelt** | Removed from the local product runtime | Removed |
@@ -68,19 +68,19 @@ Three codex ideas are deliberately deferred as future RFCs; see
the safe read-only fan-out case. Arbitrary-script execution still requires an
embedded runtime, capabilities model, and output-trust threat model; track as
a standalone RFC.
-- **Agent identity signing** (`agent-identity`): rho already provides a
+- **Agent identity signing** (`agent-identity`): decoder already provides a
per-harness anonymous user identity (`internal/identity`) and a tamper-evident
HMAC-chained security log with session-scoped events (`internal/securitylog`).
Signed subagent delegation chains are worth a focused design once multi-org
delegation exists.
- **Cloud tasks client** (`cloud-tasks*`): remote task queue integration.
- Rho Cloud already provides sync/review surfaces; a queue protocol would
+ Decoder Cloud already provides sync/review surfaces; a queue protocol would
duplicate that until a concrete consumer exists.
## Verification
- `go test ./...` full suite green.
-- `make vet`, `make lint`, `rho verify` green.
+- `make vet`, `make lint`, `decoder verify` green.
- Repo-owned markdown passes `markdownlint-cli2 '**/*.md'` (CI scope);
findings under sibling repositories belong to those repositories and follow
their own contribution flow.
diff --git a/docs/plans/commandcodeai-adoption-plan.md b/docs/plans/commandcodeai-adoption-plan.md
index 6f68896f1..15f5c5345 100644
--- a/docs/plans/commandcodeai-adoption-plan.md
+++ b/docs/plans/commandcodeai-adoption-plan.md
@@ -1,6 +1,6 @@
# CommandCodeAI Adoption Plan
-Status: Implemented in the Rho working tree where the existing architecture
+Status: Implemented in the Decoder working tree where the existing architecture
supports a safe, native implementation.
## Source Review
@@ -13,7 +13,7 @@ The reviewed CommandCodeAI organization contains four relevant categories:
| `cmd-old-public` | Archived placeholder/documentation repository | No implementation to adopt |
| `BaseAI` | Archived TypeScript pipe SDK/local provider server; licensing metadata is inconsistent | Reimplement narrow ideas only; do not add as a dependency |
| `agent-skills` | MIT skill collection with progressive-disclosure guidance | Adopt authoring/process ideas; preserve individual asset licenses |
-| `awesome-agents` | Apache-2.0 example applications | Reference only; do not merge into Rho skills |
+| `awesome-agents` | Apache-2.0 example applications | Reference only; do not merge into Decoder skills |
`starling` remains the canonical public skill registry. Its
validator and registry tooling are more complete than the CommandCodeAI
@@ -23,7 +23,7 @@ repositories and should remain authoritative.
### 5. Kimi Code workflow parity
-The Kimi Code comparison confirmed that Rho already provides native equivalents
+The Kimi Code comparison confirmed that Decoder already provides native equivalents
for most of its useful workflow ideas. The remaining gaps were addressed without
adding a second agent runtime:
@@ -34,20 +34,20 @@ adding a second agent runtime:
`UserPromptQueued`, `TurnStarted`, `PostToolFailure`, `PermissionResult`,
`SessionHeartbeat`, `TaskStarted`, `StopFailure`, `Interrupt`, and
`Notification`.
-- Rho's existing permission engine already supports ordered allow/deny rules
+- Decoder's existing permission engine already supports ordered allow/deny rules
such as `Bash(git status*)` and `Write(*.env)`, pre-tool denial hooks, scoped
policy snapshots, and destructive-command hard blocks.
-- Rho's existing goal tracker already provides durable objective state,
+- Decoder's existing goal tracker already provides durable objective state,
dependencies, progress, token budgets, continuation prompts, and lifecycle
events. A second `GOAL.md` state machine would duplicate this implementation.
The comparison also found no reason to adopt Kimi Code's two-engine split or
-replace Rho's stronger Harrier memory, Shrike token controls, Swift replay, Kestrel
-review, Merlin auditing, or Flux provider runtime.
+replace Decoder's stronger Harrier memory, Shrike token controls, Swift replay, Kestrel
+review, Merlin auditing, or Mux provider runtime.
### 1. Skill metadata interoperability
-Rho's smart-skill parser accepts both hyphenated and community-schema
+Decoder's smart-skill parser accepts both hyphenated and community-schema
snake_case keys:
- `auto-invoke` / `auto_invoke`
@@ -66,7 +66,7 @@ metadata.
### 2. Local skill validation
-Rho's existing Unicode audit remains the runtime security scanner. A new
+Decoder's existing Unicode audit remains the runtime security scanner. A new
structural validator complements it by checking:
- required `name` and `description`
@@ -77,13 +77,13 @@ structural validator complements it by checking:
- `SKILL.md` size
- `@ref(...)` path containment
-`rho skills audit` now reports both Unicode and structural findings. This is a
+`decoder skills audit` now reports both Unicode and structural findings. This is a
small Go-native subset of the community repository's broader validation model;
it does not duplicate the registry's Python implementation.
### 3. Transparent preference model
-Rho already has `internal/features/taste` with confidence, sample count,
+Decoder already has `internal/features/taste` with confidence, sample count,
decay, project identity, merge, reset, prompt projection, and accept/edit
signals. No second preference database was created. The user-facing model and
policy are documented in `docs/user-guide/26-learned-preferences.md`:
@@ -96,12 +96,12 @@ policy are documented in `docs/user-guide/26-learned-preferences.md`:
### 4. Workflow and harness documentation
-CommandCodeAI's strongest product contribution is discoverability. Rho now
+CommandCodeAI's strongest product contribution is discoverability. Decoder now
documents its existing capabilities in:
- `docs/user-guide/26-learned-preferences.md`
- `docs/user-guide/27-workflows.md`
-- `docs/architecture/rho-harness.md`
+- `docs/architecture/decoder-harness.md`
- `docs/user-guide/28-workflow-budgets.md`
These cover slash/shell/file-context input, headless review, MCP-backed
@@ -111,22 +111,22 @@ tool, depth, time, token, and cost budgets.
## Deliberately Not Adopted
-- CommandCodeAI provider adapters: Flux owns provider protocols and routing.
-- BaseAI remote pipes: incompatible with Rho's local authority and durable
+- CommandCodeAI provider adapters: Mux owns provider protocols and routing.
+- BaseAI remote pipes: incompatible with Decoder's local authority and durable
event model.
-- BaseAI `lowdb` JSON memory: weaker than Harrier and Rho persistence.
+- BaseAI `lowdb` JSON memory: weaker than Harrier and Decoder persistence.
- Unconditional parallel tool execution: unsafe for mutations and approvals.
- Historical `gpt3-agent`: no permissions, sandbox, path guard, audit, or tests.
-- Media/UI/status repositories: outside Rho's code-intelligence boundary.
+- Media/UI/status repositories: outside Decoder's code-intelligence boundary.
- CommandCodeAI branding, proprietary model claims, and undocumented services.
## Verification Plan
-1. Run formatting and static checks on all changed Rho Go files.
+1. Run formatting and static checks on all changed Decoder Go files.
2. Run focused parser, validator, taste, engine, and command tests.
-3. Run the full Rho test suite and vet.
+3. Run the full Decoder test suite and vet.
4. Repeat the focused and full checks independently.
5. Merlin the final diff, worktree, and sibling-repository status.
-The Flux repository remains a separate repository change and must be published
-through its own feature branch and PR before updating Rho's module pin.
+The Mux repository remains a separate repository change and must be published
+through its own feature branch and PR before updating Decoder's module pin.
diff --git a/docs/plans/competitive-gap-02-share-multisession.md b/docs/plans/competitive-gap-02-share-multisession.md
index 543c1b782..687eb0440 100644
--- a/docs/plans/competitive-gap-02-share-multisession.md
+++ b/docs/plans/competitive-gap-02-share-multisession.md
@@ -6,9 +6,9 @@ Source: field comparison vs OpenCode share-links/multi-session, herdr multiplexe
Constraint: developer-first, local by default, no cloud account required
(per `.github/ISSUE_TEMPLATE/feature_request.yml:60-63`).
-## Existing rho capabilities (verified)
+## Existing decoder capabilities (verified)
-- `GenerateShareLink` returns local deeplink `rho://share/` (`internal/session/export.go:801-819`); deterministic, no hosted URL.
+- `GenerateShareLink` returns local deeplink `decoder://share/` (`internal/session/export.go:801-819`); deterministic, no hosted URL.
- Session export (`session_export.go`), mission graph export (`cmd/execution_graph.go`, `mission-graph.json`), daemon sessions, `mission` worktrees.
- Completion list includes `exec`, `daemon`, `mission`, `sessions`, `tools`, `skills` (`cmd/completions_test.go:50`).
@@ -21,7 +21,7 @@ Do not adopt: hosted share URLs, cloud account,/Desktop app.
## Priority model
- P0: `sessions` list shows id/model/updated + export path; document `graph export` bundle as the share unit.
-- P1: TUI session picker surfaces the `rho://share/` deeplink + export file path for copy-paste.
+- P1: TUI session picker surfaces the `decoder://share/` deeplink + export file path for copy-paste.
- P2: Mission watchdog read-only overview (already in HUD panel) exposed via `mission --dry-run`/status; no new runtime.
## Steps
diff --git a/docs/plans/competitive-gap-03-kitty-graphics.md b/docs/plans/competitive-gap-03-kitty-graphics.md
index 6293be2f3..f53710212 100644
--- a/docs/plans/competitive-gap-03-kitty-graphics.md
+++ b/docs/plans/competitive-gap-03-kitty-graphics.md
@@ -3,7 +3,7 @@
Status: Implemented (2026-09-09)
Source: `https://github.com/kovidgoyal/kitty` (GPL-3.0; protocol only, no code copy), Ghostty compat; extends `docs/plans/pi-adoption-plan.md:25` (already proposed there — this file scopes the TUI work, it does not re-propose).
-## Existing rho capabilities (verified)
+## Existing decoder capabilities (verified)
- Vision input path: `internal/engine/vision.go`; image command: `cmd/image.go`.
- Terminal detection covers kitty/ghostty/wezterm/alacritty names (`internal/ui/icons/detect_test.go:56`).
diff --git a/docs/plans/competitive-gap-04-published-benchmarks.md b/docs/plans/competitive-gap-04-published-benchmarks.md
index 09ed2c9bb..526d81142 100644
--- a/docs/plans/competitive-gap-04-published-benchmarks.md
+++ b/docs/plans/competitive-gap-04-published-benchmarks.md
@@ -5,7 +5,7 @@ Source: field comparison vs ripgrep/fzf/alacritty (numbers in README), Aider Rep
Constraint: docs-only. No new benchmark framework; infra already exists.
-## Existing rho capabilities (verified)
+## Existing decoder capabilities (verified)
- `make bench` (`go test -bench=. -benchmem -count=3`) in `Makefile:100-101`.
- `internal/bench/suite.go` (eco suite runner + report formatter).
@@ -21,7 +21,7 @@ Do not adopt: new eval harness, SWE-bench claims, provider-funded comparisons.
## Priority model
- P0: fixed command + env (`make bench` subset: session save/load 100/1000, repomap size/tokens) recorded with machine + commit.
-- P1: `docs/BENCHMARKS.md` table (TUI-independent, no latency theater): session save/load, repomap tokens, tool-catalog size before/after `RHO_TOOL_SHRINK=1`.
+- P1: `docs/BENCHMARKS.md` table (TUI-independent, no latency theater): session save/load, repomap tokens, tool-catalog size before/after `DECODER_TOOL_SHRINK=1`.
- P2: CI artifact (optional): nightly `bench` JSON upload; never gate releases on it.
## Steps
diff --git a/docs/plans/competitive-gap-05-backend-wiring.md b/docs/plans/competitive-gap-05-backend-wiring.md
index 177ea64c2..1e741200e 100644
--- a/docs/plans/competitive-gap-05-backend-wiring.md
+++ b/docs/plans/competitive-gap-05-backend-wiring.md
@@ -5,11 +5,11 @@ Source: field comparison vs Qwen `computer_use`, Codex browser/screenshot, Goose
Constraints (non-negotiable):
-- Provider ownership lives in `../flux`; rho consumes only the stable engine facade (`AGENTS.md`, `docs/SECURITY-DEVELOPER.md:51-56`).
-- Boundary guards must stay green: `make boundaries` (incl. `flux-client-guard`, `flux-engine-guard`).
+- Provider ownership lives in `../mux`; decoder consumes only the stable engine facade (`AGENTS.md`, `docs/SECURITY-DEVELOPER.md:51-56`).
+- Boundary guards must stay green: `make boundaries` (incl. `mux-client-guard`, `mux-engine-guard`).
- Tools fail safe today with explicit errors when unwired — preserve that behavior when disabled.
-## Existing rho capabilities (verified)
+## Existing decoder capabilities (verified)
- `ComputerUseTool` reports "no computer backend installed" without `SetComputerBackend` (`internal/tool/computer_use.go:67-94`).
- `GenerateMediaTool` backend nil by default via `SetMediaEngine` (`internal/tool/media_generation.go:69-71`).
@@ -20,18 +20,18 @@ Constraints (non-negotiable):
Adopt: opt-in host wiring through the router facade, env-gated, off by default.
-Do not adopt: direct `flux/client` production imports, new secrets paths, always-on media/computer-use.
+Do not adopt: direct `mux/client` production imports, new secrets paths, always-on media/computer-use.
## Priority model
- P0: design note mapping each tool seam → facade method (media/image, STT/audio, computer backend) with guard-safe import path.
-- P1: env-gated wiring (e.g. `RHO_MEDIA=1`) + docs; unwired default error text unchanged.
-- P2: `rho doctor` reports backend status (wired/unwired) without leaking secrets.
+- P1: env-gated wiring (e.g. `DECODER_MEDIA=1`) + docs; unwired default error text unchanged.
+- P2: `decoder doctor` reports backend status (wired/unwired) without leaking secrets.
## Steps
-1. Confirm facade methods exist in sibling `../flux/engine`; if missing, file the change there first (router repo owns providers).
-2. Implement wiring in rho behind env gates; keep `Set*` seams for tests.
+1. Confirm facade methods exist in sibling `../mux/engine`; if missing, file the change there first (router repo owns providers).
+2. Implement wiring in decoder behind env gates; keep `Set*` seams for tests.
3. Run `make boundaries` + `make vet` + targeted `go test ./internal/tool/ -run 'TestComputer|TestMedia'`.
## Verification
diff --git a/docs/plans/rho-contracts-migration-backlog.md b/docs/plans/decoder-contracts-migration-backlog.md
similarity index 63%
rename from docs/plans/rho-contracts-migration-backlog.md
rename to docs/plans/decoder-contracts-migration-backlog.md
index 34cc8ff62..26c9295d0 100644
--- a/docs/plans/rho-contracts-migration-backlog.md
+++ b/docs/plans/decoder-contracts-migration-backlog.md
@@ -1,8 +1,8 @@
-# Plan: Rho Contracts Migration Backlog
+# Plan: Decoder Contracts Migration Backlog
> Status: locally complete
> Scope: graycode-eco ecosystem architecture cleanup after introducing `eagle`
-> Goal: keep `rho` as the product while moving stable cross-repo contracts out of Rho internals
+> Goal: keep `decoder` as the product while moving stable cross-repo contracts out of Decoder internals
External follow-up still outside the scope of this local workspace audit:
@@ -22,8 +22,8 @@ These items are already completed in the current workspace.
- added `eagle/types`
- moved severity and finding definitions into contracts
- migrated `kestrel` and `merlin` to import contracts
-- switched Rho `internal/types/severity.go` to re-export from contracts
-- removed `rho/shared/types` after local ecosystem migration
+- switched Decoder `internal/types/severity.go` to re-export from contracts
+- removed `decoder/shared/types` after local ecosystem migration
- removed the duplicate severity/finding definitions in `shrike/types` (shrike was the
original shared-types host)
- removed the `shrike/types` compatibility shim after verifying no in-workspace
@@ -31,15 +31,15 @@ These items are already completed in the current workspace.
### Tool contract migration
- added `eagle/tools`
-- switched Rho session persistence to provider-neutral tool contracts
+- switched Decoder session persistence to provider-neutral tool contracts
- added runtime/session conversion helpers
- added `eagle/tools/tool_test.go`
-- centralized message slice conversion in `rho/internal/session`
-- removed direct lower-level provider message reconstruction from Rho
+- centralized message slice conversion in `decoder/internal/session`
+- removed direct lower-level provider message reconstruction from Decoder
cmd/session restore paths
-- replaced the provider-owned message alias with a Rho-owned runtime DTO
-- added explicit Rho-owned runtime DTOs; the final boundary translates them
- through `flux/engine`
+- replaced the provider-owned message alias with a Decoder-owned runtime DTO
+- added explicit Decoder-owned runtime DTOs; the final boundary translates them
+ through `mux/engine`
### Event contract migration
- added `eagle/events`
@@ -56,14 +56,14 @@ These items are already completed in the current workspace.
### Governance
- added `check-shared-types-imports.sh`
- added `check-ecosystem-boundaries.sh`
-- added `check-flux-client-imports.sh`
+- added `check-mux-client-imports.sh`
- wired both guards into `Makefile` and CI
-- wired the Flux engine-boundary guards into `Makefile` and CI
+- wired the Mux engine-boundary guards into `Makefile` and CI
- added a legacy import guard so the removed `shared/types` path cannot return
- extended the ecosystem boundary guard to scan sibling engine repos when present locally
-- updated docs across Rho, kestrel, merlin, and external workspace copies
+- updated docs across Decoder, kestrel, merlin, and external workspace copies
- added standalone boundary guards in `kestrel` and `merlin`
-- added standalone boundary guards in `shrike`, `flux`, `harrier`, and `swift`
+- added standalone boundary guards in `shrike`, `mux`, `harrier`, and `swift`
- updated support repo READMEs with ecosystem boundary rules
### Review and verification contract migration
@@ -72,8 +72,8 @@ These items are already completed in the current workspace.
- added shared review/verification contract tests
- added kestrel -> review contract adapters
- added merlin -> verify contract adapters
-- switched Rho review persistence to neutral review contracts
-- switched Rho review/merlin bridge paths to return neutral review/verify contracts
+- switched Decoder review persistence to neutral review contracts
+- switched Decoder review/merlin bridge paths to return neutral review/verify contracts
## Remaining external follow-up
@@ -91,26 +91,26 @@ Still external:
### 2. Confirm release/publication convergence
Local state:
-- Rho local integration snapshot points at architecture-aligned support-repo revisions
+- Decoder local integration snapshot points at architecture-aligned support-repo revisions
Still external:
-- confirm released module versions used by Rho match the merged contract changes
+- confirm released module versions used by Decoder match the merged contract changes
-### 3. Remove Rho production dependency on lower Flux packages
+### 3. Remove Decoder production dependency on lower Mux packages
Current state:
- session persistence uses neutral tool contracts
-- Rho now owns the runtime message DTO in `internal/types.FluxMessage`
-- Rho now owns runtime tool call/result DTOs in `internal/types`
-- Rho now owns runtime response/usage/stream DTOs in `internal/types`
-- Rho now owns runtime chat options, response format, tool choice, continuation config, and tool definition DTOs in `internal/types`
-- Rho now owns the transport-provider seam in `internal/types.ChatProvider`
-- Rho session, review, setup, catalog, diagnostics, and custom-provider paths
- now enter through `flux/engine`
-- production imports of every lower Flux package are zero
+- Decoder now owns the runtime message DTO in `internal/types.MuxMessage`
+- Decoder now owns runtime tool call/result DTOs in `internal/types`
+- Decoder now owns runtime response/usage/stream DTOs in `internal/types`
+- Decoder now owns runtime chat options, response format, tool choice, continuation config, and tool definition DTOs in `internal/types`
+- Decoder now owns the transport-provider seam in `internal/types.ChatProvider`
+- Decoder session, review, setup, catalog, diagnostics, and custom-provider paths
+ now enter through `mux/engine`
+- production imports of every lower Mux package are zero
- cmd/session restore paths now go through centralized `session.ToRuntimeMessages` and `session.FromRuntimeMessages`
Decision:
-- completed: Rho owns the product DTO/port seam and Flux owns the engine,
+- completed: Decoder owns the product DTO/port seam and Mux owns the engine,
provider, credential, catalog, routing, resilience, and normalization layers
- keep the zero-exception boundary enforced; lower packages are test-fixture-only
@@ -133,7 +133,7 @@ Do this only if another repo truly needs them.
Current state:
- normalized review result contracts now live in `eagle/review`
- normalized verification report contracts now live in `eagle/verify`
-- Rho consumes neutral review/verification contracts at persistence and bridge boundaries
+- Decoder consumes neutral review/verification contracts at persistence and bridge boundaries
Possible later additions:
- review lifecycle status enums if another repo needs them
@@ -151,12 +151,12 @@ Possible later additions:
Do not move every internal event shape by default.
-### 6. Remove `rho/shared/types`
+### 6. Remove `decoder/shared/types`
Completed for the local ecosystem.
Current status:
-- Rho no longer ships `rho/shared/types`
+- Decoder no longer ships `decoder/shared/types`
- local import guards prevent the old path from returning
## Non-goals
@@ -164,36 +164,36 @@ Current status:
Do not do these without a separate decision:
- move provider runtime types into contracts
-- move Rho orchestration logic into contracts
+- move Decoder orchestration logic into contracts
- move sandbox manager internals into contracts
-- move every event struct in Rho into contracts
-- force Lark/Gitant architecture into Rho contracts
+- move every event struct in Decoder into contracts
+- force Lark/Gitant architecture into Decoder contracts
## Recommended PR order
### PR 1
-- completed: moved chat options/request DTOs behind Rho-owned runtime adapters
+- completed: moved chat options/request DTOs behind Decoder-owned runtime adapters
### PR 2
-- completed: moved provider/config interfaces behind Rho-owned transport adapters
+- completed: moved provider/config interfaces behind Decoder-owned transport adapters
### PR 3
-- completed: removed all lower-level Flux imports from Rho production code and
+- completed: removed all lower-level Mux imports from Decoder production code and
replaced the compatibility allowlist with a zero-exception guard
### PR 4
-- completed: added neutral review/verification result contracts and wired Rho bridge/persistence edges
+- completed: added neutral review/verification result contracts and wired Decoder bridge/persistence edges
### PR 5
-- completed: removed `rho/shared/types` from the local ecosystem and kept a legacy import guard
+- completed: removed `decoder/shared/types` from the local ecosystem and kept a legacy import guard
## Success criteria
The migration is in a good long-term state when:
- `eagle` is the only source of truth for shared contracts
-- support repos do not import `rho/internal/*`
-- support repos do not import `rho/shared/types`
+- support repos do not import `decoder/internal/*`
+- support repos do not import `decoder/shared/types`
- removed compatibility shims do not return
- CI prevents regressions
- new shared contracts are added deliberately, not by habit
diff --git a/docs/plans/rho-tau-alignment.md b/docs/plans/decoder-tau-alignment.md
similarity index 77%
rename from docs/plans/rho-tau-alignment.md
rename to docs/plans/decoder-tau-alignment.md
index 8078ba628..7041d1a95 100644
--- a/docs/plans/rho-tau-alignment.md
+++ b/docs/plans/decoder-tau-alignment.md
@@ -1,32 +1,32 @@
-# Plan: Rho — Tau-style TUI restyle + architecture tightening
+# Plan: Decoder — Tau-style TUI restyle + architecture tightening
Status: in progress
-Branch: `feat/rename-rho`
+Branch: `feat/rename-decoder`
## Context
-Rho (formerly Hawk) is a Go terminal coding agent (Bubble Tea + Lip Gloss,
+Decoder (formerly Hawk) is a Go terminal coding agent (Bubble Tea + Lip Gloss,
~17.7k LOC TUI across 107 files, 138 tools, 64 commands). Tau is a small
Python/Textual teaching agent with a strict 3-layer split
(`tau_ai → tau_agent → tau_coding`).
-"Make Rho like Tau" cannot mean a language port or a Textual clone. This plan
+"Make Decoder like Tau" cannot mean a language port or a Textual clone. This plan
does the achievable parts:
1. **Tau-style visual restyle** — adopt Tau's restrained, low-chrome look in
- Rho's existing Bubble Tea TUI.
+ Decoder's existing Bubble Tea TUI.
2. **Tau-style architecture discipline** — make `engine.StreamEvent` the hard
frontend contract; document and enforce the boundary.
3. **Verify twice** — targeted tests + lint, then a second independent pass.
## Phase 0 — Rename completion (done)
-- [x] Content rename hawk → rho (0 refs remain except intentional shims)
-- [x] File/dir renames (`cmd/rho`, `internal/rhoerr`, npm packages)
-- [x] Module path `github.com/GrayCodeAI/rho`
-- [x] Compatibility shims: `env.GetenvRho`, `storage.resolveAppDir`,
+- [x] Content rename hawk → decoder (0 refs remain except intentional shims)
+- [x] File/dir renames (`cmd/decoder`, `internal/decodererr`, npm packages)
+- [x] Module path `github.com/GrayCodeAI/decoder`
+- [x] Compatibility shims: `env.GetenvDecoder`, `storage.resolveAppDir`,
legacy `HAWK_*_DIR` overrides
-- [x] Committed + pushed to `feat/rename-rho`
+- [x] Committed + pushed to `feat/rename-decoder`
## Phase 1 — Tau-style theme (visual)
@@ -70,6 +70,6 @@ accent, generous dim text, no heavy borders.
## Out of scope (explicitly)
-- Rewriting Rho in Python / cloning Textual.
-- Deleting Rho's tool/command surface (separate decision).
+- Rewriting Decoder in Python / cloning Textual.
+- Deleting Decoder's tool/command surface (separate decision).
- Changing the daemon/ACP wire protocols.
\ No newline at end of file
diff --git a/docs/plans/dsh-harness-gap-port-plan.md b/docs/plans/dsh-harness-gap-port-plan.md
index 81c172863..cb65196fb 100644
--- a/docs/plans/dsh-harness-gap-port-plan.md
+++ b/docs/plans/dsh-harness-gap-port-plan.md
@@ -24,7 +24,7 @@ Same as the parent plan:
## Gap inventory (from the comparison audit)
-| # | DSH package(s) | Rho gap | Port status |
+| # | DSH package(s) | Decoder gap | Port status |
| --- | --- | --- | --- |
| 13 | `identity/anonymous-user-id` | no per-home anonymous telemetry identity | **Delivered** |
| 14 | `web/web-search-deepseek`, `-exa`, `-perplexity` | web search only has Brave/SearXNG/DDG | **Delivered** |
@@ -37,7 +37,7 @@ Same as the parent plan:
| 21 | `session/session-persistence-sqlite`, `session-query/*sqlite`, `storage/storage-sqlite` | JSONL-only session persistence | deferred |
| 22 | `e2b/*` | no cloud Linux sandbox | deferred |
| 23 | `code-runtime/*` | no sandboxed model-written program execution | deferred |
-| 24 | `sdk/client`, `sdk/protocol`, `sdk/server`, `python/sdk` | rho exposes ACP server instead of DSH JSON-RPC SDK | deferred (keep ACP) |
+| 24 | `sdk/client`, `sdk/protocol`, `sdk/server`, `python/sdk` | decoder exposes ACP server instead of DSH JSON-RPC SDK | deferred (keep ACP) |
| 25 | `terminal/*`, `tool-terminal` | no PTY terminal tool | deferred |
| 26 | `client/*`, `web/*`, `website`, `bundle/*-web-app` | web UI layer | out of scope (CLI/TUI) |
@@ -46,7 +46,7 @@ Same as the parent plan:
Port of DSH `identity/anonymous-user-id/src/index.ts`.
- `identity.Identity` — per-harness-home anonymous user id.
-- Resolved once per process (memoized): `$RHO_HOME`-style home (`~/.rho`),
+- Resolved once per process (memoized): `$DECODER_HOME`-style home (`~/.decoder`),
`.anonymous-user-id` file containing a bare random UUID.
- Never derived from hostname, network address, git remote, or env.
- Sync read/write; deleting the file mints a fresh identity.
@@ -98,7 +98,7 @@ Port of DSH `attachment/attachment` version-one image path.
`attachment.Limits` (maxImageBytes, maxImagesPerMessage,
maxMessageImageBytes, maxImagePixels, mediaTypes), `attachment.SaveImage`,
`attachment.Stored` (ref + data), `attachment.Store` interface +
- filesystem `Store` under the rho home data dir.
+ filesystem `Store` under the decoder home data dir.
- Validation: declared media type checked against decoded bytes; byte and
pixel limits enforced; duplicate writes rejected; ID opaque.
@@ -118,7 +118,7 @@ Port of DSH `session/session-projection-cache` semantics.
## Phase 18 — OTLP log-record export (`internal/observability/otellog`)
Port of DSH `session/session-telemetry-otel` backend semantics (the capture
-coordinator stays out of scope — rho has no Cordis bus; records reach the
+coordinator stays out of scope — decoder has no Cordis bus; records reach the
backend via `Emit`/`EmitFeedback`).
- `Record{Channel, Time, Severity, Attributes, Body}` / `Sink` seam —
@@ -139,8 +139,8 @@ backend via `Emit`/`EmitFeedback`).
- Shutdown races the DSH deadline (default 3s); exporter-shutdown goroutine
stays observed after the deadline; `Emit` is a non-blocking enqueue.
- `DefaultConfig()` mirrors oteltrace env conventions
- (`RHO_ENABLE_TELEMETRY=1` + `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`);
- wired in `cmd/rho/main.go` and `cmd/daemon.go`.
+ (`DECODER_ENABLE_TELEMETRY=1` + `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`);
+ wired in `cmd/decoder/main.go` and `cmd/daemon.go`.
- Tests: mode resolution, load-time validation, severity mapping, full/ops/
ledger emission (in-memory exporter), feedback-only direct-drop,
disabled-drop, idempotent shutdown, value conversion, attribute filtering.
@@ -148,7 +148,7 @@ backend via `Emit`/`EmitFeedback`).
## Gates
Each phase: `gofmt`/`go vet`/`go test` on the touched packages, then `make lint`
-and `rho verify` — run **twice** (the second pass re-runs the full touched
+and `decoder verify` — run **twice** (the second pass re-runs the full touched
suite after any fixes). No direct commits to `main`.
### Verification record (2026-08-17, branch `feat/dsh-harness-port-p0-eventlog`)
@@ -162,14 +162,14 @@ Pass 1:
- `make lint`: **0 issues** (fixed pre-existing errcheck `check-type-assertions`
debt + one unused helper in `internal/session/preparations.go`, and an S1000
single-case select in `internal/jobs/jobs.go`)
-- `rho verify`: exit 0
+- `decoder verify`: exit 0
- `scripts/check-internal-layer-imports.sh`: passed
Pass 2 (after lint fixes):
- `gofmt -l`: clean; `go vet`: clean; `go build ./...`: clean
- `go test -race` (identity, jobs, attachment): ok; `go test` (session, tool): ok
-- `make lint`: 0 issues; `rho verify`: exit 0
+- `make lint`: 0 issues; `decoder verify`: exit 0
New dependency: `golang.org/x/image v0.45.0` (direct) — webp decode validation
for `internal/attachment` (stdlib has no webp decoder).
@@ -178,18 +178,18 @@ for `internal/attachment` (stdlib has no webp decoder).
Pass 1:
-- `gofmt -l` (cmd/rho/main.go, cmd/daemon.go, internal/observability/otellog): clean
+- `gofmt -l` (cmd/decoder/main.go, cmd/daemon.go, internal/observability/otellog): clean
- `go vet` (otellog, cmd): clean
- `go test -race` (otellog): ok; `go build ./...`: ok
- `make lint`: **0 issues**
-- `rho verify`: exit 0
+- `decoder verify`: exit 0
- `scripts/check-internal-layer-imports.sh`: passed
Pass 2 (uncached re-run, no fixes were needed):
- `gofmt -l`: clean; `go vet`: clean; `go build ./...`: clean
- `go test -count=1 -race` (otellog): ok
-- `make lint`: 0 issues; `rho verify`: exit 0
+- `make lint`: 0 issues; `decoder verify`: exit 0
New dependencies (all direct): `go.opentelemetry.io/otel/log v0.20.0`,
`go.opentelemetry.io/otel/sdk/log v0.20.0`,
diff --git a/docs/plans/dsh-harness-port-plan.md b/docs/plans/dsh-harness-port-plan.md
index 9c4dba9b3..ef4b2ab41 100644
--- a/docs/plans/dsh-harness-port-plan.md
+++ b/docs/plans/dsh-harness-port-plan.md
@@ -1,4 +1,4 @@
-# Adopt durable-design ideas from deepseek-harness in rho
+# Adopt durable-design ideas from deepseek-harness in decoder
Status: Phase 0 scaffolded on `feat/dsh-harness-port-p0-eventlog`.
@@ -11,14 +11,14 @@ Status: Phase 0 scaffolded on `feat/dsh-harness-port-p0-eventlog`.
## Reference sources
-| dsh file | Extract | Maps to rho |
+| dsh file | Extract | Maps to decoder |
| --- | --- | --- |
| `packages/core/session/src/index.ts` | append-only `SessionEvent` log + `session/event` emit | `internal/eventlog` |
| `docs/architecture.md` "Turn flow" | `deriveMessages`; "model-visible ⟺ logged" | `Session.Persistence()` projection |
| `packages/core/tools/src/index.ts` | `tools/pre-execute` / `tools/execute` / `tools/post-execute` waterfall | `internal/tool/interceptor.go` (Phase 1) |
| `packages/interaction/user-approval/src/index.ts:30` | `approval/request` waterfall, fail-closed | `internal/engine/approval_gate.go` (Phase 1) |
| `docs/cordis-primer.md` "Waterfall Semantics" | `next()` delegate / short-circuit | interceptor contract |
-| `docs/capability-seams.md` | owner / impl / consumer roles | `docs/architecture/rho-capability-seams.md` (Phase 2) |
+| `docs/capability-seams.md` | owner / impl / consumer roles | `docs/architecture/decoder-capability-seams.md` (Phase 2) |
## Phase 0 — Event-sourced session log + "model-visible ⟺ logged"
@@ -93,7 +93,7 @@ concrete tool, carry it through `toolExecResult` in a later PR.
## Phase 2 — Seam discipline (docs + disposers)
-- `docs/architecture/rho-capability-seams.md`: owner / impl / consumer table.
+- `docs/architecture/decoder-capability-seams.md`: owner / impl / consumer table.
- Registrations return disposers (tool registry, hooks, MCP client).
- "Where new behavior goes" table.
@@ -114,16 +114,16 @@ concrete tool, carry it through `toolExecResult` in a later PR.
## Upstream parity matrix (honest status)
-These numbers compare Rho against the real deepseek-harness source, not the
+These numbers compare Decoder against the real deepseek-harness source, not the
plan's own scoped promises. The clone inspected was
`deepseek-ai/deepseek-harness` at `dsh-0.1.0-rc.7`.
-Rho is a **deliberate subset**. It ports the session-log spine, the fail-closed
+Decoder is a **deliberate subset**. It ports the session-log spine, the fail-closed
approval waterfall, and the interceptor/disposer seams; it does not port the
-product-wide plugin catalogue. Measured head-to-head, Rho has roughly **20–30%**
+product-wide plugin catalogue. Measured head-to-head, Decoder has roughly **20–30%**
of upstream by feature surface, and roughly **80–90%** of the plan's stated scope.
-| Surface | DSH | Rho today | Gap |
+| Surface | DSH | Decoder today | Gap |
| --- | --- | --- | --- |
| Known event types | 44 (dsh known-event-types.ts) | **44** (internal/eventlog/event.go) | **Closed** — all 26 new DSH event types added with typed payloads, wire decode, and Append helpers |
| Session spine code | ~3,156 non-test TS lines | ~868 non-test Go lines | Focused core, not full parity |
@@ -234,7 +234,7 @@ surface operations, ignorable markers, format version enforcement, and session
header parity. The port is functionally complete. Remaining optional depth:
- ~~DSH `surface.ts` `SurfaceManager`/`SurfaceReplacePlan` (live correction protocol — replacement operations).~~ Delivered: `internal/eventlog/surface.go` — `FoldSurface` (complete replay → surface nodes + replacement history) and an incremental `SurfaceManager` (bound to a `*Log`, with `Nodes`/`ReplaceGeneration`/`ValidateNext` atomic pre-flight), mirroring DSH's surface provenance, replacement-range, contiguity, and tool-result-rewrite invariants.
- ~~Zstd compression in persistence (DSH `session-persistence-jsonl/src/zstd.ts`).~~ Delivered: `internal/eventlog/zstdz/zstd.go` + `internal/session/session.go` (`.jsonl.zstd` saves) — see Phase 9.
-- DSH `packages/llm/llm/src/assembler.ts` (response normalization — covered by Flux facade).
+- DSH `packages/llm/llm/src/assembler.ts` (response normalization — covered by Mux facade).
This matrix is the honest anchor: the skeleton is ported; the deep fidelity is
the actual remaining work.
@@ -429,4 +429,4 @@ UI additions (Safari support, outside pointer handling) or ACP content admission
## Gates
-Each phase: `make ci` + `rho verify`; no direct commits to `main`.
+Each phase: `make ci` + `decoder verify`; no direct commits to `main`.
diff --git a/docs/plans/dsh-harness-rfc-port-plan.md b/docs/plans/dsh-harness-rfc-port-plan.md
index 89f86b81d..dc6539700 100644
--- a/docs/plans/dsh-harness-rfc-port-plan.md
+++ b/docs/plans/dsh-harness-rfc-port-plan.md
@@ -1,6 +1,6 @@
-# Wave 2 — high-value deepseek-harness RFC ports for rho
+# Wave 2 — high-value deepseek-harness RFC ports for decoder
-> **Sandbox phases are obsolete.** Rho no longer contains `internal/sandbox`,
+> **Sandbox phases are obsolete.** Decoder no longer contains `internal/sandbox`,
> Docker execution, or an OS/container sandbox backend. Do not implement Phase
> 2.3 or 2.11 as written; any future policy work must target the host-native
> permission, path, trust, and environment controls.
@@ -36,7 +36,7 @@ Reference source: `deepseek-ai/deepseek-harness` at `dsh-v0.1.0-rc.7`
## Wave 2 gap inventory
-| # | DSH source | Rho gap | Status |
+| # | DSH source | Decoder gap | Status |
| --- | --- | --- | --- |
| 2.1 | `guard/timeout-policy` | no per-tool declared timeout enforced at dispatch | **implemented** on `feat/dsh-harness-rfc-2.1-timeout-policy` |
| 2.2 | `compaction/compaction` tool-pairing helpers | compact strategies can cut across open tool call/result pairs | proposed |
@@ -64,7 +64,7 @@ Port of DSH `guard/timeout-policy` (`dsh-tool-call-timeout-policy`) + the
the tool's own declaration, not from a policy table.
- `tool.Tool` gains an optional `TimeoutProvider` interface (`Timeout()
- time.Duration`, 0 = no declaration) — the rho-native form of DSH's
+ time.Duration`, 0 = no declaration) — the decoder-native form of DSH's
`ToolDefinition.timeoutMs`, consistent with the existing optional-provider
pattern (`RiskLevelProvider`, `RetryPolicyProvider`, `SchemaProvider`).
`tool.TimeoutOf(t Tool) time.Duration` reads it.
@@ -94,7 +94,7 @@ TOOL_TIMEOUT).
## Phase 2.2 — Compaction tool-pairing boundaries (`internal/engine/compact` + `internal/eventlog`)
Port of DSH `compaction/compaction` surface contract + the
-`toolPairingBalancedBefore` / `toolPairingBalancedAfter` helpers. Rho's
+`toolPairingBalancedBefore` / `toolPairingBalancedAfter` helpers. Decoder's
`internal/engine/compact/` already does LLM summarization
(`strategy.go`, `micro.go`, `session_memory.go`) and `internal/eventlog` already
journals `tool.call` / `tool.result` / `session.compacted` (Wave 1 Phase 0). The
@@ -125,14 +125,14 @@ detection and adoption on load; deterministic replay after replace.
## Phase 2.3 — Sandbox mode vocabulary + model-facing policy (`internal/sandbox` + `internal/eventlog` + `internal/engine`)
> **Obsolete specification — retained for historical provenance only.** Do not
-> implement this phase. Rho's current product boundary is host-native
+> implement this phase. Decoder's current product boundary is host-native
> permission, path, trust, and environment policy; there is no sandbox mode or
> `internal/sandbox` package to extend.
Port of DSH `sandbox/sandbox-policy` semantics
(`SandboxMode` read-only / workspace-write / danger-full-access,
`ctx.sandboxPolicy.resolve()`, `setSandboxMode`, the `sandbox:policy` context
-contribution). Rho already has the vocabulary — `internal/sandbox/mode.go`
+contribution). Decoder already has the vocabulary — `internal/sandbox/mode.go`
`Mode` strict / workspace / off — so this phase ports the **policy resolution
and durability** around it.
@@ -153,7 +153,7 @@ and durability** around it.
durable context message on the first request and on each effective policy
change; unchanged requests add nothing. `workspace` carries only the canonical
workspace path (no host-dependent temp paths — summarize them). Rendered by
- the prompt assembler exactly like DSH's three templates, but with rho's
+ the prompt assembler exactly like DSH's three templates, but with decoder's
vocabulary:
- `strict` — read-only; do not refuse a required modification from this policy
alone; try the tool and follow denial/escalation guidance.
@@ -234,7 +234,7 @@ discovery; runtime provider registration/disposal.
Revives gap `#21` in **query-only** scope (no migration of the JSONL store; the
JSONL file stays the source of truth). Port of DSH
-`session-query/session-query-sqlite` semantics over rho's session logs.
+`session-query/session-query-sqlite` semantics over decoder's session logs.
- New `internal/sessionquery` package:
- FTS5 index (external content or contentless) over the session store,
@@ -282,9 +282,9 @@ resume of overdue work, no external channel, create/list/delete round-trip.
## Phase 2.8 — ACP client + external-agent subagent providers (`internal/acp` + `internal/multiagent`)
Port of DSH `acp/` (client side) + `subagent/subagent-acp`, `subagent-claude-code`,
-`subagent-codex`. Rho has the ACP **server** (Wave 1 `internal/acp/server.go` —
+`subagent-codex`. Decoder has the ACP **server** (Wave 1 `internal/acp/server.go` —
initialize, session/new, session/prompt, streamed updates,
-session/request_permission); this phase adds the client so rho's mission mode
+session/request_permission); this phase adds the client so decoder's mission mode
can **delegate to** other ACP agents, Claude Code, and Codex.
- `internal/acp/client.go`:
@@ -327,7 +327,7 @@ tool calls and supports interactive stdin.
- Local backend over the sandbox executor: PTY allocation with zero-CGO on
Linux (`syscall`-based pty or a maintained pure-Go pty; verify
`github.com/creack/pty`'s CGO status before adoption — zero-CGO is a hard
- rho constraint); Windows via `ConPTY` later, outside this phase.
+ decoder constraint); Windows via `ConPTY` later, outside this phase.
- Sandbox enforcement: the backend applies the resolved Phase 2.3 policy
(mode + workspace root) before exec, fail-closed.
- Bounded reads: per-read byte cap; no unbounded buffering in model-facing
@@ -377,12 +377,12 @@ pre-publication failure.
## Phase 2.11 — Native Windows ACL sandbox (`internal/sandbox`)
> **Obsolete specification — retained for historical provenance only.** Do not
-> implement this phase. Rho no longer provides a local OS/container sandbox or
+> implement this phase. Decoder no longer provides a local OS/container sandbox or
> Docker fallback on any platform.
The original proposal ported DSH `sandbox/sandbox-windows-acl` and assumed a
cross-platform confinement backend. That assumption is no longer part of
-Rho's local product architecture.
+Decoder's local product architecture.
- `internal/sandbox/windows_acl.go` (`//go:build windows`):
- Implements the same `Sandbox` interface as `landlock.go`
@@ -409,7 +409,7 @@ Port of DSH `lsp/lsp-stdio` operational semantics. `internal/lsp/` currently has
`client.go`/`manager.go`/`config.go`; this phase audits and aligns the client
lifecycle with DSH's:
- **Transient-open sequence**: per query — resolve and byte-bound the source
- through rho's fs, `textDocument/didOpen` (version 1, full text), the
+ through decoder's fs, `textDocument/didOpen` (version 1, full text), the
requested request, then `textDocument/didClose` in `finally`. No document
cache, no LRU, no `didChange`; a failed/canceled `didOpen` write terminates
the server instance before the pool can reuse it.
@@ -439,7 +439,7 @@ scrubbing (KEY/PASSWORD/SECRET/TOKEN absent from child env); processId null.
## Gates (each phase)
`gofmt`/`go vet`/`go test -race` on the touched packages, then `make lint` and
-`rho verify`, run **twice** (second pass re-runs the full touched suite after
+`decoder verify`, run **twice** (second pass re-runs the full touched suite after
any fixes). `scripts/check-internal-layer-imports.sh` must stay green. No direct
commits to `main` — each phase is its own feature branch
(`feat/dsh-harness-rfc-`), opened from `main`, with a PR and green CI.
diff --git a/docs/plans/engine-refactor-plan.md b/docs/plans/engine-refactor-plan.md
index ea4631074..f96550f5b 100644
--- a/docs/plans/engine-refactor-plan.md
+++ b/docs/plans/engine-refactor-plan.md
@@ -1,20 +1,20 @@
-# rho/engine sub-package split — analysis and migration plan
+# decoder/engine sub-package split — analysis and migration plan
> Status: **analysis only**. No code is moved by this document. The actual
-> split is multi-PR work that should land incrementally to keep rho's
+> split is multi-PR work that should land incrementally to keep decoder's
> build green at every step.
## The problem
```
-rho/engine/
+decoder/engine/
├── *.go 161 source files, 66,682 lines
└── *_test.go 141 test files, 65,907 lines
───── total: ~133K lines, 302 files, ONE package
```
For comparison: the entire `kubernetes/kubectl` (a non-trivial CLI) is
-~110K lines split across **dozens** of internal packages. rho's engine
+~110K lines split across **dozens** of internal packages. decoder's engine
is bigger than that and lives in a single `package engine`.
Concrete pain that creates today:
@@ -40,7 +40,7 @@ splitting into ~15 sub-packages. The line counts are file-name-based
estimates; the real numbers will shift during the split.
```
-rho/engine/
+decoder/engine/
├── engine.go # top-level Engine type, public API only
├── lifecycle.go # session start/stop, hooks, graceful shutdown
├── stream.go # the main response stream loop (large; consider further split)
@@ -193,18 +193,18 @@ code from earlier experiments).
## Migration strategy
-The split is high-risk because it touches every other package in rho
-that imports `engine.Foo`. To keep rho green at every commit:
+The split is high-risk because it touches every other package in decoder
+that imports `engine.Foo`. To keep decoder green at every commit:
1. **Stage 1 — alias-only.** For each proposed sub-package, create
`engine//.go` containing only re-exports:
```go
package compact
- import "github.com/GrayCodeAI/rho/engine"
+ import "github.com/GrayCodeAI/decoder/engine"
type Strategy = engine.CompactStrategy
var Default = engine.DefaultCompactStrategy
```
- Rho's external callers can start migrating to the new import paths.
+ Decoder's external callers can start migrating to the new import paths.
Old code keeps working unchanged. **Land this first.**
2. **Stage 2 — move bodies.** For one sub-package at a time:
@@ -223,7 +223,7 @@ that imports `engine.Foo`. To keep rho green at every commit:
coordinator package only.
This approach scales: each PR is small, reviewable, and individually
-revertible. No "big bang" merge that paralyses rho for a week.
+revertible. No "big bang" merge that paralyses decoder for a week.
## Estimated effort
@@ -266,7 +266,7 @@ The `compact/` sub-package is the cleanest extraction candidate:
| `git/` | `engine/git/aliases.go` | 9 types, 4 funcs |
| `prompt/` | `engine/prompt/aliases.go` | 6 types, 3 funcs |
-New code should import `github.com/GrayCodeAI/rho/engine/`
+New code should import `github.com/GrayCodeAI/decoder/engine/`
instead of reaching into `engine` for these names. The remaining 17
clusters follow the same pattern:
@@ -274,7 +274,7 @@ clusters follow the same pattern:
// engine//aliases.go
package
-import "github.com/GrayCodeAI/rho/engine"
+import "github.com/GrayCodeAI/decoder/engine"
// Re-export the cluster's public symbols from engine as type and var
// aliases. Implementation stays in engine until Stage 2 of this plan.
diff --git a/docs/plans/fix-critical-and-high-review.md b/docs/plans/fix-critical-and-high-review.md
index 56e83bba4..349c9456e 100644
--- a/docs/plans/fix-critical-and-high-review.md
+++ b/docs/plans/fix-critical-and-high-review.md
@@ -1,7 +1,7 @@
-# Plan: Fix Critical + High-Impact Review Findings — rho
+# Plan: Fix Critical + High-Impact Review Findings — decoder
> Branch: `fix/critical-and-high-review-2026-06`
-> PR:
+> PR:
> Status: **✅ COMPLETE — all 9 items + extensive follow-up committed.**
> Constraint: **no new go.mod / go.sum dependencies** for any item in this plan.
>
@@ -81,12 +81,12 @@ These were documented in the original plan as out-of-scope-for-this-PR. They rem
## Context
-A deep code review of `flux` and `rho` (companion plan at
-`../flux/docs/plans/fix-critical-and-high-review.md`) surfaced 7 critical
-and 9 high items. This plan covers **all rho items** (C3, C4, C5, H5,
+A deep code review of `mux` and `decoder` (companion plan at
+`../mux/docs/plans/fix-critical-and-high-review.md`) surfaced 7 critical
+and 9 high items. This plan covers **all decoder items** (C3, C4, C5, H5,
H6, H7, H8, H9) broken into a sequence of small, reviewable PRs.
-## Scope (rho)
+## Scope (decoder)
| ID | Severity | Title | File(s) | Effort |
|----|----------|-------|---------|--------|
@@ -101,9 +101,9 @@ H6, H7, H8, H9) broken into a sequence of small, reviewable PRs.
## Out of scope (deferred to next plan)
-- H10 from flux: `//nolint:errcheck` on type-assertion that can panic.
+- H10 from mux: `//nolint:errcheck` on type-assertion that can panic.
- M1–M20 medium items.
-- L-tier quick wins (e.g. `cosmenticFlags` typo, `cmd/.rho/` leaked state).
+- L-tier quick wins (e.g. `cosmenticFlags` typo, `cmd/.decoder/` leaked state).
- `internal/intelligence/repomap/` documentation (large, separate effort).
- Anything that requires a new dependency.
@@ -131,7 +131,7 @@ PRs can be merged individually; the branch is a namespace.
## PR 1 — Surface silent migration error (C4)
**What**: `cmd/root.go:114` calls `MigrateProviderSecrets()` and discards
-the error. If migration fails, secrets may remain in `~/.rho/.env` while
+the error. If migration fails, secrets may remain in `~/.decoder/.env` while
the agent is told to ignore that file.
**Fix**:
@@ -240,7 +240,7 @@ core. Mitigation: keep both code paths behind a feature flag for one
release; metric for "wait latency" before/after.
**Rollback**: feature flag. If regressions appear, set
-`RHO_MULTIAGENT_POLLING=1` to revert.
+`DECODER_MULTIAGENT_POLLING=1` to revert.
---
@@ -367,7 +367,7 @@ legitimate-input fix, not a security regression.
> This section records the original review finding only. Do not recreate the
> removed sandbox package or Docker fallback from this plan.
-**Bug**: `internal/sandbox/seatbelt.go:70-108` `DefaultRhoPolicy` defaults
+**Bug**: `internal/sandbox/seatbelt.go:70-108` `DefaultDecoderPolicy` defaults
to `AllowWrite: true` and `AllowProcess: true`. A sandboxed bash can write
and spawn processes out of the box.
@@ -471,7 +471,7 @@ behavioral changes, only structural.
```bash
go mod verify
-go build ./cmd/rho
+go build ./cmd/decoder
go test -race -count=1 -shuffle=on ./...
go vet ./...
golangci-lint run
@@ -499,10 +499,10 @@ Coverage target: maintained at 60%+ (CI gate).
## Cross-repo coordination
-- **flux PR 4 (C2 — Vertex fix)** and **rho PR 4 (H6 — Session
+- **mux PR 4 (C2 — Vertex fix)** and **decoder PR 4 (H6 — Session
decomposition)** are independent.
-- **flux PR 8 (H4 — FluxError)** is a prerequisite for any future
- rho-side `errors.As(err, &fluxErr)` use (currently none). No
+- **mux PR 8 (H4 — MuxError)** is a prerequisite for any future
+ decoder-side `errors.As(err, &muxErr)` use (currently none). No
ordering dependency.
- The two repos' branches are independent and can be merged in any
order.
diff --git a/docs/plans/fx-adoption-plan.md b/docs/plans/fx-adoption-plan.md
index d46b88893..5c8b46539 100644
--- a/docs/plans/fx-adoption-plan.md
+++ b/docs/plans/fx-adoption-plan.md
@@ -1,18 +1,18 @@
# Vercel fx Adoption Plan
-Status: Implemented in Rho's native Go architecture
+Status: Implemented in Decoder's native Go architecture
Source: `https://github.com/vercel-labs/fx`
This plan records the useful ideas identified while comparing Vercel Labs'
-`fx` Unix-like coding agent with Rho and its independent ecosystem repositories. It is an
-adoption plan, not a code-porting plan. Rho should reimplement compatible
+`fx` Unix-like coding agent with Decoder and its independent ecosystem repositories. It is an
+adoption plan, not a code-porting plan. Decoder should reimplement compatible
behavior in Go and preserve its existing provider, memory, review, audit,
session, and security boundaries.
## Executive Decision
-Rho should adopt the following `fx` ideas:
+Decoder should adopt the following `fx` ideas:
1. Stable identities and operational commands for persisted permission rules.
2. A unified machine-readable runtime status snapshot.
@@ -21,21 +21,21 @@ Rho should adopt the following `fx` ideas:
user authority.
5. Compatibility aliases for common permission modes in CLI and ACP surfaces.
6. Stronger subagent lifecycle and permission observability.
-7. A narrow embeddable host API over Rho's existing daemon and ACP surfaces.
+7. A narrow embeddable host API over Decoder's existing daemon and ACP surfaces.
-Rho should not copy `fx` source code, replace its Go runtime with Zig, create a
+Decoder should not copy `fx` source code, replace its Go runtime with Zig, create a
second permission system, or reduce its code-intelligence tool surface merely to
match `fx`'s smaller binary.
-## Existing Rho Capabilities
+## Existing Decoder Capabilities
-The comparison found that Rho already provides the foundation for most `fx`
+The comparison found that Decoder already provides the foundation for most `fx`
features:
-| `fx` capability | Rho implementation | Current decision |
+| `fx` capability | Decoder implementation | Current decision |
|---|---|---|
-| Native single binary | Go static binary and cross-platform release builds | Keep Rho implementation |
-| Agent loop | `internal/engine` | Keep Rho implementation |
+| Native single binary | Go static binary and cross-platform release builds | Keep Decoder implementation |
+| Agent loop | `internal/engine` | Keep Decoder implementation |
| Permission and host-policy split | `internal/engine/safety`, `internal/permissions`, `internal/trust` | Harden and document |
| `ask`/automatic approval behavior | Autonomy profiles, governance, grants, hooks | Add compatibility aliases only |
| Child agents | `internal/multiagent`, continuable children, cold resume | Add observability and configuration polish |
@@ -45,7 +45,7 @@ features:
| ACP | `internal/acp` | Extend status/config parity where useful |
| Swift and replay | sibling `swift` (Swift), `internal/session/replay` | Add terminal-level tape capability |
| Persistent memory | sibling `harrier` (Harrier) | Do not replace with flat JSON state |
-| Provider runtime | sibling `flux` | Do not add provider logic to Rho |
+| Provider runtime | sibling `mux` | Do not add provider logic to Decoder |
## Priority Model
@@ -63,11 +63,11 @@ when their original command, path, or workspace has changed.
### Scope and ownership
-- Primary implementation: Rho `internal/permissions` and
+- Primary implementation: Decoder `internal/permissions` and
`internal/engine/safety`.
- Shared contract changes, if needed: sibling `eagle/policy`.
- User-facing commands: `cmd` and the existing slash-command surface.
-- No changes to sibling `flux` or `falcon`.
+- No changes to sibling `mux` or `falcon`.
### Required behavior
@@ -88,12 +88,12 @@ when their original command, path, or workspace has changed.
### Proposed interfaces
```text
-rho permissions list [--json]
-rho permissions revoke
-rho permissions reset [--scope user|project]
+decoder permissions list [--json]
+decoder permissions revoke
+decoder permissions reset [--scope user|project]
```
-The exact command names may follow existing Rho conventions, but the typed
+The exact command names may follow existing Decoder conventions, but the typed
operation should be shared by CLI, TUI, daemon, and ACP.
### Acceptance criteria
@@ -155,7 +155,7 @@ the daemon, ACP clients, and the interactive UI.
### Ownership
-- Snapshot contract: Rho root or `eagle` if consumed cross-repo.
+- Snapshot contract: Decoder root or `eagle` if consumed cross-repo.
- Assembly: `internal/engine`, `internal/session`, `internal/mcp`,
`internal/permissions`, `internal/multiagent`.
- Rendering: CLI/TUI and daemon adapters.
@@ -164,7 +164,7 @@ the daemon, ACP clients, and the interactive UI.
```text
schema_version
-rho_version
+decoder_version
session_id
workspace
git_branch
@@ -193,8 +193,8 @@ identifiers rather than raw secrets.
### Required interfaces
```text
-rho status
-rho status --json
+decoder status
+decoder status --json
```
The daemon and ACP should expose the same snapshot schema, with transport
@@ -212,14 +212,14 @@ metadata kept outside the product snapshot.
### Goal
-Add `fx`-style terminal byte and resize recording to complement Rho's existing
+Add `fx`-style terminal byte and resize recording to complement Decoder's existing
agent-session swift and replay features.
### Ownership
- Preferred home: sibling `swift` (Swift) if the capability is intended for reuse by
other agents.
-- Rho integration: `internal/swift` or the TUI composition layer.
+- Decoder integration: `internal/swift` or the TUI composition layer.
- Do not put terminal tape parsing in the agent engine.
### Required behavior
@@ -237,10 +237,10 @@ agent-session swift and replay features.
### Proposed interfaces
```text
-rho swift record --output
-rho swift replay
-rho swift replay --frames
-rho swift replay --json
+decoder swift record --output
+decoder swift replay
+decoder swift replay --frames
+decoder swift replay --json
```
Existing Swift session capture remains the source of prompts, tool calls, git
@@ -260,35 +260,35 @@ ID.
### Goal
-Expose familiar `fx` permission names without weakening Rho's richer policy
+Expose familiar `fx` permission names without weakening Decoder's richer policy
engine.
### Mapping
-| Compatibility name | Rho behavior |
+| Compatibility name | Decoder behavior |
|---|---|
| `ask` | Supervised or equivalent prompt-required policy |
| `auto` | Automatic review/approval behavior where configured |
| `yolo` | Explicit high-autonomy mode, still subject to governance, sandbox, and destructive-command hard blocks |
-These are aliases or presentation-layer modes, not a replacement for Rho's
+These are aliases or presentation-layer modes, not a replacement for Decoder's
autonomy tiers, governance ceiling, spec gates, and sandbox policy.
### Required behavior
1. Accept names in configuration, CLI, and ACP only where the surface supports
them.
-2. Display the effective Rho tier and hard safety constraints.
+2. Display the effective Decoder tier and hard safety constraints.
3. Never let `yolo` bypass governance, hard-deny rules, destructive-command
blocks, or mandatory spec approval.
-4. Persist the canonical Rho representation, not an ambiguous alias.
+4. Persist the canonical Decoder representation, not an ambiguous alias.
5. Add migration and invalid-value diagnostics.
## P1: Subagent Lifecycle and Authority Observability
### Goal
-Adopt `fx`'s useful child-agent visibility while retaining Rho's continuable
+Adopt `fx`'s useful child-agent visibility while retaining Decoder's continuable
child sessions, worktree isolation, model routing, and delegated policy
inheritance.
@@ -319,7 +319,7 @@ inheritance.
### Goal
Improve discoverability and trust reporting using `fx`'s clear status model,
-without changing Rho's existing MCP and skills architecture.
+without changing Decoder's existing MCP and skills architecture.
### Required behavior
@@ -344,7 +344,7 @@ without changing Rho's existing MCP and skills architecture.
### Goal
Offer a supported embedding boundary inspired by `fx`'s ACP and WASM surfaces,
-without committing Rho to a WASM rewrite.
+without committing Decoder to a WASM rewrite.
### First implementation
@@ -417,12 +417,12 @@ make test-race
make vet
make lint
make security
-rho verify
+decoder verify
```
For sibling-repository changes, run that repository's own tests and boundary checks before
-updating the Rho pointer. Do not modify provider protocols or adapters in Rho;
-those belong in the Flux repository.
+updating the Decoder pointer. Do not modify provider protocols or adapters in Decoder;
+those belong in the Mux repository.
## Delivery Sequence
@@ -456,7 +456,7 @@ those belong in the Flux repository.
- Design and review the versioned swift artifact format in sibling `swift` (Swift).
- Implement recording, replay, redaction, and deterministic golden tests.
-- Integrate recording controls into Rho without coupling tape parsing to the
+- Integrate recording controls into Decoder without coupling tape parsing to the
agent loop.
### Milestone 5: Host integration and trust UX
@@ -469,18 +469,18 @@ those belong in the Flux repository.
## Deliberately Rejected
- Copying Zig implementation code from `vercel-labs/fx`.
-- Replacing Rho's Go runtime or independent ecosystem repositories.
+- Replacing Decoder's Go runtime or independent ecosystem repositories.
- Adding a second permission evaluator.
- Replacing Harrier with flat JSON memory.
- Replacing Swift session capture with terminal tapes.
-- Removing Rho's code intelligence, review, audit, token, or provider features
+- Removing Decoder's code intelligence, review, audit, token, or provider features
to target `fx`'s binary size.
- Automatically executing repository-local MCP servers or hooks.
- Adding WASM before daemon and ACP contracts are stable and proven.
## Success Criteria
-The adoption is successful when Rho can provide the operational clarity of
+The adoption is successful when Decoder can provide the operational clarity of
`fx` while retaining its stronger ecosystem architecture:
- Every persistent permission rule can be listed and revoked by stable ID.
@@ -488,7 +488,7 @@ The adoption is successful when Rho can provide the operational clarity of
- TUI failures can be reproduced from a credential-free terminal tape.
- Project configuration cannot silently grant private authority.
- Child-agent authority, lifecycle, model, and budget state are inspectable.
-- Existing Rho memory, provider, review, audit, MCP, ACP, and session behavior
+- Existing Decoder memory, provider, review, audit, MCP, ACP, and session behavior
remains intact.
## Implemented Scope
@@ -504,7 +504,7 @@ The adoption is successful when Rho can provide the operational clarity of
continuable children, and cold resume retained as the authoritative runtime.
The remaining items in this document are future refinements to the already
-implemented surfaces, not missing baseline features. Rho's subprocess LSP
+implemented surfaces, not missing baseline features. Decoder's subprocess LSP
manager remains a separate integration task: the current main `LSP` tool uses
the codegraph path, while `internal/lsp` provides the richer language-server
client and is not yet attached to the primary tool registry.
diff --git a/docs/plans/goose-adoption-plan.md b/docs/plans/goose-adoption-plan.md
index 2d6dd7c90..85a4cf61f 100644
--- a/docs/plans/goose-adoption-plan.md
+++ b/docs/plans/goose-adoption-plan.md
@@ -7,23 +7,23 @@ Linux Foundation / Agentic AI Foundation)
## Executive Decision
-Goose's audit against rho found that most of its runtime concepts already have
-a native rho implementation (providers via flux, sessions, MCP, ACP, skills,
-host-native policy, permissions). The genuinely novel, rho-relevant ideas are
+Goose's audit against decoder found that most of its runtime concepts already have
+a native decoder implementation (providers via mux, sessions, MCP, ACP, skills,
+host-native policy, permissions). The genuinely novel, decoder-relevant ideas are
adopted here in Go, without copying Rust code or adding a second execution
sandbox runtime.
-## Existing Rho Capabilities
+## Existing Decoder Capabilities
-| Goose package/concept | Rho implementation | Decision |
+| Goose package/concept | Decoder implementation | Decision |
|---|---|---|
-| Provider abstraction (~36) | sibling `flux` (28 built-in + 75+ live) | Keep rho |
-| Sessions (SQLite WAL) | `internal/session` JSONL+WAL+zstd + sibling `swift` (Swift) | Keep rho |
-| MCP (client+server) | `internal/mcp` + sibling `falcon` | Keep rho |
-| ACP | `internal/acp` | Keep rho |
-| Extensions/skills | `internal/plugin`, skills registry | Keep rho |
+| Provider abstraction (~36) | sibling `mux` (28 built-in + 75+ live) | Keep decoder |
+| Sessions (SQLite WAL) | `internal/session` JSONL+WAL+zstd + sibling `swift` (Swift) | Keep decoder |
+| MCP (client+server) | `internal/mcp` + sibling `falcon` | Keep decoder |
+| ACP | `internal/acp` | Keep decoder |
+| Extensions/skills | `internal/plugin`, skills registry | Keep decoder |
| Execution safety | `internal/engine/safety`, path guards, trust policy | Host-native, fail-closed |
-| OSV malware gate | `internal/permissions/osv_checker.go` (`CheckCommand`/`CheckPackage`) | Keep rho |
+| OSV malware gate | `internal/permissions/osv_checker.go` (`CheckCommand`/`CheckPackage`) | Keep decoder |
| Hints / AGENTS.md | `internal/config` AGENTS.md loader | **Adopt** @file references + subdir hints |
| Context compaction | sibling `shrike` (Shrike) + `internal/engine/compaction` | **Adopt** structured-summary retry ladder |
| Extension env safety | none (only OSV gate) | **Adopt** disallowed-env-var filter |
@@ -31,7 +31,7 @@ sandbox runtime.
## Priority Model
-- **P0:** Security-relevant, bounded, rho-native adoptions.
+- **P0:** Security-relevant, bounded, decoder-native adoptions.
- **P1:** High-value product improvements.
- **Defer:** Larger or cross-cutting changes needing an RFC.
@@ -50,7 +50,7 @@ or MCP stdio processes by filtering dangerous environment overrides
checker) — a `sanitizeEnv` / `SafeEnv` helper.
- Consumers: `internal/mcp` stdio launch path and `internal/plugin` package
execution.
-- No changes to sibling `flux`.
+- No changes to sibling `mux`.
### Required behavior
@@ -114,7 +114,7 @@ strict size/depth budgets — matching goose `hints/import_files.rs`.
### Goal
-Upgrade rho's context compaction to a structured summary with a progressive
+Upgrade decoder's context compaction to a structured summary with a progressive
tool-response-dropping retry ladder on overflow, and token-estimator-backed
accounting, matching `goose-context-management`.
@@ -142,18 +142,18 @@ accounting, matching `goose-context-management`.
## Deliberately Deferred
-- Goose's SQLite session store (`usage_ledger`, token/cost schema): rho's
+- Goose's SQLite session store (`usage_ledger`, token/cost schema): decoder's
JSONL/WAL + swift + cost tracker cover it; a schema migration is a larger
change and is tracked separately.
- MCP Apps / agent-provided HTML UIs: novel but requires UI-layer design.
- ACP-as-provider wrapping other CLIs: larger provider abstraction change.
-- Local-inference tool emulation / toolshim: depends on flux's local-model
+- Local-inference tool emulation / toolshim: depends on mux's local-model
path.
-- Recipe security scanner / cron recipes: rho already has schedule/cron.
+- Recipe security scanner / cron recipes: decoder already has schedule/cron.
## Verification
- `go test ./...` full suite.
-- `make vet`, `make lint`, `rho verify`.
+- `make vet`, `make lint`, `decoder verify`.
- Focused tests for the env filter, AGENTS.md references, and compaction retry.
- markdownlint on this document.
diff --git a/docs/plans/minimax-adoption-plan.md b/docs/plans/minimax-adoption-plan.md
index 0dc41b40a..d110114e1 100644
--- a/docs/plans/minimax-adoption-plan.md
+++ b/docs/plans/minimax-adoption-plan.md
@@ -1,40 +1,40 @@
-# MiniMax-AI → rho Adoption Plan
+# MiniMax-AI → decoder Adoption Plan
Status: Implemented in working tree; sibling-repository PRs and skills curation remain follow-ups
Date: 2026-08-21
Scope: Adopt the high-value, verified concepts from MiniMax-AI's open-source
-repos into the Rho ecosystem (Rho plus independent repositories: Flux, Eagle,
+repos into the Decoder ecosystem (Decoder plus independent repositories: Mux, Eagle,
Falcon, Kestrel, and Merlin).
## Findings summary
-Deep code review of 6 MiniMax-AI repos against Rho's existing sibling
+Deep code review of 6 MiniMax-AI repos against Decoder's existing sibling
repositories and
internals produced these adoptions, ordered by value:
| # | MiniMax repo | Adopt into | Action |
|---|---|---|---|
-| 1 | MiniMax-Provider-Verifier | sibling `flux` | Add provider-conformance metrics + wire the orphaned `verify` harness into CI |
+| 1 | MiniMax-Provider-Verifier | sibling `mux` | Add provider-conformance metrics + wire the orphaned `verify` harness into CI |
| 2 | MiniMax/skills | `starling` | Curate high-quality skill content (content, not mechanism) |
-| 3 | MiniMax-Coding-Plan-MCP | rho / `falcon` | MCP v2 no-network test pattern + image-source normalization (patterns only) |
-| 4 | minimax_search | rho tooling | Jina page→Markdown browse extractor + evidence-extraction prompt (pattern) |
-| 5 | Mini-Agent | rho engine | Cooperative-cancellation-with-cleanup + token-aware lossy summarization (patterns) |
+| 3 | MiniMax-Coding-Plan-MCP | decoder / `falcon` | MCP v2 no-network test pattern + image-source normalization (patterns only) |
+| 4 | minimax_search | decoder tooling | Jina page→Markdown browse extractor + evidence-extraction prompt (pattern) |
+| 5 | Mini-Agent | decoder engine | Cooperative-cancellation-with-cleanup + token-aware lossy summarization (patterns) |
| 6 | MiniMax-MCP / JS | — | Not adoptable (media generation, out of scope) |
-## 1. Flux provider-conformance metrics + CI wiring (highest value)
+## 1. Mux provider-conformance metrics + CI wiring (highest value)
-### Verified current state (flux repository)
+### Verified current state (mux repository)
-- `flux/verify/verify.go` — a complete behavioral conformance harness
+- `mux/verify/verify.go` — a complete behavioral conformance harness
exists: `Case`/`CaseResult`/`Expectation`/`Report`, `Run()`, `scoreResponse()`,
`ToolCallF1()`, `DiffBaseline()`, `Markdown()`.
-- `flux/verify/cases.go` — `CanonicalCases()` with 3 cases:
+- `mux/verify/cases.go` — `CanonicalCases()` with 3 cases:
`basic-chat`, `deterministic-answer`, `tool-call`.
-- `flux/verify/metrics.go` — `ToolCallF1()` already implemented.
+- `mux/verify/metrics.go` — `ToolCallF1()` already implemented.
- **Confirmed gap:** the `verify` package is referenced ONLY by its own tests.
It is not wired into any CLI, Makefile target, CI job, or provider-registration
gate. Only structural registry/parity tests are enforced.
-- flux already ships MiniMax providers (`minimax_token_plan`, `minimax_payg`)
+- mux already ships MiniMax providers (`minimax_token_plan`, `minimax_payg`)
as OpenAI-compatible adapters with `ThinkingFormat: "minimax"`.
- `client/structured.go` already has `ValidateStructuredOutput()` — a recursive
JSON-schema validator (`validateValue`, `validateObject`, `validateArray`)
@@ -43,7 +43,7 @@ internals produced these adoptions, ordered by value:
### What to implement
**A. Add a `SchemaValidate` helper (argument-level) — new file
-`flux/verify/schema.go`**
+`mux/verify/schema.go`**
Add `SchemaValidate(args map[string]any, schema map[string]any) error` that
checks tool-call arguments against the tool's `Parameters` JSON schema:
@@ -52,7 +52,7 @@ checks tool-call arguments against the tool's `Parameters` JSON schema:
This is the `ToolCalls-Schema-Accuracy` dimension from MiniMax-Provider-Verifier.
-**B. Add `MatchRate` to `Report` — edit `flux/verify/verify.go`**
+**B. Add `MatchRate` to `Report` — edit `mux/verify/verify.go`**
Compute the `ToolCalls-Match-Rate` (trigger-vs-stop correctness) alongside F1.
Extend `CaseResult` already has `ExpectedTool`/`CalledAnyTool`/`CorrectTool`, so
@@ -63,9 +63,9 @@ tool_calls_match_rate = (TP + TN) / expected_tool_call_total_count
mirroring MiniMax's confusion-matrix metric.
**C. Add a `verify` CLI entrypoint — new file
-`flux/cmd/verify/main.go`**
+`mux/cmd/verify/main.go`**
-A small `go run`-able binary (or a `verify` subcommand if flux has a cmd/) that
+A small `go run`-able binary (or a `verify` subcommand if mux has a cmd/) that
runs `verify.Run` against a provider endpoint (live or cassette) and exits
non-zero on unmet thresholds:
- `--model`, `--base-url`, `--api-key`, `--provider`
@@ -74,8 +74,8 @@ non-zero on unmet thresholds:
This makes the orphaned harness operational and enables CI gating.
-**D. Add a Makefile target + CI job — edit `flux/Makefile` and
-`flux/.github/workflows/ci.yml`**
+**D. Add a Makefile target + CI job — edit `mux/Makefile` and
+`mux/.github/workflows/ci.yml`**
- Makefile: `verify` target that runs the harness in cassette mode (no tokens)
and `verify-live` for manual live runs.
@@ -83,27 +83,27 @@ This makes the orphaned harness operational and enables CI gating.
on PRs, ensuring the harness is exercised and providers don't regress.
### Files
-- `flux/verify/schema.go` (new)
-- `flux/verify/schema_test.go` (new)
-- `flux/verify/verify.go` (add MatchRate)
-- `flux/verify/verify_test.go` (add tests)
-- `flux/cmd/verify/main.go` (new)
-- `flux/Makefile` (verify target)
-- `flux/.github/workflows/ci.yml` (verify job)
+- `mux/verify/schema.go` (new)
+- `mux/verify/schema_test.go` (new)
+- `mux/verify/verify.go` (add MatchRate)
+- `mux/verify/verify_test.go` (add tests)
+- `mux/cmd/verify/main.go` (new)
+- `mux/Makefile` (verify target)
+- `mux/.github/workflows/ci.yml` (verify job)
## 2. Curate MiniMax/skills content into starling
-### Verified current state (rho)
-- rho's skills system (`internal/plugin`) reads markdown+YAML-frontmatter skills
- from dirs (`~/.rho/skills`, `.claude/skills`, `.zero/skills`, `skills`) with a
- registry (`starling` repo, `rho skills search/install/list/remove`).
+### Verified current state (decoder)
+- decoder's skills system (`internal/plugin`) reads markdown+YAML-frontmatter skills
+ from dirs (`~/.decoder/skills`, `.claude/skills`, `.zero/skills`, `skills`) with a
+ registry (`starling` repo, `decoder skills search/install/list/remove`).
- MiniMax/skills (13.4k★) has 18 high-quality skills in the same format
(frontmatter `name`/`description`/`license`/`metadata`), especially
`frontend-dev`, `fullstack-dev`, `shader-dev`, mobile guides, `vision-analysis`.
### What to implement
- Port the best MiniMax skills into `GrayCodeAI/starling` (separate
- repo), adapting frontmatter to rho's convention (`globs`, `alwaysApply`).
+ repo), adapting frontmatter to decoder's convention (`globs`, `alwaysApply`).
- This is a content curation task in a separate repo; tracked here for
completeness but implemented as a follow-up PR in `starling`.
@@ -113,10 +113,10 @@ This makes the orphaned harness operational and enables CI gating.
## 3. MCP v2 no-network test pattern + image-source normalization
-### Verified current state (rho)
+### Verified current state (decoder)
- `internal/mcp` implements its own JSON-RPC client + server and does NOT use the
shared `falcon` scaffolding (architectural divergence).
-- rho has `internal/attachment/image.go` for image decode, and `ScreenshotTool`
+- decoder has `internal/attachment/image.go` for image decode, and `ScreenshotTool`
/ `BrowserTool`. No image-source (URL/file/data-URL) normalization helper.
- MiniMax-Coding-Plan-MCP shows: MCP v2 tool registration + no-network test
harness (in-process `Client` + stdio `ClientSession` asserting exact payloads)
@@ -135,8 +135,8 @@ This makes the orphaned harness operational and enables CI gating.
## 4. Jina page→Markdown browse extractor
-### Verified current state (rho)
-- rho has `WebSearchTool` (6-provider cascade: Brave/SearXNG/DeepSeek/Exa/
+### Verified current state (decoder)
+- decoder has `WebSearchTool` (6-provider cascade: Brave/SearXNG/DeepSeek/Exa/
Perplexity/DDG), `AgenticFetchTool`, `WebFetchTool`, `DownloadTool`,
`engine/search/url_scraper.go`.
- No lightweight "URL → Markdown" extractor (Jina Reader pattern).
@@ -155,14 +155,14 @@ This makes the orphaned harness operational and enables CI gating.
## 5. Agent-loop robustness patterns (reference)
-### Verified current state (rho)
-- rho's `Session.agentLoop` (`internal/engine/stream.go:133`) is a complete
+### Verified current state (decoder)
+- decoder's `Session.agentLoop` (`internal/engine/stream.go:133`) is a complete
think→act→observe loop with memory, 70+ tools, sub-agents, multi-agent.
- No cooperative-cancellation-with-history-cleanup, and long-session compaction
uses truncation rather than "summarize between user turns".
### What to implement (small, low-risk)
-- Add `_cleanup_incomplete_messages` equivalent to rho's loop: on cancellation
+- Add `_cleanup_incomplete_messages` equivalent to decoder's loop: on cancellation
at a safe checkpoint, trim the partial assistant message + orphaned tool
results so message history stays valid.
- Add a token-limit-driven lossy summarization option (keep user intents,
@@ -175,27 +175,27 @@ This makes the orphaned harness operational and enables CI gating.
## Out of scope (not adopted)
- MiniMax-MCP / MiniMax-MCP-JS: media generation (TTS/image/video) — no
- relevance to code intelligence; rho has no TTS and that is a product decision.
-- minimax_search's search layer: redundant (rho has more providers).
-- Mini-Agent's core loop: outclassed by rho.
+ relevance to code intelligence; decoder has no TTS and that is a product decision.
+- minimax_search's search layer: redundant (decoder has more providers).
+- Mini-Agent's core loop: outclassed by decoder.
- The `verify` harness's live-token path: optional, off by default.
## Execution order
-1. Flux verify metrics + schema validation + tests (highest value)
-2. Flux verify CLI + Makefile + CI wiring
-3. rho image-source normalization helper + tests
-4. rho Jina browse extractor + tests
+1. Mux verify metrics + schema validation + tests (highest value)
+2. Mux verify CLI + Makefile + CI wiring
+3. decoder image-source normalization helper + tests
+4. decoder Jina browse extractor + tests
5. Agent-loop cancellation/summarization patterns
6. starling content curation (follow-up PR in separate repo)
## Implementation status
-- [x] Flux schema-accuracy validation and tool-call match-rate metrics.
-- [x] Flux verification CLI, deterministic Makefile target, and CI job.
-- [x] Rho image-source normalization for data URIs, URLs, local files, and raw base64.
-- [x] Rho Jina Reader page-to-Markdown client with opt-in configuration and tests.
-- [x] Rho cancellation cleanup for incomplete assistant tool-use/tool-result turns.
-- [x] Confirmed rho's existing `internal/engine/compact` already provides token-triggered
+- [x] Mux schema-accuracy validation and tool-call match-rate metrics.
+- [x] Mux verification CLI, deterministic Makefile target, and CI job.
+- [x] Decoder image-source normalization for data URIs, URLs, local files, and raw base64.
+- [x] Decoder Jina Reader page-to-Markdown client with opt-in configuration and tests.
+- [x] Decoder cancellation cleanup for incomplete assistant tool-use/tool-result turns.
+- [x] Confirmed decoder's existing `internal/engine/compact` already provides token-triggered
compaction; no duplicate summarizer was added.
-- [ ] Publish the Flux repository changes through its own feature branch and PR.
+- [ ] Publish the Mux repository changes through its own feature branch and PR.
- [ ] Curate MiniMax skills into `starling` through its own feature branch and PR.
diff --git a/docs/plans/pi-adoption-plan.md b/docs/plans/pi-adoption-plan.md
index 280a150ad..54153c5e2 100644
--- a/docs/plans/pi-adoption-plan.md
+++ b/docs/plans/pi-adoption-plan.md
@@ -4,17 +4,17 @@ Status: Proposed
Source: `https://github.com/earendil-works/pi` (MIT, TypeScript/Bun monorepo)
-This plan records the features identified as genuinely missing from rho while
-auditing the Pi agent harness against Rho and its independent ecosystem
+This plan records the features identified as genuinely missing from decoder while
+auditing the Pi agent harness against Decoder and its independent ecosystem
repositories. It is
-an adoption plan, not a code-porting plan: rho reimplements compatible behavior
+an adoption plan, not a code-porting plan: decoder reimplements compatible behavior
in Go and preserves its existing provider, session, permission, observability,
-and protocol boundaries. Rho executes tools directly on the host; it does not
+and protocol boundaries. Decoder executes tools directly on the host; it does not
ship a product sandbox runtime.
## Executive Decision
-Rho should adopt the following Pi features:
+Decoder should adopt the following Pi features:
1. A Go telemetry conformance suite that verifies emitted OpenTelemetry spans
and attributes match the documented schema.
@@ -26,24 +26,24 @@ Rho should adopt the following Pi features:
5. Kitty graphics protocol support for terminal images.
6. Session lease/ownership semantics in the daemon protocol.
-Rho should not copy Pi's TypeScript code, replace its Go runtime, or adopt Pi's
+Decoder should not copy Pi's TypeScript code, replace its Go runtime, or adopt Pi's
custom CBOR RPC protocol. Its host-native permission and path/trust policy is
the local safety boundary.
-## Existing Rho Capabilities
+## Existing Decoder Capabilities
-The audit found that rho already provides the foundation for most Pi features:
+The audit found that decoder already provides the foundation for most Pi features:
-| Pi package | Rho implementation | Current decision |
+| Pi package | Decoder implementation | Current decision |
|---|---|---|
-| `pi-ai` (multi-provider) | sibling `flux` client + engine facade + catalog + router + credentials | Keep rho (broader) |
-| `pi-agent-core` (agent loop) | `internal/engine` | Keep rho |
-| `pi-coding-agent` (CLI) | `cmd` TUI + CLI + daemon | Keep rho |
-| `pi-session-backends` (storage) | `internal/session` JSONL + zstd + WAL + SQLite index, sibling `swift` (Swift) | Keep rho |
-| `pi-server` (RPC) | `internal/daemon` + `internal/acp` + `internal/mcp` | Keep rho (broader) |
-| Permissions and trust | `internal/engine/safety`, path guards, `internal/trust`, `internal/env` | Keep rho's host-native boundary |
+| `pi-ai` (multi-provider) | sibling `mux` client + engine facade + catalog + router + credentials | Keep decoder (broader) |
+| `pi-agent-core` (agent loop) | `internal/engine` | Keep decoder |
+| `pi-coding-agent` (CLI) | `cmd` TUI + CLI + daemon | Keep decoder |
+| `pi-session-backends` (storage) | `internal/session` JSONL + zstd + WAL + SQLite index, sibling `swift` (Swift) | Keep decoder |
+| `pi-server` (RPC) | `internal/daemon` + `internal/acp` + `internal/mcp` | Keep decoder (broader) |
+| Permissions and trust | `internal/engine/safety`, path guards, `internal/trust`, `internal/env` | Keep decoder's host-native boundary |
| `pi-tui` differential rendering | Bubble Tea v2 full-frame redraw | Adopt line-diff engine |
-| `pi-telemetry` conformance | `docs/OTEL-CONVENTIONS.md`, flux `genai_semconv` pinning | Adopt conformance suite |
+| `pi-telemetry` conformance | `docs/OTEL-CONVENTIONS.md`, mux `genai_semconv` pinning | Adopt conformance suite |
| `pi-evals` agent-level eval | `internal/features/eval` (model benchmark only) | Adopt agent-runtime eval |
## Priority Model
@@ -59,16 +59,16 @@ The audit found that rho already provides the foundation for most Pi features:
Guarantee the emitted OpenTelemetry spans and attributes always match the
documented `gen_ai.*` / `cost.usd` / `tool.name` / `session.id` / `agent.id`
-contract, so the schema cannot silently drift across Rho and its independent
+contract, so the schema cannot silently drift across Decoder and its independent
ecosystem repositories.
### Scope and ownership
- Primary implementation: `internal/observability` and
- `flux/internal/observability` (the canonical `genai_semconv`
+ `mux/internal/observability` (the canonical `genai_semconv`
constants and their pinning test).
- Shared schema constants: sibling `eagle` if a cross-repo
- contract is needed, otherwise keep them in flux as today.
+ contract is needed, otherwise keep them in mux as today.
- No changes to `internal/mcp` or `internal/daemon` for telemetry adoption.
### Required behavior
@@ -84,24 +84,24 @@ ecosystem repositories.
- asserts sensitive attributes never carry raw prompt/response text,
- asserts parent/child span relationships and settlement semantics,
- is runner-independent (usable from any Go test harness).
-4. Wire the conformance harness into the rho and flux test suites so CI
+4. Wire the conformance harness into the decoder and mux test suites so CI
enforces the contract.
5. Keep the conformance layer passive and non-throwing: malformed or unreadable
telemetry payloads must not break agent execution.
### Acceptance criteria
-- Every span rho emits is covered by the schema.
+- Every span decoder emits is covered by the schema.
- A deliberate schema drift (adding a span or attribute) fails the conformance
test until the schema is updated.
- No raw prompt/response text appears in recorded attributes.
-- The conformance harness runs green in rho and flux CI.
+- The conformance harness runs green in decoder and mux CI.
## P0: Agent-Runtime Eval Harness
### Goal
-Evaluate the full rho agent end-to-end (real session, tool loop, planning,
+Evaluate the full decoder agent end-to-end (real session, tool loop, planning,
host policy) against tasks, and snapshot session data as artifacts — not just a
model-level benchmark.
@@ -276,7 +276,7 @@ Every implementation phase must preserve:
- Eval runs the real tool loop end-to-end in an isolated dir.
- Daemon and ACP parity for leased sessions.
- fxtape recording/replay across the new renderer.
-- Cross-repo telemetry conformance in rho and flux CI.
+- Cross-repo telemetry conformance in decoder and mux CI.
### Security tests
@@ -294,11 +294,11 @@ make test-race
make vet
make lint
make security
-rho verify
+decoder verify
```
For sibling-repository changes, run that repository's own tests and boundary checks before
-updating the Rho pointer.
+updating the Decoder pointer.
## Delivery Sequence
@@ -313,7 +313,7 @@ updating the Rho pointer.
- [x] Define the typed span/attribute schema.
- [x] Implement the conformance harness.
-- [x] Wire rho and flux CI.
+- [x] Wire decoder and mux CI.
- [x] Add schema-drift regression tests.
### Milestone 2: Agent-runtime eval (P0)
@@ -321,7 +321,7 @@ updating the Rho pointer.
- [x] Implement the loop runner over the real Session/tool loop.
- [x] Add isolated execution and session-JSONL artifacts.
- [ ] Add comparative and reproducibility reporting.
-- [x] Extend `rho eval` with a loop mode.
+- [x] Extend `decoder eval` with a loop mode.
### Milestone 3: Differential renderer (P1)
@@ -347,19 +347,19 @@ updating the Rho pointer.
## Deliberately Deferred
- Copying Pi's TypeScript code or adopting its custom CBOR RPC protocol in place
- of rho's ACP/MCP/daemon stack.
-- Replacing rho's native permission/sandbox model with Pi's container-only
+ of decoder's ACP/MCP/daemon stack.
+- Replacing decoder's native permission/sandbox model with Pi's container-only
approach.
-- Porting Pi's extension system verbatim; rho's plugin/hook/skills model already
+- Porting Pi's extension system verbatim; decoder's plugin/hook/skills model already
covers it.
- Adding a full agent-swarm/graph model beyond current subagent support.
## Success Criteria
-The adoption is successful when rho closes each confirmed gap while retaining
+The adoption is successful when decoder closes each confirmed gap while retaining
its stronger architecture:
-- Telemetry spans always conform to the documented schema across rho and its
+- Telemetry spans always conform to the documented schema across decoder and its
sibling repositories.
- The agent can be evaluated end-to-end through its real tool loop.
- The TUI re-renders only changed lines with synchronized output.
diff --git a/docs/plans/pi-renderer-and-eval-reporting.md b/docs/plans/pi-renderer-and-eval-reporting.md
index 61bd6349c..44a8d813a 100644
--- a/docs/plans/pi-renderer-and-eval-reporting.md
+++ b/docs/plans/pi-renderer-and-eval-reporting.md
@@ -8,7 +8,7 @@ the three merged Pi PRs (#226, #227, #228).
## Executive Decision
Two of the three remaining sub-items are **blocked by the rendering stack** and
-cannot be adopted cleanly in rho's current UI framework:
+cannot be adopted cleanly in decoder's current UI framework:
- Bubble Tea v2 exposes **no public `Renderer` interface** (its renderer is an
unexported type with internal methods; the only option is `WithoutRenderer`).
@@ -28,13 +28,13 @@ reporting** — is fully feasible and safe (non-TUI) and is adopted here.
config) so identical runs can be cached and compared.
- Add a comparative report across runs/models: pass rate, token/latency/cost
deltas, and per-run reproducibility hash.
-- Wire it into the existing `evalloop` package and `rho eval loop` output.
+- Wire it into the existing `evalloop` package and `decoder eval loop` output.
### Scope and ownership
- Primary: `internal/features/evalloop`.
- CLI: `cmd/eval.go` loop mode.
-- No changes to a local sandbox runtime (none ships in rho), `internal/session`,
+- No changes to a local sandbox runtime (none ships in decoder), `internal/session`,
or `internal/daemon`.
### Required behavior
@@ -44,7 +44,7 @@ reporting** — is fully feasible and safe (non-TUI) and is adopted here.
result transcript.
3. A `Compare` helper aggregates multiple results and reports pass-rate and
per-metric deltas (tokens, cost, duration).
-4. `rho eval loop --report` prints the comparative summary.
+4. `decoder eval loop --report` prints the comparative summary.
### Acceptance criteria
@@ -65,6 +65,6 @@ reporting** — is fully feasible and safe (non-TUI) and is adopted here.
## Verification
- `go test ./...` full suite.
-- `make vet`, `make lint`, `rho verify`.
+- `make vet`, `make lint`, `decoder verify`.
- Focused `internal/features/evalloop` tests.
- markdownlint on this document.
diff --git a/docs/plans/qwen-code-adoption-plan.md b/docs/plans/qwen-code-adoption-plan.md
index 0f41d70eb..6a8b7b752 100644
--- a/docs/plans/qwen-code-adoption-plan.md
+++ b/docs/plans/qwen-code-adoption-plan.md
@@ -1,18 +1,18 @@
# Qwen Code Adoption Plan
-Status: Implemented selectively in the current Rho feature branch.
+Status: Implemented selectively in the current Decoder feature branch.
## Guardrails
-Qwen Code is Apache-2.0 TypeScript software with a Gemini-shaped core. Rho
-will independently reimplement behavioral contracts in Go, preserve the Flux
-provider boundary, and retain Rho's event-sourced sessions and OS sandbox.
+Qwen Code is Apache-2.0 TypeScript software with a Gemini-shaped core. Decoder
+will independently reimplement behavioral contracts in Go, preserve the Mux
+provider boundary, and retain Decoder's event-sourced sessions and OS sandbox.
No Qwen source or dependency is vendored.
-## Existing Rho Capabilities
+## Existing Decoder Capabilities
-Rho already has durable sessions, event logging, WAL/recovery, branching,
-review contracts, provider routing in Flux, MCP integration, skills, memory,
+Decoder already has durable sessions, event logging, WAL/recovery, branching,
+review contracts, provider routing in Mux, MCP integration, skills, memory,
context compaction, policy snapshots, subagents, daemon security, and
filesystem/process sandboxing. These systems will not be duplicated.
@@ -24,7 +24,7 @@ filesystem/process sandboxing. These systems will not be duplicated.
2. Added terminal reasons for permission denial, approval denial, unknown tool,
pipeline failure, timeout, cancellation, execution failure, and success.
3. Added regression coverage for the lifecycle contract.
-4. Preserved Rho's existing cancellation transcript cleanup and compaction.
+4. Preserved Decoder's existing cancellation transcript cleanup and compaction.
5. Preserved policy-snapshot inheritance and subagent cleanup already present.
6. Added explicit `StreamEvent` tool lifecycle state and terminal-reason fields,
with execution-path transitions and regression coverage.
@@ -47,7 +47,7 @@ filesystem/process sandboxing. These systems will not be duplicated.
### P2: Declarative extensibility
-- Map Markdown subagent frontmatter to Rho's typed SpawnRequest.
+- Map Markdown subagent frontmatter to Decoder's typed SpawnRequest.
- Add path-conditional skill activation and parse-error diagnostics.
- Add hot reload with bounded activation listeners.
- Scope child hooks and MCP resources by session/agent ID.
@@ -61,6 +61,6 @@ filesystem/process sandboxing. These systems will not be duplicated.
## Verification
- Focused lifecycle, skills, engine, and command tests.
-- Full Rho build, vet, and test suite.
+- Full Decoder build, vet, and test suite.
- Independent second verification pass.
- Final diff and sibling-repository status inspection.
diff --git a/docs/plans/tau-feature-parity.md b/docs/plans/tau-feature-parity.md
index 65edf68db..20082a9bb 100644
--- a/docs/plans/tau-feature-parity.md
+++ b/docs/plans/tau-feature-parity.md
@@ -1,17 +1,17 @@
-# Plan: bring Tau's feature set into Rho (Go)
+# Plan: bring Tau's feature set into Decoder (Go)
Status: in progress
-Branch: `feat/rename-rho`
+Branch: `feat/rename-decoder`
## Principle
-Tau's features must exist in Rho **without leaving Go**. Rho already has a
+Tau's features must exist in Decoder **without leaving Go**. Decoder already has a
superset of Tau's agent capabilities; this plan closes the specific gaps where
-Tau offers a documented feature Rho does not.
+Tau offers a documented feature Decoder does not.
-## Gap analysis (Tau feature → Rho status)
+## Gap analysis (Tau feature → Decoder status)
-| Tau feature | Rho status | Action |
+| Tau feature | Decoder status | Action |
|---|---|---|
| Interactive TUI | ✅ Bubble Tea TUI | none |
| `-p` print mode | ✅ `-p` | none |
@@ -20,13 +20,13 @@ Tau offers a documented feature Rho does not.
| Durable JSONL sessions + resume + branching | ✅ JSONL + DAG branching | none |
| Slash commands (login, model, sessions, compaction, export, theme) | ✅ `/login` added | none |
| `AGENTS.md` project instructions | ✅ | none |
-| `.tau/` project resources | ✅ `.rho/` | none |
+| `.tau/` project resources | ✅ `.decoder/` | none |
| `.agents/` shared resources | ✅ skills/providers/recipes/hooks/rules/workflows + `.agents/AGENTS.md` instructions | none |
| User skills, prompt templates, themes | ✅ | none |
| Context accounting + manual/auto compaction | ✅ | none |
| Provider-neutral output: text, JSON, transcript | ✅ text + json + stream-json + transcript | none |
-| `~/.tau/catalog.toml` custom providers/models, no code changes | ❌ missing | **flux-side** (see below) |
-| `tau update` | ✅ `rho update` | none |
+| `~/.tau/catalog.toml` custom providers/models, no code changes | ❌ missing | **mux-side** (see below) |
+| `tau update` | ✅ `decoder update` | none |
| Installers | ✅ `install.sh` | none |
## Work items
@@ -34,11 +34,11 @@ Tau offers a documented feature Rho does not.
1. ~~**`--cwd` global flag**~~ — done (`cmd/root.go`, applied to interactive, `-p`, and `exec`).
2. ~~**`/login` slash command**~~ — done (`cmd/chat_subcommand_login.go`).
3. ~~**`transcript` output format**~~ — done (`--output-format transcript`).
-4. **User catalog `~/.rho/catalog.toml`** — NOT implemented. The model catalog
- is owned by the flux engine (`github.com/GrayCodeAI/flux/catalog`), whose
+4. **User catalog `~/.decoder/catalog.toml`** — NOT implemented. The model catalog
+ is owned by the mux engine (`github.com/GrayCodeAI/mux/catalog`), whose
`LoadCatalogOptions` has no user-catalog override. Per `AGENTS.md`
- (provider/catalog ownership lives in flux), this must be added in flux and
- surfaced through the engine facade before rho can consume it.
+ (provider/catalog ownership lives in mux), this must be added in mux and
+ surfaced through the engine facade before decoder can consume it.
5. ~~**`.agents/` instruction resources**~~ — done (`.agents/AGENTS.md` is in
the instruction search path in `internal/config/config.go`).
@@ -50,5 +50,5 @@ Tau offers a documented feature Rho does not.
## Out of scope
-- Python/Textual port. Rho stays Go.
-- Removing Rho's larger feature surface.
\ No newline at end of file
+- Python/Textual port. Decoder stays Go.
+- Removing Decoder's larger feature surface.
\ No newline at end of file
diff --git a/docs/plans/toolbench-comparison-vs-top20.md b/docs/plans/toolbench-comparison-vs-top20.md
index 0463dce79..663111420 100644
--- a/docs/plans/toolbench-comparison-vs-top20.md
+++ b/docs/plans/toolbench-comparison-vs-top20.md
@@ -1,17 +1,17 @@
-# Toolbench Comparison: rho vs the Top-20 OSS Coding Agents (2026)
+# Toolbench Comparison: decoder vs the Top-20 OSS Coding Agents (2026)
> Status: analysis complete
-> Scope: built-in tool inventory of rho and the leading open-source coding agents
+> Scope: built-in tool inventory of decoder and the leading open-source coding agents
> Related issue: browser/screenshot automation gap
## Executive summary
-rho ships **69 built-in agent tools** — more than any top-20 OSS rival — and covers every capability category the leader board demands (file I/O, shell, web, search, memory, planning, MCP, sub-agents). The only genuine gaps versus the field are:
+decoder ships **69 built-in agent tools** — more than any top-20 OSS rival — and covers every capability category the leader board demands (file I/O, shell, web, search, memory, planning, MCP, sub-agents). The only genuine gaps versus the field are:
1. **Browser / computer-use automation** — now closed (see this plan's outcome).
-2. **IDE surfaces** — Cline/Continue/Zed are editor-native; rho remains terminal-first by design.
+2. **IDE surfaces** — Cline/Continue/Zed are editor-native; decoder remains terminal-first by design.
-rho's tool count exceeds the field (OpenCode ~10, Claude Code 18, Qwen Code ~26, Codex ~9+), but count alone is not the point: rho matches **Qwen Code** tool-for-tool *and* adds a spec/planning suite, persistent core memory, impact/codegraph/git tools, and an in-tree linter toolchain (`nilaway`, `revive`) that the others leave to MCP.
+decoder's tool count exceeds the field (OpenCode ~10, Claude Code 18, Qwen Code ~26, Codex ~9+), but count alone is not the point: decoder matches **Qwen Code** tool-for-tool *and* adds a spec/planning suite, persistent core memory, impact/codegraph/git tools, and an in-tree linter toolchain (`nilaway`, `revive`) that the others leave to MCP.
## Top-20 OSS coding agents by tool surface (2026 star snapshots)
@@ -19,7 +19,7 @@ Star counts are approximate (GitHub, ~July 2026): OpenCode ~172k, Gemini CLI ~99
| Agent | Built-in tools | Categories covered |
|---|---|---|
-| rho | **69** (+Power, +MCP) | all |
+| decoder | **69** (+Power, +MCP) | all |
| Qwen Code | 26 + computer_use | all; computer use, cron, worktree |
| Claude Code | 18 | all; notebook_edit, skills, hooks |
| Kilo Code | ~15 + Playwright MCP | all + browser via MCP |
@@ -36,7 +36,7 @@ Star counts are approximate (GitHub, ~July 2026): OpenCode ~172k, Gemini CLI ~99
| Continue | ~10 | editor |
| Plandex | ~5 | planning + git |
-## rho's current tool set
+## decoder's current tool set
See `cmd/chat_tools.go` for the registry construction.
@@ -48,23 +48,23 @@ Spec/planning suite (`plan`, `spec_*`, `approve_implementation`, `clarify`, `con
## The browser gap and how it was closed
-Every browser-native competitor drives a real browser: Cline bundles Puppeteer, Kilo bundles the Playwright MCP server, Codex CLI ships a Chrome extension + in-app browser, Qwen Code exposes `computer_use_*`, OpenManus embeds browser/crawl4ai. rho previously had only file/shell/web tools.
+Every browser-native competitor drives a real browser: Cline bundles Puppeteer, Kilo bundles the Playwright MCP server, Codex CLI ships a Chrome extension + in-app browser, Qwen Code exposes `computer_use_*`, OpenManus embeds browser/crawl4ai. decoder previously had only file/shell/web tools.
-**Outcome:** added `internal/tool/browser.go` and `internal/tool/screenshot.go`, exposed through rho's existing `tool.Tool` interface:
+**Outcome:** added `internal/tool/browser.go` and `internal/tool/screenshot.go`, exposed through decoder's existing `tool.Tool` interface:
- `BrowserTool` — headless-Chrome CDP driver with actions `navigate`, `content` (text/HTML, selector-scoped), `screenshot`, `click`, `type` (with clear), `title`, `location`, `close`. Risk level `high`; URL scheme validation restricts to `http(s)` (localhost/LAN included).
- `ScreenshotTool` — single-shot full-page PNG capture to a path (defaults to a temp file).
-Implementation uses `github.com/chromedp/chromedp` v0.16.0, the canonical pure-Go Chrome DevTools client, and reuses rho's existing `validatePathAllowed` guard for the output path. A lazily-allocated, mutex-guarded browser process is shared across calls (closed via `Browser … action:"close"` or `releaseBrowser()` in tests).
+Implementation uses `github.com/chromedp/chromedp` v0.16.0, the canonical pure-Go Chrome DevTools client, and reuses decoder's existing `validatePathAllowed` guard for the output path. A lazily-allocated, mutex-guarded browser process is shared across calls (closed via `Browser … action:"close"` or `releaseBrowser()` in tests).
-A live end-to-end test (`TestBrowserLive`, opt-in via `RHO_LIVE_BROWSER=1`) navigates `example.com`, captures a screenshot, and reads the page title against a real Chrome install — it passes.
+A live end-to-end test (`TestBrowserLive`, opt-in via `DECODER_LIVE_BROWSER=1`) navigates `example.com`, captures a screenshot, and reads the page title against a real Chrome install — it passes.
## Category parity vs the field
-| Category | rho | Field leaders |
+| Category | decoder | Field leaders |
|---|---|---|
-| File ops | read/write/edit/structured/multi/notebook (Go) | Claude Code/Qwen have notebook_edit; rho has it |
-| Search | grep/glob/ls + LSP + code_search/code_graph | OpenCode LSP; rho code_graph exceeds |
+| File ops | read/write/edit/structured/multi/notebook (Go) | Claude Code/Qwen have notebook_edit; decoder has it |
+| Search | grep/glob/ls + LSP + code_search/code_graph | OpenCode LSP; decoder code_graph exceeds |
| Shell | bash (+PowerShell on Windows) + monitor/kill/wait | all |
| Web | web_fetch/web_search/agentic_fetch/download | all |
| Memory | **persistent core_memory_\* (Harrier)** | only Qwen/Claude have persistence |
@@ -77,10 +77,10 @@ A live end-to-end test (`TestBrowserLive`, opt-in via `RHO_LIVE_BROWSER=1`) navi
## Remaining deltas (out of scope here)
- VS Code / JetBrains extension (planned in `docs/IMPLEMENTATION-ROADMAP.md`).
-- Auto-commit-per-edit discipline à la Aider (rho uses AGENTS.md branch rules instead).
+- Auto-commit-per-edit discipline à la Aider (decoder uses AGENTS.md branch rules instead).
## Verification
- `go build ./internal/tool/... ./cmd/...` — clean after adding the tools.
-- `go test ./internal/tool/` — unit tests pass; live browser test passes with `RHO_LIVE_BROWSER=1`.
+- `go test ./internal/tool/` — unit tests pass; live browser test passes with `DECODER_LIVE_BROWSER=1`.
- `/tools` REPL command now reports essential/optional breakdown (enhanced in this change; see `cmd/diagnostics.go`).
diff --git a/docs/platform-capabilities.json b/docs/platform-capabilities.json
index df481c4fb..36b054bb9 100644
--- a/docs/platform-capabilities.json
+++ b/docs/platform-capabilities.json
@@ -136,6 +136,6 @@
]
},
"ecosystem_compatibility": {
- "rho+flux": "full"
+ "decoder+mux": "full"
}
}
diff --git a/docs/plugin-development.md b/docs/plugin-development.md
index 99b2d1886..753a14909 100644
--- a/docs/plugin-development.md
+++ b/docs/plugin-development.md
@@ -2,10 +2,10 @@
## Overview
-Rho supports three plugin types:
+Decoder supports three plugin types:
1. **Simple plugins** — shell scripts with a `plugin.json` manifest. Tools are executed as one-shot subprocesses via stdin/stdout.
-2. **Managed subprocess plugins** — binary executables managed by `PluginManager`. Supports security scanning, timeout enforcement, and auto-discovery from `~/.rho/plugins/`.
+2. **Managed subprocess plugins** — binary executables managed by `PluginManager`. Supports security scanning, timeout enforcement, and auto-discovery from `~/.decoder/plugins/`.
3. **Daemon plugins** — long-lived processes communicating via JSON-RPC 2.0 over stdin/stdout. Managed by `DynamicPluginManager` with full lifecycle (Discover → Load → Activate → Failed/Disabled).
## Plugin Manifest
@@ -51,7 +51,7 @@ For hooks, daemon mode, dependencies, and configuration:
#### Hook priority
-Hooks can specify `priority` (higher runs first). Event data is passed as environment variables (`RHO_EVENT=file.write`, `RHO_FILE_PATH=/path/to/file`).
+Hooks can specify `priority` (higher runs first). Event data is passed as environment variables (`DECODER_EVENT=file.write`, `DECODER_FILE_PATH=/path/to/file`).
#### Daemon mode
@@ -59,7 +59,7 @@ Set `"mode": "daemon"` with `"entrypoint": "./my-daemon"`. The daemon receives J
## Skills
-Skills are Markdown files with YAML frontmatter placed in `.rho/skills//SKILL.md`:
+Skills are Markdown files with YAML frontmatter placed in `.decoder/skills//SKILL.md`:
```yaml
---
@@ -81,7 +81,7 @@ Skill instructions here using markdown...
- **Auto-invoke**: Skills with `auto-invoke: true` and matching path/context globs are automatically activated.
- **Chaining**: Skills can declare `chain.before` and `chain.after` for ordered execution.
- **References**: Use `@ref(path/to/doc.md)` to reference supporting documents within a skill.
-- **Cross-agent compatibility**: Skills follow the Agent Skills spec (agentskills.io) and work with rho, Claude Code, and Codex.
+- **Cross-agent compatibility**: Skills follow the Agent Skills spec (agentskills.io) and work with decoder, Claude Code, and Codex.
## Event Hooks
@@ -89,27 +89,27 @@ Available events for plugin and skill hooks:
| Event | Data | Description |
|-------|------|-------------|
-| `session.start` | `RHO_SESSION_ID` | Session began |
-| `session.end` | `RHO_SESSION_ID`, `RHO_DURATION_MS` | Session ended |
-| `turn.start` | `RHO_TURN_NUM` | Agent turn started |
-| `turn.end` | `RHO_TURN_NUM`, `RHO_TOOL_COUNT` | Agent turn ended |
-| `tool_call.start` | `RHO_TOOL_NAME`, `RHO_TOOL_INPUT` | Tool execution started |
-| `tool_call.end` | `RHO_TOOL_NAME`, `RHO_TOOL_RESULT` | Tool execution finished |
-| `tool_call.error` | `RHO_TOOL_NAME`, `RHO_ERROR` | Tool execution failed |
-| `file.read` | `RHO_FILE_PATH` | File was read |
-| `file.write` | `RHO_FILE_PATH` | File was written |
-| `file.edit` | `RHO_FILE_PATH` | File was edited |
-| `file.delete` | `RHO_FILE_PATH` | File was deleted |
-| `compaction.start` | `RHO_COMPACTION_REASON` | Context compaction began |
-| `compaction.end` | `RHO_COMPACTION_NEW_LENGTH` | Context compaction finished |
-| `budget.warning` | `RHO_BUDGET_USAGE_PCT` | Token/cost budget warning |
-| `budget.exceeded` | `RHO_BUDGET_TYPE` | Budget exceeded (hard stop) |
-| `error.occurred` | `RHO_ERROR_TYPE` | Error occurred |
-| `error.recovered` | `RHO_RECOVERY_STRATEGY` | Error was recovered |
-| `model.switch` | `RHO_NEW_MODEL` | Active model changed |
-| `provider.switch` | `RHO_NEW_PROVIDER` | Active provider changed |
-| `user.input` | `RHO_USER_MESSAGE` | User sent a message |
-| `agent.response` | `RHO_RESPONSE_LENGTH` | Agent generated a response |
+| `session.start` | `DECODER_SESSION_ID` | Session began |
+| `session.end` | `DECODER_SESSION_ID`, `DECODER_DURATION_MS` | Session ended |
+| `turn.start` | `DECODER_TURN_NUM` | Agent turn started |
+| `turn.end` | `DECODER_TURN_NUM`, `DECODER_TOOL_COUNT` | Agent turn ended |
+| `tool_call.start` | `DECODER_TOOL_NAME`, `DECODER_TOOL_INPUT` | Tool execution started |
+| `tool_call.end` | `DECODER_TOOL_NAME`, `DECODER_TOOL_RESULT` | Tool execution finished |
+| `tool_call.error` | `DECODER_TOOL_NAME`, `DECODER_ERROR` | Tool execution failed |
+| `file.read` | `DECODER_FILE_PATH` | File was read |
+| `file.write` | `DECODER_FILE_PATH` | File was written |
+| `file.edit` | `DECODER_FILE_PATH` | File was edited |
+| `file.delete` | `DECODER_FILE_PATH` | File was deleted |
+| `compaction.start` | `DECODER_COMPACTION_REASON` | Context compaction began |
+| `compaction.end` | `DECODER_COMPACTION_NEW_LENGTH` | Context compaction finished |
+| `budget.warning` | `DECODER_BUDGET_USAGE_PCT` | Token/cost budget warning |
+| `budget.exceeded` | `DECODER_BUDGET_TYPE` | Budget exceeded (hard stop) |
+| `error.occurred` | `DECODER_ERROR_TYPE` | Error occurred |
+| `error.recovered` | `DECODER_RECOVERY_STRATEGY` | Error was recovered |
+| `model.switch` | `DECODER_NEW_MODEL` | Active model changed |
+| `provider.switch` | `DECODER_NEW_PROVIDER` | Active provider changed |
+| `user.input` | `DECODER_USER_MESSAGE` | User sent a message |
+| `agent.response` | `DECODER_RESPONSE_LENGTH` | Agent generated a response |
## Security
@@ -123,16 +123,16 @@ All plugins are scanned on install for:
1. Push your plugin to a public GitHub repository.
2. The registry index (maintained at `starling/registry.json`) is periodically refreshed.
-3. Users discover plugins via `rho plugin search `.
-4. Users install via `rho plugin install `.
+3. Users discover plugins via `decoder plugin search `.
+4. Users install via `decoder plugin install `.
5. Registry installation includes automatic audit and security scanning.
## Local Development
```bash
# Create a plugin directory
-mkdir -p ~/.rho/plugins/my-plugin
-cd ~/.rho/plugins/my-plugin
+mkdir -p ~/.decoder/plugins/my-plugin
+cd ~/.decoder/plugins/my-plugin
# Create a manifest
cat > plugin.json << 'EOF'
@@ -147,14 +147,14 @@ cat > plugin.json << 'EOF'
EOF
# List installed plugins
-rho plugin list
+decoder plugin list
# Run a plugin command
-rho plugin exec my-plugin hello
+decoder plugin exec my-plugin hello
# Create a skill (project-local)
-mkdir -p .rho/skills/my-skill
-cat > .rho/skills/my-skill/SKILL.md << 'EOF'
+mkdir -p .decoder/skills/my-skill
+cat > .decoder/skills/my-skill/SKILL.md << 'EOF'
---
name: my-skill
description: My first skill
@@ -165,4 +165,4 @@ EOF
## Feedback and Learning
-Users can rate skills (1–5 stars) using `/skill rate `. Ratings are stored in `~/.rho/feedback.json` and used by the `/learn` command to recommend skills based on project signals.
+Users can rate skills (1–5 stars) using `/skill rate `. Ratings are stored in `~/.decoder/feedback.json` and used by the `/learn` command to recommend skills based on project signals.
diff --git a/docs/session-decomposition.md b/docs/session-decomposition.md
index a9ca457b1..9de93578d 100644
--- a/docs/session-decomposition.md
+++ b/docs/session-decomposition.md
@@ -6,11 +6,11 @@
> into their owning services.
> Author: opencode session
> Date: 2026-06-12
-> Scope: `rho/internal/engine/session.go` (the 35-collaborator `Session` struct)
+> Scope: `decoder/internal/engine/session.go` (the 35-collaborator `Session` struct)
## Problem
-`Session` at `rho/internal/engine/session.go:42-141` is a god object:
+`Session` at `decoder/internal/engine/session.go:42-141` is a god object:
- 35 fields, ~30 of them `*T` pointer collaborators with optional behavior
- Every new feature adds a field (Beliefs, Critic, Trajectory, Steering, etc.)
@@ -84,13 +84,13 @@ backends without an explicit migration and recovery decision.
**Owns:** `client ChatClient`, `provider string`, `model string`, `apiKeys map[string]string`, `Router *modelPkg.Router`, `DeploymentRouting bool`, `RateLimiter *ratelimit.Limiter`, `OutputSchema string`, `GLMThinkingEnabled *bool`, `ContCfg types.ContinuationConfig`, `ChatOptions{}` builder.
**Methods:**
-- `BuildOptions(systemPrompt string, tools []client.FluxTool, activeModel string, maxTokens int) types.ChatOptions`
-- `Chat(ctx, msgs, opts) (*types.FluxResponse, error)` — non-streaming, used by background goroutines
+- `BuildOptions(systemPrompt string, tools []client.MuxTool, activeModel string, maxTokens int) types.ChatOptions`
+- `Chat(ctx, msgs, opts) (*types.MuxResponse, error)` — non-streaming, used by background goroutines
- `Stream(ctx, msgs, opts) (*types.StreamResult, error)` — with retry, circuit-breaker record, rate-limit wait
- `RecordSuccess(latency time.Duration)` / `RecordFailure(err error)`
- `BuildContinuationConfig() types.ContinuationConfig`
-**File:** `rho/internal/engine/chat_service.go` (~150 LOC)
+**File:** `decoder/internal/engine/chat_service.go` (~150 LOC)
### 2. `MemoryService` — owns memory recall/remember
@@ -99,12 +99,12 @@ backends without an explicit migration and recovery decision.
**Methods:**
- `RecallContext(ctx, lastUserMsg string, budget int) string` — unifies backend recall behind one nil-safe call
- `Remember(ctx, content, category string)` — wraps memory.Remember
-- `RunSleeptimeConsolidation(ctx, provider ChatService, messages []types.FluxMessage)` — background
+- `RunSleeptimeConsolidation(ctx, provider ChatService, messages []types.MuxMessage)` — background
- `RunSkillDistillation(ctx, provider ChatService, ...)` — background
- `RecordFeedback(ctx, content string, action string)` — wraps EnhancedMemory feedback
- `ShouldRemember(text string) bool` — heuristic for auto-remember
-**File:** `rho/internal/engine/memory_service.go` (~200 LOC)
+**File:** `decoder/internal/engine/memory_service.go` (~200 LOC)
### 3. `ToolService` — owns the registry + tool execution
@@ -117,7 +117,7 @@ backends without an explicit migration and recovery decision.
- `SpawnBackgroundAgent(ctx, prompt string) (id string, err error)`
- `PollBackgroundAgent(id string) (output string, done bool, err error)`
-**File:** `rho/internal/engine/tool_service.go` (~400 LOC — biggest, owns the 15-stage pipeline)
+**File:** `decoder/internal/engine/tool_service.go` (~400 LOC — biggest, owns the 15-stage pipeline)
### 4. `PermissionService` — owns the safety layer
@@ -131,7 +131,7 @@ backends without an explicit migration and recovery decision.
- `SetMode(mode string) error` — validates + applies
- `SetMaxTurns(n int)`, `SetMaxBudgetUSD(usd float64)`
-**File:** `rho/internal/engine/permission_service.go` (~150 LOC)
+**File:** `decoder/internal/engine/permission_service.go` (~150 LOC)
### 5. `LifecycleService` — owns the self-improvement loop
@@ -139,16 +139,16 @@ backends without an explicit migration and recovery decision.
**Methods:**
- `OnSessionStart(ctx, lastUserMsg string) (learnedCtx string)`
-- `OnSessionEnd(ctx, success bool, duration time.Duration, messages []types.FluxMessage)`
+- `OnSessionEnd(ctx, success bool, duration time.Duration, messages []types.MuxMessage)`
- `SelectModel(taskType, currentModel, hint string) string` — wraps Cascade
-- `OnToolFailure(ctx, intent string, history []types.FluxMessage, errOutput string) (*Reflection, error)`
-- `RecordDecision(turn int, toolNames string, msgs []types.FluxMessage)`
+- `OnToolFailure(ctx, intent string, history []types.MuxMessage, errOutput string) (*Reflection, error)`
+- `RecordDecision(turn int, toolNames string, msgs []types.MuxMessage)`
- `CheckLimits(turnCount int) (cont bool, reason string)` — wraps Limits
- `RecordTurn(turn int)`, `RecordToolCall(name string)`
- `DetectDoomLoop(steps []ToolStep) bool`
-- `InjectSteering(messages []types.FluxMessage) []types.FluxMessage`
+- `InjectSteering(messages []types.MuxMessage) []types.MuxMessage`
-**File:** `rho/internal/engine/lifecycle_service.go` (~250 LOC)
+**File:** `decoder/internal/engine/lifecycle_service.go` (~250 LOC)
### 6. `PersistenceService` — owns checkpoint and session state
@@ -161,13 +161,13 @@ backends without an explicit migration and recovery decision.
- `AddUser(content string)`, `AddAssistant(content string)`, `AddUserWithImage(...)`, `AddUserWithAttachment(...)`
- `AddUserWithDocumentText(content, label, extracted string)`
- `AppendSystemContext(content string)`, `ReplaceSystemContextSection(header, content string)`
-- `Messages() []types.FluxMessage`, `RawMessages()`, `MessageCount()`, `LoadMessages([]types.FluxMessage)`
+- `Messages() []types.MuxMessage`, `RawMessages()`, `MessageCount()`, `LoadMessages([]types.MuxMessage)`
- `RemoveLastExchange()`
- `ConvoHead() string`, `ForkConversation(nodeID string) (string, error)`, `SwitchBranch(nodeID string) error`, `ListBranches(nodeID string) ([]*storage.DAGNode, error)`
- `CheckpointOnCompaction(strategy string, before, after int, manual bool)`
- `TokenTracking() (prompt, completion int)`, `RecordAPIUsage(prompt, completion int)`
-**File:** `rho/internal/engine/persistence_service.go` (~300 LOC)
+**File:** `decoder/internal/engine/persistence_service.go` (~300 LOC)
## What stays on `Session`
@@ -222,7 +222,7 @@ func (s *Session) agentLoop(ctx context.Context, ch chan<- StreamEvent) {
for turn := 0; ; turn++ {
if !s.Lifecycle.CheckLimits(turn) { return }
- opts := s.Chat.BuildOptions(s.system, s.Tools.Registry().FluxTools(), activeModel, maxTok)
+ opts := s.Chat.BuildOptions(s.system, s.Tools.Registry().MuxTools(), activeModel, maxTok)
result, err := s.Chat.Stream(ctx, s.Persistence.Messages(), opts)
if err != nil { /* error path */ }
defer result.Close()
@@ -256,7 +256,7 @@ The loop body shrinks from 800 lines to ~250 because:
3. **Phase 3**: extract `MemoryService` (most fields, but only consumed in the preamble/postamble of `agentLoop`).
4. **Phase 4**: extract `PermissionService` (smallest surface).
5. **Phase 5**: extract `LifecycleService` (biggest behavioral surface, but mostly reads `messages` and `tools`).
-6. **Phase 6**: extract `PersistenceService` (last because it owns the `messages []types.FluxMessage` field which is touched everywhere).
+6. **Phase 6**: extract `PersistenceService` (last because it owns the `messages []types.MuxMessage` field which is touched everywhere).
7. **Phase 7**: extract `ToolService` (depends on 4, 5; do last).
8. **Phase 8**: delete fields from `Session`, add backwards-compatible shims that delegate to the new services, mark for removal in v0.2.0.
diff --git a/docs/terminal-icons.md b/docs/terminal-icons.md
index 4b76ab924..7bc837df5 100644
--- a/docs/terminal-icons.md
+++ b/docs/terminal-icons.md
@@ -1,6 +1,6 @@
# Terminal icons
-Rho uses current Nerd Font Codicon glyphs for interactive terminal output.
+Decoder uses current Nerd Font Codicon glyphs for interactive terminal output.
The application does not try to infer the installed font from `TERM`: terminal
names do not report the active font, and guessing can produce tiny fallback
boxes or missing glyphs.
@@ -10,14 +10,14 @@ Interactive TTYs use Nerd Font icons by default. Captured output, CI, and
```bash
# Real icons (requires a Nerd Font configured in the terminal profile)
-RHO_ICONS=nerd ./bin/rho
+DECODER_ICONS=nerd ./bin/decoder
# Portable text-only output
-RHO_ICONS=ascii ./bin/rho
+DECODER_ICONS=ascii ./bin/decoder
```
-For the real icons, configure the terminal profile—not Rho's Go code—with a
+For the real icons, configure the terminal profile—not Decoder's Go code—with a
patched font such as `JetBrainsMono Nerd Font` or `Symbols Nerd Font Mono`.
-Font size and glyph scale are controlled by that profile. Rho applies bold
+Font size and glyph scale are controlled by that profile. Decoder applies bold
weight to status icons for contrast, but there is no portable ANSI escape that
can resize one glyph independently of the surrounding text.
diff --git a/docs/troubleshooting-guide.md b/docs/troubleshooting-guide.md
index 1b6ed3168..c2d32bca8 100644
--- a/docs/troubleshooting-guide.md
+++ b/docs/troubleshooting-guide.md
@@ -1,6 +1,6 @@
# Troubleshooting Guide
-A practical guide for diagnosing common rho daemon and CLI issues.
+A practical guide for diagnosing common decoder daemon and CLI issues.
## Table of Contents
@@ -29,27 +29,27 @@ because the auth middleware would be open to the network.
**Fix:** Set an API key:
```bash
-export RHO_DAEMON_API_KEY=$(openssl rand -base64 32)
-rho daemon start --host 0.0.0.0 --port 4590
+export DECODER_DAEMON_API_KEY=$(openssl rand -base64 32)
+decoder daemon start --host 0.0.0.0 --port 4590
```
Or bind to loopback only (no API key required, but not remotely accessible):
```bash
-rho daemon start --host 127.0.0.1 --port 4590
+decoder daemon start --host 127.0.0.1 --port 4590
```
### "permission denied" on state directory
-The daemon writes logs, PID files, and the audit log to `~/.rho/state/`.
+The daemon writes logs, PID files, and the audit log to `~/.decoder/state/`.
**Fix:**
```bash
-mkdir -p ~/.rho/state
-chmod 750 ~/.rho/state
-# If running under systemd as user 'rho', ensure ownership:
-chown -R rho:rho ~/.rho
+mkdir -p ~/.decoder/state
+chmod 750 ~/.decoder/state
+# If running under systemd as user 'decoder', ensure ownership:
+chown -R decoder:decoder ~/.decoder
```
### "port already in use"
@@ -63,7 +63,7 @@ Another process is using port 4590.
lsof -i :4590
# Or use a different port
-rho daemon start --port 4591
+decoder daemon start --port 4591
```
---
@@ -72,7 +72,7 @@ rho daemon start --port 4591
### `GET /v1/ready` returns 503
-The readiness probe fails when Flux's local preflight doesn't pass. This
+The readiness probe fails when Mux's local preflight doesn't pass. This
checks provider state, catalog, credentials, and model selection.
**Diagnosis:**
@@ -83,9 +83,9 @@ curl -v http://localhost:4590/v1/ready
Check the response body for the specific failed check. Common causes:
-- No model configured — set `RHO_MODEL` or provider credentials.
-- Flux catalog not initialized — the Go modules are independent sibling
- repositories; from a full parent workspace, run `make setup` in rho to
+- No model configured — set `DECODER_MODEL` or provider credentials.
+- Mux catalog not initialized — the Go modules are independent sibling
+ repositories; from a full parent workspace, run `make setup` in decoder to
regenerate the parent `go.work`:
```bash
make setup
@@ -102,11 +102,11 @@ failed to start.
```bash
# Check if the process is running
-ps aux | grep rho
+ps aux | grep decoder
# Check logs
-journalctl -u rho-daemon -n 50
-tail -50 ~/.rho/state/daemon.log
+journalctl -u decoder-daemon -n 50
+tail -50 ~/.decoder/state/daemon.log
```
---
@@ -120,7 +120,7 @@ The daemon requires `Authorization: Bearer ` or `X-API-Key: `.
**Fix:**
```bash
-curl -H "X-API-Key: $RHO_DAEMON_API_KEY" http://localhost:4590/v1/stats
+curl -H "X-API-Key: $DECODER_DAEMON_API_KEY" http://localhost:4590/v1/stats
```
### "constant time comparison" errors in logs
@@ -131,16 +131,16 @@ No action needed.
### Forgotten API key
-The API key is written to `~/.rho/state/daemon.key` (permissions 0600).
+The API key is written to `~/.decoder/state/daemon.key` (permissions 0600).
```bash
-cat ~/.rho/state/daemon.key
+cat ~/.decoder/state/daemon.key
```
**Security note:** Remove this file in production after initial testing:
```bash
-rm ~/.rho/state/daemon.key
+rm ~/.decoder/state/daemon.key
```
---
@@ -152,7 +152,7 @@ your request. The default limits are:
- **General API**: 10 req/min, burst 4
- **Chat**: 30 req/min, burst 6
-- **Concurrent chat sessions**: 4 (configurable via `RHO_DAEMON_MAX_CONCURRENT`)
+- **Concurrent chat sessions**: 4 (configurable via `DECODER_DAEMON_MAX_CONCURRENT`)
**Fix:**
@@ -170,7 +170,7 @@ your request. The default limits are:
CORS is **disabled by default**. Enable it when serving browser-based clients:
```bash
-rho daemon start --cors https://app.example.com --cors https://admin.example.com
+decoder daemon start --cors https://app.example.com --cors https://admin.example.com
```
Use `--cors '*'` only for development — it allows any origin.
@@ -181,7 +181,7 @@ The CORS middleware handles OPTIONS preflight automatically when the `cors`
feature flag is enabled. If you're getting 405, ensure CORS is enabled:
```bash
-export RHO_FEATURE_CORS=1
+export DECODER_FEATURE_CORS=1
```
---
@@ -197,7 +197,7 @@ mode) or when the engine is not ready (daemon mode).
curl http://localhost:4590/v1/ready
```
-If readiness fails, the session factory exists but Flux preflight is not
+If readiness fails, the session factory exists but Mux preflight is not
satisfied (missing model, credentials, etc.).
---
@@ -210,7 +210,7 @@ The metrics endpoint is protected by the same API key authentication as other
endpoints.
```bash
-curl -H "X-API-Key: $RHO_DAEMON_API_KEY" http://localhost:4590/v1/metrics
+curl -H "X-API-Key: $DECODER_DAEMON_API_KEY" http://localhost:4590/v1/metrics
```
### Metrics output is empty
@@ -226,7 +226,7 @@ Prometheus version supports this format (Prometheus 2.20+).
For troubleshooting, try the JSON format:
```bash
-curl -H "X-API-Key: $RHO_DAEMON_API_KEY" \
+curl -H "X-API-Key: $DECODER_DAEMON_API_KEY" \
"http://localhost:4590/v1/metrics?format=json"
```
@@ -239,13 +239,13 @@ curl -H "X-API-Key: $RHO_DAEMON_API_KEY" \
Telemetry is **opt-in**. You must explicitly enable it:
```bash
-export RHO_ENABLE_TELEMETRY=1
+export DECODER_ENABLE_TELEMETRY=1
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
-rho daemon start
+decoder daemon start
```
**Important**: Setting `OTEL_EXPORTER_OTLP_ENDPOINT` alone does **not**
-enable telemetry. The `RHO_ENABLE_TELEMETRY=1` flag is required.
+enable telemetry. The `DECODER_ENABLE_TELEMETRY=1` flag is required.
### "telemetry initialization failed" warning in logs
@@ -264,7 +264,7 @@ curl -v http://localhost:4318/v1/traces
The OTel SDK uses a batch span processor with a 5-second flush interval.
On shutdown, the daemon waits up to 2 seconds (configurable via
-`RHO_OTEL_SHUTDOWN_TIMEOUT_MS`) to flush pending spans.
+`DECODER_OTEL_SHUTDOWN_TIMEOUT_MS`) to flush pending spans.
To force a flush, send SIGTERM to the daemon — it will flush telemetry
before shutting down.
@@ -275,25 +275,25 @@ before shutting down.
### Security log won't open
-The audit log is stored in `~/.rho/state/securitylog/`. If the directory
+The audit log is stored in `~/.decoder/state/securitylog/`. If the directory
doesn't exist or isn't writable:
```bash
-mkdir -p ~/.rho/state/securitylog
-chmod 700 ~/.rho/state/securitylog
+mkdir -p ~/.decoder/state/securitylog
+chmod 700 ~/.decoder/state/securitylog
```
### "log tail does not match head pointer (truncated or tampered)"
This error means the security log has been modified or truncated. The
tamper-evident design detected an inconsistency. Restore from a backup
-of the `~/.rho/state/securitylog/` directory.
+of the `~/.decoder/state/securitylog/` directory.
### Lost the HMAC key
The HMAC key (`sel.key`) is required to verify the audit log. If it's
lost, all entries become unverifiable. **Always back up the entire
-`~/.rho/state/securitylog/` directory.**
+`~/.decoder/state/securitylog/` directory.**
---
@@ -312,13 +312,13 @@ audit log for the `denied` event type.
1. Check the metrics endpoint for request duration:
```bash
- curl -H "X-API-Key: $RHO_DAEMON_API_KEY" \
+ curl -H "X-API-Key: $DECODER_DAEMON_API_KEY" \
"http://localhost:4590/v1/metrics?format=json"
```
-2. Check concurrent sessions: `rho_daemon_chat_concurrency_used`
+2. Check concurrent sessions: `decoder_daemon_chat_concurrency_used`
3. If at capacity, increase the concurrency limit:
```bash
- export RHO_DAEMON_MAX_CONCURRENT=8
+ export DECODER_DAEMON_MAX_CONCURRENT=8
```
### High memory usage
@@ -334,41 +334,41 @@ large contexts can consume significant memory. Consider:
## Systemd Issues
-### "Failed to start rho-daemon.service: Unit not found"
+### "Failed to start decoder-daemon.service: Unit not found"
Install the unit file, the service user and the binary it runs:
```bash
-sudo useradd --system --home-dir /var/lib/rho --shell /usr/sbin/nologin rho
-sudo install -m 0755 ~/.rho/bin/rho /usr/local/bin/rho
-sudo cp packaging/systemd/rho-daemon.service /etc/systemd/system/
-# Optional: sudo install -D -m 0600 /dev/null /etc/rho/daemon.env, then add
-# RHO_DAEMON_API_KEY= (the key is read from the environment, not argv).
+sudo useradd --system --home-dir /var/lib/decoder --shell /usr/sbin/nologin decoder
+sudo install -m 0755 ~/.decoder/bin/decoder /usr/local/bin/decoder
+sudo cp packaging/systemd/decoder-daemon.service /etc/systemd/system/
+# Optional: sudo install -D -m 0600 /dev/null /etc/decoder/daemon.env, then add
+# DECODER_DAEMON_API_KEY= (the key is read from the environment, not argv).
sudo systemctl daemon-reload
-sudo systemctl enable --now rho-daemon
+sudo systemctl enable --now decoder-daemon
```
### "Permission denied" accessing state directory
-The unit runs as user `rho` with `ProtectSystem=strict` and
+The unit runs as user `decoder` with `ProtectSystem=strict` and
`ProtectHome=true`, so the only writable locations are the directories
-systemd creates for it (`StateDirectory=rho`, `CacheDirectory=rho`) and a
-private `/tmp`. Config lives in `/var/lib/rho/config`, state (sessions, security
-log, `run/daemon.log`) in `/var/lib/rho/state`, and cache in `/var/cache/rho`.
+systemd creates for it (`StateDirectory=decoder`, `CacheDirectory=decoder`) and a
+private `/tmp`. Config lives in `/var/lib/decoder/config`, state (sessions, security
+log, `run/daemon.log`) in `/var/lib/decoder/state`, and cache in `/var/cache/decoder`.
Home directories are hidden from the service, so do not point
-`ReadWritePaths=` or the `RHO_*_DIR` variables at `/home`, `/root` or `%h`
+`ReadWritePaths=` or the `DECODER_*_DIR` variables at `/home`, `/root` or `%h`
(`%h` is always `/root` in a system unit). To let the agent edit project
checkouts, add them explicitly, for example `ReadWritePaths=/srv/projects`
-in a drop-in (`sudo systemctl edit rho-daemon`).
+in a drop-in (`sudo systemctl edit decoder-daemon`).
### Daemon not logging to journald
If using the systemd unit, logs go to both journald (stdout/stderr) and
-`/var/lib/rho/state/run/daemon.log`. Check:
+`/var/lib/decoder/state/run/daemon.log`. Check:
```bash
-journalctl -u rho-daemon -f
-sudo tail -f /var/lib/rho/state/run/daemon.log
+journalctl -u decoder-daemon -f
+sudo tail -f /var/lib/decoder/state/run/daemon.log
```
If journald logs are missing, verify that stdout/stderr are not being
diff --git a/docs/user-guide/01-getting-started.md b/docs/user-guide/01-getting-started.md
index df787591c..a7a984bee 100644
--- a/docs/user-guide/01-getting-started.md
+++ b/docs/user-guide/01-getting-started.md
@@ -1,25 +1,25 @@
# Getting Started
-Rho is an AI-powered coding agent for your terminal, built for developers by GrayCode AI. It understands your codebase, executes shell commands, edits files, searches the web, and manages tasks — all through natural language.
+Decoder is an AI-powered coding agent for your terminal, built for developers by GrayCode AI. It understands your codebase, executes shell commands, edits files, searches the web, and manages tasks — all through natural language.
-You can use Rho interactively as a full-screen TUI, run it headlessly for scripting and CI/CD, or integrate it into editors via the Agent Client Protocol (ACP).
+You can use Decoder interactively as a full-screen TUI, run it headlessly for scripting and CI/CD, or integrate it into editors via the Agent Client Protocol (ACP).
---
## Installation
-Rho is currently in active development. Contributor source builds are the primary path while we harden the product in the open.
+Decoder is currently in active development. Contributor source builds are the primary path while we harden the product in the open.
### From Source (Recommended for Contributors)
```bash
-git clone https://github.com/GrayCodeAI/rho && cd rho
-GOWORK=off go build -o rho ./cmd/rho
-./rho
+git clone https://github.com/GrayCodeAI/decoder && cd decoder
+GOWORK=off go build -o decoder ./cmd/decoder
+./decoder
```
For full cross-repository development, place the nine Go repositories beside
-Rho in a parent workspace and run `make setup` from `rho`; `graycode-eco` is
+Decoder in a parent workspace and run `make setup` from `decoder`; `graycode-eco` is
only a local folder name, not a repository containing those modules.
### Verification
@@ -27,7 +27,7 @@ only a local folder name, not a repository containing those modules.
Run the developer path check to verify your setup:
```bash
-./rho path
+./decoder path
```
This checks setup and security readiness.
@@ -36,15 +36,15 @@ This checks setup and security readiness.
## First Launch
-Start Rho by running:
+Start Decoder by running:
```bash
-rho
+decoder
```
-On first launch, Rho opens a TUI where you can configure credentials. Press `/config` (or `/autonomy`) to open the configuration picker. Your API keys are stored in your OS keychain (macOS Keychain or Linux keyring), never in plain text.
+On first launch, Decoder opens a TUI where you can configure credentials. Press `/config` (or `/autonomy`) to open the configuration picker. Your API keys are stored in your OS keychain (macOS Keychain or Linux keyring), never in plain text.
-Rho supports multiple providers:
+Decoder supports multiple providers:
- **xAI Grok** — `XAI_API_KEY`
- **Anthropic Claude** — `ANTHROPIC_API_KEY`
@@ -58,12 +58,12 @@ See [Authentication](02-authentication.md) for the full set of auth options incl
## Basic Interaction
-Once authenticated, Rho presents a full-screen TUI powered by Bubble Tea with two main areas:
+Once authenticated, Decoder presents a full-screen TUI powered by Bubble Tea with two main areas:
-- **Scrollback** — the conversation history showing your prompts, Rho's responses, tool calls, file edits, and more
+- **Scrollback** — the conversation history showing your prompts, Decoder's responses, tool calls, file edits, and more
- **Prompt** — the input area at the bottom where you type messages
-Type a message and press `Enter` to send it. Rho reads files, runs commands, and edits code as needed. Each tool run streams into the scrollback in real time.
+Type a message and press `Enter` to send it. Decoder reads files, runs commands, and edits code as needed. Each tool run streams into the scrollback in real time.
Press `Tab` to move focus between the prompt and the scrollback. While a turn is running, `Ctrl+C` cancels it. In Vim mode, use `j`/`k` to navigate and `h`/`l` to collapse/expand entries.
@@ -81,7 +81,7 @@ The `@` operator opens a fuzzy file picker. By default it respects `.gitignore`
### Permissions
-Rho exposes two independent control surfaces:
+Decoder exposes two independent control surfaces:
- **`/autonomy`** — Controls the trust tier (Always Ask, Scout, Builder, Operator, Autonomous)
- **`/spec`** — A workflow gate that blocks Write/Edit/Bash until you approve implementation
@@ -105,21 +105,21 @@ Every conversation is a **session**. Sessions are automatically saved and can be
- Start a new session: `Ctrl+N` or `/new`
- Resume a previous session: `/resume` in the TUI, or `--resume ` from the CLI
-- Continue the most recent session: `rho -c`
+- Continue the most recent session: `decoder -c`
### Scrollback
The scrollback shows:
- **User prompts** — your messages, rendered as sticky headers
-- **Agent messages** — Rho's responses with markdown rendering
-- **Thinking blocks** — Rho's reasoning process (collapsible)
+- **Agent messages** — Decoder's responses with markdown rendering
+- **Thinking blocks** — Decoder's reasoning process (collapsible)
- **Tool calls** — file edits, command executions, search results
- **Task lists** — TODO items tracking progress
### Tools
-Rho has built-in tools for:
+Decoder has built-in tools for:
| Tool | Description |
|------|-------------|
@@ -152,44 +152,44 @@ See [Slash Commands](04-slash-commands.md) for the complete reference.
```bash
# Start the interactive TUI
-rho
+decoder
# Submit an initial prompt as the first turn
-rho "fix the failing auth test and run it"
+decoder "fix the failing auth test and run it"
# Start in a specific project directory
-rho --cwd ~/projects/my-app
+decoder --cwd ~/projects/my-app
# Resume a previous session
-rho -r abc123
+decoder -r abc123
# Continue the most recent session
-rho -c
+decoder -c
# Use a specific provider/model
-rho --provider openai --model gpt-4o
+decoder --provider openai --model gpt-4o
# Isolated worktree for changes
-rho --worktree "refactor module X"
+decoder --worktree "refactor module X"
# Non-interactive (headless) mode
-rho -p "Explain this codebase"
+decoder -p "Explain this codebase"
# Full auto mode
-rho exec --auto full "add error handling"
+decoder exec --auto full "add error handling"
# Dry-run mode (denies all tools)
-rho exec --autonomy dry-run "What would this do?"
+decoder exec --autonomy dry-run "What would this do?"
```
---
## Headless Mode
-Run Rho non-interactively for scripting, CI/CD, and automation:
+Run Decoder non-interactively for scripting, CI/CD, and automation:
```bash
-rho -p "Your prompt here"
+decoder -p "Your prompt here"
```
Output formats:
@@ -204,15 +204,15 @@ Output formats:
## Project Rules (AGENTS.md)
-Add per-project instructions by creating an `AGENTS.md` file in your repository. Rho reads these files and injects their contents as a project-instructions message at the start of the conversation:
+Add per-project instructions by creating an `AGENTS.md` file in your repository. Decoder reads these files and injects their contents as a project-instructions message at the start of the conversation:
```
-~/.rho/AGENTS.md # Global rules (apply to all projects)
+~/.decoder/AGENTS.md # Global rules (apply to all projects)
/AGENTS.md # Repository-level rules
/AGENTS.md # Directory-level rules (highest priority)
```
-Deeper files take precedence. Rho also reads `CLAUDE.md` files for compatibility.
+Deeper files take precedence. Decoder also reads `CLAUDE.md` files for compatibility.
---
diff --git a/docs/user-guide/02-authentication.md b/docs/user-guide/02-authentication.md
index 8f36e99a6..bec9288ec 100644
--- a/docs/user-guide/02-authentication.md
+++ b/docs/user-guide/02-authentication.md
@@ -1,14 +1,14 @@
# Authentication
-Rho supports several authentication methods, including API key configuration through the TUI and multi-provider support via Flux.
+Decoder supports several authentication methods, including API key configuration through the TUI and multi-provider support via Mux.
---
## API Key Configuration
-On first launch, Rho opens the TUI where you can configure credentials. Press `/config` or `/autonomy` to open the configuration picker. Your API keys are stored in your OS keychain (macOS Keychain or Linux keyring), never in plain text or environment variables.
+On first launch, Decoder opens the TUI where you can configure credentials. Press `/config` or `/autonomy` to open the configuration picker. Your API keys are stored in your OS keychain (macOS Keychain or Linux keyring), never in plain text or environment variables.
-Rho supports multiple providers:
+Decoder supports multiple providers:
| Provider | ID | Key |
|----------|----|-----|
@@ -24,10 +24,10 @@ Rho supports multiple providers:
```bash
# Verify credential status
-rho credentials status
+decoder credentials status
# Run the TUI and use /config to set keys interactively
-rho
+decoder
```
### Environment Variables (Fallback)
@@ -36,7 +36,7 @@ For CI/CD or headless environments, you can set API keys as environment variable
```bash
export XAI_API_KEY="xai-..."
-rho
+decoder
```
Fireworks uses its OpenAI-compatible API. Set `FIREWORKS_API_KEY`; the default
@@ -49,19 +49,19 @@ base URL is `https://api.fireworks.ai/inference/v1`. See the official
## Provider Configuration
-Rho uses Flux for provider routing, health checks, and retry logic. To configure providers:
+Decoder uses Mux for provider routing, health checks, and retry logic. To configure providers:
```bash
# In the TUI, press /config to open provider settings
-rho
+decoder
# Or validate readiness
-rho path
+decoder path
```
### Deployment-Aware Routing
-For deployment-aware routing, set in `.rho/settings.json`:
+For deployment-aware routing, set in `.decoder/settings.json`:
```json
{
@@ -72,10 +72,10 @@ For deployment-aware routing, set in `.rho/settings.json`:
Or export:
```bash
-export RHO_DEPLOYMENT_ROUTING=true
+export DECODER_DEPLOYMENT_ROUTING=true
```
-Rho will route canonical model IDs through Flux's deployment catalog. Refresh the catalog with:
+Decoder will route canonical model IDs through Mux's deployment catalog. Refresh the catalog with:
```
/refresh-model-catalog
@@ -90,7 +90,7 @@ Authenticate developers through your own Identity Provider (IdP) — such as Okt
### Configure via Settings
```json
-// .rho/settings.json
+// .decoder/settings.json
{
"oidc": {
"issuer": "https://acme.okta.com",
@@ -99,7 +99,7 @@ Authenticate developers through your own Identity Provider (IdP) — such as Okt
}
```
-Rho discovers endpoints via `{issuer}/.well-known/openid-configuration`, opens the IdP login page, and stores tokens in the keychain. Tokens auto-refresh silently via the stored `refresh_token`.
+Decoder discovers endpoints via `{issuer}/.well-known/openid-configuration`, opens the IdP login page, and stores tokens in the keychain. Tokens auto-refresh silently via the stored `refresh_token`.
### Required Scopes
@@ -116,7 +116,7 @@ When browser-based login isn't possible — for example, on sandboxed VMs, CI ru
### How It Works
-1. Rho runs your command via `sh -c ""`
+1. Decoder runs your command via `sh -c ""`
2. Your binary runs whatever auth flow it needs
3. **stdout** is captured and parsed as an access token
4. **stderr** carries human-readable output surfaced to the user
@@ -139,7 +139,7 @@ JSON with optional refresh token:
### Configuration
```json
-// .rho/settings.json
+// .decoder/settings.json
{
"auth_provider_command": "/usr/local/bin/my-auth-provider",
"auth_provider_label": "Acme Corp"
@@ -149,17 +149,17 @@ JSON with optional refresh token:
Or via environment variables:
```bash
-export RHO_AUTH_PROVIDER_COMMAND="/usr/local/bin/my-auth-provider"
-export RHO_AUTH_PROVIDER_LABEL="Acme Corp"
+export DECODER_AUTH_PROVIDER_COMMAND="/usr/local/bin/my-auth-provider"
+export DECODER_AUTH_PROVIDER_LABEL="Acme Corp"
```
### Token Refresh
-When Rho needs to refresh an expired token, it re-runs your binary with `RHO_AUTH_EXPIRED=1` set in the environment:
+When Decoder needs to refresh an expired token, it re-runs your binary with `DECODER_AUTH_EXPIRED=1` set in the environment:
```bash
#!/bin/sh
-if [ "$RHO_AUTH_EXPIRED" = "1" ]; then
+if [ "$DECODER_AUTH_EXPIRED" = "1" ]; then
echo "Refreshing token..." >&2
TOKEN=$(my-company-auth --refresh --silent)
else
@@ -182,16 +182,16 @@ echo "{\"access_token\": \"$TOKEN\", \"expires_in\": 3600}"
Check credential status at any time:
```bash
-rho credentials status
+decoder credentials status
```
-This verifies keychain entries and validates Flux's provider status.
+This verifies keychain entries and validates Mux's provider status.
---
## Credential Precedence
-Rho resolves credentials in this order:
+Decoder resolves credentials in this order:
1. **Per-model configuration** — set via `/config` or settings
2. **Keychain entry** — obtained through TUI configuration
@@ -203,7 +203,7 @@ During a session, the active method handles all refreshes.
## Multi-Provider Support
-Rho works with any LLM provider through Flux's adapter system:
+Decoder works with any LLM provider through Mux's adapter system:
| Provider | Status |
|----------|--------|
diff --git a/docs/user-guide/03-keyboard-shortcuts.md b/docs/user-guide/03-keyboard-shortcuts.md
index 6af07dd38..c0456c243 100644
--- a/docs/user-guide/03-keyboard-shortcuts.md
+++ b/docs/user-guide/03-keyboard-shortcuts.md
@@ -1,12 +1,12 @@
# Keyboard Shortcuts
-Reference for key bindings in the Rho TUI. Bindings are built-in and cannot currently be remapped.
+Reference for key bindings in the Decoder TUI. Bindings are built-in and cannot currently be remapped.
---
## Input Modes
-Rho has two input modes that control how you navigate the scrollback:
+Decoder has two input modes that control how you navigate the scrollback:
- **Simple mode** (default): Arrow keys for navigation, `Shift+Arrow` for turn navigation, `Space` to focus the prompt
- **Vim mode** (opt-in): `j`/`k` for navigation, `H`/`L` for turn navigation, `h`/`l` for fold, `Tab` to focus the prompt
@@ -17,7 +17,7 @@ Simple mode is active by default. To switch to Vim mode:
/vim-mode
```
-Or set `vim_mode = true` under `[ui]` in `~/.rho/settings.json`:
+Or set `vim_mode = true` under `[ui]` in `~/.decoder/settings.json`:
```json
{
diff --git a/docs/user-guide/04-slash-commands.md b/docs/user-guide/04-slash-commands.md
index c5877c978..6656ea70d 100644
--- a/docs/user-guide/04-slash-commands.md
+++ b/docs/user-guide/04-slash-commands.md
@@ -186,7 +186,7 @@ Install a skill from a source.
```
/skills install go-review
-rho skills install go-review
+decoder skills install go-review
```
### `/skills audit`
@@ -195,7 +195,7 @@ Security scan installed skills.
```
/skills audit
-rho skills audit
+decoder skills audit
```
---
@@ -317,7 +317,7 @@ Quick ready-to-chat check.
### `/ecosystem`
-Show ecosystem component status (Flux and the token pipeline).
+Show ecosystem component status (Mux and the token pipeline).
```
/ecosystem
@@ -413,7 +413,7 @@ Toggle vim-style keybindings.
### `/refresh-model-catalog`
-Fetch the latest deployment-aware model catalog from Flux.
+Fetch the latest deployment-aware model catalog from Mux.
```
/refresh-model-catalog
diff --git a/docs/user-guide/05-configuration.md b/docs/user-guide/05-configuration.md
index aed869a04..53e2a975c 100644
--- a/docs/user-guide/05-configuration.md
+++ b/docs/user-guide/05-configuration.md
@@ -1,6 +1,6 @@
# Configuration
-Rho reads configuration from settings files, environment variables, and has defaults for all options. This document covers the common configuration options.
+Decoder reads configuration from settings files, environment variables, and has defaults for all options. This document covers the common configuration options.
---
@@ -11,18 +11,18 @@ Configuration is resolved in this order (highest priority first):
1. **CLI `--settings` JSON override** (`LoadSettingsWithOverride`)
2. **Per-command CLI flags** (e.g., `--provider`, `--model`)
3. **Environment variables** (only where explicitly read; there is no global env layer)
-4. **Project settings** (`.rho/settings.json`, repository-safe subset only —
+4. **Project settings** (`.decoder/settings.json`, repository-safe subset only —
`model`, `provider`, permissions, MCP servers and providers are stripped)
-5. **User settings** (`~/.rho/settings.json`)
+5. **User settings** (`~/.decoder/settings.json`)
6. **Built-in defaults**
---
## Settings File
-Location: `~/.rho/settings.json`
+Location: `~/.decoder/settings.json`
-This is the main configuration file. Rho writes to it when you save changes via `/config` or `/autonomy save`.
+This is the main configuration file. Decoder writes to it when you save changes via `/config` or `/autonomy save`.
### Basic Settings
@@ -106,34 +106,34 @@ Key environment variables for configuration.
| Variable | Description |
|----------|-------------|
-| `RHO_Y0_FOLDER_TRUST` | Folder trust feature flag (default: `1`) |
-| `RHO_Y0_MARKETPLACE` | Marketplace feature flag (default: `1`, set `0` to disable remote installs) |
-| `RHO_DEPLOYMENT_ROUTING` | Not an environment variable: set `deployment_routing` in `settings.json` |
+| `DECODER_Y0_FOLDER_TRUST` | Folder trust feature flag (default: `1`) |
+| `DECODER_Y0_MARKETPLACE` | Marketplace feature flag (default: `1`, set `0` to disable remote installs) |
+| `DECODER_DEPLOYMENT_ROUTING` | Not an environment variable: set `deployment_routing` in `settings.json` |
### Paths
| Variable | Description |
|----------|-------------|
-| `RHO_HOME` | Harness home override used by identity only (default: `~/.rho`); most config paths honor `RHO_CONFIG_DIR` / `RHO_STATE_DIR` / `RHO_CACHE_DIR` instead |
+| `DECODER_HOME` | Harness home override used by identity only (default: `~/.decoder`); most config paths honor `DECODER_CONFIG_DIR` / `DECODER_STATE_DIR` / `DECODER_CACHE_DIR` instead |
---
## Project Configuration
-Place configuration in `.rho/` within your repository:
+Place configuration in `.decoder/` within your repository:
| File | Purpose |
|------|---------|
-| `.rho/settings.json` | Project settings (autonomy, rules) |
-| `.rho/lsp.json` | LSP server configuration |
+| `.decoder/settings.json` | Project settings (autonomy, rules) |
+| `.decoder/lsp.json` | LSP server configuration |
| `AGENTS.md` | Project instructions |
---
## MCP Servers
-Configure MCP servers in global `~/.rho/settings.json` only — project
-`.rho/settings.json` cannot register MCP servers (stripped by
+Configure MCP servers in global `~/.decoder/settings.json` only — project
+`.decoder/settings.json` cannot register MCP servers (stripped by
`projectSafeSettings`; project automation additionally requires folder trust,
see below):
@@ -169,7 +169,7 @@ Folder trust controls whether project automation (hooks, plugins, MCP, LSP) can
### Trust Store
-Location: `~/.rho/trusted_folders.toml`
+Location: `~/.decoder/trusted_folders.toml`
```toml
[[folders]]
diff --git a/docs/user-guide/06-theming.md b/docs/user-guide/06-theming.md
index 10533c6a5..0260d1e30 100644
--- a/docs/user-guide/06-theming.md
+++ b/docs/user-guide/06-theming.md
@@ -1,16 +1,16 @@
# Theming and Appearance Customization
-Rho draws all TUI colors from a central theme. You can switch themes while running, follow your operating system's light or dark appearance, and adjust scroll speed and compact mode through slash commands or settings.
+Decoder draws all TUI colors from a central theme. You can switch themes while running, follow your operating system's light or dark appearance, and adjust scroll speed and compact mode through slash commands or settings.
---
## Available Themes
-Rho includes 17 built-in themes, plus an `auto` option that follows your system appearance:
+Decoder includes 17 built-in themes, plus an `auto` option that follows your system appearance:
| Theme | Description |
|-------|-------------|
-| **dark** | Neutral dark base with Rho's Talon Gold accent. Default theme. |
+| **dark** | Neutral dark base with Decoder's Talon Gold accent. Default theme. |
| **dracula** | The Dracula color scheme with muted violet surfaces. |
| **nord** | Arctic cold blue palette. |
| **gruvbox** | Warm retro browns with olive-green accent. |
@@ -37,7 +37,7 @@ Theme names are case-insensitive.
### In the TUI
-Run the `/theme` slash command to open the theme picker. As you move through the list with the arrow keys, Rho previews each theme in real time:
+Run the `/theme` slash command to open the theme picker. As you move through the list with the arrow keys, Decoder previews each theme in real time:
```
/theme
@@ -54,7 +54,7 @@ Submitting `/theme` on its own opens the picker.
### Via Settings
-Set the theme in `~/.rho/settings.json`:
+Set the theme in `~/.decoder/settings.json`:
```json
{
@@ -66,7 +66,7 @@ Set the theme in `~/.rho/settings.json`:
## Auto Theme (System Appearance)
-Set `theme: "auto"` to have Rho follow your operating system's light/dark appearance and switch themes automatically:
+Set `theme: "auto"` to have Decoder follow your operating system's light/dark appearance and switch themes automatically:
```json
{
@@ -93,13 +93,13 @@ By default, dark mode maps to the **dark** theme and light mode maps to the **li
| **Windows** | Reads the system personalization registry via PowerShell. |
| **SSH / headless** | Defaults to dark theme when detection fails. |
-Once running, Rho checks for appearance changes when you explicitly switch themes (no continuous polling to avoid resource drain).
+Once running, Decoder checks for appearance changes when you explicitly switch themes (no continuous polling to avoid resource drain).
---
## Color Support Detection
-On startup, Rho detects your terminal's color capability:
+On startup, Decoder detects your terminal's color capability:
| Level | Description |
|-------|-------------|
@@ -107,7 +107,7 @@ On startup, Rho detects your terminal's color capability:
| **256-color** | Indexed palette. Colors are mapped to the nearest index. |
| **16-color** | ANSI names only. Colors map to the closest ANSI color. |
-When `COLORTERM=truecolor` is set, Rho uses truecolor mode. When `TERM` contains `256color`, it uses 256-color mode. When `NO_COLOR` is set, Rho renders in monochrome.
+When `COLORTERM=truecolor` is set, Decoder uses truecolor mode. When `TERM` contains `256color`, it uses 256-color mode. When `NO_COLOR` is set, Decoder renders in monochrome.
---
@@ -192,7 +192,7 @@ View terminal configuration recommendations and current capabilities:
/terminal-setup
```
-This shows detected color support, current settings, and tips for optimal Rho experience.
+This shows detected color support, current settings, and tips for optimal Decoder experience.
---
diff --git a/docs/user-guide/07-mcp-servers.md b/docs/user-guide/07-mcp-servers.md
index bf919ed1a..b4bcba0d7 100644
--- a/docs/user-guide/07-mcp-servers.md
+++ b/docs/user-guide/07-mcp-servers.md
@@ -1,12 +1,12 @@
# MCP Servers
-MCP (Model Context Protocol) servers extend Rho with external tool integrations. They let Rho interact with any service that implements the MCP standard.
+MCP (Model Context Protocol) servers extend Decoder with external tool integrations. They let Decoder interact with any service that implements the MCP standard.
---
## What Are MCP Servers?
-An MCP server is a process that exposes tools to Rho over a standardized protocol. When you configure an MCP server, its tools become available to the model alongside Rho's built-in tools. The model can discover and call these tools during a session.
+An MCP server is a process that exposes tools to Decoder over a standardized protocol. When you configure an MCP server, its tools become available to the model alongside Decoder's built-in tools. The model can discover and call these tools during a session.
For example, a GitHub MCP server might expose tools like `create_issue`, `list_pull_requests`, and `search_code`. A database server might expose `query`, `list_tables`, and `describe_schema`.
@@ -16,11 +16,11 @@ See the [MCP specification](https://modelcontextprotocol.io) for protocol detail
## Configuration
-MCP servers are configured in `.rho/settings.json` under the `mcp_servers` key.
+MCP servers are configured in `.decoder/settings.json` under the `mcp_servers` key.
### stdio Transport (Local Process)
-Rho spawns a local process and communicates over stdin/stdout:
+Decoder spawns a local process and communicates over stdin/stdout:
```json
{
@@ -64,40 +64,40 @@ Manage MCP servers from the command line:
```bash
# List configured MCP servers
-rho mcp list
+decoder mcp list
# Add a stdio server
-rho mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /path/to/dir
+decoder mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /path/to/dir
# Add a remote HTTP server
-rho mcp add linear --transport http https://mcp.linear.app/mcp
+decoder mcp add linear --transport http https://mcp.linear.app/mcp
# Remove a server
-rho mcp remove github
+decoder mcp remove github
# Diagnose server configuration
-rho mcp doctor
-rho mcp doctor
+decoder mcp doctor
+decoder mcp doctor
```
-Use `--scope project` to write to `.rho/settings.json` in the current directory instead of the user config.
+Use `--scope project` to write to `.decoder/settings.json` in the current directory instead of the user config.
---
## Project-Scoped MCP Servers
-MCP servers can be configured per-project in `.rho/settings.json`:
+MCP servers can be configured per-project in `.decoder/settings.json`:
```
my-project/
- .rho/
+ .decoder/
settings.json
src/
...
```
```json
-// .rho/settings.json
+// .decoder/settings.json
{
"mcp_servers": {
"linear": {
@@ -125,7 +125,7 @@ MCP tools are namespaced with the server name to avoid collisions:
## Discovering and Using Tools
-Rho provides built-in tools to work with MCP servers:
+Decoder provides built-in tools to work with MCP servers:
- **`search_tool`** — Discover available integration tools across all enabled MCP servers
- **`use_tool`** — Call an integration tool discovered via `search_tool`
diff --git a/docs/user-guide/08-skills.md b/docs/user-guide/08-skills.md
index 519c5f1a4..58adaa97f 100644
--- a/docs/user-guide/08-skills.md
+++ b/docs/user-guide/08-skills.md
@@ -1,26 +1,26 @@
# Skills
-Skills are reusable prompt packages that extend Rho with task-specific instructions. They let you capture a repeatable procedure once, instead of re-explaining it each session.
+Skills are reusable prompt packages that extend Decoder with task-specific instructions. They let you capture a repeatable procedure once, instead of re-explaining it each session.
---
## What Are Skills?
-A skill is a directory containing a `SKILL.md` file. Its markdown body tells Rho how to handle a specific type of task: step-by-step instructions, conventions, and tool-usage patterns.
+A skill is a directory containing a `SKILL.md` file. Its markdown body tells Decoder how to handle a specific type of task: step-by-step instructions, conventions, and tool-usage patterns.
-Use a skill for a repeatable procedure that's too specific for AGENTS.md but too long to retype each time. Rho activates a skill when it applies to your current task.
+Use a skill for a repeatable procedure that's too specific for AGENTS.md but too long to retype each time. Decoder activates a skill when it applies to your current task.
---
## Skill Locations
-Rho discovers skills from these directories, in priority order:
+Decoder discovers skills from these directories, in priority order:
| Location | Scope | Priority |
|----------|-------|----------|
-| `.rho/skills/`, `.rho/commands/` | Local (CWD) | Highest |
-| `/.rho/skills/` | Repo | Medium |
-| `~/.rho/skills/` | User | Lowest |
+| `.decoder/skills/`, `.decoder/commands/` | Local (CWD) | Highest |
+| `/.decoder/skills/` | Repo | Medium |
+| `~/.decoder/skills/` | User | Lowest |
Higher-priority locations override skills with the same name.
@@ -33,7 +33,7 @@ Higher-priority locations override skills with the same name.
Each skill lives in its own directory with a `SKILL.md` file:
```
-~/.rho/skills/
+~/.decoder/skills/
commit/
SKILL.md
review-pr/
@@ -103,13 +103,13 @@ Pass arguments after the name:
When names collide, use qualified forms:
```
-/local:commit # From ./.rho/skills/
-/user:commit # From ~/.rho/skills/
+/local:commit # From ./.decoder/skills/
+/user:commit # From ~/.decoder/skills/
```
### Automatic Invocation
-Rho can invoke a skill automatically when it recognizes a relevant task. Write specific descriptions in the `description` and `when-to-use` fields.
+Decoder can invoke a skill automatically when it recognizes a relevant task. Write specific descriptions in the `description` and `when-to-use` fields.
---
@@ -119,26 +119,26 @@ Manage skills from the command line:
```bash
# Search the community registry
-rho skills search go
+decoder skills search go
# Install a skill from a source
-rho skills install go-review
+decoder skills install go-review
# Audit installed skills for security
-rho skills audit
+decoder skills audit
```
---
## Installing Skills
-Rho ships **no bundled skills** by default. Skills are installed on demand
+Decoder ships **no bundled skills** by default. Skills are installed on demand
from the separate `GrayCodeAI/starling` repo (or any GitHub repo):
```bash
-rho skills search # find a skill in the registry
-rho skills install [skill] # install after user approval
-rho skills audit # security-scan installed skills
+decoder skills search # find a skill in the registry
+decoder skills install [skill] # install after user approval
+decoder skills audit # security-scan installed skills
```
Once installed, skills are discovered from the locations listed above.
diff --git a/docs/user-guide/09-plugins.md b/docs/user-guide/09-plugins.md
index bdcbdec16..a8c01fc80 100644
--- a/docs/user-guide/09-plugins.md
+++ b/docs/user-guide/09-plugins.md
@@ -20,12 +20,12 @@ For example, a `team-tools` plugin might include a deploy skill, a code-review a
## Plugin Locations
-Rho discovers plugins from these locations, in priority order:
+Decoder discovers plugins from these locations, in priority order:
| Location | Scope | Trust Required |
|----------|-------|----------------|
-| `.rho/plugins/` | Project | Yes |
-| `~/.rho/plugins/` | User | No |
+| `.decoder/plugins/` | Project | Yes |
+| `~/.decoder/plugins/` | User | No |
| `--plugin-dir` | Process | No |
When two plugins share a name, the higher-priority location wins.
@@ -38,21 +38,21 @@ Manage plugins from the command line:
```bash
# List installed plugins
-rho plugins list
+decoder plugins list
# Install a plugin
-rho plugins install user/repo
-rho plugins install user/repo@v1.0
-rho plugins install /path/to/local/plugin
+decoder plugins install user/repo
+decoder plugins install user/repo@v1.0
+decoder plugins install /path/to/local/plugin
# Install with trust (required for project plugins)
-rho plugins install user/repo --trust
+decoder plugins install user/repo --trust
# Uninstall a plugin
-rho plugins uninstall my-plugin
+decoder plugins uninstall my-plugin
# Update plugins
-rho plugins update
+decoder plugins update
```
---
@@ -63,15 +63,15 @@ Browse and install plugins from the community marketplace:
```bash
# Search marketplace
-rho plugins search go
+decoder plugins search go
# Install from marketplace
-rho plugins install go-review --trust
+decoder plugins install go-review --trust
```
### Adding Marketplace Sources
-Configure additional marketplaces in `~/.rho/settings.json`:
+Configure additional marketplaces in `~/.decoder/settings.json`:
```json
{
@@ -90,13 +90,13 @@ Configure additional marketplaces in `~/.rho/settings.json`:
## Trust Model
-- **User plugins** (`~/.rho/plugins/`) — Trusted automatically
-- **Project plugins** (`.rho/plugins/`) — Require explicit trust before activation
+- **User plugins** (`~/.decoder/plugins/`) — Trusted automatically
+- **Project plugins** (`.decoder/plugins/`) — Require explicit trust before activation
Trust is required because plugins can execute code via hooks and MCP servers. To trust a plugin:
```bash
-rho plugins install --trust
+decoder plugins install --trust
```
---
diff --git a/docs/user-guide/10-hooks.md b/docs/user-guide/10-hooks.md
index f7430a1c6..38c128b02 100644
--- a/docs/user-guide/10-hooks.md
+++ b/docs/user-guide/10-hooks.md
@@ -1,12 +1,12 @@
# Hooks
-Hooks let you run code at key moments in a Rho session. Use them to automate tasks, enforce safety checks, log activity, and integrate custom tools.
+Hooks let you run code at key moments in a Decoder session. Use them to automate tasks, enforce safety checks, log activity, and integrate custom tools.
---
## What Are Hooks?
-A hook is a shell command or HTTP endpoint that Rho calls when a specific lifecycle event occurs. Hooks can:
+A hook is a shell command or HTTP endpoint that Decoder calls when a specific lifecycle event occurs. Hooks can:
- **Block actions** — A `PreToolUse` hook can deny a dangerous command before it runs
- **React to events** — A `PostToolUse` hook can log every tool execution
@@ -36,7 +36,7 @@ Only `PreToolUse` can block a tool call. All other events are passive.
## Hook Configuration
-Create hooks in `.rho/hooks/hooks.json`:
+Create hooks in `.decoder/hooks/hooks.json`:
```json
{
@@ -100,8 +100,8 @@ Exit code `2` also signals denial. Any other exit code is fail-open (tool is all
## Trust Model
-- **User hooks** (`~/.rho/hooks/`) — Always trusted
-- **Project hooks** (`.rho/hooks/`) — Require folder trust
+- **User hooks** (`~/.decoder/hooks/`) — Always trusted
+- **Project hooks** (`.decoder/hooks/`) — Require folder trust
Project hooks are blocked until you trust the folder:
@@ -114,15 +114,15 @@ Project hooks are blocked until you trust the folder:
## Environment Variables
-Rho sets these variables for every hook:
+Decoder sets these variables for every hook:
| Variable | Description |
|----------|-------------|
-| `RHO_HOOK_EVENT` | Event name (e.g., `PreToolUse`) |
-| `RHO_SESSION_ID` | Current session ID |
-| `RHO_WORKSPACE_ROOT` | Project root path |
-| `RHO_PLUGIN_ROOT` | Plugin directory (for plugin hooks) |
-| `RHO_PLUGIN_DATA` | Plugin data directory |
+| `DECODER_HOOK_EVENT` | Event name (e.g., `PreToolUse`) |
+| `DECODER_SESSION_ID` | Current session ID |
+| `DECODER_WORKSPACE_ROOT` | Project root path |
+| `DECODER_PLUGIN_ROOT` | Plugin directory (for plugin hooks) |
+| `DECODER_PLUGIN_DATA` | Plugin data directory |
---
@@ -130,20 +130,20 @@ Rho sets these variables for every hook:
```bash
# List hooks
-rho hooks list
+decoder hooks list
# Trust project hooks
-rho hooks trust
+decoder hooks trust
# Untrust project hooks
-rho hooks untrust
+decoder hooks untrust
```
---
## Example: Safe Shell Guard
-Create `.rho/hooks/safety.json`:
+Create `.decoder/hooks/safety.json`:
```json
{
diff --git a/docs/user-guide/11-custom-models.md b/docs/user-guide/11-custom-models.md
index 1ce0e2f4a..c11870512 100644
--- a/docs/user-guide/11-custom-models.md
+++ b/docs/user-guide/11-custom-models.md
@@ -1,12 +1,12 @@
# Custom Models
-Rho connects to custom model endpoints through Flux for alternative providers, self-hosted models, and overriding built-in settings.
+Decoder connects to custom model endpoints through Mux for alternative providers, self-hosted models, and overriding built-in settings.
---
## Supported Providers
-Rho works with any LLM provider. Built-in support includes:
+Decoder works with any LLM provider. Built-in support includes:
| Provider | ID | Key |
|----------|-----|-----|
@@ -24,7 +24,7 @@ Rho works with any LLM provider. Built-in support includes:
### CLI Flag
```bash
-rho -m gpt-4o -p "Hello"
+decoder -m gpt-4o -p "Hello"
```
### Slash Command
@@ -39,7 +39,7 @@ In the TUI:
### Config Default
```json
-// ~/.rho/settings.json
+// ~/.decoder/settings.json
{
"default_provider": "openai",
"default_model": "gpt-4o"
@@ -50,7 +50,7 @@ In the TUI:
## Configuring Custom Models
-Add custom models in `~/.rho/settings.json`:
+Add custom models in `~/.decoder/settings.json`:
```json
{
@@ -73,7 +73,7 @@ Add custom models in `~/.rho/settings.json`:
### Credential Resolution
-Rho resolves credentials in this order:
+Decoder resolves credentials in this order:
1. Per-model `api_key` field
2. Environment variable (`env_key`)
@@ -127,11 +127,11 @@ ollama pull llama-3.1-70b
## Deployment-Aware Routing
-Enable deployment-aware routing to use Flux's model catalog:
+Enable deployment-aware routing to use Mux's model catalog:
```bash
-export RHO_DEPLOYMENT_ROUTING=true
-rho
+export DECODER_DEPLOYMENT_ROUTING=true
+decoder
```
Or in settings:
diff --git a/docs/user-guide/12-project-rules.md b/docs/user-guide/12-project-rules.md
index 32dc93fad..f710b464a 100644
--- a/docs/user-guide/12-project-rules.md
+++ b/docs/user-guide/12-project-rules.md
@@ -1,12 +1,12 @@
# Project Rules (AGENTS.md)
-Project rules let you configure Rho per project or directory. By placing an AGENTS.md file in your repository, you can set coding conventions, build instructions, and style guides that Rho follows automatically.
+Project rules let you configure Decoder per project or directory. By placing an AGENTS.md file in your repository, you can set coding conventions, build instructions, and style guides that Decoder follows automatically.
---
## Supported File Names
-Rho checks for these filenames in each directory (from repo root to CWD):
+Decoder checks for these filenames in each directory (from repo root to CWD):
- `AGENTS.md`
- `Agents.md`
@@ -14,26 +14,26 @@ Rho checks for these filenames in each directory (from repo root to CWD):
- `Claude.md`
- `AGENT.md`
-Rho loads all matching files. Deeper files take precedence when instructions conflict.
+Decoder loads all matching files. Deeper files take precedence when instructions conflict.
---
## Rules Directories
-Rho also scans for `*.md` files in rules directories:
+Decoder also scans for `*.md` files in rules directories:
| Location | Purpose |
|----------|---------|
-| `/.rho/rules/` | Always scanned |
+| `/.decoder/rules/` | Always scanned |
| `/.claude/rules/` | Claude compatibility |
---
## How Discovery Works
-Rho scans rules in this order:
+Decoder scans rules in this order:
-1. **Global rules**: `~/.rho/AGENTS.md` (applies to all projects)
+1. **Global rules**: `~/.decoder/AGENTS.md` (applies to all projects)
2. **Repo rules**: Every directory from git root to CWD (inclusive)
3. **CWD-only**: If not in a git repo, only current directory
@@ -49,7 +49,7 @@ my-monorepo/
AGENTS.md # "Use Express. Follow REST conventions."
```
-When Rho runs in `packages/frontend/`, it loads all instructions. The frontend-specific rules appear later and take precedence.
+When Decoder runs in `packages/frontend/`, it loads all instructions. The frontend-specific rules appear later and take precedence.
---
@@ -108,7 +108,7 @@ my-monorepo/
For one-off rules without editing files:
```bash
-rho --rules "Always use TypeScript" -p "Implement feature"
+decoder --rules "Always use TypeScript" -p "Implement feature"
```
---
diff --git a/docs/user-guide/13-memory.md b/docs/user-guide/13-memory.md
index b3d8ad9b6..45806ca31 100644
--- a/docs/user-guide/13-memory.md
+++ b/docs/user-guide/13-memory.md
@@ -1,20 +1,20 @@
# Memory
-Memory lets Rho recall facts, decisions, and patterns from earlier sessions. Rho indexes saved information and searches it automatically, so new sessions can reuse relevant context.
+Memory lets Decoder recall facts, decisions, and patterns from earlier sessions. Decoder indexes saved information and searches it automatically, so new sessions can reuse relevant context.
---
## What Is Memory?
-Without memory, each Rho session starts fresh. When memory is enabled, Rho can:
+Without memory, each Decoder session starts fresh. When memory is enabled, Decoder can:
- Recall project conventions you explained before
- Reuse debugging steps that worked
- Carry architectural decisions forward across sessions
- Avoid re-asking questions it already has answers to
-Memory is a local subsystem built into Rho. It stores memories as files under
-Rho's state directory; no external service is required.
+Memory is a local subsystem built into Decoder. It stores memories as files under
+Decoder's state directory; no external service is required.
---
@@ -29,7 +29,7 @@ Memory is on by default. To inspect what has been stored:
### Settings
```json
-// ~/.rho/settings.json
+// ~/.decoder/settings.json
{
"memory": {
"enabled": true
@@ -41,14 +41,14 @@ Memory is on by default. To inspect what has been stored:
## How Memory Is Stored
-Memory is stored under Rho's state directory (`~/.rho/` by default).
+Memory is stored under Decoder's state directory (`~/.decoder/` by default).
| Location | Scope | Description |
|----------|-------|-------------|
-| `~/.rho/memories/` | Global | Core memories and preferences |
-| `~/.rho/` state files | Workspace | Project-specific memory and lessons |
+| `~/.decoder/memories/` | Global | Core memories and preferences |
+| `~/.decoder/` state files | Workspace | Project-specific memory and lessons |
-Rho combines core memories, automatic captures, evolving guidelines, and
+Decoder combines core memories, automatic captures, evolving guidelines, and
retrieval metrics to rank what is relevant to the current turn.
---
@@ -57,17 +57,17 @@ retrieval metrics to rank what is relevant to the current turn.
### Remember
-Ask Rho to remember something:
+Ask Decoder to remember something:
```
/remember always open PR links after pushing
```
-Rho records entries as durable statements organized by topic.
+Decoder records entries as durable statements organized by topic.
### Forget
-Ask what Rho should forget:
+Ask what Decoder should forget:
```
/forget the snake_case convention
@@ -77,13 +77,13 @@ Forget is best-effort.
### Recall
-Ask what Rho remembers:
+Ask what Decoder remembers:
```
/what do you remember about auth?
```
-Rho searches across all memory sources and summarizes.
+Decoder searches across all memory sources and summarizes.
---
@@ -99,7 +99,7 @@ Lessons learned are surfaced through:
## First-Turn Injection
-On the first turn of each session, Rho automatically searches memory for content relevant to the current project and injects it as context.
+On the first turn of each session, Decoder automatically searches memory for content relevant to the current project and injects it as context.
Configure injection:
diff --git a/docs/user-guide/14-headless-mode.md b/docs/user-guide/14-headless-mode.md
index 8d7d43a38..3a8b86642 100644
--- a/docs/user-guide/14-headless-mode.md
+++ b/docs/user-guide/14-headless-mode.md
@@ -1,6 +1,6 @@
# Headless Mode and Scripting
-Headless mode runs Rho non-interactively from the command line. It accepts a prompt, executes tools, and returns results — ideal for automation and CI/CD.
+Headless mode runs Decoder non-interactively from the command line. It accepts a prompt, executes tools, and returns results — ideal for automation and CI/CD.
---
@@ -9,10 +9,10 @@ Headless mode runs Rho non-interactively from the command line. It accepts a pro
Pass a prompt to run headless:
```bash
-rho -p "Your prompt here"
+decoder -p "Your prompt here"
```
-Rho processes the prompt and prints the result to stdout.
+Decoder processes the prompt and prints the result to stdout.
---
@@ -23,7 +23,7 @@ Rho processes the prompt and prints the result to stdout.
Human-readable text:
```bash
-rho -p "Summarize this codebase"
+decoder -p "Summarize this codebase"
```
### json
@@ -31,7 +31,7 @@ rho -p "Summarize this codebase"
Single JSON object after completion:
```bash
-rho -p "Summarize this codebase" --output-format json | jq -r '.response'
+decoder -p "Summarize this codebase" --output-format json | jq -r '.response'
```
Output includes:
@@ -44,7 +44,7 @@ Output includes:
NDJSON events in real time:
```bash
-rho -p "Summarize" --output-format stream-json | jq -r 'select(.type=="content") | .content'
+decoder -p "Summarize" --output-format stream-json | jq -r 'select(.type=="content") | .content'
```
Event types:
@@ -59,20 +59,20 @@ Event types:
### Named Session
-Each `rho -p` creates a fresh session by default. To continue a session:
+Each `decoder -p` creates a fresh session by default. To continue a session:
```bash
# Get session ID
-rho -p "Initial prompt" --output-format json | jq -r '.sessionId'
+decoder -p "Initial prompt" --output-format json | jq -r '.sessionId'
# Resume the session
-rho -p "Follow-up" --resume
+decoder -p "Follow-up" --resume
```
### Continue Most Recent
```bash
-rho -p "Continue" --continue
+decoder -p "Continue" --continue
```
---
@@ -83,10 +83,10 @@ Restrict available tools:
```bash
# Allow only read tools
-rho -p "Explain this" --tools "Read,Grep,LS"
+decoder -p "Explain this" --tools "Read,Grep,LS"
# Deny specific tools
-rho -p "Review" --disallowed-tools "Bash,WebSearch"
+decoder -p "Review" --disallowed-tools "Bash,WebSearch"
```
---
@@ -97,10 +97,10 @@ Control tool permissions:
```bash
# Allow shell commands through the explicit tool policy flag
-rho -p "Build" --allowed-tools "Bash(git:*) Bash(npm:*)"
+decoder -p "Build" --allowed-tools "Bash(git:*) Bash(npm:*)"
# Deny dangerous commands
-rho -p "Clean" --disallowed-tools "Bash(rm:*) Bash(sudo:*)"
+decoder -p "Clean" --disallowed-tools "Bash(rm:*) Bash(sudo:*)"
```
---
@@ -110,8 +110,8 @@ rho -p "Clean" --disallowed-tools "Bash(rm:*) Bash(sudo:*)"
Use `--auto` for fully automated runs:
```bash
-rho -p "Format all files" --dangerously-skip-permissions
-rho exec --auto full "Add error handling"
+decoder -p "Format all files" --dangerously-skip-permissions
+decoder exec --auto full "Add error handling"
```
**Warning:** This grants full autonomy. Use only in trusted environments.
@@ -124,14 +124,14 @@ rho exec --auto full "Add error handling"
```bash
#!/bin/bash
-rho -p "Review staged changes for bugs. Reply OK if fine." \
+decoder -p "Review staged changes for bugs. Reply OK if fine." \
--dangerously-skip-permissions --output-format json | jq -r '.response' | grep -q "^OK" || exit 1
```
### Code Review
```bash
-rho -p "Review PR for security issues" \
+decoder -p "Review PR for security issues" \
--output-format json --dangerously-skip-permissions | jq -r '.response' > review.md
```
@@ -139,7 +139,7 @@ rho -p "Review PR for security issues" \
```bash
for file in src/*.go; do
- rho -p "Format $file" --auto
+ decoder -p "Format $file" --auto
done
```
@@ -149,8 +149,8 @@ done
```bash
export XAI_API_KEY="xai-..." # API key
-export RHO_HOME="/path" # Custom config location
-export RHO_LOG_FILE="/tmp/rho.log" # Log file
+export DECODER_HOME="/path" # Custom config location
+export DECODER_LOG_FILE="/tmp/decoder.log" # Log file
```
---
diff --git a/docs/user-guide/15-agent-mode.md b/docs/user-guide/15-agent-mode.md
index 6837cdb96..d968e2290 100644
--- a/docs/user-guide/15-agent-mode.md
+++ b/docs/user-guide/15-agent-mode.md
@@ -1,6 +1,6 @@
# Agent Mode (ACP) and IDE Integration
-Agent mode runs Rho as an ACP (Agent Client Protocol) server for IDE integration and custom tooling.
+Agent mode runs Decoder as an ACP (Agent Client Protocol) server for IDE integration and custom tooling.
---
@@ -17,10 +17,10 @@ The [Agent Client Protocol (ACP)](https://agentclientprotocol.com) is a standard
## stdio Transport
-Run Rho as an ACP server over stdio:
+Run Decoder as an ACP server over stdio:
```bash
-rho agent stdio
+decoder agent stdio
```
Clients include:
@@ -31,9 +31,9 @@ Clients include:
### Options
```bash
-rho agent --model gpt-4o stdio
-rho agent --auto stdio
-rho agent --agent-profile path/to/profile.yaml stdio
+decoder agent --model gpt-4o stdio
+decoder agent --auto stdio
+decoder agent --agent-profile path/to/profile.yaml stdio
```
| Flag | Description |
@@ -49,7 +49,7 @@ rho agent --agent-profile path/to/profile.yaml stdio
### WebSocket Server
```bash
-rho agent serve --bind 127.0.0.1:2419 --secret