← Back to agents

AGENTS.md from scode/gpxwrench

0 starsLast commit Aug 10, 2025

GPX Wrench — Agents Guide

This document orients future agents working on this repository. It explains the purpose, architecture, workflows, and conventions. Treat this as a living document: if anything becomes untrue or you make a substantial change, update this file immediately (see the last section).

Project overview

GPX Wrench is a Rust CLI for processing GPX (GPS Exchange Format) data via stdin/stdout. It currently offers:

  • Trim GPX track points to a user-specified time range (relative to the earliest timestamp)
  • Automatically trim to the detected activity period based on speed analysis

Primary user docs and examples live in `README.md`.

Repository layout

  • `Cargo.toml`: Crate metadata and dependencies
  • `src/main.rs`: CLI argument parsing and subcommand dispatch using `clap`
  • `src/lib.rs`: Core types and algorithms (parsing ranges, haversine distance, speed calc, activity detection)
  • `src/gpxxml.rs`: Streaming GPX read/write helpers using `quick-xml`
  • `src/commands/`: Subcommand implementations
  • `trim.rs`: Implements the `trim` subcommand
  • `trim_to_activity.rs`: Implements the `trim-to-activity` subcommand
  • `samples/activity.gpx`: Small sample for local testing
  • `.github/workflows/ci.yml`: CI for fmt, clippy, build, and tests

Core concepts and invariants

  • I/O contract:
  • Read full GPX from stdin, write resulting GPX to stdout; print errors to stderr, exit non-zero on failure.
  • Avoid interactive prompts; be scriptable.
  • Time ranges are relative to the earliest track point timestamp.
  • Range semantics are inclusive of start and exclusive of end: [start, end).
  • Preserve GPX structure and unknown extensions for any kept `trkpt`.
  • Prefer streaming processing for XML (no full DOM); `extract_track_points` returns an in-memory list only when required by algorithms (e.g., activity detection).

CLI commands

  • `trim DUR1,DUR2` or `TS1,TS2`
  • Duration units: `s`, `m`, `h` (e.g., `5s,1m`).
  • Timestamp formats: `MM:SS` or `HH:MM:SS` (e.g., `00:15,00:45`).
  • Internally: parse with `parse_range`, read earliest time via `find_minimum_time`, then filter with `filter_xml_by_time_range`.
  • `trim-to-activity [-s, --speed-threshold <m/s>] [-b, --buffer <seconds>]`
  • Detects the main activity window via speeds between consecutive track points.
  • Internals: `extract_track_points` → `detect_activity_bounds` → `filter_xml_by_time_range`.
  • Defaults: speed threshold 1.0 m/s, buffer 30 s; requires at least two timestamped points.

Key modules and functions

  • `src/lib.rs`
  • `TrackPoint { lat, lon, time }`
  • `parse_duration`, `parse_timestamp`, `parse_range`
  • `haversine_distance`, `calculate_speed`
  • `detect_activity_bounds(track_points, speed_threshold, buffer_seconds)`
  • `src/gpxxml.rs`
  • `find_minimum_time(input)`
  • `filter_xml_by_time_range(input, start_time, end_time)`
  • `filter_xml_by_time_to_writer(input, start_time, end_time, writer)`
  • `extract_track_points(input)`
  • `src/commands/`
  • `trim::trim_command(range_str)`
  • `trim_to_activity::trim_to_activity_command(speed_threshold, buffer)`

Development workflow

  • Build/test locally:
  • `cargo build`
  • `cargo test`
  • `cargo fmt`
  • `cargo clippy -- -D warnings`
  • CI mirrors these steps and treats clippy warnings as errors. Keep the code warning-free.
  • Rust edition: 2024. Dependencies: `clap`, `time`, `quick-xml` (see `Cargo.toml`).

Adding or modifying commands

1. Create a new module under `src/commands/your_cmd.rs`. 2. Export it in `src/commands/mod.rs`. 3. Wire it into the `Commands` enum and `match` in `src/main.rs`. 4. Follow the I/O contract (stdin → stdout, stderr for errors). Prefer streaming via `src/gpxxml.rs`. 5. Update `README.md` with user-facing docs and examples. 6. Update this `AGENTS.md` with architectural notes and invariants impacted by the change. 7. Add tests (see next section), run `fmt`/`clippy`/`test`, ensure CI passes.

Testing

  • Unit tests live alongside code (e.g., `#[cfg(test)]` in `src/lib.rs` and `src/gpxxml.rs`).
  • For GPX handling, prefer small inline GPX samples in tests for clarity and stability.
  • Validate:
  • Range parsing (positive and negative cases)
  • Activity detection windows against controlled inputs
  • XML filtering preserves extensions and formatting for retained `trkpt`
  • Edge cases: missing timestamps, single-point tracks, out-of-order times

Conventions and code quality

  • Style: run `cargo fmt`; keep lines reasonably wrapped; avoid unrelated reformatting.
  • Linting: fix all `clippy` warnings (`cargo clippy -- -D warnings`).
  • Naming: descriptive function and variable names; avoid abbreviations; prefer clarity over brevity.
  • Control flow: guard clauses for early exits; handle error and edge cases first; avoid deep nesting.
  • Error handling: return `Result<_, Box<dyn Error>>` from command handlers; avoid panics on malformed input.

Common pitfalls

  • Forgetting that ranges are relative to the earliest timestamp, not the first element encountered.
  • Off-by-one time inclusivity: ensure [start, end) behavior in filtering.
  • Dropping extensions inadvertently: keep `trkpt` contents intact when within range.
  • Large inputs: activity detection builds a `Vec<TrackPoint>`; consider memory implications if expanding features.

Keeping this document up-to-date (mandatory)

  • If you change behavior, interfaces, dependencies, file layout, CLI flags, or invariants, update `AGENTS.md` in the same pull request.
  • If any statement here becomes untrue, fix it immediately.
  • When adding major features:
  • Document new commands and their internals at a high level.
  • Note any new invariants or performance implications.
  • Cross-check `README.md` for consistency and update examples.
  • Use concise, skimmable language and keep sections structured for quick onboarding.

Thank you for keeping this a high-signal guide for future agents.