hosts/CONTRIBUTING.md
phg 780d9c12fe Adopt mise for development workflows
- Lock Python and uv versions with mise
- Add unified sync, app, test, lint, format, and typecheck tasks
- Update development documentation and strengthen type handling
2026-09-04 14:39:02 +02:00

4.2 KiB

Contributing

Thank you for improving hosts. Because the application modifies /etc/hosts with elevated privileges, correctness and honest user-facing behavior take priority over feature breadth.

Use the Forgejo issue tracker to report bugs or coordinate consequential changes.

Development setup

The project uses mise to install its locked Python and uv versions and to provide its development tasks:

git clone https://git.s1q.dev/phg/hosts.git
cd hosts
mise install
mise run sync
mise run app

mise run app starts the real application and reads /etc/hosts. Stay in Read-only Mode unless you deliberately intend to exercise privileged behavior on your machine. Automated tests must use mocks and temporary files instead.

Code boundaries

  • src/hosts/core/ owns Host Entries, parsing and serialization, configuration, DNS resolution, undo/redo commands, and privileged file operations.
  • src/hosts/tui/ owns the Textual application, handlers, modals, widgets, keybindings, and styles.
  • tests/ mirrors both layers and isolates operating-system interactions.

Keep domain and system logic out of Textual widgets. Route privileged writes through HostsManager; UI actions should coordinate services and render their results.

Core code that is not reachable through the TUI is not yet a supported product feature. Do not advertise it in user-facing documentation until users can actually invoke it.

Domain language and decisions

Read CONTEXT.md before naming user-visible concepts. Use its canonical terms in the interface, documentation, issues, and tests where practical.

Read the relevant architecture decision record before changing established contracts:

  • ADR 0001 covers Privileged Mode, sudo handling, system-file writes, and Pre-edit Backups.
  • ADR 0002 covers parsing, serialization, comment placement, and formatting preservation.

Add an ADR only for a consequential, surprising trade-off that would be expensive to reverse. Keep planned work in Forgejo issues rather than evergreen repository documents.

Safety contracts

  • The application starts in Read-only Mode.
  • Mutating actions require Privileged Mode, and a Pre-edit Backup must exist before writes are enabled.
  • Leaving Privileged Mode clears only application permission and undo/redo session state; it must not alter sudo's cached timestamp.
  • Default Entries are protected from mutation and must remain first when file order changes.
  • All privileged writes go through HostsManager.
  • Serialization is semantic and normalized, not byte-preserving.
  • Tests never read or write the real /etc/hosts, invoke real sudo, or depend on live DNS.

Mock subprocess and resolver boundaries and inject a temporary Hosts File path. Treat any test capable of touching the real system file as a defect.

Make and validate a change

Run the narrowest relevant test while developing. Examples:

mise run test -- tests/test_parser.py
mise run test -- tests/test_manager.py
mise run test -- tests/test_main.py

Before handing off any change, run the complete validation suite:

mise run check

Apply formatting with:

mise run format

Add or update tests for changed behavior. Test user-reachable workflows at the TUI boundary as well as isolated core behavior when both layers participate.

Keep documentation accurate

Documentation is part of the behavior contract:

  • Update README.md when installation, major reachable features, maturity, or prominent safety limitations change.
  • Update the user guide when workflows, shortcuts, persistence, recovery, configuration, or troubleshooting change.
  • Update CONTEXT.md when the canonical domain language changes; keep it a glossary rather than an architecture guide or progress log.
  • Update ADR 0002 and the README if serialization stops being normalized or becomes byte-preserving.

Describe only current, reachable behavior in user-facing documentation. Record future work in an issue instead of presenting it as an available feature.