Files
Mikkeli ceccdcc211 Document the USB webcam target, verified on the hardware
Its own repo rather than a source-selector inside camera-webui: a Codex agent is
already working in that repo on the Orin, and a second agent editing the same
files from another machine would collide for reasons unrelated to either one's
ability. Both projects exist to measure Codex + qwen3.6 on real hardware, and
two independent runs are readable where one repo full of merge conflicts is not.
Merging behind a switchable backend later is still a reasonable end state.

Hardware facts are measured, not assumed: a Logitech C505 (046d:08e3) on
/dev/video0 offering MJPG and YUYV, with a 1280x720 MJPG capture confirmed as a
genuine 33 KB JPEG by file(1) rather than by the write succeeding.

⚠ Records that /dev/video* is crowded on this board — video19 through video35
belong to the ISP and codec blocks with no camera attached, and video1 is the
webcam's metadata interface. Selecting a node by index is the obvious mistake
here, so AGENTS.md forbids it and names --list-devices and the USB ID instead.

Power is written in as a constraint rather than a footnote. The board runs on a
3 A supply with usb_max_current_enable=0, so the USB budget is the restricted
one. The C505 fits and the board is stable, but a second device may not, and the
post-mortem commands are recorded because this machine now keeps persistent
logs: a previous boot that ends in an orderly shutdown means something different
from one that stops mid-line.

AGENTS.md carries the rules earned elsewhere tonight: write files with
apply_patch and never write_stdin, stop after two identical failures instead of
incrementing an identifier, emit tool calls as JSON arguments, and read the
working tree with the shell because the gitea MCP tools see the server's copy
and cannot see anything uncommitted.
2026-08-06 00:44:19 +09:00

4.5 KiB
Raw Permalink Blame History

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 <parameter=...> 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:

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:<port>/            # 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.