Files
dev/Makefile
T
zeekay ff64e7d729 Kai decides in the dev loop, and dev flow runs Decision Programs whose steps are tools, Kai or Zen.
hanzo-loop is the contract the loop applies: a tool shortlist per step, a
command verdict joined with the policy on allow < ask < deny, and routing
hints on the turn metadata. hanzo-kai links hanzoai/decision's control and
program at ec8207d: one controller per thread answers those three through
seven anchored upstream edits, and extension contributors feed it context,
progress and completion. kai.toml turns it on, every operation in shadow by
default. Each decision is one trace line in the shape Enso's control writes.

dev flow runs a Decision Program over the repository. The shipped fix flow
retrieves candidate files, Kai picks one, Zen writes a diff, the tests run,
and Kai says done, retry or escalate within what the tests and the budget
permit. go/dev.wasm is rebuilt because Cargo.toml, Cargo.lock and the
Makefile are among its recorded inputs.

Claude-Session: https://claude.ai/code/session_018Gt5TvrE2rxXuZikWSauv3
2026-09-26 12:59:11 -07:00

116 lines
4.9 KiB
Makefile

TOOL := cargo run --quiet --manifest-path crates/hanzo-upstream/Cargo.toml --
CARGO := RUST_MIN_STACK=8388608 cargo
.PHONY: all prepare build release install test test-upstream wasm wasm-check bump v8 fmt clean reset help
.DEFAULT_GOAL := help
all: build
## prepare: apply the owned edits to the pinned upstream checkout
prepare:
@$(TOOL) prepare
## build: build the dev binary
build: prepare
@$(CARGO) build --locked -p hanzo-dev --bin dev
## release: build the optimized dev binary
release: prepare
@$(CARGO) build --locked --release -p hanzo-dev --bin dev
## install: put the release binary on PATH
install: release
@$(CARGO) install --locked --path crates/hanzo-dev --bin dev
## test: run the Hanzo test suite
# hanzo-upstream is a detached workspace, so the root run cannot see it — and it
# is the code that edits upstream in place, which is the last thing to leave
# untested.
test: prepare
@$(CARGO) nextest run --locked --no-fail-fast $(ARGS)
@$(CARGO) nextest run --no-fail-fast --manifest-path crates/hanzo-upstream/Cargo.toml $(ARGS)
## wasm: build the reasoning half for wasm32-wasip1
# The loop as a wasm module: target/wasm32-wasip1/release/dev.wasm, copied to
# go/dev.wasm, which the Go host embeds.
#
# protocol and core carry no effects, so they run wherever a wasm host runs — and
# so does ffi, which is what a host actually calls. Its C ABI is the module's
# export list unchanged; only the memory differs, and dev_alloc lends the host a
# buffer inside it. What the module may IMPORT is the proof that the core touches
# nothing: environ_get, environ_sizes_get, fd_write and proc_exit, and no file,
# socket, clock or random source. A change that grows that list has given the
# loop an effect of its own.
#
# The copy is committed, so no path of the machine that built it goes in: no
# DWARF, which spells out the build directory, and the cargo home written as
# /cargo in the panic locations the dependencies carry. Two builds on one kind
# of host are then the same bytes, whatever their directories. Two kinds of
# host are not: cargo hashes the host into every crate that has a build script
# or uses a proc macro, and into every crate built on one, and the module
# differs with those hashes, code and all. macOS arm64, Linux arm64 and Linux
# x86_64 each build a different one.
# The name section stays, so a trap still says which function it stopped in.
#
# The remap goes in CARGO_ENCODED_RUSTFLAGS because cargo takes that over every
# other source of rustflags; any other source is dropped whole the moment a
# RUSTFLAGS is set, remap and all. The target directory is named too:
# CARGO_TARGET_DIR would send the build elsewhere, and the copy would be
# whatever an older build left here.
#
# CI builds on another kind of host, so it cannot rebuild the committed bytes;
# it checks what they were built from instead. Beside the copy goes
# go/dev.wasm.sum, the sha256 of every tracked file the build reads and of the
# copy itself. wasm-check hashes the tree again and fails on any difference, so
# neither a change to the crates that never ran make wasm, nor a copy committed
# without its sum, passes as current.
CARGO_HOME ?= $(HOME)/.cargo
WASM_SUM = git ls-files -z -- Makefile Cargo.toml Cargo.lock rust-toolchain.toml \
crates/protocol crates/core crates/ffi go/dev.wasm | xargs -0 sha256sum
wasm: prepare
@CARGO_ENCODED_RUSTFLAGS='--remap-path-prefix=$(CARGO_HOME)=/cargo' \
$(CARGO) build --locked --release --target wasm32-wasip1 --target-dir target -p dev-ffi \
--config 'profile.release.debug=false' \
--config 'profile.release.strip="debuginfo"'
@install -m 644 target/wasm32-wasip1/release/dev.wasm go/dev.wasm
@$(WASM_SUM) > go/dev.wasm.sum
## wasm-check: fail unless go/dev.wasm is make wasm of the tree beside it
wasm-check:
@$(WASM_SUM) | diff go/dev.wasm.sum - || { \
echo 'go/dev.wasm was not built from this tree: run make wasm, and commit go/dev.wasm and go/dev.wasm.sum' >&2; \
exit 1; }
## test-upstream: run the upstream suite against the pinned submodule
# voice-host wants GStreamer >= 1.28, which no current distribution ships, and
# nothing else in the workspace depends on it.
test-upstream: v8
@. target/v8-env.sh && $(CARGO) nextest run --no-fail-fast \
--manifest-path upstream/codex/codex-rs/Cargo.toml \
--workspace --exclude codex-voice-host $(ARGS)
## bump: move the upstream submodules to newer revisions
bump:
@$(TOOL) bump $(ARGS)
@$(TOOL) prepare
## v8: download and verify the V8 build the JavaScript runtime links
v8:
@$(TOOL) v8
## fmt: format the crates Hanzo owns
fmt:
@$(CARGO) fmt -p hanzo-dev -p hanzo-config -p hanzo-tui -p hanzo-kai -p hanzo-loop -p dev-protocol -p dev-core -p dev-ffi
@$(CARGO) fmt --manifest-path crates/hanzo-upstream/Cargo.toml
## clean: discard build output
clean:
@$(CARGO) clean
## reset: return the upstream checkout to its pinned revision
reset:
@git submodule foreach --quiet 'git reset --quiet --hard'
help:
@grep -hE '^## ' $(MAKEFILE_LIST) | sed 's/## / make /' | sort