Files
galaxy/AGENTS.md
T

34 KiB
Raw Blame History

AGENTS.md

This file provides guidance when working with code in this repository.

Development Commands

Build and Run

  • cargo run - Build and run Warp locally
  • cargo bundle --bin warp - Bundle the main app
  • make run - Build and run galaxy-oss
  • make clean - Remove Cargo build artifacts
  • make deploy - Validate, update, bundle incrementally, and upload Galaxy to Hermes
  • make install - Validate, update, bundle incrementally, and install Galaxy to /Applications

Running with local warp-server

To connect Warp client to a local warp-server instance:

# Connect to server on default port 8080
cargo run --features with_local_server

# Connect to server on custom port (e.g., 8082)
SERVER_ROOT_URL=http://localhost:8082 WS_SERVER_URL=ws://localhost:8082/graphql/v2 cargo run --features with_local_server

Environment variables:

  • SERVER_ROOT_URL - HTTP endpoint (default: http://localhost:8080)
  • WS_SERVER_URL - WebSocket endpoint (default: ws://localhost:8080/graphql/v2)

Testing

  • Before launching galaxy-oss, check for existing app instances and close the prior development instance so only one app instance runs at a time. Distinguish the app process from its terminal-server helper; do not count the helper as a duplicate app. Leave the newly launched instance running for the user.
  • During interactive feature and bug-fix verification, make the requested code changes first and run only cargo run --bin galaxy-oss for the user to verify. Leave the app running for the user; do not stop it or treat the command timeout as a failure. Do not run cargo fmt, cargo check, cargo test, cargo clippy, presubmit, or other validation commands until the user confirms the behavior. Run formatting, tests, and linting only as the final cleanup step after interactive approval.
  • cargo nextest run --no-fail-fast --workspace --exclude command-signatures-v2 - Run tests with nextest
  • cargo nextest run -p galaxy_completer --features v2 - Run completer tests with v2 features
  • cargo test --doc - Run doc tests
  • cargo test - Run standard tests for individual packages

Linting and Formatting

  • ./script/presubmit - Run all presubmit checks (fmt, clippy, tests)
  • ./script/format - Format code
  • cargo clippy --workspace --all-targets --all-features --tests -- -D warnings - Run clippy
  • ./script/run-clang-format.py -r --extensions 'c,h,cpp,m' ./crates/galaxyui/src/ ./app/src/ - Format C/C++/Obj-C code
  • find . -name "*.wgsl" -exec wgslfmt --check {} + - Check WGSL shader formatting

Bedrock Diagnostics

  • Set GALAXY_BEDROCK_DIAGNOSTICS=1 to enable Bedrock diagnostic output, including:
    • Error_<timestamp>.txt snapshot files written to the repository root on request/stream failures (includes the serialized Bedrock context window, tool definitions, protobuf request debug payload, captured Bedrock diagnostic lines, and log tails)
    • Per-event Bedrock diagnostic logs written to bedrock-diagnostics.log in the active Warp log directory
  • Set GALAXY_TOOL_DIAGNOSTICS=1 to enable verbose local tool queue/execution debug logs and cancellation backtraces. These diagnostics are disabled during routine operation.

Remote Logging: Pulling Galaxy Logs

When investigating Galaxy behavior, retrieve recent remote logs from https://logging.ryserve.net/api/logs. Authenticate with the x-api-key header using RYSERVE_LOGGING_KEY, which is defined in ~/.zshrc. A non-interactive shell may not load that file automatically; source it explicitly. Never print the key or commit it or downloaded logs to the repository.

Fetch the latest events into a temporary file rather than dumping full payloads into the agent's context:

zsh -lc '
  source ~/.zshrc >/dev/null 2>&1
  : "${RYSERVE_LOGGING_KEY:?RYSERVE_LOGGING_KEY is not configured}"
  curl -fsS --max-time 30 --get "https://logging.ryserve.net/api/logs" \
    -H "x-api-key: ${RYSERVE_LOGGING_KEY}" \
    --data-urlencode "limit=1000" \
    --data-urlencode "offset=0" \
    -o /tmp/galaxy-remote-logs.json
'
  • The response contains logs, total, limit, and offset. Events are returned newest first. The server caps a page at 1,000 events; increase offset using the returned page size to retrieve older history.
  • To narrow a request, add --data-urlencode "level=error" and/or --data-urlencode "search=database" before the output option. Replace the search term as needed. Start without an error filter when investigating wasted turns, tool loops, or subagent behavior: the relevant events are usually informational.
  • Correlate context.conversation_id, stream_id, provider_run_id, and provider_epoch. Tool events carry their owning conversation and action IDs in context.tool; launch outcomes map child names to agent_id and identify the parent_conversation_id. Compare tool sequences and timestamps before drawing conclusions about retries or repeated discovery.
  • Inspect context.app.source_commit and source_modified to identify the running build. Remote events may come from another machine or an older build.
  • raw_model_request events can include prompts, history, and tool data in context.raw_payload.payload. Check truncated and the accompanying size fields before parsing or treating missing content as evidence. These are Galaxy request snapshots, not necessarily the exact upstream HTTP payload.
  • For upstream LiteLLM/server failures that need Kubernetes logs, use the ryserve-k3s context explicitly (for example, kubectl --context ryserve-k3s ...). Discover the current namespace/pod rather than reusing an old pod name.

AI Provider Architecture

Galaxy supports session-owned ACP backends and direct model providers. Direct-provider selection is controlled by settings (ai.openai.enabled takes priority over ai.bedrock.enabled), but provider configuration never selects lifecycle ownership.

Direct provider: controller.rs → prepare_provider_run() → ProviderRunCoordinator
                                                        ↓ one model call per turn
                                                 AgentRuntime implementation
                                                        ↓ tool batch
                                                 correlated action execution
                                                        ↓ committed results
                                                   next ProviderRun turn

ACP: controller.rs → ResponseStream → acp_output_stream (session-owned lifecycle)

Durable direct-provider run:

  • crates/galaxy_agent_core/src/provider_run.rs — Serializable ProviderRun state machine, run/epoch identity, bounded model retries, ordered tool batches, cancellation, and terminal outcomes
  • app/src/ai/runtime/provider_run_coordinator.rs — Drives one-turn AgentRuntime calls, validates model events, projects output, and commits exact tool lifecycle events
  • app/src/ai/runtime/rig.rs — Builds base/CLI request profiles and resolves the configured one-turn runtime; it does not own follow-through
  • app/src/ai/runtime/rig_request.rs — Converts controller request state into provider-neutral TurnRequest history, tools, prompts, and MCP aliases
  • app/src/ai/runtime/event_translator.rs — Projects provider-neutral runtime events into Warp response events for UI/history compatibility
  • app/src/ai/blocklist/controller.rs — Retains active runs, correlates actions by (conversation_id, run_id, epoch, call_id), monitors commands, persists checkpoints, and restores interrupted runs
  • app/src/ai/blocklist/controller/response_stream.rs — Owns ACP transport and shared UI/history projection only; it must not drive direct-provider retries or follow-up turns

Shared provider types in app/src/ai/provider/:

  • types.rs — ConversationMessage, MessageRole, MessageContent, ContentPart, ToolDefinition
  • mod.rs — ProviderConfig enum (Bedrock | OpenAI | None)

Bedrock provider in app/src/ai/provider/:

  • runtime.rs — Native one-call AgentRuntime over ConverseStream, including cancellation, reasoning signatures, token usage, and stop/error classification
  • request_translator.rs — Shared Bedrock message sanitization and tool definitions
  • response_translator.rs — Compatibility conversion helpers used by tests and background flows
  • convert.rs — Bedrock request construction and prompt-caching behavior
  • client.rs — AWS SDK client construction, runtime creation, and independent background streaming calls
  • models.rs — Model registry and cross-region inference prefix logic
  • discovery.rs — AWS profile listing and model discovery (STS identity check + ListFoundationModels)
  • diagnostic.rs — Debug logging (enabled via GALAXY_BEDROCK_DIAGNOSTICS=1)
  • external_config.rs — Fallback config from Claude Code/OpenCode settings

OpenAI-compatible providers:

  • Direct turns use one-call runtimes from galaxy_agent_rig selected in app/src/ai/runtime/rig.rs for OpenAI/LiteLLM, ChatGPT subscription, Anthropic, Gemini, and Vertex AI
  • app/src/ai/openai/request_translator.rs sanitizes provider-neutral history for OpenAI-compatible APIs
  • app/src/ai/openai/client.rs, convert.rs, and response_translator.rs remain compatibility/background transport helpers, not lifecycle owners

Provider settings (in settings TOML):

  • ai.bedrock.enabled — Use AWS Bedrock directly (default: true)
  • ai.openai.enabled — Use OpenAI-compatible endpoint(s) (default: false, takes priority over Bedrock)
  • ai.openai.base_url — Legacy single-provider endpoint URL (default: http://localhost:4000/v1)
  • ai.openai.api_key — Legacy single-provider API key (stored in keychain)
  • ai.openai.model — Model name override sent to the endpoint
  • ai.openai.models — Legacy single-provider model list (Vec<OpenAIModelConfig>)
  • ai.providers — Multi-provider config (Vec<OpenAIProviderConfig>): each entry has name, base_url, api_key, models[]

Multi-provider example (settings.toml):

[ai.openai]
enabled = true

[[ai.providers]]
name = "LiteLLM"
base_url = "http://localhost:4000/v1"
api_key = "sk-..."

[[ai.providers.models]]
model_id = "claude-sonnet-4-20250514[1m]"
display_name = "Claude Sonnet 4 (1M)"
context_size = 1000000

[[ai.providers]]
name = "Ollama (Local)"
base_url = "http://localhost:11434/v1"

[[ai.providers.models]]
model_id = "llama3.2"
display_name = "Llama 3.2"
context_size = 128000

OpenAI/LiteLLM model discovery:

  • Models can be auto-fetched from the /models endpoint via the Settings > OpenAI / LiteLLM page
  • For each model, the system probes {model_id}[1m] with a minimal chat completion request
  • If the [1m] variant is accepted (HTTP 200 or 429), it's used with 1M context window
  • Otherwise, the base model ID is used with its reported context size
  • Models injected via ai.providers[] are routed to their specific endpoint (per-model routing map)
  • Provider name shown as the description label in the model picker; icon shows OpenAI logo for all OpenAI-compatible providers

Key invariants:

  • Every direct-provider AgentRuntime::start_turn performs exactly one model call; only ProviderRun may schedule another turn or retry
  • Direct-provider model calls allow 120 seconds for stream startup and 90 seconds between stream events; either timeout is a recoverable transport failure that enters the existing bounded retry lifecycle with the same work identity
  • Direct-provider remote telemetry records requested, started, retry-scheduled, and finished model-turn phases with explicit llm_finished state; root provider_run_finished records distinguish clean completion from failure or cancellation and mark the response stream terminal
  • use_rig and provider selection may choose request/transport details but must never choose lifecycle ownership
  • Direct-provider output may be projected through ResponseStream, but provider progress must not depend on response-stream result draining or AfterStreamFinished
  • Direct-provider RequestFileEdits views must register from streaming output before provider-run completion; preprocessing results must survive delayed view registration, and NotReady retries must remain automatic rather than emitting a synthetic user permission decision
  • A clean direct-provider ProviderRunOutcome::Completed explicitly finalizes the conversation as Success after terminal output projection, even if earlier turns added tool actions; child-completion waits rely on that status
  • Provider actions and results must correlate by (conversation_id, run_id, epoch, call_id); stale or duplicate callbacks must not advance a run
  • Action status/result lookups and archived results are keyed by (conversation_id, action_id); callers must supply the owning conversation and must not fall back to a global action-ID search
  • Action blocked/executing/finished events carry conversation_id; UI subscribers must match it, and CLI shell-control mutations must also match the active block's requested-command action ID
  • Active provider runs must checkpoint before external work, persist without credentials, validate deserialized run invariants before normalization or runtime construction, normalize unsafe restored states, and reconcile command state before continuing; cancellation intent stays checkpointed until the terminal outcome is projected and finish_active_provider_run performs cleanup
  • A restored AwaitingModel checkpoint has an uncertain remote outcome and must terminate as an explicit restore failure rather than replaying the call; known recoverable failures observed in-process retain the bounded model-retry lifecycle
  • Same-conversation direct-provider follow-ups queue behind the cancelling generation; the old run keeps the active slot until terminal projection and cleanup, queued intent is checkpointed without credentials for restart recovery, and queued-only restore validates provider ownership and terminalizes the abandoned unprepared exchange from its persisted projection/stream identity before starting the successor; the next generation rebuilds provider history after cleanup so it includes the old generation's final committed output, and stale callbacks are ignored by stream identity
  • Known tools are in KNOWN_TOOLS in response_translator.rs; definitions are built by tool_definition_for_name() in convert_request.rs
  • Direct-provider normal and plan turns must advertise read_plan, create_plan, and edit_plan when the matching document capabilities are enabled; plan-creation requests should call create_plan after research rather than only returning prose
  • Unknown or invalid tool calls receive one correlated synthetic error result and a visible AgentOutput message; the durable run owns any continuation
  • recall_tool_history is an inline completed tool batch. ProviderRun commits its synthetic result and starts a bounded next turn without routing it through client action execution
  • recall_tool_history excludes earlier calls to itself; archived tool results remain searchable by query or exact tool_use_id
  • Before progressive summarization drains messages, ConversationMessage::archive_tool_results() moves tool-use/result pairs into tool_result_archive
  • Bedrock prompt caching uses three cache points: system prompt, second-to-last history message, and tool configuration
  • ensure_tool_results_paired() enforces Bedrock's invariant that every tool_use has a matching tool_result
  • Progressive summaries are prepended to provider requests as a user/assistant pair; direct-provider runs compact their live transcript at a checkpointed ReadyToCallModel boundary before another model call, while background summarization remains independent for session-owned runtimes
  • Loop prevention in controller.rs detects repeated tool failures (3+ identical) and injects a corrective instruction
  • Direct-provider long-running shell follow-ups retain CLI tasks as UI projections while command monitoring and completion stay owned by the same provider run
  • A direct-provider command completion is only queued when the terminal reports it; the CLI task remains active until the provider run applies that completion at a safe boundary and deactivates it
  • Provider command ownership is resolved from the active slot or its durable snapshot by block/action identity; completion arriving during restore is persisted into that snapshot and must never fall back to the legacy assessment path
  • Direct-provider completed-command assessments are hidden, tool-free root-task turns whose output and hidden input survive CLI-task deactivation and restoration
  • ACP remains a separate session-owned runtime; direct-provider cleanup must not move ACP lifecycle into ProviderRun
  • Orchestrated child conversations are leaf workers: nested RunAgents and legacy StartAgent calls are rejected before autonomy or permission bypasses, and child requests do not advertise delegation tools
  • Direct-provider RunAgents acknowledges linked local children and yields the parent generation after committing its launch results. Other tools in that launch batch are explicitly not executed. Persistent LocalAgentGroup membership survives parent follow-ups; only when every child reaches Success, Error, or Cancelled (with provider cleanup complete), or is removed/deleted, does one combined completion message wake the parent. Blocked, TransientError, and WaitingForEvents children remain pending. Restarts invalidate undelivered group results, and group delivery is confirmed only after the parent input is accepted.
  • StartAgentWaitPolicy follows child execution ownership, not parent run_id: grouped local children use LocalStartup, legacy local completion waits retain Completion, and hosted children use Startup with the hosted timeout. Direct-provider start_agent is normalized to a one-child RunAgents group. Cancelling or replacing a parent turn must not cancel independently running children or erase their group membership.
  • Hosted RunAgents startup timeouts detach the exact StartAgentRequestId; late launch callbacks must not register the child after the timeout result, while children linked before cancellation remain independently running

Galaxy Decides Permissions

  • GalaxyDecides is an execution-profile permission for Galaxy-owned files, commands, PTY input, MCP, computer use, and agent coordination. External CLI agents retain their own permission flows. Legacy AgentDecides profile values deserialize as GalaxyDecides; new profiles use it for file reads, file edits, and MCP.
  • app/src/ai/blocklist/action_model/risk_review.rs assesses the exact pending action with the active terminal-use model in a separate, tool-free request, falling back to the base model when the terminal-use model is unconfigured. Risk 0–3 permits automatic execution; 4–5 requires user approval. Existing denylist/protected-path/organization restrictions still require confirmation.
  • Invalid, unavailable, oversized, or timed-out assessments never grant execution. Assessment calls are bounded to 30 seconds; approval requests expire after 60 seconds and return a correlated denial telling the agent to choose another approach.
  • Reviews are scoped to conversation, action contents, and provider execution identity. Cancellation, replacement, and conversation cleanup invalidate them and cancel the reviewer request. Never treat a late callback or expired approval click as authorization.
  • Output polling and user-question behavior retain their existing policies. Risk assessment must not add another model call for each command-output poll.

Platform Setup

  • ./script/bootstrap - Platform-specific setup plus common agent skill installation from skills-lock.json; prompts for project/global when an install or update is needed unless a target flag or environment override is provided.
  • ./script/bootstrap --skip-common-skills - Platform setup without installing or updating common agent skills.
  • ./script/bootstrap --install-common-skills - Explicitly install common agent skills from skills-lock.json; this is the default behavior.
  • ./script/bootstrap --install-common-skills-in-repo - Platform setup plus common agent skill installation in this checkout's .agents/skills.
  • ./script/bootstrap --install-common-skills-globally - Platform setup plus common agent skill installation in ~/.agents/skills.
  • ../common-skills/scripts/install_common_skills --repo-root "$PWD" --project --if-needed - Install or refresh shared agent skills in this checkout's .agents/skills.
  • ../common-skills/scripts/install_common_skills --repo-root "$PWD" --global --if-needed - Install or refresh shared agent skills in ~/.agents/skills.
  • ../common-skills/scripts/remove_common_skills --repo-root "$PWD" - Remove shared agent skills listed in skills-lock.json from this checkout's .agents/skills.
  • ../common-skills/scripts/remove_common_skills --repo-root "$PWD" --global - Remove shared agent skills listed in skills-lock.json from ~/.agents/skills.
  • ../common-skills/scripts/remove_common_skills --repo-root "$PWD" --clear-lock - Remove shared agent skills from this checkout and delete skills-lock.json.
  • ./script/install_cargo_build_deps - Install Cargo build dependencies
  • ./script/install_cargo_test_deps - Install Cargo test dependencies

skills-lock.json is the standard project lock file managed by npx skills. warpdotdev/common-skills/scripts/install_common_skills requires an explicit install target before restoring: pass --project, pass --global, set WARP_COMMON_SKILLS_INSTALL_TARGET, or answer the interactive prompt from bootstrap. Non-interactive flows fail if no target is explicit. The installer creates skills-lock.json from warpdotdev/common-skills if it is missing, uses global as the recommended interactive default, errors if common skills are present in both project and global locations, prevents a global install pinned to one lock from being silently overwritten by another checkout pinned to a different lock, and verifies installed skills against the lock after successful install or skip paths. script/run and script/bootstrap execute this installer with script/resolve_common_skills, which uses WARP_COMMON_SKILLS_SCRIPTS_DIR only when explicitly set and otherwise runs the raw script from warpdotdev/common-skills. To test a remote common-skills branch, set WARP_COMMON_SKILLS_REF=<branch>. Cloud setup should use common-skills/scripts/install_common_skills --repo-root <warp-checkout> --project --if-needed --non-interactive or set WARP_COMMON_SKILLS_INSTALL_TARGET=project to avoid the prompt. To update the locked common skills, run npx --yes skills@1.5.6 update -p -y and commit the resulting skills-lock.json changes.

Architecture Overview

This is a Rust-based terminal emulator with a custom UI framework called GalaxyUI.

Key Components

GalaxyUI Framework (ui/):

  • Custom UI framework with Entity-Component-Handle pattern
  • Global App object owns all views/models (entities)
  • Views hold ViewHandle<T> references to other views
  • AppContext provides temporary access to handles during render/events
  • Elements describe visual layout (Flutter-inspired)
  • Actions system for event handling
  • MouseStateHandle must be created once during construction, and then referenced/cloned anywhere we're using mouse input to track mouse changes. Inline MouseStateHandle::default() while rendering will cause no mouse interactions to work.

Main App (app/):

  • Terminal emulation and shell management (terminal/)
  • AI integration including Agent Mode (ai/)
  • Cloud synchronization and Drive features (drive/)
  • Authentication and user management (auth/)
  • Settings and preferences (settings/)
  • Workspace and session management (workspace/)

Core Libraries:

  • crates/galaxy_core/ - Core utilities and platform abstractions
  • crates/editor/ - Text editing functionality
  • crates/galaxyui/ and crates/galaxyui_core/ - Custom UI framework
  • crates/ipc/ - Inter-process communication
  • crates/graphql/ - GraphQL client and schema

Key Architectural Patterns

  1. Entity-Handle System: Views reference other views via handles, not direct ownership
  2. Modular Structure: Workspace contains multiple workspace configurations, each with terminals, notebooks, etc.
  3. Cross-Platform: Native implementations for macOS, Windows, Linux, plus WASM target
  4. AI Integration: Built-in AI assistant with context awareness and codebase indexing
  5. Cloud Sync: Objects can be synchronized across devices via Galaxy Drive

Development Guidelines

Workspace Structure:

  • This is a Cargo workspace with 60+ member crates
  • Main binary is in app/, UI framework in crates/galaxyui/
  • Platform-specific code is conditionally compiled
  • Integration tests are in crates/integration/

Coding Style Preferences:

  • Avoid unnecessary type annotations, especially in closure params.
  • Avoid using too many Rust path qualifiers and use imports for concision. Place import statements at the top of the file as per convention. An exception to this is inside cfg-guarded code branches. In those cases, you can either embed the import into the relevant scope or just use an absolute path for one-offs.
  • If a function takes a context parameter (AppContext, ViewContext, or ModelContext), it should be named ctx and go last. The one exception is for functions that take a closure parameter, in which case the closure should be last.
  • Always remove unused parameters completely rather than prefixing them with _. Update the function signature and all call sites accordingly.
  • Prefer inline format arguments in macros like println!, eprintln!, and format! (for example, eprintln!("{message}") instead of eprintln!("{}", message)) to satisfy Clippy's uninlined_format_args lint.
  • Do not pass Itertools::format results directly to logging macros (log::*, safe_*, etc.). Itertools::format produces a single-use formatter, while logging implementations may format a message more than once. Use a reusable String such as iter.join(", ") for logging arguments instead. Direct use in format! or write! is fine.
  • Do not remove existing comments when making unrelated changes. Only remove or modify a comment if the logic it describes has changed.
  • When adding a toggleable setting, also add the matching Command Palette enable/disable entry and any required context flags so the setting is discoverable outside Settings.

Terminal Model Locking:

  • Be extremely careful when calling model.lock() on the terminal model (TerminalModel). Acquiring multiple locks on the same model from different call sites can cause a deadlock, resulting in a UI freeze (beach ball on macOS).
  • Before adding a new model.lock() call, verify that no caller in the current call stack already holds the lock.
  • Prefer passing already-locked model references down the call stack rather than acquiring new locks.
  • If you must lock the model, keep the lock scope as short as possible and avoid calling other functions that might also attempt to lock.

Testing:

  • Use cargo nextest for parallel test execution
  • Integration tests use custom framework in integration/
  • Tests should be run via presubmit script before submitting
  • Unit tests should be placed in separate files using the naming convention ${filename}_tests.rs or mod_test.rs
  • Test files should be included at the end of their corresponding module with:
    #[cfg(test)]
    #[path = "filename_tests.rs"]  // or "mod_test.rs"
    mod tests;
    

Pull Request Workflow:

  • ALWAYS run ./script/format and cargo clippy (the versions specified in ./script/presubmit) before opening a PR or pushing updates to an existing PR branch
  • Those commands must pass completely before creating or updating a pull request
  • Specifically, ensure ./script/format and cargo clippy checks pass
  • If they fail, fix all issues before proceeding with the PR
  • Do not create public pull requests or public issues that disclose a non-public security vulnerability. Refer users to SECURITY.md for the proper disclosure methods instead.
  • This applies to:
    • Opening new pull requests
    • Pushing new commits to existing PR branches
    • Any branch updates that will be reviewed
  • When opening PRs, use the PR template at .github/pull_request_template.md
  • Add changelog entries when appropriate using the format at the bottom of the PR template. Use the following prefixes (without the {{}} brackets):
    • CHANGELOG-NEW-FEATURE: for new, relatively sizable features (use sparingly - these may get marketing/docs)
    • CHANGELOG-IMPROVEMENT: for new functionality of existing features
    • CHANGELOG-BUG-FIX: for fixes related to known bugs or regressions
    • CHANGELOG-IMAGE: for GCP-hosted image URLs
    • Leave changelog lines blank or remove them if no changelog entry is needed

Database:

  • Uses Diesel ORM with SQLite
  • Migrations in migrations/ directory
  • Schema defined in app/src/persistence/schema.rs
  • Database file is galaxy.sqlite (renamed from Warp's warp.sqlite); legacy filename migration is handled in init_db()

Session Restoration:

  • Controlled by general.restore_session setting
  • App state (windows, tabs, pane tree, CWD, agent conversations) is snapshotted to SQLite on window events (close, move, resize, focus change)
  • TerminalView::active_session_path_if_local() provides the CWD for each pane; falls back to session_startup_path for agent-mode or fresh tabs
  • Agent conversations are persisted via BlocklistAIHistoryEvent → ModelEvent::UpsertAIQuery and restored via RestoredAgentConversations singleton
  • The active_conversation_id field in TerminalPaneSnapshot controls whether agent view restores in fullscreen mode

GraphQL:

  • Schema and client code generation from crates/galaxy_graphql_schema/api/schema.graphql
  • TypeScript types generated for frontend integration

Feature Flags

Warp uses compile-time feature flags with a small runtime plumbing layer.

How to add a feature flag:

  • Add a new variant to galaxy_core/src/features.rs in the FeatureFlag enum
  • (Optional) Enable it by default for dogfood builds by listing it in DOGFOOD_FLAGS
  • Gate code paths with FeatureFlag::YourFlag.is_enabled()
  • For preview or release rollout, add to PREVIEW_FLAGS or RELEASE_FLAGS respectively (as appropriate)

Best practices:

  • Prefer runtime checks over cfg directives: Prefer FeatureFlag::YourFlag.is_enabled() over #[cfg(...)] compile-time directives so flags can be toggled without recompilation and are easier to clean up later. Use #[cfg(...)] only when the code cannot compile without them (for example, platform-specific code or dependencies that do not exist when the feature is disabled).
  • Keep flags high-level and product-focused rather than per-call-site
  • Remove the flag and dead branches after launch has stabilized
  • For UI sections that expose a new feature, hide the UI behind the same flag

Example:

#[derive(Sequence)]
pub enum FeatureFlag {
    YourNewFeature,
}

// Default-on for dogfood builds
pub const DOGFOOD_FLAGS: &[FeatureFlag] = &[
    FeatureFlag::YourNewFeature,
];

// Use in code
if FeatureFlag::YourNewFeature.is_enabled() {
    // gated behavior
}

Code Editor IntelliSense (LSP Completion)

The code editor has full LSP-powered autocompletion with documentation resolution:

Key files:

  • app/src/code/completion.rs — Completion state, rendering (menu + docs panel), resolve logic
  • app/src/code/local_code_editor.rs — Keybindings and action handling

Behavior:

  • Auto-completes as you type (triggered by alphanumeric/underscore with 50ms debounce)
  • Trigger characters: . and :: fire immediately
  • Manual trigger: Ctrl+Space while the code editor is focused
  • Keyboard navigation: Up/Down to select, Tab/Enter to confirm
  • Mouse: hover an item to select it and show docs, click to confirm
  • Documentation panel appears beside the menu when the LSP returns docs for the selected item (via completionItem/resolve)

Architecture:

  • CompletionState::Showing holds items, filtered indices, per-item MouseStateHandles, and resolved docs
  • resolve_selected_completion_docs() sends completionItem/resolve to the LSP server
  • The docs panel renders markdown via FormattedTextElement in a scrollable container beside the menu

Exhaustive Matching

When adding/editing match statements, avoid using the wildcard _ when at all possible. Exhaustive matching is helpful for ensuring that all variants are handled, especially when adding new variants to enums in the future.

Rules System

Global rules (behavioral instructions for the AI agent) are stored as AIFact::Memory cloud objects and managed via the Rules settings pane.

Key files:

  • app/src/ai/facts/mod.rs — AIFact / AIMemory data model
  • app/src/ai/facts/predefined_rules.rs — Default system-defined rules (seeded on first launch)
  • app/src/ai/facts/view/rule.rs — RuleView UI with Global/Project tabs and "Add Predefined Rules" button
  • app/src/ai/facts/view/mod.rs — AIFactView parent container (Rules + RuleEditor pages)
  • app/src/ai/facts/manager.rs — AIFactManager singleton for pane tracking
  • app/src/settings/ai.rs — has_seeded_predefined_rules setting (one-time flag)

Behavior:

  • On first launch (no existing global rules and has_seeded_predefined_rules is false), predefined rules are automatically created
  • The "Add Predefined Rules" button in the Global rules tab will add/update system-defined rules (identified by the "System Defined Rule" name prefix)
  • Rules are persisted via the cloud object sync system (UpdateManager::create_ai_fact / update_ai_fact)
  • The memory_enabled setting (agents.knowledge.rules_enabled) controls whether rules are sent to the AI

Appearance Settings Notes

  • Galaxy's built-in brand themes are available as GalaxyDark and GalaxyDay.
  • UI font selection is persisted in appearance.text.ui_font_name and uses an empty string as the system-default sentinel.
  • The one-click Galaxy brand preset is implemented in app/src/settings_view/appearance_page.rs and applies:
    • Galaxy Dark/Day system theme mapping
    • terminal + AI font defaults
    • the bundled, SIL Open Font License-licensed Roboto UI font