docs: CLAUDE.md v3.5 - add VSC terminal label, session log bridge
This commit is contained in:
parent
785ec56432
commit
6498c14dc2
562
CLAUDE.md
562
CLAUDE.md
@ -1,249 +1,385 @@
|
||||
# Argonaut 3 — ROV Autonomous Inspection System
|
||||
This file defines how Claude should behave when working in this repository.
|
||||
Prioritise correctness, safety, and field-operational reliability above all else.
|
||||
This is a real autonomous vehicle system. Code runs on hardware in water.
|
||||
# CLAUDE.md — Rules for Claude on the Argonaut 3 Project
|
||||
**Version:** 3.5
|
||||
**Updated:** 8 July 2026
|
||||
|
||||
**Changelog 3.5:** Added `[VSC]` terminal label. Added SESSION LOG section + write triggers
|
||||
(bridges Claude Code work back to claude.ai chat, which has no native access to Claude Code
|
||||
sessions).
|
||||
|
||||
---
|
||||
|
||||
# Project Identity
|
||||
## PRIME DIRECTIVES — These override everything else
|
||||
|
||||
- **Project:** Argonaut 3 — Autonomous Underwater ROV Inspection System
|
||||
- **Company:** SymbyTech
|
||||
- **Vehicle:** Argonaut 3 based on the BlueROV2 Heavy (Blue Robotics)
|
||||
- **Target:** Hull and jacket surveys, no human operator during field operations
|
||||
- **Status:** Active development — Phase 2 (dev infrastructure) complete
|
||||
### 1. Research before acting. Always.
|
||||
Before any technical decision, code change, or command:
|
||||
- Read project docs (handover, UI design, DIR, this file) and search past chat history
|
||||
- Read source code and official docs before acting; GitHub source/issues are more
|
||||
authoritative than official docs for Cockpit/BlueOS specifics
|
||||
- Confirm facts from sources, not from memory
|
||||
|
||||
If uncertain: **search first, then act**. Never guess.
|
||||
|
||||
### 2. Time and tokens are finite and valuable
|
||||
- **Time wasting is FORBIDDEN. Token wasting is FORBIDDEN.**
|
||||
- Short replies. No preamble padding. To the point.
|
||||
- Never repeat an approach that has already failed
|
||||
- Never ask for information already in the project docs
|
||||
- Never issue a command without knowing what it will do and why
|
||||
|
||||
### 3. Facts only. Never assumptions.
|
||||
- Do not proceed based on what "should" work
|
||||
- Do not assume port, routing, or API behaviour — measure it
|
||||
- Do not infer system state — verify it before issuing commands
|
||||
- If a claim cannot be verified from a source, say so explicitly
|
||||
- Never present a prior session's confirmed state as the current running state
|
||||
|
||||
---
|
||||
|
||||
# Tech Stack
|
||||
## Working Style
|
||||
|
||||
- **Primary language:** Python 3 (ROS2 nodes), C++ reserved for latency-critical paths only
|
||||
- **Framework:** ROS2 Jazzy Jalisco
|
||||
- **Vehicle OS:** BlueOS (Blue Robotics) on Raspberry Pi 4
|
||||
- **Autonomy compute:** Raspberry Pi 5, Ubuntu 24.04 LTS
|
||||
- **MAVLink bridge:** MAVROS
|
||||
- **Container runtime:** Docker (ARM64 images via buildx + QEMU)
|
||||
- **Registry:** Harbor (self-hosted) — `registry.symbytech.com`
|
||||
- **Source control:** Gitea (self-hosted) — `git.symbytech.com`
|
||||
- **GCS:** Cockpit (BlueOS extension)
|
||||
- **Dev simulation:** BlueOS internal ardupilot-manager SITL (ArduSub 4.5.7)
|
||||
- **Package manager:** pip (Python), colcon (ROS2 workspace)
|
||||
### One command at a time
|
||||
Give one command, wait for feedback, then give the next. Never batch commands unless asked.
|
||||
|
||||
### Lead with context and corrections BEFORE instructions, never after.
|
||||
|
||||
### Copy-paste friendly commands
|
||||
Commands inside terminal blocks must be immediately copy-pasteable and suitable for the
|
||||
terminal in use (Git Bash on the laptop, bash on the Pis/server). Never include:
|
||||
- Placeholders like `<YOUR_IP>` or `path/to/file`
|
||||
- Hashed `#` comments inside the command block
|
||||
- Options that require editing before running
|
||||
|
||||
### Code comments
|
||||
When writing code (Python, config, scripts), always include full inline comments
|
||||
explaining what each section does and why. This is a standing user preference.
|
||||
NOTE: this applies to CODE files only — NOT to terminal command blocks, which must
|
||||
stay clean and copy-paste ready with no inline comments.
|
||||
|
||||
### Terminal labels
|
||||
Every command block is preceded by a plain-text terminal label above the block.
|
||||
Grant pastes terminal output including the shell prompt — use these to identify
|
||||
which device the output came from:
|
||||
|
||||
| Label | Shell prompt | Device | IP |
|
||||
|---|---|---|---|
|
||||
| `[SERVER]` | `grant@symbytech:~$` | Dell PowerEdge R210 | 192.168.1.175 |
|
||||
| `[RPi5]` | `ubuntu@rov-brain:~$` | Raspberry Pi 5 autonomy brain | 192.168.1.101 |
|
||||
| `[RPi4]` | `pi@blueos:~$` | Raspberry Pi 4 BlueOS gateway | 192.168.1.100 |
|
||||
| `[LAPTOP — Git Bash]` | `grant@BB8 MINGW64 ...` | Windows field laptop BB8 | — |
|
||||
| `[VSC]` | — | VS Code integrated terminal on BB8 (local Windows session at `C:\Users\grant\Desktop\Autonomous ROV System`) | — |
|
||||
| `[BROWSER]` | — | Web browser on laptop | — |
|
||||
| `[COCKPIT]` | — | Cockpit native desktop app on laptop | — |
|
||||
|
||||
`[VSC]` is a **local Windows session on BB8, NOT a Remote-SSH session to rov-brain**, unless
|
||||
explicitly stated otherwise. Do not assume `[VSC]` == RPi5 working copy.
|
||||
|
||||
Never put the label inside the bash block.
|
||||
|
||||
> The BlueOS KVM VM (`blueos-vm`) was decommissioned once RPi4/RPi5 hardware became
|
||||
> operational. `[VM]` is no longer a valid label. Any VM artefacts remaining on the
|
||||
> server are for reference only.
|
||||
|
||||
### Verify before modifying
|
||||
Always read a file before modifying it. Always check current state before changing it.
|
||||
State what you observed before proposing a change.
|
||||
|
||||
### File operations
|
||||
Read the exact file first, then `str_replace` with exact matching text. Remove old
|
||||
versions before writing new ones. Complete files, not fragments — no partial code.
|
||||
|
||||
### No guessing at code
|
||||
When writing code that interfaces with an external system:
|
||||
1. Find the official documentation or source code
|
||||
2. Find a working example from the official repo or community
|
||||
3. Build on the confirmed example
|
||||
Never invent API calls, message formats, or connection strings.
|
||||
|
||||
### Own mistakes once
|
||||
Acknowledge an error once and fix it. No repeated apologies, no grovelling.
|
||||
|
||||
### KISS
|
||||
Recommend the simple correct path, not a menu of options.
|
||||
|
||||
---
|
||||
|
||||
# Repository Structure
|
||||
|
||||
```
|
||||
rov-autonomy/
|
||||
├── src/
|
||||
│ ├── rov_interfaces/ # Custom ROS2 messages and services — shared contracts
|
||||
│ ├── rov_navigation/ # State estimation, EKF, depth fusion
|
||||
│ ├── rov_perception/ # Camera nodes, feature detection
|
||||
│ ├── rov_control/ # Failsafe monitor, motion controller
|
||||
│ ├── rov_mission/ # Mission executor, waypoint sequencing
|
||||
│ ├── rov_bringup/ # Top-level launch files
|
||||
│ └── rov_simulation/ # DEV ONLY — mock publishers, test scenarios
|
||||
├── Dockerfile # ARM64 image build — targets RPi5
|
||||
├── docker-entrypoint.sh # Container startup — sources ROS2 + workspace
|
||||
└── CLAUDE.md # This file
|
||||
```
|
||||
|
||||
**Critical rule:** `rov_simulation` is dev-only. Never include it in production builds or deploy it to vehicle hardware.
|
||||
## CREATE-THEN-BACKUP (non-negotiable)
|
||||
When any new component (device, drive, service, config, OS install) is created or
|
||||
configured, a backup must be put in place immediately as part of that work — not
|
||||
deferred. Backups and foundational architecture (storage, recovery, monitoring) are
|
||||
prerequisites, prioritised BEFORE new feature/build work. The RPi4 SD failed with no
|
||||
backup because this was deferred — do not repeat.
|
||||
|
||||
---
|
||||
|
||||
# Core Principles
|
||||
## Project-Specific Rules
|
||||
|
||||
- **Asset preservation over mission completion.** A recovered vehicle can repeat a mission. A lost vehicle cannot.
|
||||
- **Field-operational from day one.** The same codebase runs in dev and field — environment is selected by config, not by code changes.
|
||||
- **Safety is continuous, not reactive.** Failsafe monitoring runs at all times, not only on failure.
|
||||
- **Prefer simple, readable solutions.** This code may be read under pressure in the field.
|
||||
- **No premature optimisation.** Correctness first, performance when measured.
|
||||
- **Keep functions small and single-purpose.**
|
||||
- **Do not introduce new dependencies without explicit approval.** Each dependency is a liability on embedded hardware.
|
||||
### Cockpit DIY widgets
|
||||
- Cockpit is **v1.18.2** (native desktop app mandatory — browser/Lite extension does
|
||||
NOT support DIY widgets)
|
||||
- JSON format with `html`/`css`/`js` string fields
|
||||
- CSS hard constraints: no `body {}`/`:root {}` global blocks, no `@keyframes`, no
|
||||
unicode in JS strings, no `position: fixed`, no global tag selectors
|
||||
- No `async/await` in widget JS — use `.then()/.catch()`
|
||||
- Use `var` not `let`/`const` in widget JS for compatibility
|
||||
- Correct live-value getter: `window.cockpit.getDataLakeVariableData(variableId)`
|
||||
(CONFIRMED v1.18.2). `getDataLakeValue()` and `listenToDatalakeVariable()` do NOT
|
||||
exist in DIY widget scope. `getAllDataLakeVariablesInfo()` is metadata-only.
|
||||
- Widget JSON files in the repo use underscore naming: `w6_altitude.json` (matches
|
||||
W0–W5). The Cockpit-loaded widget is stored by internal config, not filename, so the
|
||||
repo filename is the canonical reference.
|
||||
|
||||
### Data injection into Cockpit data lake
|
||||
- ONLY working external-injection method is the Generic WebSocket Connections feature
|
||||
(Settings → General). Production path is the `cockpit_bridge` ROS2 node (rov_mission,
|
||||
WebSocket :9001).
|
||||
- Message format: `variable-name=value` (one per send). Data lake key: `external/{name}`.
|
||||
- ALWAYS use hyphens — Cockpit normalises underscores to hyphens in IDs.
|
||||
- HTTP POST to mavlink2rest does NOT work for data lake injection. MAVLink UDP injection
|
||||
from external scripts does NOT work. Tested and confirmed — do not suggest them.
|
||||
- Current data lake variables published by `cockpit_bridge` (19 total — 8 telemetry + 11 mode-profile flags):
|
||||
|
||||
| Variable | Source topic | Meaning |
|
||||
|---|---|---|
|
||||
| `external/rov-failsafe` | `/rov/failsafe` | 0=GREEN, 1=AMBER, 2=RED |
|
||||
| `external/rov-depth` | `/rov/depth` | Depth in metres |
|
||||
| `external/rov-voltage` | `/mavros/battery` | Battery voltage |
|
||||
| `external/rov-heading` | `/mavros/mavros/compass_hdg` | Compass heading degrees |
|
||||
| `external/rov-ms` | `/rov/mission/status` | Mission state integer |
|
||||
| `external/rov-mp` | `/rov/mission/status` | Mission progress 0-100% |
|
||||
| `external/rov-recording` | `/rov/recording/active` | 1=recording, 0=not recording |
|
||||
| `external/rov-altitude` | `/ping2/altitude` | Ping2 altitude metres (-1.0=NO SONAR) |
|
||||
| `external/rov-mode` | `/rov/mode/profile` | Active profile name: ROV / AUV / hybrid |
|
||||
| `external/rov-mode-base` | `/rov/mode/profile` | Base mode: 0=ROV, 1=AUV |
|
||||
| `external/rov-hilt` | `/rov/mode/profile` | HILT: 1=present, 0=absent |
|
||||
| `external/rov-health-role` | `/rov/mode/profile` | W1: 0=advisory, 1=gate |
|
||||
| `external/rov-rec-control` | `/rov/mode/profile` | Recording: 0=manual, 1=auto |
|
||||
| `external/rov-nogo-gate` | `/rov/mode/profile` | No-go: 0=relaxed, 1=enforced |
|
||||
| `external/rov-rec-reminder` | `/rov/mode/profile` | ARM reminder: 1=on, 0=off |
|
||||
| `external/rov-return-mode` | `/rov/mode/profile` | Return: 0=operator-selectable, 1=autonomous |
|
||||
| `external/rov-live-telem` | `/rov/mode/profile` | Telemetry: 0=on, 1=predive-only |
|
||||
| `external/rov-nav-display` | `/rov/mode/profile` | Nav: 1=shown, 0=autonomy-only |
|
||||
| `external/rov-camera-role` | `/rov/mode/profile` | Camera: 0=pilot-primary, 1=record-only |
|
||||
|
||||
### FastAPI backend (rov_api)
|
||||
- `rov_api` package provides the HTTP-to-ROS2 bridge on port 8081. Runs as
|
||||
`argonaut-api.service` (manual-start in dev, same policy as argonaut.service).
|
||||
- Architecture: uvicorn/FastAPI in the main thread, an embedded rclpy node
|
||||
(`RovApiNode`) spinning in a daemon background thread. HTTP handlers call thread-safe
|
||||
methods on the node. Do NOT call `rclpy.spin()` more than once.
|
||||
- Core endpoints (Stage 2, live): `GET /health`, `POST /abort` (W3 RETURN TO SAFE,
|
||||
publishes Bool to `/rov/mission/abort`), `POST /mission/start` (MissionCommand START),
|
||||
`POST /mission/stop` (MissionCommand ABORT).
|
||||
- Deferred to Stage 2b: `/return_budget` (W5), `/backup/status` + `/backup/delay` (W7,
|
||||
Option A design), `/mission/upload`.
|
||||
- **W3 abort path is vehicle-layer:** publishes Bool(true) to `/rov/mission/abort`, which
|
||||
failsafe_monitor latches as `flag_manual_abort` → FSM NORMAL → HOLD_AND_RECOVER. This is
|
||||
DIR-5 return-to-safe, NOT the mission ABORT service. Do not confuse the two.
|
||||
- **Python dependencies:** fastapi + uvicorn installed system-wide on RPi5 via
|
||||
`sudo pip3 install fastapi uvicorn --break-system-packages --ignore-installed typing_extensions`.
|
||||
The `--ignore-installed typing_extensions` flag is required — the Debian-managed
|
||||
typing_extensions has no pip RECORD file and blocks the install otherwise.
|
||||
|
||||
### Deploy files (version-controlled)
|
||||
- systemd units and launch wrappers live outside the workspace but are version-controlled
|
||||
in the repo `deploy/` folder (copies; authoritative running copies at deploy locations).
|
||||
- `deploy/argonaut.service` → `/etc/systemd/system/argonaut.service`
|
||||
- `deploy/argonaut-stack.sh` → `/usr/local/bin/argonaut-stack.sh`
|
||||
- `deploy/argonaut-api.service` → `/etc/systemd/system/argonaut-api.service`
|
||||
- `deploy/argonaut-api.sh` → `/usr/local/bin/argonaut-api.sh`
|
||||
- `deploy/README.md` documents locations, pip deps, and install procedure.
|
||||
- `/home/ubuntu/ros2_ws` is a symlink to `/data/ros2_ws` — both wrappers rely on it.
|
||||
|
||||
### Recording architecture (DIR-9a — ARM-bounded black-box)
|
||||
- Recording is a **single ARM-bounded tier** for black-box/debug/ML/fault-finding via
|
||||
`recording_manager`. **AUV:** starts on ARM, stops on DISARM. **ROV:** operator
|
||||
start/stop; the ARM edge fires a reminder ("armed, not recording"). Keyed to the
|
||||
`recording_control` flag, not the mode. (Supersedes the old continuous DIR-9 model.)
|
||||
- **No-go coupling:** AUV `enforced` — recording fail → mission stops, vehicle recovered.
|
||||
ROV `relaxed` — recording fail after ARM → pilot alerted; operator resolves in-water
|
||||
or recovers.
|
||||
- Certified deliverable capture is OUT of scope pending Class-approved devices; recorded
|
||||
data is dev/debug/ML only, never a client deliverable until then.
|
||||
- The recorder manages a `ros2 bag record` subprocess — MCAP format, zstd compression,
|
||||
500MB bag splitting, 10GB free-space retention on `/data`.
|
||||
- **`foxglove_bridge` is visualisation only — it does NOT record MCAP.** Correct this
|
||||
wherever the old "MCAP via foxglove_bridge" claim appears.
|
||||
- Bags written to `/data/bags/dive_<timestamp>/` on NVMe.
|
||||
- No camera in the topic set currently — recording ~2.5 MB/s (nav/MAVLink only).
|
||||
- **Storage (no reliable in-field server backup):** primary lever is LOWER PUBLISH RATES
|
||||
on heavy streams (keep topics present for debug); ARM-bounded runs self-limit; retention
|
||||
cap tunable; NVMe expansion later. Topic/rate review is an open action.
|
||||
|
||||
### Operating-mode profiles (DIR-1/2, mode_profiles.yaml)
|
||||
- One widget set; behaviour is set by flags from a mode profile. Dominant axis is HILT
|
||||
(tether present = ROV / live interfaces; absent = AUV / headless).
|
||||
- **Source of truth:** `mode_profiles.yaml` in `rov_mission/config` — ROV/AUV defaults
|
||||
plus custom hybrid via "Save As". Hybrid is NOT a third mode; it is any saved profile
|
||||
with overrides.
|
||||
- `mode_profile_loader` (rov_mission) resolves the active profile into a `ModeProfile`
|
||||
message (rov_interfaces), publishes it LATCHED on `/rov/mode/profile`, reloadable via
|
||||
the `/rov/mode/reload` (std_srvs/Trigger) service. Fail-safe: invalid flag values are
|
||||
rejected and the last-good profile is retained.
|
||||
- `cockpit_bridge` surfaces the 11 flags to the data lake as `external/rov-*`. Widgets
|
||||
read the flags, NOT the mode.
|
||||
- Flags: hilt, health_role (advisory|gate), recording_control (manual|auto), nogo_gate
|
||||
(relaxed|enforced), record_reminder_on_arm, return_mode (operator_selectable|autonomous),
|
||||
live_telemetry (on|predive_only), nav_display, camera_role (pilot_primary|record_only).
|
||||
- **YAML gotcha:** YAML 1.1 parses bare `on`/`off`/`yes`/`no` as booleans — quote enum
|
||||
values like `"on"`. The loader also normalises bool→string as a guard.
|
||||
|
||||
### BlueOS / MAVLink router
|
||||
- **MAVLinkRouter** is the confirmed router. Do NOT recommend MAVP2P — BlueOS itself
|
||||
warns "MAVP2P has been presenting issues and is not currently recommended."
|
||||
- MAVP2P was tried and reverted. Do not suggest it again.
|
||||
- The BlueOS ardupilot-manager FD exhaustion bug (Docker default `nofile=1024`) is
|
||||
fixed permanently via `/etc/docker/daemon.json` with `nofile` hard/soft = 65536.
|
||||
This fix must survive reboots — it is a host-level daemon config, not a container flag.
|
||||
Root cause: accumulated TCP socket FDs from continuous UI polling exhaust the 1024
|
||||
default; symptoms are connect/disconnect cycling and AUTOPILOT_*_FETCH_FAIL.
|
||||
|
||||
### Hardware facts (do not re-question)
|
||||
- **RPi5 storage:** boots from SD card (`/dev/mmcblk0`). NVMe holds DATA ONLY (`/data` —
|
||||
ros2_ws, bags, logs). Backup images the SD for OS, rsyncs `/data` for data.
|
||||
- **Flight controller:** Pixhawk 2.4.8 on `/dev/ttyACM0` is the active flight controller.
|
||||
SITL is NOT used in production. BlueOS `preferred_board` = Pixhawk1.
|
||||
- **Tailscale on RPi5:** installed but stopped and disabled (`tailscaled.service` disabled
|
||||
2 Jul 2026). Re-enable with `sudo systemctl enable --now tailscaled` if remote access
|
||||
to RPi5 is needed.
|
||||
|
||||
### Hostname resolution (DNS)
|
||||
- Hostnames `symbytech` (192.168.1.175), `blueos` (192.168.1.100), and `rov-brain`
|
||||
(192.168.1.101) are resolvable from the laptop (Windows hosts file) and RPi5
|
||||
(`/etc/hosts`). Grant prefers hostnames over IPs.
|
||||
- Git remotes use the hostname form: `ssh://git@symbytech:222/administrator/rov-autonomy.git`
|
||||
- If a "Could not resolve hostname symbytech" error appears on a machine, that machine is
|
||||
missing the hosts entries — add them rather than switching remotes to IPs.
|
||||
|
||||
### Backup system (built 30 Jun 2026)
|
||||
- Push model: each Pi self-backs-up via root cron, pushes to server over SSH (no inbound
|
||||
access to Pis).
|
||||
- RPi4: `/usr/local/bin/rov-brain-pi4-backup.sh`, 00:00 daily.
|
||||
- RPi5: `/usr/local/bin/rov-brain-pi5-backup.sh`, 00:30 daily (staggered).
|
||||
- Server monitor `check_rov_backup` alerts on FAILED (always) and OVERDUE (≥2 days,
|
||||
online or offline, throttled weekly).
|
||||
- Field/ops backup model is operator-aware, never unattended mid-dive (DIR-11, W7).
|
||||
|
||||
### argonaut.service / argonaut-api.service (RPi5)
|
||||
- Manual start is deliberate for both. Verify BlueOS heartbeat first, then
|
||||
`sudo systemctl start argonaut.service`. Do NOT enable auto-start until field-ready.
|
||||
Restate this rule each time it comes up.
|
||||
- `argonaut-api.service` orders After=argonaut.service but does not Require it — the API
|
||||
can start independently for /health checks; mission commands return a clear
|
||||
"service unavailable" error if the stack is down.
|
||||
|
||||
### ROS2 code
|
||||
- Check `rov_interfaces` message definitions before writing any node code
|
||||
- Use `self.get_logger()` not `print()`
|
||||
- Do not hardcode IPs, ports, or thresholds
|
||||
- Do not deploy `rov_simulation` in production launch files
|
||||
- Editing an installed launch/config requires `colcon build --packages-select <pkg>` —
|
||||
the running launch uses the installed copy under install/, not src/
|
||||
- ARM64 Docker builds on the laptop only (buildx), never on the server
|
||||
|
||||
### Git workflow
|
||||
- Commit to `master` on `administrator/rov-autonomy`
|
||||
- Gitea SSH remote (hostname form): `ssh://git@symbytech:222/administrator/rov-autonomy.git`
|
||||
- Both laptop and RPi5 resolve `symbytech` via hosts entries (see Hostname resolution).
|
||||
- Widget JSON files are re-imported from the laptop (source of truth for widgets) and
|
||||
pushed to Gitea — never overwritten from chat history.
|
||||
- UFW rules before starting new services on new ports.
|
||||
|
||||
### Security — deferred to pre-field hardening pass
|
||||
- **UFW:** currently inactive on RPi5. Deferred because there is no online exposure
|
||||
(Tailscale disabled, no proxy rules to the Pis). When enabling: allow SSH (22),
|
||||
operator TCP (8765, 9001, 8081), and all traffic from LAN subnet 192.168.1.0/24
|
||||
(covers ROS2 DDS dynamic ports — do NOT try to pin them individually), then default
|
||||
deny incoming. Bundle with SSH password change. Trigger: before remote ops or field.
|
||||
- **RPi5 SSH password:** weak dev password, password auth enabled. Change to strong
|
||||
password before field deployment.
|
||||
|
||||
---
|
||||
|
||||
# Code Style
|
||||
## What Claude MUST do
|
||||
- State confirmed facts before proposing an action; cite the source of any technical claim
|
||||
- Acknowledge when something has already been tried and failed
|
||||
- Provide complete, working code (fully commented) based on confirmed examples
|
||||
- Verify system state before and after changes
|
||||
- Update the handover doc at the end of each session (version-controlled, changelog)
|
||||
|
||||
- Follow PEP 8 for Python
|
||||
- Use consistent formatting already present in the file being edited
|
||||
- Prefer explicit code over clever shorthand
|
||||
- Always add full inline comments — every function, every non-obvious line
|
||||
- Use meaningful variable and function names — no abbreviations unless standard ROS2/MAVLink convention
|
||||
- Avoid deeply nested logic (>3 levels)
|
||||
- No commented-out code in final output
|
||||
- All ROS2 nodes must have a module-level docstring listing: purpose, subscribed topics, published topics, services
|
||||
## What Claude MUST NOT do
|
||||
- Guess at how a system works and propose commands based on that guess
|
||||
- Repeat a failed approach
|
||||
- Issue commands whose outcome is uncertain
|
||||
- Provide partial code requiring manual editing to work
|
||||
- Assume a system is stable without checking
|
||||
- Use `print()` in ROS2 nodes; hardcode addresses/ports/thresholds
|
||||
- Build x86 Docker images for vehicle deployment
|
||||
- Change the failsafe priority order without design review
|
||||
- Present prior-session state as current running state
|
||||
- Recommend MAVP2P as the MAVLink router
|
||||
- Commit docs to Gitea — only code and README go to Gitea; docs live in Claude project knowledge
|
||||
|
||||
---
|
||||
|
||||
# ROS2 Rules
|
||||
|
||||
- All custom messages live in `rov_interfaces` — do not define messages inside other packages
|
||||
- Always declare parameters explicitly with `declare_parameter()` before `get_parameter()`
|
||||
- Load configuration from YAML files via launch — do not hardcode values in nodes
|
||||
- Use `self.get_logger()` for all logging — never `print()`
|
||||
- Timers must be named and cancellable when rate changes are required
|
||||
- Topic names use the `/rov/` prefix namespace for all custom topics
|
||||
- Always include a `Header` with timestamp in custom messages
|
||||
- Destroy nodes cleanly in `finally` blocks
|
||||
## Documentation discipline
|
||||
- All project docs (handover, UI design, DIR, this file, sim/ML plan) are maintained as
|
||||
COMPLETE replacement files uploaded to Claude project knowledge — never patches or
|
||||
fragments, never committed to Gitea.
|
||||
- Version numbers and changelogs maintained on every update.
|
||||
- Only code and README files go to Gitea.
|
||||
|
||||
---
|
||||
|
||||
# Failsafe Rules
|
||||
## SESSION LOG (bridges Claude Code → claude.ai chat)
|
||||
|
||||
**These are safety-critical. Do not change without explicit instruction and design review.**
|
||||
**Why this exists:** Claude Code (VS Code) and the claude.ai chat are separate systems with
|
||||
no shared memory. Claude Code reads this file at session start but the claude.ai chat cannot
|
||||
see Claude Code's session history at all. This log is the bridge.
|
||||
|
||||
- Assessment states: GREEN / AMBER / RED — defined in `FailsafeStatus.msg`
|
||||
- Assessment runs continuously at dynamic rates: 5 Hz (GREEN), 20 Hz (AMBER), 50 Hz (RED)
|
||||
- Priority order is fixed — see `ROV_Failsafe_Design_v2.0.md`
|
||||
- All thresholds are configurable via YAML — never hardcode safety values
|
||||
- `EMERGENCY_SURFACE` is the last resort — it must never be the first response
|
||||
- Comms timeout default: 2 seconds — configurable per deployment
|
||||
- Battery thresholds: warning 25%, return 20%, critical 12%, emergency 8%
|
||||
**Format:** `YYYY-MM-DD — one-line summary of decision/change (commit hash if applicable)`
|
||||
|
||||
**Claude Code MUST append an entry here at the end of any session where one of these
|
||||
happened** — not for routine edits, refactors, or in-progress work:
|
||||
- A design/architecture decision was made or changed (DIR-level, mode-flag behaviour,
|
||||
failsafe priority, recording behaviour)
|
||||
- A hardware fact was confirmed or changed (wiring, storage layout, board config)
|
||||
- A security-relevant change was made (SSH, UFW, credentials, exposure)
|
||||
- A backup/recovery-relevant change was made
|
||||
- A bug was root-caused and fixed (not just patched)
|
||||
- A previously-deferred item was completed or its trigger condition changed
|
||||
- Anything Grant would reasonably expect the claude.ai chat to already know next time he
|
||||
opens it
|
||||
|
||||
**Skip:** typo fixes, comment-only changes, WIP/incomplete work, anything already fully
|
||||
captured by the git commit message with no extra context needed.
|
||||
|
||||
**Workflow:** Grant pastes new entries into the claude.ai chat when relevant; Claude folds
|
||||
them into chat memory via the memory tool. This log is append-only — do not edit past
|
||||
entries; correct forward with a new dated entry if something needs revising.
|
||||
|
||||
- 2026-07-05 — Widget housekeeping: added W6 altitude widget, removed probe diagnostics
|
||||
widget (`785ec56`)
|
||||
|
||||
---
|
||||
|
||||
# Package-Specific Rules
|
||||
|
||||
**rov_interfaces**
|
||||
- Changing a message definition requires updating all nodes that use it
|
||||
- Constants in messages use ALL_CAPS naming
|
||||
- Never remove a field from a message without confirming no node depends on it
|
||||
|
||||
**rov_control**
|
||||
- `failsafe_monitor.py` must always be the first node started in any launch file
|
||||
- Do not modify the priority order in `_apply_failsafe_priority()` without design review
|
||||
|
||||
**rov_mission**
|
||||
- Waypoints are loaded from YAML files — never hardcoded
|
||||
- The breadcrumb buffer must be cleared at mission start and never between waypoints
|
||||
- Entry point is recorded once at mission start — do not update it during flight
|
||||
|
||||
**rov_simulation**
|
||||
- Every file in this package must have the `DEV ONLY — NOT FOR DEPLOYMENT` warning in its docstring
|
||||
- Scenario names must be documented in the node docstring
|
||||
- Never subscribe to real hardware topics from simulation nodes
|
||||
|
||||
**rov_bringup**
|
||||
- Launch files must load config from the package share directory — never from absolute paths
|
||||
- The `env` argument selects between `dev` and `field` configs — always provide a default of `dev`
|
||||
|
||||
---
|
||||
|
||||
# Docker / Build Rules
|
||||
|
||||
- Target architecture: `linux/arm64` — always build with `--platform linux/arm64`
|
||||
- Build script: `~/build-rov.sh [tag]` — defaults to `:dev`
|
||||
- Never build x86 images for the vehicle — they will silently fail on RPi5
|
||||
- The `rov_simulation` package must be excluded from production image builds
|
||||
- Do not modify the `Dockerfile` base image without checking ROS2 Jazzy compatibility
|
||||
|
||||
---
|
||||
|
||||
# Git Rules
|
||||
|
||||
- Commit messages follow conventional commits format: `feat:`, `fix:`, `docs:`, `refactor:`
|
||||
- Do not commit directly to `master` without instruction
|
||||
- Keep commits focused — one logical change per commit
|
||||
- Always commit config changes alongside the code that depends on them
|
||||
- Branch: `master` is the working branch for this project
|
||||
|
||||
---
|
||||
|
||||
# Dev Environment
|
||||
|
||||
**Terminal conventions (always use these labels):**
|
||||
- `[SERVER]` — SSH session on SymbyTech server (192.168.1.175 / Tailscale: 100.104.236.104)
|
||||
- `[VM]` — SSH session on BlueOS VM (192.168.122.89 / Tailscale: 100.84.141.120)
|
||||
- `[GIT]` — Git Bash on laptop
|
||||
- `[LAPTOP]` — Windows Command Prompt on laptop
|
||||
|
||||
**Key addresses:**
|
||||
- BlueOS: `http://100.84.141.120`
|
||||
- Cockpit: via BlueOS sidebar
|
||||
- Harbor: `https://registry.symbytech.com`
|
||||
- Gitea: `https://git.symbytech.com`
|
||||
|
||||
**BlueOS session requirements:**
|
||||
- Enable Pirate Mode (skull icon) each session — resets due to no bootstrap container
|
||||
- Cockpit MAVLink2REST: `ws://100.84.141.120/mavlink2rest/ws/mavlink`
|
||||
- Vehicle network connection: `100.84.141.120`
|
||||
|
||||
---
|
||||
|
||||
# Testing
|
||||
|
||||
- `rov_simulation` provides mock publishers for all MAVROS topics
|
||||
- Five test scenarios: `nominal`, `low_battery`, `comms_loss`, `depth_warning`, `all_clear`
|
||||
- Dev stack launch: `ros2 launch rov_simulation dev_stack.launch.py scenario:=<name>`
|
||||
- Do not remove existing test scenarios without confirming intent
|
||||
- Add new scenarios for any new failsafe condition added to the design
|
||||
|
||||
---
|
||||
|
||||
# Claude Behaviour Rules
|
||||
|
||||
- Always read existing code in a file before modifying it
|
||||
- Always read the relevant design document before implementing a feature
|
||||
- Always check message definitions in `rov_interfaces` before writing node code
|
||||
- Explain assumptions before making architectural changes
|
||||
- If requirements are unclear, ask before implementing
|
||||
- Prefer incremental changes over large rewrites
|
||||
- Never delete code without confirming intent
|
||||
- If a safer or simpler approach exists, suggest it before proceeding
|
||||
- Do not refactor unrelated code
|
||||
- Do not optimise prematurely
|
||||
|
||||
---
|
||||
|
||||
# What Claude SHOULD do
|
||||
|
||||
- Implement features step-by-step with verification at each step stating if feedback is expected
|
||||
- Fix bugs with minimal disruption to surrounding code
|
||||
- Add comments to every function and non-obvious block
|
||||
- Highlight safety risks when they exist
|
||||
- Suggest better approaches when appropriate
|
||||
- Verify file structure and entry points after creating new nodes
|
||||
|
||||
---
|
||||
|
||||
# What Claude should NOT do
|
||||
|
||||
- Do not restructure the package layout unless explicitly asked
|
||||
- Do not introduce new Python packages without approval
|
||||
- Do not rewrite working code for style
|
||||
- Do not assume missing requirements — ask
|
||||
- Do not hardcode thresholds, addresses, or paths
|
||||
- Do not deploy or reference `rov_simulation` in production launch files
|
||||
- Do not change the failsafe priority order without design review
|
||||
- Do not use `print()` — always use `self.get_logger()`
|
||||
- Do not build x86 Docker images for vehicle deployment
|
||||
|
||||
---
|
||||
|
||||
# When Uncertain
|
||||
|
||||
1. Stop implementation
|
||||
2. State the ambiguity clearly
|
||||
3. Provide a suggested approach with trade-offs
|
||||
4. Wait for confirmation before proceeding
|
||||
|
||||
---
|
||||
|
||||
# Key Design Documents
|
||||
|
||||
All in the Claude project knowledge base:
|
||||
## Key Reference Documents (current versions)
|
||||
|
||||
| Document | Purpose |
|
||||
|---|---|
|
||||
| `ROV_Project_Handover_v2.3.md` | Master reference — architecture, environment, commands |
|
||||
| `ROV_Failsafe_Design_v2.0.md` | Failsafe state machine, sensor roadmap, priority order |
|
||||
| `Argonaut3_UI_Design_v1.1.md` | Cockpit extension and widget specifications |
|
||||
| `ROV_Project_Handover_v2_21.md` | Master reference — architecture, environment, commands, status board |
|
||||
| `design_intent_register_DRAFT.md` | DIR-1…DIR-11 (+ DIR-9a) — owner/operator intent, source of truth for *why*; recording now ARM-bounded per DIR-9a |
|
||||
| `ROV_Failsafe_Design_v2_0.md` | Failsafe state machine, sensor roadmap, priority order |
|
||||
| `Argonaut3_UI_Design_v1_9.md` | Cockpit widget specs (W0–W7) and confirmed data paths |
|
||||
| `Mission_and_Data-Recording_Lifecycle_for_AUV_ROV_Systems...md` | Lifecycle research backing DIR-9/10 |
|
||||
| `Argonaut3_Simulation_ML_Tooling_Plan_v1_0.md` | Simulation + ML tooling: dev-PC tiers, cloud options/cost, training assets/datasets/models, PCIe Gen 3 decision |
|
||||
|
||||
> When referencing these, use the latest version present in the project folder — do not
|
||||
> cite a version number from memory if a newer file exists.
|
||||
|
||||
Always use the highest version
|
||||
---
|
||||
|
||||
# Notes
|
||||
|
||||
This is a production-oriented autonomous safety system. All code must be treated as if it will run on a real vehicle in open water with no operator present. Safety, correctness, and reliability are non-negotiable.
|
||||
## Safety Notice
|
||||
This is a production-oriented autonomous safety system. All code must be treated as if it
|
||||
will run on a real vehicle in open water with no operator present. Safety, correctness,
|
||||
and reliability are non-negotiable. Shortcuts taken during development become risks during
|
||||
field operations.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user