Build inspectable SD → HD-lite road graphs from trajectories, OSM, LiDAR, and camera data — and read them in a map console.
roadgraph_builder is a graph-first toolkit. It is not an autonomous-driving stack and not a survey-grade HD-map generator. It builds an SD road graph from GPS / OSM input, lets you route / reach / snap on it, enriches it with HD-lite lane / regulatory / elevation overlays, and exports it as navigation JSON / simulation GeoJSON / Lanelet2 OSM XML. A static browser console renders every layer from committed sample data with no build step.
Open it: Map console · Showcase · Architecture · Benchmarks · Launch notes · Changelog · Contributing
- Autoware users — produce small Lanelet2 smoke maps from SD / trajectory inputs before survey-grade mapping.
sanitize-lanelet2-autowarewrites stock-loader-friendlylanelet2_map.osm+map_projector_info.yaml;validate-lanelet2bridges Autoware'slanelet2_validationCLI when on PATH. - OSS developers — pure-Python (numpy + jsonschema) CLI / library covering routing (A* / Dijkstra + turn restrictions + slope-aware + lane-change), reachability, map matching (HMM), HD-lite enrichment, schema validation, and three-way export. Heavy deps (
laspy[lazrs], OpenCV) stay in[extras]. - Researchers / educators — reproduce SD graph, HD-lite overlays, Lanelet2 output, and routing diagnostics on four committed city samples (Paris 20e grid, Berlin Mitte, Tokyo Ginza, San Francisco North Beach) without fetching live data; benchmark baselines, accuracy reports, and float32 drift studies are committed alongside.
Scope — HD-lite, not survey-grade. The pipeline produces Lanelet2-compatible OSM XML that Autoware's
lanelet2_validationcan load (the rich Roadgraph export, e.g.docs/assets/map_paris_grid.lanelet.osm); for stock Lanelet2 / Autoware loader smoke tests,sanitize-lanelet2-autowarerewrites it into a conservativelanelet2_map.osmplus optionalmap_projector_info.yaml. Lane widths are centerline-offset envelopes (default 3.5 m), lane counts fall back to 1 without paint observations, regulatory overlays are OSM-derived or sample-grade detections, and elevation is SRTM- or trajectory-derived when available. Real vehicle deployment still requires calibrated sensors, cm-class validation, and per-area QA beyond what this tool guarantees. Side-by-side numbers against Autoware's Kashiwanoha survey-HD sample (3 456 lanelets / km² vs our 232–544,eleon 100 % of nodes vs our 5–8 %, surveyed paint vs centerline offsets) and an Autoware-component-by-component "will it simulate?" matrix live indocs/AUTOWARE_HD_MAP_COMPARISON.md. TL;DR: the strictlanelet2.io.load+autoware_lanelet2_validationgates pass on all four committed cities, and v0.7.4+ now also emitstype=stop_lineways (attached asref_lineto traffic_light regulatory_elements where they share an edge) andsubtype=crosswalklanelets — schema thebehavior_velocity_plannertraffic_light / crosswalk modules walk.right_of_way(unsignalised intersections) and the Autoware-extension-only standalonesubtype=stop_lineregulatory_element are still not emitted.
v0.7.4 ships a signed diverging Slope mode (blue down / grey flat / red up,
with degrees + percent grade in popup and hover card) and CLI flags
match-trajectory --hmm-outlier-weight / --hmm-outlier-scale-m for the
Gaussian / Cauchy emission mixture (see
docs/hmm_mixture_calibration.md;
defaults stay byte-identical to v0.7.3). Layered over the v0.7.2
Autoware-friendly Lanelet2 hardening.
| Signal | Current result | Source |
|---|---|---|
| Routing | Paris TR-aware route 909 m vs unrestricted 878 m; the map console has 2D OSM + 3D graph views and route --explain compares A* with Dijkstra fallback work |
map · diagnostics compare · JSON |
| Accuracy | Lane-count MAE @ 20 m: Paris 0.938 / Tokyo 0.903 / Berlin 1.220 | accuracy report |
| Tuning | Conservative cross-city start: --max-step-m 40 --merge-endpoint-m 8 |
tuning guide |
| Memory | Default remains float64; float32 is opt-in after replay showed small RSS wins and ID drift | float32 report |
The toolbar's Mode select walks through the pipeline tiers on any committed dataset. Same data, four progressively richer views:
| Tier | What is drawn | What proves it |
|---|---|---|
| Basic | Centerlines coloured by OSM highway class (motorway → red through residential → cyan) + graph nodes coloured by junction type (T / Y / crossroads / X / complex / through-or-corner / dead-end) |
build-osm-graph + pipeline.junction_topology — bare SD graph, topology-honest, 855 nodes / 1 081 centerlines for the Paris bbox. |
| SD | + directed-state route (JS Dijkstra honouring OSM no_* / only_*) + turn restriction markers |
Paris n312 → n191 is 909 m / 11 edges / 8 TR honoured (the unrestricted shortest path is 878 m, a 31 m detour). Berlin Mitte, Tokyo Ginza, and San Francisco North Beach ship the same route / restrictions / reachability overlay pattern. |
| HD | + HD-lite lane boundaries (green / purple dashes from enrich --lane-width-m 3.5) + OSM-derived traffic lights / stop lines / crosswalks + 500-600 m reachability spans |
Paris ships 456 OSM regulatory markers; San Francisco ships 876 regulatory markers plus 1 800 SRTM-backed elevation nodes for slope-aware inspection. Same overlays apply-camera and reachable produce from the CLI. |
| Full | Everything above | Default when the viewer opens; click Reach from click to pick any node and recompute reachability live in the browser. |
| Slope | + every centerline recoloured by signed hd.slope_deg (blue downhill → grey flat → red uphill), 3D scene lifted by polyline_z with 6× exaggeration |
San Francisco North Beach surfaces 290 uphill / 315 downhill / 1 622 flat (|slope| < 0.5°) edges out of 2 227 — both ramp ends light up at the same time so the hill direction reads at a glance. Hover popups add slope: ±X.XX° (±YY.Y%, uphill / downhill / flat). |
| Lanelet2 | Downloadable per-lane OSM XML for Autoware tooling | docs/assets/map_paris_grid.lanelet.osm — 1 485 lanelets / 2 397 regulatory elements, including directed lane_connection predecessor / successor pairs, emitted by export_lanelet2_per_lane() after infer_lane_counts. Use sanitize-lanelet2-autoware for a stock-loader smoke profile. HD-lite envelopes, not survey-grade. |
The inspector on the right is driven by the same data: Road classes (9 categories), Junctions (T / Y / crossroads / …), Route steps (edge id · direction · cumulative m), and a Route engine card whose expanded / queued / pops fields use the same diagnostics shape as the CLI's route --explain. Hovering a centerline or node in 2D or 3D updates a Hover card with Edge · Primary · 3 lanes · max 50 km/h style detail.
Run the console locally — no build step, just a static server:
cd docs && python3 -m http.server 8765
# http://127.0.0.1:8765/map.html
# ?dataset=paris_grid (default) | berlin_mitte | tokyo_ginza | sf_north_beach | paris | osm | toy
# ?view=2d | 3d
# ?mode=basic | sd | hd | full | slope (centerline palette tier; slope = signed diverging)
# ?from=n312&to=n191 (deep-link route, auto-fits map bounds)
#
# Deep-link straight into the SF slope hero used above:
# http://127.0.0.1:8765/map.html?dataset=sf_north_beach&view=3d&mode=slopeThe animated hero, the two static PNGs, and the diagnostics screenshot are regenerated by scripts/record_map_console_hero.py / scripts/render_map_console_screenshot.py / scripts/render_route_diagnostics_screenshot.py — all three drive system Chrome through Playwright and pull OSM tiles, Leaflet, and Three.js over the network. OSM-derived asset attribution is tracked in docs/assets/ATTRIBUTION.md.
Use the short description and topics listed in .github/ABOUT.md, or run the gh repo edit command there after the repository is public.
| Area | Highlights |
|---|---|
| Input | Trajectory CSV · OSM highway ways · LAS 1.0–1.4 / LAZ point clouds · pixel detections + camera calibration · raw RGB for lane-marking detection |
| Pipeline | Gap segmentation → arc-length Gaussian centerline → X/T-split + union-find → duplicate / near-parallel merge → junction consolidation; topology-honest OSM path via build-osm-graph; 3D elevation when build --3d; incremental update-graph; parallel process-dataset |
| Routing | A* / Dijkstra with no_* / only_* turn restrictions + route --explain diagnostics; uncertainty / slope / lane-change variants; RoutePlanner + ReachabilityAnalyzer; guidance turn-by-turn |
| Perception / LiDAR | project-camera (Brown-Conrady distortion) + apply-camera + detect-lane-markings-camera; fuse-lidar with --ground-plane RANSAC + detect-lane-markings from intensity |
| HD / Lanelet2 | enrich --lane-width-m envelopes, infer-lane-count, export-lanelet2 --per-lane, sanitize-lanelet2-autoware loader-smoke profile, validate-lanelet2-tags + validate-lanelet2 Autoware bridge |
| Output / Bench | JSON (+ schema), GeoJSON, OSM XML 0.6, SVG, one-shot export-bundle; make bench deterministic suite with 3× regression gate (baseline + memory + accuracy reports under docs/) |
| Demo / Samples | Map console + diagrams; four committed cities (Paris / Berlin / Tokyo / SF) + toy + OSM-public CSV samples |
Full module index, command surface, and Mermaid diagrams in docs/ARCHITECTURE.md.
The latest shipped tag is v0.7.4. It keeps the full v0.6 / v0.7 command surface (lane-count inference, per-lane Lanelet2 export, uncertainty / slope / lane-change routing, camera lane detection, ground-plane LiDAR, Autoware validator bridging, incremental updates, dataset batch export) and adds the signed Slope mode + CLI HMM mixture flags described above. See CHANGELOG.md for the exact delta.
# Contributor install (editable, drives `make test` and the CLI).
python3 -m venv .venv && .venv/bin/pip install -e .
# Evaluator install (no clone needed; pulls the v0.7.4 tag directly from GitHub).
python3 -m venv .venv && .venv/bin/pip install \
"roadgraph-builder @ git+https://github.com/rsasaki0109/roadgraph_builder@v0.7.4"
# Either install gives you the same CLI entry point.
.venv/bin/roadgraph_builder doctor
.venv/bin/roadgraph_builder build examples/sample_trajectory.csv out.json
.venv/bin/roadgraph_builder enrich out.json out_hd_envelope.json
.venv/bin/roadgraph_builder validate out_hd_envelope.jsonPyPI publishing is intentionally skipped for this cycle. The VCS install above is the supported "no clone" path; the GitHub Release tarball under releases is the audited artifact.
From the repo root, make doctor, make demo, make tune (bundle + validate for parameter exploration), and make test are shortcuts (see Makefile). Opt-in suites: make viewer-smoke runs the Playwright / system Chrome smoke for docs/map.html, pytest -m slow the long perf regressions, and pytest -m city_scale the real-OSM fetch tests. Tuning workflow: docs/bundle_tuning.md.
build and export-bundle accept repeated --extra-csv PATH to concatenate extra trajectory CSVs that share the primary input's meter origin. Overlapping passes get fused (duplicate / near-parallel merge); non-overlapping passes land as independent polylines. attributes.direction_observed on each edge flips to bidirectional when at least one pass traversed the edge in the opposite direction.
roadgraph_builder build examples/sample_trajectory.csv out.json \
--extra-csv examples/another_pass.csv \
--extra-csv examples/yet_another_pass.csv日本語: ナビ向け SD シード、シミュ用の フルグラフ+GeoJSON、Lanelet 互換 OSM を、いまあるパイプラインで一括書き出します(完成品 HD ではなく、同じ土台を三系統に分ける)。
# WGS84 origin: either pass --origin-json (lat0/lon0 file) or --origin-lat / --origin-lon
roadgraph_builder export-bundle examples/sample_trajectory.csv ./out_bundle \
--origin-json examples/toy_map_origin.json \
--lane-width-m 3.5 \
--detections-json examples/camera_detections_sample.jsonFor very large bundles, add --compact-geojson to write sim/map.geojson without pretty indentation, and --compact-bundle-json to compact nav/sd_nav.json, sim/road_graph.json, and manifest.json. Defaults remain pretty-printed so frozen release bundles and human diffs stay stable.
One-shot demo (validates detections, runs bundle, validates manifest + sd_nav + road_graph):
./scripts/run_demo_bundle.sh /tmp/my_bundleParameter tuning (same export-bundle, fewer extras; open sim/map.geojson in QGIS and adjust max-step-m / merge-endpoint-m — see docs/bundle_tuning.md):
make tune
# or: ./scripts/run_tuning_bundle.sh /tmp/my_tune| Output | Role |
|---|---|
out_bundle/manifest.json |
Provenance — tool version, UTC time, origin, input basename, output paths. roadgraph_builder_version and generated_at_utc are dynamic; the remaining fields are treated as stable release output. |
out_bundle/nav/sd_nav.json |
SD / routing seed — topology + edge length_m; allowed_maneuvers / allowed_maneuvers_reverse are geometry heuristics at the digitized end/start node (straight, and at junctions/dead-ends left/right/u_turn when inferred) |
out_bundle/sim/ |
Simulation / viz — road_graph.json, map.geojson, trajectory.csv |
out_bundle/lanelet/map.osm |
Lanelet / JOSM — OSM XML (with lanelets when L/R boundaries exist) |
Use --lane-width-m 0 to skip HD-lite ribbon offsets. Origin must match your GeoJSON / Lanelet convention (see examples/*_origin.json). Validate manifest.json with roadgraph_builder validate-manifest (roadgraph_builder/schemas/manifest.schema.json) and nav/sd_nav.json with roadgraph_builder validate-sd-nav (sd_nav.schema.json).
Release stability policy: the default sample bundle is rebuilt in tests and
stable generated files are compared byte-for-byte with
examples/frozen_bundle/. manifest.json is
compared after normalizing only roadgraph_builder_version and
generated_at_utc; any other manifest drift is treated as a release-surface
change.
allowed_maneuvers is not a legal turn-restriction layer. It is a permissive 2D topology hint for routing/display; signs, signals, and turn bans should be carried in optional turn_restrictions. Design note: docs/navigation_turn_restrictions.md.
| Resource | URL |
|---|---|
| Local viewer | docs/map.html (primary), docs/diagram.html (SVG viewer + route diagnostics), docs/index.html (redirects to map.html) — serve with cd docs && python3 -m http.server 8765 |
| Changelog | CHANGELOG.md |
| Plan / handoff | docs/PLAN.md |
| PyPI | Not published by default; see PyPI (optional) |
scripts/refresh_docs_assets.py— setROADGRAPH_REPO_URLandROADGRAPH_PAGES_URLbefore running to rewritedocs/assets/site.json(footer links in the viewer).scripts/fetch_osm_trackpoints.py— setROADGRAPH_USER_AGENTor pass--user-agent(OpenStreetMap policy).
- Graph first — road = nodes + edges; centerlines / boundaries are attributes on the graph, not its definition.
- Multi-modal — trajectory, LiDAR, and camera inputs are swappable modules; fusion is an explicit later stage.
- SD seed → HD-lite —
buildmakes the SD graph;enrich/fuse-lidar/apply-camera/convert-osm-restrictionslayer on HD-lite envelopes, lane counts, semantics, and turn restrictions;export-lanelet2 --per-lanewrites Autoware-compatible OSM XML. Not cm-class survey HD.
日本語で一言: SD の「道路のつながり+中心線」中間表現として使える。 HD に必要なレーン境界・高精度・規則は別データ (LiDAR 等) を足す前提。
Full SD→HD stage table, module index, and architecture diagrams in docs/ARCHITECTURE.md.
The docs/ folder is a small static site. This repository is currently private; on the current GitHub plan, private-repo GitHub Pages is not available, so the supported preview path is local.
Local preview (no GitHub required):
cd docs && python3 -m http.server 8765
# http://127.0.0.1:8765/ — diagram viewer
# http://127.0.0.1:8765/map.html — 2D/3D OSM map console + GeoJSONWhen Pages is available, point Settings → Pages → Deploy from a branch at main / /docs; the published map.html is the same OSM + 3D graph console with the same ?view / ?dataset / ?mode / ?from / ?to deep links. Committed datasets:
- Paris grid (default, 855 nodes / 1081 edges, 10 OSM turn restrictions, 500 m reachable)
- Berlin Mitte (1883 / 2063, 17 restrictions, 600 m reachable, Lanelet2 download)
- Tokyo Ginza (548 / 598, 19 restrictions, OSM regulatory nodes, Lanelet2 download)
- San Francisco North Beach (1800 / 2227, 127 restrictions, SRTM slopes, Lanelet2 download)
- Paris / OSM Berlin sample / Toy — older trajectory-derived samples
All city datasets are ODbL.
Regenerate bundled JSON/CSV/SVG for docs/ after changing examples or pipeline logic:
python3 scripts/refresh_docs_assets.py- Python 3.10+
numpy,jsonschema(for validating exported JSON)
From the repository root (use a virtual environment on PEP 668–managed systems):
python3 -m venv .venv
.venv/bin/pip install -e .The file examples/osm_public_trackpoints.csv is real, publicly contributed GPS data fetched from the OpenStreetMap API (/api/0.6/trackpoints). It is intended for tuning build / visualize on noisy trajectories.
- License / attribution: OpenStreetMap data is © OpenStreetMap contributors and available under the Open Database License (ODbL). See openstreetmap.org/copyright.
- Regenerate (optional; requires network): set a fork-specific agent if needed, then run:
export ROADGRAPH_USER_AGENT='myfork/1.0 (+https://github.com/you/roadgraph_builder)'
python3 scripts/fetch_osm_trackpoints.py -o examples/osm_public_trackpoints.csvAlso writes examples/osm_public_trackpoints_origin.json (WGS84 origin for the meters CSV) and examples/osm_public_trackpoints_wgs84.csv (timestamp,lon,lat) for map tooling.
Try another area if the bbox has no uploads: --bbox min_lon,min_lat,max_lon,max_lat (each side ≤ 0.25°).
Example (defaults are fine; starting point for the committed OSM sample):
roadgraph_builder build examples/osm_public_trackpoints.csv osm_graph.json \
--max-step-m 40 --merge-endpoint-m 12 --centerline-bins 32
roadgraph_builder visualize examples/osm_public_trackpoints.csv osm_preview.svg \
--max-step-m 40 --merge-endpoint-m 12 --centerline-bins 32Long-form per-subcommand walkthrough lives in docs/USAGE.md: build / enrich / fuse-lidar / detect-lane-markings / match-trajectory / route + reachable + guidance / export-lanelet2 + sanitize-lanelet2-autoware / build-osm-graph + convert-osm-restrictions / project-camera + apply-camera / validate* / make bench / CI parity. Short form below.
# Smallest end-to-end: build → enrich → validate.
roadgraph_builder build examples/sample_trajectory.csv out.json
roadgraph_builder enrich out.json out_hd.json --lane-width-m 3.5
roadgraph_builder validate out_hd.json
# Three-target bundle in one call (nav SD / sim / Lanelet2).
roadgraph_builder export-bundle examples/sample_trajectory.csv ./out_bundle \
--origin-json examples/toy_map_origin.json --lane-width-m 3.5
# Routing on the frozen Paris bundle.
roadgraph_builder route examples/frozen_bundle/sim/road_graph.json n0 n1 --explain
# Tests (PYTEST_DISABLE_PLUGIN_AUTOLOAD avoids ROS pytest plugin breakage).
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .venv/bin/pytestSee docs/ARCHITECTURE.md for a single-page map
with Mermaid diagrams of the data flow, CLI surface, bundle layout, and
routing subsystem.
Python package: roadgraph_builder/
| Path | Role |
|---|---|
roadgraph_builder/core/graph/ |
Node, Edge, Graph models |
roadgraph_builder/io/trajectory/ |
Trajectory CSV loader |
roadgraph_builder/io/lidar/ |
load_points_xy_csv, load_points_xy_from_las, read_las_header (pure-Python LAS 1.0-1.4 reader, LAZ via optional [laz] extra) |
roadgraph_builder/io/camera/ |
load_camera_detections_json, apply_camera_detections_to_graph, CameraCalibration + pixel_to_ground + project_image_detections_to_graph_edges (pinhole + Brown-Conrady distortion) |
roadgraph_builder/io/osm/ |
build_graph_from_overpass_highways, convert_osm_restrictions_to_graph (Overpass → graph / turn_restrictions) |
roadgraph_builder/io/export/ |
JSON; GeoJSON (optional attribution/license fields); export_lanelet2; bundle (nav/sim/lanelet) |
roadgraph_builder/pipeline/ |
build_graph pipeline |
roadgraph_builder/hd/ |
enrich_sd_to_hd, fuse_lane_boundaries_from_points, centerline offsets |
roadgraph_builder/utils/geometry.py |
Clustering / centerline helpers |
roadgraph_builder/viz/ |
SVG export (trajectory + graph) |
roadgraph_builder/semantics/ |
Trace fusion, map matching summaries, trip reconstruction, road-class and signalized-junction inference |
roadgraph_builder/schemas/ |
road_graph, camera_detections, sd_nav, manifest (.schema.json) |
roadgraph_builder/validation/ |
validate_*_document() for graph, detections, sd_nav, manifest |
roadgraph_builder/cli/ |
Thin dispatcher plus domain command modules (build, validate, routing, export, camera, lidar, osm, guidance, trajectory, hd, incremental, dataset) |
docs/ |
Static viewer + bundled sample assets |
scripts/refresh_docs_assets.py |
Regenerate docs/assets and docs/images |
scripts/render_route_diagnostics_screenshot.py |
Render the README route diagnostics comparison PNG with headless Chrome |
scripts/compare_float32_drift.py |
Rebuild float64/float32 bundles and report topology / coordinate drift |
scripts/run_demo_bundle.sh |
Validate → export-bundle → validate outputs (demo) |
scripts/run_autoware_sanitizer_smoke.sh |
Sanitize every committed Lanelet2 OSM + validate tags + optional Python lanelet2 strict load / lanelet2_validation CLI bridge |
.github/workflows/autoware-smoke.yml |
Optional workflow (workflow_dispatch + weekly) that installs ROS Jazzy lanelet2 packages and runs the smoke script |
roadgraph_builder/io/export/geojson.py |
export_map_geojson() for Leaflet / OSM |
roadgraph_builder/utils/geo.py |
meters ↔ WGS84; load_wgs84_origin_json |
.github/ABOUT.md |
Short text + topics for GitHub About |
- Real-data camera integration (user-driven) —
project-cameraworks on any pixel-detections JSON + calibration. The shipped demo is synthetic with embedded ground truth so round-trip accuracy is provable; users wanting to run it on real photography can followdocs/camera_pipeline_demo.md. This repo intentionally does not ship imagery with viral license terms (e.g. Mapillary CC-BY-SA) so the MIT distribution stays unambiguous. - LiDAR-derived lane centerlines — today
fuse-lidarfits the boundary ribbon from nearby points; a future pass could infer per-lane centerlines directly from the cloud. - Semantics layer — broader lane-type / rule / priority model (separate from raw geometry) beyond the current
attributes.hd.semantic_rulesfree-form dict. - HD-complete Lanelet2 export — the current
export_lanelet2emits per-lane relations, directedlane_connectionpairs, lane-change relations, traffic-light relations, and stop-line ways where inputs exist; richer right-of-way / priority modeling is still future work.
Codebase TODOs also mention: graph fusion across tiles/modalities and routing graph generation for other pathfinders (A* / Contraction Hierarchies).
A frozen reference output lives at examples/frozen_bundle/
so you can browse the shape of export-bundle without running the pipeline
(manifest.json, nav/sd_nav.json, sim/{road_graph,map,trajectory},
lanelet/map.osm). The frozen build runs the full optional pipeline —
HD-lite enrich, LAS-fused LiDAR boundaries, camera detections, and turn
restrictions — so the output reflects the maximal artifact shape. Regenerate
with make release-bundle or bash scripts/build_release_bundle.sh; the
script also packs dist/roadgraph_sample_bundle.tar.gz + a sha256 file
suitable for attaching to a release.
The frozen bundle doubles as a release contract. Stable generated artifacts are
byte-compared in tests. manifest.json is normalized only for
roadgraph_builder_version and generated_at_utc; origin, inputs, graph
stats, junction counts, optional-source metadata, and output paths must match
the checked-in frozen manifest unless the release surface intentionally
changes.
Every v* tag push triggers .github/workflows/release.yml,
which runs the same script and attaches the tarball + sha256 to the auto-created
GitHub Release.
make docs renders docstrings into a static site under build/docs/.
Requires the [docs] extra (pip install -e ".[docs]"). Open
build/docs/roadgraph_builder.html in a browser. Not deployed to a
public URL — this is for local reference only.
Hand-written bash and zsh completion scripts live under
scripts/completions/. They complete the
subcommands and the common --turn-restrictions-json / --output /
--origin-* / --lidar-points style path arguments. The completion smoke
test derives the expected subcommands from the argparse parser, so future CLI
additions should update the scripts in the same change instead of drifting.
# Bash (per-user)
mkdir -p ~/.local/share/bash-completion/completions
cp scripts/completions/roadgraph_builder.bash \
~/.local/share/bash-completion/completions/roadgraph_builder
# Zsh (per-user)
mkdir -p ~/.zsh/completions
cp scripts/completions/_roadgraph_builder ~/.zsh/completions/
# then in ~/.zshrc:
# fpath=(~/.zsh/completions $fpath)
# autoload -Uz compinit && compinitroadgraph_builder --version (or -V) prints the installed package version.
Changes are listed in CHANGELOG.md.
Tag and push a version (example v0.1.0):
git tag -a v0.1.0 -m "Release 0.1.0"
git push origin main
git push origin v0.1.0The release workflow above then builds and attaches
roadgraph_sample_bundle.tar.gz + roadgraph_sample_bundle.sha256 to the
auto-generated release notes.
The distribution name in pyproject.toml is roadgraph-builder.
- Create a PyPI account and an API token with upload permission for this project.
- Install build tools:
python -m pip install build twine. - From a clean checkout:
python -m buildthentwine upload dist/*(use API token when prompted).
.github/workflows/pypi.yml is a workflow_dispatch-only
scaffold that builds sdist + wheel and publishes via pypa/gh-action-pypi-publish.
To enable, configure Trusted Publishers on
the PyPI project (workflow: pypi.yml, environment: pypi) and add a matching
GitHub Environment. No tokens live in this repository.
See CONTRIBUTING.md for dev setup, test commands, and
the conventions used across the repo (one-topic commits, no Co-Authored-By
trailers, schema discipline, data hygiene).
Released under the MIT License. © 2026 Ryohei Sasaki.





