Free, open, machine-readable aircraft checklists and configuration profiles for Part 103, ultralight and experimental aircraft — in formats anyone can consume, reformat, modify and redistribute. Served at openchecklists.net.
The format, the validators, the phone/print renderer, the exporters and the static
site all run today; the OCR pipeline and the contribution flow do not exist yet.
python3 tools/build_site.py produces the whole site from the corpus in examples/.
They are different kinds of thing and deliberately have different formats.
| What it is | Format | Why | |
|---|---|---|---|
| Checklists | Procedures a pilot reads and ticks off, with provenance and a verification state | JSON (schema/) |
A checklist is safety data that must survive conversion to any format and must carry whether a human has checked it. Reasoning in docs/02-format-decision.md |
| Aircraft profiles | How a specific airframe is wired: limits, sensor maps, calibration baselines, unit preferences | TOML (profiles/, spec/aircraft-profile.md) |
A profile is hand-edited hardware configuration for the Junco instrument node, not a document with a source to cite. TOML is the right shape for it |
The web tool at openchecklists.net does both: it generates and validates aircraft profiles, and it renders, forks, prints and exports checklists. Neither is ever required — every file here is hand-editable.
| Aircraft | Profile | Checklists | Status |
|---|---|---|---|
| ParaPlane PM-2 | profiles/pm2/pm2.toml | checklists/pm2/ | Draft. Markdown, not yet converted to the checklist schema — see below |
The PM-2 checklists predate the schema and are still Markdown with - [ ] items.
They carry their "not validated against the PM-2 POH" caveat as prose in a header,
which a consumer cannot act on; converting them to .ocl.json replaces that with a
structured verification state, so the site, the exporters and any other software can
see it. That conversion is the first outstanding task — until it happens those files
are readable by people but invisible to every tool in tools/.
Junco is the open engine and air data sensor
node. This project is the data layer it draws from: profiles tell Junco how a
specific aircraft is wired; checklists give the pilot something to read before and
during flight. The profile format is defined here and consumed by Junco firmware and
the Android app — Junco's spec/aircraft-profile.md redirects here.
Neither project depends on the other to function. Junco accepts hand-written TOML, and the checklists are useful to any pilot with a phone or a printer and no instrument node at all.
| Document | What it covers |
|---|---|
| docs/01-legal-research.md | Copyright doctrine and where the line actually is; product liability, which is the larger risk and was not in the brief; the public-domain lanes; what other collections exist and what happened to them |
| docs/02-format-decision.md | JSON as canonical, with reasoning; four things in the brief I think are wrong; architecture; licensing |
| docs/03-verification-model.md | Two-axis verification, evidence rules, automatic demotion, presentation rules, provenance, contributor warranty, takedown process |
| docs/04-roadmap.md | OCR pipeline design, the site, and a first milestone scoped to be finishable |
| docs/05-product-and-sourcing.md | The phone + log product, why freechecklists.net cannot be bulk-scraped, and where the corpus comes from instead |
| docs/06-community-currency.md | Read this one. Field reports as the way the corpus stays current; what copyright does and does not cover here; where the flight-club analogy holds and where it stops |
| Path | What it is |
|---|---|
| schema/open-checklist-1.0.schema.json | JSON Schema 2020-12. Structural validity, including the conditional rules that make a warning untickable |
| schema/open-checklist-log-1.0.schema.json | Completion log format: what was ticked, when, by whom, against which exact checklist version |
| tools/acquire.py | Public-domain acquisition: Internet Archive discovery, manifest fetch with SHA-256, host allowlist that refuses freechecklists by name |
| sources/public-domain.json | Curated PD source manifest with per-document rights basis and discovery recipes |
| tools/render.py | One JSON in, one self-contained HTML out: phone tick-off, any paper size, log export. Zero external requests |
| tools/validate.py | Reference validator: schema, then the policy rules JSON Schema cannot express |
| tools/validate_log.py | Log validator, including the implied-working-rate check |
| schema/open-checklist-report-1.0.schema.json | Field report format: stale item, transcription error, airframe variation, newer source revision |
| tools/validate_report.py | Report validator. A confirmed defect must demote the file it targets; a live safety concern must travel inside the file |
| tools/test_reports.py | 14 cases covering the demotion and safety-disclosure rules |
| tools/export.py | Converters to json, csv, tsv, md, txt, xml, docx, html — each verified against the safety-preserving export contract |
| tools/build_site.py | Static site generator: filterable catalogue, per-checklist pages, airframe family pages, all download formats, machine catalogue, SHA-256 manifest |
| tools/site_editor.py | The browser editor: create or fork a checklist, saves to browser storage, records lineage automatically |
| tools/airports.py | FAA NASR ingest: 19,426 airports, runways, 37k radio frequencies, into sharded static JSON |
| tools/training.py | 14 CFR part 61 certificate requirements, and progress computed from a logbook |
| tools/site_training.py | Flight training page: free study library plus client-side progress tracking |
| tools/library.py | Full-text BM25 index over 14 public-domain documents, plus a registry of the ones we cannot host |
| tools/site_airports.py | Airport/frequency/weather page, and the Cloudflare Worker weather proxy |
| tools/site_library.py | Troubleshooting search page, projects page, charts page |
| tools/test_library.py | Proves the library's admissibility gate rejects, and that passage ids stay contiguous per document |
| tools/site_pages.py | Branding, landing page, and the privacy / terms / takedown / contribute / contact pages |
| schema/open-logbook-1.0.schema.json | Open pilot logbook format. No interchange standard existed — every product has its own CSV template |
| tools/logbook.py | Validate, total, compute currency, and import/export proprietary CSV |
| tools/test_logbook.py | 26 checks, including the calendar-month currency boundaries |
| tools/diff.py | Semantic diff between two checklists, safety-relevant changes first. --fork diffs a file against its recorded parent |
| tools/test_validate.py | 27 negative cases proving the safety rules fire |
| examples/ | Six checklist files, a worked completion log, two field reports, and an example logbook |
None of these is airworthy. Do not fly behind any of them. Each states this in
its own verification.known_issues.
| File | Why it exists |
|---|---|
faa-generic-sep-ground-operations |
The only one grounded in a source document that was actually read: FAA-H-8083-3C Ch. 2, a US Government work in the public domain. Demonstrates the clean-rights lane |
cessna-172n-normal |
The hard copyright case. Demonstrates the recommended posture for a type whose POH is still protected: procedure as fact, wording the contributor's own, limitations deliberately omitted rather than recalled |
aerolite-103-hirth-f33 |
Part 103, the gap in the brief. Authored rather than transcribed, because Part 103 aircraft are not required to have a flight manual at all. Exercises memory items, warnings, and an emergency section |
beechcraft-t-34a-usaf |
The first real type-specific transcription. From USAF T.O. 1T-34A-1 (1958), a US Government work with no copyright, for a type civilians still fly. 117 tickable items, 27 memory items, unreviewed |
aerolite-103-kawasaki-340-n512jm |
The lineage case. Same airframe as the Aerolite baseline with a different engine, forked with derived_from, showing exactly what the swap forced |
schweizer-sgs-2-33a |
A glider. No engine, a launch phase with no powered equivalent, and emergencies that are entirely about the tow |
There is deliberately no example with rights.status: upstream_reserved,
because the recommendation is that such files must never be published — and the
validator enforces it.
The site is generated, so the deploy target is build/site and not the repository
root. There is no committed index.html at the root, deliberately: a static host
configured to serve the repository root would shadow the generated landing page with
whatever file happened to be sitting there, and the failure mode is a site that looks
fine while serving a stub.
For Cloudflare Pages: build command python3 tools/build_site.py --base-url https://openchecklists.net,
output directory build/site. Add --wx-proxy <worker-url> once the weather Worker is
deployed; without it the weather panel degrades to a link-out rather than breaking.
Everything in the repository is text. The downloaded sources, the generated indexes and the built site are not committed — together they are about 640 MB, and all of them are reproducible from the manifest, which is the point of pinning hashes. A clone gives you the corpus, the schemas and the tooling; these commands give you the rest.
pip install jsonschema # required by every validator
pip install pymupdf # required only by tools/library.py ingest
# The site works with no downloads at all: the checklist pages, editor, exporters
# and policy pages all build from examples/. Airport, weather and search pages
# explain that their data is missing rather than breaking.
python3 tools/build_site.py --base-url https://openchecklists.net
# The full build, including the 640 MB of sources. Takes a while; the NASR
# subscription alone is 249 MB.
python3 tools/acquire.py fetch --all # verifies against the pinned hashes
python3 tools/airports.py ingest sources/documents/faa-nasr-28day/*.zip
python3 tools/library.py ingest sources/documents/*/*.pdf sources/documents/*/*.txt
python3 tools/library.py index-registry
python3 tools/training.py emit
python3 tools/build_site.py --base-url https://openchecklists.net \
--wx-proxy https://ocl-weather.example.workers.devfetch --all verifies rather than downloads for anything already present, and every
asset in the manifest is hash-pinned, so a document that has been silently replaced
upstream reports a MISMATCH instead of quietly entering the corpus. If a source has
genuinely been reissued, that is a decision to make deliberately: check what changed,
then re-pin with --pin.
The NASR data is a 28-day cycle. Once sources/public-domain.json names a cycle older
than the current one, the fetch will 404 — update the URL and the effective date to the
current cycle from the NASR subscription page.
pip install jsonschema
python3 tools/validate.py # validate examples/
python3 tools/validate.py --strict # warnings become errors
python3 tools/validate.py --write-stable # normalise to the stable storage form
python3 tools/test_validate.py # prove the safety rules fire
python3 tools/render.py examples/*.ocl.json --paper kneeboard # -> build/*.html
python3 tools/validate_log.py examples/*.ocl-log.json
python3 tools/validate_report.py # validate field reports
python3 tools/test_reports.py # prove the demotion rules fire
python3 tools/acquire.py discover "NATOPS flight manual" # find PD candidates
python3 tools/acquire.py fetch --all # -> sources/documents/
python3 tools/export.py examples/*.ocl.json --formats all # -> build/downloads/
python3 tools/build_site.py --base-url https://openchecklists.net # -> build/site/
python3 tools/diff.py --fork examples/aerolite-103-kawasaki-340-n512jm.ocl.jsonForking in the editor needs to read the parent file, which browsers block for
file:// pages, so serve the site to use it:
cd build/site && python3 -m http.server 8000editor.html runs entirely in the browser:
- My checklists — saved in browser storage, so work survives closing the tab. Autosaves a draft, and imports/exports the whole library as one file. Never uploaded, which is what makes the privacy policy short and true.
- Fork anything — from the catalogue dropdown, or
editor.html?fork=<id>, or the "Fork this in the editor" button on any checklist page. Lineage and the parent's content hash are filled in for you. - Contribute — downloads the file, saves it locally, and points at the pull-request steps. Deliberately not a direct write: anonymous writes into a safety corpus would defeat the whole verification model.
- Information items structurally cannot be given a response or made tickable, so the rule that matters most cannot be broken by the editing UI.
Ten preset sizes plus a custom size, and a text scale for poor cockpit light: Letter, Legal, A4, A5, A6, kneeboard (5.5×8.5), small kneeboard (4.25×5.5), index card (5×8), small index card (3×5), half-letter landscape.
There is no open interchange standard for pilot logbooks: ForeFlight, LogTen, Garmin
Pilot, MyFlightbook and Safelog each define their own CSV template, so your flight
history is effectively hostage to a vendor. schema/open-logbook-1.0.schema.json is
a documented format your data can live in and be converted out of.
python3 tools/logbook.py validate examples/*.oclb.json
python3 tools/logbook.py totals examples/example-logbook.oclb.json
python3 tools/logbook.py currency examples/example-logbook.oclb.json --on 2026-08-10
python3 tools/logbook.py import mylog.csv --profile foreflight -o out.oclb.json
python3 tools/logbook.py export examples/example-logbook.oclb.jsonThree things it does that proprietary logbooks generally do not:
- The arithmetic is checked. Time buckets are not mutually exclusive — the same hour can be PIC and dual received and night and cross-country — but some relationships must hold. A logbook that accepts day + night greater than total is one you discover is wrong during a checkride.
- Currency is computed in calendar months, not rolling days. §61.57(c) says "the preceding 6 calendar months", which means through the end of that month. Rolling-day implementations give the wrong answer near month boundaries, in the unsafe direction. Tested at the boundary in both directions.
- Import never silently drops a column. Anything the mapper does not recognise is
preserved in
imported_from.unmappedand reported, because a lossy import is how people lose a decade of flying.
Currency output is an aid and says so: it cannot see an IPC, a type-specific requirement, or whether a landing was truly to a full stop.
Both datasets are large, so data/ is gitignored and the site build ships these
pages only when the data is present, explaining itself when it is not.
python3 tools/acquire.py fetch --all --pin # --pin records each hash in the manifest
python3 tools/airports.py ingest sources/documents/faa-nasr-28day/*.zip
python3 tools/library.py ingest sources/documents/*/*.pdf sources/documents/*/*.txt
python3 tools/library.py index-registry
python3 tools/build_site.py --wx-proxy https://ocl-weather.example.workers.dev--pin matters more than it looks: without a recorded hash a later fetch cannot tell
a corrected document from one silently replaced at the same URL, which is exactly how
a stale procedure would enter the corpus unnoticed. Agencies do reissue PDFs in
place. Every asset in the manifest is now pinned, and fetch verifies rather than
merely downloading.
Airports — 19,426 US airports, heliports, seaplane bases, gliderports and ultralight strips from the FAA's 28-day NASR data, including the 14,259 private strips most apps omit. 37,537 frequencies with callsigns and tower hours. The AIRAC effective date is shown on the page and marked SUPERSEDED once a newer cycle exists, because a stale frequency is worse than no frequency.
Weather cannot be done from a static page — aviationweather.gov serves servers
but blocks browser requests, tested and confirmed. worker/weather-proxy.js is a
one-file Cloudflare Worker that fixes it without adding a backend for anything else.
It restricts itself to one upstream host, caches 60 seconds, and logs nothing.
Troubleshooting search indexes the full text of 14 public-domain documents — 13,518 passages across AC 43.13-1B, the AMT General Handbook, the Pilot's Handbook of Aeronautical Knowledge, the Aviation Weather Handbook, the Risk Management Handbook, the Instrument Flying and Weight and Balance handbooks, five ACS documents and the T-34A flight handbook — with BM25 scoring computed in the browser from the same sharded index the CLI uses. A selector limits a search to one document, which is a range test on the passage id rather than an extra fetch, because ingest numbers each document's passages contiguously. It cites, it does not diagnose — every result is a passage with document, revision and page. A generated answer would be the only thing on the site with no provenance, and it is also less useful than the actual text. If an LLM is added later this is the right substrate: retrieve first, summarise these passages with these citations, never answer from memory.
Two bookkeeping properties are load-bearing and invisible in a search result, so
tools/test_library.py asserts them: a document directory holding two renderings of
the same document (the T-34A has both a scan and an OCR text layer) is one
document, deduplicated within itself; and each document's passage ids are contiguous,
without which the per-document filter would attribute one document's text to another.
Both were wrong when the second rendering was first indexed.
Manufacturer and engine manuals are not hosted — they are commercial products, and full-text hosting one is wholesale reproduction rather than transcribing a fact. Instead there is a registry of what you need and where to get it, which is a fact about the world rather than a copy of anything.
training.html does two things. It catalogues what the FAA publishes free — sixteen
handbooks, the ACS documents, the knowledge-test figure supplements, the AIM and the
regulations — because almost everything a student needs is public domain and almost
none of it is easy to find.
Then it does the part nothing free does well: reads a logbook against the aeronautical experience requirements in 14 CFR part 61, for sport, private, instrument, commercial, CFI and ATP. Entirely client-side, so a logbook never leaves the device.
python3 tools/training.py list
python3 tools/training.py requirements private-airplane-sel
python3 tools/training.py progress examples/example-logbook.oclb.json --for private-airplane-selThree rules make it honest, because a student will act on it:
- Every line cites its CFR paragraph. If the tool and the regulation disagree, the regulation wins, and the citation is how you find that out.
- What a logbook cannot answer is left unchecked, not guessed. Whether an airport
had an operating control tower is not a logged field, so that requirement reports
"cannot be determined" rather than failing you. An instructor's endorsement is
listed as
confirm, never counted. - Intersected buckets understate rather than overstate. A logbook records cross-country and PIC hours but not their overlap, so the tool takes the smaller per entry — and says so when carried-forward totals had to be excluded, rather than silently dropping 78.9 hours.
It reports; it does not certify. Eligibility is your instructor's and examiner's call.
Engine swaps, prop changes and panel rebuilds are the norm in this class, so one builder's checklist is most useful to the next when you can see what they changed. Three pieces make that work:
aircraft.airframe_familygroups every variation of one airframe regardless of what is bolted to the front, andaircraft.modifications[]records the swaps themselves so they are searchable.derived_fromrecords lineage by attribution, not inheritance. A forked file stays complete and standalone — a pilot always holds the whole checklist, never a composition resolved at render time — while still linking to its parent and the parent's hash at the time of the fork.tools/diff.pyand the family pages turn that into the thing a builder actually wants to read: what changed, warnings and memory items first.
build_site.py emits a complete static site with no server and no database:
| Path | What it is |
|---|---|
index.html |
Landing page: what the project is, and why not just a PDF library |
catalogue.html |
Filterable catalogue — search by make, model, category, source, engine, modification; filter by verification state |
c/<id>/index.html |
The checklist: tick on a phone, print at any paper size, export a log |
c/<id>/<id>.{json,csv,tsv,md,txt,xml,docx} |
Every download format. Quarantined files carry .UNREVIEWED in the filename |
api/index.json |
Machine catalogue: metadata, verification state and rights per file. No key, no rate limit |
api/checklists/<id>.json |
Stable plain-HTTP path to every file |
manifest.sha256 |
Hash of every published artifact, so a mirror can be verified |
reviewed.txt / unreviewed.txt |
Bundle listings, kept separate on purpose |
airports.html |
19,426 US airports with runways, radio frequencies, fuel and pattern altitude, plus live weather via the Worker proxy |
training.html |
Free FAA study material, and progress toward a certificate computed from your logbook in the browser |
search.html |
Troubleshooting search over 14 public-domain documents, filterable to one. Cites passage, document and page — never diagnoses |
charts.html |
Where to get official FAA charts and plates, and why this project links rather than republishes |
projects.html |
The open source projects that produce or consume these formats |
worker/weather-proxy.js |
One-file Cloudflare Worker. Live weather needs it: aviationweather.gov blocks browser requests |
editor.html |
Create a checklist or fork any in the catalogue. Client-side, no account. Forking fills in lineage and computes the parent hash in the browser |
f/<family>/index.html |
Every variation of one airframe, with each fork's diff from its parent inline |
about.html |
What the verification states mean, and why "flown behind it" is not the top one |
privacy.html terms.html takedown.html contribute.html contact.html |
Policy pages. The privacy policy is short because the site genuinely collects nothing |
manifest.webmanifest sw.js icon-*.png |
Installable on a phone, and precached so it works with no signal |
Open a rendered file on a phone: tick items, choose a paper size, print, export a log. It makes no network requests, so it works in a hangar with no signal.
Detail and reasoning in the documents; summarised here so they are not buried.
-
Product liability is the bigger risk than copyright. US courts have repeatedly treated aeronautical charts as products subject to strict liability, and Winter v. G.P. Putnam's Sons refused to extend that to a book specifically because a chart is a tool used in flight. A checklist is on the chart side of that line. No licence or disclaimer addresses it. Research report §2.
-
A repo-wide CC-BY-4.0 over the corpus would assert a licence the project does not hold. You cannot license text you do not own, and the harm compounds silently as the corpus grows. Rights must be per file. Research report §1, format decision §4.
-
"Verified — someone flew behind it" is the wrong top state. Flying behind a checklist cannot detect a dropped item, which is the most likely and most dangerous transcription defect: nothing prompts you to do the missing check, so the flight feels normal. Two independent axes instead of one ladder, and operational review never lifts a file out of quarantine. Verification model §1.
-
"Publish a JSON Schema so anyone can validate" is a promise that cannot be kept. Reviewer independence, dual-review distinctness, hash staleness, and reference resolution are not expressible in JSON Schema. Without a published policy layer, third-party validators will green-light files the corpus forbids. Format decision §2.1.
Plus one finding that changes the pipeline: a perfect transcription of the wrong document passes every accuracy check. Searching for a Piper J-3 POH surfaced a flight-simulator manual containing a plausible checklist, © 2009, marked "not intended for flight." Source admissibility has to be a separate gate before transcription, and for older types it will be the common case. Research report §3.4.
- efis-editor's data model was read from a local clone, not from documentation.
It is a presentation model with no phase ids, no provenance, and no verification;
its item types map cleanly onto the proposed set. Its format layer imports no
Angular and depends on
window.cryptoin two files only, so a headless Node harness is viable — but it has nobinand nomain, so it is not a library and this is days of work, not an afternoon. Research report §3.1. - The FAA source was downloaded and its text extracted directly.
- Junco's licensing was read from its
LICENSEfiles.GPL-2.0-or-laterfor code,CC-BY-4.0for specs. The "or later" matters: Apache-2.0 is incompatible with GPL-2.0-only, so it is what makes efis-editor's code reachable from Junco at all. Format decision §4. - The validator's negative cases were run; all 27 fire.
- No case law on aircraft checklists specifically, in either direction, and no evidence of any free checklist repository being taken down by a manufacturer. The observed failure mode of prior projects is attrition, not enforcement. Low enforcement is worth knowing and is not a safe harbour.
- freechecklists.net returned HTTP 503 on both attempts, so its terms of use were not read. Confirm before treating anything there as a source.
- No freely available Part 103 or ultralight checklist was found for any type. This corroborates the gap in the brief and has a structural cause: Part 103 aircraft need no approved flight manual, so there is often no source document to transcribe. Research report §3.5.
In docs/04-roadmap.md §5. The one that should be answered first is whether you will form an entity before the corpus grows, because the liability exposure is personal until you do.
| Project | What it does |
|---|---|
| Junco | Open engine and air data node. Reads aircraft profiles from this library |
| Nuthatch | Open single-seat ultralight aircraft design |
Rights are recorded per file, not repository-wide. Tooling, schemas and
documentation written for this project are freely reusable; each checklist file
carries its own rights block naming its source and basis, and the validator
refuses to publish any file whose rights are unresolved or upstream_reserved.
A blanket CC-BY-4.0 over the corpus would assert rights the project does not hold: a transcription of a manufacturer's procedure is not ours to license out, and a US Government work is already in the public domain and needs no licence from us. The reasoning is in docs/01-legal-research.md and docs/02-format-decision.md.
The aircraft profiles and the PM-2 checklists were authored for this project and are CC-BY-4.0.
Correction reports are the most useful contribution, and the format has a place to put them: a field report can demote a file's verification state, which a comment thread cannot. See docs/06-community-currency.md and the contribute page on the site.
The single most valuable thing anyone can do is take one checklist and check it
against its source document, because that is the one thing the tooling cannot do for
itself. The catalogue currently reports reviewed: 0.
If you add a new aircraft profile, copy an existing one as a template and verify it against your aircraft's documentation.