Skip to content

Commit 2e2cfba

Browse files
Add AGENTS.md with repository best practices
Documents how to modify .ipynb files (trailing newline requirement), MyST conversion, build/testing commands, content conventions, and git workflow.
1 parent f116037 commit 2e2cfba

1 file changed

Lines changed: 199 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
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`: `![alt](Lesson4.png)` (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

Comments
 (0)