diff --git a/.gitignore b/.gitignore index 5fbd3f3..f327483 100644 --- a/.gitignore +++ b/.gitignore @@ -40,9 +40,6 @@ Thumbs.db # sqlmem cache (incl. WAL sidecars from disk-backed mode) cache.db* -# Agents -AGENTS.md -CLAUDE.md -DESIGN_DOCUMENT_MODULE.md +# Claude Code .claude/ handover.md \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..053c8a8 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,101 @@ +# AI Agents - Project Rules + +**Document Version:** v6 (independent, incremented on structural changes) + +Language-agnostic rules for AI assistants (Claude Code, Cursor, Copilot, etc.). + +Everything language-specific — package manager, formatter, linter, test framework, +logging library, line length, project layout — lives in the matching design document: + +| Project type | Design document | +|--------------------|------------------------------| +| Python application | `DESIGN_DOCUMENT.md` | +| Python library | `DESIGN_DOCUMENT_MODULE.md` | +| Rust application | `DESIGN_DOCUMENT.md` | +| Rust library | `DESIGN_DOCUMENT_LIB.md` | +| Godot | `DESIGN_DOCUMENT_GODOT.md` | + +Where this file and a design document disagree, **the design document wins**. + +## First-time setup + +- **On first read of this file, immediately read all other `.md` files in the project root** (e.g. `PROJECT.md`, `CHANGELOG.md`, `DESIGN_DOCUMENT*.md`) to get full project context before starting any task. + +## Language + +- **Always write all documentation in English** + +## Dependency Management + +- **Always add and remove dependencies through the package manager CLI** — **never edit the manifest** (`pyproject.toml`, `Cargo.toml`, …) by hand +- The exact commands are in the design document for the given language + +## Project Structure + +- Source code, tests and detailed documentation each have their own directory — the concrete layout is in the design document +- Detailed documentation belongs in `docs/`, never in the project root +- The project root holds only the core documents: `README.md`, `AGENTS.md`, `DESIGN_DOCUMENT*.md`, `PROJECT.md`, `CHANGELOG.md` +- Entry points follow the language convention; a project may have several +- The dependency/build directory (`.venv/`, `target/`, …) is tool-managed — do not copy it, do not generate it by hand + +## Code + +- **Always use static typing** — annotate every parameter and return value +- Format and lint with the tools named in the design document +- **Nothing is committed without a clean formatter, linter and test run** + +## Testing + +- Use the test framework named in the design document — never a second framework alongside it +- Arrange-Act-Assert pattern +- Test naming: `test__` + +## Logging + +- Use the logging library named in the design document — **never `print()` (or its language equivalent) for debugging** +- Never log secrets, passwords, tokens, or API keys + +## Environment and Secrets + +- Applications store secrets in `.env` and load them at runtime — **never commit `.env`** +- Debug mode is driven by an `ENV_DEBUG=true/false` flag +- Libraries do not read `.env` — configuration is passed in by the caller + +## Git + +- `.gitignore` must cover at least: the dependency/build directory, tool caches, and `.env` +- **Commit the lock file for applications, do not commit it for libraries** +- **Never commit shared documentation** (`AGENTS.md`, `DESIGN_DOCUMENT*.md`) — it comes from the documentation repository, not from the project +- `README.md`, `PROJECT.md` and `CHANGELOG.md` **are committed** — they are project-specific + +### Commit messages + +- **Never sign commits with AI authorship** — no `Co-Authored-By: Claude` (or any other assistant), no "Generated with …" line, no tool name or emoji footer. The same applies to pull request descriptions and issue comments. +- The commit author is the human running the tool; the message describes the change, nothing else +- Single-line verbal style — "Add X", "Fix Y", "Refactor Z" — never a filename-style message +- Written in English + +## Versioning + +- Follow semantic versioning (MAJOR.MINOR.PATCH) +- **Always ask user before bumping version** — never increase version automatically +- **Keep `CHANGELOG.md` updated** — document all significant changes as they are made +- Update `CHANGELOG.md` **before** the version bump +- The version source of truth is the project manifest (`pyproject.toml`, `Cargo.toml`, `project.godot`) + +## Task Management + +Tasks are **single-line comments in the code**, written with Todo Tree tags: + +| Tag | Meaning | +|----------|--------------------------------------------------| +| `TODO:` | work still to be done | +| `FIXME:` | something broken that must be repaired | +| `BUG:` | a known defect, not fixed yet | +| `HACK:` | temporary workaround, needs rewriting | +| `NOTE:` | important context for whoever reads this next | + +- **No checkboxes and no numbered task lists in documentation** — the code is the task list +- `PROJECT.md` carries only cross-cutting tasks that have no single place in the code +- If a tag already exists at a location in code, do not repeat it in `PROJECT.md` +- **Update documentation** — when completing changes, update the relevant sections of `PROJECT.md` and `CHANGELOG.md` diff --git a/CHANGELOG.md b/CHANGELOG.md index 84c83d6..57355a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Changed +- `.gitignore` — stopped ignoring the shared agent documents (`AGENTS.md`, `CLAUDE.md`, `DESIGN_DOCUMENT_MODULE.md`); the section now covers only the Claude Code working files (`.claude/`, `handover.md`). + --- ## [1.17.0] - 2026-07-30 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c4aa103 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,14 @@ +# CLAUDE.md + +**Document Version:** v2 (independent, incremented on structural changes) + +## First-time setup + +**At the start of every new session, read all of the following files before doing anything else:** + +- `CLAUDE.md` (this file) +- `README.md` +- `AGENTS.md` +- `PROJECT.md` +- `CHANGELOG.md` +- `DESIGN_DOCUMENT*.md` (`DESIGN_DOCUMENT.md`, `DESIGN_DOCUMENT_MODULE.md`, `DESIGN_DOCUMENT_LIB.md` or `DESIGN_DOCUMENT_GODOT.md`) diff --git a/DESIGN_DOCUMENT_MODULE.md b/DESIGN_DOCUMENT_MODULE.md new file mode 100644 index 0000000..4fcfa84 --- /dev/null +++ b/DESIGN_DOCUMENT_MODULE.md @@ -0,0 +1,262 @@ +# Python Library Development Guidelines + +**Document Version:** v2 + +> **Note on Versioning:** +> - This document version is independent — reused across projects +> - **Project version** source of truth: `pyproject.toml` under `[project]` +> - `CHANGELOG.md` uses project version from `pyproject.toml` + +## Related Documents + +- **README.md** — Project overview, public API description, installation and usage examples +- **AGENTS.md** — Rules for AI assistants +- **PROJECT.md** — Project goals and current state +- **CHANGELOG.md** — Version history + +### Documentation Organization + +All detailed documentation of features and systems belongs in the `docs/` folder, not in the project root. + +The root directory contains only the core documents: `README.md`, `AGENTS.md`, `DESIGN_DOCUMENT_MODULE.md`, `PROJECT.md`, `CHANGELOG.md`. + +--- + +## 1. Code Style + +- **PEP8** with 120-character lines (Ruff) +- **4 spaces** indentation +- **snake_case** functions/variables, **PascalCase** classes, **SCREAMING_SNAKE_CASE** constants +- **Type hints** required on all functions +- **Import order**: stdlib → third-party → local + +--- + +## 2. SOLID Principles + +- **SRP** — One class = one responsibility +- **OCP** — Open for extension, closed for modification +- **LSP** — Subclasses substitutable for parents +- **ISP** — Small interfaces over large ones +- **DIP** — Depend on abstractions + +--- + +## 3. Dependency Injection + +Pass dependencies via constructor. Never instantiate dependencies inside a class. + +--- + +## 4. Protocols Over Inheritance + +Prefer `typing.Protocol` and composition over class inheritance. + +--- + +## 5. Data Classes + +Use `@dataclass` for internal data structures, `pydantic.BaseModel` for data that requires validation. + +--- + +## 6. Logging + +This is a library. Libraries must **never configure logging sinks** — that is the responsibility of the consuming application. + +### Usage in library code + +```python +from loguru import logger + +def some_function() -> None: + logger.debug("Detail message") + logger.info("Milestone message") +``` + +Always use the module-level `logger` from loguru directly. Never call `logger.add()` or `logger.remove()` inside library code. + +### Behavior for consumers + +Loguru has a default sink to `stderr` enabled. Consumers who also use loguru get library logs automatically in their configured sinks. Consumers who want to suppress or filter library logs use the package name as the identifier: + +```python +from loguru import logger + +logger.disable("") # suppress all +logger.add(sys.stderr, filter={"": "WARNING"}) # WARNING and above only +logger.enable("") # re-enable +``` + +This must be documented in `README.md`. + +### Rules + +- Never call `logger.add()` inside library code — no file sinks, no stdout sinks +- Never call `logger.remove()` inside library code +- Never log secrets, passwords, tokens, or API keys +- Never use `print()` inside library code — not for debugging, not for output + +#### Log levels + +| Level | When to use | +|-------|-------------| +| `DEBUG` | Per-item detail: individual operations, cache hits, internal state | +| `INFO` | Significant milestones visible to the consuming application | +| `WARNING` | Recoverable issues: fallback used, unexpected but non-fatal state | +| `ERROR` | Failures the caller must know about — operation cannot continue | + +--- + +## 7. Environment and Secrets + +- Libraries do not use `.env` files or `python-dotenv` +- Configuration is passed by the caller via arguments or constructor parameters +- Never read `os.getenv()` inside library code unless explicitly documented as a supported configuration mechanism + +--- + +## 8. Error Handling + +Define specific exception types in `src//exceptions.py`. Use a fail-fast approach — surface errors early rather than silently continuing. All public exceptions must be exported from the top-level `__init__.py`. + +--- + +## 9. Testing + +- **pytest** only — no `unittest`, no `TestCase` classes, no `self.assert*` +- Arrange-Act-Assert pattern +- Test naming: `test__` + +--- + +## 10. Tooling + +| Tool | Purpose | +|------|---------| +| **Ruff** | Formatting and linting | +| **mypy** | Static type checking | +| **pytest** | Testing | + +Run before every commit: +```bash +poetry run ruff check +poetry run mypy +poetry run pytest +``` + +--- + +## 11. Poetry + +```bash +poetry install # Install all dependencies +poetry add # Add runtime dependency +poetry add --group dev # Add dev dependency +poetry remove # Remove dependency +poetry run # Run command in virtualenv +poetry build # Build sdist and wheel into dist/ +poetry publish # Publish to PyPI +``` + +Never edit `pyproject.toml` directly to add or remove dependencies. + +### pyproject.toml configuration for a library + +```toml +[project] +name = "your-library" +version = "0.1.0" +description = "Short description" +requires-python = ">=3.x" +dependencies = [] + +[tool.poetry] +packages = [{include = "your_library", from = "src"}] + +[build-system] +requires = ["poetry-core>=2.0.0,<3.0.0"] +build-backend = "poetry.core.masonry.api" +``` + +Do **not** add `[tool.poetry.scripts]` — libraries have no entry points. + +### poetry.lock + +Do **not** commit `poetry.lock` for libraries. It is only committed for applications. Add `poetry.lock` to `.gitignore`. + +--- + +## 12. Project Structure + +``` +project/ +├── src/ +│ └── your_library/ +│ ├── __init__.py # Public API — export everything the caller needs +│ ├── exceptions.py # All public exception types +│ └── ... # Internal modules +├── tests/ # Tests +├── docs/ # Detailed documentation +├── .venv/ # Virtual environment (managed by Poetry) +└── pyproject.toml # Project config and dependencies +``` + +- No entry point scripts in the project root — this is a library, not an application +- `__init__.py` defines the public API; callers import from the top-level package only + +--- + +## 13. Public API + +- Everything intended for external use must be exported from `src//__init__.py` +- Use `__all__` to explicitly declare the public surface +- Internal modules are prefixed with `_` or kept unexported +- Public API must be stable across patch versions; breaking changes require a major version bump + +--- + +## 14. Distribution + +Build and publish with Poetry: + +```bash +poetry build # Creates dist/*.tar.gz and dist/*.whl +poetry publish # Publishes to PyPI (requires credentials) +``` + +`dist/` is **not committed** to the repository — add it to `.gitignore`. + +--- + +## 15. Versioning + +- Follow **semantic versioning**: `MAJOR.MINOR.PATCH` +- Version is defined in `pyproject.toml` under `[project]` +- Always ask before bumping the version — never increment automatically +- Update `CHANGELOG.md` before bumping the version +- Breaking changes to the public API require a major version bump + +--- + +## 16. Documentation and Task Management + +- Keep `PROJECT.md` and `CHANGELOG.md` up to date when making changes +- `README.md` must contain installation instructions and usage examples for the public API +- Document architectural changes in this file or in `docs/` + +### Task notation + +Tasks are written as single-line comments directly in code, using the **Todo Tree** tags defined in `AGENTS.md` (`TODO`, `FIXME`, `BUG`, `HACK`, `NOTE`). `PROJECT.md` carries only cross-cutting tasks that have no single place in the code. + +```python +# TODO: extract this into a separate loader +# FIXME: crashes on an empty file +# BUG: rounding is off by one cent on negative amounts +# HACK: temporary workaround until the API adds paging +# NOTE: order matters here, the parser is stateful +``` + +No other task format is used — **no checkboxes, no numbered lists in documentation**. + +If a tag already exists at a specific location in code, do not repeat it in `PROJECT.md`.