Gilfoyle is hexagonal (ports and adapters). Dependencies point inward, and the Cargo dependency graph is the enforcement.
| Crate | Role | I/O |
|---|---|---|
gilfoyle-core |
domain types, ports, use cases | none |
gilfoyle-system |
driven adapter (host uptime) | read-only |
gilfoyle-systemd |
driven adapter (systemd over D-Bus) | system bus |
gilfoyle-packagekit |
driven adapter (PackageKit over D-Bus) | system bus |
gilfoyle-docker |
driven adapter (Docker over its UNIX socket) | socket |
gilfoyle-ssh |
driving adapter: embedded SSH server + auth/channel policy | network |
gilfoyle-client |
driving adapter: multi-node aggregator | network |
gilfoyle-server |
MCP handler, config, wiring + the gilfoyle binary |
network |
Never import an adapter from the core. A capability is a narrow port (UptimeSource,
ServiceCatalog, ServiceControl); add one trait per capability rather than widening an
existing one.
Adding a tool
- Model the result in
gilfoyle-coreand add a method to the driving port. - Implement the read or mutation in a driven adapter behind a narrow port.
- Translate it in the
#[tool_router]impl ingilfoyle-server— a few lines, no logic. - Cover it with unit tests; extend the SSH integration test when the wire shape changes.
If the tool is a read, add it to gilfoyle-client’s read set so it can be fanned out.
Quality
make fmt-check # formatting
make lint # clippy -D warnings
make test # unit + integration tests
make mutants # cargo-mutants; the score must be 100%
make check # all of the above except fuzzing
The mutation score is held at 100%: a surviving mutant fails the run. Excluded glue is
the composition root (main.rs) and the thin russh/rmcp/hyper transport wiring — their
decisions live in pure, tested modules. The systemd and PackageKit adapters are covered by
in-process mock buses, the Docker adapter by a mock HTTP server on a UNIX socket, and the SSH
transport by an in-process russh client/server pair.
Fuzzing (make fuzz) runs eight targets on nightly with AddressSanitizer: uptime_parse,
authorized_key, config_toml, client_config, unit_name, package_id, container_ref
and container_allowlist. cargo-deny
(deny.toml) denies unknown registries and git sources, keeps an empty advisory ignore list,
and bans openssl.