smriti/.env.example
Himanshu Dongre 713ed9a007 Refuse to silently extract mock content into a real Space
A fresh Smriti install with no provider configured could still run
`smriti checkpoint create --extract`, which silently returned
MockAdapter content like "Mock decision from provider". If committed,
that placeholder text became part of the user's real reasoning state.

Root cause: backend/app/api/routes/checkpoint.py:417 called
`get_adapter(cfg.background.provider, allow_mock=True)`. The
`allow_mock=True` flag means the registry quietly returns MockAdapter
when no API key is configured, rather than raising. The CLI received
the canned mock JSON and committed it without inspecting whether it
came from a real LLM.

The extract endpoint was the only route in the codebase with this
pattern — draft, review, chat title, and chat send already correctly
pass `allow_mock=False`.

The new contract:

- Core Smriti (setup, doctor, quickstart, state/current/metrics,
  claims, attach, manual JSON checkpoints) requires no API key.
- Real LLM-backed paths (`--extract`, draft, review, chat send)
  require a configured provider — OpenAI / Anthropic / OpenRouter /
  generic OpenAI-compatible (local models like Ollama).
- Mock extraction still works for tests and demos, but only when the
  caller explicitly opts in (use_mock=true on the HTTP payload).
  It is never silently the default.

Backend:
- POST /api/v5/checkpoint/extract now passes allow_mock=False and
  catches ProviderNotConfiguredError, returning HTTP 412 with a
  structured detail: error code, human message, the provider it
  tried, and a list of fix paths the CLI surfaces.
- CheckpointExtractResponse gains `provider` and `model` echo fields
  (additive, default empty) so callers can confirm what answered.

CLI:
- checkpoint create --extract catches 412 and prints the actionable
  fix list; exits 78 (EX_CONFIG). Defense in depth: even on a 200,
  refuses to commit if response.provider == "mock" on the default
  path (so any future regression in the backend is still caught).
- smriti doctor surfaces background provider state prominently:
  `ready (real LLM extraction enabled)` or `⚠ MOCK or DISABLED — …
  will fail until a provider is configured`.
- smriti doctor --strict exits 78 when the background provider is
  mock/disabled or the backend is unreachable. Safe to wire into
  CI before any --extract step.
- On a successful --extract commit, the CLI shows `extracted via
  <provider>/<model>` under the commit confirmation.

Docs:
- README: new "Provider configuration (LLM-backed features)" section
  drawing the boundary explicitly; mentions the generic provider for
  local OpenAI-compatible models; flags mock as test-only.
- .env.example: rewrote the provider section so an empty key or a
  model-without-a-key is not interpreted as "ready".
- Skill pack template: new §4.1 "Before your first --extract: verify
  the provider" telling agents to run `smriti doctor`, refuse
  --extract when background_provider is mock/disabled, and fall back
  to manual JSON checkpoints or ask the human to configure a
  provider. Re-rendered to AGENTS.md (Codex target). The Claude Code
  target (.claude/skills/smriti/SKILL.md) is gitignored per-user
  install; rerun `smriti skills install claude-code` to refresh.
- website/index.html: Try-it lede now spells out which features need
  a provider rather than gesturing at "optional LLM features".

Tests:
- test_extract_without_provider_fails_loud: regression for the bug —
  monkeypatches get_adapter to raise ProviderNotConfiguredError,
  asserts HTTP 412 with the structured detail shape, and asserts
  the response body contains neither "Mock decision from provider"
  nor "Mock Checkpoint". This test would fail on pre-fix code.
- test_extract_with_provider_echoes_provider_and_model: pins the
  green path — provider and model must be echoed and must not be
  "mock" when the real adapter answers.
- test_extract_happy_path_with_mock: unchanged, still pins the
  explicit use_mock=true contract.
- Full backend integration suite: 165 passed locally (with the
  pre-existing real-provider draft test passing under
  backend/config/providers.yaml).
2026-05-23 17:48:14 +05:30

79 lines
3.6 KiB
Text

# Smriti - Environment Variables
# Copy this file to .env and fill in the values.
#
# The backend loads this file via python-dotenv at startup so API keys
# are available even when the server is launched by a process that does
# not inherit your shell profile (e.g. uvicorn from an IDE, a CI
# runner, or a subprocess-based tool host like Claude Code).
#
# Existing env vars are NOT overridden — if you also export a key in
# your shell profile, the shell value takes precedence.
# Database
#
# Solo/local mode is the low-friction default. It uses a local SQLite
# database file and does not require Docker or Postgres.
SMRITI_DB_MODE=local
# Optional: override the local SQLite database path.
# Default: ~/.smriti/smriti.db
# SMRITI_LOCAL_DB_PATH=~/.smriti/smriti.db
# Shared/team mode: uncomment for Postgres-backed operation.
# If DATABASE_URL is explicitly set to a Postgres URL, Smriti preserves
# Postgres behavior.
# SMRITI_DB_MODE=postgres
# DATABASE_URL=postgresql://smriti:smriti@localhost:5432/smriti
# ────────────────────────────────────────────────────────────────────────
# Provider configuration (LLM-backed features only)
# ────────────────────────────────────────────────────────────────────────
#
# Core Smriti — setup, doctor, quickstart, state/current/metrics, claims,
# attach, and hand-written checkpoints — works WITHOUT any API key.
#
# These features require a real configured provider:
# - `smriti checkpoint create --extract`
# - `smriti checkpoint review`
# - checkpoint draft
# - chat UI send loop
#
# Without a provider, those paths refuse to run (HTTP 412) rather than
# silently returning placeholder MockAdapter content. Mock content is for
# tests and demos only; it must never be committed into a real project.
#
# Uncomment ONE of the keys below for a hosted provider, OR configure the
# generic provider (further down) for a local OpenAI-compatible model.
#
# IMPORTANT: do not leave a key set to empty (e.g. OPENAI_API_KEY=).
# An empty value is actively placed into os.environ by dotenv and can
# mask the yaml fallback. Either set a real key or leave the line commented.
# Setting OPENAI_MODEL alone (below) without OPENAI_API_KEY is NOT enough —
# the model needs an actual provider with credentials behind it.
#
# OPENAI_API_KEY=your-openai-key-here
# ANTHROPIC_API_KEY=your-anthropic-key-here
# OPENROUTER_API_KEY=your-openrouter-key-here
# Default model for background intelligence (extraction, draft, review).
# Only takes effect when a provider key (above) is set or the generic
# provider (below) is configured.
OPENAI_MODEL=gpt-4o-mini
# Generic OpenAI-compatible provider — Ollama, LM Studio, vLLM, Together, etc.
# Use this slot for a LOCAL model (or any OpenAI-API-compatible endpoint).
# API key may be optional for local servers; OpenAI SDK accepts any non-empty
# string. Then set background_intelligence.provider to "generic" in
# backend/config/providers.yaml.
#
# Extraction is usually a lightweight structured-output task and is often
# handled well by cost-efficient or local models, but quality varies — try
# `smriti checkpoint create --extract --dry-run` on a representative
# document before relying on a small model for real work.
#
# SMRITI_GENERIC_API_URL=http://localhost:11434/v1
# SMRITI_GENERIC_MODEL=llama3.1:8b
# SMRITI_GENERIC_API_KEY=not-required
# App
DEBUG=false