25 medium-granularity issues. Each lands on the GitHub Project board (Doing / Blocked / Done) via
scripts/seed-issues.sh. Each issue has: title, body (with Acceptance Criteria + File Pointers), labels (lane + priority + phase). Pull from this board, never from this file directly. Branch per issue. PR per branch. AGENTS.md §4.
- At kickoff, after
gh repo create, runbash scripts/seed-issues.shfrom the repo root. - Issues become live GitHub Issues with labels.
- The GitHub Project board (3 columns: Doing / Blocked / Done) auto-includes them.
- WIP cap: 2 issues "Doing" per person at any time.
- When you finish, close the issue from the merged PR (
Closes #NNin PR description).
- Lane: cross-cutting · Owner: P1 (Jon) · Priority: P0
- Acceptance:
/docs/adrs/2026-05-02-002-kickoff-vote.mdexists with: codename, austere AO, hero scenario, OSM extract size, ollama vs llama.cpp, Palantir/Danti/kepler.gl decisions. - Files:
/docs/adrs/
- Lane: security/infra · Owner: P2 (Satriyo) · Priority: P0
- Acceptance: Repo is public,
mainis protected (require PR, require CI pass, empty bypass list),CODEOWNERSis enforced on PR review, all 4 teammates have write access. - Files: GitHub settings,
CODEOWNERS
- Lane: security/infra · Owner: P2 · Priority: P0
- Acceptance: Each teammate has
lefthook installrun; AI PR review action posts on every PR; one test PR exercises the full gate. - Files:
lefthook.yml,.github/workflows/ci.yml
- Lane: agent · Owner: P1 (Jon) · Priority: P0 · Phase: P1
- Acceptance:
agent/llm.pydefinesLLMClientProtocol withFrontierClient(OpenAI/Anthropic) andOllamaClientimpls. Selected viaWAYFINDER_PHASEenv var. - Files:
agent/llm.py,agent/orchestrator.py
- Lane: agent · Owner: P1 · Priority: P0 · Phase: P1
- Acceptance:
/planaccepts a prompt, invokes the LLM with tool schemas from/docs/contracts/agent_routing.schema.json, validates returned tool args, dispatches to a stub tool, returns validPlanResponse. - Files:
agent/orchestrator.py,agent/schemas.py,agent/tools/__init__.py
- Lane: ontology · Owner: P1 · Priority: P0 · Phase: P1
- Acceptance:
ontology/ontology.ymlcovers freshwater, covered route, ridgeline, vehicle-passable; loader validates schema at startup. - Files:
ontology/ontology.yml,ontology/loader.py
- Lane: routing · Owner: P4 · Priority: P0 · Phase: P1
- Acceptance:
routing/valhalla_client.pycan compute a foot route between two SF coords using locally-built tiles.make valhalla-builddocumented indata/scripts/. - Files:
routing/valhalla_client.py,data/scripts/clip_osm.sh
- Lane: data · Owner: P4 · Priority: P0 · Phase: P1
- Acceptance:
data/extracts/sf.osm.pbf+data/dem/sf.tif+ same for austere AO.make data-verifypasses againstdata/manifest.sha256. - Files:
data/aois.yml,data/manifest.sha256,data/scripts/
- Lane: atak · Owner: P4 · Priority: P1 · Phase: P1
- Acceptance: Given a
PlanResponse, write a KML file that can be imported into ATAK manually. Used as Phase 1 fallback before signed CoT lands. - Files:
atak/cot.py(KML helper),atak/bridge.py
- Lane: agent · Owner: P1 · Priority: P1 · Phase: P1
- Acceptance: Static page served by FastAPI; click on map → posts to
/plan→ renders returned route. Pick Leaflet for speed; upgrade to kepler.gl only if there's time. - Files:
agent/static/index.html,agent/app.py
- Lane: hardware · Owner: P3 · Priority: P0 · Phase: P2
- Acceptance: JetPack flashed, Python 3.11 + venv working,
make jetson-prepareidempotent,make cipasses on the Jetson. - Files:
hardware/scripts/setup.sh,hardware/jetpack.md
- Lane: crypto · Owner: P2 · Priority: P0 · Phase: P2
- Acceptance:
crypto/signer.pyexposesSigner.load,Signer.sign,Verifier.from_trust_list,Verifier.verify. Sign + verify roundtrip < 5ms (make sign-bench). Unit tests intests/test_signer.py. - Files:
crypto/signer.py,crypto/trust.py,tests/test_signer.py
- Lane: atak · Owner: P4 (impl) · Priority: P0 · Phase: P2 · Pair: P2 (signer)
- Acceptance:
bridge.pyingestsPlanResponse, builds CoT XML per/docs/contracts/cot_signed.md, signs via P2'sSigner, emits to multicast. ATAK on Android/WinTAK draws the line. - Files:
atak/bridge.py,atak/cot.py,atak/multicast.py
- Lane: deploy · Owner: P3 · Priority: P1 · Phase: P2
- Acceptance:
wayfinder-agent.service+wayfinder-bridge.servicestart on boot, restart on failure, log to journald. - Files:
deploy/systemd/,deploy/rsync.sh
- Lane: security · Owner: P2 · Priority: P1 · Phase: P2
- Acceptance:
make tcpdump-demoopens a window showing zero outbound packets during a/plancall. Audit log scrolls in a separate window with structured prompt/tool-call/sign events. - Files:
security/demo_proofs.md,infra/tcpdump_demo.sh
- Lane: models · Owner: P3 · Priority: P0 · Phase: P3
- Acceptance:
make models-pullpulls Gemma 2B (or 3n) + Whisper-tiny; SHA-256 hashes verified againstmodels/manifest.sha256.make models-benchreports per-token latency on Jetson. - Files:
models/manifest.sha256,models/pull.sh
- Lane: agent · Owner: P1 · Priority: P0 · Phase: P3
- Acceptance:
OllamaClientworks against local ollama;WAYFINDER_PHASE=3flips the orchestrator without code change. Tool-calling works (structured-output prompting if Gemma doesn't natively support tools). - Files:
agent/llm.py,agent/orchestrator.py
- Lane: voice · Owner: Jon (P1) · Priority: P1 · Phase: P3
- Acceptance:
POST /plan/voiceaccepts WAV/Opus, transcribes via Whisper-tiny, calls orchestrator, returns plan. End-to-end < 5s on Jetson. - Files:
voice/whisper_client.py,voice/ptt.py,agent/app.py
- Lane: agent · Owner: Jon (P1) · Priority: P1 · Phase: P1
- Why: Kyle provisioned a Cesium Ion token (
NPS SF Hackathon). 3D globe with real terrain is dramatically more impressive than 2D Leaflet. Phase 1 demo wow factor. - Acceptance:
agent/static/index.htmlloads CesiumJS, readsCESIUM_ION_TOKENfrom a server-side/configendpoint (never expose token to client beyond what Cesium SDK requires).- User clicks point on globe → POSTs to
/plan→ CesiumJS renders the returned route as a polyline draped on terrain. - Camera fly-to on route generation; 3D terrain visible.
- Files:
agent/static/index.html,agent/static/wayfinder.js,agent/app.py(add/configendpoint scoped toCESIUM_ION_TOKEN). - Dependency: Cesium Ion token in
.env(Kyle provisioned). - Decision point Sat 1400: if CesiumJS is too heavy or has integration friction, fall back to Leaflet.
- Lane: data · Owner: Ben (P4) · Priority: P1 · Phase: P2
- Why: Phase 3 runs WiFi-off. Cesium is online-only at runtime. We must pre-cache the demo AO tiles before going offline.
- Acceptance:
data/scripts/cache_cesium.shdownloads imagery + terrain tiles for both AOI bboxes via Cesium Ion REST API using the token.- Cached tiles live in
data/cache/cesium/and are hash-verified. data/aois.ymlenumerates AOI bbox + zoom levels needed.- In Phase 3, frontend (or local tile server) serves from cache; no calls to
*.cesium.com.
- Files:
data/scripts/cache_cesium.sh,data/aois.yml,data/cache/cesium/.gitkeep. - Dependency: Cesium Ion token (Kyle provisioned).
- Defer: if Sat 1500 progress is behind, drop Cesium tiles; use SRTM/OSM only. CesiumJS frontend still works with Cesium World Terrain online.
- Lane: voice · Owner: Jon (P1) · Priority: P0 · Phase: P3
- Why: Operators climbing, fast-roping, or hands-on with another task cannot read an ATAK screen. Hands-free output is the whole reason the system exists when the operator is moving (PRD §4).
- Acceptance:
voice/piper_client.pysynthesizes audio from text via Piper.voice/rationale.pyformats the route response into operator-cadence speech ("zero-three-zero", "ETA three-eight minutes", grid-by-digit)./planresponse includes optionalaudio_b64(base64 WAV) when?tts=truequery param is set, OR a separateGET /tts?text=...streaming endpoint.- First-audio latency < 1s on Jetson; hero rationale audio is 6-10s long.
- Demo dry-run on Sat 2200: speak the hero scenario rationale through a real headset.
- Files:
voice/piper_client.py,voice/rationale.py,voice/tts.py,agent/app.py - Dependencies: Piper voice model added to
models/manifest.sha256(P3 owns the manifest entry; Jon picks the voice).
- Lane: infra · Owner: P2 · Priority: P0 · Phase: P3
- Acceptance: When
WAYFINDER_PHASE=3,infra/jetson_harden.shactivates iptables ruleset that drops all outbound except loopback + multicast group. Verified bymake tcpdump-demoshowing zero packets. - Files:
infra/jetson_harden.sh,infra/egress.iptables
- Lane: routing · Owner: P4 · Priority: P1 · Phase: P3
- Acceptance: Valhalla custom-cost lua reads pre-computed slope + prominence rasters; "covered foot" profile uses both; demo-verifiable on Scenario B.
- Files:
routing/costs/slope.py,routing/costs/prominence.py,routing/profiles/foot_covered.json
- Lane: eval · Owner: P1 · Priority: P1 · Phase: P3
- Acceptance:
eval/prompts.ymlhas 20 prompts with golden tool calls + golden route bounding boxes.make evalreports pass rate; CI fails if < 90%. - Files:
eval/prompts.yml,eval/runner.py
- Lane: security · Owner: P2 · Priority: P1 · Phase: P3
- Acceptance:
security/parse_verify.pyvalidates OSM tag combinations, tool-call args, and CoT structure against grammars. Rejects anomalies before they reach downstream tools. Tests cover the 5 primary attack vectors from Jon's paper. - Files:
security/parse_verify.py,tests/test_parse_verify.py
- Lane: mesh · Owner: P3 · Priority: P2 · Phase: stretch
- Acceptance: All three devices visible to each other on a single mesh; CoT multicast works between Jetson and Android EUD.
- Files:
mesh/network_setup.md
- Lane: mesh · Owner: P3 (impl) · Priority: P2 · Phase: stretch · Pair: P2 (signer)
- Acceptance:
mesh/inject_demo.pysends an unsigned CoT to the multicast group. Bridge logs rejection. Then a signed CoT is generated; bridge accepts. Two-device side-by-side. - Files:
mesh/inject_demo.py
- Lane: docs · Owner: P3 (capture) + P4 (script) · Priority: P0
- Acceptance: Video captured by Sun 1100, edited by 1145, uploaded unlisted to YouTube by 1200, link in submission form + README.
- Files:
docs/demo_video.md(script + URL)