brainos-core 0.3.0

Configuration and bootstrapping for Brain OS cognitive engine
Documentation
# ─── Brain OS — Configuration ─────────────────────────────────────────────────
# Generated by `brain init`. Edit to customise your setup.
# Env-var override for any key: BRAIN_<SECTION>__<KEY>  (e.g. BRAIN_LLM__API_KEY)

# ── LLM Providers ──────────────────────────────────────────────────────────────
# Brain probes each entry at startup, picks the first reachable one, and
# automatically falls over to the next on rate-limit or error.
#
# kind: ollama | groq | openai | openrouter | deepseek | together | gemini-compat
llm:
  temperature: 0.7
  max_tokens: 4096
  providers:
    - name: ollama
      kind: ollama
      base_url: "http://localhost:11434"
      model: "qwen2.5-coder:7b"
      preferred_models: ["qwen2.5-coder:7b", "llama3.1:8b"]
    # - name: groq
    #   kind: groq
    #   api_key: "gsk_..."
    #   model: "llama-3.3-70b-versatile"
    #   preferred_models: ["llama-3.3-70b-versatile", "llama-3.1-8b-instant"]
    # - name: openrouter
    #   kind: openrouter
    #   api_key: "sk-or-..."
    #   model: "meta-llama/llama-3.1-8b-instruct:free"
    #   preferred_models: ["meta-llama/llama-3.1-8b-instruct:free"]
  # Legacy single-provider fallback — only used when providers list is empty.
  provider: "ollama"
  model: "qwen2.5-coder:7b"
  base_url: "http://localhost:11434"
  api_key: ""

# ── Embedding ──────────────────────────────────────────────────────────────────
# Run `ollama pull nomic-embed-text` before starting Brain.
# dimensions must match the model's actual output size exactly.
embedding:
  model: "nomic-embed-text"
  dimensions: 768

# ── Memory ─────────────────────────────────────────────────────────────────────
memory:
  episodic: {}
  semantic:
    similarity_threshold: 0.65
    max_results: 20
  search:
    rrf_k: 60                   # Reciprocal Rank Fusion constant
    pre_fusion_limit: 50        # candidates fetched from each source (BM25, ANN) before fusion
    importance_weight: 0.3      # weight for importance in final reranking
    recency_weight: 0.2         # weight for recency in final reranking
    decay_rate: 0.01            # forgetting-curve decay rate (higher = faster forgetting)
  consolidation:
    enabled: true
    interval_hours: 24
    forgetting_threshold: 0.05

# ── Encryption ─────────────────────────────────────────────────────────────────
# Run `brain init --encrypt` to generate a salt and enable at-rest encryption.
encryption:
  enabled: false

# ── Security ───────────────────────────────────────────────────────────────────
security:
  # Binaries the sandbox is allowed to execute. The list is intentionally
  # narrow — read-only inspection plus the toolchain. To run anything else
  # (docker, brew, ssh, custom scripts), add it here explicitly.
  exec_allowlist: [
    "ls", "cat", "head", "tail", "wc", "file", "stat",
    "grep", "find", "sort", "uniq", "cut", "awk", "sed",
    "which", "command", "type", "test", "basename", "dirname", "realpath",
    "echo", "printf", "true", "false",
    "git", "cargo", "rustc", "rustup",
    # `sh` enables the shell-wrapped execution tier for commands the
    # LLM produces with pipes, redirects, or PATH-dependent binaries.
    # When invoked via the shell tier the per-binary allowlist is
    # bypassed for the wrapped command; rlimits, Seatbelt network deny,
    # timeout, and the explicit forbidden_commands list still apply.
    "sh",
  ]
  exec_timeout_seconds: 30

# ── Actions ────────────────────────────────────────────────────────────────────
actions:
  web_search:
    # On by default. The "duckduckgo" provider is a zero-config built-in
    # that works without Docker or an API key — basic quality, but always
    # available. Switch to "searxng" (run `brain deps up` first) for the
    # best results, or "tavily" with an API key for a hosted option.
    enabled: true
    provider: "duckduckgo"      # duckduckgo | searxng | tavily | custom
    endpoint: "http://localhost:8888"  # used by searxng/custom only
    api_key: ""                 # required for tavily
    timeout_ms: 3000
    default_top_k: 5
  scheduling:
    enabled: false
    mode: "persist_only"
  messaging:
    enabled: false
    timeout_ms: 3000
    channels: {}
    # Webhook channel example — works for Discord, Telegram, Slack, or any HTTP endpoint.
    # Template vars: {{channel}} {{recipient}} {{content}} {{namespace}} {{timestamp}}
    #
    #   discord:
    #     url: "https://discord.com/api/webhooks/<ID>/<TOKEN>"
    #     body: '{"content": "{{content}}"}'
    #     headers: {}
    #   telegram:
    #     url: "https://api.telegram.org/bot<TOKEN>/sendMessage"
    #     body: '{"chat_id": "<CHAT_ID>", "text": "{{content}}", "parse_mode": "Markdown"}'
    #     headers: {}
  resilience:
    max_retries: 2
    retry_base_ms: 500
    circuit_breaker_threshold: 5
    circuit_breaker_cooldown_secs: 60

# ── Proactivity ────────────────────────────────────────────────────────────────
proactivity:
  enabled: true
  max_per_day: 2
  min_interval_minutes: 60
  quiet_hours:
    start: "20:00"
    end: "10:00"
    timezone: "UTC"             # IANA timezone, e.g. "America/New_York"
  delivery:
    outbox: true
    broadcast: true
    webhook_channels: []        # channel keys from actions.messaging.channels
    max_outbox_age_days: 7
  open_loop:
    enabled: true
    scan_window_hours: 72
    resolution_window_hours: 24
    check_interval_minutes: 120

# ── Adapters ───────────────────────────────────────────────────────────────────
adapters:
  http:
    enabled: true
    host: "127.0.0.1"
    port: 19789
    cors: true
  ws:
    enabled: true
    port: 19790
  mcp:
    enabled: true
    stdio: true
    http: true
    port: 19791
  grpc:
    enabled: true
    port: 19792

# ── Channel Relays ─────────────────────────────────────────────────────────────
# Bidirectional WebSocket gateways. Unlike webhooks these are long-lived
# connections — approval responses from any relay are correlated automatically.
channel:
  relays: []
  # - id: telegram
  #   label: "Telegram"
  #   url: "ws://127.0.0.1:7000/brain"
  #   namespace: "personal"
  #   api_key: ""
  #   initial_backoff_ms: 1000
  #   max_backoff_ms: 60000

# ── Agents ─────────────────────────────────────────────────────────────────────
# Specialist agents the orchestrator delegates multi-step tasks to.
agents:
  delegates: []
  fallbacks: []
  retry_on_timeout: true
  # Auto-discovery (default ON below) finds well-known CLI agents on $PATH
  # without needing manual entries. Use `delegates[]` for bespoke binaries
  # or non-standard invocation flags.
  # - name: script
  #   kind: subprocess
  #   binary: "/usr/local/bin/my-agent"
  #   args: ["--task", "{task_id}"]
  #   prompt_via_stdin: true
  #   tags: ["custom"]

# ── Access ─────────────────────────────────────────────────────────────────────
# A random key is generated on `brain init` and printed once to stdout.
access:
  api_keys: []

# ── Internal defaults (safe to leave unchanged) ────────────────────────────────
brain:
  version: "0.2.0"
  data_dir: "~/.brain"

storage:
  ruvector_path: "~/.brain/ruvector/"
  sqlite_path: "~/.brain/db/brain.db"
  hnsw:
    ef_construction: 200
    m: 16
    ef_search: 50