sublayer / manual / identities

identities and forges

who is who on gitea, on GitHub, on Cairn and on the queue, and which forge a change goes to

Every action on the station is taken by a named identity, and the name is what makes the record readable afterwards. There are two forges, and which one a change goes to is decided by where the issue lives, not by which is easier to reach.

On gitea

The private forge at gitea.sublayer.space on the tailnet, loopback port 3000 on the box. Every repo the station works on is here, under the abrahms owner.

userwho
abrahmsJustin, the operator
zathras, ivanova, franklinthe agents, one user each. Their commits, pull requests and reviews carry their own byline
cybrahmsthe identity an attended session commits as when it acts on the operator's behalf

Each agent authenticates with the forge token in its env, through a credential helper in its own git config that is selected by GIT_CONFIG_GLOBAL. The forge command reads the same token and works out the forge and the repo from the git remote, so there is no config file to keep in sync.

Three things forge knows that the API does not say, and the reason to use it instead of curl:

  • "Please try again later" on a merge usually means the branch cannot merge; forge reads the mergeable flag instead of believing the message.
  • A closed pull request and a merged one answer differently, and forge's exit codes tell them apart: 3 cannot merge, 4 checks failed, 5 timed out, 6 closed without merging.
  • What CI is doing for a pull request is a question about its head commit, and forge checks asks it that way.

On GitHub

The station has exactly one GitHub identity, cybrahms. The gh tool on the box is logged in as it, and an agent's git config carries a credential helper for github.com that is pinned to that account, so a push to GitHub is always cybrahms whatever account happens to be active.

cybrahms has no push access to the operator's repositories. A pull request there is the fork flow:

GH_TOKEN=$(gh auth token --user cybrahms) gh repo fork justinabrahms/<repo> --clone=false
git remote add fork https://github.com/cybrahms/<repo>.git
git push fork <branch>
GH_TOKEN=$(gh auth token --user cybrahms) gh pr create --repo justinabrahms/<repo> --head cybrahms:<branch>

with Fixes #N in the body so the issue closes on merge.

An attended session that commits on the operator's behalf uses the cybrahms git config as well: GIT_CONFIG_GLOBAL=~/agents/cybrahms/gitconfig. It signs with cybrahms's own GPG key, kept under ~/agents/cybrahms/, and never with the operator's signer. Nothing agentic goes through the operator's keys.

Which forge a change goes to

  • A repo that lives on gitea and nowhere else: a pull request on gitea. The reviewer is rung, CI runs, a green merge deploys.
  • A repo that originated on GitHub carries its GitHub URL as the gitea repo's origin, and there is no push mirror from gitea back to GitHub: the gitea copy is synced by hand. So a fix for an issue that lives on GitHub goes to GitHub, as cybrahms, and the gitea copy catches up when the operator syncs it.
  • Never both. Two open pull requests for one change is a mess someone has to clean up.

On Cairn

Every agent has a Cairn token in its env, and the artifacts it creates are owned by the operator, recorded as "on behalf of" the client that made them. The actor on an artifact is authenticated; the on-behalf-of string is the client's own report of itself and proves nothing.

Tags on an artifact are what the queue routes on; handoff is the one that rings zathras. Tags are never provenance: they say what the creator wants, not who they are. Links expire; the todo result that carries the link is the durable record, and the expiry is printed on every create.

On the queue

Each agent is one Switchboard endpoint, with its own bearer token and its own MCP URL in its crush.json. The endpoint's tool list is its grant: a tool it cannot see is a verb it may not use, which is why the reviewer cannot list webhooks and the worker can. Cairn is the opposite, showing every tool and refusing the ungranted ones on call; do not carry either rule across to the other.

An endpoint's queue grant is the set of queues it may claim from. zathras holds inbox and reviews; ivanova holds reviews; franklin holds his own inbox. The webhooks are all zathras's, fanning out to the others by rule.

Attended sessions

A person working with an agent in a terminal is not one of the crew and should not borrow a crew member's name. It picks a callsign of its own for the session, commits as cybrahms when it commits on the operator's behalf, and hands work to an agent with sbpush rather than doing it under the agent's identity.