Secure worker access for perception, vectorized training, and cross-station communication. This is Hermes's shell. Her interface to the accumulated unconscious of the fishing grounds.
Five Cloudflare Workers that give Hermes — the F/V EILEEN's perception system — secure access to:
- Reference Frame Store (D1) — Accumulate timestamped snapshots of everything the TZ Pro sees
- Screenshot Store (R2) — Store and serve raw echogram screenshots with structured paths
- Vectorize Training Pipeline — Embed frames as visual + semantic + spatial vectors for multi-dimensional search and YOLO training data export
- Cross-Station Communication — Emit and match perception vectors between agents without human-language approximation
- Web UI — A dark-themed dashboard with live frame stream, stats, vector space visualization, and resonance feed
┌──────────────────────────────────────────┐
│ Hermes (AI Agent) │
└──────────┬──────────────┬───────────────┘
│ │
┌──────────▼──────┐ ┌────▼──────────────┐
│ hermes-frames │ │ hermes-screenshots │
│ (D1 database) │ │ (R2 bucket) │
│ │ │ │
│ - Store frames │ │ - Upload images │
│ - Query frames │ │ - Serve images │
│ - Labels │ │ - AI analysis │
│ - Analyses │ │ │
└────────┬─────────┘ └────────┬───────────┘
│ │
┌────────▼────────────────────▼───────────┐
│ hermes-vectorize │
│ (Vectorize + Workers AI) │
│ │
│ - Visual embeddings (CLIP) │
│ - Semantic embeddings (bge-m3) │
│ - Spatial embeddings (sinusoidal) │
│ - Contextual embeddings │
│ - YOLO training data export │
└────────────────────┬────────────────────┘
│
┌────────────────────▼────────────────────┐
│ hermes-stations │
│ (Vectorize + D1) │
│ │
│ - Emit perception vectors │
│ - Match vectors across stations │
│ - Resonance detection │
│ - No human language needed │
└─────────────────────────────────────────┘
│
┌────────────────────▼────────────────────┐
│ hermes-ui │
│ (Cloudflare Pages) │
│ │
│ - Live frame stream │
│ - Stats dashboard │
│ - Vector space visualization │
│ - Training data overview │
│ - Resonance feed │
└─────────────────────────────────────────┘
cd hermes-cloudflare
npm install# Create D1 database (hermes-reference-frames)
npm run create:d1
# Create R2 bucket (hermes-screenshots)
npm run create:r2
# Create Vectorize index (hermes-perception, 768 dimensions)
npm run create:vectorizeAfter creating D1 and R2 resources, update the database_id and bucket_name in each worker's wrangler.toml with the actual IDs returned by the creation commands.
# For each worker, set the API keys:
cd workers/frames
npx wrangler secret put HERMES_API_KEY
npx wrangler secret put ADMIN_API_KEY
# Repeat for each worker# Deploy all workers
npm run deploy:all
# Or deploy individually
npm run deploy:frames
npm run deploy:screenshots
npm run deploy:vectorize
npm run deploy:stations
npm run deploy:uiAll endpoints require a Bearer token:
Authorization: Bearer hermes-key
| Key | Role | Access |
|---|---|---|
hermes-admin-key |
admin | Unlimited. Full access for Casey. |
hermes-key |
full | 100 req/min. Hermes's own key — read/write everything. |
agent-key |
read_emit | 100 req/min. Other agents — read + emit perception vectors. |
| Method | Endpoint | Description |
|---|---|---|
| POST | /frame |
Store a reference frame |
| GET | /frame/:id |
Retrieve a specific frame with labels and analyses |
| GET | /frames |
Query frames (time range, position, depth) |
| POST | /frame/:id/label |
Add a label ("this mark was a king salmon") |
| POST | /frame/:id/analysis |
Add model analysis results |
| GET | /frames/correlate |
Find frames correlated with catch events |
| GET | /stats |
Summary statistics |
| Method | Endpoint | Description |
|---|---|---|
| POST | /upload |
Upload a screenshot (multipart/form-data) |
| GET | /:path |
Serve a screenshot |
| GET | /:path/analyze |
Run AI analysis on a stored screenshot |
| POST | /:path/reanalyze |
Reanalyze with a newer model |
| GET | /list |
List screenshots with optional prefix filter |
| Method | Endpoint | Description |
|---|---|---|
| POST | /embed/frame |
Embed a frame (semantic + spatial + contextual vectors) |
| POST | /embed/observation |
Embed a single observation |
| POST | /search/visual |
Search by visual similarity (CLIP) |
| POST | /search/semantic |
Search by text query ("scattered marks near thermocline") |
| POST | /search/spatial |
Search by position (lat/lon/depth) |
| POST | /search/correlate |
Find frames correlating with catch events |
| GET | /training/export |
Get YOLO training data export specification |
| GET | /training/stats |
Training data statistics |
| Method | Endpoint | Description |
|---|---|---|
| POST | /emit |
Emit a perception vector to the fleet |
| GET | /recent |
Recent vectors from all stations |
| POST | /match |
Match a local vector against the fleet |
| GET | /station/:id |
All vectors from a specific station |
| POST | /resonance |
Find resonance (convergence patterns) between stations |
When Hermes captures a perception snapshot (every echogram-length of time, or triggered by events), she:
- Captures screenshots → uploads to
hermes-screenshots(R2) - Stores the frame → sends position, depth, observations to
hermes-frames(D1) - Embeds the frame → creates multi-dimensional vectors in
hermes-vectorize(Vectorize) - Emits a perception vector → broadcasts to
hermes-stationsfor cross-station awareness
The reanalysis loop:
- Capture raw reference frames (today's reflex layer)
- Label what we can ("this mark was a king salmon")
- Embed everything into Vectorize for similarity search
- Export as YOLO training data via
/training/export - Train locally (LoRA on YOLOv8/OpenCV)
- Reanalyze old frames with the new model via
/frame/:id/analysis - Repeat. The data accrues. The labels improve. The training meshes.
This is the novel part — agents communicating in pure perception vectors:
Instead of Hermes saying "I see scattered marks at 30 fathoms," she emits a vector that encodes the perception directly. Another agent at another station receives the vector and matches it against their own visual memory. The match IS the communication.
When two stations emit similar vectors at similar times, that's resonance — two different perception systems seeing the same thing from different angles. Resonance = convergence = the "in the pocket" moment.
A reference frame is a complete perception snapshot:
{
"id": "frame-1691614800-a1b2c3",
"timestamp": "2026-08-09T09:15:00.000Z",
"lat": 57.5234,
"lon": -134.2001,
"sog": 2.1,
"cog": 185,
"depth": 53.5,
"inside_gear_range": 1,
"screenshot_path": "screenshots/2026/08/09/20260809-091500-full.png",
"sounder_low": "screenshots/2026/08/09/20260809-091500-sounder-low.png",
"sounder_high": "screenshots/2026/08/09/20260809-091500-sounder-high.png",
"observations": [
{
"type": "fish_mark",
"depth": 35,
"intensity": 0.7,
"confidence": 0.85,
"description": "Scattered marks at 35 fathoms, moving NW"
}
],
"catch_events": [],
"weather": { "seaTemp": 9.2, "windSpeed": 8, "windDir": 200 }
}hermes-cloudflare/
├── workers/
│ ├── frames/ # D1 reference frame store
│ │ ├── src/index.ts
│ │ └── wrangler.toml
│ ├── screenshots/ # R2 screenshot store
│ │ ├── src/index.ts
│ │ └── wrangler.toml
│ ├── vectorize/ # Vectorize + training export
│ │ ├── src/index.ts
│ │ └── wrangler.toml
│ └── stations/ # Cross-station vectorized comms
│ ├── src/index.ts
│ └── wrangler.toml
├── ui/ # Web UI (Cloudflare Pages)
│ └── index.html
├── shared/
│ ├── types.ts # Shared TypeScript types
│ └── auth.ts # Auth utilities
├── migrations/
│ └── 001_frames.sql # D1 schema
├── scripts/
│ ├── create-d1.sh
│ ├── create-r2.sh
│ ├── create-vectorize.sh
│ └── deploy-all.sh
├── package.json
├── tsconfig.json
└── README.md
This is the distillation loop applied to real fishing data:
- Capture raw reference frames → the reflex layer (sounder screenshots + GPS + observations)
- Label what we can → the cortex layer (Casey or Hermes annotating marks)
- Train on the labels → night school (YOLO LoRA training on local GPU)
- Reanalyze old data → improved perception (new model finds patterns we missed)
- Repeat. The data accrues. The labels improve. The training meshes.
The data we capture today is the training set for the model we build tomorrow.
- The Chart = the Spatial Registry (rooms = fishing locations)
- The Sounder = the Trigger Engine (pattern matching on the echogram)
- The Contour Lines = the Vibe Field (spatial constraints)
- The Reference Frames = the Tile/Deadband system (repeated observations become tiles)
- The Log = the Collective Unconscious (everything timestamped, vectorizable, searchable)
- The Reanalysis Loop = Wesley's Night School (revisit old data with new understanding)
MIT — Hermes builds for the F/V EILEEN.
Built for the F/V EILEEN. Sounder-green on black. The feel of a commercial fishfinder, not a startup dashboard.