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

johnandersen777.bsky.social/asyncai

0
0
main
291 lines · 10.0 KB Raw History
# Contributing

## Development

Rust is pinned by `rust-toolchain.toml` (1.97.0). The atirc client is a git
dependency pinned to a revision in `Cargo.toml`; builds need fetch access to
`tangled.org`, and the revision only moves when bumped deliberately (with
`Cargo.lock` updated in the same change).

```bash
cargo build --release --bins
```

Binaries:

- `asyncai`
- `asyncai-mcp-simple`
- `socialweb-computer-kcp-readonly`
- `socialweb-computer-kcp-readwrite`

`cargo install --path .` installs all four. `prompts/*.md` and
`src/code_mode/helpers.py` are embedded at build time, so `prompts/` must be
present in any build context.

## Checks

```bash
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test
```

Pool sandbox tests need the Monty worker:

```bash
cargo +1.97.0 install monty-runtime --locked   # installs `monty`
MONTY_WORKER=$(command -v monty) cargo test --test code_mode_pool
```

Tests mock the model, MCP servers, and the atirc bus; no live services or
network are used. Never commit endpoints or tokens.

## Linux amd64 build

```bash
container system start

# Drop stopped build containers from earlier runs before building.
container list --all --format json \
  | jq -r '.[] | select(.status.state=="stopped") | .id' \
  | while read -r id; do container delete "$id"; done

rm -rf $HOME/.tmp/asyncai-out
mkdir -p $HOME/.tmp/asyncai-out

container build --platform linux/amd64 -m 8G -c 4 \
  -f Dockerfile \
  -o type=local,dest=$HOME/.tmp/asyncai-out .

find $HOME/.tmp/asyncai-out -name asyncai -type f
file $HOME/.tmp/asyncai-out/*/linux_amd64/out/asyncai   # ELF 64-bit, static-pie
```

Build context and destination must live under `$HOME`: the builder cannot read
`/tmp` (the context transfers as 2B and `COPY` fails). The container uses the
image's pinned 1.97.x toolchain; `rust-toolchain.toml` is not copied into the
build, so local builds can stay on 1.97.0 while the image builds with its own
1.97 patch release. `-j 2` keeps `monty`'s rustc within the 8G builder memory
limit (4 jobs gets OOM-killed).

Smoke-run in an Alpine container:

```bash
container run --rm --platform linux/amd64 --memory 1G \
  -v $HOME/.tmp/asyncai-out/*/linux_amd64/out:/out \
  alpine:latest /out/asyncai --help
```

## Windows amd64 build (cross-compile)

Cross-compiles self-contained PE32+ x86-64 binaries with mingw-w64 inside the
build container. No Windows host, MSVC SDK, `cargo-xwin` or zig is needed.

```bash
container system start

# Drop stopped build containers from earlier runs before building.
container list --all --format json \
  | jq -r '.[] | select(.status.state=="stopped") | .id' \
  | while read -r id; do container delete "$id"; done

rm -rf $HOME/.tmp/asyncai-win-out
mkdir -p $HOME/.tmp/asyncai-win-out

# Apple Silicon: linux/arm64. Intel Macs: linux/amd64. The build container
# architecture does not change the Windows binaries.
container build --platform linux/arm64 -m 8G -c 4 \
  -f Dockerfile.windows \
  -o type=local,dest=$HOME/.tmp/asyncai-win-out .

find $HOME/.tmp/asyncai-win-out -name '*.exe' -type f
file $HOME/.tmp/asyncai-win-out/*/linux_arm64/out/asyncai.exe
# PE32+ executable (console) x86-64, for MS Windows
```

`Dockerfile.windows` installs the mingw-w64 toolchain plus `cmake`, `perl` and
`nasm` (used by `aws-lc-sys`), adds the Rust `x86_64-pc-windows-gnu` target, and
builds with a static CRT so the `.exe` files do not require
`libgcc_s_seh-1.dll` or `libwinpthread-1.dll`. The target is added to the
image's pinned 1.97.x toolchain; `rust-toolchain.toml` is not copied into the
build so rustup cannot switch to a toolchain without that target.

A PE binary cannot be run on macOS without Windows or Wine, so this target is
compile-verified only. Windows runtime notes:

- `--monitor` and the kcp runner spawn `sh -c`, so they need Git Bash or WSL.
- The Claude Code session harness reads `HOME`; on Windows set `HOME` (Git
  Bash) or pass `--session-dir FORMAT=PATH`, or run with `--no-session`.

## macOS arm64 build

Native build on an Apple Silicon Mac:

```bash
cargo build --release --bins
file target/release/asyncai   # Mach-O 64-bit executable arm64
```

All four binaries land in `target/release/`.

## Building on a Linux host

The `container` commands above are Apple-container-specific. On a Linux host
use the same Dockerfiles with BuildKit (`docker buildx` or `podman build`, both
support `--output type=local`), or build directly with the host toolchain as
below. All three platforms can be produced from one Linux host except macOS.

### Linux amd64 on a Linux host

```bash
# Debian/Ubuntu
sudo apt-get install -y build-essential cmake perl pkg-config
# Fedora/RHEL
sudo dnf install -y gcc gcc-c++ make cmake git perl pkgconf-pkg-config

cargo build --release --bins
```

`git` is required because `.cargo/config.toml` sets `git-fetch-with-cli` for
the pinned atirc dependency.

For the same static-pie binary the container build produces, add the musl
target (static against musl, no glibc dependency on the target host):

```bash
sudo apt-get install -y musl-tools
rustup target add x86_64-unknown-linux-musl
cargo build --release --bins --target x86_64-unknown-linux-musl
```

The four binaries land in `target/x86_64-unknown-linux-musl/release/`.

### Windows amd64 on a Linux host (cross-compile)

```bash
# Debian/Ubuntu
sudo apt-get install -y \
  gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 \
  nasm cmake perl pkg-config
# Fedora/RHEL
sudo dnf install -y mingw64-gcc mingw64-gcc-c++ mingw64-binutils \
  nasm cmake perl pkgconf-pkg-config

rustup target add x86_64-pc-windows-gnu

export CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc
export CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUSTFLAGS="-C target-feature=+crt-static"

cargo build --release --bins --target x86_64-pc-windows-gnu
```

`nasm` is only needed for x86_64 Windows (`aws-lc-sys`); the static CRT flag
is what keeps the `.exe` files free of `libgcc_s_seh-1.dll` and
`libwinpthread-1.dll`.

### macOS arm64

A macOS artifact needs a macOS host: there is no supported way to produce one
from a Linux host without an Apple SDK. Build it with `cargo build --release
--bins` on an Apple Silicon Mac (or via an osxcross toolchain with a legally
obtained SDK, which is out of scope here). Linux (glibc or musl) and Windows
artifacts can both be built on one Linux host.

### Container builds on a Linux host

```bash
docker buildx build --platform linux/amd64 -f Dockerfile \
  --output type=local,dest=$PWD/out/linux .

# The build container arch does not affect the Windows artifacts.
docker buildx build --platform linux/amd64 -f Dockerfile.windows \
  --output type=local,dest=$PWD/out/windows .
```

`--output type=local` requires BuildKit (default in current Docker). The
`$HOME/.tmp` and `-m`/`-c` builder-memory notes in the Apple sections do not
apply; Docker inherits the host's resources.

## Cold container builds and cargo cache seeding

A cold container build can sit ~10 minutes at "Updating git repository":
the container VM has no IPv6 route while musl prefers AAAA for
`tangled.org`/crates.io. Seed the host cargo caches and build offline to skip
the hang. Keep the `/work/target` cache mount — when it is warm only the
`asyncai` crate recompiles; the cache also makes the copied registry layers
cheap.

Create the seed from the host caches (both git repositories must be present:
`atirc` and `atproto-crates`):

```bash
mkdir -p cargo-seed/git/db cargo-seed/git/checkouts cargo-seed/registry
cp -R ~/.cargo/git/db/atirc-* ~/.cargo/git/db/atproto-crates-* cargo-seed/git/db/
cp -R ~/.cargo/git/checkouts/atirc-* ~/.cargo/git/checkouts/atproto-crates-* cargo-seed/git/checkouts/
cp -R ~/.cargo/registry/index ~/.cargo/registry/cache cargo-seed/registry/
```

Then apply this diff to `Dockerfile` (and `Dockerfile.windows` for the same
offline behavior):

```diff
 COPY src ./src
 COPY prompts ./prompts
+COPY cargo-seed/git /usr/local/cargo/git
+COPY cargo-seed/registry/index /usr/local/cargo/registry/index
+COPY cargo-seed/registry/cache /usr/local/cargo/registry/cache

-RUN --mount=type=cache,target=/usr/local/cargo/registry \
-    --mount=type=cache,target=/usr/local/cargo/git \
-    --mount=type=cache,target=/work/target \
+RUN --mount=type=cache,target=/work/target \
     TOOLCHAIN=$(echo /usr/local/rustup/toolchains/*) && \
-    PATH="$TOOLCHAIN/bin:$PATH" cargo build --release --bins -j 2 && \
+    PATH="$TOOLCHAIN/bin:$PATH" CARGO_NET_OFFLINE=true \
+    cargo build --release --bins -j 2 && \
```

`cargo-seed/` is local scratch state; leave it untracked and do not commit it.
It must stay in the build context (do not gitignore it) or the `COPY` steps
fail.

## Disk hygiene

`container build` caches aggressively and never prunes itself. Each distinct
build adds an image (~0.4–0.5 GB), and the BuildKit builder container
(`~/Library/Application Support/com.apple.container/containers/buildkit`,
~13 GB) keeps cargo registry/target caches between builds. Apple's CLI has no
automatic garbage collection, so this grows every day a build runs.

Reclaim stopped containers (safe; the running `buildkit` builder is skipped):

```bash
container list --all --format json \
  | jq -r '.[] | select(.status.state=="stopped") | .id' \
  | while read -r id; do container delete "$id"; done
```

Deleting the `buildkit` container (`container stop buildkit && container
delete buildkit`) drops its ~13 GB cache; the next build recreates the builder
automatically and is cold. Rust build output is the other grower:
`target/` reaches multiple GB; `cargo clean` resets it.

## Installing on a host

There is no server deploy: copy the four binaries to the machine that runs the
agent and put them on `PATH` together.

```bash
scp target/release/asyncai \
    target/release/asyncai-mcp-simple \
    target/release/socialweb-computer-kcp-readonly \
    target/release/socialweb-computer-kcp-readwrite \
    <host>:/tmp/

ssh <host> 'sudo install -m 0755 /tmp/asyncai /tmp/asyncai-mcp-simple \
  /tmp/socialweb-computer-kcp-readonly /tmp/socialweb-computer-kcp-readwrite \
  /usr/local/bin/'
```

Use the matching Linux, macOS or Windows build for the target host; the Linux
amd64 binaries are static-pie and need no libc or CA bundle on the host.