Architecture

Layering

Locus is a two-layer system. Layer 1 (ARMS) is an existing open-source spatial memory fabric. Layer 2 (Locus) is the Solana protocol that anchors ARMS state and prices retrieval.

Layer 2 — Locus (this repo)
  ├─ programs/locus    on-chain accounts + instructions (Anchor)
  ├─ locus-client      Rust SDK
  ├─ locus-relayer     ARMS -> Solana bridge process
  ├─ locus-demo        end-to-end CLI for the hackathon proof
  └─ arms-service      Axum HTTP wrapper around arms-core

Layer 1 — ARMS (external)
  └─ arms-core crate   Point, Proximity, Merge, Place, Near

On-chain data model

AgentMemory — one PDA per agent

  • Seeds: ["agent", owner]
  • Fields: owner, memory_root [u8;32], version u64, last_updated i64, read_fee_lamports u64, write_count u64, read_count u64, metadata_uri String≤200, bump

The read_count and write_count counters are what the live usage dashboard sums.

RetrievalAttestation — one PDA per attested read

  • Seeds: ["attest", agent_memory, version, nonce]
  • Fields: agent, memory_root, version, query_hash, result_hash, requester, timestamp, nonce, bump

Trust model

  • The agent owner is the only party that can commit_memory or update_read_fee. Anyone can attest_retrieval — they pay the fee.
  • An attestation does not prove the off-chain retrieval was correct. It proves: at time T, requester R paid fee F for query hash Q and was returned result hash H against memory root M version V.
  • Replacing the SHA-256 result_hash with a SNARK over the actual k-NN computation closes that trust gap. That is roadmap.

Merkle root over ARMS state

The relayer computes a sorted binary Merkle tree over SHA256(id || 0x00 || coord_le_bytes) leaves and posts the root via commit_memory. For the demo this is recomputed end-to-end on each tick; production would use an incremental construction.

Hashing (cross-SDK compatible)

Both the Rust client and @lumi-node/locus-sdk compute identical hashes so attestations match regardless of which SDK created them:

  • Query hashSHA256(concat(f32_le(x) for x in embedding))
  • Result hash — for each neighbor: id_utf8 ‖ 0x00 ‖ f32_le(coords…) ‖ f32_le(distance)