---
name: peat-mesh
description: Per-repo skill for the Peat mesh networking layer — pluggable transport, peer discovery, topology, routing, optional Automerge/Iroh CRDT sync, optional HTTP/WS broker.
when_to_use: Editing files under peat-mesh/, reviewing peat-mesh PRs, debugging peer/discovery/topology/routing/storage/broker issues, or working on ADR slices that touch mesh.
verifies_with: cargo fmt --check, cargo clippy -- -D warnings, cargo test, plus feature-flagged builds for any feature whose code paths the change touches.
---

# `peat-mesh` SKILL

`peat-mesh` is the mesh networking layer of the Peat ecosystem. It provides a pluggable `Transport` abstraction (BLE via `peat-btle`, lightweight bridge via `peat-lite`, IP), peer discovery (mDNS, Kubernetes CRD), topology and partition management, routing, an optional Automerge + Iroh + redb CRDT storage backend, and an optional HTTP/WS service broker. It's a Rust library (edition 2021) with an optional `peat-mesh-node` binary; other peat-* repos depend on it as a building block — peat-mesh does not depend on its consumers.

## When this skill applies

- Editing any file under `src/transport/`, `src/discovery/`, `src/topology/`, `src/routing/`, `src/storage/`, `src/broker/`
- Authoring or reviewing tests under `tests/`
- Touching the feature-flag matrix in `Cargo.toml`
- Working on an active slice of any **local ADR** (4-digit padded `ADR-0001` through `ADR-0011` in `docs/adr/`) or any **ecosystem ADR** that lands here. Recent ecosystem slices touching this repo: `ADR-032` (BLE transport), `ADR-035` (peat-lite bridge), `ADR-042` (transport security), `ADR-049` (security primitives), `ADR-059` (translator) — these live in the sibling `peat/docs/adr/`, not in this repo.

If you're editing a peat-* sibling repo and only consume `peat-mesh` as a dependency, this skill probably isn't the one you want.

## Scope

**In scope:**
- Mesh transport implementations and the `Transport` trait surface
- Peer discovery (mDNS, Kubernetes CRD)
- Topology manager state and partition healing
- Routing logic
- Storage backends (Automerge + redb + Iroh sync, blob store)
- Service broker (HTTP/WS, Axum-based, feature-gated)
- Feature-flag wiring in `Cargo.toml`

**Out of scope (route elsewhere):**
- BLE transport implementation details → `peat-btle/SKILL.md`
- Lightweight runtime → `peat-lite/SKILL.md`
- Edge-hardware node integration → `peat-node/SKILL.md`
- ATAK / Android FFI → `peat-atak-plugin/SKILL.md`
- Top-level shared types/traits — consider whether the change belongs in `peat/` (the ecosystem core crate) instead

## Workflow

Numbered steps. Skipping a step requires explicit user instruction.

1. **Orient.** Read `peat/SKILL.md` (ecosystem) if accessible. Read this file. Read `CONTRIBUTING.md` for the build matrix. `git status`, `git log -10`.
2. **Locate the spec.** Confirm the task has a GitHub issue with Context / Scope / Acceptance / Constraints / Dependencies. If not, stop and ask the user.
3. **Plan.** Produce a 1–5 step plan. Cross-check against ecosystem hard invariants (transport agnosticism, no cross-repo direct deps, peat-mesh has no consumers as deps) and the scope guards below. If the change is architectural, reference an existing ADR (`docs/adr/`) or propose a new one.
4. **Implement.** Branch from `main` per the trunk-based convention. Vertical slices, one concern per commit. Match existing module boundaries — don't bleed transport logic into discovery, etc.
5. **Verify.** Run every command in the verification checklist below. Capture output.
6. **Hand off.** Open PR against `main` referencing the issue. Single concern per PR — peat-mesh squash-merges, so the PR title becomes the merge commit subject.

## Verification (exit criteria)

A session in this repo is not done until each of these produces evidence:

- [ ] `cargo fmt --check` exits 0
- [ ] `cargo clippy -- -D warnings` exits 0
- [ ] `cargo test` exits 0
- [ ] If the change touches code under any feature flag, also: `cargo test --features <flag>` for each affected feature (`automerge-backend`, `broker`, `kubernetes`, `bluetooth`, `lite-bridge`). Build-only (`cargo build --features <flag>`) is not sufficient — feature-gated test paths only execute under `cargo test --features`, and recent ADR-049 / ADR-059 work lives entirely under feature gates.
- [ ] If the change spans multiple features: `cargo test --features node` exercises the combined feature set used by the binary.
- [ ] If the change is functional: a behavioral test or example demonstrates the new behavior — not just unit-coverage padding
- [ ] The pre-commit hook installed by `./scripts/install-hooks.sh` runs clean (it gates `cargo fmt --check` and `cargo clippy -- -D warnings` on every commit)

"Seems right" or "the diff looks correct" is never sufficient.

## Anti-rationalization

| Excuse | Rebuttal |
|---|---|
| "This change is too small to need a test." | If it's worth changing, it's worth one assertion. Add the test. |
| "I'll fix the clippy warning later." | The CI gate is `-D warnings`. There is no later. Fix it before commit. |
| "This refactor is right next door — I'll just clean it up." | Out of scope. Open a separate issue if it matters. Squash-merge ≠ kitchen-sink PR. |
| "I only changed library code; the feature builds will pass." | Feature flags interact non-obviously with optional dependencies (especially `iroh` / `ed25519` pinning). Run the affected feature builds locally. |
| "I'll just import directly from `peat-btle` to avoid the `Transport` trait detour." | peat-mesh depends optionally on `peat-btle` (gated by `bluetooth`); the trait abstraction is the whole point. Cross-direction or non-trait imports break the abstraction and the dependency direction. |
| "The transport-level retry can live in the topology manager — same crate." | Transport-specific retry (link-level send/recv, framing) belongs in the transport adapter — topology must not assume any specific transport's retry semantics. Higher-layer retries — partition healing, route re-discovery — legitimately live above the transport seam (see `ADR-0003`) and are a different concern; do not collapse them into the same row of reasoning. |
| "I'll skip GPG signing this once — it's just a docs change." | Signing is a repo-policy gate, not a quality gate. Don't bypass. Fix the signing config instead. |
| "I'll bump `iroh` to drop the pre-release `ed25519`/`pkcs8` pins — it's cleaner." | Those pins exist because `iroh 0.97/0.98` ship pre-release transitives that don't survive their own dep ranges under rustc ≥1.95. Remove only after verifying upstream actually fixed it (see the comment in `Cargo.toml`). |

## Scope guards

- Touch only files the issue/user asked you to touch.
- Do not edit other peat-* repos. Cross-repo work goes in a separate PR in that repo, linked through a tracking issue.
- Do not bleed transport-specific logic into `discovery`, `topology`, `routing`, or `storage` modules. The `Transport` trait is the seam.
- Do not add a hard dependency on a feature-gated crate without gating it behind the matching feature.
- Do not add `peat-mesh` consumers (peat-node, peat-btle, peat-lite, etc.) as `peat-mesh` dependencies. The dependency direction is one-way.
- Do not configure git to bypass GPG signing or use `--no-verify` to skip the pre-commit hook.

## Gotchas

Add an entry each time a session produces output that needed correction. One line per gotcha plus a `Why:` line.

- `AutomergeStore::put` is wholesale-byte-replace at the doc-key level; any get→modify→put sequence on the same key must hold `store.lock_doc(&key)` across the whole sequence.
  Why: two concurrent load-modify-write cycles for the same key silently drop one writer (last `put` wins) regardless of typed-field structure inside the doc — surfaced as 6/8 lost writes in a concurrent-spawn test during the peat#868 substrate fix.
- The auto-sync push task (`AutomergeBackend::start_sync`) silently swallows the per-peer error from `sync_document_with_all_peers` (`let _ = e`); anything that returns `Err` from `initiate_sync` is dropped with no retry.
  Why: returning `FlowControlError::CooldownActive` there meant back-to-back local writes within the 100ms cooldown never reached peers — the root of peat#864's missing-frame symptom. Defer (sleep the remaining cooldown) instead of erroring on that path.
- `FlowController.sync_cooldown` is defer-not-drop on the auto-sync path as of rc.10; don't "simplify" `initiate_sync` back to fast-fail on cooldown.
  Why: the regression test pins both the timing (≥80ms wait) and error-shape (no `CooldownActive` surfaced); a revert silently re-opens peat#864.
- Jobs that share a physical self-hosted runner pool (e.g. the `peat-arm64-linux-gb10-mesh` host) must serialize with a **static, repo-wide** `concurrency` group named `peat-{repo}-{job}-self-hosted` (no `${{ github.ref }}` in the key) and `cancel-in-progress: false`. peat-mesh's `P2P Functional Tests` pairs with peat-node's `peat-cli-e2e` on the same pool.
  Why: a ref-scoped group (`${{ github.workflow }}-${{ github.ref }}`) lets two refs (push-to-main vs. a release tag) land the same job on one runner concurrently and contend for CPU + loopback multicast — the #222 P2P flake. A new repo sharing the pool is easy to miss; follow this naming so the cross-repo contract is discoverable.

## References (read on demand, not by default)

- Ecosystem invariants: `peat/SKILL.md` (sibling repo)
- Build matrix and feature flags: `CONTRIBUTING.md`
- **Local ADR index**: `docs/adr/` — repo-local ADRs use 4-digit padded form (`ADR-0001` through `ADR-0011`)
- **Ecosystem ADR index**: `peat/docs/adr/` (sibling repo) — ecosystem ADRs use 3-digit form (`ADR-032`, `ADR-049`, etc.); these are the IDs cited in this repo's `Cargo.toml` comments and recent commits
- `iroh` / `ed25519` / `pkcs8` pin rationale: comment block in `Cargo.toml` around the `automerge-backend` deps
- Codex-specific orientation: `AGENTS.md` (do not duplicate skill content there)
- Repo: https://github.com/defenseunicorns/peat-mesh

---
*Last updated: 2026-05-05*
*Maintained by: Kit Plummer, VP Data and Autonomy, Defense Unicorns*
