# Oxygenhub — Specification | | | |---|---| | **Status** | Draft 0.1 | | **Scope** | A self-hosted forge for Oxygen repositories: hosting, browsing, review, issues, releases, an HTTP API and webhooks, and the integration point for a runner. It works like GitHub where GitHub is right and differs where the commutative model makes something better possible. | | **Depends on** | `oxy-core` and `oxy-server` from the Oxygen workspace (spec Draft 0.8b); `oxy` clients speaking wire protocol version 1 | | **Companion documents** | `docs/runner.md` (Oxygen Runner, later), `docs/deploy.md` (developer edition on Earth) | | **Date** | 2026-09-27 | | **Audience** | Implementers, security reviewers, and the person who runs it | The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described in RFC 2119. --- ## Table of contents 1. [Goals and non-goals](#1-goals-and-non-goals) 2. [How it compares with GitHub](#2-how-it-compares-with-github) 3. [Architecture](#3-architecture) 4. [Repositories on the server](#4-repositories-on-the-server) 5. [Accounts, identities and authorization](#5-accounts-identities-and-authorization) 6. [Web interface](#6-web-interface) 7. [Proposals and review](#7-proposals-and-review) 8. [Issues](#8-issues) 9. [Releases and tags](#9-releases-and-tags) 10. [Notifications](#10-notifications) 11. [Search](#11-search) 12. [HTTP API and webhooks](#12-http-api-and-webhooks) 13. [Checks and OxygenFlow](#13-checks-and-oxygenflow) 14. [Git interoperability](#14-git-interoperability) 15. [Security](#15-security) 16. [Performance and caching](#16-performance-and-caching) 17. [Operations: configuration, storage, backup](#17-operations-configuration-storage-backup) 18. [Required changes to Oxygen](#18-required-changes-to-oxygen) 19. [Milestones](#19-milestones) 20. [Open questions](#20-open-questions) 21. [Changelog](#21-changelog) --- ## 1. Goals and non-goals 1. **Work like GitHub.** A developer who knows GitHub must find repositories, history, diffs, review, issues, releases, tokens and webhooks where they expect them, with the same words where the words still apply. The learning curve is Oxygen's model, not the forge. 2. **Show what the model makes possible.** Multiple heads, reified conflicts, exact blame, signatures and trust policy, proposals that never go stale, review comments that survive rebases, and approvals that are portable signed objects. Each of these is a first-class page, not a footnote. 3. **One binary, one directory.** `oxygenhub serve` links `oxy-core`, embeds the wire protocol server, renders its own pages, and keeps everything under one data directory with SQLite for hub state. A backup is a copy of that directory. There is no separate database server, job queue, cache server or front-end build. 4. **The repository is the source of truth.** Everything about code, history, references, signatures and policy lives in the Oxygen object store and is readable with `oxy` alone. Hub tables hold only what Oxygen has no object for: accounts, sessions, issues, review threads, webhooks and check results. Deleting the hub database loses discussion, never history. 5. **Off the shelf where it is not the product.** Markdown editing uses EasyMDE, in-browser code editing uses CodeMirror 6, syntax highlighting uses syntect, Markdown rendering uses pulldown-cmark with ammonia sanitising. The hub's own code is the forge logic and the pages. 6. **Honest state.** A page never shows something the object store does not say. A signature is shown as verified only when the hub verified it against policy; an approval is shown only when the approving seal exists. Non-goals for 1.0: hosting Git repositories natively (§14 covers mirrors), a marketplace, wikis, project boards, discussions, GitHub Pages, and federation between hubs. The runner is specified separately (§13, `docs/runner.md`) and is not required for 1.0. ## 2. How it compares with GitHub | GitHub | Oxygenhub | Why it differs | |---|---|---| | Repository, owner, organisation | Same | — | | Branch | **Bookmark** | An Oxygen bookmark names a set of heads, not one commit | | Commit | **Change** | Changes commute; a change has dependencies, not a parent | | Commit page shows one parent diff | Change page shows the change's own edits, its dependencies and its dependents | The diff of a change is intrinsic; it is the same on every bookmark that contains it | | Merge, merge commit, rebase before merge | **Landing**: add the proposal's changes to the target bookmark | Union of heads; no merge commit; the result is computed before landing, so CI runs on exactly what lands | | Pull request "out of date with base branch" | Never happens; a proposal stays valid as the target moves | Changes commute unless they conflict; a new conflict is shown, not a stale flag | | Merge conflict blocks the PR until the author rebases | Conflict is a reified part of the resulting state; the proposal page shows the exact sides, and any collaborator may push a resolution change | Conflicts are values in the model (spec §9) | | Review comment on a line, goes "outdated" after a force-push | Review comment anchored to an **atom** `(ChangeHash, index)`, follows the line through rebase, squash and split | Atoms are stable identities; rewrites record correspondences | | Approval is a database row | Approval is a **seal** attestation signed by the reviewer's key, stored in the repository | Verifiable offline and after export; survives hub loss | | Required status checks on a commit SHA | Required checks on a **state hash** | A state is content addressed, so a green check on the pre-landing state is exactly the check on the post-landing state | | Branch protection rules | The repository's **trust policy** (spec §14.5), edited through signed proposals | One authority for who may update a reference, enforced identically by every client and server | | Signed commits as a badge | Signature and seal status on every change, with the policy rule that admitted it | Signatures are the protocol, not an add-on | | Tags and releases | Tags are signed attestations; releases attach notes and assets | — | | Actions | Runner (§13), later | Designed from the failures of Actions and GitLab CI | | Fork and PR from a fork | Fork, and proposals from a fork or from a bookmark in the same repository | Same | | Issues, labels, milestones | Same, smaller | — | | Personal access tokens | Same, scoped | Push also accepts the client's identity signature (§5.4) | | Webhooks with HMAC | Same | — | | REST and GraphQL APIs | JSON REST only | — | ## 3. Architecture ### 3.1 One process `oxygenhub` is a Rust binary in its own Cargo workspace at `../oxygenhub`, depending on `oxy-core` and `oxy-server` by path (developer edition) or by version (release). It runs one tokio runtime with: - an axum router serving pages, static assets, the JSON API, and the wire protocol under every repository's path; - askama templates compiled into the binary; one hand-written stylesheet, also compiled in and served at `/style.css`; - SQLite through `sqlx` (WAL mode, `synchronous=NORMAL`, foreign keys on) for hub state, opened from `/hub.db`; - a small background worker pool (tokio tasks) for webhooks delivery, notification email, search indexing, Git mirror export and cache warming; - an in-process cache (§16). There is no separate front-end build. JavaScript is limited to: the theme cookie, EasyMDE (Markdown editing), CodeMirror 6 (file editing), and small progressive enhancements (history graph hover, keyboard shortcuts, live check status). Every page MUST render and every form MUST work with JavaScript disabled, except the two editors, which degrade to a plain `