Skip to content
Descoped Source Code Portalv2.2.14
PollingSign in

source-code-portal

Up to date

New Source Code Portal

Cantara/source-code-portal on GitHubLast push

last commit badgerelease badgelicense badgeissues badge

CI Release Licence

Source Code Portal (SCP) is an organisational dashboard for GitHub. It groups an organisation's repositories into the products and systems they make up and shows, for every product and every repository, how healthy it is: when it last changed, whether it has a release and a licence, how many issues are open, what it is built with and what it depends on. Commit logs, rendered READMEs and documentation, status badges and a Markdown surface for LLM agents come from the same catalogue.

It is one static Go binary that serves the API and runs the server-rendered web UI (Next.js), kept current by GitHub webhooks and a scheduled sync, and built for organisations from a handful to thousands of repositories.

A product (group) A repository

Features

Products and groups

  • Repositories grouped into products by exact name, prefix, glob, regular expression, topic or a catch-all (catalog.groups), each with a default repository.
  • One card per product with all its repositories, an activity strip and health badges per repository; large products span the width.
  • A group page with every repository, sortable and filterable, and the merged commit log of the whole product.

Organisation

  • Telemetry for the whole catalogue: repositories, active ones, the share with a release and with a licence, open issues, sync state.
  • Activity by the newest commit: active (30 days), recent (6 months), quiet (2 years), dormant and archived.
  • The commit log of the entire organisation, filterable by group and repository, with live updates.

Repositories

  • README and up to 50 Markdown documents under docs/, rendered with syntax highlighting, GitHub alerts and an outline, sanitised once.
  • Images in documents served through the portal's image proxy, so pages stay within a strict Content Security Policy.
  • Technology and dependencies from go.mod, package.json and pom.xml, with links between repositories that use each other.
  • An optional scp.yaml descriptor in the repository: title, owners, lifecycle, tags and links (repository guide).

Badges and integrations

  • SVG badges: /badges/repos/{owner}/{name}/{last-commit,release,license,issues}.svg and /badges/groups/{group}/repos.svg.
  • The JSON API under /api/v1, described by api/openapi.yaml and served at /api/v1/openapi.yaml.
  • /llms.txt, /llms-full.txt and Markdown answers for every page (Accept: text/markdown), for LLM agents and scripts.
  • /knowledge.yaml, the catalogue as a KCP manifest (discovered at /.well-known/kcp.json): a map of groups, repositories and documents with intents and reading order.
  • Server-sent events at /api/v1/events: open pages update when the catalogue changes.
  • Every page is complete HTML with its own title, description and canonical URL, plus /sitemap.xml and /robots.txt.

Operations

  • GitHub App or token authentication; webhooks (signed, with secret rotation) for updates within seconds.
  • Private repositories for viewers an authenticating proxy names, kept out of every public answer.
  • Several instances on a Hazelcast cluster: one leader syncs, the others apply its results.
  • Survives GitHub outages and rate limits: the last good data is kept in SQLite and served with its age.
  • Prometheus metrics, liveness and readiness probes and a status page on a separate admin port.

Quick start

You need a GitHub App or a token that can read the organisation's repositories (operator guide, section 1). A minimal scp.yaml:

github:
  sources:
    - id: github
      orgs: [Cantara]
      token_file: /run/secrets/github-token
      # app: { id: 123456, private_key_file: /run/secrets/scp-app.pem }
catalog:
  groups:
    - id: whydah
      name: Whydah
      description: Identity and access management
      default_repo: Whydah-OAuth2Service
      match:
        - prefix: Whydah-
    - id: other
      name: Other
      default_repo: source-code-portal
      match:
        - catch_all: true

Run the image:

docker run --rm -p 9090:9090 -p 9091:9091 -v scp-data:/data \
  -v "$PWD/scp.yaml:/etc/scp/scp.yaml:ro" -v "$PWD/secrets:/run/secrets:ro" \
  ghcr.io/cantara/source-code-portal:2.0.0 serve --config /etc/scp/scp.yaml

Open http://localhost:9090. The first sync of a large organisation takes a few minutes; the pages show what is loaded so far.

Without containers, take the binary for Linux (amd64, arm64) or macOS (arm64) and the web UI bundle scp-web_<version>.tar.gz from the releases page, unpack the bundle and run it with Node.js 26:

SCP_WEB_DIR=./scp-web scp serve --config scp.yaml

Releases are signed: the checksums with cosign, the image by digest.

Configuration

Configuration is one YAML file (--config); every key can also be set as SCP_<KEY> with dots as underscores, for example SCP_SERVER_PUBLIC_ADDR. deploy/config.example.yaml shows every key and scp config check --config scp.yaml prints the effective settings. The main ones:

Key Purpose
github.sources[] organisations and user accounts to read, with a GitHub App or a token file; forks, archived and private repositories on or off
catalog.groups[] the products: id, name, description, default repository and matchers
catalog.reconcile_interval how often each organisation is listed (default 5 minutes)
webhook.secret_file turns on POST /webhooks/github; previous_secret_file for rotation
server.public_url the portal's public address, for absolute links and HSTS
access.* identity headers and groups that may see private repositories
cluster.addresses Hazelcast members for several instances
store.path the SQLite cache (rebuildable)
web.dir, web.node the web UI bundle and the Node.js binary; the image sets both

Webhooks. Point the App's webhook, or an organisation webhook with content type application/json, at https://<portal>/webhooks/github with the secret from webhook.secret_file and the events Push, Release and Repository. For a portal on your own machine, a tunnel such as ngrok http 9090 gives GitHub an https address to deliver to. Without a webhook the portal still refreshes on its schedule.

Endpoints

Listener Path What
public :9090 /, /groups/{id}, /repos/{owner}/{name}, /commits the web UI
/api/v1/... the JSON API (API guide)
/badges/... SVG badges
/llms.txt, /llms-full.txt the catalogue for LLM agents
/webhooks/github GitHub deliveries
admin :9091 /livez, /readyz probes
/metrics Prometheus
/api/v1/status sync, rate limits, webhooks and cluster at a glance

Architecture

GitHub ──webhooks──┐
   │               ▼
   └──REST──▶ sync engine ──▶ SQLite (last good) ──▶ immutable snapshot ──▶ API, badges, llms, events
                                                                           │
                                         browser ◀── Go (CSP, proxy) ◀── Next.js server (renders from the API)
  • Sync. GitHub feeds a job engine with priorities, a rate budget, backoff and per-source pauses. Webhooks and the organisation listing tell it what changed; ETags keep unchanged data free.
  • Snapshot. Jobs write SQLite and publish an immutable snapshot behind an atomic pointer. Request handlers read only the snapshot, so a page never waits for GitHub.
  • Features. Each part is a package under internal/: catalog, commits, docs, badges, manifests, llms and webhook. Features never import each other (a test enforces it); cmd/scp wires them together.
  • Untrusted input. Everything from repositories passes bounded parsers and one HTML sanitiser.
  • Web UI. A Next.js App Router application, rendered on the server for every request and hydrated in the browser. Go starts and supervises it on loopback and proxies every page through itself, adding a per-request nonce Content Security Policy.

Stack: Go 1.27 with go-github, goldmark, bluemonday, modernc SQLite, Cobra and Viper, and the Hazelcast Go client; Next.js 16, React 19, TypeScript 7, Tailwind CSS 4, TanStack Query and openapi-fetch typed from the contract; Vitest, MSW and Playwright with axe.

Develop

Requirements: Go 1.27, Node.js 26, pnpm 12 and golangci-lint 2.15.

make check        # the gate: generated code, tidy modules, lint, Go and web tests, Playwright
make dev          # the Go server (scp.yaml) on :9090 and the web UI with hot reload on :3000
make build web    # bin/scp and the web UI bundle in web/bundle
make image        # the container image scp:dev
make gen          # regenerate the API code from api/openapi.yaml
go test -race -run TestName ./internal/catalog/

Tests never touch the network: GitHub is a fake in internal/github/githubtest. The Playwright tests need pnpm -C web exec playwright install chromium.

Documentation

  • Operator guide: connect GitHub, configure, run, several instances, monitor, troubleshoot.
  • Repository guide: what the portal reads from a repository and the scp.yaml descriptor.
  • Security model: the guarantees for private repositories and the operator's part.
  • API guide: the JSON API, badges and Markdown for agents.
  • Changelog and security policy.
  • The portal's own Guide page (/guide): how to read the signals, and the short path to a portal of your own.

Claude Code plugin. The scp plugin's run-scp skill configures, deploys, upgrades and troubleshoots a released portal with you, reading the documents of the release you run and proving the configuration with scp config check:

/plugin install scp --marketplace Cantara/source-code-portal

On Claude Code before 2.1.275: /plugin marketplace add Cantara/source-code-portal, then /plugin install scp@source-code-portal.

Contributing

Issues and pull requests are welcome. Keep changes small, follow Conventional Commits and run make check before you push. AGENTS.md describes the layout and the rules the code follows.

Roadmap

  1. The next release: the header's theme menu and account menu, every kind of work counted by default, and commits of any length read without failing (a repository's commit list is read as a stream in bounded memory).
  2. Embedding the portal in other sites (design): the portal's signals as versioned HTML fragments that a host site composes on its server, on any stack. Each fragment keeps its own styles in a shadow root, takes the host's look through --scp-* custom properties, and updates live through one small module of custom elements. Outbound webhooks tell a host when the data changed, and a typed client serves hosts that draw their own. The portal's dashboard is built from the same fragments, so the two never drift apart.

Licence

Apache License 2.0, see LICENSE. Source Code Portal is a Cantara project.

Dependencies

go.mod github.com/cantara/source-code-portal (88 dependencies)
NameVersionScope
github.com/alecthomas/chroma/v2v2.27.0runtime
github.com/bradleyfalzon/ghinstallation/v2v2.19.0runtime
github.com/coreos/go-oidc/v3v3.21.0runtime
github.com/google/go-cmpv0.7.0runtime
github.com/google/go-github/v93v93.0.0runtime
github.com/hazelcast/hazelcast-go-clientv1.6.0runtime
github.com/microcosm-cc/bluemondayv1.0.27runtime
github.com/modelcontextprotocol/go-sdkv1.8.0runtime
github.com/oapi-codegen/runtimev1.8.0runtime
github.com/pelletier/go-toml/v2v2.4.3runtime
github.com/prometheus/client_golangv1.25.0runtime
github.com/spf13/cobrav1.10.2runtime
github.com/spf13/pflagv1.1.0runtime
github.com/spf13/viperv1.21.0runtime
github.com/yuin/goldmark/v2v2.1.15runtime
github.com/zalando/go-keyringv0.2.8runtime
go.uber.org/goleakv1.3.0runtime
go.yaml.in/yaml/v4v4.0.0runtime
golang.org/x/modv0.42.0runtime
golang.org/x/netv0.62.0runtime
golang.org/x/oauth2v0.37.0runtime
golang.org/x/syncv0.24.0runtime
golang.org/x/termv0.47.0runtime
golang.org/x/textv0.43.0runtime
modernc.org/sqlitev1.61.1runtime
rsc.io/qrv0.2.0runtime
github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegentool
golang.org/x/vuln/cmd/govulnchecktool
github.com/StackExchange/wmiv0.0.0-20190523213315-cbe66965904dindirect
github.com/apapsch/go-jsonmerge/v2v2.0.0indirect
github.com/aymerick/douceurv0.2.0indirect
github.com/beorn7/perksv1.0.1indirect
github.com/cespare/xxhash/v2v2.3.0indirect
github.com/danieljoos/wincredv1.2.3indirect
github.com/dlclark/regexp2/v2v2.2.1indirect
github.com/dprotaso/go-yitv0.0.0-20220510233725-9ba8df137936indirect
github.com/dustin/go-humanizev1.1.0indirect
github.com/fsnotify/fsnotifyv1.9.0indirect
github.com/getkin/kin-openapiv0.142.0indirect
github.com/go-jose/go-jose/v4v4.1.4indirect
github.com/go-ole/go-olev1.2.4indirect
github.com/go-openapi/jsonpointerv0.23.1indirect
github.com/go-openapi/swag/jsonnamev0.26.0indirect
github.com/go-viper/mapstructure/v2v2.4.0indirect
github.com/godbus/dbus/v5v5.2.2indirect
github.com/golang-jwt/jwt/v4v4.5.2indirect
github.com/google/go-github/v88v88.0.0indirect
github.com/google/go-querystringv1.2.0indirect
github.com/google/jsonschema-gov0.4.3indirect
github.com/google/uuidv1.6.0indirect
github.com/gorilla/cssv1.0.1indirect
github.com/inconshreveable/mousetrapv1.1.0indirect
github.com/mattn/go-isattyv0.0.24indirect
github.com/munnerz/goautonegv0.0.0-20191010083416-a7dc8b61c822indirect
github.com/ncruces/go-strftimev1.1.0indirect
github.com/oapi-codegen/oapi-codegen/v2v2.8.2indirect
github.com/oasdiff/yamlv0.1.1indirect
github.com/oasdiff/yaml3v0.0.14indirect
github.com/prometheus/client_modelv0.6.3indirect
github.com/prometheus/commonv0.72.0indirect
github.com/prometheus/procfsv0.22.0indirect
github.com/remyoudompheng/bigfftv0.0.0-20230129092748-24d4a6f8daecindirect
github.com/sagikazarmark/locaferov0.11.0indirect
github.com/santhosh-tekuri/jsonschema/v6v6.0.2indirect
github.com/segmentio/asmv1.1.3indirect
github.com/segmentio/encodingv0.5.4indirect
github.com/shirou/gopsutil/v3v3.21.5indirect
github.com/sourcegraph/concv0.3.1-0.20240121214520-5f936abd7ae8indirect
github.com/speakeasy-api/jsonpathv0.6.3indirect
github.com/speakeasy-api/openapiv1.24.0indirect
github.com/spf13/aferov1.15.0indirect
github.com/spf13/castv1.10.0indirect
github.com/subosito/gotenvv1.6.0indirect
github.com/tklauser/go-sysconfv0.3.4indirect
github.com/tklauser/numcpusv0.2.1indirect
github.com/vmware-labs/yaml-jsonpathv0.3.2indirect
github.com/yosida95/uritemplate/v3v3.0.2indirect
go.yaml.in/yaml/v3v3.0.6indirect
golang.org/x/sysv0.49.0indirect
golang.org/x/telemetryv0.0.0-20261010193011-f71dc92da45eindirect
golang.org/x/timev0.15.0indirect
golang.org/x/toolsv0.52.0indirect
golang.org/x/vulnv1.9.0indirect
google.golang.org/protobufv1.36.12indirect
gopkg.in/yaml.v3v3.0.1indirect
modernc.org/libcv1.79.0indirect
modernc.org/mathutilv1.7.1indirect
modernc.org/memoryv1.12.1indirect
web/package.json scp-web (35 dependencies)
NameVersionScope
@plausible-analytics/tracker0.4.7runtime
@tanstack/react-query5.106.1runtime
next16.4.5runtime
openapi-fetch0.17.0runtime
react19.3.1runtime
react-dom19.3.1runtime
react-markdown10.1.0runtime
remark-gfm4.0.1runtime
server-only0.0.1runtime
@axe-core/playwright4.14.0dev
@eslint/js10.0.1dev
@playwright/test1.65.0dev
@tailwindcss/postcss4.3.5dev
@testing-library/dom10.4.2dev
@testing-library/jest-dom7.0.1dev
@testing-library/react16.3.3dev
@testing-library/user-event14.6.8dev
@types/node26.6.6dev
@types/react19.3.0dev
@types/react-dom19.3.0dev
@typescript/nativenpm:typescript@7.0.2dev
@vitejs/plugin-react6.2.1dev
eslint10.14.0dev
eslint-plugin-react-hooks7.1.1dev
globals17.14.0dev
jsdom31.0.0dev
msw3.0.4dev
openapi-msw2.1.1dev
openapi-typescript7.13.0dev
prettier3.9.10dev
tailwindcss4.3.5dev
typescriptnpm:@typescript/typescript6@6.0.2dev
typescript-eslint8.72.1dev
vite8.3.6dev
vitest5.1.0dev

Health

Health 100Good

Nothing costs it points.

Technology

Up to date
Languages
GoTypeScript
Build tools
Go modulespnpm
Toolchains
go 1.27.4node >=24.22.0

Pull requests

Up to date

None open.

Issues

Up to date

1 open: Needs triage 1

  1. Dependency Dashboard

    Needs triage, waits for a maintainer to look at it#2renovate[bot] (automation)idle

Releases

Up to date
  1. v2.2.14 by github-actions[bot] (automation)
    Release notes

    Changelog

    • 3d028599f336be55c71d65142640bfb0ba7dd942: fix(snapshot): hide groups that hold no repository the viewer can see (P-112) (#81) (@oranheim)
  2. v2.2.13 by github-actions[bot] (automation)
    Release notes

    Changelog

    • fa8b0603724c0636c854a06edbbdc926fed3f195: feat(catalog): a retired repository leaves its product for the Archive (#79) (@oranheim)
  3. v2.2.12 by github-actions[bot] (automation)
    Release notes

    Changelog

    • 194610e972312e5c4090fd2782479a97ad1072e3: feat(enterprise): GitHub Enterprise and Entra ID, and the enterprise mode with each person's own access (EN1 to EN8) (#77) (@oranheim)
  4. v2.2.11 by github-actions[bot] (automation)
    Release notes

    Changelog

    • 197e048ae1280571e01717a49032e1dbba50c5c3: feat(web): a theme for a deployment: colour tokens, logo, favicon and name from files (TH1) (#73) (@oranheim)
  5. v2.2.10 by github-actions[bot] (automation)
    Release notes

    Changelog

    • f9be1802cb54adadf25b5fdd2e07e90b55c51834: feat(dev): repeatable upgrade and rollback rehearsal; one way of working for everyone (#59) (@oranheim)
    • a53108169ded98407a3acf1e04e5750981470bc8: feat(forks): forks on demand (FK1 to FK3) (#68) (@oranheim)
    • 6d2cdf34100ca268e99fa1e681c31d6c3c69c567: feat(personal): an Events step makes a GitHub App per account (EV3) (#57) (@oranheim)
    • b520d9e61b738b614a691f91c1cb4d63db85f74a: feat(personal): first run in the browser, repositories sorted into products (PE3) (#51) (@oranheim)
    • ceac52307ad459f4ba47ba0b8a95120ec6080707: feat(personal): products by drag and drop with calculated rules, progress for long work (PE4) (#54) (@oranheim)
    • 97c5506496f8ac399e2630eec810919de3701ab9: feat(personal): scp personal, the personal edition's wizard, vault and loopback portal (PE1) (#49) (@oranheim)
    • 64e472f0425b9a5c4c3d1f9654ffd1aeee74eac2: feat(personal): sign in with the GitHub CLI's login on the first-run page (#52) (@oranheim)
    • b0f2b8d79c75b28b04d675829112330c989ba591: feat(personal): what is yours on the pull request and issue lists (PE2) (#50) (@oranheim)
    • 1f83167fbba121e6132e7046ad1add0115806dac: feat(releases): release notes on the releases page and the repository and product panels (#47) (@oranheim)
    • dfa0f0b4b91ab0a8a990f0e9dc915598fe8e0a1b: feat(security): the hardened profile's last gaps (H2): audit counter, opt-in verified email, route coverage (#65) (@oranheim)
    • df6e0ee8549be8ec9091b2c31b9e2ae91ee803d5: feat(store): layouts and announcements live in SQLite; a killed instance comes back whole (SQ1) (#62) (@oranheim)
    • 1d5a2dfd187a9dc26ec276cfcab590cfad934ee3: feat(store): migration 0002 with a copy first, repository visibility, one owner for an address (SM-a) (#48) (@oranheim)
    • 8c0b30b2f4269871e6554043752c4c090f961e36: feat(store): one baseline schema marked SCP1; earlier generations are moved aside (SC1) (#69) (@oranheim)
    • ef4ca768488d623e7ffaf212cf10b9f2d5091e7b: feat(sync): a mode per source and a cadence per subject (EV2) (#56) (@oranheim)
    • 20d309c464ce58deb3abf54953711206790bd906: feat(sync): a push to another branch and deleted refs reach the history and the tags; releases of an unlogged source read every 30 minutes (EV5, issue 5) (#67) (@oranheim)
    • 915b77fc677dfedf1ee08e65eca4abf0f483e0d1: feat(sync): the delivery log is read to its end or said to be cut; the status shows each log (EV4, issue 5) (#66) (@oranheim)
    • ee21619a34df14b88077c9e19ee1d413eec2300a: feat(webhook): read the App's delivery log without a receiver (webhook.catch_up) (EV1) (#55) (@oranheim)
    • 8cbde75587fdbbc6c7bc6d89028053e8e49c13af: fix(security): shared site isolation tests, neutrality guard, and the review's three low findings (#63) (@oranheim)
    • 4f56d8347e805467d6024f144b9720dbbe7f585b: fix(setup): one entry per repository name, unique product names, clearer count (#53) (@oranheim)
    • 4bc1df308f9d92010f62c656dcd3a07d08f680f1: fix: the review's findings since v2.2.9 (store mode, credential delete, releases, tags, stream, host) (#70) (@oranheim)
    • 8a80277d351ff7096b22998849646331860f2c0f: refactor(ghlogin): GitHub's calls through the libraries (GL1); feat(security): the modes are kept apart (ML1) (#64) (@oranheim)
  6. v2.2.9 by github-actions[bot] (automation)
    Release notes

    Changelog

    • a7482daee0fc52f78334f065ece3ada36b20d581: feat(web): filter panel, one row layout, packages in releases (#45) (@oranheim)
  7. v2.2.8 by github-actions[bot] (automation)
    Release notes

    Changelog

    • 5e6712df1d5a725781974eaaab0e7c8f9637b70b: feat(insights): graphs; rename Alumni to Archive (#44) (@oranheim)
  8. v2.2.7 by github-actions[bot] (automation)
    Release notes

    Changelog

    • 7855ff0d2ec0ad12f39b57d40bb3b31d152ea707: Merge pull request #36 from Cantara/feat/releases-insights-alumni (@oranheim)
    • c03e60c56a87aa8c3ecc7f07372336a8a672145b: feat(alumni): list the retired repositories through GET /api/v1/alumni (@oranheim)
    • 0d2f14a4ac0d1d5cf79cfcdb9796eff4fe600aae: feat(alumni): the /alumni page, its sitemap entry, docs and tests (@oranheim)
    • a62f812da858c0dc5a155083beacfc215beebb1a: feat(insights): five insights derived from the snapshot (IN1, IN2); faster leak and twin tests (#40) (@oranheim)
    • a247dbfdac1216aa54b4a7171307fe947a15225f: feat(releases): panels on a repository's and a group's page; the group's retired link (RL3, AL2) (#39) (@oranheim)
    • 803ec330ac9ee3d8dcd3e5fa55a789b5d45b0da9: feat(releases): the recent releases of the fleet (RL1, RL2) (#37) (@oranheim)
    • 82b5512c2a5402d4a04dea8f9278e3b1e340c5f7: feat: releases and retired repositories for agents, search and llms (RL3, AL2) (#38) (@oranheim)
    • 418d868c82d7c96dc846e9a8654a73b70874a8f0: fix(insights): name each month and write the count over its bar; narrower tables (#42) (@oranheim)
  9. v2.2.6 by github-actions[bot] (automation)
    Release notes

    Changelog

    • e7f3ea592650ed5cb892685b85c2f487e8315bf0: Merge pull request #34 from Cantara/chore/deps-round-3 (@oranheim)
    • 4413827da08c1df5b586545d9a82a96a94c6b671: Merge pull request #35 from Cantara/chore/release-2.2.6 (@oranheim)
  10. v2.2.5 by github-actions[bot] (automation)
    Release notes

    Changelog

    • a0eaeaeba128d56c0fc101caa38858cdf881ea93: Merge pull request #18 from Cantara/refactor/review-1 (@oranheim)
    • 63e3f802db5824d88c08c8991786a61bee4a9f7d: Merge pull request #19 from Cantara/refactor/review-2 (@oranheim)
    • 53249e0d7e968635029a3dbc5f486ba05a6c5985: Merge pull request #20 from Cantara/refactor/review-3 (@oranheim)
    • be15b4a32267f613a7445e7b117b044f0a8bfa01: Merge pull request #21 from Cantara/review/go-core (@oranheim)
    • 2d1ba8c1995e81e68c2f6d4fbcf63603ca933437: Merge pull request #22 from Cantara/review/go-features (@oranheim)
    • a4280ec75ee84fb64949116ae0b7f0989020ba3b: Merge pull request #23 from Cantara/review/web-shared (@oranheim)
    • a9c566f849c593d1618ec698f885689009166f4d: Merge pull request #24 from Cantara/review/web-features (@oranheim)
    • e08203fd0e73fdbe11b16adc06aa3e5ccb060ada: Merge pull request #25 from Cantara/review/majors (@oranheim)
    • b5b99291cd667a454d0c7605653fbf561374db0f: Merge pull request #27 from Cantara/review/regressions (@oranheim)
    • ab05b95fab655c55fe80a0c1fa408f20001ec43f: Merge pull request #28 from Cantara/fix/event-confirm (@oranheim)
    • 4cb02bc832504ce3902ff0757edb27d0c6416f18: Merge pull request #29 from Cantara/feat/durable-webhooks (@oranheim)
    • 362ed43d8754904f2aa821359cc18a66e9e71bf5: Merge pull request #3 from Cantara/haah/analysis-2026-10-14 (@oranheim)
    • b566a0fd321f4d930c20e2b6c748916b33fed8c5: Merge pull request #30 from Cantara/docs/guide-screenshots (@oranheim)
    • 74affb88a4920aa21a412452cb9f8c7590100edd: Merge pull request #31 from Cantara/chore/tooling (@oranheim)
    • 5c628795c43005a178bd7a0c4716448f41551f49: Merge pull request #32 from Cantara/chore/deps-renovate-2 (@oranheim)
    • 9550107edc1cbe0e7a86cabe5872149647c53e7d: Merge pull request #33 from Cantara/chore/release-2.2.5 (@oranheim)
    • 529c98b5d6ed7408c5838bc3839b219692b9a137: chore(renovate): TypeScript stays on 6 for the tooling API and on 7.0 for tsc (@oranheim)
    • d475750619752c78fc340daffede3af2873d67dc: chore: complexity ceilings, a pre-commit hook, one golangci-lint version (@oranheim)
    • 96152df59beef1be52f7ea27d49659028b5151fe: feat(webhook): a delivery is not lost: parked before the answer, replayed at the start, read from the App's delivery log (@oranheim)
    • 716c91db5cce15a6e71c0e03bd1c25f57ae54796: fix(auth): a renewed old session keeps when it was first issued (@oranheim)
    • efcdfa928321317c36521a44770a4142baf3c4eb: fix(auth): a sign-in ends sessionMax after it began, however it is renewed (@oranheim)
    • c8acdd38122dddc88ad1a752c2c5a41c22452bb5: fix(auth,assistant): email_verified given as a string; the keep-alive ping ends before the handler returns (@oranheim)
    • 953c5bb3407376a9827f62ea65a4ad80bc85b673: fix(cluster,filestore,jsonstream): no lead on an unread state map; a transient read error clears; a surrogate keeps its neighbour (@oranheim)
    • 73e487b8eb01cb922f4556b380989b9ce3f019c1: fix(github,lru): the conditional cache is keyed by credential and bounded by bytes; the LRU counts every value (@oranheim)
    • 4a921400a6e1280b1dbdca1c3cd50e1a6f0f5b77: fix(llms): the sitemap is built once per snapshot, the origin filled in per request (@oranheim)
    • ab5501b5e8a59a229e8e26ef3f7e212fbad478c6: fix(snapshot): an index whose builder panics keeps its last good value; the batch is published (@oranheim)
    • 6ff149f70fffa9286d6fee51ee978b6c79752ae7: fix(snapshot): an index with nothing to keep fails the build, as before (@oranheim)
    • 6332d4c4fc2edaf09efad057360f6089ac164355: fix(untrusted): the format characters that are written stay (@oranheim)
    • a35951806f0ad7b3bcb818d561f8089e16ef4ec9: fix(untrusted,tools,httpapi): every format character is stripped; schemas Check would skip are refused; one origin computation (@oranheim)
    • 4db59194d1c1f4178d35b7f78bcaac1bf883dd5b: fix(web): shared pieces and the review's small defects (@oranheim)
    • 3c601cd1216943cf25076ea4d15f66a4f8219720: fix(web): the features review's findings (@oranheim)
    • 507466c5e4593c8a628f98ce28c92e1c51bc5242: fix(webhook): a parked event goes when its jobs have run; the parking write is synced; a confirming read only when the first found nothing new (@oranheim)
    • 52773d7eace970198273e62d82753844d0734261: fix(webhook): only large deliveries wait for a slot (@oranheim)
    • d5d005bd6a48ba59a20480069e45af9bac4e398e: fix(webhook,llms,packages): bounded bodies held, no shared cache for Host-derived files, bounded registry hosts (@oranheim)
    • 968c31b1157769f3f115a97abcc03c0ea7b2e689: fix: new issues and pull requests show without waiting for the poll (@oranheim)
    • 9ddab7dbdd692ad3e07d510f68d1cd0277a02935: fix: the media type is checked first again; the sitemap keeps the last origin filled; the cache key needs a credential; comments and changelog (@oranheim)
    • 89baa6b43cc24543ed5443f0f8157c274e3a6a5d: perf(web): refresh once per 15 s, keep /me, no prefetch on dense links, read page 2 only when near (@oranheim)
    • f64b9b67fcb6a3b907c6d0a70a542ee57be9072c: refactor(api): one scope package for the commits, pull requests and issues listings (@oranheim)
    • 9417b25f14840e141d0094031c7769064b4bd881: refactor(dashboard): one section shell for the pull requests and the issues; changelog (@oranheim)
    • 5e7c7d3377e57c0dac4ae9b24916cbdcb873bca2: refactor(lru): one typed LRU cache for the GitHub transport, the package registries and the image proxy (@oranheim)
    • 78b61ed5047c7155d7f1598bee8901ec01755143: refactor(packages,badges): no release is an explicit error, not nil, nil (@oranheim)
    • 248f284a245db3070668bda7475dee881a5c6ca2: refactor(present): split the presentation page into its screen, status, stream and controls (@oranheim)
    • 9783ad97bc7fc0cc6eb097db4e5f969df574d830: refactor(scp): the repository hooks in order, not by index; changelog (@oranheim)
    • 70d3f70a472facbfeaced5719c8de2ded13b6378: refactor(web): one paging hook for the commits, pull requests and issues lists; one repository queue panel (@oranheim)
    • 601c4178ae686b0e36767a9c1f5652a89ea8cede: refactor(web): shared product and repository filter fields, one tile title (@oranheim)
    • 152bd33e7da7bf70711eccd6242ae06b11beeadf: refactor: one portal origin, one JSON body reader, one label type (@oranheim)

    The notes are cut here. Read all of them

All 17 held

Latest commits

Commit log

Documentation