Subgraph (Indexing Layer)¶
This document explains what Sage's subgraph does, why it exists, and what contributors need to know when protocol features change. It's a mental model for coding agents and developers.
For the schema itself, see subgraph/schema.graphql in the monorepo. For endpoint and deployment source-of-truth guidance, see Deployment Addresses and Sources.
What the Subgraph Does¶
The subgraph indexes on-chain events into a queryable dataset so the rest of the system can do fast reads without expensive chain scans. Without it, every governance query, library lookup, and discovery request would require scanning blocks — which is slow, rate-limited, and expensive on Base.
In Sage, the subgraph powers:
- Governance UX: proposals, votes, delegations
- DAO metadata: SubDAO creation and configuration
- Library provenance: "what is the latest manifest CID for DAO X?"
- Prompt registries: prompt metadata and update events
- Personal/premium commerce: listings, purchases, receipts
- Author reputation: badge mints for achievements via SoulboundBadge
Who Depends on It (and Why)¶
Web App¶
The web app uses the subgraph for governance visibility and "chain state" views. Subgraph reads are proxied under packages/sage-web-app/src/app/api/subgraph/*. Without the subgraph, the governance UI would need to fall back to direct RPC calls — much slower and more expensive.
IPFS Worker¶
The worker uses the subgraph as an indexer input to populate KV caches for hot paths: latest manifest CID resolution, discovery indexes, and any read-time guards that must be fast. The design rule is: avoid chain RPC in the worker on install/search hot paths. Instead, rely on subgraph → KV for freshness.
CLI¶
The CLI is primarily a write surface. For read operations (governance queries, proposals, tips, bounties), the CLI calls the Worker's REST API — not the subgraph directly. The Worker proxies and caches subgraph data. If CLI code sends raw GraphQL to a subgraph endpoint, that is a regression.
Freshness Model¶
The subgraph is eventually consistent with the chain. There is always a propagation delay — often minutes — between "transaction mined" and "visible in the subgraph." This delay cascades through the system: the worker's KV caches lag behind the subgraph, and discovery/install surfaces lag behind the KV caches.
User-facing UX should communicate this: "your proposal was submitted" is immediate (transaction confirmed), but "your new library version is discoverable" may take minutes. Systems should not try to shortcut around this delay — it's a fundamental property of the eventual consistency model.
The Template-Based Build System¶
A key design decision: addresses are not hardcoded in the subgraph YAML. Instead:
subgraph.template.yamldefines data sources with placeholder addressesnetworks.jsonmaps data source names to per-network addresses and startBlocksgraph build --network <name> --network-file networks.jsoninjects values at build time
This eliminates manual YAML patching when contract addresses change (which happens on every fresh deployment). It also means the build script (build.sh) can sync addresses directly from the deployment output.
ABI Compatibility (Important Gotcha)¶
Some subgraph ABIs are hand-crafted event-only files that intentionally don't match the latest compiled contracts. When contracts evolve (add indexed params, change signatures), the subgraph handlers still reference the original event signatures emitted by deployed contracts.
Do not blindly sync all ABIs from forge output. The following ABIs are hand-crafted: GovernanceHelper, FederatedTreasuryManagerV2, PersonalMarketplace, SimpleBountySystem, PromptRegistry, SubDAOEvents.
What Needs Updating When Features Change¶
If you add a feature that needs new indexed data:
- Contracts: Ensure the data is emitted in events (or otherwise indexable)
- Subgraph: Update
subgraph/schema.graphql,subgraph/subgraph.template.yaml, andsubgraph/src/* - Consumers: Update worker/web/CLI code that reads the new entities
Examples: new library metadata surfaced in the UI → subgraph schema + mapping update. Worker needs to decide "public vs encrypted" quickly → index into subgraph, then cache in KV.
Environment Variables¶
Subgraph URLs are injected via env vars. Only the Worker and web app should reference subgraph URLs directly. The CLI should use the Worker's REST API via SAGE_API_URL.
- Worker:
SUBGRAPH_URL(Goldsky endpoint, internal to the Worker) - Web app:
NEXT_PUBLIC_GRAPH_ENDPOINT,NEXT_PUBLIC_SUBGRAPH_URL - CLI:
SAGE_API_URL(points to the Worker REST API, NOT a subgraph) - Graph Studio auth:
GRAPH_ACCESS_TOKEN/GRAPH_API_KEY
How This Connects¶
- Architecture — Where the subgraph fits in the system model
- Worker — The materialization layer that consumes subgraph data
- Governance — How governance events flow through the subgraph
- Data Access Architecture — Client read-path invariants