| # Rules |
|
|
| Contract for every contributor β human or AI β working in this repo. |
|
|
| ## Project Overview |
|
|
| `automAIta` is a deployment-ready boilerplate for HuggingFace Spaces. |
|
|
| - **Backend:** FastAPI (MVC) managed by `uv`, defined in `backend/pyproject.toml`. |
| - **Frontend:** Vite + React + TypeScript + Tailwind + PWA. No app frameworks. |
| - **Container:** one Docker image, single port `7860`. FastAPI serves the built React bundle as static files at `/` and the API under `/api/*`. |
| - **Deploy:** GitHub `main` β `.github/workflows/sync-to-hf.yml` mirrors the repo to a HuggingFace Space, which rebuilds automatically. |
|
|
| ## Scope & Goals |
|
|
| - Stay a **boilerplate**. The only "feature" is `App.tsx` proving the `/api/status` round-trip works. |
| - New projects fork this repo and fill it in β they should not have to rewire Docker, ports, the workflow, or the layout. |
|
|
| ## Coding Rules |
|
|
| - **No hardcoded values.** Backend goes through `app/core/config.py` (env prefix `AUTOMAITA_`). Frontend uses Vite env vars (`import.meta.env.VITE_*`) when needed. |
| - **Backend MVC layering:** |
| - `controllers/` β `APIRouter`s only. Thin: parse, call a service, return. |
| - `services/` β business logic. No FastAPI imports. |
| - `schemas/` β pydantic request/response DTOs. |
| - `models/` β pydantic domain models. |
| - `core/` β config, lifespan, anything cross-cutting. |
| - **Frontend:** |
| - TypeScript `strict` is on. Don't downgrade it. |
| - Tailwind is the only styling system. **No** Material UI, Chakra, Mantine, shadcn, etc., without explicit approval. |
| - **No** state libraries (Redux/Zustand/Jotai) or routers (React Router/TanStack Router) until the project actually needs one. |
| - All API calls go through `src/api/client.ts`. |
| - **Single-port contract.** The container exposes only `7860`. Don't introduce nginx, supervisord, or a second process. FastAPI mounts the static SPA itself. |
| - **Same-origin in prod.** API client uses relative URLs (`/api/...`). Don't hardcode `http://localhost:8000` or any HF URL. |
|
|
| ## Agent Behavior Rules |
|
|
| - Never bypass the `frontend/` β `backend/` boundary β they communicate over HTTP, not shared imports. |
| - Never break the **single-port** contract or the **non-root UID 1000** Dockerfile. |
| - Never edit `.github/workflows/sync-to-hf.yml` to add deploy logic that belongs inside the container β the workflow's job is mirroring, nothing else. |
| - Preserve the Dockerfile's two-stage shape (`frontend-build` β `runtime`). New build steps go inside an existing stage; don't add stages without need. |
| - When adding a backend route, create a controller in `app/controllers/`, register it in `app/main.py`, and put the logic in `app/services/`. |
|
|
| ## Workflow Rules |
|
|
| - **Local dev (split):** |
| - Backend: `cd backend && uv sync && uv run uvicorn app.main:app --reload --port 8000` |
| - Frontend: `cd frontend && npm install && npm run dev` (proxy handles `/api`). |
| - **Container parity (run what HF runs):** `docker build -t automaita . && docker run --rm -p 7860:7860 automaita` β http://localhost:7860. |
| - **Deploy:** push to GitHub `main`. Required repo secrets: `HF_TOKEN`, `HF_USER`, `HF_SPACE_NAME`. |
| - Don't push directly to the HF Space repo β let the action do it, otherwise you fork history. |
|
|
| ## Conventions |
|
|
| - **Env var prefix:** `AUTOMAITA_` (backend), `VITE_` (frontend). |
| - **API prefix:** all backend routes live under `/api/*`. The PWA service worker explicitly excludes `/api/*` from navigation fallback. |
| - **Filenames:** |
| - Backend: snake_case modules, controllers suffixed `_controller.py`, services suffixed `_service.py`. |
| - Frontend: PascalCase for components (`App.tsx`), camelCase for utilities (`client.ts`). |
| - **Health:** `/api/health` is the simplest possible OK probe; `/api/status` is the rich one (used by the SPA on mount). |
| - **Python:** 3.12+, `ruff` for linting (config in `pyproject.toml`). |
| - **Node:** 20+ (matches the Dockerfile build stage). |
| |
| ## HuggingFace Space deployment |
| |
| - The HF Space's README is **generated at CI time** by `.github/workflows/sync-to-hf.yml` from the template at `.github/hf-space.README.tpl.md`. Don't hand-edit the repo's `README.md` expecting it to ship to HF β edit the template instead. The repo's `README.md` is purely for GitHub readers and is overwritten in the workflow's checkout (never pushed back to GitHub). |
| - **Required GitHub repo secrets** (Settings β Secrets and variables β Actions β Secrets): |
| - `HF_TOKEN` β HF user access token, **write** scope. |
| - `HF_USER` β HF username or org that owns the Space. |
| - `HF_SPACE_NAME` β the Space's repo name (no `user/` prefix). |
| - **Optional GitHub repo variables** (Settings β Secrets and variables β Actions β Variables) β each falls back to a default if unset: |
| - `HF_SPACE_TITLE`, `HF_SPACE_EMOJI`, `HF_COLOR_FROM`, `HF_COLOR_TO`, `HF_APP_PORT`, `HF_SHORT_DESCRIPTION`. |
| - **Persistent storage** lives at `/data`. It's mounted at runtime **only if** persistent storage is enabled in the Space's Settings UI. Without it, `/data` still exists and is writable, but writes are wiped on every restart. The boilerplate works in both modes. |
| - `/data` is **runtime-only** per HF docs β never write to `/data` from the Dockerfile (build step). Pre-create + chown is fine; writes are not. |
| - Do **not** use `VOLUME /data` in the Dockerfile β HF Spaces don't honor `VOLUME` declarations and it complicates layer permissions. |
| - Container must run as **UID 1000**. `$HOME` must be writable by that user (we set `HOME=/home/app` in the Dockerfile so libraries like `huggingface_hub` can cache to `~/.cache/huggingface`). |
| - **Build-time secrets** (private model downloads, etc.) use `--mount=type=secret,id=NAME` and are read from `/run/secrets/NAME` per HF docs. **Never** pass runtime secrets through `ARG` β they would bake into image layers. |
| - **Runtime secrets/variables** set in the HF Space Settings UI become regular env vars in the container β read them via `os.environ.get(...)` or via `pydantic-settings` (`AUTOMAITA_*` prefix for our config). |
| - The backend reports storage status under `storage` in `/api/status` (`exists`, `writable`, `persistent`). The `persistent` flag is a heuristic: it's `true` when a marker file from a previous startup survived to the current one. |
|
|
| ## Out of Scope |
|
|
| - Auth, database, persistence, queues, LLM integrations β add per project, don't bake into the boilerplate. |
| - Tests β the boilerplate has nothing meaningful to test. Add tests when you add logic. |
| - Analytics, telemetry, error tracking β opt in per project. |
| - HF Hub Storage Buckets (`hf://buckets/...`) β that's a separate object-storage product accessed via `huggingface_hub`, not a filesystem mount. Not wired in by default; add the lib + auth if you need it per project. |
|
|