ci / lint-test-leaks (pull_request) Canceled after 0s
- cayceops core: env-only config (CAYCE_OPS_*), engine/session, ORM models with state machines (proposal/mail/content) and audited writes - provider-agnostic LLM interface (null provider default, stdlib openai-compat) - Typer CLI with lazy component loading (scanner/executor/maild/publisher/monitor) - alembic 0001 initial schema; sqlite-portable JSON columns - tests: 7 passing on throwaway sqlite; fixtures invented, never real data - ci: ruff + alembic smoke + pytest + gitleaks(full history) in .gitea/workflows + .github/workflows; local gate = make check - deploy: docker-compose (postgres 16) + hardened systemd units/timers - docs: DECISIONS D1-D9; README project (grant text retired)
168 lines
5.3 KiB
Python
168 lines
5.3 KiB
Python
"""Cayce Ops — configuration.
|
|
|
|
All configuration comes from environment variables prefixed with ``CAYCE_OPS_``.
|
|
No config files, no defaults that touch the network. See .env.example for the
|
|
full list with placeholder values.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from dataclasses import dataclass, field
|
|
|
|
|
|
def _bool(name: str, default: bool = False) -> bool:
|
|
raw = os.environ.get(name)
|
|
if raw is None:
|
|
return default
|
|
return raw.strip().lower() in {"1", "true", "yes", "on"}
|
|
|
|
|
|
def _int(name: str, default: int) -> int:
|
|
raw = os.environ.get(name)
|
|
if raw is None or not raw.strip():
|
|
return default
|
|
return int(raw)
|
|
|
|
|
|
def _list(name: str, default: list[str] | None = None) -> list[str]:
|
|
raw = os.environ.get(name)
|
|
if raw is None or not raw.strip():
|
|
return list(default or [])
|
|
return [item.strip() for item in raw.split(",") if item.strip()]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Config:
|
|
"""Snapshot of the process environment. Constructed once per CLI invocation."""
|
|
|
|
# --- core ---
|
|
database_url: str = field(
|
|
default_factory=lambda: os.environ.get(
|
|
"CAYCE_OPS_DATABASE_URL", "sqlite:///cayce-ops.db"
|
|
)
|
|
)
|
|
autonomous_mode: bool = field(
|
|
default_factory=lambda: _bool("CAYCE_OPS_AUTONOMOUS_MODE", False)
|
|
)
|
|
log_level: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_LOG_LEVEL", "INFO")
|
|
)
|
|
state_dir: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_STATE_DIR", ".")
|
|
)
|
|
media_dir: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_MEDIA_DIR", "./media")
|
|
)
|
|
|
|
# --- scanner ---
|
|
scanner_sources: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_SCANNER_SOURCES", "[]")
|
|
)
|
|
scanner_keywords: list[str] = field(
|
|
default_factory=lambda: _list(
|
|
"CAYCE_OPS_SCANNER_KEYWORDS",
|
|
["affiliate", "partnership", "bitcoin", "lightning", "travel"],
|
|
)
|
|
)
|
|
scanner_user_agent: str = field(
|
|
default_factory=lambda: os.environ.get(
|
|
"CAYCE_OPS_SCANNER_USER_AGENT", "cayce-ops-scanner/0.1"
|
|
)
|
|
)
|
|
|
|
# --- executor ---
|
|
autonomous_kinds: list[str] = field(
|
|
default_factory=lambda: _list("CAYCE_OPS_AUTONOMOUS_KINDS", [])
|
|
)
|
|
autonomous_daily_cap: int = field(
|
|
default_factory=lambda: _int("CAYCE_OPS_AUTONOMOUS_DAILY_CAP", 0)
|
|
)
|
|
max_attempts: int = field(
|
|
default_factory=lambda: _int("CAYCE_OPS_MAX_ATTEMPTS", 2)
|
|
)
|
|
enable_http_actions: bool = field(
|
|
default_factory=lambda: _bool("CAYCE_OPS_ENABLE_HTTP_ACTIONS", False)
|
|
)
|
|
|
|
# --- mail ---
|
|
imap_host: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_IMAP_HOST", "")
|
|
)
|
|
imap_port: int = field(default_factory=lambda: _int("CAYCE_OPS_IMAP_PORT", 993))
|
|
imap_user: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_IMAP_USER", "")
|
|
)
|
|
imap_password: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_IMAP_PASSWORD", "")
|
|
)
|
|
imap_mailbox: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_IMAP_MAILBOX", "INBOX")
|
|
)
|
|
smtp_host: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_SMTP_HOST", "")
|
|
)
|
|
smtp_port: int = field(default_factory=lambda: _int("CAYCE_OPS_SMTP_PORT", 587))
|
|
smtp_user: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_SMTP_USER", "")
|
|
)
|
|
smtp_password: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_SMTP_PASSWORD", "")
|
|
)
|
|
mail_from: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_MAIL_FROM", "")
|
|
)
|
|
|
|
# --- llm ---
|
|
llm_provider: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_LLM_PROVIDER", "null")
|
|
)
|
|
llm_model: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_LLM_MODEL", "")
|
|
)
|
|
llm_base_url: str = field(
|
|
default_factory=lambda: os.environ.get(
|
|
"CAYCE_OPS_LLM_BASE_URL", "https://api.openai.com/v1"
|
|
)
|
|
)
|
|
llm_api_key: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_LLM_API_KEY", "")
|
|
)
|
|
llm_review_threshold: float = field(
|
|
default_factory=lambda: float(
|
|
os.environ.get("CAYCE_OPS_LLM_REVIEW_THRESHOLD", "0.7")
|
|
)
|
|
)
|
|
|
|
# --- publisher / nostr ---
|
|
nostr_private_key: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_NOSTR_PRIVATE_KEY", "")
|
|
)
|
|
nostr_relays: list[str] = field(
|
|
default_factory=lambda: _list("CAYCE_OPS_NOSTR_RELAYS", [])
|
|
)
|
|
enable_facebook: bool = field(
|
|
default_factory=lambda: _bool("CAYCE_OPS_ENABLE_FACEBOOK", False)
|
|
)
|
|
facebook_page_token: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_FACEBOOK_PAGE_TOKEN", "")
|
|
)
|
|
enable_instagram: bool = field(
|
|
default_factory=lambda: _bool("CAYCE_OPS_ENABLE_INSTAGRAM", False)
|
|
)
|
|
instagram_user_id: str = field(
|
|
default_factory=lambda: os.environ.get("CAYCE_OPS_INSTAGRAM_USER_ID", "")
|
|
)
|
|
|
|
# --- monitor ---
|
|
monitor_output: str = field(
|
|
default_factory=lambda: os.environ.get(
|
|
"CAYCE_OPS_MONITOR_OUTPUT", "./status.html"
|
|
)
|
|
)
|
|
|
|
|
|
def load() -> Config:
|
|
"""Build the process Config snapshot."""
|
|
return Config()
|