# Working in this repo Project instructions for Codex on `pi5`. The client-wide prompt lives in `~/.codex/AGENTS.md`; this file is the project-specific part. ## Where you are **You are on the target hardware.** `pi5` is the Raspberry Pi 5 this runs on, with the webcam physically attached. You can test everything for real — there is no deploy step and no emulation. Use that: prefer running the thing over reasoning about whether it would run. `platform_info` confirms which machine you are on if you need it. ⚠ **Do not copy code or assumptions from the sibling `camera-webui` repo.** That one targets a Jetson Orin Nano with a CSI IMX219 and uses a different capture stack entirely. Here it is plain **V4L2 / UVC** — no libcamera, no `picamera2`, no Argus, no device-tree overlays. ## The camera **Logitech C505 HD Webcam at `/dev/video0`**, offering `MJPG` and `YUYV`. A 1280x720 MJPG capture is verified working. ⚠ **Never select a video node by index.** This board exposes `/dev/video19`–`/dev/video35` for its ISP and codec blocks with no camera involved, and `/dev/video1` is the webcam's *metadata* interface, not a capture device. Resolve the device with `v4l2-ctl --list-devices`, or by matching the USB ID `046d:08e3` — never by assuming `video0` is stable across reboots or a second camera being plugged in. **Prefer `MJPG` for streaming.** The camera compresses in hardware; `YUYV` is uncompressed and makes the Pi's CPU do encoding work that is already done for you. ## ⚠ Writing files, and not looping **Write files with `apply_patch`**, or a heredoc through the shell. **Never** use `write_stdin` to create file contents — it writes to the stdin of an already-running process and will not create anything. `write_stdin` takes a session id that an actual `exec_command` returned; never invent one and never increment one. **If the same tool call fails twice with the same error, STOP and report it.** Do not retry, and do not vary an identifier hoping one works. A repeated identical failure means the assumption is wrong, not that the call needs another attempt. This is from life, in the sibling repo: an agent tried to write a file with `write_stdin`, was told `Unknown process id 45`, and answered by incrementing the id — 46, 47, 48 — for **27 attempts over nine minutes** until a human killed it. ⚠ **Emit tool calls as the API's JSON arguments only.** Markup like `` inside a string argument means you are mixing in a different tool-calling format, and the call will not do what you mean. ## ⚠ Read the working tree with the shell, not over MCP The `gitea__*` tools read the **Gitea server's** copy of a repo over its API. They do not see this machine's files. Anything uncommitted or unpushed is invisible to them, so a file fetched that way can be silently stale. **Use the shell for files in front of you.** Use the MCP tools only for repo state you have not cloned — history, issues, another repository. ## Constraints - **Power is tight.** The Pi is on a 3 A supply with a restricted USB budget (`usb_max_current_enable=0`). The webcam fits; a second USB device may not. Do not add powered peripherals, and do not assume headroom. - **Install from system packages where possible** (`apt`), not pip, for anything binding to system libraries. Keep dependencies few — they all have to build on aarch64. - **Do not commit captured images or video.** Frames of a real room are not test fixtures. Generate a synthetic one if a fixture is genuinely needed. - This is a **4-core Pi 5 with no GPU acceleration for inference.** Anything per-frame must be cheap, and must run off the capture thread. ## Verifying your work Claims about the camera or the stream need a command that ran: ```bash v4l2-ctl --list-devices # which node is really the webcam v4l2-ctl -d /dev/video0 --list-formats # what it can actually produce curl -sI http://localhost:/ # is the server responding ``` ⚠ **The absence of an error is not evidence that something works.** A stream endpoint returning 200 with no frames is indistinguishable from a working one unless you look at what came back. A capture that writes a file proves nothing until the file is checked — `file frame.jpg` must say `JPEG image data`, not merely exist with a non-zero size. ## Git The remote is Gitea at `192.168.2.199:3005`, over SSH on port 2222. ⚠ **`tea` (the Gitea CLI) is denied by policy.** Ordinary `git` is fine. **Do not push** unless the operator asks — commit locally and say what is ready.