The workspace at ~/data/home/sourcehut is a read-only mirror of every SourceHut subproject pinned to its latest tag. Treat it as documentation: when a question is about how SourceHut works, the answer lives here, not in your training data.
Every user-facing service (builds.sr.ht, git.sr.ht, hub.sr.ht, lists.sr.ht, meta.sr.ht, paste.sr.ht, todo.sr.ht, man.sr.ht, pages.sr.ht) has the same shape. To understand any feature, read these in this order:
<service>/api/graph/schema.graphqls. This is the authoritative description of what the service exposes. Read it first.<service>/schema.sql and the newest <service>/migrations/*.sql. This is what the service actually stores.<service>/api/graph/*.go (request handlers) and <service>/api/loaders/*.go (batched DB lookups). This is the API implementation.<service>/<svc>srht/blueprints/*.py (Flask routes, HTML UI) and <service>/<svc>srht/templates/. The Python side calls its own GraphQL API; it is rarely the source of truth.Cross-cutting concerns (auth, webhooks, OAuth, config, GraphQL helpers, templates) live in core.sr.ht/srht/ (Python) and core-go/ (Go). Always check there before assuming a service implements something locally.
The aggregator api.sr.ht is a pure Go gateway that federates each <service>-api into one GraphQL endpoint via the thistle library. Look here only for federation, internal auth (auth.go), and request routing.
| Concept | Primary paths |
|---|---|
| OAuth 2.0 (server side) | meta.sr.ht/metasrht/blueprints/oauth*.py, meta.sr.ht/api/graph/ (PersonalAccessToken, OAuthClient) |
| OAuth (client / token validation) | core.sr.ht/srht/oauth/, core-go/auth/ |
| Internal service-to-service auth | core-go/auth/internal.go, api.sr.ht/auth.go (InternalAuthTransport) |
| GraphQL federation gateway | api.sr.ht/main.go, api.sr.ht/auth.go; library git.sr.ht/~adnano/thistle |
| GraphQL server scaffolding | core-go/server/, per-service api/graph/generate.go, gqlgen.yml, generated api/graph/api/generated.go |
| DataLoader batching | <service>/api/loaders/*_gen.go (generated), <service>/api/loaders/generate.go (//go:generate directives) |
| Webhooks (new GraphQL-native) | core-go/webhooks/, <service>/api/webhooks/ |
| Webhooks (legacy HTTP) | core.sr.ht/srht/webhook/ |
| Build manifests / job lifecycle | builds.sr.ht/api/manifest.go, manifest_test.go, api/task.go; worker in builds.sr.ht/worker/ |
| Build images and shell | builds.sr.ht/images/, builds.sr.ht/builds.sr.ht-shell/ |
| Build job queue | builds.sr.ht/cmd/worker/, gocelery + Redis (see go.mod), worker/tasks.go |
| Git push/pull access control | git.sr.ht/gitsrht/, git.sr.ht/update-hook/, git.sr.ht/api/, sourcehut-ssh/dispatch/ |
| SSH dispatch (git/hg shells) | sourcehut-ssh/ (cmd/, dispatch/, shell/) |
| Mailing-list ingestion | lists.sr.ht/ingress/ (LMTP), lists.sr.ht/listssrht/ |
| Ticket-tracker LMTP | todo.sr.ht/todo.sr.ht-lmtp/ |
| Page hosting | pages.sr.ht/graph/, pages.sr.ht/cmd/, pages.sr.ht/account/ |
| Hub / project aggregation | hub.sr.ht/hubsrht/, hub.sr.ht/api/ |
| Config (INI loader) | core-go/config/config.go, core.sr.ht/srht/config.py; per-service config.example.ini |
| DB / migration tooling | core-go/database/, core.sr.ht/srht/database.py, <service>/schema.sql + migrations/ |
| Redis usage | core-go/redis/, core.sr.ht/srht/redis.py |
core-go/email/, core.sr.ht/srht/email.py |
|
| Shared SCSS / theme | core.sr.ht/scss/ (everything else's scss/main.scss imports from here) |
| nginx routing in production | sr.ht-nginx/*.conf |
| Kubernetes deployment | gensokyo/ (RBAC, ingress, monitoring, mirror) |
| Package builds | sr.ht-apkbuilds/ (Alpine), sr.ht-pkgbuilds/ (Arch) |
| Docs site (man.sr.ht content) | sr.ht-docs/ |
| Go client library | sourcehut-go/ |
| Marketing site | sourcehut.org/, srht.site/ |
| Performance benchmarks | forgeperf/ |
~/data/home/sourcehut/.claude/INDEX.md first if you have not already this session. It is auto-generated by sourcehut-refresh and lists, per service: current tag, every GraphQL type name, every SQL table name, every Python blueprint, every Go package, plus a cross-repo type map (which services define User, Mutation, OAuthClient, etc.). It is ~16 KB and answers "which service defines X?" without any grep. If INDEX.md is missing, run the sourcehut-refresh skill — it regenerates it as its final step.builds.sr.ht = CI, meta.sr.ht = accounts/OAuth, etc.). If it's a cross-cutting concern, start with core.sr.ht / core-go. For ambiguous symbol names, the cross-repo type map at the bottom of INDEX.md resolves it.rg scoped to the service directory rather than the whole workspace:
rg --type go 'symbol' ~/data/home/sourcehut/<service>/
rg --type py 'symbol' ~/data/home/sourcehut/<service>/<svc>srht/
User, Job, Token, etc. and you will drown in matches.api/graph/schema.graphqls. The GraphQL schema names line up with Go struct names in api/graph/model/ (auto-generated by gqlgen). The SQL table names usually line up too.<svc>srht/graphql/*.graphql, generated client in <svc>srht/graphql/__init__.py via ariadne-codegen). Inter-service Python calls go through <svc>srht/meta/*.graphql (the meta.sr.ht client).~/data/home/sourcehut/ so the user can click them.cat/head clutter context.sourcehut-refresh will destroy any local changes.paste.sr.ht, man.sr.ht, and pages.sr.ht are intentionally smaller and may lack things like webhooks or jobs.cmd/api exists, Python for the web UI, and Go for everything new (pages.sr.ht, sourcehut-ssh, api.sr.ht, forgeperf).If the user's question is about a recently-released feature (last few months), or your answer would depend on the exact tag in use, run the sourcehut-refresh skill before answering. Otherwise the current pinned tags are sufficient.