diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..cefa35c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,165 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this repository is + +This is **not** a Rust project. It is a CraftBukkit/Spigot-style **patch workflow** wrapped around +[`xai-org/grok-build`](https://github.com/xai-org/grok-build) (the `grok` CLI/TUI, a 91-crate Rust +workspace). + +Upstream is a periodic one-way export of an xAI-internal monorepo — linear squashed +`Synced from monorepo` commits, with `SOURCE_REV` naming the internal commit — and its +`CONTRIBUTING.md` states that **no external PRs or patches are accepted**. Changes cannot be pushed +back, and upstream re-drops the whole tree. So local changes live as replayable patches, exactly as +CraftBukkit does against Mojang: + +> **`patches/` is the source. `work/` is the build output.** + +## The two-layer model — read this before editing anything + +| Path | Tracked? | What it is | +|------|----------|------------| +| `patches/` | **yes** | The only source of truth. One `.patch` file per change. | +| `scripts/`, `Makefile`, `upstream.rev`, `README.md` | **yes** | The workflow itself and the pinned upstream SHA. | +| `upstream/` | no (gitignored) | Pristine clone of the vendor repo. Never edit. | +| `work/` | no (gitignored) | `upstream@upstream.rev` + `patches/` applied. **This is where you edit Rust code.** Fully disposable. | + +Two rules follow, and violating either silently destroys work: + +1. **Rust source edits go in `work/`, never in `patches/`.** Patch files are generated output — hand-editing them is how you get a tree that no longer applies. +2. **`make rebuild` is the only exit from `work/`.** `make apply` does `git reset --hard` + `git clean -fdx`. Anything in `work/` that has not been committed *and* exported by `make rebuild` is gone. + +Spigot mapping, if it helps: `upstream/` ≈ the CraftBukkit clone, `work/` ≈ the patched work dir, +`patches/` ≈ `CraftBukkit-Patches/`, `apply-patches.sh` ≈ `applyPatches.sh`, +`rebuild-patches.sh` ≈ `rebuildPatches.sh`, `upstream.rev` ≈ `versions/*.json`. + +## Commands + +Run everything from the repo root via `make` (`make help` lists all targets). The scripts inject +`~/.cargo/bin` into `PATH` themselves, so `cargo` need not be on the interactive `PATH`. + +```sh +make setup # idempotent: rustup + pinned toolchain, dotslash/protoc +make apply # upstream.rev + patches/ -> work/ (FORCE=1 to discard work/ changes) +make rebuild # work/ commits above `base` -> patches/ +make status # pinned rev, patch count, commits in work/, dirty state +make update-dry # preview an upstream sync, change nothing +make update # re-pin upstream.rev and forward-port patches +``` + +Build and test — all of these operate inside `work/`: + +```sh +make build # debug binary -> work/target/debug/xai-grok-pager +make release # optimised build +make check # cargo check +make test # PKG= to pick the crate; defaults to xai-grok-version +make clippy +make fmt +make run # build + launch the TUI +``` + +**Running a single test.** `make test` is a thin wrapper; go through `build.sh` directly to pass a +filter, since extra args are forwarded to cargo verbatim: + +```sh +CARGO_CMD=test PKG=xai-grok-version ./scripts/build.sh test_fork_tag +CARGO_CMD=test PKG=xai-grok-pager-bin ./scripts/build.sh version_output_writer -- --nocapture +``` + +`./scripts/build.sh` also accepts arbitrary cargo flags (`--release`, `--locked`, `-j2`, …). + +## Daily loop + +One commit in `work/` == one patch file. The commit message becomes the patch title. + +```sh +make apply +$EDITOR work/crates/codegen/.../foo.rs +cd work && git add -A && git commit -m 'Do the thing' +cd .. && make rebuild +git add patches/ && git commit -m 'Do the thing' +``` + +To amend, reorder, squash, or drop existing patches, use ordinary git — `work/` is a real repo, and +the `base` tag marks the boundary between upstream and ours: + +```sh +cd work && git rebase -i base +cd .. && make rebuild # patches/ is regenerated wholesale +``` + +## Upstream syncs + +`make update` fetches upstream, reports the new commits / `SOURCE_REV` delta / changed-file count, +re-pins `upstream.rev`, replays `patches/` on the new base, and re-exports on success. On conflict it +stops mid-`git am` and prints the resolution steps — resolve it like a rebase (`git status`, fix +markers, `git add -A`, `git am --continue`), then `make rebuild` from the root. + +Conflicts here are the point of the model, not a defect: they mark exactly where an upstream change +collided with ours instead of letting it vanish. + +## Safety rails + +The scripts refuse rather than silently discard. When one fires, understand it before overriding: + +- `make apply` aborts if `work/` has uncommitted changes. +- `make apply` aborts if the commit count above `base` ≠ the number of files in `patches/`. Usually this means a forgotten `make rebuild`; it also fires when you deliberately add or delete patch files, and the check cannot tell the two apart. +- `make rebuild` / `make build` abort while a `git am` is half-finished. +- `FORCE=1` (i.e. `make apply FORCE=1`) is the escape hatch for both `apply` guards — it means "discard `work/` and replay `patches/` as-is". + +`make apply`'s `git clean -fdx` deliberately excludes `/target`; preserving the incremental cache is +the difference between a fast replay and a cold rebuild. + +Patches are generated with `--zero-commit --full-index --no-signature --no-stat -N`. `--zero-commit` +keeps the `From ` line stable across rebases (otherwise every patch file churns on every +replay); `--full-index` gives `git am --3way` blob hashes to fall back on when context drifts. + +## Upstream tree architecture (inside `work/`) + +91 workspace members: `crates/codegen/` (74 — the CLI crate closure), `crates/common/` (11 — shared +leaves), `crates/build/` (1), `prod/mc/` (1), and `third_party/` (4 — a vendored Mermaid diagram +stack). + +| Crate | Role | +|-------|------| +| `xai-grok-pager-bin` | Composition root; produces the `xai-grok-pager` binary (shipped as `grok`) | +| `xai-grok-pager` | The TUI — scrollback, prompt, modals, rendering. Also carries `docs/user-guide/` | +| `xai-grok-shell` | Agent runtime + leader/stdio/headless entry points | +| `xai-grok-tools` | Tool implementations (terminal, file edit, search, …) | +| `xai-grok-workspace` | Host filesystem, VCS, execution, checkpoints | + +Constraints inherited from upstream: + +- **The root `Cargo.toml` is generated — treat it as read-only.** Edit per-crate `Cargo.toml` files instead. Note it also carries the `[patch.crates-io]` pin for the `our-forks/async-openai` git dependency. +- **Always target a specific crate (`-p `).** Full-workspace builds are slow enough to be impractical here; `build.sh` enforces this by always passing `-p`. +- Toolchain is pinned to **Rust 1.94.0** by `rust-toolchain.toml`. Lint/format config: `clippy.toml`, `rustfmt.toml` at the tree root. +- **protoc** is needed only by `xai-grok-tools-api` (for `proto/grok-tools.proto`). Resolution order is `$PROTOC` → walk up for `bin/protoc` → `PATH`. `bin/protoc` is a [DotSlash](https://dotslash-cli.com) wrapper that fetches protoc 29.3; `setup.sh` installs dotslash and falls back to the system `protobuf-compiler`, and `build.sh` sets `PROTOC` if the wrapper is unusable. + +When touching upstream code, check the tests that already cover it — the shipped example patch +(below) exists partly to demonstrate this failure mode. + +## Build cost + +On this host (4 cores / 7 GB) a cold debug build of `xai-grok-pager-bin` takes ~11 min and +`work/target` grows to ~24 GB; the binary is ~612 MB. `cargo check` and `cargo build` keep separate +caches, so `make check` after a `make build` is not fast (~6 min cold). Avoid `make clean` and +`make distclean` unless you actually need the space — both throw away that cache. Prefer +per-crate commands while iterating. + +## Example patches + +`patches/` ships two patches, both tagged `[EXAMPLE PATCH]` in their commit messages, and both safe +to delete: + +- `0001` modifies upstream Rust: adds `FORK_NAME` / `fork_tag()` to `xai-grok-version` and wires it into the pager's version line, so `--version` prints `grok [newgrok] 1.0.3 (…)`. The tag is inserted *after* `"grok "` rather than appended, because `main.rs`'s `version_output_writer_preserves_channel_aware_contract` asserts the line still ends with the channel label; and `display_version` itself is untouched because `test_display_version_formatting_matrix` pins its output. +- `0002` adds a new file (`FORK.md`), demonstrating that file-creating patches work. + +Deleting them requires the override, since `work/` still holds their commits: +`rm patches/000*.patch && make apply FORCE=1`. + +## License + +Upstream code is Apache-2.0 (`work/LICENSE`); changes in `patches/` are distributed under the same. +This is an unofficial fork, unaffiliated with xAI. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file