AGENTS.md@packages/config · git:20261024.d05c2c6 · 2026-10-24 · sha256 d3651fdfbf1a0c4c
AGENTS.md@packages/config git:20261024.d05c2c6A
Immutable. This exact content never changes and is served at /api/v1/blob/d3651fdfbf1a0c4c.
# config ## Purpose Typed environment parsing and managed-run presentation schemas. `loadConfig()` and `saveConfigPatch()` live in `packages/canonry/src/config.ts`; `loadConfig()` validates `dashboard.managedSweeps` and `dashboard.managedRunKinds` without rewriting the dashboard block. The list uses `schedulableRunKindSchema`. ## Key Files | File | Role | |------|------| | `src/index.ts` | `dashboardManagedRunKindsSchema`, `dashboardManagedSweepsSchema`, `getPlatformEnv()`, `getBootstrapEnv()` | | `src/classification.ts` | Independent generative domain-classification provider/model role | | `src/sentiment.ts` | Private enablement, direct/routed Jev evaluator and readiness | | `src/seo.ts` | Explicit host funding mode, integer-micro budget caps and discriminated SEO credentials. Stored only in config.yaml; never accepted as a project API argument. | ## Patterns - **Config source priority**: Environment variables override `config.yaml` values. - **OpenRouter roles**: `OPENROUTER_API_KEY` / `OPENROUTER_MODEL` are parsed in the bootstrap and platform paths. `classification` selects domain categorization independently of sweep and Aero models. Sentiment uses `sentiment.provider` or `CANONRY_SENTIMENT_PROVIDER`, and `CANONRY_SENTIMENT_MODEL`; direct TypeSafe also accepts `TYPESAFE_MODEL`. Routed sentiment reads the shared OpenRouter credential, never `sentiment.apiKey`. Only the pinned model for the selected sentiment provider is ready. - **`getBootstrapEnv()`**: never injects a default. An unset model stays undefined and quotas are never read, so a bootstrap rerun keeps saved values. `withBootstrapProviderDefaults()` fills only a new entry's gaps (`BOOTSTRAP_PROVIDER_DEFAULT_MODELS`, `BOOTSTRAP_PROVIDER_DEFAULT_QUOTA`). - **`loadConfig()`**: Loads config for CLI commands (via `createApiClient()`) and the server. Preserve legacy dashboard fields and their key order; never replace the block with schema parse output. An invalid managed boolean or run-kind list raises a path-qualified `CliError` (exit 1). Missing or blank values leave the opt-in unset. - **`saveConfigPatch()`**: Merges partial updates into `~/.canonry/config.yaml`. - **Base path**: `CANONRY_BASE_PATH` env var and `basePath` in config.yaml are merged into `apiUrl`. ## Common Mistakes - **Reading env vars directly instead of using `loadConfig()`** — the config module handles validation and defaults. - **Storing secrets in the database** — credentials belong in `~/.canonry/config.yaml`. ## See Also - `packages/contracts/src/config-schema.ts` — Zod schemas for config validation - `packages/canonry/src/client.ts` — `createApiClient()` uses `loadConfig()`