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

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

The install script brings the runner, labeller and reviewer

Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:run/ship-binary
.changeset/install-runner-triage-reviewer.mdnew+7−0
@@ -0,0 +1,7 @@
---
default: minor
---
# The install script brings the runner, labeller and reviewer
`curl -fsSL https://knotless.dev/install.sh | sh` now installs `knotless-run`, `knotless-triage`, `knotless-agent` and its `knotless-claude-review` script beside `knotless`, `git-remote-knotless` and `knotless-mcp`. A runner, labeller or reviewer no longer needs a clone of knotless and Rust to build it. Pinning `KNOTLESS_VERSION` to a release from before these shipped still installs the first three.
crates/knotless-serve/src/install.sh+9−1
@@ -1,5 +1,7 @@
#!/bin/sh
# Installs knotless: `knotless`, `git-remote-knotless` and `knotless-mcp`,
# and `knotless-run`, `knotless-triage`, `knotless-agent` and
# `knotless-claude-review` for running a runner, labeller or reviewer,
# from the releases of the knotless-serve that handed out this script.
#
# curl -fsSL __KNOTLESS_URL__/install.sh | sh
@@ -61,7 +63,13 @@ fetch "$releases/$version/$name.tar.gz.sha256" "$tmp/sum" || fail "no checksum f
tar -xzf "$tmp/$name.tar.gz" -C "$tmp"
mkdir -p "$dir"
for bin in knotless git-remote-knotless knotless-mcp; do
for bin in knotless git-remote-knotless knotless-mcp \
knotless-run knotless-triage knotless-agent knotless-claude-review; do
# A release from before these shipped has only the first three.
case "$bin" in
knotless | git-remote-knotless | knotless-mcp) ;;
*) [ -f "$tmp/$name/$bin" ] || continue ;;
esac
# Moved into place, so a running copy is replaced rather than written over.
cp "$tmp/$name/$bin" "$dir/.$bin.new"
chmod 755 "$dir/.$bin.new"
crates/knotless-serve/tests/releases.rs+26−2
@@ -12,7 +12,29 @@ use std::path::Path;
use std::process::{Command, Output};
use std::sync::{Arc, Mutex};
const BINS: [&str; 3] = ["knotless", "git-remote-knotless", "knotless-mcp"];
const BINS: [&str; 7] = [
"knotless",
"git-remote-knotless",
"knotless-mcp",
"knotless-run",
"knotless-triage",
"knotless-agent",
"knotless-claude-review",
];
/// What a release from before the runner, labeller and reviewer shipped
/// holds.
const OLD_BINS: usize = 3;
/// The binaries a release of `version` holds: 0.1.0 is one from before
/// the rest shipped.
fn bins(version: &str) -> &'static [&'static str] {
if version == "0.1.0" {
&BINS[..OLD_BINS]
} else {
&BINS
}
}
/// The target this machine's script asks for.
fn target() -> String {
@@ -29,7 +51,7 @@ fn archive(dir: &Path, out: &Path, version: &str) -> std::path::PathBuf {
let name = format!("knotless-{version}-{}", target());
let staged = dir.join("staging").join(&name);
std::fs::create_dir_all(&staged).unwrap();
for bin in BINS {
for bin in bins(version) {
std::fs::write(staged.join(bin), format!("#!/bin/sh\necho {bin}\n")).unwrap();
}
std::fs::create_dir_all(out).unwrap();
@@ -151,6 +173,8 @@ fn installing_a_release() {
assert!(!stdout.contains("is not on your PATH"));
}
assert!(bin.join("knotless-mcp").exists());
// A release from before the runner shipped installs without it.
assert!(!bin.join("knotless-run").exists());
// No such version.
let out = install(&server, &home, &[("KNOTLESS_VERSION", "9.9.9")]);
deploy/build-client.sh+6−3
@@ -1,6 +1,8 @@
#!/usr/bin/env bash
# Builds the client, `knotless`, `git-remote-knotless` and `knotless-mcp`,
# for every target the install script fetches, as one archive per target:
# and the accounts that work for a repository, `knotless-run` (its runner),
# `knotless-triage` (its labeller) and `knotless-agent` (its reviewer, with
# the `knotless-claude-review` script it runs), for every target the install script fetches, as one archive per target:
#
# deploy/build-client.sh <out dir>
#
@@ -35,12 +37,13 @@ for target in "${TARGETS[@]}"; do
"Darwin "*-apple-darwin) build=build ;;
*) build=zigbuild ;;
esac
$CARGO $build --release --locked --target "$target" -p knotless -p knotless-mcp
$CARGO $build --release --locked --target "$target" -p knotless -p knotless-mcp -p knotless-run -p knotless-triage -p knotless-agent
name="knotless-$VERSION-$target"
mkdir "$OUT/$name"
for bin in knotless git-remote-knotless knotless-mcp; do
for bin in knotless git-remote-knotless knotless-mcp knotless-run knotless-triage knotless-agent; do
cp "target/$target/release/$bin" "$OUT/$name/"
done
install -m 755 crates/knotless-agent/claude-review "$OUT/$name/knotless-claude-review"
cp README.md LICENSE-MIT LICENSE-APACHE "$OUT/$name/"
tar -czf "$OUT/$name.tar.gz" -C "$OUT" "$name"
rm -r "$OUT/$name"
deploy/README.md+2−1
@@ -312,7 +312,8 @@ What it does not count:
The server hands out the client, so installing it needs no clone and no
Rust: `curl -fsSL https://knotless.dev/install.sh | sh` installs
`knotless`, `git-remote-knotless` and `knotless-mcp` into `~/.local/bin`
`knotless`, `git-remote-knotless`, `knotless-mcp`, `knotless-run`,
`knotless-triage`, `knotless-agent` and `knotless-claude-review` into `~/.local/bin`
(`KNOTLESS_INSTALL_DIR`), the latest release or `KNOTLESS_VERSION`'s,
checked against its sha256.
docs/guide/getting-started.md+7−3
@@ -6,9 +6,13 @@
curl -fsSL https://knotless.dev/install.sh | sh
```
The script installs three binaries into `$HOME/.local/bin`: `knotless` (the
CLI), `git-remote-knotless` (which lets `git` use `knotless://` URLs) and
`knotless-mcp` (for agents). `KNOTLESS_INSTALL_DIR` picks another directory,
The script installs into `$HOME/.local/bin`: `knotless` (the CLI),
`git-remote-knotless` (which lets `git` use `knotless://` URLs) and
`knotless-mcp` (for agents). It also installs what you need to run an
account that works for a repository: `knotless-run`, a
[runner](workflows.md#start-a-runner), `knotless-triage`, a labeller, and
`knotless-agent` with `knotless-claude-review`, a
[reviewer](reviews.md). `KNOTLESS_INSTALL_DIR` picks another directory,
and `KNOTLESS_VERSION` another release.
To build from a clone instead:
docs/guide/reviews.md+3−6
@@ -7,8 +7,7 @@
- An atproto account for the reviewer, such as a new Bluesky account, and an app password for it. An app password is a password for one app, made in the account's settings (Bluesky: Settings > Privacy and security > App passwords).
- Claude Code, with a Claude Pro or Max subscription or an Anthropic API key.
- Node 18 or later.
- `knotless-agent` and `knotless-mcp`, both built from the knotless repository. `knotless-mcp` is knotless's MCP server: Claude reads the pull through its tools.
- `knotless-claude-review`, the script that runs Claude Code for each review. It is `crates/knotless-agent/claude-review` in the repository.
- `knotless-agent`, `knotless-mcp` and `knotless-claude-review`, which the [install](getting-started.md#install) puts in place. `knotless-mcp` is knotless's MCP server: Claude reads the pull through its tools. `knotless-claude-review` is the script that runs Claude Code for each review.
Use a new account, not your own. The owner's approvals count toward required reviews, and the reviewer posts as whichever account it logs in as.
@@ -16,12 +15,10 @@ Use a new account, not your own. The owner's approvals count toward required rev
1. Make the reviewer's account, say `reviewer.example.com`, and make an app password for it.
2. Install the two binaries and the script from a checkout of knotless:
2. Install the two binaries and the script:
```sh
cargo install --path crates/knotless-agent
cargo install --path crates/knotless-mcp
install crates/knotless-agent/claude-review /usr/local/bin/knotless-claude-review
curl -fsSL https://knotless.dev/install.sh | sh
```
The knotless server image (`docker pull knotless.dev/chadtmiller.com/knotless/knotless-server`) has all three, with Claude Code, the script at `/usr/local/bin/knotless-claude-review`.
docs/guide/workflows.md+3−0
@@ -13,6 +13,9 @@ beside knotless-serve.
## Start a runner
`knotless-run` comes with the [install](getting-started.md#install), and
runs steps in Docker, so the machine needs Docker too.
A runner acts as an account of its own. Give it that account's handle and
an app password, and name the repositories to watch:
docs/reference/cli.md+4−2
@@ -421,8 +421,10 @@ file that does not exist. It fails with `<file>: its tables are version
<v>, this build's <version>: starting would rebuild it` otherwise.
`/install.sh`, served with `--releases`, installs `knotless`,
`git-remote-knotless` and `knotless-mcp` for `aarch64` or `x86_64`, macOS
or Linux (musl), with curl or wget. It checks each download's SHA-256, and
`git-remote-knotless`, `knotless-mcp`, `knotless-run`, `knotless-triage`,
`knotless-agent` and `knotless-claude-review` for `aarch64` or `x86_64`,
macOS or Linux (musl), with curl or wget. A release from before the last
four shipped installs the first three. It checks each download's SHA-256, and
moves each binary into place, so a running copy is replaced. The routes
are in the [API reference](api.md#releases).
README.md+1−1
@@ -15,7 +15,7 @@ of pulls and issues, a gateway for collaborators, and web pages. It is cheap
to run.
```sh
curl -fsSL https://knotless.dev/install.sh | sh # knotless, git-remote-knotless, knotless-mcp
curl -fsSL https://knotless.dev/install.sh | sh # knotless, git-remote-knotless, knotless-mcp, and the runner, labeller and reviewer
knotless login alice.bsky.social # OAuth, in your browser
git push knotless://alice.bsky.social/my-project main