Replaces the "always dispatch via the Agent tool" instruction with a direct Bash-tool run_in_background pattern, following the harness's own task-notification mechanism instead of trusting a subagent's self-reported "I'll report back." Confirmed broken 2026-09-03: a general-purpose subagent given the exact "wait for it, do not background it" instruction redirected the build to a log file, announced it would report back once finished, and returned immediately with no result -- its own Agent-tool call showed completed with nothing to relay. The harness did eventually deliver a second, fuller notification for that same subagent several minutes later, but a controller cannot rely on that arriving, per the prior "fork claimed will report back, never reachable in a new session" incident already logged in .wolf/cerebrum.md. The new pattern (proven reliable twice this session: a full `all debug` build and a `controller` ASAN rebuild) runs the resolved command directly with Bash's own run_in_background, waits for the harness's real completion notification, then reads only the log's tail plus a targeted error grep -- keeping context usage low without depending on a subagent's compliance. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAWMhfRJFnmmnG8h97yUDd
12 KiB
| name | description | disable-model-invocation | allowed-tools |
|---|---|---|---|
| xce-build | Build XCE components with tests. Usage: /xce-build [component] [profile] [build_dir] [--incremental]. Components: all (default), lib, controller, scheduler, worker, apiserver, xcecli, xceadmin. Profiles: asan (default), debug (non-ASAN -O0 -g3 for gdb/cores), release. | false | Bash(*) |
build xce source code
Args: [component] [profile|build_dir] [build_dir] [--incremental] — passed as free text after /xce-build, e.g. /xce-build controller debug. --incremental can appear anywhere in the words (it's stripped out before the rest are parsed positionally — see below). Parse the ARGUMENTS text yourself and run the command below with the parsed values inline.
- No
context: fork, intentionally. It was tried (twice) and reproducibly breaks this skill: whenever ARGUMENTS is non-empty (e.g.controller), the forked subagent receives no usable task — it responds as if handed only ambient project context, never runs the build, and reports nothing back. Bare/xce-build(no args) happens to still "succeed" undercontext: forkonly because the empty-arg case is indistinguishable from no task at all failing open into some default — not because forking works. Do not re-addcontext: forkhere without first confirming the harness actually threads a non-empty ARGUMENTS payload into the forked subagent's prompt. - component (1st word, default
all) —all,lib,controller,scheduler,worker,apiserver,xcecli,xceadmin - profile (2nd word, default
asan) —asan(debug + AddressSanitizer →xce.build),debug(non-ASAN-O0 -g3 -fno-inline -fno-omit-frame-pointer→build.dbg),release(-O3, no sanitizer →build.release). Each profile uses its own default build dir so the variants never clobber each other. If the 2nd word isn't one of these three keywords, treat it as a legacy explicit build_dir instead (3rd word, if present, always overrides the build dir). - Use the
debugprofile to root-cause heisenbug crashes that ASAN perturbs away and that gdb-on-release turns into a hang/timeout — the non-ASAN-O0 -g3build reproduces them and gives a fully symbolized backtrace under gdb (how bug-1282/bug-1286 were cracked). controlleralways buildsxce_testtoo (meson compile … xce_controller controller_unit_test controller/xce_test), in every profile — not justasan.xce_testis the driver/xce-test-haneeds; you never have to build it as a separate step after/xce-build controller, and the two binaries in a build dir are always the same commit/profile in lockstep.xceadminis Python, meson-driven (src/xceadmin/meson.build'scustom_targetwrapsmeson-build.sh), and ignores the ASAN/debug/release sanitizer semantics entirely —xce-build.sh'sxceadmincase just runsmeson compile -C "$BUILD_DIR" xceadmin, the same targetnix build .#xcecoreand every other component use; theprofilearg is accepted but has no effect on it (every invocation does the identical pinned, non-editable, out-of-tree install + test, regardless ofasan/debug/release— unlike the old editable-install-by-default behavior, this always exercises real packaged schema resolution, not just areleaserun). For fast iterative dev without a full meson reconfigure,xceadmincan still be built standalone:cd src/xceadmin && pip install -e .(seemeson-build.shfor the exact out-of-tree steps the meson target itself runs). Every invocation syncs the bundledcontroller.capnp/c.capnpand the 7 JSON validation schemas fromsrc/schema/andsrc/configs/schema/intoxcecommon's packagedschema_files/, installs pinned into a fresh build-dir venv, runspytestagainst that install, and — only after tests pass — builds an installable wheel from that same schema-synced tree into$BUILD_DIR/xceadmin/dist/xceadmin-<version>-py3-none-any.whl(pip wheel … --no-deps, so it's xceadmin's own wheel only, not a vendored bundle ofclick/pycapnp/etc).xce-build.shprints the wheel's path and a ready-to-runpip install "<path>"line after the build. Requires the nix dev shell (pycapnp,pyyaml,jsonschema,click,pytest,ruff— all provided bysrc/nixSupport/xce.nix).--incremental(bug-1565 escape hatch, opt-in, NOT the default): every invocation normally doesrm -rf "$BUILD_DIR"+ a full freshmeson setup, unconditionally — correct in isolation, but since the actual compile step afterward only rebuilds the ONE requested component, a plain single-component build silently deletes any OTHER already-built binary sharing that dir (e.g./xce-build xceadminafter/xce-build controllerwipesxce_controller). Pass--incrementalto reconfigure the existing dir in place instead (meson setup --reconfigure), preserving whatever else was already built there — use it specifically when you want a sibling component alongside an already-built one, e.g./xce-build controllerthen/xce-build xceadmin --incrementalto end up with both in the same dir at once (needed for/xce-deploy-ha, which wantsxce_controller+xcecd_virtual+xce_scheduler+ the xceadmin wheel all together). Deliberately not the default: this project's capnp-generationcustom_targethas documented, unfixed missing-dependency-edge races (buglog.json — normally papered over as a loud, retry-fixable failure on a clean build; skipping the wipe could instead let the same gap cause silent staleness). If anything looks wrong after an incremental build, rebuild without the flag.
Examples: /xce-build controller (ASAN), /xce-build controller debug (gdb/core build), /xce-build all release, /xce-build xceadmin (build + test + wheel, any profile arg is accepted and ignored), /xce-build xceadmin --incremental (same, but keeps other components already built in the same dir).
Run (substituting the parsed component/profile/build_dir; omit trailing empty ones; append --incremental at the end, anywhere, when requested):
nix develop ./src --command bash src/tools/xce-build.sh <component> <profile> <build_dir> [--incremental]
e.g. for /xce-build controller: nix develop ./src --command bash src/tools/xce-build.sh controller. For /xce-build xceadmin --incremental: nix develop ./src --command bash src/tools/xce-build.sh xceadmin --incremental.
Run the build via Bash run_in_background, not an Agent-tool subagent
Do not dispatch the build to an Agent-tool subagent (confirmed broken 2026-09-03: a general-purpose subagent given this exact instruction redirected the build to a log file, announced "I've kicked off the build in the background... I'll report back once it finishes," and returned immediately — its own Agent-tool call then shows as completed with no build result. That "I'll report back" is not reliable: the parent has already regained control and cannot assume a second notification is coming. In this occurrence the harness did eventually deliver a second, fuller notification for the same subagent several minutes later, but a controller cannot bank on that — a near-identical pattern in an unrelated cross-session case never came back at all, per the OpenWolf cerebrum warning "A fork/subagent dispatched in a prior session that claimed 'build/tests in progress, will report back' is NOT reachable in a new session." A model instructed in plain English to "wait, don't background it" backgrounding it anyway is the actual failure mode — a differently-worded subagent prompt is not a reliable fix for that).
Instead, run the resolved command directly with the Bash tool's own run_in_background: true, from the current session, and let the harness's own task-notification mechanism — not a subagent's self-report — tell you when it's done. This has been empirically proven reliable in this exact repo (2026-09-03: both a full all debug build and a controller ASAN rebuild were driven this way, and each genuinely blocked until real completion).
nix develop ./src --command bash src/tools/xce-build.sh <component> <profile> <build_dir> [--incremental] \
> <scratchpad>/xce-build-<component>-<profile>.log 2>&1; \
echo "EXIT_CODE=$?" >> <scratchpad>/xce-build-<component>-<profile>.log
Call this once with run_in_background: true (substitute the resolved component/profile/build_dir and a scratchpad log path first — do not make anything downstream re-parse ARGUMENTS). Then stop and wait; do not poll, sleep-loop, or call ScheduleWakeup — the harness delivers a <task-notification> the moment the process exits, exactly like any other backgrounded Bash command. When it arrives, read the log's tail (e.g. tail -30) plus a targeted grep -nE "error:|FAILED|undefined reference|Traceback" rather than the whole log, to get the meson test Ok/Fail summary line and any failures without pulling the full (often thousands-of-lines) compiler output into context. Then ls -la the expected output binaries to confirm fresh mtimes, the same verification this skill has always asked for — just performed directly instead of trusted from a subagent's claim.
This is deliberately not context: fork either — that frontmatter field reproducibly failed to thread a non-empty ARGUMENTS payload into a forked subagent (see above). Running the resolved command directly via Bash/run_in_background sidesteps both failure modes: there is no subagent in the loop to either drop the ARGUMENTS payload or silently background-and-return.
Installing the xceadmin wheel elsewhere
/xce-build xceadmin always leaves a fresh, tested wheel at
<build_dir>/xceadmin/dist/xceadmin-<version>-py3-none-any.whl (e.g.
xce.build/xceadmin/dist/xceadmin-0.1.0-py3-none-any.whl). It's a normal
wheel — pip install it anywhere a compatible Python is available, no nix
or meson needed at install time:
pip install /path/to/xce.build/xceadmin/dist/xceadmin-0.1.0-py3-none-any.whl
The wheel bundles its own schema_files/ (the same controller.capnp,
c.capnp, and 7 JSON schemas synced in above) so xceadmin config build
works fully standalone against any src/configs/-shaped directory — it
does not need to run from inside this repo or the nix dev shell. Its 4 real
runtime imports (click, pycapnp, PyYAML, jsonschema —
pyproject.toml's dependencies, verified against every actual import
in src/xceadmin/src/xcecommon) are declared, so a plain pip install
resolves them from PyPI on its own; the one caveat is pycapnp, whose
prebuilt PyPI wheels are usually fine outside the nix shell but aren't the
same guaranteed-consistent link against the capnproto C++ runtime the nix
shell's own python3Packages.pycapnp gets (see pyproject.toml's
dependencies comment).
For that guarantee, do NOT use a --system-site-packages venv — tried
and confirmed broken: this nix devShell injects click/pycapnp/PyYAML/
jsonschema via $PYTHONPATH, not into the base python3 interpreter's own
site-packages (it's the bare interpreter derivation; each package is a
separate /nix/store/... path added to $PYTHONPATH by the shell hook —
confirmed via nix develop … --command sh -c 'echo $PYTHONPATH'). A
--system-site-packages venv only inherits the base interpreter's own
(empty) site-packages, so it silently can't see any of them —
ModuleNotFoundError: No module named 'click' the moment you actually run
it, even though the venv's own pip install step succeeds. Instead extract
the wheel directly and bake the resolved $PYTHONPATH into a wrapper at
install time (no venv/pip needed at all) — this is exactly what
/xce-deploy-ha's deploy-ha.sh does for scripts/xceadmin, and it's
proven to work with zero nix/network dependency at runtime:
mkdir -p /path/to/xceadmin-site
python3 -m zipfile -e /path/to/xceadmin-0.1.0-py3-none-any.whl /path/to/xceadmin-site
nix develop ./src --command bash -c '
cat > /path/to/xceadmin << EOF
#!'"$(nix develop ./src --command which bash)"'
export PYTHONPATH="/path/to/xceadmin-site:$PYTHONPATH"
exec '"$(nix develop ./src --command which python3)"' -m xceadmin.cli "\$@"
EOF
chmod +x /path/to/xceadmin
'
($PYTHONPATH must be expanded inside the nix develop --command shell,
not the outer one, so the resolved nix store paths get baked into the
wrapper literally — see deploy-ha.sh's own xceadmin-install block for the
exact working pattern.)