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

johnandersen777.bsky.social/knotless-fork-infra

0
0
main
119 lines · 7.2 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

WhatWhere
Deployedhttps://knotless.socialweb.computer (serve + pages), https://knotless-runner.socialweb.computer (runner, per-composition OAuth); deploy: this repo
Runner + Executor UIfork johnandersen777.bsky.social/knotless, branch runner-atlibs-composition @ ed991eb5 (22 commits on upstream main; fork only, no PRs)
Design + decisionsthat branch: docs/design/atlibs-compositions.md
The compositionbobvmbuilder.bsky.social/socialweb-computer-cicd
Its sourceatlibs-socialweb-computer-requester: compositions/socialweb-computer-cicd.compose.ts → committed composition.json
Scratch experimentbranch runner-socialweb-computer (kept, not developed)
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)

// 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);
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

RunPushVMResult
first green (OAuth per composition)7ebc5c5hat-9steps ok; release bug → fixed
release fixed00df7b3hat-9success 59 s, vm.terminated on its own, records deleted
atlibs 0.3.0 model861f3813hat-9success 57 s, released, records deleted
final composition bafyreiag5yjb…ef96ee9fhat-7success 46 s, released, records deleted
deployed runner, composition bafyreifzmo3b… (requester dab378f8, user-data c605eb61)325f96dhat-7success 52 s, released (fc-lpfuqerea3de-ed3fca28), no round records in the owner's account

Rows 1–4 as aliceoa.bsky.social/kc-ci-test, runner on hat-8; row 5 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: knotless-triage's questions_from_labels and a_decision_model_triages_issues expect sorted keys and fail. Fork-introduced; not fixed.
  • 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):

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

On hat-8 at ff309352: 728 passed, 5 failed: the two triage tests above, searching_code (no zoekt), binary_lifecycle and forks_pulls_reviews_and_merges (not chased). CI runs them through harness/cov.mjs against the spaces alpha.