--- description: sow-tools / Crucible — the build/conversion/sync toolchain repo. alwaysApply: true --- # sow-tools / Crucible Agent Guide This repo owns the **builder logic:** one Go module (`git.westgate.pw/ShadowsOverWestgate/sow-tools`) producing the `crucible` dispatcher and the `crucible-` binaries. ## What it is / part it serves Shadows Over Westgate (SoW) is a Neverwinter Nights: Enhanced Edition persistent world, split into single-purpose repos. This repo is Crucible, the Go build toolkit. The content repos hold game source (module areas, rules data, binary assets) and call Crucible to turn that source into artifacts: the `.mod` file, 2DA/TLK tables, HAKs, wiki pages. Crucible is the only place builder logic lives; content repos only run it through thin wrapper scripts. ## Guidance map | Where | What | |-------|------| | `cmd/crucible/`, `cmd/crucible-/` | dispatcher + per-builder shims (thin `main.go` files) | | `internal/dispatch/` | the command registry — single source of truth for the command surface | | `internal/` (app, pipeline, project, erf, gff, topdata, changelog, validator, depot, menu, buildinfo) | the actual builder logic | | `wrappers/` | canonical bootstrap wrappers (`crucible`, `crucible.ps1`) synced to consumer repos; `wrappers/consumers.txt` lists targets | | `docs/command-surface.md` | every command, old `nwn-tool` name → new home | | `docs/consumer-contract.md` | how consumer repos resolve/pin a Crucible binary | | `docs/migration-from-nwn-tool.md` | migration status, what remains | | `tests/`, `Makefile`, `flake.nix` | checks, targets, dev shell | Task routing: adding/changing a command → read `docs/command-surface.md` first, then `internal/dispatch`. Changing how consumers get binaries → `docs/consumer-contract.md` + `wrappers/`. Release/CI questions → README "CI" section and `.gitea/workflows/`. ## How it is used - Dev loop: `nix develop`, then `make check` / `make build` / `make smoke` (see Commands below). - Release: push a `v*` tag. CI uploads cross-built binaries + wrappers to the Gitea release. There is no container image; Crucible ships as binaries, wrappers, and the Nix input. - Consumers (they download released binaries via the wrapper; they never vendor a toolkit): - sow-module — https://git.westgate.pw/ShadowsOverWestgate/sow-module - sow-topdata — https://git.westgate.pw/ShadowsOverWestgate/sow-topdata - sow-assets-manifest — https://git.westgate.pw/ShadowsOverWestgate/sow-assets-manifest - sow-platform (infra/deploy authority) — https://git.westgate.pw/ShadowsOverWestgate/sow-platform ## What this repo owns / does not own Owns: build/extract/validate/compare pipeline, ERF/HAK packing, topdata 2da/tlk compilation, wiki rendering/deploy, depot blob verify, changelog. Does **not** own authored game content (that is `sow-module` / `sow-topdata` / `sow-assets-manifest`) or any production deploy authority (that is `sow-platform`). ## Rules 1. **Fail closed, never fake.** A builder with no migrated logic yet (`depot`) exits `70`. Do not stub a builder to emit a placeholder artifact. 2. **Binaries are not committed.** They are CI artifacts. `/bin/`, `*.exe`, `nwn-tool`, `sow-toolkit` are gitignored. 3. **The registry is the command surface.** `internal/dispatch.Registry` is the single source of truth; keep it in sync with `cmd/` and [`docs/command-surface.md`](docs/command-surface.md). Adding a builder = a `cmd/crucible-/main.go` shim + a `Registry` entry + a doc row. ## Wiring a builder 1. Ensure the relevant `internal/` package(s) cover the work. 2. Add tests; keep outputs deterministic (same input → same bytes). 3. `make check` must stay green; update `make smoke` to expect the wired exit. ## Commands ```bash nix develop && make check # vet + test + shellcheck + yamllint make build # cmd/* -> ./bin make smoke # assert fail-closed contract ``` ## Tests Tests must survive harmless changes to constants, defaults, wording, ordering, fixture data, and internal implementation details. A test that fails merely because a basic value changed is usually a bad test. Only assert exact values when the value is part of a documented public contract, external protocol, compatibility requirement, security rule, migration, or business rule.