This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
- Never
git commitorgit pushwithout the user's explicit consent. Do the work, then stop and ask. - When asking, show the list of changed files (e.g.
git status/git diff --stat) alongside the question so the user can see exactly what would be committed. - Only commit and push after the user explicitly says yes. A "yes" approves that one set of changes — ask again for the next commit.
A single-file Python CLI (zone.py) that downloads the BrandMeister DMR repeater
list and emits Motorola MOTOTRBO CPS2 zone files (XML) for import into Motorola
DMR radios. Repeaters are filtered by band and by country (MCC), QTH locator, or GPS
coordinates. There is no package structure, no test suite, and no build step — it is
run directly as a script.
# Set up environment (a .venv already exists in the repo)
pip install -r requirements.txt
# Run (always requires -n, -b, and -t)
./zone.py -n 'Germany' -b vhf -t mcc -m 262 -6 -zc 16
./zone.py -n 'Paris' -b uhf -t qth -q JN18EU -r 150 -6
./zone.py -n 'Stockholm' -b uhf -t gps -lat 59.225 -lon 18.250 -6
# Force re-download of the repeater list
./zone.py ... -fNegative GPS coordinates must be quoted with a leading space or written as
-lon=-93.2780, otherwise argparse treats them as flags.
The whole pipeline lives in zone.py and runs top-to-bottom in __main__:
download_file()— fetchesbm_url(BrandMeister/v2/device) intoBM.json, only if the file is missing or-f/--forceis given. TLS verification is intentionally disabled (verify=False) because of the upstream cert.filter_list()— readsBM.json, sorts by callsign + id, and applies all filters, buildingfiltered_list. Deduplicates by (rx, tx, callsign). The module-levelexistingdict counts how many repeaters share a callsign so duplicates get#Nsuffixes later.- Output, one of two modes:
- Default:
process_channels()chunksfiltered_listinto zones of--zone-capacitychannels, callsformat_channel()per repeater, writes one<zone alias>.xmlper chunk, and prints atabulatesummary table. -js/--javascript:create_js()prints repeater objects for an external web map instead of writing XML.
- Default:
format_channel() emits raw CPS2 XML by string interpolation (no XML library).
A repeater with rx == tx (simplex/hotspot) produces a single SLOT2 personality;
otherwise it produces paired TS1 and TS2 personalities. Contents of
custom-values.xml are spliced into every channel only when -c/--customize is set.
-js/--javascript is a private feature on the js branch for the maintainer's own
internal use — it is not part of the upstream tool and should not be merged to main
or treated as a general feature. It changes filtering semantics, not just output: in
filter_list() the band and location/MCC filters are skipped entirely when
args.javascript is set (only -p, -6, -cs still apply). create_js()
additionally drops repeaters with no coordinates and any id starting with 247.
- State flows through module-level globals (
filtered_list,existing,custom_values,qth_coords) mutated viaglobal— not return values. -m/--mccaccepts a numeric MCC prefix or a two-letter country code, which is resolved to MCC(s) viamobile_codes.alpha2(...)[4]and may be a list.last_seenfrom the API is UTC;local_datetime()converts it to the machine's local timezone for the printed table.BM.json,a.json,b.jsonare large downloaded data snapshots, not source.- Output XML is import-only; CPS16 cannot paste XML, so this targets CPS2 (radio firmware R2.10+).