Claim a Namespace
Claiming a namespace is opening the PR that adds the firstp/<namespace>/<package>.json entry under it. There is no separate reservation step — the first accepted claim PR is the claim.
1. Pick a Namespace and Package Name
Read Namespace Policy first. In short: the namespace names a real identity (an organisation, business, or project), not a hosting location; it must fit the charset (^[a-z0-9](?:-?[a-z0-9])*$, 1–39 chars) and must not be on the reserved-segments list; the package segment follows the OCI repository-component grammar, ≤100 chars.
2. Write the Entry
Add p/<namespace>/<package>.json conforming to root.schema.json (field table: Entry Schema). At first claim you typically populate:
name—ocx.sh/<namespace>/<package>, matching the file's own pathrepository—oci://<host>/<repo path>of the physical mirrorowners— at least one{github, github_id}pairstatus—activedeprecated_message—nullcreated— today's dateupstream— required if the namespace names a real third-party vendor; omit only for OCX's own first-party namespacesdesc—nulluntil the bot's first announce/reconcile copies__ocx.desc, if the physical registry publishes onetags—{}if you are claiming ahead of the first announce, or populated byindexbot seed-importif this is a batch seed import
Open the PR. Do not hand-write tags[*].content/observed values — those are bot-regenerated fields; a claim PR that also wants an initial tag set populated should let an announce (or seed-import, for batch seeding) do that work, not encode digests by hand.
Multi-Owner Support
owners[] accepts more than one {github, github_id} pair. Every listed owner independently satisfies the machine-lane authorization check on that root (FP-5) — a PR from any one of them, refreshing or curating that package's tags, qualifies for auto-merge on its own. Co-maintained packages and org-owned namespaces should list every maintainer who should be able to auto-merge a refresh, not just the person who happened to file the claim.
This is also why github_id is mandatory alongside the login: it's the actual authorization key the machine lane checks against, not the login string. github_id is immutable and survives a username change or account rename; a login string is display-only and is never what an ownership check compares against.
3. Automated Checks
Two jobs run against the PR:
schema-validate(unprivileged, runs against your PR's own content): JSON Schema conformance viacheck-jsonschema, plus semantic checks —namematches the path-derived logical name (G-02),repositoryhost is on this index's registry-host policy (G-03 —ghcr.iohere), neither namespace nor package segment is on the reserved list, digest fields (if any) are well-formed.governance-gate(privileged, API-diff only, never checks out your PR's code): classifies the PR. A newp/*.jsonfile always gets thenew-packagelabel (G-04) and a redgovernance/review-requiredstatus — this never auto-resolves, regardless of how greenschema-validateis.
4. Human Review
A maintainer reviews the PR for:
- Namespace identity fit — does the claimed namespace plausibly belong to the entity it names? This is not automatable and is the reviewer's primary judgment call.
upstreamattribution present where the namespace names a real third-party vendor, with adisclaimerif the mirror is unaffiliated.owners[].github_idpresent (mandatory) alongside the login.- General entry sanity —
repositoryactually points at the intended physical mirror,statusisactivefor a new claim.
New-package PRs are never auto-merged, no matter how green the automated checks are — a human approval is required every time. This holds regardless of how many owners are listed in owners[]: multiple owners let any one of them auto-merge a later refresh (see Multi-Owner Support above), but a first claim is always human lane (G-04) — curated tags don't change that either.
After Merge
The namespace is now claimed and immutable — there is no rename primitive. Trigger your first announce to populate tags from live registry state (or rely on the nightly reconcile to pick it up).