Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# AGENTS.md

> Universal agent brief for **ForecastLabAI** — the shared, cross-tool source of truth read by any AI coding agent (Claude Code, Cursor, GitHub Copilot, Gemini CLI, Aider, Zed, …). Claude Code additionally reads `CLAUDE.md`, which imports this file; do not duplicate this content there.

## Project Overview

ForecastLabAI is a portfolio-grade, **single-host retail demand-forecasting** system that exercises the full lifecycle: data platform → ingest → time-safe feature engineering → forecasting → backtesting → model registry → RAG → agentic layer → React dashboard. It is pre-1.0, runs end-to-end on one machine via `docker compose up`, and ships working code in every vertical slice — not specs.

## Tech Stack

- **Backend** — Python 3.12: FastAPI + SQLAlchemy 2.0 async + Pydantic v2; structlog; Alembic migrations.
- **Frontend** — TypeScript 5.9 + React 19: Vite 7, Tailwind 4, shadcn/ui (New York), TanStack Query + Table, React Router 7, Recharts.
- **Database** — PostgreSQL 16 + pgvector (host `:5433` → container `:5432`).
- **ML** — pandas, numpy, scikit-learn, joblib, LightGBM (opt-in).
- **Agents / RAG** — PydanticAI, anthropic, openai, tiktoken; Ollama optional for local embeddings.
- **Package managers** — `uv` (Python), `pnpm` via corepack (JS).
- **CI/CD** — GitHub Actions + release-please (SemVer; pre-1.0 `feat:` → PATCH bumps).

## Setup

```bash
cp .env.example .env # set OPENAI_API_KEY / ANTHROPIC_API_KEY
docker compose up -d # Postgres+pgvector on :5433
uv sync --extra dev # backend deps (Python 3.12)
uv run alembic upgrade head # apply migrations
uv run uvicorn app.main:app --reload --port 8123
cd frontend && corepack enable pnpm && pnpm install && pnpm dev # UI on :5173
```

## Build & Test Commands

Use these exact strings.

```bash
# Backend tests
uv run pytest -v -m "not integration" # unit, no DB
uv run pytest -v -m integration # integration, requires docker compose up

# Frontend
cd frontend && pnpm tsc --noEmit && pnpm lint && pnpm test --run

# End-to-end demo (seed → features → train ×3 → backtest → register → alias → agent)
make demo
```

## Validation Gates

Run before every commit. All five gate merge in CI — never skip them.

```bash
uv run ruff check . && uv run ruff format --check .
uv run mypy app/ && uv run pyright app/ # both --strict
uv run pytest -v -m "not integration"
```

## Architecture & Conventions

- **Vertical slices** — every domain lives under `app/features/<slice>/{models,schemas,service,routes,tests}.py`. A slice may NOT import from another slice; cross-cutting code goes through `app/core/` or `app/shared/`. Routers are wired in `app/main.py`.
- **Errors** — RFC 7807 `application/problem+json` via `app/core/problem_details.py`. No bare `HTTPException` with raw strings; no ad-hoc error shapes.
- **Validation** — Pydantic v2 at every boundary (HTTP, agent tools, seeder config). ORM uses `Mapped[]` + `mapped_column()` + async sessions.
- **Config** — read settings via `app/core/config.get_settings()`; never touch `os.environ` in feature code. Use `pathlib.Path`, never `os.path`.
- **Time-safety** — feature engineering must prevent leakage (`shift(lag)`, `shift(1).rolling()`, entity-aware `groupby`). `app/features/featuresets/tests/test_leakage.py` is the spec.
- **Migrations** — every schema change ships an Alembic migration; migrations are forward-only once merged.
- **UI** — frontend work goes through the design skills referenced in `.claude/rules/ui-design.md`; never hand-roll UI when a skill applies.

## Testing Requirements

- Every new module, public function, API endpoint, SQLAlchemy model, and Alembic migration ships with a matching test; every bug fix ships a regression test that would have caught it.
- Unit tests mock external services (OpenAI / Anthropic / Ollama). Integration tests are marked `@pytest.mark.integration` and run against the real docker-compose Postgres.
- New endpoints need a route test covering the 2xx happy path plus at least one error path.

## Safety

**Hard rules — never violate:**

- Never commit `.env` or embed secrets in URLs, code, or logs — only `.env.example` is tracked; log key names, never values.
- Never build SQL with string concatenation — only SQLAlchemy 2.0 parameter binding.
- Never use `eval` / `exec` / `pickle.loads` on untrusted input, `subprocess(shell=True, …)` with user input, or `verify=False` on httpx / openai clients.
- Never skip `ruff`, `mypy --strict`, or `pyright --strict` — all gate merge.
- Never edit a merged Alembic migration — migrations are forward-only; add a new one.
- Never weaken `app/features/featuresets/tests/test_leakage.py` — it is the leakage spec.
- Never mock the database in integration tests — they must run against real docker-compose Postgres.
- Never `git push --force` on `dev` or `main`; never add an AI co-author or "Generated with" commit trailer.
- Never add a managed-cloud SDK (AWS/GCP/Azure) to the `app/` core path — it violates the single-host vision.

**Stop and ask before:**

- Cutting `dev` → `main`, or pushing any tag (release-please owns tagging).
- Bumping pydantic-ai / FastAPI / SQLAlchemy major versions.
- Widening an agent's mutation surface without adding the tool name to `agent_require_approval`.

Agent-tool and Pydantic strict-mode specifics: see `docs/_base/SECURITY.md`.

## Git & PR Conventions

- **Branches** — `<type>/<kebab-slug>` off `dev` (`hotfix/*` off `main`). One branch per issue. See `.claude/rules/branch-naming.md`.
- **Commits** — `type(scope): description (#issue)`. Type ∈ {feat, fix, docs, refactor, test, chore, release}; scope from the allow-list in `.claude/rules/commit-format.md`; lowercase description, no trailing period; every commit references an open GitHub issue. No AI co-author / "Generated with" trailer (a hook enforces this).
- **Flow** — branch off `dev` → implement → run the validation gates → PR into `dev` → CI green → merge. Release: PR `dev` → `main`; release-please opens a Release PR; merging it tags `vX.Y.Z`.

## Deep-Dive Docs

Load only what the current task touches.

- Developer guide & stack — `docs/_base/DEV_GUIDE.md`
- Architecture & boundaries — `docs/_base/ARCHITECTURE.md`
- API & WebSocket contracts — `docs/_base/API_CONTRACTS.md`
- Operational runbooks — `docs/_base/RUNBOOKS.md`
- Security & compliance — `docs/_base/SECURITY.md`
- Rules & constraints — `docs/_base/RULES.md`
- Domain model & glossary — `docs/_base/DOMAIN_MODEL.md`
- Service & dependency map — `docs/_base/REPO_MAP_INDEX.md`
- CI/CD pipeline contract — `docs/_base/PIPELINE_CONTRACT.md`
- Project rules — `.claude/rules/*.md`
115 changes: 27 additions & 88 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# ForecastLabAI
# ForecastLabAI — Claude Code Operating Index

> **Read `@AGENTS.md` first.** It is the shared cross-tool brief — stack, setup, build/test
> commands, validation gates, architecture, conventions, safety, and git flow. This file adds
> only Claude-specific operating context on top; it does not repeat AGENTS.md content.

@AGENTS.md

## Deep-Dive References

Claude pulls these in on demand — load only what the task touches.

Deep-dive references (Claude loads only when needed):
- Developer guide & tech stack: @docs/_base/DEV_GUIDE.md
- Architecture & boundaries: @docs/_base/ARCHITECTURE.md
- API contracts & interfaces: @docs/_base/API_CONTRACTS.md
Expand All @@ -11,106 +20,36 @@ Deep-dive references (Claude loads only when needed):
- Service & dependency map: @docs/_base/REPO_MAP_INDEX.md
- Pipeline contract (CI/CD): @docs/_base/PIPELINE_CONTRACT.md

> Project rules already enforced via `.claude/rules/` (commit-format, branch-naming, security-patterns, product-vision, test-requirements, ui-design, versioning, output-formatting). Read those first; this file is the operating index.

## Stack

- Language: Python 3.12 (backend), TypeScript 5.9 + React 19 (frontend)
- Framework: FastAPI + SQLAlchemy 2.0 async + Pydantic v2; Vite 7 + Tailwind 4 + shadcn/ui
- Infrastructure: Single-host `docker-compose` (no K8s, no cloud SDK in core path)
- Database: PostgreSQL 16 + pgvector (port `5433` host → `5432` container)
- CI/CD: GitHub Actions + release-please (SemVer, pre-1.0 patch bumps)

## Architecture

**Owns:** Full vertical-slice retail-demand-forecasting demo — data platform, ingest, feature engineering (time-safe), forecasting, backtesting, model registry, RAG (pgvector), agentic layer (PydanticAI), React dashboard.

**Depends on:** PostgreSQL+pgvector (required), OpenAI/Anthropic/Google API (agent + RAG embeddings), Ollama (optional local embeddings).

**Depended on by:** Nothing internal — single deployment, no consumers. Frontend ↔ backend over HTTP + WebSocket (`/agents/stream`).

**Vertical-slice layout:** Every domain lives under `app/features/<slice>/{models,schemas,service,routes,tests}.py`. Cross-slice code goes through `app/core/` or `app/shared/`. Wire-up in `app/main.py`.

**Core data flow:** Seeder/Ingest → `sales_daily` + dimensions → Featuresets (lag/rolling/calendar, leakage-safe) → Forecasting (naive/seasonal/MA/LightGBM) → Backtesting (rolling/expanding splits) → Registry (runs + aliases) → Serving via `/forecasting`, `/backtesting`, `/analytics`. RAG indexes docs → pgvector → Agents (experiment / rag_assistant) call tools with human-in-loop approval for mutating ops.

## Commands

### Local Development
```bash
docker-compose up -d # Postgres+pgvector on :5433
uv sync --extra dev # install backend deps (Python 3.12)
uv run alembic upgrade head # apply migrations
uv run uvicorn app.main:app --reload --port 8123
cd frontend && pnpm install && pnpm dev # UI on :5173
```

### Testing
```bash
uv run pytest -v -m "not integration" # unit, no DB
uv run pytest -v -m integration # integration, requires docker-compose up
cd frontend && pnpm tsc --noEmit && pnpm lint && pnpm test --run
```

### Validation gates (run before commit)
```bash
uv run ruff check . && uv run ruff format --check .
uv run mypy app/ && uv run pyright app/ # both --strict, both block merge
```

### Database & seeder
```bash
uv run alembic revision --autogenerate -m "<desc>"
uv run python scripts/seed_random.py --full-new --seed 42 --confirm
uv run python scripts/seed_random.py --status
```

## Conventions

- Branches: `<type>/<kebab-slug>` off `dev` (off `main` for hotfix). See `.claude/rules/branch-naming.md`.
- Commits: `type(scope): description (#issue)` — scope from allow-list, no AI co-author trailer, every commit references an open GitHub issue. Hook `.claude/hooks/check-commit-format.sh` enforces it.
- All errors via `app/core/problem_details.py` (RFC 7807 `application/problem+json`).
- Pydantic v2 at every boundary (HTTP, agent tools, seeder config). SQLAlchemy with `Mapped[]` + async sessions.
- Time-safe features only — `app/features/featuresets/tests/test_leakage.py` is the spec; never weaken to make a feature pass.
- UI work goes through the skills in `.claude/rules/ui-design.md` (stitch-design, frontend-design, webapp-testing) — never hand-roll.
> Project rules are enforced via `.claude/rules/` (commit-format, branch-naming,
> security-patterns, product-vision, test-requirements, ui-design, versioning,
> output-formatting). Read those first — they are authoritative on detail.

## Safety

> Load `docs/_base/RULES.md` for the full constraint matrix.

**STOP and ask before:**
- Cutting `dev` → `main` (release-please will tag) or any tag push
- Editing a merged Alembic migration (migrations are forward-only; create a new one)
- `git push --force` on `dev` or `main` (forbidden)
- Adding a managed-cloud SDK to `app/` core path (violates single-host vision)
- Bumping pydantic-ai / FastAPI / SQLAlchemy major versions

**NEVER:**
- Commit `.env` (only `.env.example` is tracked) or embed secrets in URLs/code/logs
- Use raw SQL string concat — always SQLAlchemy parameter binding
- Disable `verify=False` on httpx / openai clients
- Skip `mypy --strict` or `pyright --strict` — both gate merge
- Add AI co-author trailers to commits (`commit-format.md` forbids it)
- Mock external services in integration tests (use real Postgres via docker-compose)
Full constraint matrix: `docs/_base/RULES.md`. Hard rules and stop-and-ask gates: `@AGENTS.md`
§ Safety. When a change is ambiguous or hard to reverse, surface the concern before acting.

## Verification

```bash
uv run ruff check . && uv run mypy app/ && uv run pyright app/ && uv run pytest -v -m "not integration"
gh issue view <N> --json state # confirm referenced issue exists
gh issue view <N> --json state # confirm the referenced issue exists
wc -l CLAUDE.md # must stay ≤ 150
```

## Workflow

1. Open or pick a GitHub issue (`gh issue list`); branch off `dev` per `branch-naming.md`.
2. Implement inside the matching `app/features/<slice>/` (or new slice with PRP).
3. Run `ruff` → `mypy` → `pyright` → `pytest -m "not integration"` locally.
4. (DB/UI touched) Run integration tests + frontend type-check + dogfood via webapp-testing skill.
5. Commit with `type(scope): description (#issue)`; push.
6. Open PR into `dev`; CI must be green; merge.
7. When ready to release: PR `dev` → `main`. release-please opens a Release PR; merge to tag.
2. Implement inside the matching `app/features/<slice>/` (or a new slice with a PRP).
3. Run the validation gates (`@AGENTS.md` § Validation Gates) locally before pushing.
4. (DB/UI touched) Run integration tests + frontend type-check + dogfood via the webapp-testing skill.
5. Commit `type(scope): description (#issue)`; push; open a PR into `dev`; merge once CI is green.
6. Release: PR `dev` → `main`; merge the release-please Release PR to tag `vX.Y.Z`.

## Learnings

<!-- Session-specific discoveries Claude should remember. Update sparingly. -->
- HEURISTIC_MODE generated this doc (no `docs/_kB/repo-map/` KB). Run `mapping-repo-context` to upgrade fidelity; sections marked `[ASSUMPTION]` in `docs/_base/` need verification.
- HEURISTIC_MODE generated `docs/_base/` (no `docs/_kB/repo-map/` KB). Run `mapping-repo-context`
to upgrade fidelity; `[ASSUMPTION]`-marked sections in `docs/_base/` need verification.
- `.claude/` is gitignored — skills, rules, and hooks are local-only and never appear in commits or PRs.
- AGENTS.md is the universal agent brief; CLAUDE.md is the Claude-specific layer that imports it.
Keep shared content in AGENTS.md only — never duplicate it here.
Loading