2026-08-05 23:16:25 +09:00
|
|
|
# Working in this repo
|
|
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
Project instructions for Codex. The client-wide prompt lives in `~/.codex/AGENTS.md`; this file is
|
|
|
|
|
the project-specific part.
|
2026-08-05 23:16:25 +09:00
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
## Know which board you are on
|
2026-08-05 23:16:25 +09:00
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
This project spans **two different single-board computers with incompatible camera stacks**, and
|
|
|
|
|
Codex is installed on both. Getting this wrong produces code that runs where you tested it and
|
|
|
|
|
nowhere else.
|
2026-08-05 23:16:25 +09:00
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
- **Jetson Orin Nano** — the *target*. L4T / JetPack, CUDA, TensorRT. V4L2 / GStreamer, with Argus
|
|
|
|
|
(`nvarguscamerasrc`) for CSI Bayer sensors.
|
|
|
|
|
- **Raspberry Pi 5** — the *test platform*. libcamera / `rpicam` / `picamera2`. CPU-only inference.
|
2026-08-05 23:16:25 +09:00
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
**Call `platform_info` before writing anything platform-specific.** It is client-local and reports
|
|
|
|
|
the machine you are actually on, not `halogen`. Do not infer the board from the fact that both are
|
|
|
|
|
aarch64 — that is the one thing they have in common.
|
2026-08-05 23:16:25 +09:00
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
⚠ **Code written directly against `picamera2` will not run on the Orin.** Put capture behind an
|
|
|
|
|
interface with a backend per platform, selected at runtime from what the hardware reports. Everything
|
|
|
|
|
above capture — streaming, UI, recognition — depends only on "a source of frames".
|
2026-08-05 23:16:25 +09:00
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
⚠ **The Pi proves the pipeline, never the performance.** Face recognition on the Orin goes through
|
|
|
|
|
TensorRT on GPU/DLA; on the Pi it is CPU-only and will not hold a live stream. Never present a Pi
|
|
|
|
|
timing as evidence the target is fast enough, and say which board a measurement came from.
|
2026-08-05 23:16:25 +09:00
|
|
|
|
2026-08-05 23:49:55 +09:00
|
|
|
## Camera state
|
2026-08-05 23:16:25 +09:00
|
|
|
|
2026-08-05 23:49:55 +09:00
|
|
|
**Orin Nano: working.** IMX219 on CAM0 at `/dev/video0`, format `RG10` (10-bit Bayer), full frame
|
|
|
|
|
captured and verified as real data. This is the board to develop capture against.
|
2026-08-05 23:20:55 +09:00
|
|
|
|
2026-08-05 23:49:55 +09:00
|
|
|
**Pi 5: dead.** Not detected; a cable fault, with the module possibly damaged. Nothing to do there
|
|
|
|
|
until the hardware is replaced.
|
2026-08-05 23:20:55 +09:00
|
|
|
|
2026-08-05 23:49:55 +09:00
|
|
|
⚠ **The two boards failed for completely different reasons, and the fixes do not transfer.** The
|
|
|
|
|
Orin was a missing device-tree overlay — a configuration fault that looks exactly like dead hardware.
|
|
|
|
|
The Pi was genuinely a broken cable. See README.md.
|
|
|
|
|
|
|
|
|
|
⚠ **On the Pi, you cannot fix camera detection from software.** Do not add `dtoverlay=` lines or edit
|
|
|
|
|
`/boot/firmware/config.txt`; `camera_auto_detect=1` is already correct there. On the Orin the overlay
|
|
|
|
|
*is* the mechanism, but it is already configured — do not change it without being asked.
|
|
|
|
|
|
|
|
|
|
⚠ **`/dev/video*` is not evidence of a camera.** Those nodes exist on both boards with nothing
|
2026-08-05 23:20:55 +09:00
|
|
|
attached.
|
|
|
|
|
|
2026-08-05 23:49:55 +09:00
|
|
|
If you are ever on a board with no working camera, work that does not need live capture is still
|
|
|
|
|
available: the capture interface and a synthetic backend, streaming plumbing, the web UI, tests.
|
|
|
|
|
**Say plainly when you are working against a placeholder** rather than a real frame.
|
|
|
|
|
|
|
|
|
|
## ⚠ 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, which is a different
|
|
|
|
|
thing and will not create anything. `write_stdin` takes a session id that an actual `exec_command`
|
|
|
|
|
returned to you; 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 happened here, in this repo. A session got as far as creating `src/camera_webui/capture/`, then
|
|
|
|
|
tried to write `base.py` via `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.** If you find yourself writing markup like
|
|
|
|
|
`<parameter=...>` inside a string argument, you are mixing in a different tool-calling format and the
|
|
|
|
|
call will not do what you mean. That is what the loop above degenerated into.
|
2026-08-05 23:16:25 +09:00
|
|
|
|
|
|
|
|
## Constraints
|
|
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
- **Install capture libraries from system packages, not pip.** `python3-picamera2` on the Pi; the
|
|
|
|
|
Jetson camera stack ships with L4T. Both bind to system libraries and a pip build will not match.
|
|
|
|
|
- **Do not commit captured images or video.** Frames of a real room are not test fixtures. Generate a
|
|
|
|
|
synthetic fixture if one is genuinely needed.
|
|
|
|
|
- Keep dependencies few. Everything here has to build on aarch64, and on the Jetson it has to
|
|
|
|
|
coexist with a vendor-pinned CUDA and Python.
|
|
|
|
|
- Face recognition runs on **downscaled frames, off the capture thread**.
|
2026-08-05 23:16:25 +09:00
|
|
|
|
|
|
|
|
## Verifying your work
|
|
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
Claims about hardware, the stream, or performance need a command that ran:
|
2026-08-05 23:16:25 +09:00
|
|
|
|
|
|
|
|
```bash
|
2026-08-05 23:20:55 +09:00
|
|
|
# is a sensor present
|
|
|
|
|
rpicam-hello --list-cameras # Pi 5
|
|
|
|
|
v4l2-ctl --list-devices # Orin
|
|
|
|
|
|
|
|
|
|
# is the server actually serving frames
|
|
|
|
|
curl -sI http://localhost:<port>/
|
2026-08-05 23:16:25 +09:00
|
|
|
```
|
|
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
⚠ **The absence of an error is not evidence that something works.** A stream endpoint returning 200
|
|
|
|
|
with no frames and a working one are indistinguishable to `curl -o /dev/null` — check what actually
|
|
|
|
|
came back. The same applies to a capture backend that constructs cleanly and yields nothing.
|
2026-08-05 23:16:25 +09:00
|
|
|
|
|
|
|
|
## Git
|
|
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
The remote is Gitea at `192.168.2.199:3005`, reachable over SSH on port 2222.
|
2026-08-05 23:16:25 +09:00
|
|
|
|
2026-08-05 23:20:55 +09:00
|
|
|
⚠ **`tea` (the Gitea CLI) is denied by policy** and blocked by a `PreToolUse` hook. Ordinary `git` is
|
|
|
|
|
fine. **Do not push** unless the operator asks — commit locally and say what is ready.
|