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
103 changes: 85 additions & 18 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -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/<topic>/<exercise>.py` for learner code, `checks/<topic>/<exercise>.py` for hidden assertions, and `solutions/<exercise>.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_<behavior>.py` and test functions `test_<expected_behavior>`. 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/<topic>/<name>.py`
- the mirrored `checks/<topic>/<name>.py`
- `solutions/<name>.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.
62 changes: 4 additions & 58 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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 `<workspace>/.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/<topic>/<name>.py` — the broken code the learner edits, containing the `# I AM NOT DONE` marker (defined in `core/exercise.py`)
- `checks/<topic>/<name>.py` — hidden bare `assert` statements (not pytest)
- `solutions/<name>.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_<behavior>.py` / `test_<expected_behavior>`.
- 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.
21 changes: 21 additions & 0 deletions docs-site/AGENTS.md
Original file line number Diff line number Diff line change
@@ -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.
25 changes: 25 additions & 0 deletions pythonlings/docs/AGENTS.md
Original file line number Diff line number Diff line change
@@ -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`.
Loading