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

johnandersen777.bsky.social/knotless-fork-infra

0
0
main
128 lines · 8.4 KB Raw History
# knotless: runs on an atlibs composition

A knotless repository picks an **atlibs composition**; `knotless-run` runs the repo's CI on it:
rent a VM on the socialweb.computer market → check out the commit → run the steps → release.

Status 2026-11-10: **works end to end, live**, on atlibs 0.3.0.

## Where

| What | Where |
|---|---|
| Deployed | https://knotless.socialweb.computer (serve + pages), https://knotless-runner.socialweb.computer (runner, per-composition OAuth); deploy: this repo |
| Runner + Executor UI | fork `johnandersen777.bsky.social/knotless`, branch `runner-atlibs-composition` @ `b1d515dd` (25 commits on upstream `main`, atlibs-host v0.5.0; deployed; fork only, no PRs) |
| Design + decisions | that branch: `docs/design/atlibs-compositions.md` |
| The composition | `bobvmbuilder.bsky.social/socialweb-computer-cicd` |
| Its source | `atlibs-socialweb-computer-requester`: `compositions/socialweb-computer-cicd.compose.ts` → committed `composition.json` |
| Scratch experiment | branch `runner-socialweb-computer` (kept, not developed) |

```bash
git clone https://knotless.dev/johnandersen777.bsky.social/knotless
git -C knotless checkout runner-atlibs-composition
less knotless/docs/design/atlibs-compositions.md
```

## How a run goes

```
push → knotless-run
  getRecord com.fedfork.exec.binding/<repo key>  (else /self)   ← the owner's binding, pinned by CID
  trust check: composition + every module publisher ∈ --trust-publisher
  load composition at its CID (atlibs-host, in process, Rust)
  prepare (once per owner) → vm.provision → workload.run (checkout + steps via the process contract) → vm.release (always)
  → dev.knotless.check  success | failure
```

## The composition (atlibs 0.3.0)

```ts
// compositions/socialweb-computer-cicd.compose.ts (excerpt)
const machine = c.instance("machine", requester, {
	session: "requester",
	input: { bidders, kind: "vm", cpus, mem, ssh_key: host("sshPublicKey"), shell: true, iroh: true, via: "iroh", release: false },
});
const workload = c.instance("workload", cicdWorkload);
for (const step of ["start", "write", "read"] as const)
	c.route(workload, `computer.socialweb.cicd.process.${step}`, process_, `the job's ${step} on the VM`);

c.export("computer.socialweb.vm.prepare", machine, "bind_key");
c.export("computer.socialweb.vm.provision", machine);       // the runner calls the exports
c.export("computer.socialweb.vm.release", machine);
c.export("computer.socialweb.cicd.workload.run", workload);
```

```bash
K=https://knotless.dev/johnandersen777.bsky.social
git clone -q $K/atlibs && git -C atlibs checkout -q 88b2ba8          # v0.3.0, the sibling compose.ts imports
git clone -q $K/atlibs-socialweb-computer-requester && cd atlibs-socialweb-computer-requester
node --test compositions/compose.test.mjs   # fails if a composition.json isn't what its compose.ts writes
atlibs compose check compositions/socialweb-computer-cicd.composition.json
```

Routes reach the target's `implements` (no `entry`); instance input is typed by `module.json` `config`.

## Bind a repository

Copy-paste block (validated): design doc § **Bind a repository**. Result:
`com.fedfork.exec.binding/<repo key>` in the owner's repo (an org's repo: the org's account; `self` = every repo).

Settings › **Executor** (repo or account) does the same from the UI.

## Live evidence

| Run | Push | VM | Result |
|---|---|---|---|
| first green (OAuth per composition) | `7ebc5c5` | hat-9 | steps ok; release bug → fixed |
| release fixed | `00df7b3` | hat-9 | success 59 s, `vm.terminated` on its own, records deleted |
| atlibs 0.3.0 model | `861f3813` | hat-9 | success 57 s, released, records deleted |
| final composition `bafyreiag5yjb…` | `ef96ee9f` | hat-7 | success 46 s, released, records deleted |
| deployed runner, composition `bafyreifzmo3b…` (requester `dab378f8`, user-data `c605eb61`) | `325f96d` | hat-7 | success 52 s, released (`fc-lpfuqerea3de-ed3fca28`), no round records in the owner's account |
| deployed runner `b1d515dd`, atlibs-host v0.5.0: `bafyreifzmo3b…` via its version record `socialweb-computer-cicd.bafyreifzmo3b…` | `ad0fc50` | hat-9 | success 53 s, released (`fc-lpfuqerea3de-8ca2adf2`), no round records in the owner's account |

Rows 1–4 as `aliceoa.bsky.social/kc-ci-test`, runner on hat-8; rows 5–6 as `aliceoa.bsky.social/kc-ci-demo` on https://knotless-runner.socialweb.computer.

## Decided

- NSIDs: `com.fedfork.exec.*` (atlibs, sandboxed: binding, composition); `computer.socialweb.*` (external compute: `vm.provision/release/prepare`, `cicd.process.*`).
- Rents with the **repo owner's own session** (they pay; their vouches count). OAuth **per composition**; app-password fallback.
- Binding lookup: getRecord at the repo key, then `self`. Never `listRecords`. Precedence: workflow > repo > account.
- Publisher allowlist (`--trust-publisher`, DIDs), compositions pinned by CID; default net denylist (loopback, link-local, metadata, private ranges).
- **Workload modules run the steps** over a generic process contract (`exec/start/read/write/kill/list`); MCP is only an adapter.
- The workload fetches the commit from the owner's PDS; private repos get a narrower read-only per-repo grant.
- In process Rust: `atlibs-host` + `atlibs-iroh` as rev-pinned crates; no Node, no CLI, no extra binary.
- One attestation key per **owner**, not per composition.
- Compositions are **written in code** (TS / Rust), JSON generated + committed (atlibs 0.3.0).

## Open

- Pulls / merge queue: refused (their merged commit is on no remote).
- OAuth session is per composition **CID**: a republish means signing in again (live runs used the app-password fallback after repins).
- Orgs that delegated before `c9b05996` must delegate again to bind (`repo:com.fedfork.exec.binding`).
- The runner doesn't log the release result; termination is seen in the bidder's log.
- ~~Runner deploy is manual~~: deployed as a systemd-managed container on the gateway (this repo).
- ~~`/oauth/bot` had no `repo:dev.knotless.runnerKey`~~: fixed in the fork (`6879ad7e`, bots only, no one else's login behind); a runner's client-side warn on the 25 s `awaitSpaceWrites` long poll fixed (`25b8fb0c`).
- Shots don't cover the Executor page's lookup view.
- Workloads can fetch only `iroh://` (covers the net denylist).
- Upstream: none (fork only, by policy).
- The runner image needs `dumbpipe` (0.40.1) and an `ssh` client: `atlibs-iroh` reaches a rented machine with them. The fork's Dockerfile ships neither; this repo's `Dockerfile` adds both.
- ~~The fork's `atlibs-host`/`atlibs-iroh` turn on `serde_json/preserve_order` for the whole workspace, so triage asked its questions in label order~~: fixed in the fork (`95899bec`, triage sorts with a `BTreeMap`; atlibs keeps its ordered maps). 
- ~~A merge right after a push or another merge said `<repo> has no branch <name>`~~: a single pull's reads (`Target::around`) took its state records (merged, retargeted) from the appview's index only, which hadn't heard of one written a moment before; they now also read the writers' newest state records, as the merge queue does (fork `f47f4e62`). Verified live: stacked `demo-low` → `demo-base`, then `demo-mid` (was on `demo-low`) merged right after it from the pages.
- With those crates beside it, rustls had both ring and aws-lc-rs and knotless-serve's Jetstream panicked: fixed in the fork (`ed991eb5`, ring picked in `Ctx::new`).

## Fork tests

`cargo test --workspace` alone fails ~100 tests, the same at the base: each test binary starts its own PDS with 32 accounts and the big ones run out (`index out of bounds: the len is 32`, then `PoisonError`). Run them as the Justfile does, against one shared PDS (Node 24, `.node-version`; `zoekt-webserver` on PATH for code search):

```sh
just pds &                      # harness/pds.mjs, accounts made as asked
just t --workspace --no-fail-fast
```

Code search and `binary_lifecycle` (which starts serve with `--code-index`) need zoekt at the Dockerfile's commit:

```sh
GOBIN=$PWD/.tools go install github.com/sourcegraph/zoekt/cmd/zoekt-git-index@e1fafb15177040d792bd7c8c41a24a0fb39aada4 github.com/sourcegraph/zoekt/cmd/zoekt-webserver@e1fafb15177040d792bd7c8c41a24a0fb39aada4
export PATH=$PWD/.tools:$PATH
```

On hat-8 at `f47f4e62`, that way: 733 passed, 0 failed; `forks_pulls_reviews_and_merges` and `merges_wait_for_their_checks` 10/10 (before: about 4/5 and 2/5 failing, the same at upstream `bc4a8cef`). CI runs them through `harness/cov.mjs` against the spaces alpha.