diff --git a/AGENTS.md b/AGENTS.md index 71e5eb2..73020bf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,29 +1,96 @@ -# Repository Guidelines +# AGENTS.md -## Project Structure & Module Organization +## Scope -`pythonlings/` contains the installable application package. Core exercise loading, workspace setup, state, reset, solutions, and runner logic live in `pythonlings/core/`; CLI entry points are in `pythonlings/cli.py` and `pythonlings/__main__.py`; Textual screens/widgets live in `pythonlings/screens/` and `pythonlings/widgets/`; `pythonlings/pythonlings.tcss` holds TUI styles. +This guide applies to the entire repository. It is the canonical operational +policy for contributors and coding agents. -Curriculum files are split between `exercises//.py` for learner code, `checks//.py` for hidden assertions, and `solutions/.py` for reference answers. Keep these trees aligned with `info.toml`, which defines order, hints, and docs URLs. Tests live in `tests/unit/`, `tests/integration/`, and `tests/tui/`, with fixtures in `tests/fixtures/`. +- Before editing `docs-site/**`, also read `docs-site/AGENTS.md`. +- Before editing `pythonlings/docs/**` or its generator, also read + `pythonlings/docs/AGENTS.md`. +- Nested guides add local requirements; this root guide still applies. +- Treat `.pythonlings/` as ignored learner runtime state, not repository source. -## Build, Test, and Development Commands +## Supported Commands -- `pip install -e ".[dev]"`: install pythonlings locally with pytest dependencies. -- `pythonlings init --path ./learn-python`: create a self-contained learner workspace. -- `pythonlings`, `pythonlings topics`, `pythonlings list`: launch the TUI or inspect progress. -- `pythonlings run variables1`, `pythonlings dry-run variables1`, `pythonlings solution variables1`: test exercise and solution flows. -- `pythonlings --root tests/fixtures/passing_curriculum verify`: smoke-test a known passing fixture. -- `python -m pytest -q`: run the full suite configured in `pyproject.toml`. -- `python -m build`: build source and wheel distributions. +Run commands from the repository root. -## Coding Style & Naming Conventions +- Install development dependencies: `python -m pip install -e ".[dev]"` +- Run a targeted test: `python -m pytest tests/unit/test_runner.py -q` +- Run the full suite: `python -m pytest -q` +- Verify a passing curriculum: + `pythonlings --root tests/fixtures/passing_curriculum verify` +- Install the packaging frontend: `python -m pip install build` +- Build the source and wheel distributions: `python -m build` -Use Python 3.11+ idioms and 4-space indentation. Prefer small, typed functions where practical. Keep UI behavior in `screens` or `widgets`; keep filesystem, manifest, reset, and runner behavior in `core`. Name tests `test_.py` and test functions `test_`. Curriculum names use topic plus ordinal, such as `variables1.py` or `collections10.py`. +## Pull Request Validation -## Testing Guidelines +Every pull request must run: -Use pytest for all tests; async tests are supported by `pytest-asyncio` in auto mode. Add unit tests for core behavior, integration tests for CLI/workspace flows, and TUI tests for Textual interactions. When changing curriculum, update `exercises/`, `checks/`, `solutions/`, and `info.toml`, then run relevant pytest files plus `pythonlings --root tests/fixtures/passing_curriculum verify`. +- `python -m pytest -q` +- `pythonlings --root tests/fixtures/passing_curriculum verify` -## Commit & Pull Request Guidelines +Add the checks that match the change: -Recent history uses conventional prefixes such as `feat:`, `fix:`, `docs:`, `chore:`, and merge commits between `feature/*`, `dev`, and `main`. Keep commits focused and imperative, for example `fix: reset exercise originals`. Pull requests should explain the user-facing change, list tests run, link issues when applicable, and include screenshots or terminal output for TUI/CLI changes. +- Packaging, curriculum, or workspace changes: install `build`, run + `python -m build`, run + `python -m pip install --force-reinstall dist/pythonlings-*.whl`, and exercise + the relevant installed flow. +- CLI changes: run the relevant tests under `tests/integration/` and include + representative command output. +- TUI changes: run the relevant tests under `tests/tui/` and include current + screenshots or GIFs of the affected flow. +- Documentation changes: follow the applicable nested `AGENTS.md`. + +Record the exact commands and their results in the pull request description. + +## Branch and Merge Policy + +- Branch from the current `main` and target pull requests to `main`. +- Use `dev` only when an explicitly approved release plan reactivates it. +- Keep pull requests in draft until local validation is complete and recorded. +- Merge with a merge commit only after CI passes and review feedback is resolved. +- Never merge or enable auto-merge without explicit maintainer approval. + +## Compatibility and Architecture + +- Maintain Python 3.9 compatibility. Guard standard-library APIs introduced in + newer Python versions and preserve required fallbacks. +- Keep Textual imports out of `pythonlings/core/` and one-shot CLI command import + paths. Core behavior must remain usable without loading the TUI. +- Preserve the runner's isolated subprocess, five-second default timeout, + shared exercise/check namespace, and `# I AM NOT DONE` completion marker. +- Preserve atomic state writes and corrupt-state backup. Do not discard learner + progress when changing state handling. +- Preserve learner-edited exercises during workspace updates. Reset snapshots + and bundled curriculum updates must not overwrite learner work implicitly. + +## Learner and Curriculum Contract + +Exercise names and their order in `info.toml` are learner-facing compatibility. +Avoid renaming, reordering, or removing them without an explicit migration. + +For each curriculum change, keep all of these synchronized: + +- `exercises//.py` +- the mirrored `checks//.py` +- `solutions/.py`, which is a reference-solution loader +- the corresponding answer in `solutions/_answers.py` +- the hint, documentation URL, and ordered manifest entry in `info.toml` + +Keep learner exercise files intentionally incomplete with `# I AM NOT DONE`. +Checks must use bare assertions with actionable, beginner-facing messages. Keep +curriculum code self-contained because it is copied into learner workspaces. + +For changed learner exercises, confirm the marker remains present and run +`python -m pytest tests/integration/test_solution_verify.py -q` to prove their +reference solutions pass. + +## Security and Releases + +- Report vulnerabilities privately. Never disclose them through public issues + or pull requests; follow `SECURITY.md`. +- Use only `pythonlings` as the distribution name. Do not publish or document + this repository under a different package name. +- Read `RELEASE.md` before changing versions, tags, release workflows, or + publishing behavior. diff --git a/CLAUDE.md b/CLAUDE.md index e881eeb..cdeffb8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,61 +1,7 @@ # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +Read and follow the repository policy in `AGENTS.md`. -Pythonlings is "Rustlings for Python": a terminal TUI (Textual) where learners fix small broken exercises and checks rerun on save. Published on PyPI as `pythonlings` (formerly `python-learnings`; the unrelated `pylings` PyPI name belongs to a different project). - -## Commands - -```bash -pip install -e ".[dev]" # local install with pytest deps - -python -m pytest -q # full suite -python -m pytest tests/unit/test_runner.py -q # one file -python -m pytest tests/unit/test_state.py::test_name -q # one test - -pythonlings --root tests/fixtures/passing_curriculum verify # smoke-test: all solutions pass their checks - -python -m build # sdist + wheel -``` - -Manual testing of flows: `pythonlings init --path ./learn-python` (create a learner workspace), `pythonlings` (TUI), `pythonlings run variables1`, `pythonlings dry-run variables1`, `pythonlings solution variables1`, `pythonlings hint`, `pythonlings list`, `pythonlings topics`, `pythonlings reset`. `--root` points any command at an arbitrary workspace (used heavily by tests against `tests/fixtures/`). - -## Architecture - -Two distinct trees in this repo: - -1. **The application** — `pythonlings/` (installable package) -2. **The curriculum** — repo-root `exercises/`, `checks/`, `solutions/`, and `info.toml` - -At build time, hatch `force-include` maps the curriculum into the wheel as `pythonlings/curriculum/` (see `pyproject.toml`). `pythonlings init` copies that bundled curriculum into a self-contained learner workspace; progress lives in `/.pythonlings/state.json` (written atomically, with `.bak` recovery on corruption). - -### Curriculum model - -Each exercise is a triple that must stay in sync, plus a manifest entry: - -- `exercises//.py` — the broken code the learner edits, containing the `# I AM NOT DONE` marker (defined in `core/exercise.py`) -- `checks//.py` — hidden bare `assert` statements (not pytest) -- `solutions/.py` — reference answer -- `info.toml` — ordered `[[exercises]]` entries with `name`, `path`, `hint`, `docs` URL; this file is the source of truth for exercise order and topics - -When changing curriculum, update all four, then run the relevant tests plus `pythonlings --root tests/fixtures/passing_curriculum verify`. Exercise names are topic + ordinal (`variables1`, `collections10`). - -### How checks run (`core/runner.py`) - -An exercise passes when a generated runner script `exec()`s the exercise source and then the check source in a shared namespace, in a fresh subprocess with a 5s timeout. The check sees the exercise's variables directly — that's why checks are bare asserts. Passing checks alone aren't enough: the learner must also remove `# I AM NOT DONE` to advance. - -### Layering - -- `pythonlings/core/` — all filesystem, manifest, state, reset, solutions, and runner logic. No UI imports. (Checks rerun on a debounce in the TUI editor, not a filesystem watcher.) -- `pythonlings/screens/` and `pythonlings/widgets/` — Textual UI only; `pythonlings/app.py` wires them up; `pythonlings.tcss` holds styles. -- `pythonlings/cli.py` — argparse subcommands; entry point `pythonlings = "pythonlings.cli:main"`. - -Keep UI behavior in screens/widgets and behavior logic in core — tests depend on this split (`tests/unit/` for core, `tests/integration/` for CLI/workspace flows, `tests/tui/` for Textual pilot tests, fixtures in `tests/fixtures/`). - -## Conventions - -- `requires-python = ">=3.9"`: guard newer-stdlib usage (e.g. `tomllib` falls back to `tomli` in `core/manifest.py`); `from __future__ import annotations` at the top of modules. -- Async tests run under `pytest-asyncio` in auto mode (configured in `pyproject.toml`). -- Tests are named `test_.py` / `test_`. -- Commits use conventional prefixes (`feat:`, `fix:`, `docs:`, `chore:`); work flows through `feature/*` → `dev` → `main`. -- `AGENTS.md` holds the same contributor guidelines in long form. +Before editing `docs-site/**` or `pythonlings/docs/**`, read the corresponding +nested `AGENTS.md` in that directory. Operational rules belong in the canonical +`AGENTS.md` hierarchy and must not be duplicated here. diff --git a/docs-site/AGENTS.md b/docs-site/AGENTS.md new file mode 100644 index 0000000..ee4b923 --- /dev/null +++ b/docs-site/AGENTS.md @@ -0,0 +1,21 @@ +# docs-site/AGENTS.md + +## Scope + +This guide applies to `docs-site/**`. The root `AGENTS.md` also applies. +`mkdocs.yml` defines the documentation navigation and theme configuration. + +## Documentation Site Workflow + +Run documentation commands from the repository root: + +```bash +python -m pip install -r requirements-docs.txt +mkdocs build --strict +``` + +Update the `nav` section in `mkdocs.yml` whenever a page is added, removed, or +renamed. Keep documented commands, keyboard bindings, package versions, and +screenshots synchronized with current product behavior. + +Run `mkdocs build --strict` before completing any documentation-site change. diff --git a/pythonlings/docs/AGENTS.md b/pythonlings/docs/AGENTS.md new file mode 100644 index 0000000..0a4b0aa --- /dev/null +++ b/pythonlings/docs/AGENTS.md @@ -0,0 +1,25 @@ +# pythonlings/docs/AGENTS.md + +## Scope + +This guide applies to generated local documentation under `pythonlings/docs/**`. +The root `AGENTS.md` also applies. + +## Generated Content + +Do not edit `index.json`, `topics/*.md`, or `NOTICE.md` directly. They are +generated by `scripts/fetch_python_docs.py`. The generator's `SOURCES` table +defines the bundled topics, while `info.toml` holds exercise-facing +documentation URLs. + +Regenerate from the repository root: + +```bash +python scripts/fetch_python_docs.py +``` + +Commit generator or source changes with their regenerated outputs. Review broad +generated diffs because upstream Python documentation can change unrelated +topics. Preserve the Python documentation licensing notice in `NOTICE.md`. + +After regeneration, run `python -m pytest tests/unit/test_docs.py -q`.