# pg_sage configuration # Copy this file to config.yaml and fill in your values. mode: standalone postgres: host: # e.g., 10.0.0.5, your-instance.region.cloudsql port: 5432 user: sage_agent password: database: postgres # or your application database sslmode: require # use "disable" for local dev only max_connections: 5 collector: interval_seconds: 60 # how often to snapshot pg_stat_statements analyzer: interval_seconds: 120 # how often to run analysis slow_query_threshold_ms: 500 # queries slower than this are flagged seq_scan_min_rows: 10000 # seq scans on tables larger than this are flagged unused_index_window_days: 7 # indexes unused for this many days are flagged table_bloat_dead_tuple_pct: 10 # dead tuple ratio threshold for bloat findings trust: level: observation # start with observation, promote after review # observation: findings only, no actions (day 0-7) # advisory: safe actions like dropping unused indexes (day 8-30) # autonomous: moderate actions like creating indexes (day 31+) maintenance_window: always # when moderate actions may run: always, # never, nights, weeknights, weekends, # "weekdays 01:00-05:00", or a cron # expression such as "0 3 * * 0" # Fast elevation. By default pg_sage earns trust over weeks (8-day SAFE # ramp, 31-day MODERATE ramp, 7-day IO baseline, 30-day shadow, 50 live # recoveries for L3). On a database you are dogfooding, uncomment the # profile below to elevate in hours. The sidecar logs a FAST ELEVATION # warning per lowered value. Irreversible actions keep the full ramp and # never exceed L1, and an admin still approves every promotion. Merge the # keys into the sections above rather than repeating a section. # --- fast elevation (dogfood) profile: start --- # trust: # ramp_safe_hours: 1 # ramp_moderate_hours: 4 # verify: # io_baseline_hours: 2 # drop_window_hours: 2 # sre: # autonomy: # evaluate_interval_minutes: 5 # promotion: # shadow_window_hours: 4 # shadow_min_reviewed: 3 # min_live_recoveries: 3 # --- fast elevation (dogfood) profile: end --- safety: ddl_timeout_seconds: 300 # per-statement ceiling for executor DDL # LLM configuration. LLM features are on by default and call a provider # only once endpoint and api_key are set; until then pg_sage uses its # deterministic rules. token_budget_daily caps the daily spend. llm: enabled: true # false turns every LLM feature off endpoint: "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions" model: "gemini-2.5-flash" api_key: ${SAGE_GEMINI_API_KEY} # set via environment variable timeout_seconds: 60 token_budget_daily: 100000 # Index optimizer (on by default; needs a configured LLM) optimizer: enabled: true # false turns off LLM index recommendations min_query_calls: 100 # minimum query calls before analyzing a table max_new_per_table: 3 # max new indexes recommended per table per cycle # Configuration advisor (on by default; needs a configured LLM) advisor: enabled: true # false turns off vacuum/WAL/connection/memory advice interval_seconds: 86400 # how often to run configuration analysis # Optional: dedicated model for index optimization (higher quality, higher # cost, and its own token_budget_daily). Off by default. This block nests # under llm: as llm.optimizer_llm. # optimizer_llm: # enabled: true # endpoint: "https://api.anthropic.com/v1" # model: "claude-opus-4-6" # api_key: ${SAGE_OPTIMIZER_LLM_API_KEY} # timeout_seconds: 120 # token_budget_daily: 50000 # max_output_tokens: 2048 # fallback_to_general: true # Notification channel targets (Slack/webhook URLs, SMTP hosts). Private # addresses (loopback, RFC 1918, ULA, CGNAT) and plain http are refused # unless allowed here, e.g. for an internal SMTP relay. Link-local and # cloud metadata addresses are always refused. YAML only; requires restart. # notification_policy: # allow_private_targets: false # Prometheus metrics endpoint prometheus: listen_addr: "0.0.0.0:9187" # REST API + Dashboard (web UI) api: listen_addr: "0.0.0.0:8080" # ------------------------------------------------------------------- # Fleet Mode (monitor multiple databases from a single sidecar) # ------------------------------------------------------------------- # To use fleet mode, change mode to "fleet" and replace the postgres # block with a databases list: # # mode: fleet # # defaults: # max_connections: 3 # trust_level: observation # collector_interval_seconds: 60 # analyzer_interval_seconds: 300 # # databases: # - name: prod-orders # host: orders.db.internal # port: 5432 # user: sage_agent # password: ${SAGE_PG_PASSWORD_ORDERS} # database: orders # sslmode: require # tags: [production, critical] # trust_level: advisory # # - name: prod-users # host: users.db.internal # port: 5432 # user: sage_agent # password: ${SAGE_PG_PASSWORD_USERS} # database: users # sslmode: require # tags: [production] # # - name: staging # host: staging.db.internal # port: 5432 # user: sage_agent # password: ${SAGE_PG_PASSWORD_STAGING} # database: staging # sslmode: prefer # tags: [staging] # executor_enabled: false # llm_enabled: false