The faithful chronicler of Pocket Network.
A Go-native indexer for Pocket Network's Shannon protocol. Stream-first ingestion via ABCI FilePlugin, append-only state snapshots with chain-as-source-of-truth, version-aware decoders, and bucket-sealed analytics. Built for owned infrastructure. No cloud lock-in.
Slice 1 complete (2026-06-11). cmd/ps ships with fileplugin, consumer block, consumer supplier, sync-upgrades, and reconciler subcommands. The multi-version decoder library covers all 31 mainnet-applied protocol versions, the BatchRuntime orchestration framework (ADR-024 triggers 1β3) is in place, 27 spec test scenarios are green, and make ci-full passes the 100%/90% coverage gate. See the Slice 1 spec for the full scope and exit criteria.
Visual overview: docs/architecture/00-system-flow.md β 4 mermaid diagrams covering live ingestion, schema generation pipeline, decoder routing, and archeology substrate.
What exists today: production Go runtime + skills + schema + archeology. See STATUS.md for the precise breakdown.
| Past pain (legacy indexers) | PocketScribe answer |
|---|---|
| Single-thread / per-block tx (Node.js) | Native Go, per-module consumers, parallel processing |
| Math bugs causing accumulated drift | Snapshots from chain β never computed locally |
| Reindex = days of downtime | Append-only history + per-module reindex in minutes |
| Silent indexer/chain drift | Reconciler with bulk gRPC comparison + auto-heal |
| Replication pain on legacy analytics DBs | Postgres + TimescaleDB OSS, single DB |
| Subscriptions tied to write primary | NATS WebSocket bridge; queries hit replicas |
| Schema changes = full rewrite | Versioned proto decoders per upgrade height |
- Language: Go 1.26+
- Chain: poktroll (Cosmos SDK v0.53.0 + CometBFT fork)
- Ingestion: official Cosmos SDK ABCI
FilePlugin - Bus: NATS JetStream 2.10+ (3-replica cluster, file storage)
- Storage: PostgreSQL 18+ with TimescaleDB OSS 2.18+
- Migrations: goose
- Codegen: buf (protos), sqlc (queries)
- DB driver: pgx v5
- Local dev: Tilt + kind/k3d
- Testing: testcontainers-go + sebdah/goldie/v2
- CLI: cobra + viper, single
psbinary with subcommands
poktroll archive node (no-prune)
β official Cosmos SDK FilePlugin
βΌ
/var/lib/poktroll/streaming/block-{H}-data + block-{H}-meta
β ps fileplugin (sidecar)
βΌ
NATS JetStream (3 replicas, dedup by Msg-Id, file storage)
β
ββββΊ ps consumer supplier βββ
ββββΊ ps consumer application β€
ββββΊ ps consumer gateway β€βββΊ PostgreSQL 18 + TimescaleDB
ββββΊ ps consumer tokenomics β ββ entity history (append-only)
β ββ event hypertables (time-series)
ββββΊ ps sealing ββββββββββββββΊ continuous aggregates
(bucket-sealed, gap-aware)
ps reconciler ββββΊ periodic bulk gRPC list βββΊ drift detection + auto-heal
Downstream (NOT part of PocketScribe):
ββββΊ Hasura β GraphQL
ββββΊ PostgREST β REST + OpenAPI
ββββΊ NATS WS bridge β real-time push
Full design in docs/architecture/.
Single binary ps, cobra subcommands:
# Long-running services
ps fileplugin # sidecar: tails FilePlugin dir β NATS
ps consumer <module> # run one module consumer
ps indexer # run all enabled consumers in one process
ps reconciler # periodic drift detection
ps sealing # bucket sealing loop
# Admin
ps migrate up | down | status
ps inspect streams | cursors | seals
ps replay --module=X --from=H1 --to=H2
ps backfill --from-genesis
ps reconcile --module=X
ps doctor # health check: DB, NATS, node
ps versionFull CLI in docs/architecture/02-ingestion.md and CLAUDE.md.
- Go 1.26+ (
go version) - Docker (with at least 8 GB RAM allocated)
- kind (
kind version) β installs viago install sigs.k8s.io/kind@latest - Tilt (
tilt version) β see https://docs.tilt.dev/install.html - kubectl (
kubectl version --client) - golangci-lint v2+ (
golangci-lint --version) β install:go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest - goose (
goose --version) β install:go install github.com/pressly/goose/v3/cmd/goose@latest
make cluster-up # one-time per session: create the kind cluster
tilt up # brings up postgres + nats; applies migrations
# press space in the terminal to open the Tilt UI;
# ctrl-C stops it (resources keep running)
# When done:
tilt down # remove the deployed resources (cluster stays)
make cluster-down # delete the kind cluster entirelymake cluster-up is idempotent β re-running it is a no-op if the cluster already exists.
After tilt up shows all resources green:
- Postgres reachable at
localhost:5432(userpocketscribe, passworddev_only_password, dbpocketscribe). - NATS reachable at
localhost:4222(client) andlocalhost:8222(monitor). - The
pocketscribedatabase has the full 244-table schema applied via goose.
make ci # vet + fmt-check + lint + lint-integration + test-race (fast, no containers)
make ci-full # ci + integration tests + coverage gate (100% decoders / β₯90% internal/)
make coverage # combined unit+integration coverage with per-package gate
make fmt # apply gofmt to the treetilt down
tilt up # fresh start; migrations re-run automaticallyOr for a full reset (incl. the cluster itself):
make cluster-down
make cluster-up
tilt upCLAUDE.mdβ operating rules for Claude Code working on this repo (also valuable for humans)docs/architecture/β full system design (12 documents)docs/decisions/β ADRs for every major calldocs/operations/β deployment, monitoring, runbooksdocs/research/β focused technical researchROADMAP.mdβ phased plan from spike to productionCONTRIBUTING.mdβ how to add module / aggregate / version
- Every row carries
(block_height, block_time)from the chain header. Never indexer write time. - State entities are append-only. No
UPDATE. Novalid_to_*. Ranges viaLEAD(). - The chain is the source of truth. We never compute state β we mirror it.
- Ack NATS messages after Postgres commit. Never before.
- No cloud-managed services. No Node.js framework indexers.
- Test-driven by default. DRY across the codebase.
- Local dev runs in Kubernetes (kind/k3d) via Tilt β same as production.
Full rules + rationale: CLAUDE.md.
TBD (likely MIT or Apache-2.0 to match the broader Pocket ecosystem).