This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Short Circuit (formerly Pathfinder) is a PySide2 desktop application that finds the shortest path between Eve Online solar systems, including wormhole connections fetched from third-party mappers (Tripwire, Eve Scout). Python 3.10, packaged with PyInstaller.
Environment setup (the project uses Pipenv with a local .venv):
pip install pipenv
mkdir .venv
pipenv install --dev
pipenv shellRun the application:
cd src
python main.pyRegenerate Qt UI and resource modules after editing files under resources/ui/ or resources/resources.qrc:
./generate_gui.sh # or generate_gui.bat on WindowsThis runs pyside2-uic / pyside2-rcc and writes to src/shortcircuit/view/gui_*.py and resources_rc.py. Do not edit those generated files by hand — edit the .ui / .qrc source and regenerate.
Run tests (pytest, collocated with source under src/shortcircuit/model/test_*.py):
pipenv run pytest src/shortcircuit/model
pipenv run pytest src/shortcircuit/model/test_tripwire.py # single file
pipenv run pytest src/shortcircuit/model/test_tripwire.py::TestX # single testBuild standalone binaries:
./build_win_installer.bat # Windows, PyInstaller --onefile
./build_mac_installer.sh # macOSThe app follows a three-layer split under src/shortcircuit/: view/ (Qt widgets, mostly generated from .ui files), model/ (domain logic, networking, graph algorithms), and app.py as the MainWindow glue. Entry point is src/main.py.
The control flow from a button click to an updated solar map spans several modules — understanding this chain is important before modifying any piece:
app.py(MainWindow) handles the button click and starts a Qtworker_threadso the UI stays responsive.navprocessor.py(NavProcessor, runs on that worker thread) coordinates the workflow and emits afinishedsignal back to the main thread.navigation.py(Navigation) owns theSolarMap, callssetup_mappers()to read config fromapp_obj(theMainWindow), and delegates fetching to the registry.mapper_registry.py(MapperRegistry) iterates over registeredMapperSourceinstances, callsaugment_map(solar_map)on each, aggregates counts, and isolates failures so one broken mapper doesn't kill the others.mapper_base.pydefines the abstractMapperSourceinterface:augment_map,get_name,get_config,validate_config. Every mapper implementation inherits from it.- Concrete mappers (
tripwire.py,evescout.py) authenticate if needed, fetch JSON, and callsolar_map.add_connection(...)for each wormhole. solarmap.py(SolarMap) is the graph itself — holds systems/connections, runs Dijkstra with weights influenced by security prioritization, wormhole size/life/mass restrictions, and the avoidance list.
The detailed flow and diagrams live in docs/MODULE_ARCHITECTURE.md; adding a new mapper is documented in docs/MAPPER_MODULES.md.
UI code runs on the main thread; anything that blocks on network I/O (mappers, ESI calls) must run on a worker thread and communicate back via signals. Do not call mapper or ESI methods directly from UI event handlers.
model/esi/ wraps the optional Eve Online ESI integration (implicit OAuth flow, 20-minute sessions, used for reading player location and setting in-game destination). Configuration (Tripwire credentials, Eve Scout toggle, proxy, restrictions, avoid list) is persisted via Qt's QSettings, loaded in MainWindow.read_settings(), and accessed by Navigation through its app_obj reference.
Eve SDE CSVs (mapSolarSystems.csv, mapSolarSystemJumps.csv, mapLocationWormholeClasses.csv) live in src/database/ and are loaded by evedb.py. Refresh them from https://www.fuzzwork.co.uk/dump/latest/ when the SDE updates — see README.
- Python 3.10, 2-space indentation (see existing files).
- Qt-generated files under
view/are regenerated artifacts — never edit directly. - Tests live next to the code they test (
test_*.pyinsrc/shortcircuit/model/), not in a separate top-level tests directory. - Known follow-ups and intentionally deferred work are tracked in
TODO.md(connection deduplication, multi-instance mapper UI, parallel fetching, caching). Prefer aligning with what's listed there over introducing a parallel plan.
When writing commit messages, always explain why the change was made, not just what was changed. The diff already shows what changed - the commit message should provide context and reasoning.
The "why" is often harder to infer than the "what", and it requires proper documentation. Without it, future developers (including your future self) will struggle to understand:
- Contextual Background: Why was this change necessary? What problem or feature was being addressed?
- Decision-Making Process: What options were considered? Why was this particular solution chosen?
- Implications and Considerations: What are the potential impacts or limitations of this change? Were there any trade-offs?
❌ Bad: Summarizing the changes
Update authentication logic
❌ Bad: Only linking to a ticket
Fix #123
The problem: These messages don't explain why the change was necessary. The diff shows what changed - you need to provide the context and reasoning.
✅ Good: Explaining the reasoning
Fix race condition in authentication flow
Users were occasionally getting logged out unexpectedly during page
navigation. This was caused by the auth token refresh happening
simultaneously with route changes, leading to a race condition where
the old token would sometimes override the refreshed one.
This change ensures token refresh completes before allowing navigation
to proceed, preventing the race condition.
- Don't just link to tickets - that puts all the work on the reader to understand context
- Explain the problem being solved and why this solution was chosen
- Include relevant trade-offs or limitations if applicable
- Write for your future self and other engineers who may need to maintain this code
PR descriptions follow the same principles as commit messages: focus on the "why", not just the "what".
- Summary: A concise overview of what the PR accomplishes and why it's needed
- Context: Background information about the problem being solved or feature being added
- Approach: Explanation of the solution chosen and why (especially if there were alternatives)
- Trade-offs: Any known limitations, compromises, or technical debt introduced
- Testing: How the changes were tested and what scenarios were covered
- Risks: Any potential impacts on existing functionality or deployment considerations
Fix race condition in authentication flow
## Summary
Users were occasionally getting logged out unexpectedly during page navigation.
This PR fixes the race condition by ensuring token refresh completes before
navigation proceeds.
## Context
The issue occurred when the auth token refresh was triggered simultaneously
with route changes. The old token would sometimes override the refreshed one,
causing unexpected logouts.
## Approach
Added a mutex to ensure token refresh operations are atomic. Considered using
a queue-based approach but opted for the mutex solution due to its simplicity
and lower overhead.
## Testing
- Added unit tests for concurrent token refresh scenarios
- Manually tested rapid page navigation while token refresh was occurring
- Verified no performance regression with load testing
## Risks
Low risk - the mutex is only held briefly during token operations.