Compare commits

...
4 Commits
Author SHA1 Message Date
iceBear67 a6bef210e9 add workflow
Build / grok-linux-amd64 (push) Canceled after 0s
Build / grok-macos-arm64 (push) Canceled after 0s
Build / grok-windows-amd64 (push) Canceled after 0s
Build / release (push) Canceled after 0s
2026-08-16 02:36:24 +00:00
iceBear67andClaude Opus 5 36f10f1256 Add scripts/paced.sh, and record what actually limits builds here
Cargo on this box was suspected of writing the disk to death. Measuring
it says otherwise: 4 CPUs, load peaks at 3.0 during a full build, while
writes peak at 30 MB/s and sit at zero for most samples. The long poles
are single-crate rustc compiles that cannot be parallelised, so the
binding constraint is CPU and `nice -n 19` is the first-line tool.

The disk itself reads at 210 MB/s and writes at 50 MB/s, identically
across block sizes and IO modes -- a volume-level write cap rather than
disk physics. A short burst reaches ~150 MB/s on what look like burst
credits; calibrating against that number is a mistake, and it is the one
that made an earlier 40 MB/s ceiling do nothing.

paced.sh is the fallback for the phase that does write hard -- linking
the 643 MB debug binary saturates writes for about 13 seconds. It
duty-cycles a process group against the observed rate in
/proc/diskstats, because every kernel-side lever is unavailable here:
/sys/fs/cgroup is read-only and cannot be remounted or re-mounted
elsewhere even under sudo (no CAP_SYS_ADMIN), /proc/sys is read-only,
and the scheduler cannot be switched to BFQ so ionice is a no-op. Each
of those is verified, not assumed; the header records them so the next
person does not re-derive it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 11:08:33 +00:00
iceBear67 95ba918629 Add /rc remote control bridge (patch 0004)
Exports the work/ commit that adds the RC bridge: the ACP tee, the outbound
glance transport with reconnect and replay, the first-answer-wins interaction
race, and the /rc slash command.
2026-08-15 09:10:07 +00:00
iceBear67 dd9b41e72f Add [remote_control] config section (patch 0003)
Exports the work/ commit adding the [remote_control] config section that the
/rc bridge reads: url, api_key, auto_start and replay_buffer, with
GROK_RC_URL / GROK_RC_API_KEY overriding the file.
2026-08-15 09:10:07 +00:00
4 changed files with 2768 additions and 0 deletions
+154
View File
@@ -0,0 +1,154 @@
# Native release builds of the patched grok binary.
#
# Matrix is host=target (no cross): Windows/Linux amd64 and macOS arm64.
# work/ is derived the same way as `make apply`, but the upstream checkout is
# a depth-1 fetch of the pinned SHA so CI does not clone full grok-build history.
name: Build
on:
push:
branches: [main]
tags: ["v*"]
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: "0"
RUST_BACKTRACE: "1"
permissions:
contents: read
jobs:
build:
name: ${{ matrix.artifact }}
runs-on: ${{ matrix.os }}
timeout-minutes: 180
defaults:
run:
shell: bash
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact: grok-linux-amd64
exe: xai-grok-pager
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact: grok-windows-amd64
exe: xai-grok-pager.exe
- os: macos-14
target: aarch64-apple-darwin
artifact: grok-macos-arm64
exe: xai-grok-pager
steps:
- name: Disable CRLF conversion
run: git config --global core.autocrlf false
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.94.0
with:
targets: ${{ matrix.target }}
- uses: arduino/setup-protoc@v3
with:
version: "29.3"
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Apply patches onto pinned upstream
run: |
set -euo pipefail
REV="$(grep -vE '^\s*(#|$)' upstream.rev | head -n1 | tr -d '[:space:]')"
[[ -n "$REV" ]] || { echo "upstream.rev has no revision" >&2; exit 1; }
git init work
git -C work remote add origin https://github.com/xai-org/grok-build.git
git -C work fetch --depth 1 origin "$REV"
git -C work checkout --force --detach FETCH_HEAD
git -C work checkout -B fork
git -C work tag -f base
git -C work config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git -C work config user.name "github-actions[bot]"
shopt -s nullglob
patches=("$GITHUB_WORKSPACE"/patches/*.patch)
if ((${#patches[@]})); then
git -C work am --3way --keep-cr --whitespace=nowarn "${patches[@]}"
fi
echo "work/ ready: upstream ${REV:0:12} + ${#patches[@]} patch(es)"
- uses: Swatinem/rust-cache@v2
with:
workspaces: work
key: ${{ matrix.target }}
cache-targets: false
- name: Release build
working-directory: work
run: cargo build --release --locked -p xai-grok-pager-bin --target ${{ matrix.target }}
- name: Package
env:
TARGET: ${{ matrix.target }}
ARTIFACT: ${{ matrix.artifact }}
EXE: ${{ matrix.exe }}
run: |
set -euo pipefail
src="work/target/${TARGET}/release/${EXE}"
[[ -f "$src" ]] || { echo "missing $src" >&2; ls -la "work/target/${TARGET}/release" >&2; exit 1; }
mkdir -p dist
if [[ "$EXE" == *.exe ]]; then
dest="dist/${ARTIFACT}.exe"
else
dest="dist/${ARTIFACT}"
strip "$src" || true
fi
cp "$src" "$dest"
{
echo "artifact=$(basename "$dest")"
echo "target=${TARGET}"
echo "git=${GITHUB_SHA}"
echo "upstream=$(grep -vE '^\s*(#|$)' upstream.rev | head -n1 | tr -d '[:space:]')"
echo "rustc=$(rustc --version)"
} > "dist/${ARTIFACT}.txt"
if command -v sha256sum >/dev/null; then
(cd dist && sha256sum "$(basename "$dest")" "${ARTIFACT}.txt" > "${ARTIFACT}.sha256")
else
(cd dist && shasum -a 256 "$(basename "$dest")" "${ARTIFACT}.txt" > "${ARTIFACT}.sha256")
fi
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: dist/*
if-no-files-found: error
release:
if: startsWith(github.ref, 'refs/tags/')
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- uses: softprops/action-gh-release@v2
with:
files: dist/*
generate_release_notes: true
fail_on_unmatched_files: true
@@ -0,0 +1,108 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: iceBear67 <icebear67@sfclub.cc>
Date: Sat, 15 Aug 2026 06:39:14 +0000
Subject: [PATCH] Add [remote_control] config section for the /rc glance bridge
diff --git a/crates/codegen/xai-grok-shell/src/agent/config.rs b/crates/codegen/xai-grok-shell/src/agent/config.rs
index 3dd50b3217936911d6858e4c9c169d7609e1a0fd..f39d1bd460a4635dd4767afe92622ab9b04952a1 100644
--- a/crates/codegen/xai-grok-shell/src/agent/config.rs
+++ b/crates/codegen/xai-grok-shell/src/agent/config.rs
@@ -1014,6 +1014,79 @@ pub struct CliConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub session_picker_grouped: Option<bool>,
}
+/// `[remote_control]` section: the `/rc` bridge to a grok-glance server.
+///
+/// `/rc` mirrors the session you are already in to glance over ACP -- it does not
+/// restart it, switch it to headless, or hand it over. Both ends stay live and
+/// either can drive the session.
+///
+/// Every field has an env override, which is how the API key is normally supplied:
+/// a bearer token in a plaintext config file is a poor default.
+#[derive(Clone, Debug, Default, Serialize, Deserialize)]
+#[serde(default)]
+pub struct RemoteControlConfig {
+ /// Glance WebSocket endpoint, e.g. `wss://glance.example.com/api/acp/agent`.
+ /// Env `GROK_RC_URL`.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub url: Option<String>,
+ /// Bearer token presented on the WebSocket upgrade. Env `GROK_RC_API_KEY`.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub api_key: Option<String>,
+ /// Connect at session start instead of waiting for `/rc`. Env `GROK_RC_AUTO_START`.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub auto_start: Option<bool>,
+ /// Session updates retained for replay when glance (re)connects.
+ /// See [`RemoteControlConfig::DEFAULT_REPLAY_BUFFER`].
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub replay_buffer: Option<usize>,
+}
+impl RemoteControlConfig {
+ /// Bounded so a long session cannot grow the bridge without limit; large
+ /// enough that a browser attaching mid-session still sees useful history.
+ pub const DEFAULT_REPLAY_BUFFER: usize = 2048;
+ /// Env wins over config, and an empty value counts as unset -- an exported
+ /// but blank `GROK_RC_URL` should not mask a working config entry.
+ fn env_override(key: &str) -> Option<String> {
+ std::env::var(key)
+ .ok()
+ .map(|v| v.trim().to_owned())
+ .filter(|v| !v.is_empty())
+ }
+ pub fn resolved_url(&self) -> Option<String> {
+ Self::env_override("GROK_RC_URL").or_else(|| {
+ self.url
+ .as_deref()
+ .map(str::trim)
+ .filter(|v| !v.is_empty())
+ .map(str::to_owned)
+ })
+ }
+ pub fn resolved_api_key(&self) -> Option<String> {
+ Self::env_override("GROK_RC_API_KEY").or_else(|| {
+ self.api_key
+ .as_deref()
+ .map(str::trim)
+ .filter(|v| !v.is_empty())
+ .map(str::to_owned)
+ })
+ }
+ pub fn auto_start_enabled(&self) -> bool {
+ Self::env_override("GROK_RC_AUTO_START")
+ .map(|v| matches!(v.to_ascii_lowercase().as_str(), "1" | "true" | "yes" | "on"))
+ .or(self.auto_start)
+ .unwrap_or(false)
+ }
+ pub fn replay_buffer_len(&self) -> usize {
+ self.replay_buffer
+ .filter(|n| *n > 0)
+ .unwrap_or(Self::DEFAULT_REPLAY_BUFFER)
+ }
+ /// Both a URL and a key are required; `/rc` reports which one is missing
+ /// rather than dialing an endpoint that will reject it.
+ pub fn is_configured(&self) -> bool {
+ self.resolved_url().is_some() && self.resolved_api_key().is_some()
+ }
+}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct DiagnosticsConfig {
@@ -1348,6 +1421,9 @@ pub struct Config {
pub paths: PathsConfig,
#[serde(default, skip_serializing)]
pub cli: CliConfig,
+ /// `[remote_control]` section: the `/rc` bridge to grok-glance.
+ #[serde(default, skip_serializing)]
+ pub remote_control: RemoteControlConfig,
#[serde(default, skip_serializing)]
pub models: ModelsConfig,
#[serde(default, skip_serializing)]
@@ -1759,6 +1835,7 @@ impl Default for Config {
feedback: FeedbackConfig::default(),
paths: PathsConfig::default(),
cli: CliConfig::default(),
+ remote_control: RemoteControlConfig::default(),
models: ModelsConfig::default(),
harness: HarnessConfig::default(),
relay: RelayConfig::default(),
File diff suppressed because it is too large Load Diff
+110
View File
@@ -0,0 +1,110 @@
#!/usr/bin/env bash
# Run a command with its disk-write rate held under a ceiling.
#
# Cargo on this box can saturate the virtual disk badly enough to take the
# whole machine out. The usual levers are unavailable here and it is worth
# recording why, so nobody burns an afternoon rediscovering it:
#
# cgroup v2 io.max -- /sys/fs/cgroup is mounted ro and cannot be remounted
# or re-mounted elsewhere; the container has no
# CAP_SYS_ADMIN, so this fails even under sudo.
# vm.dirty_bytes -- /proc/sys is read-only.
# ionice -- the scheduler is mq-deadline, where IO priority is a
# no-op, and /sys/block/*/queue/scheduler is read-only
# so BFQ cannot be selected.
# nice -- CPU only. Writeback happens in kernel flusher threads
# that never see the nice value, so a niced build
# saturates the disk exactly as fast as an un-niced one.
#
# What is left is duty-cycling from userspace: sample the block device's
# written-sectors counter, and when the observed rate exceeds the ceiling,
# SIGSTOP the whole process group until it drops. Crude, but it acts on
# measured throughput rather than on a scheduler hint, which is the only
# property that actually matters here.
#
# scripts/paced.sh -- make build
# MBPS=30 scripts/paced.sh -- env CARGO_CMD=test PKG=xai-grok-pager ./scripts/build.sh --lib
set -euo pipefail
# Measured on this box, idle, 1 GB transfers:
#
# read 210 MB/s (O_DIRECT and buffered alike)
# write 50 MB/s (identical for buffered+fdatasync, O_DIRECT 1M, O_DIRECT 64k)
#
# Write is pinned at ~50 MB/s regardless of block size or IO mode, so it is a
# volume-level cap rather than disk physics, and it is 4x slower than read.
# A short burst can reach ~150 MB/s on what look like burst credits -- do not
# calibrate against that, it is the number that made an earlier 40 MB/s ceiling
# useless. 15 MB/s is under a third of sustained capacity, which leaves the rest
# of the machine usable while a build runs.
MBPS="${MBPS:-15}" # write ceiling in MB/s, averaged over one window
DEV="${DEV:-vdb}" # block device to watch; the disk, not the partition
WINDOW="${WINDOW:-1}" # sampling window in seconds
[[ "${1:-}" == "--" ]] && shift
if [[ $# -eq 0 ]]; then
echo "usage: [MBPS=60] [DEV=vdb] scripts/paced.sh -- <command...>" >&2
exit 2
fi
stats_field() {
# /proc/diskstats field 10 is sectors written, in 512-byte units.
awk -v dev="$DEV" '$3 == dev { print $10; exit }' /proc/diskstats
}
if [[ -z "$(stats_field)" ]]; then
echo "paced: no such device in /proc/diskstats: $DEV" >&2
exit 1
fi
# Its own process group, so one signal reaches cargo and every rustc it spawned.
#
# `set -m` rather than setsid: setsid only forks when it is already a group
# leader, so under `cmd &` it usually execs in place -- but when it does fork,
# $! is setsid's pid, which exits immediately. The loop below then sees the
# child "finish" instantly and reports success while the real build is still
# running. Job control gives the background job its own pgid deterministically.
set -m
"$@" &
child=$!
pgid=$child
set +m
cleanup() {
# Never leave the build stopped: a SIGSTOPped process group that outlives
# this script looks exactly like a hang.
kill -CONT -- "-$pgid" 2>/dev/null || true
kill -TERM -- "-$pgid" 2>/dev/null || true
}
trap cleanup INT TERM
ceiling_sectors=$(( MBPS * 1024 * 1024 / 512 * WINDOW ))
prev=$(stats_field)
stalled=0
while kill -0 "$child" 2>/dev/null; do
sleep "$WINDOW"
now=$(stats_field)
delta=$(( now - prev ))
prev=$now
if (( delta > ceiling_sectors )); then
# Stop for as long as the overshoot implies, capped so the build still
# makes progress even when something else on the box is writing hard.
pause=$(( delta / ceiling_sectors ))
(( pause > 4 )) && pause=4
stalled=$(( stalled + pause ))
kill -STOP -- "-$pgid" 2>/dev/null || true
sleep "$pause"
kill -CONT -- "-$pgid" 2>/dev/null || true
prev=$(stats_field)
fi
done
rc=0
wait "$child" || rc=$?
trap - INT TERM
echo "paced: done rc=$rc (throttled ${stalled}s at ${MBPS}MB/s ceiling on /dev/$DEV)" >&2
# Propagate the wrapped command's status. Swallowing it once already produced a
# confident "build finished, exit 0" for a build that had in fact been killed.
exit "$rc"