|
| 1 | +# AGENTS.md — Repository Best Practices |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +**Open Executable Books in Robotics** is a collection of Jupyter notebooks teaching kinematic modelling and control of serial-link robotic manipulators. The project is licensed under [CC-BY-NC-SA 4.0](LICENSE) and hosted at <https://github.com/MarinhoLab/OpenExecutableBooksRobotics>. |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## Repository Structure |
| 10 | + |
| 11 | +| Path | Purpose | |
| 12 | +|------|---------| |
| 13 | +| `basic_lessons/` | Canonical source: `.ipynb` notebooks (5 tutorials + 5 exercise answer keys) | |
| 14 | +| `unstable/` | Work-in-progress text-only MyST notebooks (`.md` with `{code-cell}` directives) | |
| 15 | +| `other/` | Supplementary content (e.g. `dqrobotics.md`) | |
| 16 | +| `convert_to_myst.py` | Script: converts `basic_lessons/*.ipynb` → `unstable/*.md` | |
| 17 | +| `myst.yml` | MyST project config (root): LaTeX macros, TOC, site options | |
| 18 | +| `unstable/myst.yml` | MyST project config (unstable): mirrors root with adjusted paths | |
| 19 | +| `build_html.sh` | Build script for `jupyter-book` (legacy pipeline) | |
| 20 | +| `conf.py` | MyST parser extensions (`dollarmath`) | |
| 21 | +| `_build/` | Build artifacts (excluded from git via `unstable/.gitignore`) | |
| 22 | + |
| 23 | +--- |
| 24 | + |
| 25 | +## Modifying `.ipynb` Files |
| 26 | + |
| 27 | +Jupyter notebooks are JSON files. Every cell's `source` field is a **list of strings**, where **each string must end with `\n`** (trailing newline). This is critical: |
| 28 | + |
| 29 | +### Correct format (renders properly in Jupyter): |
| 30 | +```json |
| 31 | +"source": [ |
| 32 | + "# L1 A quick Python refresher\n", |
| 33 | + "\n", |
| 34 | + "*License: CC-BY-NC-SA 4.0*\n", |
| 35 | + "\n", |
| 36 | + "### Prerequisites\n", |
| 37 | + "The user of this notebook is expected to have prior knowledge in\n" |
| 38 | +] |
| 39 | +``` |
| 40 | + |
| 41 | +### Broken format (renders as one concatenated line): |
| 42 | +```json |
| 43 | +"source": [ |
| 44 | + "# L1 A quick Python refresher", |
| 45 | + "", |
| 46 | + "*License: CC-BY-NC-SA 4.0*", |
| 47 | + "" |
| 48 | +] |
| 49 | +``` |
| 50 | + |
| 51 | +### When editing notebooks programmatically: |
| 52 | +1. Load with `json.load()`, modify `cell['source']` entries. |
| 53 | +2. **Every source line must end with `\n`** before writing back. |
| 54 | +3. Save with `json.dump(nb, f, indent=1)` (single-space indent is standard). |
| 55 | +4. Clear execution state on code cells to avoid stale output: |
| 56 | + ```python |
| 57 | + cell['outputs'] = [] |
| 58 | + cell['execution_count'] = None |
| 59 | + ``` |
| 60 | + |
| 61 | +### When editing notebooks manually: |
| 62 | +- Use a notebook editor (Jupyter, VSCode, or nbconvert) rather than raw text edits. |
| 63 | +- If editing raw JSON, always verify trailing `\n` on source lines. |
| 64 | + |
| 65 | +### Cell types: |
| 66 | +| Type | Purpose | |
| 67 | +|------|---------| |
| 68 | +| `markdown` | Text, equations, images, headings | |
| 69 | +| `code` | Python cells (numpy, math) | |
| 70 | +| `raw` | Raw LaTeX macro definitions (`\providecommand`) | |
| 71 | + |
| 72 | +### LaTeX macros: |
| 73 | +Custom macros (`\myvec`, `\mymatrix`, `\quat`, `\dual`) are defined in two places: |
| 74 | +1. As **raw cells** in each notebook (for Jupyter/LaTeX rendering) |
| 75 | +2. In **`myst.yml`** under `project.math` (for MyST rendering) |
| 76 | + |
| 77 | +--- |
| 78 | + |
| 79 | +## Converting to MyST Text Notebooks |
| 80 | + |
| 81 | +Run the converter script to regenerate `unstable/*.md` from the canonical notebooks: |
| 82 | + |
| 83 | +```bash |
| 84 | +python3 convert_to_myst.py |
| 85 | +``` |
| 86 | + |
| 87 | +This script: |
| 88 | +- Copies images (`Lesson4.png`, `Lesson4.svg`) to `unstable/` |
| 89 | +- Converts markdown cells as-is, code cells as ` ````{code-cell}```` directives |
| 90 | +- Strips raw cells and LaTeX macro markdown cells (handled by `myst.yml`) |
| 91 | +- Fixes `attachment:` image syntax → plain relative paths |
| 92 | +- Handles both trailing-newline and no-trailing-newline source formats |
| 93 | + |
| 94 | +--- |
| 95 | + |
| 96 | +## Building & Testing |
| 97 | + |
| 98 | +### Dependencies |
| 99 | + |
| 100 | +```bash |
| 101 | +# Create venv |
| 102 | +python3 -m venv venv |
| 103 | +source venv/bin/activate |
| 104 | + |
| 105 | +# For MyST text notebook builds: |
| 106 | +pip install mystmd jupyter-server ipykernel |
| 107 | + |
| 108 | +# For legacy jupyter-book builds: |
| 109 | +pip install jupyter-book --pre |
| 110 | +``` |
| 111 | + |
| 112 | +### Build Commands |
| 113 | + |
| 114 | +**MyST build (unstable/):** |
| 115 | +```bash |
| 116 | +cd unstable |
| 117 | +myst build --execute --html |
| 118 | +``` |
| 119 | +- `--execute` runs all code cells and caches results in `_build/execute/` |
| 120 | +- `--html` produces HTML output in `_build/html/` |
| 121 | +- Site format (JSON) goes to `_build/site/` |
| 122 | + |
| 123 | +**Legacy jupyter-book build (root):** |
| 124 | +```bash |
| 125 | +chmod +x build_html.sh |
| 126 | +./build_html.sh |
| 127 | +``` |
| 128 | +- Requires `BASE_URL` env variable for correct link resolution |
| 129 | +- Outputs to `_build/html/` |
| 130 | + |
| 131 | +### CI/CD |
| 132 | + |
| 133 | +The GitHub Actions workflow (`.github/workflows/notebook_to_html.yml`) runs on pushes/PRs to `main`: |
| 134 | +1. Runs `./build_html.sh` (jupyter-book pipeline) |
| 135 | +2. Uploads `_build/html/` as Pages artifact |
| 136 | +3. Deploys to GitHub Pages |
| 137 | + |
| 138 | +**Timeout:** 5 minutes. Keep cells fast to avoid CI failures. |
| 139 | + |
| 140 | +--- |
| 141 | + |
| 142 | +## Content Conventions |
| 143 | + |
| 144 | +### Notebook header format (every tutorial): |
| 145 | +```markdown |
| 146 | +# LN <Title> |
| 147 | +*License: CC-BY-NC-SA 4.0* |
| 148 | + |
| 149 | +*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* |
| 150 | + |
| 151 | +## Prerequisites for the learner |
| 152 | +The user of this notebook is expected to have prior knowledge in |
| 153 | +- All the content and prerequisites of lessons X. |
| 154 | + |
| 155 | +## I found an issue |
| 156 | +Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues |
| 157 | +``` |
| 158 | + |
| 159 | +### Equation macros: |
| 160 | +- `\myvec{q}` for vectors |
| 161 | +- `\mymatrix{H}` for matrices |
| 162 | +- `\quat{}` for quaternions |
| 163 | +- `\dual{}` for dual numbers |
| 164 | + |
| 165 | +### Image references: |
| 166 | +- In `.ipynb`: `` (relative to `basic_lessons/`) |
| 167 | +- In `.md` (unstable): same — images are copied to `unstable/` |
| 168 | +- Avoid `attachment:` prefix in MyST notebooks |
| 169 | + |
| 170 | +### Language: |
| 171 | +- **UK English** spelling (e.g. *behaviour*, *modelling*, *summarised*) |
| 172 | +- Angles in **radians**, lengths in **meters** |
| 173 | + |
| 174 | +--- |
| 175 | + |
| 176 | +## Git Workflow |
| 177 | + |
| 178 | +- **Main branch:** `main` |
| 179 | +- **Never push directly to `main`** — always use feature branches and PRs |
| 180 | +- Feature branch naming: `fix/<short-description>` or `feat/<short-description>` |
| 181 | +- Example: `fix/typos-and-uk-english`, `feat/add-lesson6` |
| 182 | + |
| 183 | +### Files excluded from version control: |
| 184 | +- `venv/` — Python virtual environment |
| 185 | +- `_build/` — Build artifacts (both root and `unstable/`) |
| 186 | +- `unstable/.gitignore` already excludes `unstable/_build/` |
| 187 | + |
| 188 | +--- |
| 189 | + |
| 190 | +## Adding a New Lesson |
| 191 | + |
| 192 | +1. Create `basic_lessons/lesson<N>_tutorial.ipynb` and `basic_lessons/lesson<N>_exercise_answers.ipynb` |
| 193 | +2. Follow the header format convention above |
| 194 | +3. Add LaTeX macro raw cell (or markdown cell with `vscode` language metadata) |
| 195 | +4. Update `myst.yml` → add new file to `project.toc` list |
| 196 | +5. Run `python3 convert_to_myst.py` to regenerate `unstable/` |
| 197 | +6. Update `unstable/myst.yml` → add new `.md` file to TOC |
| 198 | +7. Test: `cd unstable && myst build --execute --html` |
| 199 | +8. Open PR with descriptive title and body |
0 commit comments