Skip to content

Plan 008: Add .env.example and document which model providers actually work out of the box #21

Description

@strickvl

Plan 008: Add .env.example and document which model providers actually work out of the box

Executor instructions: Follow this plan step by step. Run every
verification command and confirm the expected result before moving to the
next step. If anything in the "STOP conditions" section occurs, stop and
report — do not improvise. When done, update the status row for this plan
in plans/README.md.

Drift check (run first): git diff --stat 5b5c634..HEAD -- README.md src/constants.py src/utils/provider_routing.py
If provider_routing.py or constants.py changed since this plan was
written, re-derive the env-var list from the live code before writing docs.

Status

  • Priority: P3
  • Effort: S
  • Risk: LOW
  • Depends on: none (but if plans 001/004 have landed, include their new env vars — see Step 1)
  • Category: docs
  • Planned at: commit 5b5c634, 2026-06-12

Why this matters

The README's feature list advertises "Gemini, OpenAI, Anthropic, OpenRouter"
cloud models, but the setup instructions only ever mention GEMINI_API_KEY,
and Anthropic support isn't even installed by default (uv sync skips the
anthropic extra — a user who sets an anthropic/... model gets an
ImportError at their first LLM call). There is no .env.example, so the full
set of recognized environment variables is discoverable only by reading
src/constants.py and src/utils/provider_routing.py. Fifteen minutes of
documentation removes the worst onboarding traps.

Current state

  • README.md setup section (~lines 97–135): documents uv sync,
    uv sync --extra local-embeddings, creating .env via echo commands
    with GEMINI_API_KEY and OLLAMA_API_URL, and overriding
    HINBOX_OLLAMA_MODEL / HINBOX_CLOUD_MODEL. No mention of OpenAI /
    Anthropic / OpenRouter setup despite the feature list at line ~15.
  • Environment variables actually read by the code (verified by grep at the
    planning commit):
    • src/utils/provider_routing.py: GEMINI_API_KEY (required for
      gemini/ models and gemini embeddings), OPENROUTER_API_KEY (for
      openrouter/ models), JINA_API_KEY (for the default cloud embedding
      model jina_ai/jina-embeddings-v3 — see src/constants.py:11).
      OPENAI_API_KEY and ANTHROPIC_API_KEY are read implicitly by the
      OpenAI/Anthropic SDKs (comments at provider_routing.py:111 and :119).
    • src/constants.py: HINBOX_CLOUD_MODEL (default
      gemini/gemini-2.0-flash), HINBOX_OLLAMA_MODEL (default
      ollama/qwen2.5:32b-instruct-q5_K_M), OLLAMA_API_URL (default
      http://localhost:11434/v1), ENABLE_PROFILE_VERSIONING (default true).
    • src/utils/embeddings/manager.py: EMBEDDING_MODE (cloud | local | hybrid).
  • The anthropic extra: pyproject.toml [project.optional-dependencies]
    has anthropic = ["anthropic>=0.40"]; src/utils/llm.py raises a helpful
    ImportError if an anthropic/ model is used without it.
  • A real .env file exists in the working directory (gitignored). Never
    open, read, or copy it.
    The example file is written from the code-derived
    list above, with placeholder values only.
  • justfile has set dotenv-load, so .env is auto-loaded by all recipes —
    worth stating in the docs.

Commands you will need

Purpose Command Expected on success
Env-var census `grep -rhoE 'os.(getenv environ.get)("[A-Z_]+' src | grep -oE '[A-Z_]{3,}' | sort -u`
Lint/CI just ci exit 0 (docs don't affect it; run anyway)

Scope

In scope:

  • .env.example (create, repo root)
  • README.md (setup section + a new "Supported model providers" subsection)

Out of scope (do NOT touch):

  • Any src/ code — documentation only. (The "warn early when an
    anthropic/ model is configured but the extra is missing" idea is noted
    in Maintenance notes as deferred.)
  • The local .env file — do not read it, do not modify it, do not quote it.

Git workflow

  • Branch: advisor/008-onboarding-docs
  • Commit style: imperative subject, backticks around code identifiers.
  • Do NOT push or open a PR unless the operator instructed it.

Steps

Step 1: Create .env.example

Repo root, placeholder values only. Before writing, check whether plans 001
and 004 have landed (grep -n "HINBOX_CHECKPOINT_INTERVAL\|HINBOX_FRONTEND_HOST" src/constants.py)
and include those vars only if present. Content shape:

# hinbox environment configuration — copy to .env (auto-loaded by `just`).
# Only GEMINI_API_KEY is required for the default cloud setup.

# --- Cloud LLM providers ---
GEMINI_API_KEY=your-gemini-api-key          # required for default gemini/ models
# OPENAI_API_KEY=...                        # for openai/ models (read by OpenAI SDK)
# ANTHROPIC_API_KEY=...                     # for anthropic/ models (needs: uv sync --extra anthropic)
# OPENROUTER_API_KEY=...                    # for openrouter/ models

# --- Embeddings ---
# JINA_API_KEY=...                          # required for default cloud embeddings (jina_ai/jina-embeddings-v3)
# EMBEDDING_MODE=cloud                      # cloud | local | hybrid

# --- Local models (Ollama) ---
# OLLAMA_API_URL=http://localhost:11434/v1

# --- Model overrides ---
# HINBOX_CLOUD_MODEL=gemini/gemini-2.0-flash
# HINBOX_OLLAMA_MODEL=ollama/qwen2.5:32b-instruct-q5_K_M

# --- Behavior toggles ---
# ENABLE_PROFILE_VERSIONING=true

Verify: test -f .env.example && grep -c "=" .env.example → ≥10; and
grep -E "=(sk-|AIza|key-[A-Za-z0-9])" .env.example → no matches (no real-looking keys)

Step 2: README — point at the example file

In the "Set up environment variables" step (~line 107), replace the echo
instructions' lead-in with: copy .env.example to .env and fill in keys
(cp .env.example .env); keep one echo example for the minimal
Gemini-only path. Mention that just auto-loads .env (set dotenv-load).

Verify: grep -n ".env.example" README.md → ≥1 match

Step 3: README — "Supported model providers" subsection

Add a short subsection (near the model-override docs, ~line 125) with a
table:

Provider Model string format Required setup
Gemini (default) gemini/gemini-2.0-flash GEMINI_API_KEY
OpenAI openai/<model> OPENAI_API_KEY
Anthropic anthropic/<model> uv sync --extra anthropic + ANTHROPIC_API_KEY
OpenRouter openrouter/<vendor>/<model> OPENROUTER_API_KEY
Ollama (local) ollama/<model> Ollama running at OLLAMA_API_URL

Cross-check each row against src/utils/provider_routing.py:95-185 before
writing — the prefix-to-provider mapping there is the source of truth (e.g.
confirm the exact openrouter/ model-string shape it parses). Add one
sentence: cloud embeddings default to Jina (JINA_API_KEY); pass --local
or install --extra local-embeddings for fully local operation.

Verify: each table row's prefix appears in
grep -n "startswith\|prefix" src/utils/provider_routing.py output or the
routing match statements — confirm manually, then just ci → exit 0

Test plan

No code changes; no new tests. Verification = the grep gates above plus a
human read-through of the rendered README section.

Done criteria

  • .env.example exists, ≥10 documented variables, zero real secret values
  • README references .env.example and contains the provider table
  • Every env var named in the README/example is actually read somewhere in src/ (census command matches)
  • just ci exits 0
  • No files outside the in-scope list modified (git status)
  • plans/README.md status row updated

STOP conditions

Stop and report back (do not improvise) if:

  • The env-var census returns names not covered in "Current state" — list
    them and extend the example only after confirming what they do from code.
  • provider_routing.py has gained/lost providers since planning (drift) —
    re-derive the table, and flag the change.
  • You find yourself about to open the local .env for "reference" — don't;
    that file may contain real credentials.

Maintenance notes

  • When a new env var is added to constants.py or provider_routing.py,
    .env.example must gain a line in the same PR — reviewers should check.
  • Deferred (code change, separate decision): an early startup warning when
    the configured cloud model needs a missing optional extra or env var, so
    failures happen at launch rather than at the first LLM call.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions