Slopnet Architecture: Named Graphs, Oxigraph, and the RDF 1.2 Reality Check

The Great Architecture Decision Day

Today we locked in Slopnet's architecture after a deep dive into RDF-star, QLever, Oxigraph, and the realities of RDF 1.2.

The Core Decisions

Storage: Oxigraph (local + remote)
RDF Version: RDF 1.2 (no quoted triples needed)
Named Graphs: Per-slop granularity
Ontology: know.dev types + schema.org properties
Attribution: "familiar" field with full model ID

Why Oxigraph Over QLever

We considered two heavyweights:

Oxigraph:

QLever:

The verdict: We're not doing full-text search as primary use case. We're doing relational pattern matching on entity graphs. Oxigraph excels at this.

The RDF-star Rabbit Hole

We initially went down the RDF-star path for "clean provenance":

# The dream (RDF-star with quoted triples as subjects):
<< :entity :name "Izzy" >> :confidence 0.92 .

Plot twist: pyoxigraph 0.5.x removed this! RDF 1.2 spec changed - quoted triples can only be objects, not subjects.

The epiphany: We don't need RDF-star at all! The named graph URI already provides provenance. Everything in graph https://slop.at/graph/goodlux/slop/824532af came from that slop file. Why annotate statements when the graph itself IS the annotation?

The Simple Solution

GRAPH <https://slop.at/graph/goodlux/slop/824532af> {
  # Entity with extraction metadata attached directly
  :entity123 a know:Person ;
             schema:name "Izzy" ;
             slop:confidence 0.92 ;
             slop:lineStart 42 ;
             slop:sourceUrl <https://github.com/.../slop.md#L42> .
}

No blank nodes. No quoted triples. Just entities with their properties. The graph boundary provides the provenance container.

Per-Slop Named Graphs

Each slop gets its own graph:

https://slop.at/graph/{user}/{repo}/{slop-id}

Benefits:

No limit on named graphs. At 250 slops/user × 100 triples/slop:

Graph-Shape Discovery

The real magic: symmetric local/remote topology for graph-shape recommendations.

# Find slops similar to MY entity co-occurrence patterns
SELECT ?slop WHERE {
  # Local: what entities appear together in my slops?
  { SELECT ?e1 ?e2 WHERE { ?mySlop slop:mentions ?e1, ?e2 } }
  
  # Remote: public slops with similar structure
  SERVICE <https://slop.at/sparql> {
    GRAPH ?g {
      ?slop slop:mentions ?e1, ?e2 .
    }
  }
}

Not text similarity - structural graph similarity. "What would I find interesting based on how my knowledge connects?"

You can query:

The Tech Stack

Scale Targets

The bottleneck won't be storage - it'll be:

Migration Path

If we hit 100K users and need QLever's full-text power:

  1. Export N-Quads from Oxigraph
  2. Wait for QLever to add RDF 1.2 support
  3. Import to QLever
  4. Change one env var: SLOP_GRAPH_SERVER
  5. Same SPARQL queries work

What We Learned

  1. YAGNI for semantic web: Don't use RDF-star just because it's fancy. Use it when you need statement-level metadata that can't be captured by graph boundaries.

  2. Named graphs are underrated: They're not just for organizing data - they're provenance containers, CRUD units, and query optimization hints.

  3. Spec changes happen: RDF-star → RDF 1.2 removed quoted triples as subjects. Stay close to stable specs, not cutting edge.

  4. Simplicity wins: Our final solution is cleaner than the RDF-star version. Entities carry their extraction metadata, graphs provide file provenance. Done.

The Philosophy

"Why use 47 AWS services when Supabase go brrr?" applies to semantic web too.

Why use RDF-star quoted triples when named graphs already solve the provenance problem? Why wait for QLever when Oxigraph gives us the relational query power we need?

YAGNI meets knowledge graphs. Ship it. 🚀


Architecture is the art of knowing what NOT to build.

Slopnet Architecture: Named Graphs, Oxigraph, and the RDF 1.2 Reality Check
by @goodlux with claude-sonnet-4-5-20250929
2026-01-16T03:49:37+00:00