- Fix make test: was pointing to non-existent api/tests/, now runs unit tests correctly with --ignore=e2e --ignore=integration - Remove dead phase test targets (test-phase1..4, test-all-phases) that all referenced cd api && pytest tests/ (non-existent path) - Add .test_admin_pass file: reset_admin_password.py now writes a persistent test password file alongside .admin_initial_password; the API never deletes it (unlike .admin_initial_password which is consumed on first startup) - Update both integration/conftest.py and e2e/helpers/admin_password.py to read .test_admin_pass before .admin_initial_password — so tests work after make restart without needing PIC_ADMIN_PASS env var - Add AI collaboration rules to CLAUDE.md (auto-loaded every session) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What This Project Is
Personal Internet Cell (PIC) — a self-hosted digital infrastructure platform. It manages DNS, DHCP, NTP, WireGuard VPN, email, calendar/contacts (CalDAV), file storage (WebDAV), reverse proxy (Caddy), a certificate authority, and container orchestration, all from a single API + React UI.
Common Commands
# Full stack
make start # docker-compose up -d
make stop # docker-compose down
make restart # docker-compose restart
make status # docker status + API health
make logs # docker-compose logs -f
make build # rebuild api image
# Tests
make test # pytest tests/ api/tests/
make test-coverage # pytest with coverage HTML report
make test-api # pytest tests/test_api_endpoints.py
pytest tests/test_<module>.py # single test file
# Local dev (no Docker)
pip install -r api/requirements.txt
python api/app.py # Flask API on :3000
cd webui && npm install && npm run dev # React UI on :5173 (proxies API to :3000)
# WireGuard
make show-routes
make add-peer PEER_NAME=foo PEER_IP=10.0.0.5 PEER_KEY=<pubkey>
make list-peers
Architecture
Backend (api/)
All service managers inherit BaseServiceManager (api/base_service_manager.py). This enforces a consistent interface: get_status(), get_config(), update_config(), validate_config(), test_connectivity(), get_logs(), restart_service(). When adding or modifying a service manager, follow this pattern.
The ServiceBus (api/service_bus.py) is a pub/sub event system used for inter-service communication. Services publish events (e.g., SERVICE_STARTED, CONFIG_CHANGED, PEER_CONNECTED) and subscribe to events from dependencies. Dependency graph is declared in the bus — e.g., wireguard depends on network; email depends on network and vault.
ConfigManager (api/config_manager.py) is the single source of truth. Config lives in /app/config/cell_config.json (mapped from config/api/). All managers read/write through ConfigManager, which validates against per-service schemas and maintains automatic backups.
LogManager (api/log_manager.py) provides structured JSON logging with rotation (5 MB / 5 backups per service). Use it instead of print() or raw logging.
app.py (2000+ lines) contains all Flask REST endpoints, organized by service. It runs a background health-monitoring thread.
Service managers:
network_manager.py— DNS (CoreDNS), DHCP (dnsmasq), NTP (chrony)wireguard_manager.py— VPN peer lifecycle, QR codespeer_registry.py— peer registration/lookuprouting_manager.py— NAT, firewall rules, VPN gatewayvault_manager.py— internal certificate authorityemail_manager.py— Postfix + Dovecotcalendar_manager.py— Radicale CalDAV/CardDAVfile_manager.py— WebDAV storagecontainer_manager.py— Docker SDK wrapperscell_manager.py— top-level orchestration
Frontend (webui/)
React 18 + Vite + Tailwind CSS. All API calls go through src/services/api.js (Axios). Vite dev server proxies /api to localhost:3000. Pages in src/pages/, shared components in src/components/.
Infrastructure
docker-compose.yml defines 13 services on a custom bridge network cell-network (172.20.0.0/16). Cell IPs default to 10.0.0.0/24. Key ports: 53 (DNS), 80/443 (Caddy), 3000 (API), 5173/8081 (WebUI), 51820/udp (WireGuard), 25/587/993 (mail), 5232 (CalDAV), 8080 (WebDAV).
Config files for each service live under config/<service>/. Persistent data is under data/ (git-ignored). WireGuard configs are also git-ignored.
Testing
Tests live in tests/ (28 files). Use mocking (pytest-mock) for external system calls. Integration tests in test_integration.py require Docker services running.
AI Collaboration Rules (Claude Code)
These rules apply to every Claude Code session in this repo:
- Read memory first — load
/home/roof/.claude/projects/-home-roof/memory/MEMORY.mdand referenced files at session start. - Dev machine context — you are already on pic0 (192.168.31.51), the dev machine. Execute commands here directly; do not ask the user to run them.
- Use all available agents — spawn specialized sub-agents (pic-remote, pic-qa, pic-architect, etc.) for tasks that match their description.
- make is the only interface — never call docker/docker-compose directly. All container lifecycle operations go through
make start,make stop,make build,make logs, etc. - Test every new feature — after implementing any change, run
make testbefore considering the task done. - Test before commit — the pre-commit hook enforces this, but run
make testmanually first and fix all failures before staging files.