Start with docs/wiki/INDEX.md, then read the topics relevant to the task.
Trust high-coverage sections; consult raw sources for medium/low coverage or
specific implementation details. Never edit generated wiki files directly;
they are regenerated by /wiki-compile.
- Check existing worktrees first and reuse a suitable one without nesting.
- Create uniquely named worktrees with Git under
<primary-repo-root>/.codex/worktrees/<task-slug>by default. - Work and test inside the selected worktree. Preserve unrelated changes and existing worktrees.
- Ignore only
/.codex/worktrees/through Git's localinfo/exclude; keep other.codex/files visible.
Next.js App Router runs on the pod and controls its hardware:
src/hardware/: DAC Unix-socket transport to frankenfirmware, status polling, gestures, pump-stall protection, and snooze.src/server/: tRPC routers and REST endpoints at/api/*. The API uses a LAN-only trust model without authentication; seesrc/server/openapi.ts.src/scheduler/: JobManager for temperature, power, alarms, and system jobs.src/automation/: Autopilot rules evaluated in the device timezone.src/streaming/: WebSocket sensor stream on port 3001, frame normalization, and the optional MQTT bridge with Home Assistant discovery.src/homekit/: HAP thermostats, snooze switches, and sensors; hardware writes pass throughsideControllerandsideLock.src/db/: Drizzle schemas forsleepypod.db(configuration/state) andbiometrics.db(time series), with separate migration directories.modules/: Python sensor-processing daemons;modules/common/is shared.app/,src/components/,src/hooks/: UI. Device status prefers WebSocket updates with a tRPC fallback throughuseDeviceStatus.
- Per-side hardware writes must use
withSideLock. - Shared singletons belong on
globalThis; Turbopack can load multiple module instances. - DAC commands are strictly sequential because the protocol has no correlation IDs. Read only the response to the command just sent.
- Add behavioral regression tests for fixes; Stryker tracks surviving mutants.
Vitest tests live beside the code in
tests/; Python tests live within each module and stub pod-only imports when needed. - Use each Python module's locked uv dependencies. Unpinned NumPy/SciPy versions
can change signal-processing results. CI's module matrix is defined in
.github/workflows/python-modules.yml. - For schema changes, edit
src/db/*schema.tsand generate migrations for the appropriate database. Never hand-edit migration journals; theirwhenvalues must remain strictly increasing. - Run the relevant tests and quality gates before pushing. Keep commits focused and use conventional commit subjects.
Every PR to main is a release promotion. Its title must start with feat:,
fix:, perf:, or revert: (optional scope and breaking-change !). The
PR title gate enforces these prefixes so the promotion triggers a release.
Complete requested publishing work by pushing and verifying the remote state.
The main merge queue squashes, so each release leaves main with a commit
dev lacks. .github/workflows/back-merge.yml runs after "Analyze & Release"
succeeds and pushes a real --no-ff merge of main into dev (never through
dev's merge queue, which would squash it). It needs the BACKMERGE_TOKEN
secret: an org-admin fine-grained PAT or a GitHub App installation token with
contents: write, whose actor is on the Dev ruleset bypass list. Without the
secret it skips; on conflict it pushes nothing and opens a "Back-merge main →
dev needs a hand" issue with the manual steps.
Use docs/DEBUGGING.md for SSH access, data paths, biometrics failures, and
pump-stall diagnosis. The /debug console exposes live diagnostics.
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ (resolved from this file's directory; in monorepos the next package may not be visible from the repo root) before writing any code. Heed deprecation notices.
This block is written and re-added by next dev — verify at node_modules/next/dist/server/lib/generate-agent-files.js. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.