Skip to content

Commit d374d75

Browse files
RyanMorashclaude
andcommitted
Add CLAUDE.md agent guide
Surfaces the load-bearing invariants from docs/architecture.md (no asyncio, pure modules stay pure, frozen dataclasses, card ID redaction, fail-secure safety guards) so they bind without requiring a full read of the architecture doc. Includes uv-prefixed command list and a pointer to the architecture doc as authoritative. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f0678e4 commit d374d75

1 file changed

Lines changed: 41 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# door-sync — agent guide
2+
3+
CiviCRM → UniFi Access reconciliation daemon. Runs on a Raspberry Pi under systemd.
4+
5+
**Status: pre-implementation.** Module skeleton exists in `src/door_sync/` but reconciler/safety/clients are not yet written. Architecture is locked; see `docs/architecture.md` before adding code.
6+
7+
## Commands
8+
9+
```bash
10+
uv sync # install
11+
uv run pytest # tests
12+
uv run mypy src tests # type check (strict)
13+
uv run ruff check . # lint
14+
uv run door-sync --once # one reconcile cycle, exit
15+
uv run door-sync --dry-run # compute + log diff; no UniFi writes
16+
```
17+
18+
All tooling goes through `uv run` — the venv is managed by uv, not pip.
19+
20+
## Architecture
21+
22+
`docs/architecture.md` is authoritative for module layout, data contracts, and the pure/impure boundary. Read it before designing changes that cross module boundaries.
23+
24+
## Hard rules (from architecture doc — do not violate without a human in the loop)
25+
26+
- **No asyncio.** Sync `httpx` only. Do not "modernize" to async; the design rejects it deliberately (architecture.md §3).
27+
- **Pure modules stay pure.** `reconciler.py`, `safety.py`, `tier_mapping.py` take dataclasses, return dataclasses. No logging, no config lookups, no HTTP, no exceptions on data issues — return a sentinel instead (architecture.md §5).
28+
- **Frozen dataclasses.** All domain models in `models.py` are `@dataclass(frozen=True)`. Never mutate; construct a new instance.
29+
- **Strict layering.** Nothing imports `orchestrator` except `scheduler` and (future) `webhook`. See dependency table in architecture.md §4.
30+
- **Card ID redaction.** Logs show last-4 only. Never log a full card ID at any level (architecture.md §11).
31+
- **Dry-run is sacred.** Dry-run flips a flag inside `UnifiClient` that turns writes into no-ops. Pure modules behave identically in dry-run and live — do not branch on dry-run in pure code.
32+
- **Fail-secure on safety guards.** Any guard firing means zero writes that cycle. No partial application.
33+
34+
## Testing
35+
36+
- Pure-module tests use plain dataclass construction — no mocks, no HTTP fixtures.
37+
- Idempotency canary: `compute_diff` immediately after `unifi.apply()` must yield all-empty diff sets. Include this test for the reconciler (architecture.md §8).
38+
39+
## Config
40+
41+
Two-file split: secrets in env (`.env` dev, `/etc/door-sync/env` prod, mode 0400), everything else in TOML (`config.toml` dev, `/etc/door-sync/config.toml` prod). Schema is not yet implemented.

0 commit comments

Comments
 (0)