--- name: sourcehut-lookup description: Fast traversal of the SourceHut documentation mirror at ~/data/home/sourcehut. Use when the user asks how any SourceHut feature works (auth, webhooks, GraphQL, builds, OAuth, federation, jobs, ACLs, repos, lists, tickets, migrations, etc.) or asks to find/cite the canonical implementation of a SourceHut concept. --- # sourcehut-lookup 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. ## Mental model 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: 1. **The GraphQL contract** — `/api/graph/schema.graphqls`. This is the authoritative description of what the service exposes. Read it first. 2. **The SQL schema** — `/schema.sql` and the newest `/migrations/*.sql`. This is what the service actually stores. 3. **Go resolvers** — `/api/graph/*.go` (request handlers) and `/api/loaders/*.go` (batched DB lookups). This is *the* API implementation. 4. **Python web tier** — `/srht/blueprints/*.py` (Flask routes, HTML UI) and `/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 `-api` into one GraphQL endpoint via the `thistle` library. Look here only for federation, internal auth (`auth.go`), and request routing. ## Concept → where to look (search this map BEFORE grepping blind) | 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 | `/api/loaders/*_gen.go` (generated), `/api/loaders/generate.go` (`//go:generate` directives) | | Webhooks (new GraphQL-native) | `core-go/webhooks/`, `/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`, `/schema.sql` + `migrations/` | | Redis usage | `core-go/redis/`, `core.sr.ht/srht/redis.py` | | Email | `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/` | ## Workflow 0. **Read `~/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. 1. **Identify which service(s)** the question belongs to — usually obvious from the feature name (`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. 2. **Read the table above** for likely file paths. Read those files directly — do not grep first. 3. **For specifics inside a service**, prefer `rg` scoped to the service directory rather than the whole workspace: ```bash rg --type go 'symbol' ~/data/home/sourcehut// rg --type py 'symbol' ~/data/home/sourcehut//srht/ ``` Searching the entire workspace at once is almost always wrong — every service has its own `User`, `Job`, `Token`, etc. and you will drown in matches. 4. **For "where is type X defined?"** — start in `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. 5. **For "what calls X?"** — Python and Go sides do *not* call each other directly. Python web tier calls its own service's GraphQL API (queries are in `srht/graphql/*.graphql`, generated client in `srht/graphql/__init__.py` via `ariadne-codegen`). Inter-service Python calls go through `srht/meta/*.graphql` (the meta.sr.ht client). 6. **Cite file:line** in answers. Prefer absolute paths under `~/data/home/sourcehut/` so the user can click them. ## Anti-patterns to avoid - Do **not** use Bash to read files — use the Read tool. The workspace is large and `cat`/`head` clutter context. - Do **not** answer from training data when the file is right there. Tag versions move; your priors about SourceHut may be stale. Read the actual file. - Do **not** edit, commit, or branch in these clones. `sourcehut-refresh` will destroy any local changes. - Do **not** assume a feature exists in every service — `paste.sr.ht`, `man.sr.ht`, and `pages.sr.ht` are intentionally smaller and may lack things like webhooks or jobs. - Do **not** grep the workspace root for common identifiers. Scope to a service. - If unsure whether the canonical implementation is Python or Go: it is **Go** if a `cmd/api` exists, **Python** for the web UI, and **Go** for everything new (`pages.sr.ht`, `sourcehut-ssh`, `api.sr.ht`, `forgeperf`). ## When to refresh first 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.