# leaguelaw — agents.md

Project constitution. Inherits from `/srv/CLAUDE.md` (server scope) and
`/srv/apps/CLAUDE.md` (tenant scope). Only rules meeting the admission rubric
(failure-backed, tool-enforceable, decision-encoding, or triggerable) belong
here — no generic advice a model already applies. Budget: ~200 lines.

Model-independence: this file is the source of truth. `CLAUDE.md` is a symlink
to it so Claude Code loads the same content.

## Read first (in order)
1. **`brief.md`** — what this project is, what was sold, and the stack decision.
2. **`.logs/planning/build-plan.md`** — the build plan: locked decisions, phases, gates.
3. **`/srv/projects/standards/README.md`** — server-wide coding standards
   (dispatches by stack: `coding.md` → `wordpress.md` → `frontend.md`).
4. **`.logs/handoff.md`** — newest-first; where the last session left off.
5. **`adi-note.md`** — Adi's manual notes as designer/developer. Read for
   context; treat as input only — never edit or reorganize it unasked, and flag
   (don't silently resolve) any conflict with the brief or build plan.

Prototyping work also reads **`.logs/planning/design-direction.md`** — the
client's written design requirements, the anchor every design artifact is
checked against — and **`prototype.md`** — the atomic prototyping process
being distilled on this project into a reusable prompt for future sites. It is
co-owned with Adi: refine it as prototyping teaches us things, but keep it
project-agnostic.

## Project-specific rules

- **`design-direction.md` anchors all design work.** The client's written
  requirements live in `.logs/planning/design-direction.md` (no large hero
  imagery, contact at the top, practice areas as immediate clickable zones,
  modern but not showy). **Check every direction or mockup artifact against it
  before anyone sees it.** Provenance: a full prototyping day produced a
  full-bleed hero slider that contradicted it and was stopped at review
  (2026-08-20).

- **An approach pivot is a check-in, not a judgment call.** When an agreed
  approach is not working, flag Rian with two lines — what is failing, what to
  try instead — *before* hours go into a replacement. Async is fine and
  preferred; never wait for a meeting. Design-detail choices stay with the
  designer; changing the agreed process or approach does not.

- **Direction before mockup, and phase discipline on fidelity.** The direction
  phase exists to get the client to confirm structure ("sedan vs SUV, not rims
  and tail-lights") without feeling committed to a design: low-fidelity,
  deliberately unfinished-looking artifacts, anchored on the client's input,
  never on a replica of the current site. High-fidelity work (mega menus,
  animated CTAs, polish) belongs to the mockup phase — park it, don't build it
  early. The current-site replica is an internal measurement artifact only.

- **Never touch the live site.** `https://www.leaguelaw.com` is the client's
  production site on Flywheel. This project is a build environment only. All work
  happens here and reaches the client through a staging URL they approve, never
  by editing production. There is no push script in this project, and one should
  not be added without Rian deciding the deploy path first.

- **This database is the build — never rebuild it from scratch.** `wp-content/`
  is a fresh pull of production and we build on it in place: keep the database,
  swap the theme, strip the content back to plain blocks. A fresh WordPress
  install plus a content import would reset every password and lose 3,929
  Gravity Forms entries. **The conversion touches `post_content` only** — never
  `wp_users`, `wp_usermeta`, or the `gf_*` tables, and never re-slug or renumber
  anything, because the IDs and slugs are what protect the URLs.

- **Snapshot the database before any destructive content pass**, and verify each
  conversion with **text in equals text out**: strip all markup from before and
  after and confirm no words were lost. Formatting disappearing is the goal;
  content disappearing is a bug.

- **Schema is a plugin, not code.** If the AI add-on is accepted it is delivered
  by configuring `bw-ai-schema-pro` (team post type mapped to the `lawyers` CPT). Do not hand-write JSON-LD. If a task starts to look like custom
  schema development, stop and re-read `brief.md`.

- **Two lines in `themes/kadence-child/includes/post-types.php` are load-bearing
  and must not be "tidied".** The `lawyers` rewrite slug is **hardcoded** to
  `lawyers` (it used to come from a Total theme mod, which died with the theme,
  and every published lawyer URL depends on that string); and `has_archive` is
  **false** because the page "Our Lawyers" (ID 14661) holds the slug `lawyers` —
  enabling an archive makes the two collide. Both are commented in the file.

- **Some post types are orphaned — their plugins are gone but the rows remain**
  (`mt_pp`, `guest_author`, `law_fact`; `testimonials` was re-registered in the
  child theme and is live again). They are invisible in
  wp-admin, which is expected, not data loss. Do not "fix" one by reinstalling
  its old plugin; decide deliberately whether to rebuild or dispose of it.
  Note the taxonomy API returns `WP_Error` for an unregistered taxonomy, so
  cleanup of anything Total-registered has to go through direct SQL.

- **Build with patterns, not bespoke pages.** Every recurring section is an
  **unsynced pattern** in a project-specific category, inserted and then edited
  per page. Do not hand-build a one-off layout when an existing pattern plus
  changed variables covers it, and do not create a near-duplicate pattern when a
  toggle or swapped column order covers the difference. This is the core build
  decision for the project — the rationale and the mechanics are in
  `.logs/planning/build-plan.md` §Patterns.

- **A pattern whose contents cannot be edited is a broken pattern.** WordPress
  locks non-declared blocks inside patterns to content-only editing, which
  silently makes images, buttons, and tables un-swappable. Every block type used
  inside a pattern must be declared editable, from a single shared list. Verify by
  inserting the pattern and confirming an image shows a **Replace** button before
  calling the pattern done.

- **Photography is placeholder until November.** The client reshoots office and
  staff photos in November. Build and mock up with clearly-marked placeholders,
  sized and cropped to the final aspect ratios, so the real photos drop in without
  re-layout. Never present a placeholder to the client without labelling it as one.

- **Prototype file locations are fixed (multi-user).** Finished, served
  prototype pages live ONLY in `wp-content/prototype/`
  (https://leaguelaw.demoing.info/wp-content/prototype/, id-auth gated;
  `index.html` is the hub). Working copies/version history live in
  `prototyping/` at the workspace root; session temp files go to the Claude
  scratchpad, never the served folder. Before any prototype/design work read
  `adi-note.md` and `prototype.md` — the conventions and design decisions
  recorded there are binding for every user and session on this server.

- **Content and rankings must survive the move.** 427 posts back to 2014 and their
  URLs are the firm's most valuable asset. Any URL that changes needs a redirect,
  and the redirect map is a deliverable, not an afterthought.

## Operational

- **Manage:** `srv-gw {status,restart,logs,deploy} --project leaguelaw`.
- **WP-CLI:** `srv-gw wp --project leaguelaw -- <command>`.
- **Read the DB:** `srv-gw db-query --project leaguelaw "<SELECT ...>"` (read-only;
  writes go through `srv-gw wp`). Note the table prefix is `wp_eopoktulnc_`, not `wp_`.
- **Write access:** `leaguelaw-dev` Unix group (setgid + default ACL). New files need
  `chmod 664` / dirs `775`, or `srv-gw fix-permissions --project leaguelaw`,
  so WordPress (`www-data`) can read them. A plugin file at 600 is the usual cause
  of "the plugin does not have a valid header".
- **Create new subdirectories under `sg leaguelaw-dev`.** If the session's groups
  don't include `leaguelaw-dev`, the kernel silently strips setgid on `chmod 2775`
  and files underneath get the wrong group.
- **Build URL:** `https://leaguelaw.demoing.info` (id-auth gated; port 3129 internal).
- **Members:** rian, rob, adi.

## Layout

```
/srv/apps/leaguelaw/          # workspace — docs and runtime state
├── brief.md  agents.md  CLAUDE.md -> agents.md
├── adi-note.md  prototype.md      # Adi's notes · reusable prototyping process
├── .logs/{planning/, handoff.md, diary.md, v8-feedback.md}
├── .memory/  .archive/  notes/
├── prototyping/              # prototype working copies / version history
├── docker-compose.yml  .env  uploads.ini  apache-tuning.conf
└── wp-content/               # the instance — themes, plugins, uploads
```

**Declared override (v8 workspace standard).** The instance folder is
`wp-content/`, not `main/`. The gateway bind-mounts `wp-content/` into the
WordPress container at a fixed path, so code cannot move down a level without
breaking the site. This is a deliberate, documented divergence — per
`/srv/apps/CLAUDE.md`, that is conformance, not drift. The compose file and
`.env` sit at the workspace root for the same gateway reason.
