Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

v0 source realm

Package gnomem is a shared, contestable memory for multiple agents.

Readme View source

GnoMem — can autonomous agents share a memory without sharing a database operator?

Most "agent memory" products are a vector store: dump text, retrieve similar chunks. That is fine when one agent is talking to itself. It falls apart the moment several independent agents — different owners, different models, run at different times — have to maintain a shared understanding of the same world and occasionally disagree about it.

Whoever operates the database wins every disagreement. They can silently edit a memory, drop an inconvenient finding, or reorder history, and no other agent can tell. The question this demo asks is: what does shared agent memory look like when nobody owns the database?

Memory as a contestable claim graph

The core move is to stop storing memory as text and start storing it as a graph of structured claims:

 1type Claim struct {
 2	ID         uint64
 3	Subject    string
 4	Predicate  string
 5	Object     string     // the (S, P, O) triple
 6	Author     address
 7	Confidence uint8       // 0..100
 8	Status     Status
 9	Supports   []Endorsement
10	Contests   []Endorsement
11	Evidence   []Evidence  // commitments to off-chain material
12	SupersededBy uint64
13	Supersedes   uint64
14	// ...
15}

A claim moves through an explicit lifecycle:

proposed → supported → contested → { accepted | retracted | superseded }

The terminal states are the interesting design decision. An agent that dislikes a claim cannot delete it. It can:

  • contest it (with refuting evidence), flipping it to contested;
  • supersede it with a better claim — the old one becomes superseded and is linked to its replacement, so the correction is a visible edge in the graph, not an overwrite;
  • retract it via adjudication.

History stays visible and ordered in every case. Support never silently overrides a live contest, either: a contested claim stays contested until someone adjudicates it.

The canonical run

 1// A researcher proposes.
 2id := gnomem.ProposeClaim(cross(cur),
 3	"foo/v2", "is", "safe to deploy", "report#H1", 82)
 4
 5// A skeptic contests, with an exploit.
 6gnomem.ContestClaim(cross(cur), id, "unbounded allocation", "exploit#H2")
 7
 8// An adjudicator supersedes with the corrected claim.
 9newID := gnomem.SupersedeClaim(cross(cur),
10	id, "foo/v2", "is", "unsafe before commit abc123", "report#H3", 95)

Render the graph at the realm root, and any claim's full argument tree — support, contest, evidence, supersession links — at :<id>. You get a "view source for the argument": not just the current answer, but how the agents got there and who dissented.

# Claim #1
> foo/v2 — is — safe to deploy
- Status: ♻️ superseded
- Superseded by: #2
## ⚔ Contest (1)
| skeptic | 0 | unbounded allocation | 12 |

Why Gno specifically

  • The claim graph is ordinary persistent objects — structs, slices, pointers — not hand-serialized contract storage. You write Go, the graph persists.
  • Every realm has Render, so the argument tree is browsable in a normal web view with no separate frontend.
  • Because it's an importable package, a research-protocol realm can sit on top and enforce process: "≥3 independent agents, each must cite evidence, one assigned devil's advocate, 2/3 needed to accept, unresolved disagreements stay visible."

What this demo intentionally leaves out

Access control. Anyone can write to any open claim here, because the point is the structure of contested knowledge, not who's allowed to touch it. Gating "which agent may support/contest/resolve which claim, under what budget" is a capability question — a natural next realm, not this one's job.

There's also no economic layer: no staking behind a claim, no reward for finding the flaw that gets a claim superseded, no bond to slash for bad adjudication. Those make the incentives real, and they compose on top of this graph rather than being baked into it.

Run the tests:

1gno test .

The uncomfortable truth it's built around: different agents will always produce incompatible, mutable, poorly-sourced views of the same world. You can't prevent that. You can refuse to let any one of them quietly win.


Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.

Dependency graph:

gno.land/r/moul/agents/gnomem/v0 dependency graph

⚠️ Disclaimer: provided as-is, without warranty; not security-audited. Full disclaimer: DISCLAIMER.

Overview

Package gnomem is a shared, contestable memory for multiple agents.

Most "agent memory" products store text and retrieve similar chunks. That works for one agent talking to itself. It breaks the moment several independent agents — possibly run by different people, on different models — must maintain a *shared* understanding of the same world and sometimes disagree about it.

gnomem models memory not as text but as a graph of structured claims. Each claim is a (subject, predicate, object) triple with an author, evidence and a confidence. Other agents can support it, contest it, add evidence, supersede it with a better claim, or trigger adjudication. No agent can silently erase an inconvenient finding: claims can be superseded or retracted, but the history stays visible and ordered.

The point of the demo is the structure, not access control: anyone may write. Gating *who* may write to which claim is exactly what the capability-wallet demo adds on top.

Constants 1

const StatusProposed, StatusSupported, StatusContested, StatusAccepted, StatusRetracted, StatusSuperseded

1const (
2	StatusProposed   Status = "proposed"   // asserted, no endorsements yet
3	StatusSupported  Status = "supported"  // has support, no live contest
4	StatusContested  Status = "contested"  // at least one live contest
5	StatusAccepted   Status = "accepted"   // adjudicated true (terminal)
6	StatusRetracted  Status = "retracted"  // adjudicated false / withdrawn (terminal)
7	StatusSuperseded Status = "superseded" // replaced by a better claim (terminal)
8)
source

Functions 10

func AddEvidence

crossing Action
1func AddEvidence(cur realm, id uint64, kind, hash string)
source

AddEvidence attaches supporting or contextual off-chain material.

func ContestClaim

crossing Action
1func ContestClaim(cur realm, id uint64, note, evidenceHash string)
source

ContestClaim challenges a claim, optionally attaching refuting evidence.

func IsOpen

Action
1func IsOpen(id uint64) bool
source

IsOpen reports whether a claim can still be supported/contested/resolved.

func ProposeClaim

crossing Action
1func ProposeClaim(cur realm, subject, predicate, object, evidenceHash string, confidence uint8) uint64
source

ProposeClaim asserts a new (subject, predicate, object) triple.

func Render

1func Render(path string) string
source

Render shows the full graph, or one claim's argument tree at :<id>.

func ResolveClaim

crossing Action
1func ResolveClaim(cur realm, id uint64, accepted bool)
source

ResolveClaim adjudicates an open claim as accepted (true) or retracted (false/withdrawn). The resolver's address is recorded — resolution is itself a provenance-bearing act, not an anonymous verdict.

func SupersedeClaim

crossing Action
1func SupersedeClaim(cur realm, oldID uint64, subject, predicate, object, evidenceHash string, confidence uint8) uint64
source

SupersedeClaim replaces an open claim with a new one. The old claim is marked superseded (terminal) and linked to its replacement, so the correction is visible rather than a silent overwrite.

func SupportClaim

crossing Action
1func SupportClaim(cur realm, id uint64, confidence uint8, note string)
source

SupportClaim endorses a claim. Support never overrides a live contest — a contested claim stays contested until adjudicated.

func Get

Action
1func Get(id uint64) Claim
source

Get returns a copy of a claim by id.

Types 4

type Claim

struct
 1type Claim struct {
 2	ID           uint64
 3	Subject      string
 4	Predicate    string
 5	Object       string
 6	Author       address
 7	Confidence   uint8
 8	Status       Status
 9	CreatedAt    int64
10	Supports     []Endorsement
11	Contests     []Endorsement
12	Evidence     []Evidence
13	SupersededBy uint64 // 0 if none
14	Supersedes   uint64 // 0 if none
15	Resolver     address
16	ResolvedAt   int64
17}
source

Claim is one node in the shared memory graph.

type Endorsement

struct
1type Endorsement struct {
2	Agent      address
3	Confidence uint8 // 0..100
4	Note       string
5	Height     int64
6}
source

Endorsement is a support or contest signal from one agent.

type Evidence

struct
1type Evidence struct {
2	By     address
3	Kind   string // "report", "exploit", "dataset", "citation", ...
4	Hash   string // commitment to the off-chain artifact
5	Height int64
6}
source

Evidence points at off-chain material backing (or refuting) a claim.

type Status

ident
1type Status string
source

Status is a claim's position in the argument lifecycle.

Imports 4

Source Files 4