{"families":[{"caution":"`go/comms` and `go/comms-discord` (formerly chat-platform) are NOT in this family despite the old name: comms is messaging-platform integration and its go.mod does not require go/chat. Grouping by name put them in the wrong train.","core":{"module":"gitlab.com/phpboyscout/go/chat","path":"phpboyscout/go/chat"},"derived_from":"go.mod requires on gitlab.com/phpboyscout/go/chat","ecosystem":"go","members":["phpboyscout/go/chat-anthropic","phpboyscout/go/chat-gemini","phpboyscout/go/chat-openai","phpboyscout/go/chat-openai-azure","phpboyscout/go/chat-bedrock","phpboyscout/go/chat-mcptools"],"name":"chat","summary":"LLM provider abstraction and the per-provider adapters."},{"caution":"Membership is nearly the whole estate and changes constantly, so it is deliberately not enumerated. Enumerate on demand by scanning .gitlab-ci.yml for `phpboyscout/cicd/\u003cname\u003e@`.","core":{"module":null,"path":"phpboyscout/cicd"},"derived_from":"`include: component:` URLs in each consumer's .gitlab-ci.yml. NOT derivable by release-train.","ecosystem":"component","name":"cicd-components","summary":"The reusable CI/CD component monorepo and everything that includes it."},{"caution":"Renamed from chat-platform on 2026-10-04 to separate it from the LLM `chat` family; the core moved to gitlab.com/phpboyscout/go/comms at v0.31.0 and the Discord provider to gitlab.com/phpboyscout/go/comms-discord at v0.30.0. Independent of `chat` in both directions.","core":{"module":"gitlab.com/phpboyscout/go/comms","path":"phpboyscout/go/comms"},"derived_from":"go.mod requires on gitlab.com/phpboyscout/go/comms","ecosystem":"go","members":["phpboyscout/go/comms-discord"],"name":"comms","summary":"Messaging-platform integration (Discord now, Slack and Teams to come) and its per-platform adapters."},{"caution":"The largest family, and NOT a star. Some adapters depend on other adapters, so they form their own tier below the core. Derive the order; do not assume one core plus N independent leaves.","core":{"module":"gitlab.com/phpboyscout/go/config","path":"phpboyscout/go/config"},"derived_from":"go.mod requires on gitlab.com/phpboyscout/go/config","ecosystem":"go","members":["phpboyscout/go/config-schema","phpboyscout/go/config-json","phpboyscout/go/config-toml","phpboyscout/go/config-hcl","phpboyscout/go/config-xml","phpboyscout/go/config-dotenv","phpboyscout/go/config-ini","phpboyscout/go/config-properties","phpboyscout/go/config-afero","phpboyscout/go/config-iofs","phpboyscout/go/config-billy","phpboyscout/go/config-sftp","phpboyscout/go/config-filekv","phpboyscout/go/config-aws-s3","phpboyscout/go/config-gcp-gcs","phpboyscout/go/config-azure-blob","phpboyscout/go/config-consul","phpboyscout/go/config-etcd","phpboyscout/go/config-aws-ssm","phpboyscout/go/config-azure-appconfig","phpboyscout/go/config-gcp-parameter","phpboyscout/go/config-vault","phpboyscout/go/config-aws-secrets","phpboyscout/go/config-azure-keyvault","phpboyscout/go/config-keychain","phpboyscout/go/config-gcp-secret"],"name":"config","summary":"Configuration loader and its 26 source/format adapters."},{"core":{"module":"gitlab.com/phpboyscout/go/encryption","path":"phpboyscout/go/encryption"},"derived_from":"go.mod requires on gitlab.com/phpboyscout/go/encryption","ecosystem":"go","members":["phpboyscout/go/encryption-aws-kms"],"name":"encryption","summary":"Encryption abstraction and its backends."},{"caution":"All four adapters pin the core, so the core releases first or every adapter tags twice. This is the textbook case for `release-train`.","core":{"module":"gitlab.com/phpboyscout/go/forge","path":"phpboyscout/go/forge"},"derived_from":"go.mod requires on gitlab.com/phpboyscout/go/forge","ecosystem":"go","members":["phpboyscout/go/forge-github","phpboyscout/go/forge-gitlab","phpboyscout/go/forge-gitea","phpboyscout/go/forge-bitbucket"],"name":"forge","summary":"Git forge abstraction and the per-forge adapters."},{"caution":"The widest blast radius in the estate — a go-tool-base tag reaches every tool. The members are also end-user products with their own maintainers, so a train here needs more than one person's agreement.","core":{"module":"gitlab.com/phpboyscout/go-tool-base","path":"phpboyscout/go-tool-base"},"derived_from":"go.mod requires on gitlab.com/phpboyscout/go-tool-base","ecosystem":"go","members":["phpboyscout/keryx","phpboyscout/krites","phpboyscout/sigillum","phpboyscout/skillup","phpboyscout/phpbotscout"],"name":"gtb","summary":"The Go tool framework and the CLI tools built on it."},{"caution":"THE CORE AND THE COORDINATOR ARE DIFFERENT REPOS HERE, and that is the trap. `ci-base` is what the images are built FROM. `cicd` is where their pins live, and no consumer ever references an image directly — they take a cicd component version, which carries the image reference inside it. So the release flows ci-base -\u003e the derived images -\u003e a cicd pin bump -\u003e consumers, and cicd is LAST in that order while being the repo through which the whole family is actually driven. Treating cicd as an upstream core sends you up the chain backwards. Two more. (1) These repos' product IS their pinned base and package set, so every change arrives from Renovate as `chore(deps)`, which releases nothing — see cicd#25. (2) A toolchain bump here moves every consumer's compiler and standard library regardless of what their manifests declare. playwright-tools derives from node-tools, not ci-base directly.","coordinated_by":"phpboyscout/cicd","core":{"module":null,"path":"phpboyscout/images/ci-base"},"derived_from":"Dockerfile FROM lines. NOT derivable by release-train, which reads go.mod only — this family has to be written down.","ecosystem":"image","members":["phpboyscout/images/go-tools","phpboyscout/images/rust-tools","phpboyscout/images/node-tools","phpboyscout/images/tofu-tools","phpboyscout/images/docs-tools","phpboyscout/images/playwright-tools","phpboyscout/images/release-tools"],"name":"images","summary":"The CI toolchain images. ci-base is the root; the rest derive from it."},{"core":{"module":"gitlab.com/phpboyscout/go/messaging","path":"phpboyscout/go/messaging"},"derived_from":"go.mod requires on gitlab.com/phpboyscout/go/messaging","ecosystem":"go","members":["phpboyscout/go/messaging-nats","phpboyscout/go/messaging-sqs","phpboyscout/go/messaging-rabbitmq","phpboyscout/go/messaging-amqp"],"name":"messaging","summary":"The message bus and its per-broker backends."},{"core":{"module":"gitlab.com/phpboyscout/go/signing","path":"phpboyscout/go/signing"},"derived_from":"go.mod requires on gitlab.com/phpboyscout/go/signing","ecosystem":"go","members":["phpboyscout/go/signing-aws-kms","phpboyscout/go/signing-cli"],"name":"signing","summary":"Artefact signing and its backends."},{"core":{"module":"gitlab.com/phpboyscout/go/transport","path":"phpboyscout/go/transport"},"derived_from":"go.mod requires on gitlab.com/phpboyscout/go/transport","ecosystem":"go","members":["phpboyscout/go/transport-openapi","phpboyscout/go/transport-metrics"],"name":"transport","summary":"Transport abstraction and its adapters."}],"generated_at":"2026-10-06T01:37:57Z","pairs":[{"caution":"A CHANGE TO ffmpeg-wasi IS ONLY OBSERVABLE TO THE OTHER TWO AFTER A RELEASE, because both reach it by release tag rather than by source. So smoke-test a candidate against a real consumer BEFORE the tag, not after: the two worst defects found on 2026-08-23 surfaced that way and would not have appeared in any of the three test suites. All three have their own sessions. Ask before assuming any is unattended, and most of all keryx, which is genuinely someone else's rather than the other half of a pair.","derived_from":"Stated by the maintaining sessions. Only PARTLY visible in manifests: keryx requires afmpeg through go.mod, but afmpeg's go.mod requires only go/errors and go/signing and has no edge to ffmpeg-wasi at all. afmpeg fetches ffmpeg-wasi's signed driver and wasm module at runtime, pinned by release tag, and keryx pins ffmpeg-wasi's tag directly as `defaultReleaseTag`. Those two edges are over built artefacts, which no dependency tool reads.","handle":"afmpeg-ffmpeg-wasi-keryx","name":"afmpeg + ffmpeg-wasi + keryx","repositories":["phpboyscout/keryx","phpboyscout/afmpeg","phpboyscout/ffmpeg-wasi"],"summary":"The WASI ffmpeg build, the Go wrapper that drives it, and the tool that pins both. Worked across all three together, because a defect in the engine surfaces in the consumer."}],"products":[{"display":{"kind":"Blog","language":"Hugo","name":"PHP Boy Scout blog","site":"https://phpboyscout.uk","summary":"This site: the home for the project write-ups, leadership pieces, tutorials and the occasional personal essay."}},{"display":{"kind":"Business site","language":"Hugo","name":"The Dusthole","site":"https://thedusthole.co.uk","summary":"A bespoke site for my dad's 15th-century coaching inn and bed and breakfast in Shepton Mallet."}},{"display":{"kind":"Photography / recipes","language":"Hugo","name":"Shutter \u0026 Stove","site":"https://shutterandstove.uk","summary":"Hailey's vanlife photography and galley-kitchen cooking site, built ahead of the 2027 trip so the shape exists before the content does."}},{"display":{"kind":"Tabletop tool","language":"Go / Svelte","name":"Scout.DM","site":"https://scoutdm.com","summary":"A co-DM that rides ahead of the table, holding the minutia (the barkeep's name, the eight market stalls, what each character actually knows) so the DM can hold the narrative. It never speaks to the table, and it never rolls the players' dice."}}],"repositories":[{"display":{"docs":"https://gtb.phpboyscout.uk","kind":"Framework","language":"Go","name":"go-tool-base"},"family":"gtb","listed":true,"modules":["gitlab.com/phpboyscout/go-tool-base","gitlab.com/phpboyscout/go-tool-base/cli"],"path":"phpboyscout/go-tool-base","role":"core"},{"display":{"docs":"https://rtb.phpboyscout.uk","kind":"Framework","language":"Rust","name":"rust-tool-base"},"listed":true,"modules":["rtb-cli-bin"],"path":"phpboyscout/rust-tool-base"},{"display":{"docs":"https://config.go.phpboyscout.uk","kind":"Configuration store","language":"Go","name":"config","summary":"A layered configuration store: read from files, the environment, flags and remote backends, ask where any value came from, and write a change back without wrecking the file. Rewritten off Viper to own config I/O end to end."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config"],"path":"phpboyscout/go/config","role":"core"},{"display":{"kind":"Validation","language":"Go","name":"config-schema","summary":"JSON Schema validation over a layered store: compose partial schemas per section, and get each failure attributed back to the layer that supplied the offending value."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-schema"],"path":"phpboyscout/go/config-schema","role":"member"},{"display":{"kind":"Codec","language":"Go","name":"config-json","summary":"Read and write JSON and JSON Lines, preserving the document's structure on write."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-json"],"path":"phpboyscout/go/config-json","role":"member"},{"display":{"kind":"Codec","language":"Go","name":"config-toml","summary":"Read and write TOML, structure-preserving."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-toml"],"path":"phpboyscout/go/config-toml","role":"member"},{"display":{"kind":"Codec","language":"Go","name":"config-hcl","summary":"Read and write HCL, treating it as a configuration format in its own right, not Terraform."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-hcl"],"path":"phpboyscout/go/config-hcl","role":"member"},{"display":{"kind":"Codec","language":"Go","name":"config-xml","summary":"Read XML over the standard library alone, with no added dependency."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-xml"],"path":"phpboyscout/go/config-xml","role":"member"},{"display":{"kind":"Codec","language":"Go","name":"config-dotenv","summary":"Read dotenv (.env) configuration, read-only with no added dependency."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-dotenv"],"path":"phpboyscout/go/config-dotenv","role":"member"},{"display":{"kind":"Codec","language":"Go","name":"config-ini","summary":"Read INI configuration, read-only with no added dependency."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-ini"],"path":"phpboyscout/go/config-ini","role":"member"},{"display":{"kind":"Codec","language":"Go","name":"config-properties","summary":"Read Java .properties configuration, read-only with no added dependency."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-properties"],"path":"phpboyscout/go/config-properties","role":"member"},{"display":{"kind":"Filesystem","language":"Go","name":"config-afero","summary":"Bridge an afero filesystem a consumer already holds to config's own FS interface."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-afero"],"path":"phpboyscout/go/config-afero","role":"member"},{"display":{"kind":"Filesystem","language":"Go","name":"config-iofs","summary":"Read config from any io/fs.FS, including an embed.FS compiled into the binary. Read-only, as io/fs is."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-iofs"],"path":"phpboyscout/go/config-iofs","role":"member"},{"display":{"kind":"Filesystem","language":"Go","name":"config-billy","summary":"Read and write config through a go-billy filesystem a tool already uses."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-billy"],"path":"phpboyscout/go/config-billy","role":"member"},{"display":{"kind":"Filesystem","language":"Go","name":"config-sftp","summary":"Read and write config on a remote host over SFTP, staged and renamed over so a reader never sees a half-written file."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-sftp"],"path":"phpboyscout/go/config-sftp","role":"member"},{"display":{"kind":"Filesystem","language":"Go","name":"config-filekv","summary":"Treat a directory of single-value files as a config layer, where each filename is a key and its contents are the value. The shape Kubernetes secrets and Docker secrets already mount."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-filekv"],"path":"phpboyscout/go/config-filekv","role":"member"},{"display":{"kind":"Filesystem","language":"Go","name":"config-aws-s3","summary":"Read and write a config file that lives in an AWS S3 bucket, staged and renamed over for an atomic commit."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-aws-s3"],"path":"phpboyscout/go/config-aws-s3","role":"member"},{"display":{"kind":"Filesystem","language":"Go","name":"config-gcp-gcs","summary":"Read and write a config file in a Google Cloud Storage bucket, atomic per object."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-gcp-gcs"],"path":"phpboyscout/go/config-gcp-gcs","role":"member"},{"display":{"kind":"Filesystem","language":"Go","name":"config-azure-blob","summary":"Read and write a config file in an Azure Blob container, through the same stage-and-rename machinery a local file uses."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-azure-blob"],"path":"phpboyscout/go/config-azure-blob","role":"member"},{"display":{"kind":"Backend","language":"Go","name":"config-consul","summary":"Read and write HashiCorp Consul, with structure-preserving compare-and-swap writes."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-consul"],"path":"phpboyscout/go/config-consul","role":"member"},{"display":{"kind":"Backend","language":"Go","name":"config-etcd","summary":"A prefix of an etcd v3 cluster as a layer, with real compare-and-swap writes and a real change feed behind hot reload. Keys split on the separator into the tree, with the prefix stripped."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-etcd"],"path":"phpboyscout/go/config-etcd","role":"member"},{"display":{"kind":"Backend","language":"Go","name":"config-aws-ssm","summary":"Read AWS SSM Parameter Store as a layer. Read-only: Parameter Store has no compare-and-swap write."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-aws-ssm"],"path":"phpboyscout/go/config-aws-ssm","role":"member"},{"display":{"kind":"Backend","language":"Go","name":"config-azure-appconfig","summary":"Read and write Azure App Configuration, each write guarded by the setting's ETag."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-azure-appconfig"],"path":"phpboyscout/go/config-azure-appconfig","role":"member"},{"display":{"kind":"Backend","language":"Go","name":"config-gcp-parameter","summary":"Read GCP Parameter Manager as a layer, read-only."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-gcp-parameter"],"path":"phpboyscout/go/config-gcp-parameter","role":"member"},{"display":{"kind":"Secret backend","language":"Go","name":"config-vault","summary":"Read secrets from HashiCorp Vault as a config layer, with the client injected so you own how it authenticates."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-vault"],"path":"phpboyscout/go/config-vault","role":"member"},{"display":{"kind":"Secret backend","language":"Go","name":"config-aws-secrets","summary":"Read secrets from AWS Secrets Manager as a config layer."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-aws-secrets"],"path":"phpboyscout/go/config-aws-secrets","role":"member"},{"display":{"kind":"Secret backend","language":"Go","name":"config-azure-keyvault","summary":"Read secrets from Azure Key Vault as a config layer."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-azure-keyvault"],"path":"phpboyscout/go/config-azure-keyvault","role":"member"},{"display":{"kind":"Secret backend","language":"Go","name":"config-keychain","summary":"Read and write sensitive values in the OS keychain as a config layer, so a CLI's tokens never sit in a plain file on disk."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-keychain"],"path":"phpboyscout/go/config-keychain","role":"member"},{"display":{"kind":"Secret backend","language":"Go","name":"config-gcp-secret","summary":"Read secrets from Google Cloud Secret Manager as a config layer."},"family":"config","listed":true,"modules":["gitlab.com/phpboyscout/go/config-gcp-secret"],"path":"phpboyscout/go/config-gcp-secret","role":"member"},{"display":{"docs":"https://yamldoc.go.phpboyscout.uk","kind":"YAML editing","language":"Go","name":"yamldoc","summary":"Edit a YAML document without destroying it: comments, key order, quoting and block styles survive a targeted change. Built for config, useful on its own."},"listed":true,"modules":["gitlab.com/phpboyscout/go/yamldoc"],"path":"phpboyscout/go/yamldoc"},{"display":{"docs":"https://browser.go.phpboyscout.uk","kind":"Utility module","language":"Go","name":"browser","summary":"A safe entry point for opening URLs: scheme allowlist, length bound and control-character rejection."},"listed":true,"modules":["gitlab.com/phpboyscout/go/browser"],"path":"phpboyscout/go/browser"},{"display":{"docs":"https://controls.go.phpboyscout.uk","kind":"Service lifecycle","language":"Go","name":"controls","summary":"Startup ordering, health probes, graceful shutdown and self-healing restarts for Go services."},"listed":true,"modules":["gitlab.com/phpboyscout/go/controls","gitlab.com/phpboyscout/go/controls/lint"],"path":"phpboyscout/go/controls"},{"display":{"docs":"https://redact.go.phpboyscout.uk","kind":"Safety utility","language":"Go","name":"redact","summary":"Strips credential-like content from free-form strings before they reach logs or telemetry."},"listed":true,"modules":["gitlab.com/phpboyscout/go/redact"],"path":"phpboyscout/go/redact"},{"display":{"docs":"https://regexutil.go.phpboyscout.uk","kind":"Safety utility","language":"Go","name":"regexutil","summary":"Bounded, DoS-safe regex compilation for patterns that might come from untrusted sources."},"listed":true,"modules":["gitlab.com/phpboyscout/go/regexutil"],"path":"phpboyscout/go/regexutil"},{"display":{"docs":"https://observability.go.phpboyscout.uk","kind":"Telemetry","language":"Go","name":"observability","summary":"Hardened OpenTelemetry setup for Go services: OTLP logs, metrics and traces, wired up once and correctly."},"listed":true,"modules":["gitlab.com/phpboyscout/go/observability"],"path":"phpboyscout/go/observability"},{"display":{"docs":"https://credentials.go.phpboyscout.uk","kind":"Secrets","language":"Go","name":"credentials","summary":"A storage-mode abstraction for user-supplied secrets: env-var reference, OS keychain or literal value, with a pluggable backend and an auditable keychain opt-out."},"listed":true,"modules":["gitlab.com/phpboyscout/go/credentials"],"path":"phpboyscout/go/credentials"},{"display":{"docs":"https://errors.go.phpboyscout.uk","kind":"Error package","language":"Go","name":"errors","summary":"The error package the estate owns: stack traces, user-facing hints, structured attributes for logging, and an aggregate that behaves like the standard library's, so nothing goes missing below a Join. It imports nothing outside the standard library, and a test enforces that."},"listed":true,"modules":["gitlab.com/phpboyscout/go/errors"],"path":"phpboyscout/go/errors"},{"display":{"docs":"https://errorhandling.go.phpboyscout.uk","kind":"CLI errors","language":"Go","name":"errorhandling","summary":"Structured, user-friendly error reporting for CLIs: actionable hints, exit codes carried on the error, debug-gated stack traces and a pluggable support channel."},"listed":true,"modules":["gitlab.com/phpboyscout/go/errorhandling"],"path":"phpboyscout/go/errorhandling"},{"display":{"docs":"https://aferobilly.go.phpboyscout.uk","kind":"FS adapter","language":"Go","name":"aferobilly","summary":"Use a go-billy filesystem anywhere an afero one is expected: a complete billy-to-afero adapter with optional locking that makes a live handle concurrency-safe."},"listed":true,"modules":["gitlab.com/phpboyscout/go/aferobilly"],"path":"phpboyscout/go/aferobilly"},{"display":{"docs":"https://workspace.go.phpboyscout.uk","kind":"Utility module","language":"Go","name":"workspace","summary":"Find a project's root by walking up to a marker file, over an injected afero filesystem so it stays testable."},"listed":true,"modules":["gitlab.com/phpboyscout/go/workspace"],"path":"phpboyscout/go/workspace"},{"display":{"docs":"https://output.go.phpboyscout.uk","kind":"CLI output","language":"Go","name":"output","summary":"Structured, themeable output for CLI tools: one Renderer facade for text, JSON, YAML, CSV, TSV and Markdown, plus tables, spinners, progress bars and status lines. Framework-free core, with an opt-in cobra subpackage."},"listed":true,"modules":["gitlab.com/phpboyscout/go/output"],"path":"phpboyscout/go/output"},{"display":{"docs":"https://onnxruntime.go.phpboyscout.uk","kind":"Runtime resolver","language":"Go","name":"onnxruntime","summary":"Resolve the ONNX Runtime shared library at run time: pick the right archive for the platform from the estate artefact channel, extract the library and cache it."},"listed":true,"modules":["gitlab.com/phpboyscout/go/onnxruntime"],"path":"phpboyscout/go/onnxruntime"},{"display":{"docs":"https://features.go.phpboyscout.uk","kind":"Feature gating","language":"Go","name":"features","summary":"Feature gating and feature flags as values rather than process state: declare at init, snapshot at build, resolve a set once, and evaluate dynamic flags through a vendor-neutral backend seam."},"listed":true,"modules":["gitlab.com/phpboyscout/go/features"],"path":"phpboyscout/go/features"},{"display":{"kind":"Backend","language":"Go","name":"features-openfeature","summary":"A features.Backend over any OpenFeature provider: one adapter opens LaunchDarkly, Unleash, GitLab Feature Flags, flagd and the rest."},"listed":true,"modules":["gitlab.com/phpboyscout/go/features-openfeature"],"path":"phpboyscout/go/features-openfeature"},{"display":{"docs":"https://transport.go.phpboyscout.uk","kind":"Server stack","language":"Go","name":"transport","summary":"A framework-free HTTP + gRPC + gateway server stack: hardened server constructors, health endpoints, authentication and security headers."},"family":"transport","listed":true,"modules":["gitlab.com/phpboyscout/go/transport"],"path":"phpboyscout/go/transport","role":"core"},{"display":{"docs":"https://httpclient.go.phpboyscout.uk","kind":"HTTP client","language":"Go","name":"httpclient","summary":"A hardened *http.Client factory: secure TLS defaults, downgrade-proof redirects and the transit middleware."},"listed":true,"modules":["gitlab.com/phpboyscout/go/httpclient"],"path":"phpboyscout/go/httpclient"},{"display":{"docs":"https://grpcclient.go.phpboyscout.uk","kind":"gRPC client","language":"Go","name":"grpcclient","summary":"A light gRPC client dial factory: a decoupled target, go/tls credentials and the transit client interceptors."},"listed":true,"modules":["gitlab.com/phpboyscout/go/grpcclient"],"path":"phpboyscout/go/grpcclient"},{"display":{"docs":"https://transit.go.phpboyscout.uk","kind":"Client middleware","language":"Go","name":"transit","summary":"The shared HTTP and gRPC client middleware both factories use: retry, circuit-breaker and auth."},"listed":true,"modules":["gitlab.com/phpboyscout/go/transit"],"path":"phpboyscout/go/transit"},{"display":{"docs":"https://transport-openapi.go.phpboyscout.uk","kind":"API docs","language":"Go","name":"transport-openapi","summary":"Serve an OpenAPI spec and an interactive Stoplight Elements docs site from one Register call, mounted on your transport mux. Keeps the ~2.4 MB embedded docs UI out of servers that don't need it."},"family":"transport","listed":true,"modules":["gitlab.com/phpboyscout/go/transport-openapi"],"path":"phpboyscout/go/transport-openapi","role":"member"},{"display":{"docs":"https://transport-metrics.go.phpboyscout.uk","kind":"Metrics","language":"Go","name":"transport-metrics","summary":"Cardinality-safe Prometheus instrumentation: a scrapeable /metrics endpoint (Go runtime, process and build-info collectors), optional pprof, mounted on your server or standalone. The pull/scrape counterpart to the OTel observability module; go/transport, gRPC and OTel isolated in opt-in subpackages."},"family":"transport","listed":true,"modules":["gitlab.com/phpboyscout/go/transport-metrics"],"path":"phpboyscout/go/transport-metrics","role":"member"},{"display":{"docs":"https://tls.go.phpboyscout.uk","kind":"TLS plumbing","language":"Go","name":"tls","summary":"Hardened, framework-free TLS plumbing for Go: sensible defaults and the pieces the transports and clients build on."},"listed":true,"modules":["gitlab.com/phpboyscout/go/tls"],"path":"phpboyscout/go/tls"},{"display":{"docs":"https://authn.go.phpboyscout.uk","kind":"Authentication","language":"Go","name":"authn","summary":"Transport-agnostic request authentication: API key, JWT/OIDC and mTLS, usable from either transport."},"listed":true,"modules":["gitlab.com/phpboyscout/go/authn"],"path":"phpboyscout/go/authn"},{"display":{"docs":"https://localca.go.phpboyscout.uk","kind":"Local CA","language":"Go","name":"localca","summary":"A framework-free, mkcert-style local development CA: a per-machine root, cross-OS trust-store install and browser-trusted HTTPS on localhost and LAN IPs with zero manual setup."},"listed":true,"modules":["gitlab.com/phpboyscout/go/localca"],"path":"phpboyscout/go/localca"},{"display":{"docs":"https://clientlifecycle.go.phpboyscout.uk","kind":"Lifecycle primitive","language":"Go","name":"clientlifecycle","summary":"Resolve a value that is expensive to build exactly once, shared by every caller, race-free, and retried rather than cached if it fails. The general case the provider modules below are built on, and nothing about it is cloud-specific: any client behind a costly SDK has this shape."},"listed":true,"modules":["gitlab.com/phpboyscout/go/clientlifecycle"],"path":"phpboyscout/go/clientlifecycle"},{"display":{"docs":"https://awsclient.go.phpboyscout.uk","kind":"Client construction","language":"Go","name":"awsclient","summary":"Resolve the AWS configuration a service client is built from, once and shared or afresh per operation, as the caller chooses."},"listed":true,"modules":["gitlab.com/phpboyscout/go/awsclient"],"path":"phpboyscout/go/awsclient"},{"display":{"docs":"https://azureclient.go.phpboyscout.uk","kind":"Client construction","language":"Go","name":"azureclient","summary":"Resolve the Azure credential a service client is built from, once and shared or afresh per operation."},"listed":true,"modules":["gitlab.com/phpboyscout/go/azureclient"],"path":"phpboyscout/go/azureclient"},{"display":{"docs":"https://gcpclient.go.phpboyscout.uk","kind":"Client construction","language":"Go","name":"gcpclient","summary":"Resolve the Google Cloud credential and hand it over as client options. GCP is the provider where building the service client is not free, so the seam stops one step earlier and the client stays yours to build and close."},"listed":true,"modules":["gitlab.com/phpboyscout/go/gcpclient"],"path":"phpboyscout/go/gcpclient"},{"display":{"docs":"https://vaultclient.go.phpboyscout.uk","kind":"Client construction","language":"Go","name":"vaultclient","summary":"Resolve the Vault client an adapter talks to. Vault is the provider where the client *is* the connection prerequisite, carrying the address, namespace, token and retry policy together, so there is no separate config object to hand on."},"listed":true,"modules":["gitlab.com/phpboyscout/go/vaultclient"],"path":"phpboyscout/go/vaultclient"},{"display":{"docs":"https://chat.go.phpboyscout.uk","kind":"AI client","language":"Go","name":"chat","summary":"A light, framework-free multi-provider AI chat client with provider support kept opt-in."},"family":"chat","listed":true,"modules":["gitlab.com/phpboyscout/go/chat","gitlab.com/phpboyscout/go/chat/tools/capabilitygen"],"path":"phpboyscout/go/chat","role":"core"},{"display":{"kind":"Provider","language":"Go","name":"chat-anthropic","summary":"Anthropic Claude provider for the Go chat client."},"family":"chat","listed":true,"modules":["gitlab.com/phpboyscout/go/chat-anthropic"],"path":"phpboyscout/go/chat-anthropic","role":"member"},{"display":{"kind":"Provider","language":"Go","name":"chat-gemini","summary":"Google Gemini provider for the Go chat client."},"family":"chat","listed":true,"modules":["gitlab.com/phpboyscout/go/chat-gemini"],"path":"phpboyscout/go/chat-gemini","role":"member"},{"display":{"kind":"Provider","language":"Go","name":"chat-openai","summary":"OpenAI and OpenAI-compatible provider for the Go chat client."},"family":"chat","listed":true,"modules":["gitlab.com/phpboyscout/go/chat-openai"],"path":"phpboyscout/go/chat-openai","role":"member"},{"display":{"kind":"Provider","language":"Go","name":"chat-openai-azure","summary":"Azure OpenAI backend for the Go chat client, delegating to chat-openai."},"family":"chat","listed":true,"modules":["gitlab.com/phpboyscout/go/chat-openai-azure"],"path":"phpboyscout/go/chat-openai-azure","role":"member"},{"display":{"kind":"Provider","language":"Go","name":"chat-bedrock","summary":"AWS Bedrock provider for the Go chat client, speaking the Converse API."},"family":"chat","listed":true,"modules":["gitlab.com/phpboyscout/go/chat-bedrock"],"path":"phpboyscout/go/chat-bedrock","role":"member"},{"display":{"kind":"Tool bridge","language":"Go","name":"chat-mcptools","summary":"Publishes a chat.Tool set on a loopback MCP server for the life of one subprocess call, so a local-CLI provider can offer in-process Go handlers to a CLI in another process."},"family":"chat","listed":true,"modules":["gitlab.com/phpboyscout/go/chat-mcptools"],"path":"phpboyscout/go/chat-mcptools","role":"member"},{"display":{"docs":"https://mcp.go.phpboyscout.uk","kind":"MCP server","language":"Go","name":"mcp","summary":"Progressive MCP discovery and execution for Go applications: an agent reads a catalogue before it sees the tools, with the same operation tree served from a Cobra CLI or mounted in an HTTP or gRPC service."},"listed":true,"modules":["gitlab.com/phpboyscout/go/mcp"],"path":"phpboyscout/go/mcp"},{"display":{"docs":"https://nats.go.phpboyscout.uk","kind":"Messaging","language":"Go","name":"nats","summary":"NATS as an estate convention: a controls-managed embedded server and a client that is the same code whether the broker is in this process or a cluster somebody else runs."},"listed":true,"modules":["gitlab.com/phpboyscout/go/nats"],"path":"phpboyscout/go/nats"},{"display":{"docs":"https://messaging.go.phpboyscout.uk","kind":"Message bus","language":"Go","name":"messaging","summary":"One way to send a message between services: a controls-managed bus carrying CloudEvents, with the thing that carries them behind a swappable backend."},"family":"messaging","listed":true,"modules":["gitlab.com/phpboyscout/go/messaging"],"path":"phpboyscout/go/messaging","role":"core"},{"display":{"docs":"https://messaging.go.phpboyscout.uk/","kind":"Backend","language":"Go","name":"messaging-nats","summary":"NATS and JetStream backends, over go/nats: the bus's second implementation, and the one that survives a restart."},"family":"messaging","listed":true,"modules":["gitlab.com/phpboyscout/go/messaging-nats"],"path":"phpboyscout/go/messaging-nats","role":"member"},{"display":{"docs":"https://messaging.go.phpboyscout.uk/","kind":"Backend","language":"Go","name":"messaging-sqs","summary":"SQS and SNS backends: FIFO fan-out with the subject as the message group, and standard queues for throughput."},"family":"messaging","listed":true,"modules":["gitlab.com/phpboyscout/go/messaging-sqs"],"path":"phpboyscout/go/messaging-sqs","role":"member"},{"display":{"docs":"https://messaging.go.phpboyscout.uk/","kind":"Backend","language":"Go","name":"messaging-rabbitmq","summary":"RabbitMQ over AMQP 0-9-1: quorum queues, the topic exchange as the subject space, and the management API as the source of every queue fact."},"family":"messaging","listed":true,"modules":["gitlab.com/phpboyscout/go/messaging-rabbitmq"],"path":"phpboyscout/go/messaging-rabbitmq","role":"member"},{"display":{"docs":"https://messaging.go.phpboyscout.uk/","kind":"Backend","language":"Go","name":"messaging-amqp","summary":"AMQP 1.0 over Azure/go-amqp, Apache ActiveMQ Artemis first, with durable subscriptions as the identity."},"family":"messaging","listed":true,"modules":["gitlab.com/phpboyscout/go/messaging-amqp"],"path":"phpboyscout/go/messaging-amqp","role":"member"},{"display":{"docs":"https://cloudevents.go.phpboyscout.uk","kind":"Event codec","language":"Go","name":"cloudevents","summary":"CloudEvents in binary mode over a header map: a codec rather than a protocol binding, so the same envelope crosses NATS today and HTTP tomorrow."},"listed":true,"modules":["gitlab.com/phpboyscout/go/cloudevents"],"path":"phpboyscout/go/cloudevents"},{"display":{"docs":"https://schema.go.phpboyscout.uk","kind":"Schema registry","language":"Go","name":"schema","summary":"A schema registry for the estate: JSON Schema and protobuf under permanent URNs that refuse to change, resolved offline from an embedded register or served over HTTP and gRPC."},"listed":true,"modules":["gitlab.com/phpboyscout/go/schema"],"path":"phpboyscout/go/schema"},{"display":{"docs":"https://comms.go.phpboyscout.uk","kind":"Chat platform contract","language":"Go","name":"comms","summary":"Receive, reply and moderate across chat platforms with no vendor SDK in the core. The other side of the chat modules: those talk to models, this one talks to the people."},"family":"comms","listed":true,"modules":["gitlab.com/phpboyscout/go/comms"],"path":"phpboyscout/go/comms","role":"core"},{"display":{"kind":"Provider","language":"Go","name":"comms-discord","summary":"The Discord provider: read channels, reply in threads, moderate and run slash commands."},"family":"comms","listed":true,"modules":["gitlab.com/phpboyscout/go/comms-discord"],"path":"phpboyscout/go/comms-discord","role":"member"},{"display":{"docs":"https://app.rust.phpboyscout.uk","kind":"Application core","language":"Rust","name":"app","summary":"The application context and command contract for RTB-based CLI tools: App\u003cC\u003e, ToolMetadata, typed config and cancellation."},"listed":true,"modules":["rtb-app","rtb-test-support"],"path":"phpboyscout/rust/app"},{"display":{"kind":"CLI runtime","language":"Rust","name":"cli","summary":"The CLI runtime family: a four-crate workspace on one version line. rtb-cli builds the application; the others each register a built-in command into the same link-time registry."},"listed":true,"modules":["rtb-cli","rtb-docs","rtb-mcp","rtb-update"],"path":"phpboyscout/rust/cli"},{"display":{"docs":"https://config.rust.phpboyscout.uk","kind":"Configuration","language":"Rust","name":"config","summary":"Strongly-typed layered configuration with hot reload."},"listed":true,"modules":["rtb-config"],"path":"phpboyscout/rust/config"},{"display":{"docs":"https://credentials.rust.phpboyscout.uk","kind":"Secrets","language":"Rust","name":"credentials","summary":"User-secret storage behind one seam: env-var reference, OS keychain or literal config."},"listed":true,"modules":["rtb-credentials"],"path":"phpboyscout/rust/credentials"},{"display":{"docs":"https://error.rust.phpboyscout.uk","kind":"Error handling","language":"Rust","name":"error","summary":"Error types and the miette diagnostic report pipeline for CLI tools."},"listed":true,"modules":["rtb-error"],"path":"phpboyscout/rust/error"},{"display":{"docs":"https://assets.rust.phpboyscout.uk","kind":"Embedded assets","language":"Rust","name":"assets","summary":"Embedded-asset overlay filesystem: ship defaults in the binary, override on disk."},"listed":true,"modules":["rtb-assets"],"path":"phpboyscout/rust/assets"},{"display":{"docs":"https://redact.rust.phpboyscout.uk","kind":"Safety utility","language":"Rust","name":"redact","summary":"Strips credential-like content from strings before they reach logs or telemetry."},"listed":true,"modules":["rtb-redact"],"path":"phpboyscout/rust/redact"},{"display":{"docs":"https://tui.rust.phpboyscout.uk","kind":"Terminal UI","language":"Rust","name":"tui","summary":"Reusable terminal-UI widgets: wizards, tables and spinners."},"listed":true,"modules":["rtb-tui"],"path":"phpboyscout/rust/tui"},{"display":{"docs":"https://chat.rust.phpboyscout.uk","kind":"AI client","language":"Rust","name":"chat","summary":"A unified AI chat client: Claude, OpenAI, Gemini, Ollama and compatibles behind one interface."},"listed":true,"modules":["rtb-chat"],"path":"phpboyscout/rust/chat"},{"display":{"docs":"https://forge.rust.phpboyscout.uk","kind":"Release ops","language":"Rust","name":"forge","summary":"Forge release providers (GitHub, GitLab, Gitea, Codeberg, Bitbucket), plus git operations over gix."},"listed":true,"modules":["rtb-forge"],"path":"phpboyscout/rust/forge"},{"display":{"docs":"https://telemetry.rust.phpboyscout.uk","kind":"Telemetry","language":"Rust","name":"telemetry","summary":"Opt-in, consent-gated anonymous usage telemetry with pluggable sinks."},"listed":true,"modules":["rtb-telemetry"],"path":"phpboyscout/rust/telemetry"},{"display":{"docs":"https://keryx.phpboyscout.uk","kind":"Publishing studio","language":"Go / Svelte","name":"keryx"},"family":"gtb","listed":true,"modules":["gitlab.com/phpboyscout/keryx"],"pair":"afmpeg-ffmpeg-wasi-keryx","path":"phpboyscout/keryx","role":"member"},{"display":{"docs":"https://krites.phpboyscout.uk","kind":"Photography tool","language":"Go / Svelte","name":"krites"},"family":"gtb","listed":true,"modules":["gitlab.com/phpboyscout/krites"],"path":"phpboyscout/krites","role":"member"},{"display":{"docs":"https://afmpeg.phpboyscout.uk","kind":"Media library","language":"Go","name":"afmpeg"},"listed":true,"modules":["gitlab.com/phpboyscout/afmpeg"],"pair":"afmpeg-ffmpeg-wasi-keryx","path":"phpboyscout/afmpeg"},{"display":{"docs":"https://ffmpeg-wasi.phpboyscout.uk","kind":"Media engine","language":"C / WASI","name":"ffmpeg-wasi","summary":"Current FFmpeg as a sandboxed WASI module, runnable from Go through wazero without CGO or a host FFmpeg install. Built for afmpeg, but it stands on its own: anything that can host a WASI runtime can use it."},"listed":true,"modules":["gitlab.com/phpboyscout/ffmpeg-wasi"],"pair":"afmpeg-ffmpeg-wasi-keryx","path":"phpboyscout/ffmpeg-wasi"},{"display":{"docs":"https://sigillum.phpboyscout.uk","kind":"Signing CLI","language":"Go","name":"sigillum","summary":"A standalone command-line tool for signing and verifying release artefacts with OpenPGP. The private key never leaves your KMS, HSM or PEM file, and nothing about it cares what language your project is written in."},"family":"gtb","listed":true,"modules":["gitlab.com/phpboyscout/sigillum"],"path":"phpboyscout/sigillum","role":"member"},{"display":{"docs":"https://signing.phpboyscout.uk","kind":"Library","language":"Go","name":"signing"},"family":"signing","listed":true,"modules":["gitlab.com/phpboyscout/go/signing"],"path":"phpboyscout/go/signing","role":"core"},{"display":{"kind":"Backend","language":"Go","name":"signing-aws-kms","summary":"The AWS KMS backend for the signing module, keeping private release-signing keys inside KMS while the public API stays framework-free."},"family":"signing","listed":true,"modules":["gitlab.com/phpboyscout/go/signing-aws-kms"],"path":"phpboyscout/go/signing-aws-kms","role":"member"},{"display":{"kind":"Command surface","language":"Go","name":"signing-cli","summary":"The shareable sign and keys command builders, and nothing else. Splitting the commands off means go-tool-base and the standalone sigillum can offer the same ones without a dependency cycle between them."},"family":"signing","listed":true,"modules":["gitlab.com/phpboyscout/go/signing-cli"],"path":"phpboyscout/go/signing-cli","role":"member"},{"display":{"docs":"https://encryption.go.phpboyscout.uk","kind":"Library","language":"Go","name":"encryption","summary":"The other direction: assemble an OpenPGP certificate whose private halves live in a KMS, and decrypt a message addressed to it from a raw ECDH shared secret. Built because KMS can sign an OpenPGP key but cannot decrypt one, so the unwrap has to happen outside it."},"family":"encryption","listed":true,"modules":["gitlab.com/phpboyscout/go/encryption"],"path":"phpboyscout/go/encryption","role":"core"},{"display":{"kind":"Backend","language":"Go","name":"encryption-aws-kms","summary":"The AWS KMS backend for the encryption module, deriving the shared secret and certifying inside KMS so no private key material leaves it."},"family":"encryption","listed":true,"modules":["gitlab.com/phpboyscout/go/encryption-aws-kms"],"path":"phpboyscout/go/encryption-aws-kms","role":"member"},{"display":{"docs":"https://forge.go.phpboyscout.uk","kind":"Release ops","language":"Go","name":"forge","summary":"Forge release operations: a provider contract, registry and credential chain, with no vendor SDK in the core. Each forge is a swappable provider module."},"family":"forge","listed":true,"modules":["gitlab.com/phpboyscout/go/forge"],"path":"phpboyscout/go/forge","role":"core"},{"display":{"kind":"Provider","language":"Go","name":"forge-github","summary":"GitHub release provider (github.com and Enterprise), over go-github."},"family":"forge","listed":true,"modules":["gitlab.com/phpboyscout/go/forge-github"],"path":"phpboyscout/go/forge-github","role":"member"},{"display":{"kind":"Provider","language":"Go","name":"forge-gitlab","summary":"GitLab release provider, over the official client-go."},"family":"forge","listed":true,"modules":["gitlab.com/phpboyscout/go/forge-gitlab"],"path":"phpboyscout/go/forge-gitlab","role":"member"},{"display":{"kind":"Provider","language":"Go","name":"forge-gitea","summary":"Gitea and Codeberg release provider, over the gitea SDK."},"family":"forge","listed":true,"modules":["gitlab.com/phpboyscout/go/forge-gitea"],"path":"phpboyscout/go/forge-gitea","role":"member"},{"display":{"kind":"Provider","language":"Go","name":"forge-bitbucket","summary":"Bitbucket release provider, over the Downloads API."},"family":"forge","listed":true,"modules":["gitlab.com/phpboyscout/go/forge-bitbucket"],"path":"phpboyscout/go/forge-bitbucket","role":"member"},{"display":{"docs":"https://changelog.go.phpboyscout.uk","kind":"Release notes","language":"Go","name":"changelog","summary":"Turn a repository's Conventional-Commits history, or a release-notes archive, into a structured, categorised changelog."},"listed":true,"modules":["gitlab.com/phpboyscout/go/changelog"],"path":"phpboyscout/go/changelog"},{"display":{"kind":"Package tap","language":"Ruby","name":"homebrew","summary":"The Homebrew tap for phpboyscout tools, used to distribute the binaries that come out of the release pipeline."},"listed":true,"path":"phpboyscout/homebrew"},{"display":{"docs":"https://colophon.phpboyscout.uk","kind":"Release orchestration","language":"Go","name":"colophon","summary":"Release orchestration that tags the commit which actually landed: work out the version your commits have earned, open the release as a merge request, then resolve the tag against the target branch itself rather than trusting whatever the forge says merged. A colophon is the mark a printer leaves at the end of the book, once it is finished."},"listed":true,"modules":["gitlab.com/phpboyscout/colophon"],"path":"phpboyscout/colophon"},{"display":{"docs":"https://artifacts.phpboyscout.uk","kind":"Artefact channel","language":"CI / OpenTofu","name":"artifacts","summary":"Approved artefacts for the estate, models and runtimes, mirrored, checksummed, signed and published as one channel, so a tool that needs a large binary dependency fetches it from somewhere accountable instead of from wherever upstream happens to host it today."},"listed":true,"path":"phpboyscout/artifacts"},{"display":{"docs":"https://artifacts.go.phpboyscout.uk","kind":"Artefact client","language":"Go","name":"go/artifacts","summary":"The Go client for that channel: fetch by name and version, verify the signed manifest against embedded and WKD trust, cache it, and hand back a path. Usable without the framework around it."},"listed":true,"modules":["gitlab.com/phpboyscout/go/artifacts"],"path":"phpboyscout/go/artifacts"},{"display":{"docs":"https://cicd.phpboyscout.uk","kind":"Components","language":"GitLab CI","name":"cicd"},"family":"cicd-components","listed":true,"path":"phpboyscout/cicd","role":"core"},{"display":{"kind":"Base image","language":"Docker","name":"ci-base","summary":"The minimal Wolfi base every other image derives from: bash, git, curl, jq and python3, and nothing else."},"family":"images","listed":true,"path":"phpboyscout/images/ci-base","role":"core"},{"display":{"kind":"Language CI image","language":"Docker","name":"go-tools","summary":"Go, golangci-lint, goreleaser, syft and govulncheck."},"family":"images","listed":true,"path":"phpboyscout/images/go-tools","role":"member"},{"display":{"kind":"Language CI image","language":"Docker","name":"rust-tools","summary":"The rustup toolchain with clippy, rustfmt and llvm-tools."},"family":"images","listed":true,"path":"phpboyscout/images/rust-tools","role":"member"},{"display":{"kind":"Language CI image","language":"Docker","name":"node-tools","summary":"Node, npm and corepack for pnpm and yarn, used by the Svelte front ends."},"family":"images","listed":true,"path":"phpboyscout/images/node-tools","role":"member"},{"display":{"kind":"Infrastructure CI image","language":"Docker","name":"tofu-tools","summary":"OpenTofu and tflint, with the AWS ruleset pre-baked so a pipeline is not fetching it on every run."},"family":"images","listed":true,"path":"phpboyscout/images/tofu-tools","role":"member"},{"display":{"kind":"Docs CI image","language":"Docker","name":"docs-tools","summary":"Zensical on Python, the image that builds every docs microsite in the estate."},"family":"images","listed":true,"path":"phpboyscout/images/docs-tools","role":"member"},{"display":{"kind":"Browser CI image","language":"Docker","name":"playwright-tools","summary":"node-tools plus the Chromium runtime libraries, for the browser-driven tests."},"family":"images","listed":true,"path":"phpboyscout/images/playwright-tools","role":"member"},{"display":{"kind":"Release CI image","language":"Docker","name":"release-tools","summary":"colophon on ci-base: the image every release in the estate runs on."},"family":"images","listed":true,"path":"phpboyscout/images/release-tools","role":"member"},{"display":{"kind":"Build toolchain image","language":"Docker","name":"ffmpeg-wasi-build","summary":"ffmpeg-wasi's build toolchain: the wasi-sdk cross-compiler with native gcc, nasm and cmake."},"listed":false,"path":"phpboyscout/images/ffmpeg-wasi-build"},{"display":{"docs":"https://repo.go.phpboyscout.uk","kind":"Git operations","language":"Go","name":"repo","summary":"Git repository operations for Go: clone, commit, worktrees and tree inspection over go-git, behind focused role interfaces."},"listed":true,"modules":["gitlab.com/phpboyscout/go/repo"],"path":"phpboyscout/go/repo"},{"display":{"kind":"Plugin marketplace","language":"Markdown / JSON","name":"claude-code-plugins"},"listed":true,"path":"phpboyscout/claude-code-plugins"},{"display":{"docs":"https://skillup.phpboyscout.uk","kind":"Marketplace versioning","language":"Go","name":"skillup","summary":"Version the segments of a Claude Code plugin marketplace from the history of their manifests, so each plugin gets the version its own changes earned. Correct even on a repository that has never been tagged."},"family":"gtb","listed":true,"modules":["gitlab.com/phpboyscout/skillup"],"path":"phpboyscout/skillup","role":"member"},{"display":{"docs":"https://docscheck.go.phpboyscout.uk","kind":"Docs gate","language":"Go","name":"docscheck","summary":"Check the command examples in a tool's documentation against its real command tree, so a renamed flag fails a pipeline instead of quietly misleading a reader."},"listed":true,"modules":["gitlab.com/phpboyscout/go/docscheck"],"path":"phpboyscout/go/docscheck"},{"display":{"docs":"https://phpbotscout.phpboyscout.uk","kind":"Support bot","language":"Go","name":"phpbotscout","summary":"A support and moderation bot bridging Discord and GitLab: it answers what the docs already cover, with citations, and offers to raise an issue with the thread attached when it can't. Every question it can't answer is a documentation gap with a timestamp on it."},"family":"gtb","listed":true,"modules":["gitlab.com/phpboyscout/phpbotscout"],"path":"phpboyscout/phpbotscout","role":"member"},{"display":{"docs":"https://aws-bootstrap.iac.phpboyscout.uk","kind":"Terraform module","language":"OpenTofu","name":"terraform-aws-bootstrap","summary":"The small first stack for a new AWS account: remote state, CI OIDC identity and an aws-nuke config. It deliberately stops there."},"listed":true,"path":"phpboyscout/iac/terraform-aws-bootstrap"},{"display":{"kind":"CI runner fleet","language":"OpenTofu","name":"terraform-aws-gitlab-runner-fleet","summary":"A GitLab Runner fleeting fleet on AWS: one always-on manager plus scale-to-zero spot workers on the docker-autoscaler executor. Built to replace cattle-ops/gitlab-runner and expose the levers it hid, including worker disk size and a shared cache layer."},"listed":true,"path":"phpboyscout/iac/terraform-aws-gitlab-runner-fleet"},{"display":{"docs":"https://aws-security-baseline.iac.phpboyscout.uk","kind":"Terraform module","language":"OpenTofu","name":"terraform-aws-security-baseline","summary":"The downstream account baseline: audit logging, threat detection, account hardening, operator access and the alerts wiring I keep reusing."},"listed":true,"path":"phpboyscout/iac/terraform-aws-security-baseline"},{"display":{"docs":"https://aws-signing-kms.iac.phpboyscout.uk","kind":"Terraform module","language":"OpenTofu","name":"terraform-aws-signing-kms","summary":"The KMS-backed release signing module: asymmetric keys, CI signer role and the policy shape needed to sign without ever exporting the key."},"listed":true,"path":"phpboyscout/iac/terraform-aws-signing-kms"},{"display":{"docs":"https://aws-encryption-kms.iac.phpboyscout.uk","kind":"Terraform module","language":"OpenTofu","name":"terraform-aws-encryption-kms","summary":"A KMS-held OpenPGP identity for receiving encrypted mail: a certification primary, an ECDH subkey, and reader and certifier roles kept deliberately apart so neither can do the other's job."},"listed":true,"path":"phpboyscout/iac/terraform-aws-encryption-kms"}],"schema_version":1,"source":"https://phpboyscout.uk/projects/"}