Build spec and host brief carried in from C:\Claude and WRPS/02-env; the plant model (equipment, tags, alarm bitmask, enums, unit conversions) is derived from WRPS/04-plc/register-map.csv, WRPS/05-scada/modbus/scada-points.csv and WRPS-CTL-003. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3.7 KiB
CLAUDE.md — rules to keep front of mind
Plant Operations Assistant for the Waterloo Road Pump Station (WRPS), deployed onto an
existing, live, shared Docker host. Full detail: BUILD-AI-CONTAINERS.md (the build spec) and
YAU_Linux_Host_Onboarding.md (the host brief). Where the two conflict, the host brief wins.
The three lines this system does not cross
- No instructions for safety-critical actions. Procedural questions get document identity, revision, effective date and verbatim prerequisites — never synthesised steps.
- No recommended setpoints or operating parameters. Advisory questions get evidence, ranges, outcomes, documented limits, then an explicit deferral. Never a number presented as the answer.
- No answers outside the evidence. Zero rows means "no records found", never a plausible figure.
These are code paths, not prompt instructions. A safety rule living only in a prompt is not implemented. The classifier runs first; each class has a Pydantic contract validated in Python after generation and before returning. Contract failure -> regenerate once -> error. Never return.
When class is uncertain, choose the more restrictive class. Procedural beats Reference. Advisory beats Historical. Partly-advisory is advisory.
Host rules — inherited, non-negotiable
- Growing data goes on
/datadisk, never/. Root is 62 GB and has hit 100% before. - No published host ports. Join the external
proxynetwork, reach it through Caddy. - Never omit
import autheliafrom a Caddyfile block — it silently makes a service public. ~/authelia/configuration.ymlis root-owned:sudo, back up as.bak-<purpose>-<date>. Restarting Authelia logs out every active user — announce it first.- AD group membership must be DIRECT. Nested membership silently fails.
pg-aiandcubeare pinned — do not add them to Watchtower's update list.openplc-runtimeis live control for this demo. Never restart, update or reconfigure it as a side effect of AI work. Do not copy its published-port pattern.- Never install on, write to or restart
cicore1. Never exceed read-only onimh. - No secrets in Git, compose files, logs or error messages.
0600env files under~/ai/.
Verification
docker ps showing "Up" is not proof. curl -sI the public URL, expect 302 to the auth
portal, and read the container logs. Prove each layer without the LLM first: prove Cube returns
the right number by hand, prove retrieval finds the right procedure by hand, then wire the agent.
Working conventions
- Prefer additive changes. Snapshot config before editing.
- Do not invent schema.
imhis pending — inspect it, or ask. Fixtures are marked as fixtures. - Store UTC. Convert to
SITE_TIMEZONEexactly once, in Cube. Never do timezone maths in a prompt. - Fix failures in the classifier, Cube or ingestion — not by adding instructions to the prompt.
- When something fails, add the failing case to
eval/testset.jsonlbefore fixing it. - Small commits, one concern each. If a change alters an accepted phase, re-run that phase's gate.
The plant
Waterloo Road Pump Station: a three-pump wastewater station. Wet well WW-101 (0–7000 mm,
120 m³/m), duty/assist/assist pumps PU-301/302/303 on a common VSD speed reference, discharging
through manifold MAN-301 against 22 m static lift. Spill weir at 6000 mm, LSHH-102 at 5500 mm.
Control runs on openplc-runtime; Yokogawa CI Server on cicore1 polls it over Modbus TCP and
historises the result. Source of truth for tags: db/seed/tags.csv, derived from
WRPS/04-plc/register-map.csv and WRPS/05-scada/modbus/scada-points.csv.