diff --git a/.github/skills/diataxis-docs-planner/SKILL.md b/.github/skills/diataxis-docs-planner/SKILL.md new file mode 100644 index 0000000..55bad30 --- /dev/null +++ b/.github/skills/diataxis-docs-planner/SKILL.md @@ -0,0 +1,169 @@ +--- +name: diataxis-docs-planner +description: Audit, plan, and structure Python package documentation following the Diátaxis framework (tutorials, how-to guides, reference, explanation). Use when asked to plan documentation, audit existing docs, identify documentation gaps, restructure docs, create a documentation roadmap, or organize documentation for a Python package. Triggers on "plan docs", "audit documentation", "structure docs", "documentation roadmap", "what docs do I need", "organize documentation". +--- + +# Diátaxis Documentation Planner + +Audit existing documentation and produce a structured plan following the Diátaxis framework - four quadrants of documentation that serve distinct user needs. + +## The Four Quadrants + +| Quadrant | Orientation | User mode | Serves | Question answered | +|----------|-------------|-----------|--------|-------------------| +| **Tutorial** | Learning | Study | Acquisition of skill | "Can you teach me to…?" | +| **How-to guide** | Task | Work | Application of skill | "How do I…?" | +| **Reference** | Information | Work | Application of skill | "What is…?" | +| **Explanation** | Understanding | Study | Acquisition of skill | "Why…?" | + +## Compass Decision Tree + +Classify any content by asking two questions: + +1. **Action or cognition?** Does it guide what the user *does*, or inform what the user *knows*? +2. **Acquisition or application?** Does it serve *study* (learning) or *work* (applying skills)? + +| Informs… | Serves… | → Quadrant | +|----------|---------|------------| +| Action | Acquisition (study) | Tutorial | +| Action | Application (work) | How-to guide | +| Cognition | Application (work) | Reference | +| Cognition | Acquisition (study) | Explanation | + +## Audit Workflow + +### Step 1: Analyze the Codebase + +Examine the package to understand what needs documenting: + +- Read `pyproject.toml` for package name, description, dependencies, entry points, CLI tools +- Scan `src//` for public modules, classes, functions (the API surface) +- Check for CLI entry points, configuration files, plugin systems +- Look at `tests/` for usage patterns and features exercised +- Check `examples/` if present + +### Step 2: Inventory Existing Documentation + +Read all files in `docs/` and classify each page by quadrant using the compass: + +- For each page, note: file path, current title, actual quadrant, intended quadrant +- Flag pages that mix quadrants (e.g., a "getting started" that is half tutorial, half reference) +- Flag pages that are misclassified (e.g., an "explanation" page that is really a how-to) + +### Step 3: Identify Gaps + +For a well-documented Python package, expect at minimum: + +**Tutorials** (at least 1): +- Getting Started / First Steps - install, import, first meaningful result + +**How-to Guides** (varies by feature count): +- One per common task/problem users face +- Installation/setup variations (different platforms, configs) +- Integration with other tools/libraries +- Configuration for common scenarios +- Troubleshooting guide + +**Reference** (comprehensive): +- API reference (all public modules, classes, functions) +- CLI reference (if applicable) +- Configuration reference (all settings/options) +- Error codes / exceptions (if applicable) + +**Explanation** (at least 1-2): +- Architecture / design overview +- Key concepts and terminology +- Advantages of the chosen tooling and patterns (focus on benefits, not justification) + +### Step 4: Produce the Plan + +Output a structured documentation plan: + +1. **Gap analysis table** - what exists, what is missing, what needs reclassification +2. **Recommended pages** - organized by quadrant, with title, purpose, priority (high/medium/low) +3. **MkDocs nav structure** - ready to paste into `mkdocs.yml` +4. **Implementation order** - tutorials and key how-tos first (highest user impact) +5. **Skill recommendations** - name the specific writer skill for each page: + - Tutorial pages → `diataxis-tutorial-writer` + - How-to pages → `diataxis-howto-writer` + - Reference pages → `diataxis-reference-writer` + - Explanation pages → `diataxis-explanation-writer` + +## MkDocs Nav Patterns + +Typical Python package nav structure: + +```yaml +nav: + - Home: index.md + - Getting Started: getting-started.md # tutorial + - How-to Guides: # how-to + - how-to/index.md + - How to Configure X: how-to/configure-x.md + - How to Integrate with Y: how-to/integrate-y.md + - Reference: # reference + - reference/index.md + - API Reference: reference/api.md + - CLI Reference: reference/cli.md + - Configuration: reference/configuration.md + - Explanation: # explanation + - explanation/index.md + - Architecture: explanation/architecture.md + - Contributing: contributing.md # how-to (for contributors) +``` + +For complex packages with multiple user types or deployment targets, see [references/compass-and-patterns.md](references/compass-and-patterns.md) for multi-layer hierarchy and two-dimensional structure guidance. + +## Common Anti-Patterns to Flag + +- **The mega-README**: Everything in one file - split by quadrant +- **Tutorial-reference hybrid**: "Getting Started" that is actually an API walkthrough - separate +- **How-to disguised as explanation**: "Understanding X" that is really step-by-step instructions +- **Missing tutorials entirely**: Only reference docs (common with auto-generated docs) +- **Explanation scattered everywhere**: Bits of "why" sprinkled across how-to guides - consolidate + +## Quality Signals + +When auditing, also note: + +- **Functional quality**: accuracy, completeness, consistency, precision +- **Deep quality**: flow, fit to user needs, anticipation of the user +- Use the `mkdocs` skill for site configuration and build concerns - this skill focuses on content structure + +## Output Format + +```markdown +## Documentation Audit: + +### Current State + +| Page | File | Current Quadrant | Issues | +|------|------|-----------------|--------| +| ... | ... | ... | ... | + +### Gap Analysis + +| Quadrant | Existing | Missing | Priority | +|----------|----------|---------|----------| +| Tutorial | ... | ... | ... | +| How-to | ... | ... | ... | +| Reference | ... | ... | ... | +| Explanation | ... | ... | ... | + +### Recommended Pages +#### Tutorials (use `diataxis-tutorial-writer`) +1. **Getting Started** - Install, first use, verify result [HIGH] + +#### How-to Guides (use `diataxis-howto-writer`) +1. **How to configure X** - ... [HIGH] + +#### Reference (use `diataxis-reference-writer`) +1. **API Reference** - Full public API [HIGH] + +#### Explanation (use `diataxis-explanation-writer`) +1. **Architecture Overview** - ... [MEDIUM] + +### Proposed MkDocs Nav +nav: + ... +``` diff --git a/.github/skills/diataxis-docs-planner/references/compass-and-patterns.md b/.github/skills/diataxis-docs-planner/references/compass-and-patterns.md new file mode 100644 index 0000000..b535a5f --- /dev/null +++ b/.github/skills/diataxis-docs-planner/references/compass-and-patterns.md @@ -0,0 +1,119 @@ +# Diátaxis Compass and Documentation Patterns + +## Full Compass Table + +| Content characteristic | Tutorial | How-to Guide | Reference | Explanation | +|----------------------|----------|-------------|-----------|-------------| +| **What they do** | Introduce, educate, lead | Guide | State, describe, inform | Explain, clarify, discuss | +| **Answers the question** | "Can you teach me to…?" | "How do I…?" | "What is…?" | "Why…?" | +| **Oriented to** | Learning | Goals | Information | Understanding | +| **Purpose** | Provide a learning experience | Help achieve a particular goal | Describe the machinery | Illuminate a topic | +| **Form** | A lesson | A series of steps | Dry description | Discursive explanation | +| **Analogy** | Teaching a child to cook | A recipe in a cookbook | Info on a food packet | Article on culinary history | + +## Boundary Blur Risks + +Adjacent quadrants share affinities that cause content to bleed across boundaries: + +| Shared trait | Quadrants at risk | Common mistake | +|-------------|------------------|----------------| +| Guide action | Tutorial ↔ How-to | Conflating "getting started" with "how to configure" | +| Serve application of skill | Reference ↔ How-to | Stuffing procedures into API docs | +| Contain propositional knowledge | Reference ↔ Explanation | Expanding reference examples into explanations | +| Serve acquisition of skill | Tutorial ↔ Explanation | Overloading tutorials with background context | + +## Python Package Page Patterns + +### Typical Tutorial Pages +- **Getting Started** - Install via pip/uv, import, call a function, verify output +- **Your First ** - Build something small end-to-end +- **Tutorial Series Part N** - Multi-part progressive learning path + +### Typical How-to Pages +- **How to install** (with variations: pip, uv, conda, Docker, from source) +- **How to configure ** - Settings, env vars, config files +- **How to integrate with ** - Using the package alongside another tool +- **How to deploy** - Production setup, CI/CD integration +- **How to extend / write plugins** - For extensible packages +- **How to migrate from vX to vY** - Upgrade guides +- **Troubleshooting** - Common problems and solutions + +### Typical Reference Pages +- **API Reference** - Auto-generated via mkdocstrings (modules → classes → methods) +- **CLI Reference** - Commands, flags, options, exit codes +- **Configuration Reference** - All settings with types, defaults, descriptions +- **Error Reference** - Exception classes, error codes, meanings +- **Changelog** - Version history (auto-generated via git-cliff or similar) + +### Typical Explanation Pages +- **Architecture Overview** - How the package is structured and why +- **Design Decisions** - Why certain approaches were chosen +- **Key Concepts** - Domain terminology and mental models +- **Comparison with Alternatives** - How this package differs from similar tools +- **Performance Characteristics** - Complexity, benchmarks, trade-offs +- **Security Model** - Trust boundaries, threat model (when applicable) + +## Complex Hierarchy Patterns + +### Single Product, Multiple User Types + +```text +docs/ + getting-started.md # tutorial (all users) + how-to/ + users/ # how-to for end users + configure.md + troubleshoot.md + developers/ # how-to for integrators + extend.md + write-plugins.md + contributors/ # how-to for maintainers + development-setup.md + release-process.md + reference/ + api.md # reference (shared) + cli.md + config.md + explanation/ + architecture.md # explanation (shared) + design-decisions.md +``` + +### Single Product, Multiple Deployment Targets + +```text +docs/ + getting-started.md # tutorial (generic) + how-to/ + install-pip.md # how-to per target + install-docker.md + install-from-source.md + deploy-aws.md + deploy-gcp.md + reference/ # reference (shared) + api.md + config.md + explanation/ # explanation (shared) + architecture.md +``` + +## Contents Page Guidelines + +- Landing pages should read as overviews, not bare lists +- Keep lists under 7 items per group; break into sub-sections if longer +- Use headings with brief introductory text to provide context +- Each landing page should help the user quickly find what they need + +## Quality Checklist + +### Functional Quality (measurable) +- [ ] Accurate - code examples run, commands produce stated output +- [ ] Complete - all public API surface documented +- [ ] Consistent - terminology, formatting, style uniform across pages +- [ ] Up-to-date - matches current version of the package + +### Deep Quality (experiential) +- [ ] Flow - reader progresses naturally without jarring transitions +- [ ] Fit to needs - each page serves a clear user need +- [ ] Anticipation - docs address questions before they arise +- [ ] Minimal friction - no unnecessary detours or digressions diff --git a/.github/skills/diataxis-explanation-writer/SKILL.md b/.github/skills/diataxis-explanation-writer/SKILL.md new file mode 100644 index 0000000..29b8de5 --- /dev/null +++ b/.github/skills/diataxis-explanation-writer/SKILL.md @@ -0,0 +1,143 @@ +--- +name: diataxis-explanation-writer +description: Generate understanding-oriented explanation documentation for Python packages following Diátaxis principles. Use when asked to write conceptual docs, architecture overview, design decisions, "about" pages, "why" docs, background context, or any documentation that helps the reader understand a topic through reflection and discussion. Triggers on "write an explanation", "conceptual docs", "architecture overview", "design decisions", "why did we choose", "background", "about the design", "explain the architecture". +--- + +# Diátaxis Explanation Writer + +Generate explanation documentation - understanding-oriented discussion that helps the reader make sense of a topic through reflection. + +Explanation is like reading **On Food and Cooking** by Harold McGee: it does not teach you to cook or give you recipes, but it places cooking in context of history, science, and society, deepening your understanding of the craft. + +## What Explanation Is + +- Discursive treatment of a subject that permits reflection +- Deepens and broadens understanding by providing context, connections, and perspective +- An answer to "Can you tell me about…?" +- The only documentation you might read in the bath - away from the keyboard + +Explanation serves the user's **study**, not their work. It is the counterpart to reference (which also contains propositional knowledge but serves work). + +## Generation Workflow + +### Step 1: Identify the Topic + +- What concept, decision, or aspect of the package would benefit from deeper understanding? +- Frame it as an implicit "About…": "About the plugin architecture", "About authentication design" +- Choose a topic that can be meaningfully bounded - not the entire package, but a coherent area + +### Step 2: Gather Context + +- Read the source code to understand the design +- Check git history or ADRs for decision rationale +- Look at `README.md` and existing docs for hints about design philosophy +- Identify connections to other systems, concepts, or alternatives + +### Step 3: Write the Explanation + +Structure as a discussion that circles around the topic from different angles. Apply all key principles below. Target 500-2000 words. + +## Key Principles + +### Make connections + +Weave a web of understanding. Connect the topic to other things - even outside the immediate subject - if it helps comprehension. + +"The event system works similarly to browser DOM events, where handlers are registered for specific event types and called when those events fire." + +### Provide context + +Describe the advantages of the approach taken. Focus on what is gained - not on defending the choice or comparing with rejected alternatives. Draw implications. Mention specific examples. + +"SQLite requires zero configuration and ships with Python's standard library. For production workloads exceeding 100 concurrent writers, see the PostgreSQL backend." + +### Talk about the subject + +Explanation guides are **about** a topic - they circle around it. The title should allow an implicit "about": "About user authentication", "About the caching strategy". + +Discuss: +- The bigger picture +- History and evolution +- Choices, alternatives, possibilities +- Why: reasons and justifications + +### State advantages, not justifications + +Describe what the chosen approach provides. Do not include "Why X over Y" sections or comparison tables with alternatives. The reader wants to understand the benefits, not the decision-making process. + +### Keep explanation closely bounded + +One risk of explanation is absorbing other things. The urge to include instruction (how-to) or technical description (reference) is strong. Resist it - those have their own places. Allowing them in interferes with the explanation and removes them from where they belong. + +## Language Patterns + +- **"The reason for X is because historically, Y…"** - Explain origins +- **"W is better than Z, because…"** - Offer judgements where appropriate +- **"An X in this system is analogous to a Y in…"** - Provide context through analogy +- **"Some users prefer W (because Z). This can be a good approach, but…"** - Weigh alternatives +- **"X interacts with Y as follows:…"** - Unfold internal workings to build understanding + +## Python Package Explanation Template + +```markdown +# About [Topic] + +[Opening paragraph that frames the topic and its role in the package.] + +## Overview + +[High-level description of the concept, system, or approach. +Connect it to the reader's existing knowledge.] + +## [Component/Aspect Name] + +[Describe what it does and the advantages it provides. +Focus on benefits, not on justifying the choice or comparing with alternatives. +Keep sections concise - state what is gained, not what was rejected.] + +## How It Works + +[Describe the mechanism at a conceptual level - not a step-by-step procedure +(that would be a how-to), but the logic and flow of the system.] + +[Diagrams or analogies are valuable here.] + +## Connections + +[Link this topic to related concepts, other parts of the system, or broader +patterns in the ecosystem.] + +- [Related concept in the package](other-explanation.md) +- [API Reference for this system](../reference/api.md) +- [How to configure this feature](../how-to/configure.md) +``` + +## Typical Explanation Pages for Python Packages + +- **Architecture Overview** - How the package is structured, the component graph, data flow +- **Key Concepts** - Domain terminology, mental models, glossary with depth +- **Plugin/Extension Model** - How extensibility works +- **Performance Characteristics** - Complexity analysis, caching strategy, benchmarks with context +- **Security Model** - Trust boundaries, threat model, security approach + +## Distinction from Reference + +| Aspect | Explanation | Reference | +|--------|------------|-----------| +| Purpose | Illuminate a topic | Describe the machinery | +| User mode | At study | At work | +| Tone | Discursive, reflective | Austere, neutral | +| Content | Context, reasons, opinions | Facts, specifications | +| Structure | Circles around a topic | Mirrors code structure | +| When read | Away from the keyboard | While coding | +| Test | "Could I read this in the bath?" → explanation | "Is this boring?" → reference | + +## Anti-Patterns to Avoid + +- **Disguised reference** - Lists of parameters or API details belong in reference +- **Disguised how-to** - Step-by-step procedures belong in how-to guides +- **No clear topic** - Every explanation must be "about" something bounded +- **Too abstract** - Ground discussion in concrete examples from the actual package +- **Missing the "why"** - If it does not explain advantages or mechanisms, it is probably reference, not explanation +- **Justification mode** - "Why X over Y" sections and comparison tables belong in ADRs, not docs +- **Unbounded scope** - Explanation that tries to cover everything covers nothing well diff --git a/.github/skills/diataxis-howto-writer/SKILL.md b/.github/skills/diataxis-howto-writer/SKILL.md new file mode 100644 index 0000000..b5204aa --- /dev/null +++ b/.github/skills/diataxis-howto-writer/SKILL.md @@ -0,0 +1,182 @@ +--- +name: diataxis-howto-writer +description: Generate task-oriented how-to guide documentation for Python packages following Diátaxis principles. Use when asked to write a how-to guide, cookbook entry, recipe, procedure, troubleshooting guide, or any documentation that helps an already-competent user accomplish a specific real-world task. Triggers on "write a how-to", "how to configure", "how to deploy", "how to integrate", "troubleshooting guide", "cookbook", "recipe", "procedure for". +--- + +# Diátaxis How-to Guide Writer + +Generate how-to guides - task-oriented documentation that helps already-competent users accomplish specific goals. + +A how-to guide is a **recipe**. It addresses a real-world problem and provides practical directions to solve it. The reader already knows what they want to do. + +## What a How-to Guide Is + +- Directions that guide the reader through a problem or towards a result +- Addresses an already-competent user who knows what they want to achieve +- Concerned with **work**, not study +- Like a recipe: a professional chef still uses recipes to ensure correctness + +A how-to guide is NOT a tutorial. Tutorials serve learning; how-to guides serve work. See the distinction section below. + +## Generation Workflow + +### Step 1: Identify the Task + +- What real-world problem or goal does the user have? +- Frame it from the **user's perspective**, not the tool's capabilities +- Good: "How to configure logging for production" (user need) +- Bad: "Using the LogConfig class" (tool-centric, not a need) + +### Step 2: Determine Prerequisites + +- What should the user already know or have set up? +- List these briefly at the top - do not teach them (that is a tutorial's job) + +### Step 3: Write the Guide + +Structure as a sequence of actions toward the goal. Apply all key principles below. + +## Key Principles + +### Address real-world complexity + +A guide useless for any purpose except exactly the narrow case described is rarely valuable. Remain open to the range of possibilities so users can adapt guidance to their needs. + +Use conditional steps: "If you are using X, do Y instead." + +### Omit the unnecessary + +Practical usability over completeness. A how-to guide should start and end in some reasonable place, requiring the reader to join it up to their own work. Unlike a tutorial, it does not need to be end-to-end. + +### Provide a set of instructions + +The steps are in the form of actions - including thinking and judgement, not just physical acts. Address how the user thinks as well as what the user does. + +### Describe a logical sequence + +The fundamental structure is a sequence that implies logical ordering in time. If one step sets up the environment for another, put it first even if the ordering is not strictly required. + +### Seek flow + +Ground sequences in the user's activity patterns. A workflow that has the user repeatedly switching contexts is clumsy. Consider: + +- What are you asking the user to think about? +- How long must they hold a thought before resolving it in action? +- Does the guide require unnecessary back-and-forth? + +At its best, a how-to guide anticipates the user - the helper who has the tool ready before you reach for it. + +### Pay attention to naming + +Titles must say exactly what the guide shows: + +- Good: "How to integrate application performance monitoring" +- Bad: "Integrating application performance monitoring" (could be about whether to, not how) +- Worse: "Application performance monitoring" (could be anything) + +### No digression, explanation, or teaching + +Anything beyond action dilutes the guide. Do not explain concepts inline - link to explanation pages. Do not teach basics - that is a tutorial's job. Do not provide exhaustive reference - link to reference pages. + +## Language Patterns + +- **"This guide shows you how to…"** - Describe the problem and what will be solved +- **"If you want x, do y. To achieve w, do z."** - Conditional imperatives +- **"Refer to the X reference guide for a full list of options."** - Don't pollute with every option + +## Python Package How-to Template + +````markdown +# How to [Accomplish Specific Goal] + +This guide shows you how to [goal description]. Use this when you need to +[real-world scenario]. + +## Prerequisites + +- installed ([Getting Started](../getting-started.md)) +- [Other requirement] + +## Steps + +### 1. [First Action] + +```python +from import + + +``` + +### 2. [Second Action] + +If you are [condition A]: + +```python +# approach for condition A +``` + +If you are [condition B] instead: + +```python +# approach for condition B +``` + +### 3. [Verify / Complete] + +```python +# verification step +``` + +## Common Variations + +- **[Variation 1]**: [Brief guidance] +- **[Variation 2]**: [Brief guidance] + +## Troubleshooting + +**Problem: [common issue]** +: [Solution] + +**Problem: [another issue]** +: [Solution] + +## See Also + +- [API Reference for X](../reference/api.md) - full list of options +- [About Y architecture](../explanation/architecture.md) - understanding the design +```text + +## Typical How-to Guides for Python Packages + +- **How to install** - pip, uv, conda, Docker, from source variations +- **How to configure ** - settings, env vars, config files +- **How to integrate with ** - using alongside pytest, FastAPI, Django, etc. +- **How to deploy to production** - WSGI, Docker, cloud platforms +- **How to write a plugin / extension** - for extensible packages +- **How to migrate from vX to vY** - upgrade path with breaking changes +- **How to test your code** - patterns for testing code that uses the package +- **How to troubleshoot ** - common problems and solutions +- **How to contribute** - development setup, workflow, conventions + +## Distinction from Tutorials + +| Aspect | Tutorial | How-to Guide | +|--------|----------|-------------| +| User state | At study | At work | +| User skill | Beginner | Already competent | +| Goal | Learning experience | Task completion | +| Path | Single, managed | Branching, real-world | +| Setting | Contrived, safe | Real world, unpredictable | +| Choices | None - pick for them | Conditional alternatives | +| Responsibility | Teacher's | User's | +| Explanation | Minimal, inline | None - link out | + +A tutorial teaches general skills through a specific exercise. A how-to guide helps accomplish a specific task using existing skills. + +## Anti-Patterns to Avoid + +- **Teaching basics** - Do not explain what a function is; the user is competent +- **Exhaustive options** - List 2-3 variations, link to reference for the rest +- **Tool-centric framing** - "How to use the X class" is not addressed to a human need +- **Missing conditionals** - Real-world tasks branch; acknowledge this with if/then guidance +- **Burying the action** - Lead with what to do, not why diff --git a/.github/skills/diataxis-reference-writer/SKILL.md b/.github/skills/diataxis-reference-writer/SKILL.md new file mode 100644 index 0000000..826f3f6 --- /dev/null +++ b/.github/skills/diataxis-reference-writer/SKILL.md @@ -0,0 +1,227 @@ +--- +name: diataxis-reference-writer +description: Generate and structure information-oriented reference documentation for Python packages following Diátaxis principles. Use when asked to write API reference docs, CLI reference, configuration reference, error code reference, or any documentation that provides austere technical description of the machinery. Triggers on "write reference docs", "API documentation", "document the API", "CLI reference", "configuration reference", "error reference", "describe the interface". +--- + +# Diátaxis Reference Writer + +Generate reference documentation - information-oriented technical descriptions of the machinery, meant to be consulted, not read. + +Reference material is like a **map**: it describes the territory accurately so the user can navigate it confidently while working. It is austere, authoritative, and free of interpretation. + +## What Reference Is + +- Technical description of the machinery and how to operate it +- Propositional knowledge the user looks to while working +- Led by the **product structure**, not by user needs +- Purpose: describe, as succinctly as possible, in an orderly way + +Reference is what the user needs while they are at work - applying their existing skills. + +## Generation Workflow + +### Step 1: Map the API Surface + +- Scan `src//` for all public modules +- Within each module, identify public classes, functions, constants, type aliases +- Note the module hierarchy: package → subpackages → modules → classes → methods +- Check `__all__` exports if defined +- Identify CLI entry points from `pyproject.toml` `[project.scripts]` +- Find configuration schemas, settings classes, env var definitions + +### Step 2: Mirror the Code Structure + +The documentation structure must reflect the code structure - like a map reflects territory. If a method belongs to a class in a module, the docs should show the same hierarchy. + +```text +reference/ + api.md # or split per module: + api/ + module_a.md # mirrors src//module_a.py + module_b.md # mirrors src//module_b.py + cli.md # mirrors CLI commands + configuration.md # mirrors settings/config +``` + +### Step 3: Write the Reference + +Apply all key principles below. For API docs, prefer mkdocstrings auto-generation with well-written docstrings over hand-written reference. + +## Key Principles + +### Describe and only describe + +Neutral description is the key imperative. Do not explain, instruct, discuss, or opine. These run counter to reference needs which demand accuracy, precision, completeness, and clarity. + +If instruction or explanation feels necessary, link to how-to guides or explanation pages instead. + +### Adopt standard patterns + +Reference is useful when it is consistent. Use the same format for every function, every class, every CLI command. Standard patterns let users scan rapidly. + +No creative vocabulary or varied styles - reference is not the place. + +### Respect the structure of the machinery + +The documentation structure mirrors the code structure. If the code organizes functionality into modules and classes, the reference should do the same. This lets the user navigate code and docs in parallel. + +### Provide examples + +Short usage examples illustrate without distracting. An example of a command invocation or function call is a succinct way to show context without falling into explanation. + +```python +# Example: Create a client with custom timeout +client = MyClient(timeout=30) +``` + +Keep examples minimal - just enough to illustrate, not to teach. + +## Language Patterns + +- **" provides…"**, **" returns…"** - State facts about the machinery +- **"Parameters: a, b, c"** - List inputs, outputs, options +- **"You must use X. You must not apply Y unless Z."** - Warnings where appropriate +- **"See [How to configure X] for usage guidance."** — Link out + +## mkdocstrings Integration + +For Python packages using MkDocs with mkdocstrings, generate reference via docstrings: + +### Docstring Format (NumPy style) + +```python +def process(data: list[float], *, normalize: bool = False) -> Result: + """Process the input data and return a Result. + + Parameters + ---------- + data : list[float] + The input data points to process. + normalize : bool, optional + Whether to normalize values to [0, 1] range, by default False. + + Returns + ------- + Result + The processed result containing summary statistics. + + Raises + ------ + ValueError + If `data` is empty. + + Examples + -------- + >>> process([1.0, 2.0, 3.0]) + Result(mean=2.0, std=0.816) + + >>> process([1.0, 2.0, 3.0], normalize=True) + Result(mean=0.5, std=0.408) + """ +``` + +### MkDocs Page Using mkdocstrings + +```markdown +# API Reference + +::: package_name + options: + show_root_heading: true + show_source: true + members_order: source +``` + +Or per-module: + +```markdown +# module_name + +::: package_name.module_name + options: + show_root_heading: true + show_source: true + members_order: source +``` + +## CLI Reference Template + +```markdown +# CLI Reference + +## `command-name` + +``` +command-name [OPTIONS] ARGUMENT +```text + +### Arguments + +| Argument | Description | Required | +|----------|-------------|----------| +| `ARGUMENT` | Description | Yes | + +### Options + +| Option | Short | Description | Default | +|--------|-------|-------------|---------| +| `--verbose` | `-v` | Enable verbose output | `false` | +| `--output` | `-o` | Output file path | stdout | + +### Exit Codes + +| Code | Meaning | +|------|---------| +| 0 | Success | +| 1 | General error | +| 2 | Invalid arguments | + +### Examples + +```bash +command-name --verbose input.txt +command-name -o result.json input.txt +``` +```text + +## Configuration Reference Template + +```markdown +# Configuration Reference + +## Environment Variables + +| Variable | Type | Default | Description | +|----------|------|---------|-------------| +| `PACKAGE_DEBUG` | `bool` | `false` | Enable debug mode | +| `PACKAGE_LOG_LEVEL` | `str` | `"INFO"` | Logging level | + +## Configuration File + +The configuration file is read from `~/.config/package/config.toml`. + +### `[section]` + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| `key` | `str` | `""` | Description | +``` + +## Distinction from Explanation + +| Aspect | Reference | Explanation | +|--------|-----------|-------------| +| Purpose | Describe the machinery | Illuminate a topic | +| User mode | At work | At study | +| Tone | Austere, neutral | Discursive, reflective | +| Content | Facts, specifications | Context, reasons, connections | +| When read | While doing something | When stepping back to think | +| Test | "Is this boring and unmemorable?" → reference | "Could I read this in the bath?" → explanation | + +## Anti-Patterns to Avoid + +- **Creeping explanation** - Examples that expand into "why" discussions; keep examples terse +- **Missing structure** - Flat lists of functions with no hierarchy; mirror the code +- **Incomplete coverage** - Every public API surface must be documented, no gaps +- **Stale content** - Reference must match the current version; automate where possible +- **Instruction mixed in** - "To use this, first do X" is a how-to; reference just describes diff --git a/.github/skills/diataxis-tutorial-writer/SKILL.md b/.github/skills/diataxis-tutorial-writer/SKILL.md new file mode 100644 index 0000000..fc6aaa6 --- /dev/null +++ b/.github/skills/diataxis-tutorial-writer/SKILL.md @@ -0,0 +1,204 @@ +--- +name: diataxis-tutorial-writer +description: Generate learning-oriented tutorial documentation for Python packages following Diátaxis principles. Use when asked to write a tutorial, getting started guide, first steps page, quickstart, onboarding guide, or any documentation that teaches a beginner by walking them through hands-on steps. Triggers on "write a tutorial", "getting started page", "quickstart guide", "first steps", "beginner guide", "onboarding docs", "teach how to use". +--- + +# Diátaxis Tutorial Writer + +Generate tutorials - learning-oriented documentation where the reader acquires skills through hands-on practice under guidance. + +A tutorial is a **lesson**. The reader does things, and learns by doing. The author is the teacher; the reader is the student. + +## What a Tutorial Is + +- A practical activity where the student learns by doing something meaningful +- Designed around an encounter the learner can make sense of +- The teacher is responsible for the learner's safety and success +- Purpose: help them **learn**, not help them **get something done** + +A tutorial is like a driving lesson: the purpose is to develop skills and confidence, not to get from A to B. + +## Generation Workflow + +### Step 1: Understand the Package + +- Read `pyproject.toml` for package name, description, key features +- Scan `src//` for the simplest useful public API +- Check `examples/` for existing usage patterns +- Identify the **single most impressive thing** a beginner can achieve quickly + +### Step 2: Design the Learning Journey + +Choose a concrete goal the learner will achieve. Structure it as: + +1. **Setup** - Install the package, verify installation +2. **First contact** - Import, call the simplest function, see a result +3. **Build** - Incrementally add complexity, one concept at a time +4. **Completion** - Arrive at a meaningful, visible result +5. **Next steps** - Link to how-to guides and explanation (not more tutorials) + +Every step should produce a **visible, verifiable result**. + +### Step 3: Write the Tutorial + +Apply all key principles below. Use the language patterns. Target 500-1500 words. + +## Key Principles + +### Show the learner where they are going + +Open with what they will achieve: "In this tutorial, we will create a [concrete thing]. Along the way we will [encounter X, Y, Z]." + +Never say "In this tutorial you will learn…" - that is presumptuous. + +### Deliver visible results early and often + +Every step must produce something the user can see. Start with the smallest possible success, then build. + +```python +# Step 1: Verify installation +import my_package +print(my_package.__version__) +# Output: 1.0.0 +``` + +### Maintain a narrative of the expected + +Tell the user what will happen before it happens: "You will notice that…", "After a moment, you should see…", "The output should look something like…" + +Show exact expected output. Flag likely mistakes: "If you see X instead, you probably forgot to Y." + +### Point out what the learner should notice + +Close learning loops: "Notice that the prompt changed to…", "See how the output now includes…" + +Observing is an active skill. Prompt it. + +### Ruthlessly minimise explanation + +A tutorial is not the place for explanation. One sentence is enough: "We use HTTPS because it is more secure." Link to explanation pages for depth. + +Explanation distracts the learner's attention and blocks learning. Resist the urge to teach by telling. + +### Focus on the concrete + +Focus on *this* problem, *this* action, *this* result. Lead the learner from step to concrete step. General patterns will emerge naturally from concrete examples - the mind does this automatically. + +### Ignore options and alternatives + +There may be many interesting diversions - ignore them. Stay on the path to the conclusion. Every option adds cognitive load. Save alternatives for how-to guides. + +### Encourage and permit repetition + +Where possible, make steps repeatable. Learners often repeat a step just to confirm "the same thing really does happen again." + +### Aspire to perfect reliability + +Every step must produce the stated result for every user, every time. A learner who does not get the expected result loses confidence immediately. Test the tutorial end-to-end. + +## Language Patterns + +Use these templates: + +- **"We…"** - First-person plural affirms the teacher-learner relationship +- **"In this tutorial, we will…"** - Describe what the learner will accomplish +- **"First, do x. Now, do y. Now that you have done y, do z."** - No ambiguity +- **"The output should look something like…"** - Set expectations +- **"Notice that…"**, **"Remember that…"**, **"Let's check…"** - Confirm they are on track +- **"You have built a…"** - Celebrate the accomplishment at the end + +## Python Package Tutorial Template + +````markdown +# Getting Started + +In this tutorial, we will [concrete achievement]. Along the way, we will +[encounter key concepts]. + +## Prerequisites + +- Python [version]+ installed +- A terminal or command prompt + +## Installation + +=== "pip" + + ```bash + pip install + ``` + +=== "uv" + + ```bash + uv add + ``` + +Verify the installation: + +```python +import +print(.__version__) +``` + +The output should look something like: + +```text +x.y.z +``` + +## Your First [Thing] + +Now let's [do the first meaningful action]. + +```python +from import + +result = () +print(result) +``` + +You should see: + +```text +[expected output] +``` + +Notice that [observation about the result]. + +## [Building On It] + +Now that we have [previous result], let's [next step]. + +[... continue building incrementally ...] + +## What We Built + +You have [accomplished concrete thing]. Along the way, you: + +- [Learned concept 1] +- [Used tool/function X] +- [Saw how Y works] + +## Next Steps + +- [How-to guide for a related task](../how-to/something.md) +- [Explanation of a concept encountered](../explanation/concept.md) +- [API reference for the functions used](../reference/api.md) +```text + +## Anti-Patterns to Avoid + +- **Starting with explanation** - Do not open with "X is a framework that…"; open with what they will do +- **Offering choices** - "You can use either A or B" forces a decision; just pick one +- **Assumed knowledge** - Do not skip steps because they seem obvious +- **Wall of code** - Break into small steps, each with visible output +- **Missing output examples** - Every code block needs its expected output +- **Teaching by telling** - Show, do not explain; link to explanation pages instead + +## What a Tutorial Is NOT + +- Not a how-to guide (serves work, not study) +- Not a reference (describes machinery, doesn't guide action) +- Not an explanation (discusses topics, doesn't guide action) +- Not "the basics" - tutorials can be advanced; the distinction is study vs. work diff --git a/docs/index.md b/docs/index.md index 3c0f71d..b2781a6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,7 +3,7 @@ # Welcome to Python Copier Template's Documentation -A modern Python package template using [Copier](https://copier.readthedocs.io/) that gets you from zero to production-ready in minutes. +A modern Python package template using [Copier](https://copier.readthedocs.io/) that gets you from zero to production-ready in minutes. Answer a few questions, and Copier renders a complete project with testing, linting, documentation, CI/CD, and release automation - all wired up and ready to go. ## Features @@ -21,5 +21,24 @@ A modern Python package template using [Copier](https://copier.readthedocs.io/) ## Get Started - **[Quick Start](pages/quickstart.md)** - Create your package in 5 minutes -- **[Reference](pages/reference.md)** - Complete guide to all features and commands -- **[Contributing](pages/contributing.md)** - Help improve the template + +## How-to Guides + +- **[Set Up CI/CD Services](pages/how-to/setup-cicd.md)** - Configure Codecov, PyPI, ReadTheDocs +- **[Customize Your Project](pages/how-to/customize-template.md)** - Adjust ruff rules, coverage, hooks +- **[Update from Template](pages/how-to/update-template.md)** - Pull in template improvements +- **[Add Dependencies](pages/how-to/add-dependencies.md)** - Manage runtime and dev dependencies +- **[Contribute to the Template](pages/how-to/contribute.md)** - Help improve the template + +## Reference + +- **[Template Variables](pages/reference/template-variables.md)** - All configurable options +- **[Project Structure](pages/reference/project-structure.md)** - Generated file tree and roles +- **[Commands](pages/reference/commands.md)** - just, nox, and uv command reference +- **[GitHub Workflows](pages/reference/github-workflows.md)** - CI/CD workflow details +- **[Configuration Files](pages/reference/configuration.md)** - Tool configuration reference + +## Explanation + +- **[Architecture Overview](pages/explanation/architecture.md)** - How the template is designed +- **[Release Process](pages/explanation/release-process.md)** - How automated releases work diff --git a/docs/pages/contributing.md b/docs/pages/contributing.md deleted file mode 100644 index 4040cb2..0000000 --- a/docs/pages/contributing.md +++ /dev/null @@ -1,418 +0,0 @@ -# Contributing - -## Setup - -```bash -# Clone the repository -git clone https://github.com/stateful-y/python-package-copier.git -cd python-package-copier - -# Install dependencies -uv sync --group test --group docs - -# Install pre-commit hooks (optional) -uv run pre-commit install -``` - -## Test Template Changes - -The template repository uses pytest with markers to categorize tests: - -- **Fast tests**: Unit tests that validate template generation without running subprocesses -- **Slow tests**: Tests marked with `@pytest.mark.slow` that take longer to execute -- **Integration tests**: Tests marked with `@pytest.mark.integration` that use `copier.run_copy()` to generate actual projects - -### Test Commands - -Run fast tests only (recommended during development): - -=== "just" - - ```bash - just test-fast - ``` - -=== "nox" - - ```bash - uvx nox -s test_fast - ``` - -=== "uv run" - - ```bash - uv run pytest -m "not slow and not integration" -v - ``` - -Run slow and integration tests: - -=== "just" - - ```bash - just test-slow - ``` - -=== "nox" - - ```bash - uvx nox -s test_slow - ``` - -=== "uv run" - - ```bash - uv run pytest -m "slow or integration" -v - ``` - -Run all tests: - -=== "just" - - ```bash - just test - ``` - -=== "nox" - - ```bash - uvx nox -s test - ``` - -=== "uv run" - - ```bash - uv run pytest -v - ``` - -### When to Mark Tests - -Mark your tests appropriately to maintain fast feedback: - -- Use `@pytest.mark.slow` for tests that take more than a few seconds -- Use `@pytest.mark.integration` for tests that run `copier.run_copy()` or execute commands in generated projects -- Tests without marks should be fast unit tests that only validate template structure and content - -Example: - -```python -import pytest - -@pytest.mark.integration -@pytest.mark.slow -def test_generated_project_builds(copie): - """Test that generated project can run nox sessions.""" - result = copie.copy() - subprocess.run(["uvx", "nox", "-s", "tests"], cwd=result.project_dir, check=True) -``` - -### CI Test Strategy - -The CI pipeline uses a two-tier testing strategy optimized for fast feedback: - -1. **Fast tests** (`test-fast` job): Runs on minimum and maximum Python versions (3.11, 3.14) only: - - **Draft PRs**: Ubuntu only (2 jobs) - Quick feedback in ~2-3 minutes - - **Ready PRs/Main**: All OS - Ubuntu, Windows, macOS (6 jobs) - Cross-platform validation - -2. **Full test suite** (`test-full` job): Runs all tests (fast + slow + integration) on Ubuntu across all Python versions (3.11-3.14) when the PR is not in draft mode or on the main branch (4 jobs). - -**Total CI jobs:** -- Draft PRs: 3 jobs (2 test + 1 lint) -- Ready PRs: 11 jobs (6 test-fast + 4 test-full + 1 lint) - -### Manual Testing with `just gen` - -The `just gen` command generates a temporary project from the template, runs a recipe inside it, and automatically cleans up afterwards. This is the fastest way to verify template changes produce a working project. - -```bash -# Build docs in a generated project (with examples, the default) -just gen build - -# Run tests in a generated project -just gen test - -# Run linters -just gen lint - -# Format and fix code -just gen fix - -# Generate without examples -just examples=false gen build -just examples=false gen test -``` - -The generated project is created in `.generated/` and removed automatically via a shell trap, even if the recipe fails. - -#### Available recipes - -Any recipe from the generated project's justfile can be passed to `just gen`: - -| Recipe | Description | -| --- | --- | -| `test` | Run tests and doctests | -| `test-fast` | Fast tests only (no slow/integration) | -| `test-cov` | Tests with coverage report | -| `test-docstrings` | Run docstring examples | -| `lint` | Run ruff, rumdl, and ty | -| `fix` | Auto-format via pre-commit | -| `build` | Build documentation | -| `build-fast` | Build docs without notebook export (with examples only) | -| `serve` | Serve docs locally at localhost:8080 | -| `link` | Check built docs for dead links | -| `all` | Run fix + test | - -## Code Quality - -Format and fix all issues: - -=== "just" - - ```bash - just fix - ``` - -=== "nox" - - ```bash - uvx nox -s fix - ``` - -=== "uv run" - - ```bash - uv run ruff format src tests - uv run ruff check src tests --fix - uv run ty check src - ``` - -Check code (fix + test): - -=== "just" - - ```bash - just all - ``` - -=== "uv run" - - ```bash - uvx pre-commit run --all-files && uv run pytest tests/ -n auto -v - ``` - -## Documentation - -Build documentation: - -=== "just" - - ```bash - just build - ``` - -=== "nox" - - ```bash - uvx nox -s build_docs - ``` - -=== "uv run" - - ```bash - uv run mkdocs build - ``` - -Serve documentation at localhost:8080: - -=== "just" - - ```bash - just serve - ``` - -=== "nox" - - ```bash - uvx nox -s serve_docs - ``` - -=== "uv run" - - ```bash - uv run mkdocs serve - ``` - -## Modifying the Template - -### Edit Template Files - -Template files are in the `template/` directory. Files ending with `.jinja` are rendered by Copier with variable substitution. - -### Edit Template Configuration - -Edit `copier.yml` to add or modify template prompts and variables. - -### Test Your Changes - -After making changes: - -1. Run `just test-fast` to test template generation -2. Run `just gen build` to verify the generated project builds docs -3. Run `just gen test` to verify tests pass in the generated project - -## Commit Message Format - -This project uses [Conventional Commits](https://www.conventionalcommits.org/) to automate changelog generation and releases. All commit messages must follow this format: - -```text -(): - -[optional body] - -[optional footer(s)] -``` - -### Commit Types - -- `feat:` - A new feature (triggers minor version bump) -- `fix:` - A bug fix (triggers patch version bump) -- `docs:` - Documentation changes -- `style:` - Code style changes (formatting, etc.) -- `refactor:` - Code refactoring -- `perf:` - Performance improvements -- `test:` - Adding or updating tests -- `chore:` - Maintenance tasks - -### Breaking Changes - -To indicate a breaking change (triggers major version bump): -- Add `!` after the type: `feat!: remove deprecated API` -- Or include `BREAKING CHANGE:` in the footer - -### Examples - -```bash -feat: add support for Python 3.13 -fix(tests): correct test fixture configuration -docs: update quickstart guide -feat!: remove support for Python 3.9 -``` - -The pre-commit hook will validate your commit messages automatically. - -## Release Process - -Releases are automated via GitHub Actions with a **manual approval gate** before PyPI publishing to ensure quality control. - -```mermaid -graph LR - A[Push Tag
v*.*.*] --> B[changelog.yml] - B --> C[Generate
CHANGELOG.md] - B --> D[Build Package
validation] - C --> E[Create PR] - E --> F[Review & Merge
PR] - F --> G[publish-release.yml] - G --> H[Create GitHub
Release] - H --> I{Manual
Approval} - I -->|Approve| J[Publish to PyPI] - style I fill:#ff9,stroke:#333,stroke-width:2px - style J fill:#9f9,stroke:#333,stroke-width:2px -``` - -### Initial Setup (One-time) - -Before you can create releases, you need to configure two things: - -#### 1. Create a Personal Access Token for Changelog Automation - -1. **Create a Fine-grained Personal Access Token**: - - Go to GitHub Settings → Developer settings → Personal access tokens → Fine-grained tokens - - Click "Generate new token" - - Configure: - - **Token name**: `CHANGELOG_AUTOMATION_TOKEN` - - **Expiration**: 90 days or longer - - **Repository access**: Only select repositories → Choose this repository - - **Permissions**: - - Contents: Read and write - - Pull requests: Read and write - -2. **Add token as repository secret**: - - Go to repository Settings → Secrets and variables → Actions - - Click "New repository secret" - - Name: `CHANGELOG_AUTOMATION_TOKEN` - - Value: Paste your generated token - -#### 2. Configure PyPI Environment with Required Reviewers - -To enable the manual approval gate before PyPI publishing: - -1. **Set up Trusted Publishing on PyPI** (if not already done): - - Go to your PyPI project → Manage → Publishing - - Add a new publisher with: - - **Owner**: stateful-y - - **Repository**: python-package-copier - - **Workflow**: `publish-release.yml` - - **Environment**: `pypi` - -2. **Configure environment protection in GitHub**: - - Go to repository Settings → Environments - - Click on the `pypi` environment (or create it if it doesn't exist) - - Enable "Required reviewers" - - Add maintainers as required reviewers - - Optionally set a wait timer for additional safety - -This ensures that no package is published to PyPI without explicit approval from a maintainer. - -### Creating a Release - -1. **Ensure all changes follow conventional commits** - The changelog is auto-generated from commit messages - -2. **Create and push a version tag**: - ```bash - git tag v0.2.0 -m "Release v0.2.0" - git push origin v0.2.0 - ``` - -3. **Automated changelog workflow** (`changelog.yml`): - - Generates the changelog using [git-cliff](https://git-cliff.org/) - - Creates a **Pull Request** with the updated `CHANGELOG.md` - - Builds the package distributions (wheels and sdist) for **immediate validation** - - Stores distributions as workflow artifacts (reused later to avoid rebuilding) - -4. **Review and merge the changelog PR**: - - Review the generated changelog - - Merge the PR to update the main branch - - The PR is automatically labeled with `changelog` and `automated` - -5. **Automated release workflow** (`publish-release.yml`): - - Creates a GitHub Release with auto-generated release notes - - Attaches distribution files to the release - - **Waits for manual approval** before proceeding to PyPI - -6. **Manual approval for PyPI publishing**: - - Designated reviewers receive a notification - - Review the GitHub Release to verify everything is correct - - Approve the deployment to publish to PyPI - - Package is published using Trusted Publishing (OIDC, no tokens needed) - -### Version Numbering - -This project follows [Semantic Versioning](https://semver.org/): -- **MAJOR** (1.0.0): Breaking changes -- **MINOR** (0.1.0): New features (backward compatible) -- **PATCH** (0.0.1): Bug fixes - -The version is tracked via Git tags and managed by `hatch-vcs`. - -### What Gets Into the Changelog - -Based on your commit types: -- `feat:` → **Added** section -- `fix:` → **Fixed** section -- `docs:` → **Documentation** section -- `perf:` → **Performance** section -- `refactor:` → **Refactored** section -- `style:` → **Styling** section -- `test:` → **Testing** section -- `chore:` → **Miscellaneous** section - -Commits that don't follow conventional format are excluded from the changelog. diff --git a/docs/pages/explanation/architecture.md b/docs/pages/explanation/architecture.md new file mode 100644 index 0000000..668fea6 --- /dev/null +++ b/docs/pages/explanation/architecture.md @@ -0,0 +1,84 @@ +# About the Architecture + +This page explains how python-package-copier is designed and how the template maps to generated projects. + +## How Template Generation Works + +Python-package-copier is a [Copier](https://copier.readthedocs.io/) template - a collection of Jinja2 files that Copier renders into a complete Python project based on user answers. + +```mermaid +graph LR + A[copier.yml
Variables & Prompts] --> C[Copier Engine] + B[template/
Jinja2 Source Files] --> C + C --> D[Generated Project
Ready to develop] +``` + +The `copier.yml` file defines the questions asked during generation (project name, Python version, etc.). The `template/` directory contains the source files - some are static (copied as-is) and some are `.jinja` files (rendered with variable substitution). + +### Conditional Content + +The template uses Copier's conditional directory and file naming to include or exclude content: + +- **Conditional directories**: `template/{% if include_examples %}examples{% endif %}/` - the entire directory is skipped when `include_examples=false` +- **Conditional files**: `template/docs/pages/{% if include_examples %}examples.md{% endif %}.jinja` - individual files can be conditional +- **Inline conditionals**: Jinja `{% if %}` blocks within `.jinja` files control which sections appear + +## src Layout + +Generated projects use the `src/` layout (`src//`): + +- Prevents accidental imports from the source directory during testing - forces installation, catching packaging errors early +- Matches [PyPA recommendations](https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/) for distributable packages +- Clean separation between source code, tests, and docs + +## hatchling + hatch-vcs + +The build system uses **hatchling** as the build backend and **hatch-vcs** for version management: + +- Lightweight and fast, with native `src/` layout support +- Version is derived automatically from Git tags - tagging `v1.2.3` sets the package version to `1.2.3` +- Zero version management overhead + +## nox + just (Two-Layer Commands) + +The template provides two command interfaces: + +| Layer | Tool | Purpose | When to Use | +|-------|------|---------|-------------| +| Outer | just | Convenience aliases for daily development | `just test`, `just fix`, `just serve` | +| Inner | nox | Multi-version testing and CI automation | `uvx nox -s test` (tests across Python 3.11–3.14) | + +The three layers compose: `just` calls `nox`, which uses `uv` internally for package installation. Just provides short aliases for the 90% case, while nox handles multi-version matrices and environment isolation. + +## Pre-commit Hooks + +The template configures pre-commit hooks that run locally before each commit: + +- Fast feedback - catches formatting and linting issues in seconds, not after a CI round-trip +- Every commit is clean, not just every PR +- Optional - CI still runs the same checks via `nox -s fix` as a safety net + +## The Testing Architecture + +### Two Levels of Testing + +The template tests operate at two levels: + +1. **Template tests** (this repo's `tests/`): Verify that Copier generates correct files with correct content. These are fast and don't run any code in the generated project. + +2. **Generated project tests** (via `just gen test`): Actually run nox sessions in a freshly generated project. These are slow but verify end-to-end correctness. + +### Test Markers + +The `@pytest.mark.slow` and `@pytest.mark.integration` markers enable a two-tier CI strategy: + +- **Draft PRs**: Only fast tests run (2–3 minutes), giving quick feedback during development +- **Ready PRs**: Full test suite runs (fast + slow + integration across all OS and Python versions) + +This optimizes for both developer experience (fast iteration) and release quality (thorough validation). + +## Connections + +- [Release Process](release-process.md) - how the multi-step release pipeline works +- [Project Structure](../reference/project-structure.md) - what files the template generates +- [Commands](../reference/commands.md) - the just/nox/uv command hierarchy diff --git a/docs/pages/explanation/release-process.md b/docs/pages/explanation/release-process.md new file mode 100644 index 0000000..78a1df9 --- /dev/null +++ b/docs/pages/explanation/release-process.md @@ -0,0 +1,71 @@ +# About the Release Process + +This page explains how the automated release pipeline works. + +## Overview + +The release pipeline converts a Git tag into a published PyPI package through a series of automated steps with a human checkpoint: + +```mermaid +graph LR + A[Push Tag
v*.*.*] --> B[changelog.yml] + B --> C[Generate
CHANGELOG.md] + B --> D[Build Package
validation] + C --> E[Create PR] + E --> F[Review & Merge
PR] + F --> G[publish-release.yml] + G --> H[Create GitHub
Release] + H --> I{Manual
Approval} + I -->|Approve| J[Publish to PyPI] + style I fill:#ff9,stroke:#333,stroke-width:2px + style J fill:#9f9,stroke:#333,stroke-width:2px +``` + +## Two Separate Workflows + +The release is split into two workflows: + +1. **changelog.yml** - Triggered by tag push, generates changelog, builds packages, creates a PR +2. **publish-release.yml** - Triggered by PR merge, creates GitHub Release, publishes to PyPI + +Each workflow has a single responsibility - preparation vs. publication. The PR between them creates a natural review point where maintainers can verify the changelog and build before anything is published. + +## Manual Approval Before PyPI + +Publishing to PyPI is irreversible. The manual approval gate (via GitHub [environment protection rules](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment)) provides human verification, an emergency brake for bad releases, and a clear audit trail. + +## Trusted Publishing (OIDC) + +The template uses PyPI's [Trusted Publishing](https://docs.pypi.org/trusted-publishers/): + +- No stored secrets - authentication uses short-lived OIDC tokens generated by GitHub Actions +- Workflow-scoped - only `publish-release.yml` in the specific repository can publish +- Environment-scoped - the OIDC token is only available after manual approval + +## Changelog Generation + +The changelog is generated automatically from [Conventional Commits](https://www.conventionalcommits.org/) using git-cliff - `feat:` commits appear under **Added**, `fix:` under **Fixed**, breaking changes are highlighted prominently. The template enforces conventional commits via pre-commit hooks and PR title validation. + +## Version Numbering + +The template follows [Semantic Versioning](https://semver.org/): + +- **MAJOR** (1.0.0): Breaking changes (indicated by `!` or `BREAKING CHANGE:`) +- **MINOR** (0.1.0): New features (`feat:` commits) +- **PATCH** (0.0.1): Bug fixes (`fix:` commits) + +The version is determined by the Git tag - there is no version file to manually edit. The `hatch-vcs` build plugin reads the tag and sets the package version accordingly. + +## The Complete Flow in Practice + +1. Developer pushes a version tag: `git tag v0.2.0 -m "Release v0.2.0" && git push origin v0.2.0` +2. `changelog.yml` generates the changelog, builds the package, creates a PR +3. Maintainer reviews and merges the PR +4. `publish-release.yml` creates a GitHub Release with artifacts +5. Designated reviewer receives a notification and approves the PyPI deployment +6. Package is published to PyPI via Trusted Publishing + +## Connections + +- [How to Set Up CI/CD Services](../how-to/setup-cicd.md) - step-by-step setup instructions +- [GitHub Workflows](../reference/github-workflows.md) - workflow technical reference diff --git a/docs/pages/how-to/add-dependencies.md b/docs/pages/how-to/add-dependencies.md new file mode 100644 index 0000000..e8d4974 --- /dev/null +++ b/docs/pages/how-to/add-dependencies.md @@ -0,0 +1,84 @@ +# How to Add Dependencies + +This guide shows you how to add runtime and development dependencies to a project generated from the template. + +## Prerequisites + +- A generated project with [uv](https://docs.astral.sh/uv/) installed +- Familiarity with Python packaging basics + +## Add a Runtime Dependency + +Runtime dependencies are packages your users need when they install your package: + +```bash +uv add requests +``` + +This updates `pyproject.toml` under `[project.dependencies]` and refreshes the lock file. + +## Add a Development Dependency + +Development dependencies are organized into groups. Add to the appropriate group: + +```bash +# Add to the tests group +uv add --group tests hypothesis + +# Add to the docs group +uv add --group docs mkdocs-glightbox + +# Add to the lint group +uv add --group lint bandit +``` + +After adding, sync your environment: + +```bash +uv sync --group dev +``` + +## Dependency Groups + +The template organizes development dependencies into these groups: + +| Group | Purpose | Contents | +|-------|---------|----------| +| `dev` | Meta-group - includes all others | References tests, lint, docs, fix, examples | +| `tests` | Testing tools | pytest, pytest-cov, pytest-mock, pytest-xdist, covdefaults, hypothesis | +| `lint` | Code quality | ruff, ty | +| `docs` | Documentation | mkdocs, mkdocs-material, mkdocstrings, pymdown-extensions | +| `fix` | Auto-formatting | pre-commit-uv | +| `examples` | Interactive notebooks | marimo (if `include_examples=true`) | + +## Add an Optional Dependency + +For features users can opt into: + +1. Edit `pyproject.toml` to define the optional group: + + ```toml + [project.optional-dependencies] + pandas = ["pandas>=2.0"] + ``` + +2. Users install with: + + ```bash + pip install my-package[pandas] + ``` + +## Remove a Dependency + +```bash +# Runtime dependency +uv remove requests + +# Development dependency from a specific group +uv remove --group tests hypothesis +``` + +## See Also + +- [Configuration Files](../reference/configuration.md) - `pyproject.toml` structure and tool settings +- [How to Customize Your Project](customize-template.md) - other project customizations diff --git a/docs/pages/how-to/contribute.md b/docs/pages/how-to/contribute.md new file mode 100644 index 0000000..393d683 --- /dev/null +++ b/docs/pages/how-to/contribute.md @@ -0,0 +1,218 @@ +# How to Contribute to the Template + +We welcome contributions to python-package-copier! This guide helps you get set up and submit your first pull request. + +## Types of Contributions + +Not sure where to start? Pick a path: + +- **Report a bug**: [Open an issue](https://github.com/stateful-y/python-package-copier/issues/new) with steps to reproduce, expected behavior, and your environment (Python, uv, copier versions) +- **Fix a bug**: Find an open issue, comment that you're working on it, then follow the development workflow below +- **Add a template feature**: Update `copier.yml` + `template/` files + tests - see [Modifying the Template](#modifying-the-template) +- **Improve documentation**: Edit files in `docs/` and run `just serve` to preview + +## Repository Structure + +!!! important "Scope confusion is the #1 contributor issue" + This repository has three distinct layers. Understanding them prevents most mistakes. + +```text +python-package-copier/ +├── copier.yml # Template configuration (prompts/variables) +├── template/ # Jinja2 source files → what users GET +│ ├── pyproject.toml.jinja +│ ├── noxfile.py.jinja +│ └── ... +├── tests/ # Tests for the template itself +├── docs/ # Documentation for this template repo +├── noxfile.py # Nox config for testing the template +└── pyproject.toml # Dependencies for template development +``` + +| Layer | Path | Purpose | +|-------|------|---------| +| **Root project** | `noxfile.py`, `pyproject.toml`, `tests/`, `docs/` | Infrastructure for developing and testing the template | +| **Template source** | `template/` | Jinja2 files rendered by Copier into generated projects | +| **Generated project** | *(created by `copier copy`)* | The user's actual Python package - not in this repo | + +Changes to files in `template/` affect what users get. Changes to root files affect how the template is developed and tested. + +## Setup + +```bash +git clone https://github.com/stateful-y/python-package-copier.git +cd python-package-copier + +# Install dependencies +uv sync --group test --group docs + +# Install pre-commit hooks (optional but recommended) +uv run pre-commit install +``` + +## Test Template Changes + +### Test Categories + +- **Fast tests**: Validate template generation without running subprocesses +- **Slow tests**: Tests marked with `@pytest.mark.slow` that take longer +- **Integration tests**: Tests marked with `@pytest.mark.integration` that use `copier.run_copy()` + +### Test Commands + +=== "just" + + ```bash + just test-fast # Fast tests (recommended during development) + just test-slow # Slow and integration tests + just test # All tests + ``` + +=== "nox" + + ```bash + uvx nox -s test_fast # Fast tests across versions + uvx nox -s test_slow # Slow tests across versions + uvx nox -s test # All tests + ``` + +=== "uv run" + + ```bash + uv run pytest -m "not slow and not integration" -v # Fast tests + uv run pytest -m "slow or integration" -v # Slow tests + uv run pytest -v # All tests + ``` + +### When to Mark Tests + +- Use `@pytest.mark.slow` for tests that take more than a few seconds +- Use `@pytest.mark.integration` for tests that run `copier.run_copy()` or execute commands in generated projects +- Tests without marks should be fast unit tests that only validate template structure and content + +### Manual Testing with `just gen` + +`just gen` generates a temporary project, runs a recipe inside it, and cleans up automatically: + +```bash +just gen build # Build docs in a generated project +just gen test # Run tests in a generated project +just gen lint # Run linters +just gen fix # Format and fix code +just examples=false gen build # Generate without examples +``` + +### CI Test Strategy + +| PR State | Fast Tests | Full Tests | Lint | Total Jobs | +|----------|-----------|------------|------|------------| +| Draft | Ubuntu only (2 jobs) | - | 1 job | 3 | +| Ready | All OS (6 jobs) | All Python versions (4 jobs) | 1 job | 11 | + +## Modifying the Template + +### Edit Template Files + +Template files are in `template/`. Files ending in `.jinja` are rendered by Copier with variable substitution. + +### Edit Template Configuration + +Edit `copier.yml` to add or modify template prompts and variables. + +### Test Your Changes + +After making changes: + +1. Run `just test-fast` to test template generation +2. Run `just gen build` to verify the generated project builds docs +3. Run `just gen test` to verify tests pass in the generated project + +## Code Quality + +=== "just" + + ```bash + just fix # Format and fix code + just all # Fix + test + ``` + +=== "nox" + + ```bash + uvx nox -s fix + ``` + +=== "uv run" + + ```bash + uvx pre-commit run --all-files --show-diff-on-failure + ``` + +## Documentation + +=== "just" + + ```bash + just build # Build documentation + just serve # Preview at localhost:8080 + ``` + +=== "nox" + + ```bash + uvx nox -s build_docs + uvx nox -s serve_docs + ``` + +## Commit Message Format + +This project uses [Conventional Commits](https://www.conventionalcommits.org/). All commit messages must follow: + +```text +(): +``` + +Types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore` + +Breaking changes: Add `!` after the type (`feat!: remove deprecated API`) or include `BREAKING CHANGE:` in the footer. + +The pre-commit hook validates your commit messages automatically. + +## Before You Open a PR + +- [ ] Run `just test-fast` - all fast tests pass +- [ ] Run `just fix` - code is formatted and linted +- [ ] Write or update tests for your changes +- [ ] If you changed docs, run `just serve` and verify they render +- [ ] Use conventional commit messages +- [ ] If adding a template feature, update `copier.yml` and add a test in `tests/` + +## Release Process + +!!! note "Maintainers only" + Releases are handled by project maintainers via git tags. Contributors do not need to manage releases. + +Maintainers: see [About the Release Process](../explanation/release-process.md) for the full workflow. + +## Troubleshooting + +**Problem: `uvx nox` not found** +: Install uv first: `curl -LsSf https://astral.sh/uv/install.sh | sh`. Nox is run via `uvx`, not installed globally. + +**Problem: Pre-commit fails on first run** +: Run `uv sync --group test` first to install all dependencies, then `uv run pre-commit install`. + +**Problem: Tests pass locally but fail in CI** +: Check the Python version matrix. CI tests across 3.11–3.14 and multiple operating systems. Your local Python may differ. + +**Problem: `copier copy` fails during integration tests** +: Ensure you have a recent copier version: `uvx copier --version`. The template requires copier 9+. + +**Problem: `just gen` fails** +: Check that `uv` and `copier` are installed and available in your PATH. Run `just gen test` with `--verbose` for more details. + +## See Also + +- [Commands](../reference/commands.md) - full command reference +- [Template Variables](../reference/template-variables.md) - what each variable controls +- [Architecture Overview](../explanation/architecture.md) - understanding the template design diff --git a/docs/pages/how-to/customize-template.md b/docs/pages/how-to/customize-template.md new file mode 100644 index 0000000..4628472 --- /dev/null +++ b/docs/pages/how-to/customize-template.md @@ -0,0 +1,95 @@ +# How to Customize Your Project + +This guide shows you how to modify common settings in a project generated from the template. These changes are safe to make and will be preserved when you [update from the template](update-template.md). + +## Prerequisites + +- [uv](https://docs.astral.sh/uv/) installed +- A project generated with `uvx copier copy gh:stateful-y/python-package-copier my-package` + +## Customize Ruff Rules + +Edit `pyproject.toml` to adjust linting and formatting: + +```toml +[tool.ruff] +line-length = 88 # Change from default 120 + +[tool.ruff.lint] +select = ["E", "W", "F", "I", "B", "C4", "UP", "ARG", "SIM", "PL", "T201"] +ignore = ["PLR0913"] # Allow many arguments +``` + +Run `just fix` to apply the new rules. + +## Adjust Coverage Thresholds + +The default coverage threshold is intentionally permissive (`fail_under = 1`). To increase it: + +```toml +[tool.coverage.report] +fail_under = 80 # Require 80% coverage +``` + +## Customize Pre-commit Hooks + +Edit `.pre-commit-config.yaml` to add or remove hooks. For example, to add a security scanner: + +```yaml +- repo: https://github.com/PyCQA/bandit + rev: 1.8.3 + hooks: + - id: bandit + args: ["-r", "src/"] +``` + +After editing, update hooks and run them: + +```bash +uv run pre-commit autoupdate +uv run pre-commit run --all-files +``` + +## Customize the Docstring Coverage Threshold + +The default requires 75% docstring coverage. To change it: + +```toml +[tool.interrogate] +fail-under = 90 # Require 90% docstring coverage +``` + +## Add Custom Nox Sessions + +Edit `noxfile.py` to add project-specific automation sessions. For example, a benchmarking session: + +```python +@nox.session(python=PYTHON_VERSIONS[0]) +def benchmark(session: nox.Session) -> None: + """Run performance benchmarks.""" + session.install(".[tests]", "pytest-benchmark") + session.run("pytest", "benchmarks/", "--benchmark-only") +``` + +## Customize Documentation Theme + +Edit `mkdocs.yml` to change the theme colors, logo, or features: + +```yaml +theme: + palette: + - scheme: default + primary: blue # Change color + accent: amber +``` + +## Common Variations + +- **Switching build backend**: Possible but requires updating `pyproject.toml` `[build-system]` and removing hatch-vcs config +- **Adding a CLI**: Add an entry point in `pyproject.toml` `[project.scripts]` and create the CLI module + +## See Also + +- [Template Variables](../reference/template-variables.md) - what each variable controls +- [Configuration Files](../reference/configuration.md) - full configuration reference +- [How to Add Dependencies](add-dependencies.md) - managing project dependencies diff --git a/docs/pages/how-to/setup-cicd.md b/docs/pages/how-to/setup-cicd.md new file mode 100644 index 0000000..df73469 --- /dev/null +++ b/docs/pages/how-to/setup-cicd.md @@ -0,0 +1,93 @@ +# How to Set Up CI/CD Services + +This guide walks you through configuring the external services that power your generated project's CI/CD pipeline. Complete these steps after pushing your project to GitHub. + +## Prerequisites + +- A project generated with `include_actions=true` (the default) +- The project pushed to a GitHub repository + +## Codecov (Coverage Reporting) + +Codecov aggregates test coverage reports from CI runs. + +1. Sign up at [codecov.io](https://codecov.io/) with your GitHub account +2. Add your repository from the Codecov dashboard +3. Go to **Settings** and copy the upload token +4. In your GitHub repository: **Settings → Secrets and variables → Actions → New repository secret** +5. Add `CODECOV_TOKEN` with your token value + +This token is used by `tests.yml` (on every push/PR) and `nightly.yml` (daily testing). + +## PyPI Publishing (Automated Releases) + +The release pipeline uses **Trusted Publishing** (OIDC) - no API tokens are stored in your repository. + +### 1. Configure Trusted Publishing on PyPI + +1. Create an account at [pypi.org](https://pypi.org/account/register/) +2. Publish your first release manually, or create the project on PyPI +3. Go to your project → **Manage → Publishing** +4. Add a new publisher: + - **Owner**: Your GitHub username/organization + - **Repository**: Your repository name + - **Workflow**: `publish-release.yml` + - **Environment**: `pypi` + +### 2. Create a Personal Access Token for Changelog Automation + +The changelog workflow needs a token to create PRs: + +1. Go to **GitHub Settings → Developer settings → Personal access tokens → Fine-grained tokens** +2. Click **Generate new token** and configure: + - **Token name**: `CHANGELOG_AUTOMATION_TOKEN` + - **Expiration**: 90 days or longer + - **Repository access**: Only select repositories → choose your repository + - **Permissions**: Contents (Read/Write), Pull requests (Read/Write) +3. In your repository: **Settings → Secrets and variables → Actions → New repository secret** +4. Add `CHANGELOG_AUTOMATION_TOKEN` with the token value + +### 3. Configure the PyPI Environment for Manual Approval + +This ensures releases require explicit maintainer approval before publishing: + +1. Go to repository **Settings → Environments** +2. Create or select the `pypi` environment +3. Enable **Required reviewers** under *Deployment protection rules* +4. Add one or more maintainers as required reviewers +5. (Optional) Enable a **Wait timer** for additional safety + +!!! note + Environment protection rules require **public repositories** or **GitHub Pro/Team/Enterprise** plans. + +### Verify the Release Pipeline + +Push a version tag to trigger the full flow: + +```bash +git tag v0.1.0 -m "Release v0.1.0" +git push origin v0.1.0 +``` + +This triggers: changelog generation → PR creation → (after merge) GitHub Release → **manual approval** → PyPI publish. + +See [GitHub Workflows](../reference/github-workflows.md) for the full workflow reference and [About the Release Process](../explanation/release-process.md) for design rationale. + +## ReadTheDocs (Documentation) + +1. Sign up at [readthedocs.org](https://readthedocs.org/accounts/signup/) with GitHub +2. Click **Import a Project** +3. Select your repository +4. Click **Build version** - your docs are live + +Documentation builds automatically on every push to main. The generated `.readthedocs.yml` handles all build configuration. + +## Summary + +| Service | Secret/Config | Used By | +|---------|--------------|---------| +| Codecov | `CODECOV_TOKEN` secret | tests.yml, nightly.yml | +| PyPI | Trusted Publishing (no secret) | publish-release.yml | +| Changelog | `CHANGELOG_AUTOMATION_TOKEN` secret | changelog.yml | +| Manual approval | `pypi` environment with reviewers | publish-release.yml | +| ReadTheDocs | Repository import (no secret) | Automatic on push | diff --git a/docs/pages/how-to/update-template.md b/docs/pages/how-to/update-template.md new file mode 100644 index 0000000..eba6538 --- /dev/null +++ b/docs/pages/how-to/update-template.md @@ -0,0 +1,122 @@ +# How to Update from Template + +This guide shows you how to pull in the latest template improvements to an existing project generated from python-package-copier. + +## Prerequisites + +- A project previously generated with `uvx copier copy gh:stateful-y/python-package-copier` +- The project must contain a `.copier-answers.yml` file (generated automatically) +- [copier](https://copier.readthedocs.io/) installed (`uvx copier` works) + +## Check Your Current Template Version + +```bash +cat .copier-answers.yml +``` + +The `_commit` field shows the template commit your project was generated from. + +## Update to Latest Template + +Run from your project's root directory: + +```bash +copier update --trust +``` + +Copier will: + +1. Pull the latest template from `gh:stateful-y/python-package-copier` +2. Show you a diff of changes +3. Prompt for any new configuration questions added since your last update +4. Apply updates while preserving your modifications + +## Update to a Specific Version + +Pin to a specific template version: + +```bash +copier update --trust --vcs-ref=v1.2.0 +``` + +Or update to a specific commit: + +```bash +copier update --trust --vcs-ref=abc123 +``` + +## Handle Conflicts + +If you've modified files that the template also changed, Copier will flag conflicts. + +### Inline Conflict Markers (Default) + +```bash +copier update --trust --conflict inline +``` + +This adds Git-style conflict markers in the affected files: + +```text +<<<<<<< before updating +your local changes +======= +template changes +>>>>>>> after updating +``` + +Resolve them manually, then commit. + +### Reject Files + +```bash +copier update --trust --conflict rej +``` + +This creates `.rej` files alongside conflicting files. Review each `.rej` file, apply the changes you want, and delete the `.rej` files. + +## What Gets Updated + +Template updates can include: + +- **CI workflow improvements** - new testing strategies, updated actions versions +- **Tool configuration** - ruff rules, coverage settings, pre-commit hooks +- **Documentation scaffolding** - new doc pages, improved templates +- **Build system** - dependency group changes, hatchling config + +## What Is Preserved + +Copier respects your local changes. Files you've customized are merged, not overwritten. Specifically: + +- Your source code in `src/` is never touched by template updates +- Your test files in `tests/` are preserved +- Custom content you added to documentation is preserved +- Dependencies you added to `pyproject.toml` are preserved + +## AI-Assisted Updates + +If you use GitHub Copilot or a similar AI coding assistant, you can ask it to handle the update for you. The template ships with an **`update-from-template` skill** that automates the full workflow: + +1. Pre-flight checks (clean working tree, current template version) +2. Detecting which files you've customized vs. kept as-is +3. Running `copier update` on a dedicated branch +4. Resolving conflicts using a 3-tier file classification (template-managed, merge-required, local-owned) +5. Verifying tests and linting pass after the update + +To trigger it, ask your AI assistant: *"update from template"* or *"sync template changes"* from within your generated project. + +## Troubleshooting + +**Problem: `copier update` fails with "not a copier project"** +: Ensure `.copier-answers.yml` exists in the project root. If it was accidentally deleted, you cannot update - you would need to regenerate the project. + +**Problem: Too many conflicts after a long gap** +: Update incrementally by specifying intermediate versions with `--vcs-ref`. + +**Problem: New template variables have no answers** +: Copier will prompt you for any new variables interactively. To set defaults non-interactively, use `--defaults`. + +## See Also + +- [Template Variables](../reference/template-variables.md) - understand what each variable controls +- [Project Structure](../reference/project-structure.md) - what files the template generates diff --git a/docs/pages/quickstart.md b/docs/pages/quickstart.md index 37dd399..de7deea 100644 --- a/docs/pages/quickstart.md +++ b/docs/pages/quickstart.md @@ -32,7 +32,7 @@ Answer the prompts about your project. You'll be asked for: - `include_actions`: Include GitHub Actions CI/CD workflows? (default: true) - `include_examples`: Include interactive [marimo](https://marimo.io/) notebooks in `examples/`? (default: true) -See [Template Variables](reference.md#template-variables) in the Reference Guide for detailed descriptions. +See [Template Variables](reference/template-variables.md) in the Reference for detailed descriptions. ## Initialize Your Project @@ -121,7 +121,7 @@ git push origin v0.1.0 This triggers: changelog generation → PR creation → (after merge) GitHub release → **manual approval** → PyPI publish. -See the [Contributing Guide](contributing.md) for detailed release process documentation. +See the [Contributing Guide](how-to/contribute.md) for detailed release process documentation. ### ReadTheDocs (Documentation) @@ -135,6 +135,9 @@ Documentation builds automatically on every push to main. ## Next Steps -- **[Reference Guide](reference.md)** - Full command reference, CI/CD setup, testing guide -- **[Contributing](contributing.md)** - For template developers +- **[Set Up CI/CD Services](how-to/setup-cicd.md)** - Configure Codecov, PyPI publishing, and ReadTheDocs +- **[Customize Your Project](how-to/customize-template.md)** - Adjust ruff rules, coverage thresholds, and more +- **[Add Dependencies](how-to/add-dependencies.md)** - Add runtime and development dependencies +- **[Reference: Commands](reference/commands.md)** - Full command reference for just, nox, and uv +- **[Contributing](how-to/contribute.md)** - Help improve the template - **[GitHub Template](https://github.com/stateful-y/python-package-copier)** - Source code and issues diff --git a/docs/pages/reference.md b/docs/pages/reference.md deleted file mode 100644 index d63c6e1..0000000 --- a/docs/pages/reference.md +++ /dev/null @@ -1,381 +0,0 @@ -# Reference - -## Technology Stack - -| Category | Tool | Purpose | -|----------|------|---------| -| **Build** | hatchling | Modern build backend | -| **Build** | hatch-vcs | Git-based versioning | -| **Package Manager** | uv | Fast dependency management | -| **Formatter** | ruff | Code formatting | -| **Linter** | ruff | Code linting | -| **Type Checker** | ty | Static type checking | -| **Test Framework** | pytest | Unit testing | -| **Docstring Testing** | pytest-doctest | Test code examples in docstrings | -| **Coverage** | pytest-cov | Code coverage | -| **Test Automation** | nox | Multi-environment testing | -| **Pre-commit** | pre-commit | Git hooks | -| **Documentation** | MkDocs | Static site generator | -| **Doc Theme** | Material | Beautiful theme | -| **API Docs** | mkdocstrings | Docstring extraction | -| **Task Runner** | just | Command automation | -| **CI/CD** | GitHub Actions | Automation platform | -| **Coverage Reporting** | Codecov | Test coverage tracking | -| **Dependency Updates** | Dependabot | Automated updates | -| **Changelog** | git-cliff | Automated changelog generation | -| **Commit Convention** | commitizen | Conventional commits enforcement | - -## Template Variables - -When creating a new project with `uvx copier copy gh:stateful-y/python-package-copier my-package`, you'll be prompted for these variables: - -| Variable | Type | Default | Description | -|----------|------|---------|-------------| -| `project_name` | str | *required* | Human-readable project name (e.g., "My Awesome Package") | -| `package_name` | str | *derived* | Python import name with underscores (e.g., "my_awesome_package")
Auto-generated from `project_name` | -| `project_slug` | str | *derived* | Repository/URL name with hyphens (e.g., "my-awesome-package")
Auto-generated from `project_name` | -| `version` | str | `0.1.0` | Initial package version following [Semantic Versioning](https://semver.org/) | -| `description` | str | `""` | One-line project description for README and package metadata | -| `author_name` | str | *required* | Author or maintainer name | -| `author_email` | str | *required* | Author or maintainer email | -| `github_username` | str | `""` | GitHub username or organization (used in URLs and badges) | -| `license` | str | `MIT` | Project license. Choices:
• Apache-2.0
• MIT
• BSD-3-Clause
• GPL-3.0
• Proprietary | -| `min_python_version` | str | `3.11` | Minimum Python version. Choices: 3.11, 3.12, 3.13, 3.14 | -| `max_python_version` | str | `3.14` | Maximum Python version. Choices: 3.11, 3.12, 3.13, 3.14
Must be ≥ `min_python_version` | -| `include_actions` | bool | `true` | Include GitHub Actions CI/CD workflows (tests, changelog, releases) | -| `include_examples` | bool | `true` | Include `examples/` directory with [marimo](https://marimo.io/) interactive notebooks | - -**Note**: Derived variables (`package_name`, `project_slug`) are auto-generated but can be overridden during setup. - -**Example**: -- `project_name`: "My Data Tool" -- `package_name`: "my_data_tool" (underscores for Python imports) -- `project_slug`: "my-data-tool" (hyphens for repository names and URLs) - -## Generated Project Structure - -```text -my-package/ -├── .github/ -│ ├── ISSUE_TEMPLATE/ -│ │ ├── bug_report.yml -│ │ ├── feature_request.yml -│ │ └── config.yml -│ ├── workflows/ -│ │ ├── tests.yml -│ │ ├── pr-title.yml -│ │ ├── changelog.yml -│ │ ├── publish-release.yml -│ │ └── nightly.yml -│ ├── dependabot.yml -│ └── pull_request_template.md -├── docs/ -│ ├── index.md -│ ├── getting-started.md -│ ├── user-guide.md -│ ├── api-reference.md -│ └── contributing.md -├── src/ -│ └── package_name/ -│ ├── __init__.py -│ ├── example.py -│ └── py.typed -├── tests/ -│ ├── conftest.py -│ └── test_example.py -├── .editorconfig -├── .gitignore -├── .pre-commit-config.yaml -├── .readthedocs.yml -├── CHANGELOG.md -├── CONTRIBUTING.md -├── justfile -├── LICENSE -├── mkdocs.yml -├── noxfile.py -├── pyproject.toml -└── README.md -``` - -## GitHub Actions Workflows - -### Release Workflow - -The automated release process follows this flow with a **manual approval gate** before PyPI publishing: - -```mermaid -graph LR - A[Push Tag
v*.*.*] --> B[changelog.yml] - B --> C[Generate
CHANGELOG.md] - B --> D[Build Package
validation] - C --> E[Create PR] - E --> F[Review & Merge
PR] - F --> G[publish-release.yml] - G --> H[Create GitHub
Release] - H --> I{Manual
Approval} - I -->|Approve| J[Publish to PyPI] - style I fill:#ff9,stroke:#333,stroke-width:2px - style J fill:#9f9,stroke:#333,stroke-width:2px -``` - -**Steps**: -1. Developer pushes version tag (e.g., `git tag v0.2.0 -m "Release v0.2.0" && git push origin v0.2.0`) -2. `changelog.yml` triggers, generates changelog, builds package, creates PR with changelog -3. Developer reviews and merges the changelog PR -4. `publish-release.yml` triggers on PR merge, creates GitHub Release with artifacts -5. **Manual approval required** - designated reviewers approve PyPI deployment -6. Package is published to PyPI using Trusted Publishing (OIDC) - -**Required secrets**: `CHANGELOG_AUTOMATION_TOKEN`, `CODECOV_TOKEN` - -**Required environment protection**: `pypi` environment with required reviewers configured - -#### Configuring Manual Approval for PyPI - -To enable the manual approval gate before PyPI publishing, configure GitHub environment protection rules: - -1. Navigate to repository **Settings → Environments** -2. Create or select the `pypi` environment -3. Enable **Required reviewers** under *Deployment protection rules* -4. Add one or more reviewers who must approve before PyPI publication -5. (Optional) Enable **Wait timer** to delay deployment after approval - -When a release is ready: -- The workflow will pause at the "Wait for approval" step -- Designated reviewers receive a notification -- Reviewers can inspect the GitHub Release and artifacts before approving -- Once approved, the package is automatically published to PyPI - -**Note**: Environment protection rules require **public repositories** or **GitHub Pro/Team/Enterprise** plans. - -### tests.yml - Continuous Integration - -Runs on every push and pull request: -- Tests across multiple Python versions (configurable via `min_python_version` and `max_python_version` template variables, defaults to 3.11-3.14) -- Tests on Ubuntu, Windows, and macOS -- Matrix of 15 combinations -- **Uploads coverage to Codecov** (requires `CODECOV_TOKEN` secret) -- **Uploads test results to Codecov** - -### pr-title.yml - Pull Request Title Validation - -Runs on pull requests to main: -- Validates PR title follows [Conventional Commits](https://www.conventionalcommits.org/) format -- Required types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert` -- Ensures consistency with changelog generation (git-cliff) -- Helps maintain clean commit history - -### changelog.yml - Automated Changelog and Build - -Triggers on version tags (`v*.*.*`): -- Generates changelog from conventional commits using git-cliff -- Creates a **Pull Request** with updated `CHANGELOG.md` -- Runs pre-commit hooks on generated changelog -- Builds and validates package distributions for **immediate validation** -- Stores distributions as workflow artifacts for reuse (avoiding rebuilds) -- **Requires** `CHANGELOG_AUTOMATION_TOKEN` secret for PR creation - -### publish-release.yml - GitHub Releases and PyPI Publishing - -Triggers when changelog PR is merged: -- Detects merged PRs with the `changelog` label -- Extracts version from PR title -- Downloads build artifacts from changelog workflow -- Creates a **GitHub Release** with: - - Release notes extracted from `CHANGELOG.md` - - Package distributions attached (wheel + sdist) - - Automatic tagging -- **Publishes to PyPI with manual approval**: - - Waits for designated reviewers to approve deployment - - Uses Trusted Publishing (OIDC) for secure authentication - - Requires `pypi` environment with required reviewers configured - -**Complete release flow**: Tag push → Changelog + Build → PR creation → Review & Merge → GitHub Release → **Manual Approval** → PyPI publish - -### nightly.yml - Proactive Monitoring - -Runs daily on schedule: -- Tests against latest dependencies -- **Uploads coverage to Codecov** (requires `CODECOV_TOKEN` secret) -- Creates GitHub issue on failure - -## Key Configuration Files - -### pyproject.toml - -Central configuration containing: -- Project metadata (name, version, description) -- Dependencies and dependency groups -- Build system configuration (hatchling + hatch-vcs) -- Tool configurations (ruff, pytest, coverage) - -### noxfile.py - -Task automation sessions: -- `test` - Run tests on Python 3.11-3.14 -- `test_fast` - Run fast tests only (excludes slow and integration) -- `test_slow` - Run slow and integration tests only -- `test_coverage` - Run tests with coverage -- `doctest` - Run docstring examples -- `fix` - Auto-format, fix linting issues, and type check (via pre-commit) -- `lint` - Check code quality (legacy, use `fix` instead) -- `build_docs` - Build documentation -- `serve_docs` - Serve docs at localhost:8080 - -## Command Hierarchy - -The template provides three ways to run common tasks, organized by use case: - -### Run Tests - -=== "just" - - ```bash - just test # Run all tests - just test-fast # Fast tests only - just test-slow # Slow and integration tests - ``` - -=== "nox" - - ```bash - uvx nox -s test # Test on Python 3.11-3.14 - uvx nox -s test_fast # Fast tests across versions - uvx nox -s test_slow # Slow tests across versions - ``` - -=== "uv run" - - ```bash - uv run pytest -v # Run all tests with verbosity - uv run pytest -m "not slow and not integration" # Fast tests only - uv run pytest -k test_specific # Run specific test - ``` - -### Format and Fix Code - -=== "just" - - ```bash - just fix # Format and fix code - just all # Fix + test - ``` - -=== "nox" - - ```bash - uvx nox -s fix # Format and fix (used in CI) - ``` - -=== "uv run" - - ```bash - uvx pre-commit run --all-files --show-diff-on-failure - ``` - -### Build Documentation - -=== "just" - - ```bash - just build # Build documentation - just serve # Build and preview at localhost:8080 - ``` - -=== "nox" - - ```bash - uvx nox -s build_docs # Build documentation - uvx nox -s serve_docs # Build and preview at localhost:8080 - ``` - -=== "uv run" - - ```bash - uv run mkdocs build --clean # Build documentation - uv run mkdocs serve -a localhost:8080 # Preview at localhost:8080 - ``` - -**Use Case Summary**: -- **just**: Convenience for everyday development (recommended) -- **nox**: Multi-version testing and CI/CD -- **uv run**: Direct tool control when specific options are needed - -**CI/CD Note**: GitHub Actions workflows use `uv tool install nox` followed by `nox` commands (not `uvx nox`) to leverage build caching and faster execution. - -### mkdocs.yml - -Documentation configuration: -- Material theme -- Search functionality -- API documentation via mkdocstrings - -### .pre-commit-config.yaml - -Pre-commit hooks: -- Ruff formatter and linter -- Type checking with ty -- YAML/TOML validation -- Docstring coverage checks -- Trailing whitespace and EOF fixes - -### .readthedocs.yml - -ReadTheDocs configuration: -- Automatic documentation builds -- Version management -- uv for fast installs - -## Updating Projects Created from This Template - -Projects generated from this template include a `.copier-answers.yml` file that tracks the template version and source. This enables you to pull in template updates as they are released. - -### Update Command - -To update your generated project with the latest template changes: - -```bash -copier update --trust -``` - -Run this from your project's root directory. - -### What Gets Updated - -Copier will: -1. Pull the latest template changes from `gh:stateful-y/python-package-copier` -2. Show you a diff of changes -3. Prompt for any new configuration questions -4. Apply updates while preserving your modifications - -### Handling Conflicts - -If you've modified files that the template also changed: -- Copier will show you conflicts -- Use `--conflict` flag to control merge strategy: - - `copier update --trust --conflict inline` - Inline conflict markers (default) - - `copier update --trust --conflict rej` - Create `.rej` files for conflicts - -### Version Pinning - -To update to a specific template version: - -```bash -copier update --trust --vcs-ref=v1.2.0 -``` - -Or update to a specific commit: - -```bash -copier update --trust --vcs-ref=abc123 -``` - -### Checking Current Version - -View your current template version: - -```bash -cat .copier-answers.yml -``` - -The `_commit` field shows the template commit your project was generated from. diff --git a/docs/pages/reference/commands.md b/docs/pages/reference/commands.md new file mode 100644 index 0000000..67a2954 --- /dev/null +++ b/docs/pages/reference/commands.md @@ -0,0 +1,117 @@ +# Commands + +The template provides three ways to run common tasks, organized by use case: + +- **just**: Convenience for everyday development (recommended) +- **nox**: Multi-version testing and CI/CD +- **uv run**: Direct tool control when specific options are needed + +!!! tip "CI/CD Note" + GitHub Actions workflows use `uv tool install nox` followed by `nox` commands (not `uvx nox`) to leverage build caching and faster execution. + +## Run Tests + +=== "just" + + ```bash + just test # Run all tests + just test-fast # Fast tests only + just test-slow # Slow and integration tests + ``` + +=== "nox" + + ```bash + uvx nox -s test # Test on Python 3.11-3.14 + uvx nox -s test_fast # Fast tests across versions + uvx nox -s test_slow # Slow tests across versions + ``` + +=== "uv run" + + ```bash + uv run pytest -v # Run all tests with verbosity + uv run pytest -m "not slow and not integration" # Fast tests only + uv run pytest -k test_specific # Run specific test + ``` + +## Format and Fix Code + +=== "just" + + ```bash + just fix # Format and fix code + just all # Fix + test + ``` + +=== "nox" + + ```bash + uvx nox -s fix # Format and fix (used in CI) + ``` + +=== "uv run" + + ```bash + uvx pre-commit run --all-files --show-diff-on-failure + ``` + +## Build Documentation + +=== "just" + + ```bash + just build # Build documentation + just serve # Build and preview at localhost:8080 + ``` + +=== "nox" + + ```bash + uvx nox -s build_docs # Build documentation + uvx nox -s serve_docs # Build and preview at localhost:8080 + ``` + +=== "uv run" + + ```bash + uv run mkdocs build --clean # Build documentation + uv run mkdocs serve -a localhost:8080 # Preview at localhost:8080 + ``` + +## Nox Sessions Reference + +| Session | Purpose | Python Versions | +|---------|---------|-----------------| +| `test` | Full test suite with doctests | All (min–max) | +| `test_fast` | Fast tests only (excludes slow/integration) | All (min–max) | +| `test_slow` | Slow and integration tests | All (min–max) | +| `test_coverage` | Tests with coverage on default Python | Single (min) | +| `test_compat` | Dependency pinning/compatibility | Single (min) | +| `test_examples` | Run marimo notebook examples | Single | +| `test_docstrings` | Run docstring examples (pytest --doctest) | Single (min) | +| `lint` | Code quality checks (ruff, rumdl, ty) | Single (latest) | +| `fix` | Auto-format and fix (pre-commit) | Single (latest) | +| `build_docs` | Render documentation with MkDocs | Single (latest) | +| `serve_docs` | Local dev server (localhost:8080) | Single (latest) | +| `link_docs` | Check documentation for broken links | Single (latest) | + +## Just Commands Reference + +| Command | Description | +|---------|-------------| +| `just test` | Run full tests with doctests | +| `just test-fast` | Fast tests only (no slow/integration) | +| `just test-slow` | Slow/integration tests | +| `just test-cov` | Tests with coverage report (HTML) | +| `just test-docstrings` | Docstring examples | +| `just test-compat` | Compatibility with pinned versions | +| `just example [file]` | Open marimo notebook interactively (if `include_examples`) | +| `just test-examples` | Run all example tests (if `include_examples`) | +| `just lint` | Ruff, rumdl, ty checks | +| `just fix` | Run pre-commit on all files | +| `just build` / `just build-fast` | Build docs (fast skips notebook export) | +| `just serve` / `just serve-fast` | Serve docs locally | +| `just link` | Check for broken links | +| `just clean` | Remove build artifacts | +| `just all` | Run fix + test | diff --git a/docs/pages/reference/configuration.md b/docs/pages/reference/configuration.md new file mode 100644 index 0000000..7be932e --- /dev/null +++ b/docs/pages/reference/configuration.md @@ -0,0 +1,113 @@ +# Configuration Files + +## Technology Stack + +| Category | Tool | Purpose | +|----------|------|---------| +| **Build** | hatchling | Modern build backend | +| **Build** | hatch-vcs | Git-based versioning | +| **Package Manager** | uv | Fast dependency management | +| **Formatter** | ruff | Code formatting | +| **Linter** | ruff | Code linting | +| **Type Checker** | ty | Static type checking | +| **Test Framework** | pytest | Unit testing | +| **Docstring Testing** | pytest-doctest | Test code examples in docstrings | +| **Coverage** | pytest-cov | Code coverage | +| **Test Automation** | nox | Multi-environment testing | +| **Pre-commit** | pre-commit | Git hooks | +| **Documentation** | MkDocs | Static site generator | +| **Doc Theme** | Material | Beautiful theme | +| **API Docs** | mkdocstrings | Docstring extraction | +| **Task Runner** | just | Command automation | +| **CI/CD** | GitHub Actions | Automation platform | +| **Coverage Reporting** | Codecov | Test coverage tracking | +| **Dependency Updates** | Dependabot | Automated updates | +| **Changelog** | git-cliff | Automated changelog generation | +| **Commit Convention** | commitizen | Conventional commits enforcement | + +## pyproject.toml + +Central configuration containing: + +- Project metadata (name, version, description) +- Dependencies and dependency groups +- Build system configuration (hatchling + hatch-vcs) +- Tool configurations (ruff, pytest, coverage) + +### Ruff Configuration + +```toml +[tool.ruff] +line-length = 120 +target-version = "py3XX" # Set to min_python_version + +[tool.ruff.format] +preview = true +docstring-code-format = true + +[tool.ruff.lint] +select = ["E", "W", "F", "I", "B", "C4", "UP", "ARG", "SIM", "PL", "T201"] +``` + +### Coverage Configuration + +```toml +[tool.coverage.run] +branch = true +plugins = ["covdefaults"] + +[tool.coverage.report] +fail_under = 1 # Permissive default +``` + +### Interrogate (Docstring Coverage) + +```toml +[tool.interrogate] +fail-under = 75 +exclude = ["setup.py", "docs", "build", "*_version.py"] +ignore-init-method = true +ignore-init-module = true +``` + +## .pre-commit-config.yaml + +Pre-commit hooks configured in generated projects: + +| Hook | Purpose | +|------|---------| +| trailing-whitespace | Remove trailing whitespace | +| end-of-file-fixer | Ensure files end with newline | +| check-yaml | Validate YAML syntax | +| check-toml | Validate TOML syntax | +| check-json | Validate JSON syntax | +| check-added-large-files | Prevent large file commits | +| check-merge-conflict | Detect merge conflict markers | +| debug-statements | Detect debugger imports | +| mixed-line-ending | Normalize line endings | +| commitizen | Enforce conventional commit messages (if `include_actions=true`) | +| interrogate | Check docstring coverage (75% minimum) | +| ruff | Format and lint code | +| rumdl | Lint markdown files (MkDocs flavor) | +| ty | Type checking via uv run | + +## mkdocs.yml + +Documentation site configuration: + +- Material for MkDocs theme with light/dark toggle +- Search, tags, and mkdocstrings plugins +- Code highlighting with line numbers and copy buttons +- Mermaid diagram support +- MathJax for LaTeX equations +- Tabbed content and admonitions + +## .readthedocs.yml + +ReadTheDocs build configuration: + +- Python 3.13 build environment +- Ubuntu 24.04 base image +- uv integration for fast installs +- Post-build link checking via linkchecker +- Syncs the `docs` dependency group diff --git a/docs/pages/reference/github-workflows.md b/docs/pages/reference/github-workflows.md new file mode 100644 index 0000000..46e0bff --- /dev/null +++ b/docs/pages/reference/github-workflows.md @@ -0,0 +1,108 @@ +# GitHub Workflows + +All workflows are conditional on `include_actions=true` (the default). + +## Release Workflow + +The automated release process follows this flow with a **manual approval gate** before PyPI publishing: + +```mermaid +graph LR + A[Push Tag
v*.*.*] --> B[changelog.yml] + B --> C[Generate
CHANGELOG.md] + B --> D[Build Package
validation] + C --> E[Create PR] + E --> F[Review & Merge
PR] + F --> G[publish-release.yml] + G --> H[Create GitHub
Release] + H --> I{Manual
Approval} + I -->|Approve| J[Publish to PyPI] + style I fill:#ff9,stroke:#333,stroke-width:2px + style J fill:#9f9,stroke:#333,stroke-width:2px +``` + +**Complete release flow**: Tag push → Changelog + Build → PR creation → Review & Merge → GitHub Release → **Manual Approval** → PyPI publish + +See [About the Release Process](../explanation/release-process.md) for the design rationale behind this multi-step approach. + +## Workflow Reference + +### tests.yml - Continuous Integration + +**Triggers**: Push to main, pull requests + +- Tests across multiple Python versions (configurable via `min_python_version` and `max_python_version`, defaults to 3.11–3.14) +- Tests on Ubuntu, Windows, and macOS +- Matrix of 15 combinations +- Uploads coverage to Codecov (requires `CODECOV_TOKEN` secret) +- Uploads test results to Codecov + +### pr-title.yml - Pull Request Title Validation + +**Triggers**: Pull requests to main + +- Validates PR title follows [Conventional Commits](https://www.conventionalcommits.org/) format +- Required types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert` +- Ensures consistency with changelog generation (git-cliff) + +### changelog.yml - Automated Changelog and Build + +**Triggers**: Version tags (`v*.*.*`) + +- Generates changelog from conventional commits using git-cliff +- Creates a Pull Request with updated `CHANGELOG.md` +- Runs pre-commit hooks on generated changelog +- Builds and validates package distributions +- Stores distributions as workflow artifacts for reuse (avoiding rebuilds) + +**Required secret**: `CHANGELOG_AUTOMATION_TOKEN` + +### publish-release.yml - GitHub Releases and PyPI Publishing + +**Triggers**: Changelog PR merged to main + +- Detects merged PRs with the `changelog` label +- Extracts version from PR title +- Downloads build artifacts from changelog workflow +- Creates a GitHub Release with release notes and distribution attachments +- Publishes to PyPI with manual approval (Trusted Publishing via OIDC) + +**Required environment**: `pypi` with required reviewers configured + +### nightly.yml - Proactive Monitoring + +**Triggers**: Daily schedule + +- Tests against latest dependencies +- Uploads coverage to Codecov (requires `CODECOV_TOKEN` secret) +- Creates GitHub issue on failure + +## Required Secrets and Environments + +| Secret/Environment | Used By | Purpose | +|--------------------|---------|---------| +| `CHANGELOG_AUTOMATION_TOKEN` | changelog.yml | Fine-grained PAT with Contents (R+W) + Pull Requests (R+W) | +| `CODECOV_TOKEN` | tests.yml, nightly.yml | Coverage upload token | +| `pypi` environment | publish-release.yml | Environment with required reviewers for manual approval | + +!!! note "Environment protection rules" + The `pypi` environment requires **public repositories** or **GitHub Pro/Team/Enterprise** plans. + +See [How to Set Up CI/CD Services](../how-to/setup-cicd.md) for step-by-step configuration instructions. + +### Configuring Manual Approval for PyPI + +To enable the manual approval gate before PyPI publishing: + +1. Navigate to repository **Settings → Environments** +2. Create or select the `pypi` environment +3. Enable **Required reviewers** under *Deployment protection rules* +4. Add one or more reviewers who must approve before PyPI publication +5. (Optional) Enable **Wait timer** to delay deployment after approval + +When a release is ready: + +- The workflow pauses at the "Wait for approval" step +- Designated reviewers receive a notification +- Reviewers can inspect the GitHub Release and artifacts before approving +- Once approved, the package is automatically published to PyPI diff --git a/docs/pages/reference/project-structure.md b/docs/pages/reference/project-structure.md new file mode 100644 index 0000000..5e0d514 --- /dev/null +++ b/docs/pages/reference/project-structure.md @@ -0,0 +1,114 @@ +# Project Structure + +## Generated Project Tree + +```text +my-package/ +├── .github/ +│ ├── ISSUE_TEMPLATE/ +│ │ ├── bug_report.yml +│ │ ├── feature_request.yml +│ │ └── config.yml +│ ├── workflows/ +│ │ ├── tests.yml +│ │ ├── pr-title.yml +│ │ ├── changelog.yml +│ │ ├── publish-release.yml +│ │ └── nightly.yml +│ ├── dependabot.yml +│ └── pull_request_template.md +├── docs/ +│ ├── index.md +│ ├── getting-started.md +│ ├── user-guide.md +│ ├── api-reference.md +│ └── contributing.md +├── src/ +│ └── package_name/ +│ ├── __init__.py +│ ├── example.py +│ └── py.typed +├── tests/ +│ ├── conftest.py +│ └── test_example.py +├── .editorconfig +├── .gitignore +├── .pre-commit-config.yaml +├── .readthedocs.yml +├── CHANGELOG.md +├── CONTRIBUTING.md +├── justfile +├── LICENSE +├── mkdocs.yml +├── noxfile.py +├── pyproject.toml +└── README.md +``` + +## File Roles + +### Root Files + +| File | Purpose | +|------|---------| +| `pyproject.toml` | Project metadata, dependencies, build config, tool settings | +| `noxfile.py` | Test automation sessions (multi-version testing, linting, docs) | +| `justfile` | Convenience commands wrapping nox sessions | +| `mkdocs.yml` | Documentation site configuration | +| `.pre-commit-config.yaml` | Git hook configuration for code quality | +| `.readthedocs.yml` | ReadTheDocs build configuration | +| `.editorconfig` | Editor-neutral formatting settings | +| `LICENSE` | Project license (based on `license` template variable) | +| `CHANGELOG.md` | Auto-generated changelog from conventional commits | +| `CONTRIBUTING.md` | Quick-start contributing guide (redirects to full docs) | +| `README.md` | Project overview, badges, installation instructions | + +### Source Code (`src/`) + +The project uses a **src layout** - all package code lives under `src//`: + +| File | Purpose | +|------|---------| +| `__init__.py` | Package initialization with version import | +| `hello.py` | Example module with a sample function | +| `py.typed` | PEP 561 marker for type checker support | + +### Tests (`tests/`) + +| File | Purpose | +|------|---------| +| `conftest.py` | Shared fixtures for pytest | +| `test_hello.py` | Example test file | +| `test_examples.py` | Marimo notebook tests (if `include_examples=true`) | + +### GitHub Configuration (`.github/`) + +| File | Purpose | +|------|---------| +| `workflows/tests.yml` | CI testing pipeline | +| `workflows/pr-title.yml` | PR title conventional commit validation | +| `workflows/changelog.yml` | Changelog generation on version tags | +| `workflows/publish-release.yml` | GitHub Release + PyPI publishing | +| `workflows/nightly.yml` | Daily dependency testing | +| `dependabot.yml` | Automated dependency update PRs | +| `pull_request_template.md` | PR description template | +| `ISSUE_TEMPLATE/` | Bug report and feature request templates | + +### Documentation (`docs/`) + +| File | Purpose | +|------|---------| +| `index.md` | Documentation homepage | +| `getting-started.md` | Installation and first steps (tutorial) | +| `user-guide.md` | Usage guide scaffold (how-to) | +| `api-reference.md` | Auto-generated API reference | +| `contributing.md` | Full contributing guidelines | + +## Conditional Files + +Some files are only generated based on template variable choices: + +| Condition | Files Generated | +|-----------|----------------| +| `include_actions=true` | `.github/workflows/*`, `.github/dependabot.yml` | +| `include_examples=true` | `examples/hello.py`, `tests/test_examples.py`, `docs/pages/examples.md`, `docs/stylesheets/gallery.css` | diff --git a/docs/pages/reference/template-variables.md b/docs/pages/reference/template-variables.md new file mode 100644 index 0000000..c306124 --- /dev/null +++ b/docs/pages/reference/template-variables.md @@ -0,0 +1,59 @@ +# Template Variables + +When creating a new project with `uvx copier copy gh:stateful-y/python-package-copier my-package`, you'll be prompted for these variables: + +| Variable | Type | Default | Description | +|----------|------|---------|-------------| +| `project_name` | str | *required* | Human-readable project name (e.g., "My Awesome Package") | +| `package_name` | str | *derived* | Python import name with underscores (e.g., "my_awesome_package")
Auto-generated from `project_name` | +| `project_slug` | str | *derived* | Repository/URL name with hyphens (e.g., "my-awesome-package")
Auto-generated from `project_name` | +| `version` | str | `0.1.0` | Initial package version following [Semantic Versioning](https://semver.org/) | +| `description` | str | `""` | One-line project description for README and package metadata | +| `author_name` | str | *required* | Author or maintainer name | +| `author_email` | str | *required* | Author or maintainer email | +| `github_username` | str | `""` | GitHub username or organization (used in URLs and badges) | +| `license` | str | `MIT` | Project license. Choices:
• Apache-2.0
• MIT
• BSD-3-Clause
• GPL-3.0
• Proprietary | +| `min_python_version` | str | `3.11` | Minimum Python version. Choices: 3.11, 3.12, 3.13, 3.14 | +| `max_python_version` | str | `3.14` | Maximum Python version. Choices: 3.11, 3.12, 3.13, 3.14
Must be ≥ `min_python_version` | +| `include_actions` | bool | `true` | Include GitHub Actions CI/CD workflows (tests, changelog, releases) | +| `include_examples` | bool | `true` | Include `examples/` directory with [marimo](https://marimo.io/) interactive notebooks | + +**Note**: Derived variables (`package_name`, `project_slug`) are auto-generated but can be overridden during setup. + +**Example**: + +- `project_name`: "My Data Tool" +- `package_name`: "my_data_tool" (underscores for Python imports) +- `project_slug`: "my-data-tool" (hyphens for repository names and URLs) + +## Variable Effects + +### `min_python_version` / `max_python_version` + +These variables control several aspects of the generated project: + +- **Nox test matrix**: Tests run across all Python versions from min to max +- **CI matrix**: GitHub Actions tests the same version range +- **Ruff target**: The linter targets the minimum Python version +- **Package classifiers**: `pyproject.toml` includes the appropriate `Programming Language :: Python :: 3.x` classifiers + +### `include_actions` + +When `true`, generates the following in `.github/workflows/`: + +- `tests.yml` - CI testing across Python versions and operating systems +- `pr-title.yml` - Conventional commit validation for PR titles +- `changelog.yml` - Automated changelog generation on version tags +- `publish-release.yml` - GitHub Release creation and PyPI publishing +- `nightly.yml` - Daily dependency testing with issue creation on failure + +See [GitHub Workflows](github-workflows.md) for full details on each workflow. + +### `include_examples` + +When `true`, generates: + +- `examples/` directory with a sample [marimo](https://marimo.io/) interactive notebook +- `tests/test_examples.py` for testing notebooks +- Additional documentation pages for the example gallery +- Extra dependencies: `numpy`, `pandas`, `plotly` diff --git a/mkdocs.yml b/mkdocs.yml index a4da7bf..d263a1e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -62,8 +62,21 @@ markdown_extensions: nav: - Home: index.md - Quick Start: pages/quickstart.md - - Reference: pages/reference.md - - Contributing: pages/contributing.md + - How-to Guides: + - Set Up CI/CD Services: pages/how-to/setup-cicd.md + - Customize Your Project: pages/how-to/customize-template.md + - Update from Template: pages/how-to/update-template.md + - Add Dependencies: pages/how-to/add-dependencies.md + - Contribute to the Template: pages/how-to/contribute.md + - Reference: + - Template Variables: pages/reference/template-variables.md + - Project Structure: pages/reference/project-structure.md + - Commands: pages/reference/commands.md + - GitHub Workflows: pages/reference/github-workflows.md + - Configuration Files: pages/reference/configuration.md + - Explanation: + - Architecture Overview: pages/explanation/architecture.md + - Release Process: pages/explanation/release-process.md extra_javascript: - javascripts/readthedocs.js diff --git a/template/.github/skills/diataxis-docs-planner/SKILL.md b/template/.github/skills/diataxis-docs-planner/SKILL.md new file mode 100644 index 0000000..8cd3558 --- /dev/null +++ b/template/.github/skills/diataxis-docs-planner/SKILL.md @@ -0,0 +1,171 @@ +--- +name: diataxis-docs-planner +description: Audit, plan, and structure Python package documentation following the Diátaxis framework (tutorials, how-to guides, reference, explanation). Use when asked to plan documentation, audit existing docs, identify documentation gaps, restructure docs, create a documentation roadmap, or organize documentation for a Python package. Triggers on "plan docs", "audit documentation", "structure docs", "documentation roadmap", "what docs do I need", "organize documentation". +--- + +# Diátaxis Documentation Planner + +Audit existing documentation and produce a structured plan following the Diátaxis framework — four quadrants of documentation that serve distinct user needs. + +## The Four Quadrants + +| Quadrant | Orientation | User mode | Serves | Question answered | +|----------|-------------|-----------|--------|-------------------| +| **Tutorial** | Learning | Study | Acquisition of skill | "Can you teach me to…?" | +| **How-to guide** | Task | Work | Application of skill | "How do I…?" | +| **Reference** | Information | Work | Application of skill | "What is…?" | +| **Explanation** | Understanding | Study | Acquisition of skill | "Why…?" | + +## Compass Decision Tree + +Classify any content by asking two questions: + +1. **Action or cognition?** Does it guide what the user *does*, or inform what the user *knows*? +2. **Acquisition or application?** Does it serve *study* (learning) or *work* (applying skills)? + +| Informs… | Serves… | → Quadrant | +|----------|---------|------------| +| Action | Acquisition (study) | Tutorial | +| Action | Application (work) | How-to guide | +| Cognition | Application (work) | Reference | +| Cognition | Acquisition (study) | Explanation | + +## Audit Workflow + +### Step 1: Analyze the Codebase + +Examine the package to understand what needs documenting: + +- Read `pyproject.toml` for package name, description, dependencies, entry points, CLI tools +- Scan `src//` for public modules, classes, functions (the API surface) +- Check for CLI entry points, configuration files, plugin systems +- Look at `tests/` for usage patterns and features exercised +- Check `examples/` if present + +### Step 2: Inventory Existing Documentation + +Read all files in `docs/` and classify each page by quadrant using the compass: + +- For each page, note: file path, current title, actual quadrant, intended quadrant +- Flag pages that mix quadrants (e.g., a "getting started" that is half tutorial, half reference) +- Flag pages that are misclassified (e.g., an "explanation" page that is really a how-to) + +### Step 3: Identify Gaps + +For a well-documented Python package, expect at minimum: + +**Tutorials** (at least 1): +- Getting Started / First Steps — install, import, first meaningful result + +**How-to Guides** (varies by feature count): +- One per common task/problem users face +- Installation/setup variations (different platforms, configs) +- Integration with other tools/libraries +- Configuration for common scenarios +- Troubleshooting guide + +**Reference** (comprehensive): +- API reference (all public modules, classes, functions) +- CLI reference (if applicable) +- Configuration reference (all settings/options) +- Error codes / exceptions (if applicable) + +**Explanation** (at least 1-2): +- Architecture / design overview +- Key concepts and terminology +- Design decisions / "why" docs +- Comparison with alternatives (when useful) + +### Step 4: Produce the Plan + +Output a structured documentation plan: + +1. **Gap analysis table** — what exists, what is missing, what needs reclassification +2. **Recommended pages** — organized by quadrant, with title, purpose, priority (high/medium/low) +3. **MkDocs nav structure** — ready to paste into `mkdocs.yml` +4. **Implementation order** — tutorials and key how-tos first (highest user impact) +5. **Skill recommendations** — name the specific writer skill for each page: + - Tutorial pages → `diataxis-tutorial-writer` + - How-to pages → `diataxis-howto-writer` + - Reference pages → `diataxis-reference-writer` + - Explanation pages → `diataxis-explanation-writer` + +## MkDocs Nav Patterns + +Typical Python package nav structure: + +```yaml +nav: + - Home: index.md + - Getting Started: getting-started.md # tutorial + - How-to Guides: # how-to + - how-to/index.md + - How to Configure X: how-to/configure-x.md + - How to Integrate with Y: how-to/integrate-y.md + - Reference: # reference + - reference/index.md + - API Reference: reference/api.md + - CLI Reference: reference/cli.md + - Configuration: reference/configuration.md + - Explanation: # explanation + - explanation/index.md + - Architecture: explanation/architecture.md + - Design Decisions: explanation/design-decisions.md + - Contributing: contributing.md # how-to (for contributors) +``` + +For complex packages with multiple user types or deployment targets, see [references/compass-and-patterns.md](references/compass-and-patterns.md) for multi-layer hierarchy and two-dimensional structure guidance. + +## Common Anti-Patterns to Flag + +- **The mega-README**: Everything in one file — split by quadrant +- **Tutorial-reference hybrid**: "Getting Started" that is actually an API walkthrough — separate +- **How-to disguised as explanation**: "Understanding X" that is really step-by-step instructions +- **Missing tutorials entirely**: Only reference docs (common with auto-generated docs) +- **Explanation scattered everywhere**: Bits of "why" sprinkled across how-to guides — consolidate + +## Quality Signals + +When auditing, also note: + +- **Functional quality**: accuracy, completeness, consistency, precision +- **Deep quality**: flow, fit to user needs, anticipation of the user +- Use the `mkdocs` skill for site configuration and build concerns — this skill focuses on content structure + +## Output Format + +```markdown +## Documentation Audit: + +### Current State + +| Page | File | Current Quadrant | Issues | +|------|------|-----------------|--------| +| ... | ... | ... | ... | + +### Gap Analysis + +| Quadrant | Existing | Missing | Priority | +|----------|----------|---------|----------| +| Tutorial | ... | ... | ... | +| How-to | ... | ... | ... | +| Reference | ... | ... | ... | +| Explanation | ... | ... | ... | + +### Recommended Pages +#### Tutorials (use `diataxis-tutorial-writer`) +1. **Getting Started** — Install, first use, verify result [HIGH] + +#### How-to Guides (use `diataxis-howto-writer`) +1. **How to configure X** — ... [HIGH] + +#### Reference (use `diataxis-reference-writer`) +1. **API Reference** — Full public API [HIGH] + +#### Explanation (use `diataxis-explanation-writer`) +1. **Architecture Overview** — ... [MEDIUM] + +### Proposed MkDocs Nav +nav: + ... +``` diff --git a/template/.github/skills/diataxis-docs-planner/references/compass-and-patterns.md b/template/.github/skills/diataxis-docs-planner/references/compass-and-patterns.md new file mode 100644 index 0000000..45132ee --- /dev/null +++ b/template/.github/skills/diataxis-docs-planner/references/compass-and-patterns.md @@ -0,0 +1,119 @@ +# Diátaxis Compass and Documentation Patterns + +## Full Compass Table + +| Content characteristic | Tutorial | How-to Guide | Reference | Explanation | +|----------------------|----------|-------------|-----------|-------------| +| **What they do** | Introduce, educate, lead | Guide | State, describe, inform | Explain, clarify, discuss | +| **Answers the question** | "Can you teach me to…?" | "How do I…?" | "What is…?" | "Why…?" | +| **Oriented to** | Learning | Goals | Information | Understanding | +| **Purpose** | Provide a learning experience | Help achieve a particular goal | Describe the machinery | Illuminate a topic | +| **Form** | A lesson | A series of steps | Dry description | Discursive explanation | +| **Analogy** | Teaching a child to cook | A recipe in a cookbook | Info on a food packet | Article on culinary history | + +## Boundary Blur Risks + +Adjacent quadrants share affinities that cause content to bleed across boundaries: + +| Shared trait | Quadrants at risk | Common mistake | +|-------------|------------------|----------------| +| Guide action | Tutorial ↔ How-to | Conflating "getting started" with "how to configure" | +| Serve application of skill | Reference ↔ How-to | Stuffing procedures into API docs | +| Contain propositional knowledge | Reference ↔ Explanation | Expanding reference examples into explanations | +| Serve acquisition of skill | Tutorial ↔ Explanation | Overloading tutorials with background context | + +## Python Package Page Patterns + +### Typical Tutorial Pages +- **Getting Started** — Install via pip/uv, import, call a function, verify output +- **Your First ** — Build something small end-to-end +- **Tutorial Series Part N** — Multi-part progressive learning path + +### Typical How-to Pages +- **How to install** (with variations: pip, uv, conda, Docker, from source) +- **How to configure ** — Settings, env vars, config files +- **How to integrate with ** — Using the package alongside another tool +- **How to deploy** — Production setup, CI/CD integration +- **How to extend / write plugins** — For extensible packages +- **How to migrate from vX to vY** — Upgrade guides +- **Troubleshooting** — Common problems and solutions + +### Typical Reference Pages +- **API Reference** — Auto-generated via mkdocstrings (modules → classes → methods) +- **CLI Reference** — Commands, flags, options, exit codes +- **Configuration Reference** — All settings with types, defaults, descriptions +- **Error Reference** — Exception classes, error codes, meanings +- **Changelog** — Version history (auto-generated via git-cliff or similar) + +### Typical Explanation Pages +- **Architecture Overview** — How the package is structured and why +- **Design Decisions** — Why certain approaches were chosen +- **Key Concepts** — Domain terminology and mental models +- **Comparison with Alternatives** — How this package differs from similar tools +- **Performance Characteristics** — Complexity, benchmarks, trade-offs +- **Security Model** — Trust boundaries, threat model (when applicable) + +## Complex Hierarchy Patterns + +### Single Product, Multiple User Types + +```text +docs/ + getting-started.md # tutorial (all users) + how-to/ + users/ # how-to for end users + configure.md + troubleshoot.md + developers/ # how-to for integrators + extend.md + write-plugins.md + contributors/ # how-to for maintainers + development-setup.md + release-process.md + reference/ + api.md # reference (shared) + cli.md + config.md + explanation/ + architecture.md # explanation (shared) + design-decisions.md +``` + +### Single Product, Multiple Deployment Targets + +```text +docs/ + getting-started.md # tutorial (generic) + how-to/ + install-pip.md # how-to per target + install-docker.md + install-from-source.md + deploy-aws.md + deploy-gcp.md + reference/ # reference (shared) + api.md + config.md + explanation/ # explanation (shared) + architecture.md +``` + +## Contents Page Guidelines + +- Landing pages should read as overviews, not bare lists +- Keep lists under 7 items per group; break into sub-sections if longer +- Use headings with brief introductory text to provide context +- Each landing page should help the user quickly find what they need + +## Quality Checklist + +### Functional Quality (measurable) +- [ ] Accurate — code examples run, commands produce stated output +- [ ] Complete — all public API surface documented +- [ ] Consistent — terminology, formatting, style uniform across pages +- [ ] Up-to-date — matches current version of the package + +### Deep Quality (experiential) +- [ ] Flow — reader progresses naturally without jarring transitions +- [ ] Fit to needs — each page serves a clear user need +- [ ] Anticipation — docs address questions before they arise +- [ ] Minimal friction — no unnecessary detours or digressions diff --git a/template/.github/skills/diataxis-explanation-writer/SKILL.md b/template/.github/skills/diataxis-explanation-writer/SKILL.md new file mode 100644 index 0000000..cf33a4c --- /dev/null +++ b/template/.github/skills/diataxis-explanation-writer/SKILL.md @@ -0,0 +1,160 @@ +--- +name: diataxis-explanation-writer +description: Generate understanding-oriented explanation documentation for Python packages following Diátaxis principles. Use when asked to write conceptual docs, architecture overview, design decisions, "about" pages, "why" docs, background context, or any documentation that helps the reader understand a topic through reflection and discussion. Triggers on "write an explanation", "conceptual docs", "architecture overview", "design decisions", "why did we choose", "background", "about the design", "explain the architecture". +--- + +# Diátaxis Explanation Writer + +Generate explanation documentation — understanding-oriented discussion that helps the reader make sense of a topic through reflection. + +Explanation is like reading **On Food and Cooking** by Harold McGee: it does not teach you to cook or give you recipes, but it places cooking in context of history, science, and society, deepening your understanding of the craft. + +## What Explanation Is + +- Discursive treatment of a subject that permits reflection +- Deepens and broadens understanding by providing context, connections, and perspective +- An answer to "Can you tell me about…?" +- The only documentation you might read in the bath — away from the keyboard + +Explanation serves the user's **study**, not their work. It is the counterpart to reference (which also contains propositional knowledge but serves work). + +## Generation Workflow + +### Step 1: Identify the Topic + +- What concept, decision, or aspect of the package would benefit from deeper understanding? +- Frame it as an implicit "About…": "About the plugin architecture", "About authentication design" +- Choose a topic that can be meaningfully bounded — not the entire package, but a coherent area + +### Step 2: Gather Context + +- Read the source code to understand the design +- Check git history or ADRs for decision rationale +- Look at `README.md` and existing docs for hints about design philosophy +- Identify connections to other systems, concepts, or alternatives + +### Step 3: Write the Explanation + +Structure as a discussion that circles around the topic from different angles. Apply all key principles below. Target 500-2000 words. + +## Key Principles + +### Make connections + +Weave a web of understanding. Connect the topic to other things — even outside the immediate subject — if it helps comprehension. + +"The event system works similarly to browser DOM events, where handlers are registered for specific event types and called when those events fire." + +### Provide context + +Explain **why** things are the way they are: design decisions, historical reasons, technical constraints. Draw implications. Mention specific examples. + +"We chose SQLite as the default backend because it requires zero configuration and ships with Python's standard library. For production workloads exceeding 100 concurrent writers, see the PostgreSQL backend." + +### Talk about the subject + +Explanation guides are **about** a topic — they circle around it. The title should allow an implicit "about": "About user authentication", "About the caching strategy". + +Discuss: +- The bigger picture +- History and evolution +- Choices, alternatives, possibilities +- Why: reasons and justifications + +### Admit opinion and perspective + +All human creation is invested with opinion. Explanation can and must consider alternatives, counter-examples, and multiple approaches. It is a discussion, not a decree. + +"Some teams prefer a monolithic configuration file while others split settings by concern. Both approaches have trade-offs…" + +### Keep explanation closely bounded + +One risk of explanation is absorbing other things. The urge to include instruction (how-to) or technical description (reference) is strong. Resist it — those have their own places. Allowing them in interferes with the explanation and removes them from where they belong. + +## Language Patterns + +- **"The reason for X is because historically, Y…"** — Explain origins +- **"W is better than Z, because…"** — Offer judgements where appropriate +- **"An X in this system is analogous to a Y in…"** — Provide context through analogy +- **"Some users prefer W (because Z). This can be a good approach, but…"** — Weigh alternatives +- **"X interacts with Y as follows:…"** — Unfold internal workings to build understanding + +## Python Package Explanation Template + +```markdown +# About [Topic] + +[Opening paragraph that frames the topic and why it matters to the reader's +understanding of the package.] + +## Overview + +[High-level description of the concept, system, or decision being explained. +Connect it to the reader's existing knowledge.] + +## Why [This Approach] + +[Explain the reasoning behind the design. What problem does it solve? What +alternatives were considered? What constraints shaped the decision?] + +For example, [concrete example that illustrates the concept]. + +## How It Works + +[Describe the mechanism at a conceptual level — not a step-by-step procedure +(that would be a how-to), but the logic and flow of the system.] + +[Diagrams or analogies are valuable here.] + +## Trade-offs and Alternatives + +[Discuss what was gained and what was given up. Mention alternative approaches +and why they were not chosen — or when they might be better.] + +| Approach | Pros | Cons | +|----------|------|------| +| Current approach | ... | ... | +| Alternative A | ... | ... | +| Alternative B | ... | ... | + +## Connections + +[Link this topic to related concepts, other parts of the system, or broader +patterns in the ecosystem.] + +- [Related concept in the package](other-explanation.md) +- [API Reference for this system](../reference/api.md) +- [How to configure this feature](../how-to/configure.md) +``` + +## Typical Explanation Pages for Python Packages + +- **Architecture Overview** — How the package is structured, the component graph, data flow +- **Design Decisions** — Why certain approaches were chosen (ADR-style or narrative) +- **Key Concepts** — Domain terminology, mental models, glossary with depth +- **Plugin/Extension Model** — How extensibility works and why it is designed this way +- **Performance Characteristics** — Complexity analysis, caching strategy rationale, benchmarks with context +- **Security Model** — Trust boundaries, threat model, why certain security choices were made +- **Comparison with Alternatives** — How this package differs from similar tools, when to choose which +- **History and Evolution** — How the package got to its current state (for mature projects) + +## Distinction from Reference + +| Aspect | Explanation | Reference | +|--------|------------|-----------| +| Purpose | Illuminate a topic | Describe the machinery | +| User mode | At study | At work | +| Tone | Discursive, reflective | Austere, neutral | +| Content | Context, reasons, opinions | Facts, specifications | +| Structure | Circles around a topic | Mirrors code structure | +| When read | Away from the keyboard | While coding | +| Test | "Could I read this in the bath?" → explanation | "Is this boring?" → reference | + +## Anti-Patterns to Avoid + +- **Disguised reference** — Lists of parameters or API details belong in reference +- **Disguised how-to** — Step-by-step procedures belong in how-to guides +- **No clear topic** — Every explanation must be "about" something bounded +- **Too abstract** — Ground discussion in concrete examples from the actual package +- **Missing the "why"** — If it does not answer "why", it is probably reference, not explanation +- **Unbounded scope** — Explanation that tries to cover everything covers nothing well diff --git a/template/.github/skills/diataxis-howto-writer/SKILL.md b/template/.github/skills/diataxis-howto-writer/SKILL.md new file mode 100644 index 0000000..f04a8c2 --- /dev/null +++ b/template/.github/skills/diataxis-howto-writer/SKILL.md @@ -0,0 +1,182 @@ +--- +name: diataxis-howto-writer +description: Generate task-oriented how-to guide documentation for Python packages following Diátaxis principles. Use when asked to write a how-to guide, cookbook entry, recipe, procedure, troubleshooting guide, or any documentation that helps an already-competent user accomplish a specific real-world task. Triggers on "write a how-to", "how to configure", "how to deploy", "how to integrate", "troubleshooting guide", "cookbook", "recipe", "procedure for". +--- + +# Diátaxis How-to Guide Writer + +Generate how-to guides — task-oriented documentation that helps already-competent users accomplish specific goals. + +A how-to guide is a **recipe**. It addresses a real-world problem and provides practical directions to solve it. The reader already knows what they want to do. + +## What a How-to Guide Is + +- Directions that guide the reader through a problem or towards a result +- Addresses an already-competent user who knows what they want to achieve +- Concerned with **work**, not study +- Like a recipe: a professional chef still uses recipes to ensure correctness + +A how-to guide is NOT a tutorial. Tutorials serve learning; how-to guides serve work. See the distinction section below. + +## Generation Workflow + +### Step 1: Identify the Task + +- What real-world problem or goal does the user have? +- Frame it from the **user's perspective**, not the tool's capabilities +- Good: "How to configure logging for production" (user need) +- Bad: "Using the LogConfig class" (tool-centric, not a need) + +### Step 2: Determine Prerequisites + +- What should the user already know or have set up? +- List these briefly at the top — do not teach them (that is a tutorial's job) + +### Step 3: Write the Guide + +Structure as a sequence of actions toward the goal. Apply all key principles below. + +## Key Principles + +### Address real-world complexity + +A guide useless for any purpose except exactly the narrow case described is rarely valuable. Remain open to the range of possibilities so users can adapt guidance to their needs. + +Use conditional steps: "If you are using X, do Y instead." + +### Omit the unnecessary + +Practical usability over completeness. A how-to guide should start and end in some reasonable place, requiring the reader to join it up to their own work. Unlike a tutorial, it does not need to be end-to-end. + +### Provide a set of instructions + +The steps are in the form of actions — including thinking and judgement, not just physical acts. Address how the user thinks as well as what the user does. + +### Describe a logical sequence + +The fundamental structure is a sequence that implies logical ordering in time. If one step sets up the environment for another, put it first even if the ordering is not strictly required. + +### Seek flow + +Ground sequences in the user's activity patterns. A workflow that has the user repeatedly switching contexts is clumsy. Consider: + +- What are you asking the user to think about? +- How long must they hold a thought before resolving it in action? +- Does the guide require unnecessary back-and-forth? + +At its best, a how-to guide anticipates the user — the helper who has the tool ready before you reach for it. + +### Pay attention to naming + +Titles must say exactly what the guide shows: + +- Good: "How to integrate application performance monitoring" +- Bad: "Integrating application performance monitoring" (could be about whether to, not how) +- Worse: "Application performance monitoring" (could be anything) + +### No digression, explanation, or teaching + +Anything beyond action dilutes the guide. Do not explain concepts inline — link to explanation pages. Do not teach basics — that is a tutorial's job. Do not provide exhaustive reference — link to reference pages. + +## Language Patterns + +- **"This guide shows you how to…"** — Describe the problem and what will be solved +- **"If you want x, do y. To achieve w, do z."** — Conditional imperatives +- **"Refer to the X reference guide for a full list of options."** — Don't pollute with every option + +## Python Package How-to Template + +````markdown +# How to [Accomplish Specific Goal] + +This guide shows you how to [goal description]. Use this when you need to +[real-world scenario]. + +## Prerequisites + +- installed ([Getting Started](../getting-started.md)) +- [Other requirement] + +## Steps + +### 1. [First Action] + +```python +from import + + +``` + +### 2. [Second Action] + +If you are [condition A]: + +```python +# approach for condition A +``` + +If you are [condition B] instead: + +```python +# approach for condition B +``` + +### 3. [Verify / Complete] + +```python +# verification step +``` + +## Common Variations + +- **[Variation 1]**: [Brief guidance] +- **[Variation 2]**: [Brief guidance] + +## Troubleshooting + +**Problem: [common issue]** +: [Solution] + +**Problem: [another issue]** +: [Solution] + +## See Also + +- [API Reference for X](../reference/api.md) — full list of options +- [About Y architecture](../explanation/architecture.md) — understanding the design +```text + +## Typical How-to Guides for Python Packages + +- **How to install** — pip, uv, conda, Docker, from source variations +- **How to configure ** — settings, env vars, config files +- **How to integrate with ** — using alongside pytest, FastAPI, Django, etc. +- **How to deploy to production** — WSGI, Docker, cloud platforms +- **How to write a plugin / extension** — for extensible packages +- **How to migrate from vX to vY** — upgrade path with breaking changes +- **How to test your code** — patterns for testing code that uses the package +- **How to troubleshoot ** — common problems and solutions +- **How to contribute** — development setup, workflow, conventions + +## Distinction from Tutorials + +| Aspect | Tutorial | How-to Guide | +|--------|----------|-------------| +| User state | At study | At work | +| User skill | Beginner | Already competent | +| Goal | Learning experience | Task completion | +| Path | Single, managed | Branching, real-world | +| Setting | Contrived, safe | Real world, unpredictable | +| Choices | None — pick for them | Conditional alternatives | +| Responsibility | Teacher's | User's | +| Explanation | Minimal, inline | None — link out | + +A tutorial teaches general skills through a specific exercise. A how-to guide helps accomplish a specific task using existing skills. + +## Anti-Patterns to Avoid + +- **Teaching basics** — Do not explain what a function is; the user is competent +- **Exhaustive options** — List 2-3 variations, link to reference for the rest +- **Tool-centric framing** — "How to use the X class" is not addressed to a human need +- **Missing conditionals** — Real-world tasks branch; acknowledge this with if/then guidance +- **Burying the action** — Lead with what to do, not why diff --git a/template/.github/skills/diataxis-reference-writer/SKILL.md b/template/.github/skills/diataxis-reference-writer/SKILL.md new file mode 100644 index 0000000..f735605 --- /dev/null +++ b/template/.github/skills/diataxis-reference-writer/SKILL.md @@ -0,0 +1,227 @@ +--- +name: diataxis-reference-writer +description: Generate and structure information-oriented reference documentation for Python packages following Diátaxis principles. Use when asked to write API reference docs, CLI reference, configuration reference, error code reference, or any documentation that provides austere technical description of the machinery. Triggers on "write reference docs", "API documentation", "document the API", "CLI reference", "configuration reference", "error reference", "describe the interface". +--- + +# Diátaxis Reference Writer + +Generate reference documentation — information-oriented technical descriptions of the machinery, meant to be consulted, not read. + +Reference material is like a **map**: it describes the territory accurately so the user can navigate it confidently while working. It is austere, authoritative, and free of interpretation. + +## What Reference Is + +- Technical description of the machinery and how to operate it +- Propositional knowledge the user looks to while working +- Led by the **product structure**, not by user needs +- Purpose: describe, as succinctly as possible, in an orderly way + +Reference is what the user needs while they are at work — applying their existing skills. + +## Generation Workflow + +### Step 1: Map the API Surface + +- Scan `src//` for all public modules +- Within each module, identify public classes, functions, constants, type aliases +- Note the module hierarchy: package → subpackages → modules → classes → methods +- Check `__all__` exports if defined +- Identify CLI entry points from `pyproject.toml` `[project.scripts]` +- Find configuration schemas, settings classes, env var definitions + +### Step 2: Mirror the Code Structure + +The documentation structure must reflect the code structure — like a map reflects territory. If a method belongs to a class in a module, the docs should show the same hierarchy. + +```text +reference/ + api.md # or split per module: + api/ + module_a.md # mirrors src//module_a.py + module_b.md # mirrors src//module_b.py + cli.md # mirrors CLI commands + configuration.md # mirrors settings/config +``` + +### Step 3: Write the Reference + +Apply all key principles below. For API docs, prefer mkdocstrings auto-generation with well-written docstrings over hand-written reference. + +## Key Principles + +### Describe and only describe + +Neutral description is the key imperative. Do not explain, instruct, discuss, or opine. These run counter to reference needs which demand accuracy, precision, completeness, and clarity. + +If instruction or explanation feels necessary, link to how-to guides or explanation pages instead. + +### Adopt standard patterns + +Reference is useful when it is consistent. Use the same format for every function, every class, every CLI command. Standard patterns let users scan rapidly. + +No creative vocabulary or varied styles — reference is not the place. + +### Respect the structure of the machinery + +The documentation structure mirrors the code structure. If the code organizes functionality into modules and classes, the reference should do the same. This lets the user navigate code and docs in parallel. + +### Provide examples + +Short usage examples illustrate without distracting. An example of a command invocation or function call is a succinct way to show context without falling into explanation. + +```python +# Example: Create a client with custom timeout +client = MyClient(timeout=30) +``` + +Keep examples minimal — just enough to illustrate, not to teach. + +## Language Patterns + +- **" provides…"**, **" returns…"** — State facts about the machinery +- **"Parameters: a, b, c"** — List inputs, outputs, options +- **"You must use X. You must not apply Y unless Z."** — Warnings where appropriate +- **"See [How to configure X] for usage guidance."** — Link out + +## mkdocstrings Integration + +For Python packages using MkDocs with mkdocstrings, generate reference via docstrings: + +### Docstring Format (NumPy style) + +```python +def process(data: list[float], *, normalize: bool = False) -> Result: + """Process the input data and return a Result. + + Parameters + ---------- + data : list[float] + The input data points to process. + normalize : bool, optional + Whether to normalize values to [0, 1] range, by default False. + + Returns + ------- + Result + The processed result containing summary statistics. + + Raises + ------ + ValueError + If `data` is empty. + + Examples + -------- + >>> process([1.0, 2.0, 3.0]) + Result(mean=2.0, std=0.816) + + >>> process([1.0, 2.0, 3.0], normalize=True) + Result(mean=0.5, std=0.408) + """ +``` + +### MkDocs Page Using mkdocstrings + +```markdown +# API Reference + +::: package_name + options: + show_root_heading: true + show_source: true + members_order: source +``` + +Or per-module: + +```markdown +# module_name + +::: package_name.module_name + options: + show_root_heading: true + show_source: true + members_order: source +``` + +## CLI Reference Template + +```markdown +# CLI Reference + +## `command-name` + +``` +command-name [OPTIONS] ARGUMENT +```text + +### Arguments + +| Argument | Description | Required | +|----------|-------------|----------| +| `ARGUMENT` | Description | Yes | + +### Options + +| Option | Short | Description | Default | +|--------|-------|-------------|---------| +| `--verbose` | `-v` | Enable verbose output | `false` | +| `--output` | `-o` | Output file path | stdout | + +### Exit Codes + +| Code | Meaning | +|------|---------| +| 0 | Success | +| 1 | General error | +| 2 | Invalid arguments | + +### Examples + +```bash +command-name --verbose input.txt +command-name -o result.json input.txt +``` +```text + +## Configuration Reference Template + +```markdown +# Configuration Reference + +## Environment Variables + +| Variable | Type | Default | Description | +|----------|------|---------|-------------| +| `PACKAGE_DEBUG` | `bool` | `false` | Enable debug mode | +| `PACKAGE_LOG_LEVEL` | `str` | `"INFO"` | Logging level | + +## Configuration File + +The configuration file is read from `~/.config/package/config.toml`. + +### `[section]` + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| `key` | `str` | `""` | Description | +``` + +## Distinction from Explanation + +| Aspect | Reference | Explanation | +|--------|-----------|-------------| +| Purpose | Describe the machinery | Illuminate a topic | +| User mode | At work | At study | +| Tone | Austere, neutral | Discursive, reflective | +| Content | Facts, specifications | Context, reasons, connections | +| When read | While doing something | When stepping back to think | +| Test | "Is this boring and unmemorable?" → reference | "Could I read this in the bath?" → explanation | + +## Anti-Patterns to Avoid + +- **Creeping explanation** — Examples that expand into "why" discussions; keep examples terse +- **Missing structure** — Flat lists of functions with no hierarchy; mirror the code +- **Incomplete coverage** — Every public API surface must be documented, no gaps +- **Stale content** — Reference must match the current version; automate where possible +- **Instruction mixed in** — "To use this, first do X" is a how-to; reference just describes diff --git a/template/.github/skills/diataxis-tutorial-writer/SKILL.md b/template/.github/skills/diataxis-tutorial-writer/SKILL.md new file mode 100644 index 0000000..8642bfe --- /dev/null +++ b/template/.github/skills/diataxis-tutorial-writer/SKILL.md @@ -0,0 +1,204 @@ +--- +name: diataxis-tutorial-writer +description: Generate learning-oriented tutorial documentation for Python packages following Diátaxis principles. Use when asked to write a tutorial, getting started guide, first steps page, quickstart, onboarding guide, or any documentation that teaches a beginner by walking them through hands-on steps. Triggers on "write a tutorial", "getting started page", "quickstart guide", "first steps", "beginner guide", "onboarding docs", "teach how to use". +--- + +# Diátaxis Tutorial Writer + +Generate tutorials — learning-oriented documentation where the reader acquires skills through hands-on practice under guidance. + +A tutorial is a **lesson**. The reader does things, and learns by doing. The author is the teacher; the reader is the student. + +## What a Tutorial Is + +- A practical activity where the student learns by doing something meaningful +- Designed around an encounter the learner can make sense of +- The teacher is responsible for the learner's safety and success +- Purpose: help them **learn**, not help them **get something done** + +A tutorial is like a driving lesson: the purpose is to develop skills and confidence, not to get from A to B. + +## Generation Workflow + +### Step 1: Understand the Package + +- Read `pyproject.toml` for package name, description, key features +- Scan `src//` for the simplest useful public API +- Check `examples/` for existing usage patterns +- Identify the **single most impressive thing** a beginner can achieve quickly + +### Step 2: Design the Learning Journey + +Choose a concrete goal the learner will achieve. Structure it as: + +1. **Setup** — Install the package, verify installation +2. **First contact** — Import, call the simplest function, see a result +3. **Build** — Incrementally add complexity, one concept at a time +4. **Completion** — Arrive at a meaningful, visible result +5. **Next steps** — Link to how-to guides and explanation (not more tutorials) + +Every step should produce a **visible, verifiable result**. + +### Step 3: Write the Tutorial + +Apply all key principles below. Use the language patterns. Target 500-1500 words. + +## Key Principles + +### Show the learner where they are going + +Open with what they will achieve: "In this tutorial, we will create a [concrete thing]. Along the way we will [encounter X, Y, Z]." + +Never say "In this tutorial you will learn…" — that is presumptuous. + +### Deliver visible results early and often + +Every step must produce something the user can see. Start with the smallest possible success, then build. + +```python +# Step 1: Verify installation +import my_package +print(my_package.__version__) +# Output: 1.0.0 +``` + +### Maintain a narrative of the expected + +Tell the user what will happen before it happens: "You will notice that…", "After a moment, you should see…", "The output should look something like…" + +Show exact expected output. Flag likely mistakes: "If you see X instead, you probably forgot to Y." + +### Point out what the learner should notice + +Close learning loops: "Notice that the prompt changed to…", "See how the output now includes…" + +Observing is an active skill. Prompt it. + +### Ruthlessly minimise explanation + +A tutorial is not the place for explanation. One sentence is enough: "We use HTTPS because it is more secure." Link to explanation pages for depth. + +Explanation distracts the learner's attention and blocks learning. Resist the urge to teach by telling. + +### Focus on the concrete + +Focus on *this* problem, *this* action, *this* result. Lead the learner from step to concrete step. General patterns will emerge naturally from concrete examples — the mind does this automatically. + +### Ignore options and alternatives + +There may be many interesting diversions — ignore them. Stay on the path to the conclusion. Every option adds cognitive load. Save alternatives for how-to guides. + +### Encourage and permit repetition + +Where possible, make steps repeatable. Learners often repeat a step just to confirm "the same thing really does happen again." + +### Aspire to perfect reliability + +Every step must produce the stated result for every user, every time. A learner who does not get the expected result loses confidence immediately. Test the tutorial end-to-end. + +## Language Patterns + +Use these templates: + +- **"We…"** — First-person plural affirms the teacher-learner relationship +- **"In this tutorial, we will…"** — Describe what the learner will accomplish +- **"First, do x. Now, do y. Now that you have done y, do z."** — No ambiguity +- **"The output should look something like…"** — Set expectations +- **"Notice that…"**, **"Remember that…"**, **"Let's check…"** — Confirm they are on track +- **"You have built a…"** — Celebrate the accomplishment at the end + +## Python Package Tutorial Template + +````markdown +# Getting Started + +In this tutorial, we will [concrete achievement]. Along the way, we will +[encounter key concepts]. + +## Prerequisites + +- Python [version]+ installed +- A terminal or command prompt + +## Installation + +=== "pip" + + ```bash + pip install + ``` + +=== "uv" + + ```bash + uv add + ``` + +Verify the installation: + +```python +import +print(.__version__) +``` + +The output should look something like: + +```text +x.y.z +``` + +## Your First [Thing] + +Now let's [do the first meaningful action]. + +```python +from import + +result = () +print(result) +``` + +You should see: + +```text +[expected output] +``` + +Notice that [observation about the result]. + +## [Building On It] + +Now that we have [previous result], let's [next step]. + +[... continue building incrementally ...] + +## What We Built + +You have [accomplished concrete thing]. Along the way, you: + +- [Learned concept 1] +- [Used tool/function X] +- [Saw how Y works] + +## Next Steps + +- [How-to guide for a related task](../how-to/something.md) +- [Explanation of a concept encountered](../explanation/concept.md) +- [API reference for the functions used](../reference/api.md) +```text + +## Anti-Patterns to Avoid + +- **Starting with explanation** — Do not open with "X is a framework that…"; open with what they will do +- **Offering choices** — "You can use either A or B" forces a decision; just pick one +- **Assumed knowledge** — Do not skip steps because they seem obvious +- **Wall of code** — Break into small steps, each with visible output +- **Missing output examples** — Every code block needs its expected output +- **Teaching by telling** — Show, do not explain; link to explanation pages instead + +## What a Tutorial Is NOT + +- Not a how-to guide (serves work, not study) +- Not a reference (describes machinery, doesn't guide action) +- Not an explanation (discusses topics, doesn't guide action) +- Not "the basics" — tutorials can be advanced; the distinction is study vs. work diff --git a/template/CONTRIBUTING.md b/template/CONTRIBUTING.md index badc000..75f743a 100644 --- a/template/CONTRIBUTING.md +++ b/template/CONTRIBUTING.md @@ -1,3 +1,29 @@ # Contributing -Please see [docs/contributing.md](docs/contributing.md) for detailed contribution guidelines. +Thank you for your interest in contributing! All contributions - bug reports, fixes, documentation improvements, and feature suggestions - are welcome. + +Please review our [Code of Conduct](CODE_OF_CONDUCT.md) before participating. + +## Quick Setup + +```bash +git clone +cd +uv sync --group dev +uv run pre-commit install +just test-fast +``` + +## Full Guidelines + +For the complete contributing guide - including test strategy, code quality standards, commit conventions, and CI/CD details - see: + +**[Full Contributing Guide](docs/pages/contributing.md)** + +## Reporting Issues + +Found a bug? Have a suggestion? [Open an issue](../../issues/new/choose) and include: + +- Python and uv versions +- Steps to reproduce +- Expected vs. actual behavior diff --git a/template/docs/pages/contributing.md.jinja b/template/docs/pages/contributing.md.jinja index efdc445..bc00553 100644 --- a/template/docs/pages/contributing.md.jinja +++ b/template/docs/pages/contributing.md.jinja @@ -531,6 +531,15 @@ Add a link to your example in `docs/pages/examples.md`: The mkdocs hooks automatically export notebooks to HTML during docs build. All notebooks in `examples/` are automatically discovered and tested by `test_examples.py` using pytest's parametrization feature, which runs them in parallel for fast validation. {% endif %} +## Before You Open a PR + +- [ ] Run `just test-fast` - all fast tests pass +- [ ] Run `just fix` - code is formatted and linted +- [ ] Write or update tests for your changes +- [ ] If you changed docs, run `just serve` and verify they render +- [ ] Use conventional commit messages +- [ ] Keep the PR focused on a single concern + ## Submitting Changes 1. Push your changes to your fork: @@ -586,6 +595,9 @@ The pre-commit hook will validate your commit messages and prevent commits that ## Release Process +!!! note "Maintainers only" + The release process is managed by project maintainers. Contributors do not need to create releases. Open PRs and a maintainer will handle versioning and publishing. + Releases are fully automated through GitHub Actions when a new tag is pushed, with a **manual approval gate** before publishing to PyPI to ensure quality control. ```mermaid