Skip to content

Identifiers and Git URLs

Tangled names accounts, repositories and records with AT Protocol identifiers, and names commits and branches with ordinary Git identifiers. This page lists each form, what it points at, and when it changes.

git clone git@knot.example.com:alice.example.com/proj
git clone https://knot.example.com/did:plc:4kx2vqmn7d3rjzy5lbk6hq3c
IdentifierExampleNamesChanges when
Handlealice.example.comAn accountThe owner changes it
Account DIDdid:plc:…A user or organizationNever
Repository DIDdid:plc:…One repositoryNever, including renames and transfers
Service DIDdid:web:knot.example.comA knot, spindle or other serviceIts hostname changes
AT URIat://did:plc:…/org.tangled.track.ticket/3l…One recordThe record is deleted
CIDbafyrei…One version of a recordThe record changes
NSIDorg.tangled.track.ticketA record type or XRPC methodNever
Git object IDa1b2… (40 or 64 hex)One commit, tree or blobIts content changes
Git refrefs/heads/mainA branch or tagIt moves on push
Pipeline IDspindle-localOne CI run on one spindleNever; meaningless on another spindle

A handle is the readable name of an account and resolves to a DID. Records and permissions store the DID, so changing a handle does not rewrite anything. Web URLs accept either form: https://tangled.org/alice.example.com/proj and https://tangled.org/did:plc:…/proj show the same repository.

Users and repositories use did:plc. Knots and spindles use did:web derived from their hostname: a knot at knot.example.com is did:web:knot.example.com, and its DID document is served at https://knot.example.com/.well-known/did.json.

Every repository has its own did:plc, separate from its owner’s. The knot that hosts it mints it (or adopts one the client prepared with org.tangled.repo.reserveKey) and holds its rotation and signing key. Its DID document lists the knot as both #atproto_pds and #tangled_knot.

The repository DID is the stable handle for everything about the repository: its records, CI pipelines, secrets, webhooks and git mirror all key on it. The human name is claimed by the owner, under a slug that is the lowercased name:

  • The repository account holds org.tangled.repo.manifest/self with declaration: {owner, name}.
  • The owner’s PDS holds org.tangled.repo.declaration/<slug> with repo: <repoDid>.

A repository is only visible under owner/slug while both sides agree. Renaming changes the name, the slug and the declaration; the repository DID stays the same.

at://<account DID>/<collection NSID>/<record key>

The first segment is the account whose repository holds the record, which is not always the author. Issues, pull requests, comments, reactions, labels and patches live in the repository DID’s account on the knot, so their URIs start with the repository DID:

at://did:plc:repoxyz/org.tangled.track.ticket/3lzq4w5qk2c2a

The person who wrote such a record is in its x-tngl-editor field, stamped by the knot. Stars, follows, vouches, profiles and strings live in the author’s own PDS and start with the author’s DID.

Record key (rkey) rules depend on the collection:

RuleCollections
selfactor.profile, repo.manifest, git.refs
Repository slugrepo.declaration
Subject DIDgraph.follow, graph.vouch, graph.collaborator
The record’s own CIDreview.patch
TID, minted by the knottrack.ticket, feed.comment, feed.reaction written through the knot
TIDeverything else

Web URLs for issues and pull requests use the ticket’s rkey: /alice.example.com/proj/issues/3lzq4w5qk2c2a. There are no sequential numbers.

Records lists every collection.

New repositories on a knot use SHA-256 by default, so object IDs are 64 hex characters. Repositories migrated from the Go knot keep SHA-1 (40 characters). A SHA-256 repository can’t push to or fetch from a SHA-1 one. Don’t assume a fixed hash length in tools.

A knot serves each repository under two addresses: owner plus name, or the repository DID. The owner can be a handle or a DID.

Over SSH:

git clone git@knot.example.com:alice.example.com/proj
git clone git@knot.example.com:did:plc:alice/proj
git clone git@knot.example.com:did:plc:repoxyz

Over HTTPS:

git clone https://knot.example.com/alice.example.com/proj
git clone https://knot.example.com/did:plc:alice/proj
git clone https://knot.example.com/did:plc:repoxyz
  • A trailing .git is accepted on the name form (proj.git) but not on the DID form: did:plc:repoxyz.git won’t resolve.
  • The knot’s SSH listener defaults to port 2222. If the knot doesn’t listen on 22, use ssh://git@knot.example.com:2222/did:plc:repoxyz or a Host block in ~/.ssh/config.
  • The DID form keeps working after a rename; the name form follows the current slug.

SSH push authenticates with a key published in your PDS. If your agent offers several keys and the knot rejects them, add IdentitiesOnly yes for that host. HTTPS push takes a service-auth token bound to org.tangled.git.receivePack as the Bearer token or Basic password, supplied by a credential helper.

Knots don’t allow pushes to these namespaces. All of these are also not under ref advertisement, other than refs/cobs/* which can be fetched with an explicit refs/cobs/ ref-prefix, read only.

Ref prefixHolds
refs/cobs/*Collaborative objects: signed change graphs for collaborators, tickets, comments and more. Append-only.
refs/cob-checkpoints/*Knot-written COB snapshots.
refs/hidden/*Nothing. Legacy fork staging refs are deleted on boot; the prefix stays reserved.
refs/atproto/*The repository DID’s atproto commit chain, PLC queue and tombstones.

Push options pass through to the knot’s org.tangled.git.pushEvent (at most 10) and to spindle.

git push -o skip-ci origin main
OptionEffect
skip-ci or ci-skipSpindle does not start pipelines for this push. Push webhooks still fire.

Workflow Reference describes how pushes trigger pipelines.