Make smarter decisions with a coach who knows how you're really doing. Harlo reads your Apple Watch — sleep, heart, stress — learns your patterns, and eases off when you're running low. It watches for your crashes, backs off during flow, and helps you stop before you burn out.

Private by design. All your data lives on your device as local, composable state — no cloud, no data mining, no rented access to your own mind.


Status

PRODUCTION LIVE — Harlo v6.1-MOTOR
1,381 passing · 5 skipped (lean bundle) · Real OpenUSD canonical persistence · USD-Lite runtime tier
8/8 phase gates passed · Substrate-unified with sister project Moneta · P1 CIP defensible
1,390+ organic observations collected · Path C closed (Step 3)
Phase 5A landed: macOS bundle · intake calibration · biometric barrier · Motor Cortex with Basal Ganglia gating
v0.1.2: USD-proof trial — §F1 native composition · §F2 structural lossless · anchor immunity · P5 customData · P1 decision-tier — CONFIRMED on live pxr stage (verifier-first, 4 cycles)
v0.1.6: HarloPulse loop LIVE — Apple Watch → HealthKit → push-on-arrival → launchd socket → biometric barrier → coach
        first organic biometrics through the barrier · Siri/Shortcuts/Spotlight surface · Xcode 27 / iOS 27 SDK
Phase 5B built: Mac-local sibling — Apple Watch → HealthBridge (sandboxed) → XPC relay → daemon biometric loop (relay→daemon proven; full live Watch test pending)
v0.2.0: unified release — biometric_prior seed + HarloPulse (iPhone) + HealthBridge/XPC (macOS) reconciled; one version across every surface (core · Rust · macOS app · iOS app · bridge)
Sprint Tests What Shipped
S1 State Machine 84 Pydantic schemas, MockCogExec DAG (networkx), 7 pure computation functions, 26-invariant validator, 10K synthetic trajectories via Profile-Driven Markov Biasing, XGBoost predictor (100% per-field accuracy), Bridge integration
S2 OpenExec -- USD 26.03 built from source with PXR_BUILD_EXEC=ON. C++ Exec libraries compile. Circuit-breaker triggered: zero Python bindings in v26.03 source. MockCogExec continues to serve.
S3 Hydra Delegates 85 HdCognitiveDelegate ABC, DelegateRegistry (capability matching), HdClaude + HdClaudeCode, compute_routing (requirements not names), OOB consent tokens (HMAC-signed, TTL), sublayer-per-delegate concurrency, CognitiveEngine singleton, 20-exchange e2e
S4 Real USD 59 CognitiveStage wrapping pxr.Usd.Stage, stage_factory toggle, .usda files on disk with time-sampled CognitiveObservation, delegate sublayer .usda files, backend parity verified (mock = real USD)
S5 Production 22 Graceful degradation (independent failure isolation), health check endpoint, kill switches (ENGINE_ENABLED, USE_REAL_USD, OBSERVATION_LOGGING, PREDICTION_ENABLED), first session verified, production docs
Path C Step 3 v3.4.0 +39 Real OpenUSD as canonical persistence (codeless schema, 21 prim types under harlo plugin separate from Moneta); USD-Lite engine preserved as fast in-memory runtime tier (Fabric pattern); sync layer per D4 policy table; migration script for USD-Lite v1 → real USD; substrate-unified with sister project Moneta. P1 CIP framing now defensible.
Phase 5A macOS + Operator +51 macOS app bundle (Harlo.app + launchd socket activation), intake calibration CLI emitting three INTAKE_CALIBRATED Merkle layers, biometric barrier per ADR-0001 (opt-in HealthKit signals, freshness window, never enter trace pipeline), Motor Cortex with Basal Ganglia inhibition-default gating, harlo doctor --strict operator readiness, signing-readiness pre-flight (27 checks)
USD Trial v0.1.2 +verifier SOLO trial-harness loop (docs/trial-harness.md + docs/usd-proof-trial.md); 4 engine cycles verifier-first against wave1_harness.py; native USD-composition theses CONFIRMED on the live pxr-backed stage: §F1 LOCAL > VARIANT > SPECIALIZE resolution, §F2 reconstruct_clean bit-identical, anchor structural immunity (adversarial probe), P5 customData state tracking; new MCP tools — compose_demo, lossless_demo, anchor_demo, p5_state_demo, persist_stage, decision. P1 closed via Path C Actor-driven motor surface.
Pulse Loop v0.1.6 +13 HarloPulse iPhone sidecar deployed to hardware (Xcode 27 / iOS 27 SDK): 6-word HMAC pairing, per-type opt-in HealthKit reads (ADR-0001/D65), HKObserverQuery + background delivery for push-on-arrival, 48h lookback + chunked frames; Mac side pulse listen adopts a launchd-held TCP socket (Rule 1 — 0W between Watch syncs); App Intents surface (sync, status snippet, type toggles with clarification, OpenIntent, onscreen awareness); field-debugged end-to-end — first organic Apple Watch biometrics through the barrier into the coach. Four WWDC26 frontier docs: App Intents adoption plan, Foundation Models provider review (+ live-verified Python SDK addendum), code-along addendum, HealthKit collaboration report.
Phase 5B macOS HealthBridge -- Mac-local sibling to the HarloPulse iPhone loop — same biometric_barrier, different transport. Sandboxed HarloHealthBridge.app (HealthKit observers, signed under the Apple Developer Program) + HarloXPCRelay launchd Mach service bridging the sandboxed app to the daemon's UNIX socket — the App Group container can't host it (macOS blocks the non-sandboxed daemon from binding there). DaemonWriter over NSXPC, mach-lookup entitlement; full HR/HRV → biometric_barrierAllostasisTracker → DEPLETED/RED. Relay→daemon proven (XPC ingest of 180 bpm → force_red: true).

Benchmarks

Measured 2026-06-10 on the reference machine (Mac Studio M1 Ultra, 128 GB, macOS 27). Reproduce the search rows with cargo bench -p hippocampus (criterion, crates/hippocampus/benches/recall.rs).

Path Constitutional budget Measured Headroom
SDR search, 10k traces (k=5) 0.084 ms median
SDR search, 100k traces (k=5) < 2 ms (Rule 3) 0.844 ms median 2.4×
PyO3 module import 2.4 ms
Cold start — import + first recall over FFI < 5 ms (Rule 3) 3.4 ms 1.5×
Hot recall round trip (Python → Rust → SQLite) < 2 ms (Rule 3) 0.66 ms p50 · 0.94 ms p95 3.0×
Resident processes between sessions 0 (Rule 1) 0 — launchd holds the sockets, PID column reads -
Full Python suite (lean bundle) 1,381 passed in 17 s

1-bit SDR vectors with Hamming distance (no float32, no cosine — Rule 2) keep the search path pure integer XOR + popcount: a full 100k-trace scan completes in less time than a single localhost HTTP round trip.


USD Substrate Trial — Live-Stage Theses Confirmed (v0.1.2)

Four engine cycles run against a verifier-first SOLO trial harness proved the foundational USD-as-cognitive-substrate theses on the live pxr- backed real_usd stage — not via Python proxy, not by parametric guarantee. Every cycle observed RED before the change, GREEN after, and was independently re-verified in a cold-pxr process. Trial state lives in docs/usd-proof-trial.md (SPEC + CHAMPION v6 + LOG).

  • §F1 — USD-native-priority (Cycle 2). pxr resolves LOCAL > VARIANT > SPECIALIZE on /Brain/CompositionDemo. GetPropertyStack reports the strength order itself. Native composition arcs map to cognitive priority without fighting USD semantics.
  • §F2 — structural lossless (Cycle 3). reconstruct_clean() as flatten-to-base recovers the clean baseline bit-identically from a composed (clean + delta) stage. Same SHA256 from cold-pxr re-read; reconstruction is exact, not float-tolerant.
  • §F2 anchor structural immunity (Cycle 4). CONSTITUTIONAL / SAFETY / CONSENT / KNOWLEDGE anchors invariant across 4 delta profiles. The adversarial profile explicitly authors /Brain/Anchors/CONSTITUTIONAL.value = "MALICIOUS_OVERRIDE"; pxr rejects it by composition mechanics — anchor sublayer at subLayerPaths[0] wins. Structural, not parametric.
  • P5 — customData state tracking (Cycle 5). Unchanged / Edited / New derived per-prim from prim-stack analysis, written to a derived tags sublayer, read back through composition. Three prims, three states — tagged / computed / expected all agree.
  • P1 decision-tier closure (Cycle 6). New decision MCP tool — the Actor-driven motor surface — queues MotorPrims that persist_current_brain drains. Live stage now authors session + entity + decision tiers.

Reproduce: .venv312/bin/python wave1_harness.py. The 7-row scoreboard asserts the live USD flip, populated hierarchy (P1), native composition (P3 / §F1), structural lossless (P4 / §F2), anchor immunity (§F2 follow- up), and customData state tracking (P5).

Path C motor surface (Cycle 6) — Actor → live MotorPrim

sequenceDiagram
    participant User
    participant Tool
    participant Queue
    participant Persist
    participant Brain
    participant Writer
    participant Stage
    User->>Tool: decision action gate_status
    Note right of Tool: Rule 23 default<br/>Basal Ganglia inhibit-by-default
    Tool->>Queue: queue_motor_action
    Note over Queue: module-level list<br/>lives for the MCP subprocess
    User->>Persist: persist_stage
    Persist->>Queue: snapshot_pending_motor_actions
    Persist->>Brain: full_stage with motor_actions
    Brain->>Writer: motor_to_prims
    Writer->>Stage: DefinePrim MotorPrim under Brain Motor
    Note over Stage: live pxr stage<br/>Brain Motor populated

Diagram legend:

  • User = the actor (Claude in production; the trial harness in tests)
  • Tool = decision MCP tool (Actor-driven motor surface)
  • Queue = _PENDING_MOTOR_ACTIONS module-level list in persistence/__init__.py
  • Persist = persist_current_brain (called by persist_stage MCP tool)
  • Brain = brainstem.stage_builder.full_stage(motor_actions=…)
  • Writer = python/harlo/usd_lite/persistence/writer.py:_write_motorstage.DefinePrim("/Brain/Motor/action_i", "MotorPrim")
  • Stage = <DATA_DIR>/stages/runtime.usda (the live pxr.Usd.Stage)

The inert motor system (premotor, basal_ganglia, executor) remains disconnected — Path C creates the smallest honest motor surface. Consent escalation, basal-ganglia gating, and executor wiring are parked for future cycles.


HarloPulse — The Push-on-Arrival Biometric Loop (v0.1.6)

The iPhone sidecar shipped to hardware. Apple Watch biometrics now reach the Modulation Layer with zero resident processes on either side of the wire:

flowchart LR
    W["Apple Watch<br/>HR · HRV · RR · sleep · workouts"]:::runtime --> HK["iPhone HealthKit<br/>background delivery"]:::runtime
    HK --> APP["HarloPulse app<br/>HKObserverQuery wakes it"]:::runtime
    APP --> PUSH["delta push<br/>HMAC auth · 48h window · chunked frames"]:::runtime
    PUSH --> LD["Mac launchd<br/>holds TCP 48653 · spawns on SYN"]:::substrate
    LD --> LIS["pulse listen<br/>adopts socket · whitelist only"]:::substrate
    LIS --> BB["biometric barrier<br/>ADR-0001 · freshness window"]:::substrate
    BB --> MOD["modulation layer<br/>derived verdict only — D60"]:::substrate
    MOD --> COACH["coach · status<br/>Claude Desktop / Claude Code"]:::substrate

    classDef substrate fill:#d4895e,stroke:#a0623d,color:#000000
    classDef runtime fill:#e6c466,stroke:#a8884a,color:#000000

Properties, all field-verified on real hardware (iPhone → Mac Studio, June 2026):

  • Push-on-arrival, not polling — the Watch syncs, HealthKit wakes the app in the background, the app pushes the delta. No schedule, no daemon on the phone, no polling loop anywhere.
  • 0 W on the Mac (Rule 1) — launchd holds port 48653; pulse listen is spawned by the first SYN, drains the connection, exits. KeepAlive is structurally forbidden by the plist tests.
  • 6-word pairing, HMAC-authenticated frames — the raw token never persists; both sides keep only the derived key (iOS Keychain / 0600 file). Single-command whitelist (biometric_ingest), 1 MiB frame cap, 5-minute auth window.
  • Raw samples never touch disk on the Mac (Rule 9) — the barrier consumes them in memory and stores only the derived modulation verdict (load, depleted, stale).
  • Per-type opt-in, default OFF (ADR-0001 / D65) — nine HealthKit types, each with its own toggle and its own permission sheet.
  • Siri surface — "Sync HarloPulse," status snippet, type toggles with clarification dialogs, OpenIntent, onscreen awareness on iOS 18.2+.

Design history: docs/adr/0002-iphone-sidecar.md · WWDC26 adoption analyses in docs/frontier/.


Architecture · Path C (Fabric Pattern)

v3.4.0-path-c introduced codeless OpenUSD schemas as canonical persistence while preserving the existing USD-Lite engine as a fast in-memory runtime tier. Path C — the Fabric pattern — separates the two tiers so each can win at what it's good at: real OpenUSD owns durability and patent claims; USD-Lite owns hot-path latency.

Fabric pattern

flowchart TB
    subgraph PERSISTENCE["PERSISTENCE LAYER · canonical truth"]
        SCHEMA["HarloSchema.usda<br/>21 prim types · codeless"]:::substrate
        PLUG["plugInfo.json<br/>harlo namespace"]:::substrate
        DISK[".usda files on disk<br/>via pxr.Usd.Stage"]:::substrate
    end

    subgraph SYNCLAYER["SYNC LAYER · write-side dispatch"]
        WT["write_through<br/>SessionPrim · GateStatusPrim<br/>MerkleRootPrim · MotorPrim"]:::substrate
        CP["checkpoint<br/>TracePrim · CompositionLayerPrim<br/>SkillPrim · intake/multipliers"]:::substrate
    end

    subgraph RUNTIME["RUNTIME LAYER · hot-path reads"]
        ENGINE["USD-Lite engine<br/>regex parser · sub-ms reads"]:::runtime
        DC["21 dataclass prim types<br/>Python in-memory"]:::runtime
    end

    MIG["migrate_path_c.py<br/>USD-Lite v1 → real USD<br/>idempotent · CLI"]:::substrate

    PERSISTENCE -->|"sync at boundaries"| SYNCLAYER
    SYNCLAYER --> RUNTIME
    MIG -.->|"upgrade path"| PERSISTENCE

    classDef substrate fill:#d4895e,stroke:#a0623d,color:#000000
    classDef runtime fill:#e6c466,stroke:#a8884a,color:#000000

The persistence layer is the canonical truth. The runtime layer is the fast tier that tests and live sessions exercise. The sync layer routes mutations between them based on a per-prim policy table. Reads always hit the runtime tier; persistence is touched only at sync boundaries (Constitution Law 4).

The [substrate] extra activates the persistence layer:

pip install -e .[substrate]   # Pulls usd-core 26.5; activates persistence/

Core Harlo runs without [substrate]pxr stays optional per Constitution Law 3.

Schema · IsA hierarchy

The codeless schema in schema/HarloSchema.usda declares 21 prim types in a 3-tier IsA hierarchy parallel to containment (D2):

flowchart TB
    Typed["Typed · USD root"]:::substrate

    HP["HarloPrim · abstract"]:::substrate
    HC["HarloContainer · abstract"]:::substrate

    Typed --> HP
    HP --> HC

    BS["BrainStage"]:::substrate
    AP["AssociationPrim"]:::substrate
    CP["CompositionPrim"]:::substrate
    EP["ElenchusPrim"]:::substrate
    ICP["InquiryContainerPrim"]:::substrate
    MCP["MotorContainerPrim"]:::substrate
    SCP["SkillsContainerPrim"]:::substrate
    CPP["CognitiveProfilePrim"]:::substrate

    HC --> BS
    HC --> AP
    HC --> CP
    HC --> EP
    HC --> ICP
    HC --> MCP
    HC --> SCP
    HC --> CPP

    TP["TracePrim"]:::runtime
    CLP["CompositionLayerPrim"]:::runtime
    GSP["GateStatusPrim"]:::runtime
    MRP["MerkleRootPrim"]:::runtime
    SP["SessionPrim"]:::runtime
    IP["InquiryPrim"]:::runtime
    MP["MotorPrim"]:::runtime
    SkP["SkillPrim"]:::runtime
    MuP["MultipliersPrim"]:::runtime
    IHP["IntakeHistoryPrim"]:::runtime

    HP --> TP
    HP --> CLP
    HP --> GSP
    HP --> MRP
    HP --> SP
    HP --> IP
    HP --> MP
    HP --> SkP
    HP --> MuP
    HP --> IHP

    APIB["APISchemaBase · USD"]:::substrate
    PROV["Provenance · applied API"]:::substrate
    APIB --> PROV
    PROV -.->|"attaches to"| CLP

    classDef substrate fill:#d4895e,stroke:#a0623d,color:#000000
    classDef runtime fill:#e6c466,stroke:#a8884a,color:#000000
  • Two abstract bases: HarloPrim (root of every Harlo type) and HarloContainer (parent of structural composites).
  • Eight concrete container types: BrainStage plus seven subsystem containers (Association, Composition, Elenchus, Inquiry, Motor, Skills, CognitiveProfile).
  • Ten concrete leaf types holding the actual cognitive-state attributes.
  • One singleApply API schema (Provenance, per D10) that attaches origin metadata to host prims without cluttering the IsA tree.

Five enum types use lower-case allowedTokens per Constitution Cmd 11: SourceType, VerificationState, RetrievalPath, MotorGateStatus, ArcType. Cross-plugin: zero collisions with sister project Moneta's MonetaMemory typeName (D3 verified).

Sync layer · per-prim policy

The sync layer at python/harlo/sync/ routes writes per the D4 policy table:

flowchart LR
    START["BrainStage<br/>write"]:::substrate
    DECISION{"Prim type<br/>policy?"}:::substrate

    WT["write_through<br/>MotorPrim · GateStatusPrim<br/>MerkleRootPrim · SessionPrim"]:::substrate
    CP["checkpoint<br/>TracePrim · CompositionLayerPrim<br/>SkillPrim · intake/multipliers<br/>InquiryPrim"]:::substrate
    INMEM["InjectionPrim<br/>D5 · session-scoped"]:::runtime

    OUT_WT["immediate<br/>sync to disk"]:::substrate
    OUT_CP["deferred sync<br/>at checkpoint"]:::substrate
    OUT_INMEM["no persistence"]:::runtime

    START --> DECISION
    DECISION -->|"write-through"| WT
    DECISION -->|"checkpoint"| CP
    DECISION -.->|"in-memory-only"| INMEM
    WT --> OUT_WT
    CP --> OUT_CP
    INMEM -.-> OUT_INMEM

    classDef substrate fill:#d4895e,stroke:#a0623d,color:#000000
    classDef runtime fill:#e6c466,stroke:#a8884a,color:#000000
  • write_through — synchronous persistence on every mutation. Used for consistency-critical prims (SessionPrim, GateStatusPrim, MerkleRootPrim) and the safety-critical MotorPrim (D4 ruling).
  • checkpoint — deferred persistence; callers mark prim paths dirty during the session and flush explicitly. Used for high-write-rate prims to keep per-mutation persistence cost bounded.
  • In-memory onlyInjectionPrim is session-scoped per D5 (evicted from disk; runtime dataclass retained for /inject command flows).

Containers inherit policy from their dominant child type. The migration script (python/harlo/migrate_path_c.py) converts existing USD-Lite text-format captures to real-USD format; read-tolerant on input, idempotent on already-migrated files.


Architecture · v6.1-MOTOR (Brain Stages)

The v6.1-MOTOR architecture is governed by 33 inviolable rules that decompose Harlo into biologically-named stages: two hemispheres (Association and Composition), a Bridge with an Amygdala for 1-shot safety reflexes, a Modulation Layer fronted by a Blood-Brain Barrier, the Elenchus verification engine (GVR with hard trace-exclusion), the Default Mode Network for inquiry synthesis, and a Motor Cortex governed by Basal Ganglia gating. State lives in real USD layers (Path C); the brain stages are how that state is operated on.

Inhibition-default Motor Cortex matters because it inverts the usual agent-actuation default. Every motor action is INHIBITED until all five Basal Ganglia checks pass — anchor · consent · elenchus · reversibility · scope (see python/harlo/motor/basal_ganglia.py). One failed check = inhibit. No exceptions, no chaining, no implicit retry — RED state locks the gate entirely (Rule 28). The Amygdala bypass exists for the inverse case: SAFETY and CONSENT resolutions compile to 1-shot permanent reflexes (Rule 7), so the verification engine never re-evaluates "do not do the unsafe thing."

flowchart TB
    INPUT["MCP / CLI input"]:::substrate

    subgraph SENSORY["Sensory · two hemispheres"]
        HIPP["Hippocampus<br/>Rule 2 · 1-bit SDR<br/>Rule 3 · Rust hot path<br/>Rule 4 · lazy decay"]:::substrate
        COMP["Composition<br/>Rule 6 · Merkle trees<br/>partial branch O(log n)"]:::substrate
    end

    subgraph BRIDGE["Bridge with Amygdala"]
        AMYG["Amygdala<br/>Rule 7 · 1-shot SAFETY/CONSENT<br/>Rule 14 · intent preservation"]:::runtime
    end

    subgraph MOD["Modulation Layer"]
        BBB["Blood-Brain Barrier<br/>Rule 8 · jsonschema validate<br/>strip epigenetic wash"]:::substrate
        ALLO["Allostatic Load<br/>Rule 9 · velocity + freq<br/>+ biometric (ADR-0001)"]:::substrate
        ANCH["Anchors<br/>Rule 10 · gain 1.0<br/>SAFETY · CONSENT · KNOWLEDGE"]:::substrate
    end

    subgraph ELENCHUS["Elenchus GVR · verification"]
        VER["verify()<br/>Rule 11 · TRACE EXCLUSION<br/>Rule 13 · max 3 cycles<br/>Rule 15 · spec-gaming detect"]:::runtime
        UNPROV["UNPROVABLE state<br/>Rule 16 · dignified park"]:::runtime
    end

    subgraph DMN["DMN · Inquiry"]
        INQ["Inquiry Engine<br/>S1 · apophenia guard<br/>S2 · epistemological bypass<br/>S8 · sincerity gate"]:::runtime
    end

    subgraph MOTOR["Motor Cortex with Basal Ganglia"]
        BG["Basal Ganglia gate<br/>Rule 23 · INHIBIT default<br/>5 checks · one fails = inhibit"]:::substrate
        ACT["Atomic action<br/>Rule 24 · one at a time<br/>Rule 32 · zero-tolerance reflex"]:::substrate
    end

    RED["RED state<br/>Rule 28 · kills motor<br/>Rule 18 · overrides all"]:::runtime

    INPUT --> HIPP
    INPUT --> COMP
    HIPP --> AMYG
    COMP --> AMYG
    AMYG --> BBB
    BBB --> ALLO
    BBB --> ANCH
    ALLO --> VER
    ANCH --> VER
    VER --> UNPROV
    VER --> INQ
    INQ --> BG
    VER --> BG
    BG --> ACT
    RED -.->|"inhibit"| BG
    RED -.->|"halt"| INQ
    RED -.->|"halt"| VER

    classDef substrate fill:#d4895e,stroke:#a0623d,color:#000000
    classDef runtime fill:#e6c466,stroke:#a8884a,color:#000000

Phase 5A · macOS bundle + operator layer

Phase 5A wraps the v6.1-MOTOR brain in a shippable macOS surface and the operator tools to keep it healthy:

  • harlo intake — calibrated questionnaire that emits three INTAKE_CALIBRATED Merkle layers (raw answers, derived multipliers, coaching scaffold) under Rule 8 (JSON Barrier) and Rule 19/30 (preemption via TEMP_DIR, never SQLite mid-flow).
  • harlo doctor --strict — read-only operator readiness check: DATA_DIR sizing, daemon/PID/socket state, JSON schema parseability, and the eight compliance greps from CLAUDE.md. Exits nonzero in strict mode for CI gating.
  • harlo audit — surface for Elenchus state and reflex cache inspection without waking System 2.
  • biometric_barrier — opt-in HealthKit ingest path per ADR-0001. Biometric samples enter the Modulation Layer only; compliance grep forbids them from bridge/ or elenchus/. Freshness window (default 5 min) prevents stale signals from driving RED (Rule 28).
  • macos/launchd/* — socket-activated daemon plist (0W idle, Rule 1) plus the separate com.harlo.healthbridge KeepAlive plist for the HealthKit observer process.
  • Harlo.app — py2app bundle, codesigned and notarized via the signing chain documented in docs/SIGNING.md.
flowchart LR
    FIRST["First run"]:::substrate
    DATA["DATA_DIR setup<br/>ensure_data_dirs()<br/>schemas + stages + temp"]:::substrate
    INTAKE["harlo intake start<br/>3 Merkle layers<br/>Rule 8 validated"]:::substrate
    DOC["harlo doctor --strict<br/>27 readiness checks<br/>8 compliance greps"]:::substrate
    BIO["Biometric ingest<br/>opt-in per data type<br/>ADR-0001 barrier"]:::runtime
    GATE["Motor gate<br/>Rule 23 · INHIBIT default<br/>5 checks · pass=act"]:::substrate
    ACT["Atomic action<br/>Rule 24 · one at a time"]:::runtime

    FIRST --> DATA --> INTAKE --> DOC
    DOC --> BIO
    DOC --> GATE
    BIO -.->|"allostatic only"| GATE
    GATE --> ACT

    classDef substrate fill:#d4895e,stroke:#a0623d,color:#000000
    classDef runtime fill:#e6c466,stroke:#a8884a,color:#000000

See docs/SIGNING.md and docs/APPLE_SECRETS_SETUP.md for the signing/notarization chain.

Phase 5B · Apple Watch biometric loop (HealthKit → XPC → daemon)

Phase 5B closes the sensor loop: an opt-in Apple Watch → Mac biometric stream feeding the Modulation Layer's allostatic load. The bridge that owns HealthKit must be sandboxed (Apple requires it); the daemon is not — and the two cannot share a UNIX socket (the App Group container blocks the non-sandboxed daemon from binding there). The rendezvous is a launchd Mach service reached over XPC:

flowchart LR
    WATCH["Apple Watch<br/>HR · HRV · RR · sleep · SpO₂"]:::runtime
    BRIDGE["HarloHealthBridge.app<br/>SANDBOXED · HealthKit observers<br/>HKObserverQuery · wakes on callback"]:::substrate
    RELAY["HarloXPCRelay<br/>launchd Mach service · NOT sandboxed<br/>com.harlo.xpc"]:::substrate
    DAEMON["Harlo daemon<br/>socket-activated · 0W idle"]:::substrate
    BARRIER["biometric_barrier<br/>jsonschema · Rule 9 / ADR-0001<br/>Modulation Layer ONLY"]:::runtime
    ALLO["AllostasisTracker<br/>HR · HRV · RR → load<br/>freshness window · DEPLETED / force-RED"]:::runtime

    WATCH -->|"iCloud Health sync"| BRIDGE
    BRIDGE -->|"NSXPCConnection<br/>mach-lookup entitlement"| RELAY
    RELAY -->|"framed JSON<br/>twind.sock"| DAEMON
    DAEMON --> BARRIER --> ALLO

    classDef substrate fill:#1a2332,stroke:#4a90a4,color:#e8eef2
    classDef runtime fill:#d4af37,stroke:#8b7115,color:#1a2332
  • HarloHealthBridge.app — sandboxed, signed under the Apple Developer Program (HealthKit is a restricted entitlement → paid membership). Owns the HealthKit observers; wakes only on HKObserverQuery callbacks (the sole KeepAlive process, ADR-0001).
  • HarloXPCRelay — a non-sandboxed launchd Mach service. The sandboxed bridge reaches it via a mach-lookup temporary-exception entitlement; the relay forwards length-prefixed biometric_ingest JSON to the daemon's twind.sock, which it (being unsandboxed) can reach. On-demand + idle-exit, so Rule 1 (0W idle) holds.
  • biometric_barrier — every sample is jsonschema-validated and enters the Modulation Layer only; a compliance grep forbids biometrics in bridge/ or elenchus/. Stale samples (older than the freshness window) can mark DEPLETED but never drive RED — Apple-Watch→Mac latency must not inhibit motor.

The daemon receive-side and the relay→daemon path are proven end-to-end (an XPC ingest of 180 bpm returned {force_red: true, biometric_load: 1.0}). See docs/HEALTHKIT_ACTIVATION.md for the build / provisioning / install runbook.


Tech Stack

  • USD 26.03 — Cognitive state stored in real .usda files. Time-sampled. Human-readable. Git-trackable. Sublayer composition via LIVRPS.
  • OpenExec — C++ libs built, Python bindings deferred (Pixar hasn't shipped them yet). Architecture is OpenExec-native; implementation catches up later.
  • Hydra Delegates — The Hd prefix is a naming convention, not an import. Pure Python. Any LLM implements the interface, registers, done.
  • XGBoost — MultiOutputRegressor predicting momentum, burnout, energy, burst from 111-feature sliding window. Trained on 10K synthetic trajectories (278K exchanges).
  • Python 3.12 (USD) / 3.14 (project) — Dual venv. Real USD on 3.12, graceful mock fallback on 3.14.
  • Rust — Hippocampus crate via PyO3. 1-bit SDR encoding, XOR popcount kNN, lazy decay. Sub-2ms recall.
  • MCP — 8 tools over stdio. Works with Claude Desktop, Claude Code, any MCP client.
  • Click 8.x CLIharlo intake, harlo doctor, harlo audit operator surfaces.
  • launchd socket activation — 0W idle daemon per Rule 1; separate KeepAlive plist for the HealthBridge.
  • Swift + HealthKitHarloHealthBridge.app (sandboxed HealthKit observer over HKObserverQuery/HKAnchoredObjectQuery) and HarloXPCRelay (the non-sandboxed XPC Mach-service relay). Apple Watch → Mac biometric stream into the Modulation Layer.
  • XPC (NSXPCConnection) — sandbox-safe bridge↔daemon rendezvous; the relay is a launchd Mach service the sandboxed app reaches via a mach-lookup entitlement (the App Group container can't host the daemon socket).
  • py2app bundling — Harlo.app produced from the Python source tree.
  • codesign + notarytool — Apple Developer ID signing and notarization for distributed artifacts.

Architecture

System Layers

%%{init: {'theme': 'dark', 'themeVariables': {'primaryColor': '#1a1a2e', 'primaryTextColor': '#e0e0e0', 'primaryBorderColor': '#7c3aed', 'lineColor': '#7c3aed', 'secondaryColor': '#16213e', 'tertiaryColor': '#0f3460'}}}%%
graph TB
    USER["You · Claude Desktop / Claude Code"]:::user

    subgraph MCP["MCP Server · 8 Tools · stdio"]
        direction LR
        COACH["coach"]:::tool
        STORE["store"]:::tool
        RECALL["recall"]:::tool
        QPE["query_past_experience"]:::tool
        PATTERNS["patterns"]:::tool
        SESSION["status"]:::tool
        RESOLVE["resolve_verifications"]:::tool
        RECAL["trigger_recalibration"]:::tool
    end

    subgraph ENGINE["CognitiveEngine · Production Singleton"]
        direction TB
        DAG["MockCogExec · networkx DAG\nburst → energy → momentum\n→ burnout → allostasis\n+ injection_gain · context_budget · routing"]:::engine
        DELEGATES["Hydra Delegates\nHdClaude · HdClaudeCode\ncapability-matched routing"]:::engine
        PREDICT["XGBoost Predictor\n3-step window · 111 features\n→ momentum · burnout · energy · burst"]:::engine
    end

    subgraph STAGE["USD Stage · .usda on Disk"]
        direction LR
        ROOT["harlo.usda\nTime-sampled state\nCanonical prim hierarchy"]:::usd
        CLAUDE_SUB["delegates/claude.usda\nInteractive opinions"]:::usd
        CODE_SUB["delegates/claude_code.usda\nBatch opinions"]:::usd
    end

    subgraph MEMORY["Core Twin · Biologically-Architected Memory"]
        direction TB
        HOT["Hot Tier · FTS5\n< 0.2ms store"]:::memory
        WARM["Warm Tier · SDR Hamming\nRust PyO3 · < 2ms recall"]:::memory
        ELENCHUS["Elenchus · GVR\ntrace-excluded verify"]:::memory
        HEBBIAN["Hebbian · dual-mask\nSDR evolution"]:::memory
        COMPOSITION["Composition · Merkle\nLIVRPS resolution"]:::memory
    end

    BUFFER["Observation Buffer\nanchor 20% · organic 80%\n458 observations"]:::buffer

    USER --> MCP
    MCP --> ENGINE
    ENGINE --> STAGE
    ENGINE --> BUFFER
    STAGE --> ENGINE
    MCP --> MEMORY
    MEMORY --> MCP
    ENGINE -->|"enriched context"| USER

    classDef user fill:#e6c466,stroke:#a8884a,color:#000000,font-weight:bold
    classDef tool fill:#d4895e,stroke:#a0623d,color:#000000
    classDef engine fill:#d4895e,stroke:#a0623d,color:#000000,font-weight:bold
    classDef usd fill:#e6c466,stroke:#a8884a,color:#000000,font-weight:bold,stroke-width:3px
    classDef memory fill:#d4895e,stroke:#a0623d,color:#000000
    classDef buffer fill:#e6c466,stroke:#a8884a,color:#000000

Exchange Loop

Every MCP tool call flows through this 7-step pipeline:

%%{init: {'theme': 'dark', 'themeVariables': {'primaryColor': '#1a1a2e', 'primaryTextColor': '#e0e0e0', 'primaryBorderColor': '#7c3aed', 'lineColor': '#7c3aed'}}}%%
graph LR
    CALL["MCP Tool Call"]:::input

    subgraph PIPELINE["CognitiveEngine · Per-Exchange Pipeline"]
        direction LR
        S1["1 · Author\nBuild observation\nfrom tool context"]:::step
        S2["2 · Evaluate\nDAG: burst → energy\n→ momentum → burnout\n→ allostasis"]:::step
        S3["3 · Route\ncompute_routing →\ncapability requirements"]:::step
        S4["4 · Delegate\nSync → Execute\n→ CommitResources\nto sublayer"]:::step
        S5["5 · Observe\nEmit to buffer\nanchor/organic split"]:::step
        S6["6 · Predict\nXGBoost forecast\nauthor to /prediction"]:::step
        S7["7 · Save\n.usda to disk\ngraceful on failure"]:::step
        S1 --> S2 --> S3 --> S4 --> S5 --> S6 --> S7
    end

    RESPONSE["Enriched Response\ncognitive_context\ndelegate_id · expert\nprediction"]:::output

    CALL --> PIPELINE --> RESPONSE

    classDef input fill:#e6c466,stroke:#a8884a,color:#000000,font-weight:bold
    classDef step fill:#d4895e,stroke:#a0623d,color:#000000
    classDef output fill:#e6c466,stroke:#a8884a,color:#000000,font-weight:bold

Cognitive State Machines

Five state machines evaluated via topologically-sorted DAG on every exchange:

%%{init: {'theme': 'dark', 'themeVariables': {'primaryColor': '#1a1a2e', 'primaryTextColor': '#e0e0e0', 'primaryBorderColor': '#7c3aed', 'lineColor': '#7c3aed'}}}%%
stateDiagram-v2
    direction LR

    state Momentum {
        direction LR
        [*] --> COLD_START
        CRASHED --> COLD_START: always
        COLD_START --> BUILDING: tasks >= threshold
        BUILDING --> ROLLING: coherence + velocity
        ROLLING --> PEAK: exchanges + burst
        PEAK --> CRASHED: burnout >= ORANGE
    }

    state Burnout {
        direction LR
        [*] --> GREEN
        GREEN --> YELLOW: frustration or duration
        YELLOW --> ORANGE: sustained frustration
        ORANGE --> RED: extreme frustration
        note right of RED: ANY -> RED via exogenous override
    }

    state Energy {
        direction LR
        [*] --> MEDIUM
        HIGH --> MEDIUM: natural decay
        MEDIUM --> LOW: session length
        LOW --> DEPLETED: continued work
        note right of DEPLETED: Burst suspends decay\nDebt applies on exit
    }

    state Burst {
        direction LR
        [*] --> NONE_B
        NONE_B --> DETECTED: velocity + coherence
        DETECTED --> PROTECTED: sustained
        PROTECTED --> WINDING: exchange threshold
        WINDING --> EXIT_PREP: exit threshold
        EXIT_PREP --> NONE_B: next exchange
    }

Hydra Delegate Pattern

The DAG outputs what's needed. The registry selects who fulfills it. The DAG never names a specific LLM.

%%{init: {'theme': 'dark', 'themeVariables': {'primaryColor': '#1a1a2e', 'primaryTextColor': '#e0e0e0', 'primaryBorderColor': '#7c3aed', 'lineColor': '#7c3aed'}}}%%
graph TB
    ROUTING["compute_routing\nOutputs: requirements\nNOT delegate names"]:::route

    subgraph REQUIREMENTS["Capability Requirements"]
        direction LR
        REQ_TASKS["supported_tasks\nreasoning · coaching\ncode_generation"]:::req
        REQ_LATENCY["latency_max\nrealtime · interactive\nbatch"]:::req
        REQ_CODING["requires_coding\ntrue / false"]:::req
        REQ_CTX["context_budget\nlight · medium · heavy"]:::req
    end

    subgraph SAFETY["Safety Overrides"]
        direction LR
        RED["RED burnout\n-> force restorer\nconsent ignored"]:::red
        ORANGE["ORANGE + no consent\n-> force restorer"]:::orange
        CONSENT["OOB Consent\nHMAC-signed\nTTL · revocable"]:::consent
    end

    subgraph REGISTRY["DelegateRegistry · Capability Match"]
        direction TB
        MATCH["Filter → Sort → Select\nprefer lower latency\nthen higher context"]:::registry

        subgraph DELEGATES["Registered Delegates"]
            direction LR
            CLAUDE["HdClaude\nreasoning · coaching\nanalysis · exploration\ninteractive · 200K"]:::claude
            CODE["HdClaudeCode\nimplementation · debugging\ncode_generation · testing\nbatch · 200K"]:::code
            FUTURE["Your Delegate\nimplement interface\nregister · done"]:::future
        end
    end

    subgraph SUBLAYERS["Per-Delegate .usda Sublayers"]
        direction LR
        SUB_C["claude.usda\nSTRONGEST"]:::sub
        SUB_CC["claude_code.usda"]:::sub
    end

    ROUTING --> REQUIREMENTS
    ROUTING --> SAFETY
    REQUIREMENTS --> REGISTRY
    SAFETY --> REGISTRY
    MATCH --> DELEGATES
    DELEGATES -->|"Sync/Execute/Commit"| SUBLAYERS

    classDef route fill:#d4895e,stroke:#a0623d,color:#000000,font-weight:bold
    classDef req fill:#d4895e,stroke:#a0623d,color:#000000
    classDef red fill:#e6c466,stroke:#a8884a,color:#000000,font-weight:bold
    classDef orange fill:#e6c466,stroke:#a8884a,color:#000000
    classDef consent fill:#e6c466,stroke:#a8884a,color:#000000
    classDef registry fill:#d4895e,stroke:#a0623d,color:#000000
    classDef claude fill:#d4895e,stroke:#a0623d,color:#000000,font-weight:bold
    classDef code fill:#d4895e,stroke:#a0623d,color:#000000,font-weight:bold
    classDef future fill:#d4895e,stroke:#a0623d,color:#000000,stroke-dasharray: 5 5
    classDef sub fill:#e6c466,stroke:#a8884a,color:#000000,stroke-width:2px

Prediction Pipeline

From synthetic autoresearch to live organic observations:

%%{init: {'theme': 'dark', 'themeVariables': {'primaryColor': '#1a1a2e', 'primaryTextColor': '#e0e0e0', 'primaryBorderColor': '#7c3aed', 'lineColor': '#7c3aed'}}}%%
graph TB
    subgraph SYNTHETIC["Autoresearch · Sprint 1"]
        direction TB
        GEN["Trajectory Generator\n7 profiles · Markov Biasing\nnormal 40% · deep_work 15%\nstruggling 15% · recovery 10%\ninjection 10% · crisis 5% · mobile 5%"]:::gen
        TRAJ["10,000 sessions\n278,577 exchanges\n0 invariant violations"]:::gen
        GEN --> TRAJ
    end

    subgraph BUFFER["Observation Buffer · SQLite"]
        direction LR
        ANCHOR["Anchor Partition\n20% · locked synthetic\nbaseline coverage"]:::anchor
        ORGANIC["Organic Partition\n80% · surprise-weighted\nlive session data"]:::organic
    end

    subgraph TRAINING["XGBoost Training"]
        direction TB
        WINDOW["3-step sliding window\n111 features per sample"]:::train
        ENCODE["Ordinal: momentum, burnout, energy\nOne-Hot: action_type, injection_profile\nDrop: exchange_index, session_id"]:::train
        MODEL["MultiOutputRegressor\nXGBRegressor(reg:squarederror)\nRound + clamp to valid range"]:::train
        WINDOW --> ENCODE --> MODEL
    end

    subgraph LIVE["Live Prediction · Per Exchange"]
        direction TB
        OBS_WIN["Last 3 observations\nfrom current session"]:::live
        PRED["Predict: momentum\nburnout · energy · burst"]:::live
        AUTHOR["Author to\n/prediction/forecast\non USD stage"]:::live
        OBS_WIN --> PRED --> AUTHOR
    end

    TRAJ --> ANCHOR
    TRAJ --> TRAINING
    ORGANIC -->|"retrain"| TRAINING
    MODEL --> LIVE

    classDef gen fill:#d4895e,stroke:#a0623d,color:#000000
    classDef anchor fill:#d4895e,stroke:#a0623d,color:#000000,stroke-width:3px
    classDef organic fill:#e6c466,stroke:#a8884a,color:#000000
    classDef train fill:#d4895e,stroke:#a0623d,color:#000000
    classDef live fill:#e6c466,stroke:#a8884a,color:#000000,font-weight:bold

Graceful Degradation

Every component fails independently. The MCP server never crashes.

Component Failure Fallback Logged