Repo layout convention

August 18, 2026 · View on GitHub

Shared on-disk layout for PyDevices source repos. Missing folders or files are fine when unused — only create what the repo needs.

Directories

DirectoryMeaning
.cursor/Cursor rules and agent notes for this repo
.github/GitHub workflows, issue templates, Actions config
.vscode/Editor / workspace settings committed for the team
src/C sources and headers (native modules)
lib/Python package source (importable package tree)
tests/Unit tests only
tools/Developer tools and smoke / integration helpers (not maintainer publish scripts)
scripts/Maintainer and CI scripts (publish, sync, regen)
docs/Documentation
web/GitHub Pages site (or Pages-related assets)
assets/Static assets (images, fonts, media) for docs, examples, or the site
packages/MIP / GitHub-mip package manifests (.json)

Root files

Keep packaging, build discovery, and short entry points at the repo root. Long-form notes and guides belong under docs/.

KindExamplesStay at root?
Packaging / build metadatapyproject.toml, setup.py, setup.cfg, MANIFEST.in, micropython.mk, circuitpython.mkYes — tooling discovers these at root
Docs site configmkdocs.ymlYes
Short entry scriptsapply_*.sh, build_*.sh, regenerate_*.shYes when they are the public entry point
License / communityLICENSE, README.md, AGENTS.md, CONTRIBUTING.mdYes
Pip requirementsrequirements.txt, requirements-dev.txtYes (see below)
Long-form docsdesign notes, build guides, handoffs, publishing write-upsNo — use docs/

Markdown naming

  • Reserve all-caps Markdown names for conventional repository and community control files such as README.md, AGENTS.md, CONTRIBUTING.md, SECURITY.md, and CHANGELOG.md.
  • Do not add RELEASE_NOTES.md. All three that existed carried a bare ## Unreleased heading, never recorded a shipped version, and were linked from nowhere; they were deleted in August 2026. Releases use --generate-notes, so a hand-maintained file is a second source of truth that goes stale immediately.
  • Name narrative and topic documents under docs/ with lowercase kebab-case, for example building-wheels.md, build-and-flash.md, and soft-reset-and-bring-up.md.
  • Keep generated fixtures and upstream or vendored filenames unchanged when renaming would create needless divergence from their source project. This includes MicroPython's CODEOFCONDUCT.md, SENML's senml_*.md pages, and vendored LVGL translations.
  • Put a document in the repository that owns its subject: product architecture, package behavior, and driver contracts belong with pydevices; application tutorials and gallery integration belong with pydevices-examples; package- specific API documentation belongs with that package.

requirements.txt vs requirements-dev.txt

A plain root requirements.txt means runtime deps needed to run this repo’s product (or to run its primary tool). Use requirements-dev.txt for developer / CI / host tooling.

NameUse for
requirements.txtDependencies required to run the product or primary tool in this repo (e.g. generator needs pycparser)
requirements-dev.txtDeveloper, CI, packaging, or host-only tools (lint, test runners, Jupyter, Playwright, buildozer, wheel/build helpers, editable -e . for local builds)

Do not put a root requirements.txt that only lists tooling — that reads as “install these to use the app,” which is misleading when the product ships via MIP / TestPyPI / wheels / source trees instead.

MkDocs (and similar) stay under docs/requirements.txt, not at the repo root.

Examples:

RepoFileWhy
lvgl-bindingsrequirements.txtGenerator runtime (pycparser)
pydevices-examplesrequirements-dev.txtPlaywright, pytest, Jupyter, ruff, … — not product runtime
lvgl-pythonrequirements-dev.txtLocal editable build / wheel tooling; users install pydevices-lvgl
pydevices-android-templaterequirements-dev.txtHost buildozer/Cython for APK builds — not packaged into the APK
pydevices-pyscript-templatenoneStatic app template; PyScript runtime is vendored only for Pages deployment

Exceptions

  1. pydevices-examples — example applications and gallery utilities live under lib/ (lib/examples/, lib/utils/). Shareable packages belong in their owning product repos, not here.
  2. pydevices — canonical product repo: portable packages under lib/, board configs under board_configs/, hardware drivers under drivers/, and MIP manifests under packages/.
  3. Application templatespydevices-android-template and pydevices-pyscript-template are replaceable host shells, not product package trees.

Notes

  • Prefer headers next to C under src/ (not a separate top-level include/).
  • Do not put non-unit developer tests in tests/ — those belong in tools/.
  • Root build glue may stay at the repo root when discovery requires it (e.g. micropython.mk, setup.py, apply_*.sh entry points).
  • Meta / workspace repos (this .github org repo, PyDevices.github.io, cmods, mip) are not package trees; they follow their own roles and need not mirror every directory above.

Preferred search paths (MICROPYPATH / PYTHONPATH)

On hosted runtimes — CPython, the MicroPython unix and Windows ports, CircuitPython unix — set:

# Linux / macOS (bash)
export MICROPYPATH=".:.frozen:lib:utils:~/.micropython/lib:/usr/lib/micropython"
export PYTHONPATH=".:lib:utils"
REM Windows (cmd.exe)
set MICROPYPATH=.;.frozen;lib;utils;%USERPROFILE%\.micropython\lib
set PYTHONPATH=.;lib;utils

This mirrors the default search order on hosted runtimes and on hardware MCUs — where .frozen, the user's ~/.micropython/lib, and the system /usr/lib/micropython are searched by default — while appending . (the current folder), lib/ (the local workspace), and utils/ (shared dev tools). Custom packages and examples then run from any directory without path conflicts, and installing the CPython micropython.py compatibility shim stays harmless on MicroPython because .frozen resolves first.

Optional by design

The workflow helpers — cmods, mpftp, and the custom MIP index — are all optional. Stock make USER_C_MODULES=..., mpremote, circup, and any standalone IDE work unchanged.