Skip to content

Contributing

Quadstronaut edited this page Jul 28, 2026 · 2 revisions

Contributing

This is a personal learning project (it is alpha — the steady-state jump loop is live-validated over hundreds of consecutive jumps, but docking and the rarer recovery paths are still under live validation). Contributions are welcome as pull requests against master. The architecture is built so that adding behavior — new procedures, new steps — does not require modifying existing code.

The repository is a six-package workspace under projects/: ed-core (the engine), ed-vision (the perception leaf), ed-autojump (the one shippable tool + the editable TOML procedures), ed-explore (in-system body tour), and ed-combat / ed-trading (Phase-1 scaffolds that register nothing yet). Each is an editable install.

Only the jump loop in ed-autojump is validated against the live game. ed-explore is non-functional (the body tour never completes a body), and ed-combat / ed-trading are not implemented. Live testing is currently blocked, so those three are frozen where they are — treat them as unfinished scaffolding rather than as behaviour to preserve.


Licensing split — know this before you start

  • Repository root: MIT (LICENSE).
  • ed-autojump distribution: AGPL-3.0-or-later (projects/ed-autojump/LICENSE). It bundles the nav-compass model whose Ultralytics weights are AGPL-3.0, so the whole distribution that ships those weights carries AGPL obligations. The OpenCV fallback backend needs no weights, so that obligation does not attach if you do not ship the bundled model.

Code touching the shippable ed-autojump distribution falls under AGPL; the rest of the workspace root is MIT. Keep this in mind for where you add code.


Running the test suite

cd projects\ed-autojump
.\.venv\Scripts\Activate.ps1
pytest

The offline unit + replay suite runs without the game; one @requires_game test is deselected by default (it needs the live game running).

To run a specific test file:

pytest tests/test_cli_flow.py -v

To include the requires-game tests (live game must be running):

pytest -m "requires_game"

Adding a new step

  1. Add a function step_<name>(ctx: StepContext, *, <params>) -> bool. Autojump step impls live in projects/ed-autojump/src/ed_autojump/flow/steps.py; shared primitives reused across domains live in projects/ed-core/src/ed_core/flow/steps_shared.py.
  2. Register it by name with register_step("<name>", step_<name>) into the one core-owned STEP_REGISTRY (ed_core.flow.step_registry). Registration is fail-on-duplicate — a colliding name raises rather than silently shadowing.
  3. Document it in projects/ed-autojump/procedures/procedures.md (the canonical action reference).
  4. Write a unit test in tests/.
  5. Use the new step in a procedure TOML.

Steps must return True on success and False on failure. A False on a required step triggers the procedure's [on_required_fail] policy. Steps catch KeyError from the sender (an unbound bind) and return False cleanly — they never raise from a missing bind.


Adding or editing a procedure

Procedures live in projects/ed-autojump/procedures/ as TOML files — there are 11 scenes (startup, arrival, traversal, smack_recovery, exploration, sc_resume, dock, dock_resume, route_complete_park, honk, connection_recovery). They are editable data, not code: reorder steps by moving lines, adjust timings and counts in place. The loader validates every procedure at startup — unknown action, unbound key, or an invalid skip_to / loop_to / retry_from / retry_from_if_supercruise reference → the bot refuses to run. Because the procedures are data validated at load, they carry no shape-pinning tests; behavior changes to the steps they call still need tests.

Procedure structure:

parallel_tracks = ["honk"]   # optional: names of parallel tracks to launch at start

[on_required_fail]
retry_from = "action_name"   # action name of the step to jump back to
max_retries = 3
backoff_s = 2.0

steps = [
  { action = "wait", s = 1.0 },
  { action = "orient_compass", required = true },
  { action = "engage_jump", required = true },
]

See procedures/procedures.md for the full action reference and required semantics.


Branching conventions

  • The default branch is master; PRs target master.
  • Feature / fix branches: feat/<description>, fix/<description>.
  • Docs branches: docs/<description>.
  • Keep changes small and well-scoped so any single commit is cleanly revertable — prefer many small labelled commits over few large ones. Open an issue first for anything large so the design can be discussed before you build.

Architecture overview

The engine lives in ed-core (ed_core.flow); the autojump domain (ed_autojump.flow) supplies its steps, boot routes, and the TOML procedures; perception lives in ed-vision (the leaf). Dependency direction: ed-autojump → ed-core → ed-vision.

The main loop (ed_core.flow unless noted):

  • flow/dispatcher.py — maps journal events to procedure names, and fires the real-time preempts (FSDJump → arrival, star-smack → smack_recovery, CONNECTION ERROR modal → connection_recovery)
  • flow/interpreter.py — runs an ordered step list; handles required failures, retry-from, retry_anchor, skip_to/loop_to, and parallel tracks
  • flow/loader.py — loads and validates TOML procedures at startup
  • flow/step_registry.py — the one core-owned action → fn registry; register_step is fail-on-duplicate
  • flow/steps_shared.py — shared flight primitives reused across domains
  • ed_autojump/flow/steps.py — the autojump step impls (they register_step on import)
  • ed_autojump/flow/boot_routes.py — boot-scene determination + the never-strand re-dispatch driver

Supporting modules:

  • ed_core/journal/ — journal file tail + pydantic event models
  • ed_core/status/Status.json poller + NavRoute.json reader
  • ed_core/keys/ — DirectInput scancode sender + .binds parser + NullSender + LoggingSender
  • ed_vision/ — screen capture + nav-compass reader backends (cyan, yolo-onnx, ultralytics, opencv) + widget-ring fine pass + nav-panel/HUD/target-panel OCR
  • ed_core/fsd/ — danger-class list + FSD constants (from EDCD/coriolis-data)
  • ed_core/launcher/ — MinEdLauncher spawn + dryrun + menu navigation + credential wizards
  • ed_core/recorder.py — session JSONL writer (keypress + journal event + outcome rows)
  • ed_core/anonymizer.py — scrubs CMDR/FID/AccountID from session JSONLs (python -m ed_core.anonymizer in.jsonl out.jsonl)
  • session_audit — pure functions for safety assertions over recorded sessions
  • ed_core/panic.py — thread-safe trip flag; listeners call switch.trip() from any thread
  • ed_core/doctor.py — pre-flight environment checks

Test discipline

The project uses three test tiers:

  • Offline unit tests (tests/test_*.py) — no game, no file I/O beyond fixtures; the bulk of the suite
  • Recorded-session regression tests — auto-discovered from ~/ed-afk-sessions/; assert safety invariants: no HullDamage, no engagement on a danger StarClass, no fuel starvation, no abandoned routes
  • @requires_game stub — one test requiring the live game; deselected by default

Behavior changes should come with a unit or replay-based test, since live testing is not always available. Safety invariants are pure functions (session_audit) individually unit-tested without any session file.

Clone this wiki locally