This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This directory is a read-only documentation mirror, not a development workspace. It exists to let Claude inspect the current state of every SourceHut service in one place when answering questions about how SourceHut works.
The set of repos is discovered by scraping the upstream source listing pages:
https://sr.ht/~sircmpwn/sourcehut/sourceshttps://sr.ht/~sircmpwn/sourcehut/sources?page=2 (and additional pages if they exist)This workspace is itself a git superproject: every cloned subproject is a submodule pinned to a specific commit (typically the latest upstream tag), tracked in .gitmodules. Use the sourcehut-refresh skill to re-discover upstream and bump submodules; use sourcehut-lookup for fast cross-repo documentation traversal. A refresh leaves submodule pointer bumps uncommitted so the user can review and commit one snapshot at a time.
Submodules' .git directories are absorbed into .git/modules/<name>/ of the superproject. Each clone's worktree contains a .git file (gitlink), not a directory — do not be confused by this.
A pre-built inventory lives at .claude/INDEX.md — per-service GraphQL types, SQL tables, Python blueprints, Go packages, plus a cross-repo type map. Regenerated automatically by sourcehut-refresh; the sourcehut-lookup skill reads it first to skip a lot of grepping.
The user runs a patched SourceHut in production under ~/data/home/phoebe-lab/srht/. Fixes not yet upstreamed are mirrored here in patches/ for reference — they are not applied to the clones in this workspace. When answering questions about behavior that might diverge from upstream, check patches/README.md first. Currently tracked:
patches/core-go-checksum.patch — disables AWS SDK v2 default request/response checksum calculation in core-go/objects/middleware.go NewClient. Upstream defaults break streaming PutObject (pages publish, builds artifact upload) on non-AWS S3 backends.Do not commit, push, or develop in these clones — they will be wiped/replaced by the next refresh. If you need to make changes, clone the upstream repo separately.
This is not a single repo — it is a workspace of ~28 sibling clones of upstream SourceHut subprojects (https://git.sr.ht/~sircmpwn/<name>). Each subdirectory is an independent git repo with its own LICENSE, build, and history. Always cd into the specific subproject before running per-repo commands.
SourceHut is a federation of services that share a common architecture. Categorize a repo by inspecting its top level:
api/, *srht/, Makefile, run.py, schema.sql, migrations/, pyproject.toml, go.mod):
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.
Python Flask app (<name>srht/app.py) serves the user-facing web UI; Go binary (cmd/api → <service>-api) serves the GraphQL API. builds.sr.ht additionally has cmd/worker → builds.sr.ht-worker (job runner using Celery via gocelery, Redis, and builds.sr.ht-shell).api.sr.ht (the federated GraphQL gateway built on git.sr.ht/~adnano/thistle), sourcehut-ssh (SSH dispatch for git/hg shells), pages.sr.ht (newer version, Go-only).core.sr.ht (Python — srht package: ORM, OAuth, GraphQL helpers, templates, SCSS/Bootstrap assets) and core-go (Go equivalent: auth, client, config, database, redis, server, webhooks, crypto).sourcehut.org and srht.site (Hugo), sr.ht-docs (man.sr.ht content), git-am.io, git-rebase.io, git-send-email.io.gensokyo (Kubernetes YAML for the production cluster), sr.ht-nginx (nginx configs), sr.ht-apkbuilds / sr.ht-pkgbuilds (Alpine/Arch packaging), sourcehut-migrate (data migration tooling), status.sr.ht, go-away-config.sourcehut-go (Go client library and CLI examples), forgeperf (forge performance benchmark harness using Chromium+Lighthouse), hut (third-party CLI client for SourceHut from ~xenrox — not part of the ~sircmpwn umbrella but the de-facto CLI users reach for; covers builds/git/lists/meta/paste/pages/todo/hub via the GraphQL APIs).Each service that builds has a top-level Makefile. The hybrid Python+Go services follow a uniform pattern (driven by core.sr.ht's Makefile conventions):
make # default: all-bin all-share all-python
make all-bin # Go binaries: <service>-api, <service>-worker (if present)
make all-share # compile SCSS via sassc → static/main.min.css
make all-python # generate buildsrht/graphql/__init__.py via ariadne-codegen
make install # install to $(PREFIX)=/usr/local
make clean
Toolchain prerequisites (vary by service):
1.16 (older repos like api.sr.ht) to 1.22+ with toolchain go1.24.0 (newer repos like builds.sr.ht).srht package from core.sr.ht installed (editable or via system package). Production uses pip install -e . after pip install -e ../core.sr.ht.sassc (or set SASSC), minify, ariadne-codegen (Python package, used to generate GraphQL client stubs from *.graphql queries).gqlgen (Go) — cd api && go generate ./graph (uses gqlgen.yml, reads api/graph/schema.graphqls, writes api/graph/api/generated.go).dataloaden — cd api && go generate ./loaders (the api/loaders/gen shell helper + directives in generate.go).sourcehut-buildver / sourcehut-builddate (installed from core.sr.ht) and are injected via -ldflags into core-go/server.BuildVersion/BuildDate.For Python web tier: python3 run.py (calls srht.debug.run_service(app)). For the Go API: ./<service>-api after make. Both read config.ini (copy from config.example.ini).
Each service ships its full schema.sql plus incremental migrations/*.sql. Tests/dev use Postgres; Redis is required for job queues, GraphQL pubsub, and webhooks. lists.sr.ht additionally has an ingress/ (LMTP) component; todo.sr.ht has todo.sr.ht-lmtp.
builds.sr.ht/api/manifest_test.go shows the Go test convention — standard go test ./... from inside each service's repo. There is no top-level "run all tests" target across the workspace; each repo is tested independently.
api/graph/schema.graphqls; clients (the Python web tier of the same service, the federated gateway api.sr.ht, and the Python web tiers of other services) consume it. Python clients are generated under <svc>srht/graphql/ and <svc>srht/meta/ via ariadne-codegen. Go resolvers live under api/graph/, with batched lookups in api/loaders/.api.sr.ht is the federation layer. It uses thistle to merge per-service schemas into one endpoint and forwards requests to each <service>-api based on the type. InternalAuthTransport in api.sr.ht/auth.go is how it elevates calls when needed.meta.sr.ht as the IdP. core-go/auth and core.sr.ht/srht/oauth are the canonical client implementations — every other service depends on one of them. Internal service-to-service calls use the "internal user" with HMAC-signed headers (core-go/auth/internal.go).core-go/webhooks defines the worker; each service registers concrete event subscriptions in api/webhooks/.core.sr.ht/scss/ provides the shared bootstrap-derived theme; each service has its own scss/main.scss that imports it. The Makefile compiles to a hashed main.min.<sha>.css for cache busting..builds/ directory (if present) and run on builds.sr.ht — see the sourcehut-ci skill for authoring rules.Upstream is hosted at git.sr.ht/~sircmpwn/<name>. Patches go to the sr.ht-dev mailing list via git send-email. This workspace is a read-only mirror — do not commit, push, or develop here. To contribute, clone the upstream repo independently outside this workspace.
make from the workspace root does nothing useful — there is no top-level Makefile. Always work inside a single subproject.git.sr.ht/~sircmpwn/core-go from upstream tags; do not add a replace directive to point at the local ./core-go clone unless explicitly working on a coordinated change, since the local clone is pinned to a tag that may not match what the service expects.api.sr.ht, possibly older clones). Use the toolchain declared in each go.mod.gensokyo uses the Go-based yq (github.com/mikefarah/yq), not the Python one — they are not interchangeable.forgeperf is an offline benchmark harness, not a service — it needs Chromium, an X server, and lighthouse via npm to run.