Skip to content

Commit 59aad3e

Browse files
committed
chore: make runs working
1 parent 74dfe49 commit 59aad3e

26 files changed

Lines changed: 2941 additions & 103 deletions

.claude/rules/backend-frontend.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
description: Backend (FastAPI) and Frontend (React) rules for app_starter
3+
globs: backend/**,frontend/**
4+
alwaysApply: false
5+
---
6+
7+
# Backend and Frontend Rules
8+
9+
## FastAPI App Structure
10+
11+
- The `backend/` package lives at the repo root (not under `src/`).
12+
- Always run the backend with `PYTHONPATH=.:src` so both `backend` and `app` are importable.
13+
- The FastAPI application object is `app` in `backend/main.py`.
14+
- The items router is mounted at prefix `/api`.
15+
- CORS is configured to allow `http://localhost:5173` (the Vite dev server). Do not add wildcard origins.
16+
- Use `make serve` to start the backend on port 8000 with hot-reload.
17+
18+
## API Endpoints
19+
20+
- `GET /health` returns `{"status": "ok"}` with status 200. No authentication required.
21+
- `GET /api/items` returns a list of `Item` objects.
22+
- `POST /api/items` accepts an `ItemCreate` JSON body and returns an `Item`.
23+
24+
## Schemas
25+
26+
- Defined in `backend/schemas.py` as Pydantic `BaseModel` subclasses.
27+
- `Item`: `id: int`, `name: str`
28+
- `ItemCreate`: `name: str`
29+
30+
## Testing
31+
32+
- Tests live in `backend/tests/test_api.py`.
33+
- Use `fastapi.testclient.TestClient` with the `app` from `backend.main`.
34+
- Three tests required:
35+
1. `test_health` -- GET `/health` returns 200 and `{"status": "ok"}`.
36+
2. `test_get_items` -- GET `/api/items` returns 200 and a list.
37+
3. `test_create_item` -- POST `/api/items` with `{"name": "Test Item"}` returns 200.
38+
39+
## Frontend
40+
41+
- The frontend is a Vite + React + TypeScript app in `frontend/`.
42+
- Use `make frontend` to start the dev server on port 5173.
43+
- `VITE_API_URL` env var controls the backend URL; defaults to `http://localhost:8000`. Set it in `frontend/.env` (copy from `.env.example`).
44+
- TypeScript interfaces in `App.tsx` must mirror the Pydantic schemas in `backend/schemas.py`. Keep them in sync when either side changes.
45+
46+
## Running the Full Stack
47+
48+
- Backend: `make serve` (port 8000, `PYTHONPATH=.:src`).
49+
- Frontend: `make frontend` (port 5173).
50+
- The frontend calls the backend directly via `VITE_API_URL`. CORS on the backend allows the frontend origin.
51+
- Run `make setup` once to install both Python and Node dependencies.

.claude/rules/infrastructure.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
---
2+
description: Infrastructure rules for Docker, CI, gitignore, pre-commit, and Claude hooks
3+
globs: docker/**,Dockerfile,.dockerignore,.github/workflows/**,.gitignore,.pre-commit-config.yaml,.claude/**
4+
alwaysApply: false
5+
---
6+
7+
# Infrastructure Rules
8+
9+
## Docker Build
10+
11+
- Always build from the repo root: `docker build -f docker/Dockerfile .`
12+
- The Dockerfile must install `git` via `apt-get install -y --no-install-recommends git` because `uv-dynamic-versioning` calls git to resolve the package version at install time.
13+
- Install production deps with `uv sync --no-dev --no-editable`. The `--no-editable` flag is required so the package is installed into `.venv` as a regular package, not a symlink.
14+
- The full repo context is copied into the image so git history is available for versioning.
15+
16+
## Docker Compose Services
17+
18+
Two services defined in `docker/docker-compose.yml`:
19+
20+
| Service | Image / Build | Port |
21+
|------------|-----------------------------------|-------|
22+
| `backend` | Built locally from `docker/Dockerfile` (context: `..`) | 8000 |
23+
| `frontend` | `node:22-alpine` | 5173 |
24+
25+
Startup order enforced via `depends_on` with `condition: service_healthy`:
26+
`backend` (healthy) -> `frontend`.
27+
28+
## Healthchecks
29+
30+
- **backend**: HTTP check on port 8000 (`/health`). Interval 10s, start period 15s.
31+
- **frontend**: `wget` check on port 5173. Interval 15s, start period 30s.
32+
33+
## Env Vars in Docker
34+
35+
- `PYTHONPATH=.:src` -- Set so both `backend` and `app` packages are importable.
36+
- `VITE_API_URL=http://localhost:8000` -- Frontend env var for the browser to reach the backend. Uses `localhost` because the browser runs on the host.
37+
38+
## Running Docker
39+
40+
```shell
41+
docker compose -f docker/docker-compose.yml up --build -d
42+
```
43+
44+
## CI Pipeline
45+
46+
Two parallel jobs in `.github/workflows/ci.yml`:
47+
48+
### `build` job
49+
- Matrix: Python 3.11, 3.12, 3.13 on `ubuntu-latest`.
50+
- Checks out with `fetch-depth: 0` (full history needed for version resolution).
51+
- Runs `uv run python devtools/lint.py` for linting.
52+
- Runs `uv run pytest` with `PYTHONPATH=.:src`.
53+
54+
### `docker-build` job
55+
- Runs in parallel with `build`.
56+
- Builds the backend image: `docker build -f docker/Dockerfile -t app-starter-backend:ci .`
57+
- Does not push; build-only verification.
58+
59+
## Gitignore
60+
61+
Key project-specific entries in `.gitignore`:
62+
- **Frontend build**: `frontend/node_modules/`, `frontend/dist/`, `frontend/.env`
63+
64+
## Pre-commit Hooks
65+
66+
Hooks defined in `.pre-commit-config.yaml`:
67+
68+
1. `trailing-whitespace`, `end-of-file-fixer`, `check-yaml`, `check-merge-conflict`
69+
2. `check-added-large-files` with 5 MB limit (`--maxkb=5000`)
70+
3. `ruff` (with `--fix`) and `ruff-format`
71+
72+
If `core.hooksPath` is set in global git config (e.g., by another tool), pre-commit
73+
hooks installed via `pre-commit install` may be silently ignored. To work around this,
74+
run hooks manually:
75+
```shell
76+
uv run pre-commit run --all-files
77+
```
78+
79+
## Post-edit Claude Hook
80+
81+
Configured in `.claude/settings.json` as a `PostToolUse` hook on `Edit|Write|NotebookEdit`.
82+
83+
- `asyncRewake: true` -- Runs in the background; exit code 2 wakes Claude on failure.
84+
- Timeout: 300 seconds.
85+
- Script: `.claude/validate.sh`.
86+
87+
Behavior of `validate.sh`:
88+
- Skips validation entirely for config/doc files (`.md`, `.json`, `.yaml`, `.yml`, `.toml`, `.txt`, `.sh`, `.env`, `.gitignore`, `.dockerignore`).
89+
- Always runs `make lint` and `make test`.
90+
- Exits 2 on any failure to trigger Claude rewake.
91+
92+
Do not modify `validate.sh` or `.claude/settings.json` without understanding the
93+
rewake behavior. A non-zero exit other than 2 will not wake the model.

.claude/rules/tooling.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
description: Tooling, build system, and CI rules for python_nbdev_starter
3+
globs: "*"
4+
alwaysApply: true
5+
---
6+
7+
# Tooling Rules
8+
9+
## Package Management
10+
11+
- Always use `uv` for all package and environment operations. Never use `pip`, `pip install`, or bare `python` directly.
12+
- Install dependencies: `uv sync --all-extras`
13+
- Add a new dependency: `uv add <package>`
14+
- Run any command in the project venv: `uv run <command>`
15+
- Upgrade all deps: `uv sync --upgrade --all-extras --dev`
16+
17+
## nbdev Commands
18+
19+
- Export notebooks to Python: `uv run nbdev_export`
20+
- Test notebooks: `uv run nbdev_test`
21+
- Build docs: `uv run nbdev_docs`
22+
- Clean notebook outputs: `uv run nbdev_clean`
23+
- Always run `nbdev_export` after editing notebooks before running lint or tests.
24+
25+
## Make Targets
26+
27+
| Target | What it does |
28+
|---|---|
29+
| `make` (default) | Runs `agent-rules`, `install`, `lint`, `test` in order |
30+
| `make install` | `uv sync --all-extras` |
31+
| `make lint` | `uv run python devtools/lint.py` (codespell, ruff check --fix, ruff format, basedpyright) |
32+
| `make test` | `uv run pytest` |
33+
| `make nbdev-export` | Export notebooks to `python_nbdev_starter/` |
34+
| `make nbdev-test` | Run tests inside notebooks |
35+
| `make nbdev-docs` | Build documentation |
36+
| `make nbdev-clean` | Strip notebook outputs |
37+
| `make upgrade` | `uv sync --upgrade --all-extras --dev` |
38+
| `make build` | `nbdev_export` + `uv build` |
39+
| `make clean` | Removes dist, caches, .venv |
40+
| `make agent-rules` | Regenerates `CLAUDE.md` and `AGENTS.md` from `.cursor/rules/*.mdc` |
41+
42+
## Testing
43+
44+
- Test paths: `python_nbdev_starter`. Configured via `testpaths` in `pyproject.toml`.
45+
- `pythonpath = ["."]` is set in pytest config so imports resolve.
46+
- `python_files = ["*.py"]` — pytest discovers tests in any `.py` file.
47+
- Run all tests: `make test`
48+
- Run notebook tests: `make nbdev-test`
49+
- Run a single test with output: `uv run pytest -s path/to/file.py`
50+
51+
## Linting
52+
53+
- `make lint` runs `devtools/lint.py`, which executes in order:
54+
1. `codespell --write-changes` on `python_nbdev_starter devtools README.md`
55+
2. `ruff check --fix` on `python_nbdev_starter devtools`
56+
3. `ruff format` on `python_nbdev_starter devtools`
57+
4. `basedpyright --stats` on `python_nbdev_starter devtools`
58+
- Always run `make lint` after changes and fix all errors before considering work complete.
59+
60+
## Versioning
61+
62+
- Uses `uv-dynamic-versioning` which reads version from git tags at build time.
63+
- The `git` binary must be available for versioning to work.
64+
- `fetch-depth: 0` is required in CI checkout for full tag history.
65+
- Do not hardcode version strings; the version is always derived from git.
66+
67+
## CI Pipeline
68+
69+
- `test.yaml` uses `fastai/workflows/nbdev-ci@master` — the standard nbdev CI workflow.
70+
- Runs on push/PR/workflow_dispatch.
71+
72+
## Post-Edit Validation Hook
73+
74+
- `.claude/settings.json` registers a `PostToolUse` hook on `Edit|Write|NotebookEdit`.
75+
- The hook runs `.claude/validate.sh` with a 300-second timeout and `asyncRewake: true`.
76+
- Conditional logic in `validate.sh`:
77+
- **Skips entirely** for non-source files (`.md`, `.json`, `.yaml`, `.yml`, `.toml`, `.txt`, `.sh`, `.env`, `.gitignore`, `.dockerignore`).
78+
- **For `.ipynb` files**: runs `nbdev_export` first, then `make lint` and `make test`.
79+
- **For `.py` files**: always runs `make lint` and `make test`.
80+
- Exit code 2 on failure wakes the model to address the issue.
81+
82+
## Pre-commit Hooks
83+
84+
- To run hooks manually: `uv run pre-commit run --all-files`
85+
- Never skip pre-commit checks. If a hook fails, fix the underlying issue.

.claude/settings.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(uv sync:*)",
5+
"Bash(uv run:*)",
6+
"Bash(make:*)",
7+
"Bash(nbdev_export:*)",
8+
"Bash(nbdev_test:*)",
9+
"Bash(nbdev_clean:*)",
10+
"Bash(nbdev_docs:*)"
11+
]
12+
},
13+
"hooks": {
14+
"PostToolUse": [
15+
{
16+
"matcher": "Edit|Write|NotebookEdit",
17+
"hooks": [
18+
{
19+
"type": "command",
20+
"command": "bash /Users/mrmacbook/Desktop/muneeb/python_nbdev_starter/.claude/validate.sh",
21+
"timeout": 300,
22+
"statusMessage": "Validating (lint + test)...",
23+
"asyncRewake": true
24+
}
25+
]
26+
}
27+
]
28+
}
29+
}

.claude/validate.sh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env bash
2+
# Post-edit validation hook. Reads the changed file path from stdin JSON,
3+
# then runs make targets appropriate for what changed.
4+
# Exit 2 on failure so asyncRewake wakes the model.
5+
6+
set -uo pipefail
7+
8+
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
9+
cd "$PROJECT_DIR"
10+
11+
# Extract changed file path from hook JSON payload
12+
CHANGED_FILE=$(python3 -c "
13+
import sys, json
14+
data = json.load(sys.stdin)
15+
inp = data.get('tool_input', {})
16+
print(inp.get('file_path', '') or inp.get('notebook_path', ''))
17+
" 2>/dev/null || echo "")
18+
19+
# Regenerate CLAUDE.md when rule files change
20+
if echo "$CHANGED_FILE" | grep -qE "(\.cursor/rules/.*\.mdc$|\.claude/rules/.*\.md$)"; then
21+
echo "--- make agent-rules ---"
22+
if ! make agent-rules; then
23+
echo "FAILED: make agent-rules"
24+
exit 2
25+
fi
26+
exit 0
27+
fi
28+
29+
# Skip validation for non-source files
30+
if echo "$CHANGED_FILE" | grep -qE "\.(mdc|md|json|yaml|yml|toml|txt|sh|env|gitignore|dockerignore)$"; then
31+
exit 0
32+
fi
33+
34+
FAILED=0
35+
36+
run() {
37+
echo "--- $* ---"
38+
if ! "$@"; then
39+
echo "FAILED: $*"
40+
FAILED=1
41+
fi
42+
}
43+
44+
# For notebook changes, export first
45+
if echo "$CHANGED_FILE" | grep -qE "\.ipynb$"; then
46+
echo "--- nbdev_export ---"
47+
if ! uv run nbdev-export; then
48+
echo "FAILED: nbdev_export"
49+
FAILED=1
50+
fi
51+
fi
52+
53+
# Always run lint and notebook tests
54+
run make lint
55+
run make nbdev-test
56+
57+
if [ "$FAILED" -ne 0 ]; then
58+
exit 2
59+
fi

.cursor/rules/general.mdc

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
description: General Guidelines
3+
globs:
4+
alwaysApply: true
5+
---
6+
# Assistant Rules
7+
8+
**Your fundamental responsibility:** Remember you are a senior engineer and have a
9+
serious responsibility to be clear, factual, think step by step and be systematic,
10+
express expert opinion, and make use of the user’s attention wisely.
11+
12+
**Rules must be followed:** It is your responsibility to carefully read these rules as
13+
well as Python or other language-specific rules included here.
14+
15+
Therefore:
16+
17+
- Be concise. State answers or responses directly, without extra commentary.
18+
Or (if it is clear) directly do what is asked.
19+
20+
- If instructions are unclear or there are two or more ways to fulfill the request that
21+
are substantially different, make a tentative plan (or offer options) and ask for
22+
confirmation.
23+
24+
- If you can think of a much better approach that the user requests, be sure to mention
25+
it. It’s your responsibility to suggest approaches that lead to better, simpler
26+
solutions.
27+
28+
- Give thoughtful opinions on better/worse approaches, but NEVER say “great idea!”
29+
or “good job” or other compliments, encouragement, or non-essential banter.
30+
Your job is to give expert opinions and to solve problems, not to motivate the user.
31+
32+
- Avoid gratuitous enthusiasm or generalizations.
33+
Use thoughtful comparisons like saying which code is “cleaner” but don’t congratulate
34+
yourself. Avoid subjective descriptions.
35+
For example, don’t say “I’ve meticulously improved the code and it is in great shape!”
36+
That is useless generalization.
37+
Instead, specifically say what you’ve done, e.g., "I’ve added types, including
38+
generics, to all the methods in `Foo` and fixed all linter errors."
39+
40+
# General Coding Guidelines
41+
42+
## Using Comments
43+
44+
- Keep all comments concise and clear and suitable for inclusion in final production.
45+
46+
- DO use comments whenever the intent of a given piece of code is subtle or confusing or
47+
avoids a bug or is not obvious from the code itself.
48+
49+
- DO NOT repeat in comments what is obvious from the names of functions or variables or
50+
types.
51+
52+
- DO NOT include comments that reflect what you did, such as “Added this function” as
53+
this is meaningless to anyone reading the code later.
54+
(Instead, describe in your message to the user any other contextual information.)
55+
56+
- DO NOT use fancy or needlessly decorated headings like “===== MIGRATION TOOLS =====”
57+
in comments
58+
59+
- DO NOT number steps in comments.
60+
These are hard to maintain if the code changes.
61+
NEVER DO THIS: “// Step 3: Fetch the data from the cache”\
62+
This is fine: “// Now fetch the data from the cache”
63+
64+
- DO NOT use emojis or special unicode characters like ① or • or – or — in comments.
65+
66+
- Use emojis in output if it enhances the clarity and can be done consistently.
67+
You may use ✔︎ and ✘ to indicate success and failure, and ∆ and ‼︎ for user-facing
68+
warnings and errors, for example, but be sure to do it consistently.
69+
DO NOT use emojis gratuitously in comments or output.
70+
You may use then ONLY when they have clear meanings (like success or failure).
71+
Unless the user says otherwise, avoid emojis and Unicode in comments as clutters the
72+
output with little benefit.

0 commit comments

Comments
 (0)