Workflows #
Type: knowledge
Build, test, verify #
Worktree builds can seed from the primary checkout's Cargo target directory. This keeps Bevy/wgpu and other heavy dependencies warm without sharing local crate artifacts across source trees. Run this once after creating a worktree, before long Cargo commands:
tools/seed-cargo-target.sh
Do not point multiple worktrees at one shared CARGO_TARGET_DIR. Cargo can
reuse stale local-package artifacts across checkouts; this produced a false
green once (the test count matched main, not the edited worktree). The seed
script copies the cache (including dependency incremental/ dirs), removes
misaligned artifacts/fingerprints/incremental trees, and keeps the current
worktree's target/ private so local code rebuilds correctly while third-party
incremental compilation stays warm.
./tools/check.sh rejects external CARGO_TARGET_DIR by default for the same
reason; override only for a deliberately isolated target with
MISALIGNED_ALLOW_EXTERNAL_TARGET=1.
One command runs the whole gate — use it before every commit:
./tools/check.sh # fmt, tests, clippy (both features), bevy build, spec headers, wiki gate, mdbook build
check.sh is the executable form of AGENT.md's definition of done; if it
passes, the mechanical bar is met. Local dirty worktrees get a speed path:
when the only changed paths are docs/process/tooling that cannot affect Rust
artifacts, check.sh skips Cargo fmt/tests/clippy/Bevy and still runs shell
syntax, spec headers, the wiki gate, and mdBook. A clean checkout (including
CI after push) has no local diff to classify, so it always runs the full Rust
gate. Force the local full gate with MISALIGNED_FORCE_RUST_GATE=1 ./tools/check.sh.
The individual steps, if you need them:
cargo test # all in the lib (sim-heavy)
cargo clippy --all-targets # must stay at zero warnings
cargo fmt # rustfmt is enforced-by-convention since 05048e4
cargo build --features bevy_ui --bin misaligned-bevy # keep the Bevy build green
cargo build --features bevy_ui --bin misaligned-assets # procedural asset tester
cargo clippy --features bevy_ui --all-targets # ...and lint-clean
The definition of done for a functional change: check.sh green, and the
change was seen running (below) — the gate can't judge whether it plays.
Browsing the wiki #
Public site (Starlight). The wiki renders as a Tangled-hosted static
site from the orphan pages branch. Builder lives on main under
site/ (Astro + Starlight, clinical-gore theme). Source of truth remains
wiki/ + root DESIGN.md; site/scripts/sync-wiki.mjs copies them into
Starlight's content tree and builds the sidebar from wiki/SUMMARY.md.
pnpm --dir site dev # sync wiki + local preview (base=/)
./tools/site-build.sh # sync + build → site/dist/ (base=/misaligned)
./tools/site-deploy.sh # build, then force-push orphan pages branch
The public site opens on a splash homepage (site/src/pages/index.astro)
whose copy is drawn from DESIGN.md / README. It is a game-first
one-pager: the hero carries the MISALIGNED wordmark, the body sells the
actual loop (cover, concealment, intel, people, machine growth, rollback),
and the primary CTA is the constitution. Visual identity is allowed to carry
the mood, but the body should not spend a full section explaining palette
law unless the page is explicitly being redesigned as an art/process page.
The constitution lives at /constitution/; the wiki tree follows. Public
claims about the game are part of the constitution contract: amend DESIGN.md
if the pitch on the splash changes.
Per DESIGN.md's No unsourced surface law, every public site page and
asset needs provenance. wiki/interface/site.md is the binding visual spec;
site/README.md records the current asset/page mapping. If a homepage
image, standalone page, script, model, or generated output no longer has a
source clause, delete it or write the clause first.
Tangled Sites config (Settings → Sites on the repo) — required;
pushing pages alone does not publish. Until this is saved, Tangled's
edge returns plain Not Found at cameron.tngl.io/misaligned/ even
though origin/pages has a valid index.html:
- Branch:
pages - Deploy directory:
/(the orphan branch root isindex.html) - Site type: sub-path (served as
<your-domain>/misaligned)
After Save, check Recent Deploys on that settings page — a successful
deploy copies the branch into Tangled's object store. Re-save or push
pages again if the deploy list is empty.
site/astro.config.mjs sets base: '/misaligned' to match Tangled's
sub-path hosting (the edge strips /misaligned before looking up files;
Starlight still needs the base so asset URLs are correct). Local
pnpm --dir site dev overrides with SITE_BASE=/.
.tangled/workflows/site.yml runs ./tools/site-build.sh on every push
to main so the builder stays green. Publishing pages from CI is
deferred until a write credential exists under Settings → Secrets
(Spindle cannot push otherwise). Until then, run ./tools/site-deploy.sh
after wiki-facing landings when the public site should refresh. Optional
later step: add a deploy job that uses the secret to force-push pages
the same way site-deploy.sh does.
mdBook (local / check gate). Still wired for agent browsing and
tools/check.sh:
mdbook serve # local live-reloading server (default: http://localhost:3000)
mdbook build # static site in book/ (gitignored)
book.toml at the repo root points mdBook at src = "wiki"; the
constitution renders as the front page via wiki/DESIGN.md (a symlink
to ../DESIGN.md). Install once with cargo install mdbook — CI
enforces the build via the nixpkgs-provided binary regardless of what's
installed locally (.tangled/workflows/check.yml).
Running the game #
cargo run --release # terminal frontend
cargo run --release -- --agent --seed 1 # agent line protocol
cargo run --release --features bevy_ui --bin misaligned-bevy # Bevy frontend
cargo run --features bevy_ui --bin misaligned-assets # procedural asset tester
- The Bevy frontend must be run via
cargo run(or withBEVY_ASSET_ROOTpointing at the repo root): Bevy resolvesassets/fromBEVY_ASSET_ROOT, thenCARGO_MANIFEST_DIR, then the executable's directory. Running the binary directly fromtarget/silently loads zero assets. - The asset tester (
misaligned-assets) is a Bevy-only orbit viewer for flat-material procedural meshes — see art/asset-tester.md. It does not load the sim.
Headless smoke tests (they catch real bugs) #
Agent mode is the standard observed-run gate for terminal playability. It is
command-clocked, deterministic under --seed, and produces plain-text frames
with greppable terminators:
printf 'salvage\nwait 1\npeople\nreview janitor\nhelp\nquit\n' | \
cargo run --quiet --bin misaligned -- --agent --seed 1
./tools/check.sh runs this script twice with the same seed (stdout must be
byte-identical), once with a different seed (stdout must differ), and asserts
that the response contains no ANSI escape bytes plus the required frame/help
substrings. This replaces pty choreography as the default "seen running"
evidence for terminal behavior.
Human terminal chrome still needs pty coverage when raw-mode rendering, alternate-screen behavior, or size handling changes:
(printf '\n'; sleep 4; printf 'm'; sleep 1; printf '\r'; sleep 2; printf '\x1b'; sleep 1; printf 'q') | \
script -q /dev/null sh -c 'stty rows 40 cols 140; ./target/debug/misaligned'
The stty matters: script's pty is otherwise 0x0 (the game guards against
< 60x20 now, but you want a real render).
Bevy launch check (opens a window briefly; greps the log for failures):
BEVY_ASSET_ROOT=$PWD ./target/debug/misaligned-bevy > /tmp/bevy.log 2>&1 &
sleep 8 && kill %1; grep -iE "panic|ERROR" /tmp/bevy.log
Git conventions #
-
Use a task-named git worktree for every agent session; do not edit the primary checkout directly. Clean up the worktree when the work is committed and pushed/merged or explicitly handed off.
-
Cameron has standing permission for agents to commit coherent completed work in this repository. Be aggressive about committing; pause only for pending product/design questions, failing checks, unresolved conflicts, or explicit review gates.
-
Commits: no AI attribution, plain descriptive messages, body bullets for multi-part changes. Stage files explicitly —
git add -Ais not permitted. -
Ledgers merge by union.
wiki/log/DEVLOG.md, the DESIGN.md decisions log, and the wiki/process/specs.md tables are append-only records: resolve merge/rebase conflicts in them by keeping BOTH sides' entries, then ordering sensibly. Taking one side wholesale destroys parallel sessions' history (it happened 2026-07-06; three DEVLOG entries had to be restored). -
Spec-driven rule: functional change commits include their DESIGN.md amendment and any affected
Type: knowledgewiki updates (see development-style.md). -
Remote:
originis a Tangled knot (tangled.org, SSH). Land changes by merging tomaindirectly after./tools/check.shpasses. (The "PRs are the norm" rule was removed 2026-07-07 — CLI-created PRs write to the PDS but don't render on tangled.org, so the process could not be followed. See the DESIGN.md decisions log.) From your worktree:git fetch origin && git rebase origin/main git checkout main && git merge <branch> && git push origin mainOr, if the worktree branch is a fast-forward of main:
git fetch origin && git rebase origin/main git push origin HEAD:main -
Identity map: this machine has two SSH keys that authenticate to Tangled:
~/.ssh/id_ed25519(cameron@pfiffer.org) → Cameron's account (did:plc:gfrmhdmjvxn2sjedzboeudef, @cameron.stream). This key has push access to the misaligned repo. The misaligned repo is configured to use this key viagit config core.sshCommand(repo-local).~/.ssh/tangled_ed25519(void.comind.network@letta) →did:plc:mxzuau6m53jtdsbqe6f4laov(a different identity). This is the default key in~/.ssh/configfortangled.org, but it does NOT have push access to the misaligned repo.- The misaligned repo's own DID is
did:plc:t53fxjacrmulx3e5d3sbdfui(the repo identifier, not Cameron's account). access denied: user not allowedmeans the wrong SSH key is being used. Fix:git config core.sshCommand "ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes"(already set on this repo). Verify withssh -i ~/.ssh/id_ed25519 -T git@tangled.org.
-
.letta/settings.local.jsonis gitignored (machine-local session state);.letta/.lettaignoreis tracked.
Documentation flow per session #
- DESIGN.md amendment (if functionality changed).
Type: knowledgewiki page updates (if reality changed).wiki/log/YYYY-MM-DD-topic.mdsession writeup;wiki/log/DEVLOG.mdgets the short ledger line.