Reference
Contributing
Bug reports, fixes and new features are welcome. TripLibre is small enough to read in an afternoon, and most of the interesting logic lives in a package you can test without a phone.
Development setup
git clone https://github.com/zyang91/TripLibre.git
cd TripLibre
brew install xcodegen swiftlint swiftformat
make test # core tests, no simulator needed
make sim # run the app with demo data
make lint # docs JS/CSS/HTML + accessibility, Markdown, Python, Swift (needs node + ruff)
Changing Swift? make swift-lint runs the same SwiftLint and SwiftFormat checks as CI. SwiftLint only enforces
correctness and VoiceOver rules (.swiftlint.yml); violations that already existed are listed in
.swiftlint-baseline.json, so only new ones fail. If you fix old ones, run make swiftlint-baseline and commit
the updated file. SwiftFormat checks whitespace only (.swiftformat) and never rewrites files in CI.
Changing the docs site? Run npm run lint (or npm run lint:fix) before opening a PR. The HTML check includes
html-validate's accessibility rules: images need alt, buttons need a type and an accessible name, and
aria-label only goes on elements that can carry one. npm run a11y then loads every page in Chromium, in light and
dark theme, and runs axe-core's WCAG 2.1 AA rules against the finished page, including colour contrast and the navigation
docs.js builds (first run: npx playwright install chromium).
Where to make a change
| You want to… | Look in |
|---|---|
| Improve visit / trip / mode detection | Inference/ and InferenceConfig; add a fixture scenario in Tests/HHTCoreTests/InferenceTests.swift |
| Add a correction | Editing/EditService.swift; always write audit_log and set user_status |
| Change the schema | Database/Schema.swift; add a new migration, never edit an old one |
| Add a metric | Analytics/MobilityMetrics.swift, mirrored in analysis/hht.py and docs/analytics.md |
| Add an export column | Export/Exporter.swift; the Python contract check (make export-check) must still pass |
| Change background collection | App/Location/LocationCollector.swift; test on a real device, the simulator can't reproduce it |
| Change a Home Screen widget | Views in Widgets/; data in Widget/WidgetSnapshot.swift (bump currentVersion if its shape changes, and extend WidgetSnapshotTests) |
| Change the UI | App/Screens/, styling in App/Support/Theme.swift |
| Edit these docs | docs/triplibre/docs/*.html; navigation is in docs/assets/docs.js. See Documentation below |
Ground rules
- Never modify raw observations.
raw_location_pointsandmotion_activitiesare append-only. - Never overwrite user corrections. Anything with
user_status ≠ autois locked against inference. - Keep inference deterministic. Same input → same output, and incremental runs must equal one-shot runs.
- No new network calls without discussion. Anything that sends data off the device must be opt-in and documented on the Privacy page.
- No third-party dependencies in
HHTCore. - Thresholds go in
InferenceConfig, not inline.
Proposing an inference test case
Wrong visits, trips and modes are the most useful reports, and the hardest to share safely: the evidence is your
location history. Please never attach an export, a travel.sqlite file, a GPX track or screenshots of
your map to a public issue. Describe the shape of the problem instead, so it can be rebuilt as a synthetic
fixture:
- Describe what happened"Walked 600 m between two buildings, stayed 40 min, took a rideshare for 12 min." Times can be relative ("+0:40"); no addresses or coordinates needed.
- Describe what TripLibre recorded"One 2 h visit, no trip" or "the rideshare was labelled subway". Include the mode confidence and whether the trip showed a gap, if you can see them.
- Add the signal, not the placeIf you're comfortable, read from your own export: roughly how often fixes
arrived, their accuracy (
h_accuracy), speeds, any silences longer than a couple of minutes, and the CoreMotion activity during the problem. - Write or request the fixtureTest cases are written with the synthetic
Trajectorybuilder inPackages/HHTCore/Tests/HHTCoreTests/Fixtures.swift, using its fixed Philadelphia landmarks, and go inCalibrationTests.swiftorInferenceTests.swift. A good fixture fails on the current engine and states the expected visits, trips and modes.
If a real trace is truly needed, share it privately with the maintainer, and only after shifting it far from where it happened, rotating it and offsetting the times. Even then, home and work can sometimes be recovered from the pattern. Accuracy measurements on real data are summarised in aggregate only; see Validation.
Documentation
- The site is plain HTML. Everything in
docs/is published as-is at hhtdiary.org. The organization's pages (home, products, vision, roadmap, about) sit at the top and useassets/site.js; TripLibre's overview isdocs/triplibre/(the same script withdata-brand="triplibre") and these docs aredocs/triplibre/docs/. There is no Markdown build: a.mdfile indocs/is visible on GitHub but not on the site. To add a doc page, copy an existing one and add it toNAVindocs/assets/docs.js. - Say what is true today. Label anything that isn't built yet with a status: Available
In progress Planned
Exploratory (
<span class="status planned">). Don't add dates to plans, and don't call accuracy "research-grade" without a benchmark to point to. - Check against the code. Field names, defaults and file lists should be copied from the source
(
Exporter.swift,Schema.swift,InferenceConfig.swift), not from memory. - Use the project's terms: TripLibre, household travel survey (HHTS), visit, trip, segment, tour, person-day, local-first.
- Use synthetic examples only.
make simandmake export-checkproduce demo data you can quote. - Run
npm run lintandnpm run a11y. A Vercel preview is posted on every pull request that touchesdocs/.
Before opening a pull request
- Run the checks CI runs
make ci - Regenerate the project if you touched
project.yml:make project, and commitHHT.xcodeproj. CI fails if they differ. - Update docs: the markdown specs in
docs/*.mdand these pages if behaviour changed. - Open the PR against
mainwith a short description of what changed and why.
Releases
Released versions are listed in CHANGELOG.md
and on GitHub Releases. Each GitHub release is archived on Zenodo
under one concept DOI, 10.5281/zenodo.23307589. Before tagging
vX.Y.Z, set the same version in all three places, or the archive will be labelled with the old one:
MARKETING_VERSIONinproject.yml(thenmake project)versionanddate-releasedinCITATION.cffversionin.zenodo.json
Then add a section to CHANGELOG.md.
Reporting issues
Use the issue templates for bugs and feature requests.
For a wrong trip or visit, follow proposing an inference test case
above. Don't attach raw exports: they contain your location history. Security problems go through
SECURITY.md, not public issues.
Everyone participating is expected to follow the Code of Conduct.
License
TripLibre is released under the Apache License 2.0.
Contributions are accepted under the same license. The repository has no NOTICE file; if a contribution
brings in third-party code that requires one, add it in the same pull request.