~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

7
144 lines · 6.7 KB Raw History
# Design

How knotless works, and why it works that way. This page gives the goals,
the pieces and how they fit, and an order for reading the pages after it.
It assumes you know git, and roughly what atproto is: accounts that hold
records and blobs on a server of their choosing, their PDS.

## Goals

- Git in your own account. A repository is a few kinds of record in its
  owner's atproto account, and nowhere else. Nothing is installed on the
  PDS.
- Any stock PDS. Public repositories work against the reference PDS
  (`@atproto/pds`) as shipped, under its default limits. Private
  repositories also need the permissioned-data alpha of that PDS. On a PDS
  without it, every repository is public.
- Fast enough for agents. Every operation is planned around round trips to
  the PDS. A warm push takes two, and a fetch of a small push one. Writers
  on separate branches never contend. Writers pushing straight to one
  branch land one per round, so agents work best on a branch each, or
  commit through a gateway, which queues commits per branch.
- Git objects need no trust. Every object is named by its hash and checked
  by the reader that indexes it. This goal is only partly met: where a ref
  points is read from the owner's PDS and not yet checked against the
  account's signed commits.
- Cheap to run. One server binary does every optional job, on one small
  VPS.

## Non-goals

- Replacing git. Clients are plain `git` with a remote helper, or plain git
  smart HTTP for reads.
- A source of truth besides the PDS. `knotless-serve` keeps a cache that
  can be thrown away and read again. It is still needed for some jobs: a
  collaborator pushes through a gateway, and listing a public repository's
  pulls and issues takes an appview. Anyone can run either.
- A second way to write. The pages write as the account logged in to
  them (stars, follows, comments, opening, merging and queueing pulls,
  sharing), through the same code the CLI uses. A repository's content
  changes only through git, the CLI and agents.
- Running untrusted code by default. A runner checks a pull as it moves
  only if its author and its head repository's owner each write to the
  repository or are agents it names; an agent's runs get no secrets.
  Anyone else's runs only when the owner asks, and then once.

## The pieces

```mermaid
flowchart LR
  clients[git + remote helper,<br/>knotless CLI, knotless-mcp]
  subgraph pds[Owner's PDS]
    records[(dev.knotless.* records<br/>and pack blobs)]
    space[(Spaces:<br/>private repositories)]
  end
  others[(Other accounts' PDSes:<br/>pulls, issues, comments, checks)]
  jet[Jetstream or firehose]
  subgraph serve[knotless-serve, optional]
    gw[Gateway]
    cache[Mirrors and smart HTTP]
    index[(Appview index)]
    web[Web pages]
  end
  run[knotless-run]

  clients -->|owner reads and writes| records
  clients -->|collaborators write| gw
  gw -->|writes as the owner| records
  clients -->|each writes their own| others
  records & others --> jet
  jet --> cache & index
  jet -->|doorbell| run
  records -->|refs| run
  run -->|checks| others
  cache & index --> web
```

`knotless` is the CLI and the git remote helper (`git-remote-knotless`), in
one crate. It talks to PDSes directly, with no server in between. The owner
writes their own records. Everyone else writes pulls, issues, comments and
states into their own accounts, and pushes to the owner's repository
through a gateway.

`knotless-mcp` offers the CLI's operations to agents as MCP tools over
stdio. Writes go through the same code as `knotless commit`, `fork`, `pull`
and `merge`. It acts as the logged-in account, or as `KNOTLESS_IDENTIFIER`
with `KNOTLESS_PASSWORD`. A public `knotless-serve` offers the same tools
over HTTP at `/mcp`, to any account that signs in with atproto OAuth,
unless the operator refuses it, as one taken down.

`knotless-serve` is one binary with several optional jobs: a read cache, an
appview that indexes records across accounts, a gateway, a moderation
service and the web pages. It follows Jetstream or the firehose, the public
streams of record changes, to know when to sync.

`knotless-run` runs workflows when a ref moves or a pull changes, and lands
merge queues. A stream event only tells it which repository to read again
from the owner's PDS. It writes each run as a check record in its own
account.

`knotless-triage` triages issues: a classifier chooses their labels, and
it writes them as label records in its own account, which count once the
owner names it a triager (see [Labels](collaboration.md#labels)).

`knotless-agent review` reviews the pulls that ask its account for one:
a command, Claude Code by default, reads each, and it writes the review
as its own comment, which counts as advice and never toward a branch's
required reviews (see [Review agents](collaboration.md#review-agents)).

## Constraints

knotless runs against the reference PDS as shipped, and that PDS's limits
shape the rest of the design. It has no locks and no per-record
compare-and-swap, so each ref gets one from create-only claim keys. Only an
account writes to its own records, so collaborators need a gateway. Blob
size, request size, writes per call and rate limits decide how packs are
stored and pushes are batched. [What a stock PDS
offers](storage.md#what-a-stock-pds-offers) has the table of limits and
what each one forces.

## Reading order

1. [How repositories are stored](storage.md): which records hold a
   repository, and how push, fetch and compaction work within a stock PDS.
2. [Naming and identity](identity.md): what identifies a repository, and
   how renames, transfers and commit authors work.
3. [Access](access.md): how knotless logs in, what it asks for, and how
   private repositories are kept and read.
4. [Gateway](gateway.md): how a collaborator writes to an account that is
   not theirs, and how branches are protected.
5. [Collaboration](collaboration.md): how pulls, issues, states, merges,
   forks and moderation work when each person writes to their own account.
6. [knotless-serve](serve.md): what the optional server's cache, appview,
   moderation and web pages do, and how fresh they are.
7. [The runner](runner.md): which workflows run, when, in what order, and
   with which caches and secrets.
8. [Shared steps](reusable-workflows.md): how a workflow uses steps
   another repository publishes, pinned so they cannot change under it.
9. [Merge queue](merge-queue.md): how queued pulls are checked and landed
   together in batches.
10. [Releases](packages.md): how a repository publishes versions of a
    package, as records that never change.
11. [Integrity and trust](security.md): what each party can and cannot do.
12. [Prior art](prior-art.md): what came before, and what knotless takes
    from it.