---
title: "Navi: Claude Code Rules"
type: reference
tags:
  - recon
aliases: []
related:
  - [[deployment]]
  - [[CLAUDE-baseline]]
  - [[environment]]
  - [[themes]]
  - [[caddy]]
updated: 2026-06-18
---
# Navi: Claude Code Rules

## Repository & SSH

**All Navi SSH goes to:** `recon-vm` (VM 1130, 192.168.1.130)

**Never SSH to cortex for Navi work.** Previous attempt to deploy from cortex wrecked production by deploying from a stale clone.

**Work directory:** `/home/zvx/projects/repos/navi` on VM 1130

**Never touch:** `/home/zvx/projects/navi-work` on cortex (stale clone, do not use)

## Git / Repository Rules

**GitHub (zvx-echo6) is the source of truth for all repos.**

### Remote Convention

- **origin** = GitHub (github.com/zvx-echo6/{repo})
- **forge** = Forgejo backup (forge.echo6.co/matt/{repo})

### Creating New Repos

1. Create on GitHub first (public unless told otherwise)
2. Create matching repo on Forgejo
3. Configure Forgejo repo as pull mirror from GitHub (8h interval)
4. Local clone: origin = GitHub, forge = Forgejo

### Exceptions

- **echo6-docs** is the sole exception — Forgejo only, no GitHub copy

### Rules

- Never force-push to origin without explicit approval
- Never use `git add -A` — stage files explicitly

## Critical Constraints

- **Never re-export namedTheme** through any intermediary module — import directly from protomaps-themes-base in MapView.jsx
- **Never use `git add -A`** — stage files explicitly
- **Never deploy without smoke tests** — run full checklist (see deployment.md)
- **Never start preview servers** — deploy to production and test there

## Build & Deploy

```bash
ssh recon-vm
cd /home/zvx/projects/repos/navi
npm run build && rsync -av --delete dist/ /mnt/nav/frontend/
```

## Git Workflow

- Feature branches: name descriptively (theme-*, fix-*, feat-*)
- Always merge to master before deploying
- Check for unmerged commits: `git log branch..master --oneline`

## Code Patterns

### queryRenderedFeatures for Optional Layers

Guard with map.getLayer() — USFS/BLM hit layers may not exist:

```javascript
const layers = [USFS_TRAILS_HIT, USFS_ROADS_HIT].filter(id => map.getLayer(id))
const features = layers.length > 0
  ? map.queryRenderedFeatures(e.point, { layers })
  : []
```

### buildStyle Theme Colors

```javascript
const theme = getTheme(themeName)
const colors = theme.colors || namedTheme(themeName)  // direct import
```

### PlaceCard useEffect Changes

Investigation-before-implementation — fragile race conditions between:
- Boundary fetch from Wikidata/OSM
- selectedPlace state updates
- AbortController cleanup

## Architecture Notes

- **Boundary highlight** is NOT an overlay toggle — it's a dynamic click-response layer
- **Route polyline** uses GeoJSON source.setData() — silent failure if namedTheme is re-exported
- **Measure tool** also uses GeoJSON — same failure mode

## Smoke Test Checklist

After every deploy:

- [ ] Route between two addresses — polyline renders
- [ ] Click city label — boundary outline appears
- [ ] Theme switching (all 4 [[themes]])
- [ ] Overlay toggles (hillshade, contours, public lands)
- [ ] Console: no "bt is not defined" or "f is not defined"
