Architecture decisions
Remote includes: git-only, mutable refs, cache-pinned, no lockfile
Remote references/includes resolve a build file from a git repository only (no HTTP transport). A reference may use a mutable ref (branch or tag) or an immutable commit SHA. There is no lockfile: the first resolution fetches the repo at the ref and caches it locally, and subsequent runs use the cached copy (so a machine is stable run-to-run, including offline). The cache — not a lockfile or an in-manifest SHA — is the pin. A dedicated refresh/pull command (and hammerkit clean --cache) re-fetches the latest for mutable refs. A commit SHA is the opt-in for full reproducibility.
Considered options
- HTTP transport — rejected: no natural immutable identity, and git's clone-at-commit makes a remote file's own relative
references/includesresolve trivially within the repo tree. - Committed lockfile — rejected for simplicity; the user prefers a cache-as-pin model refreshed by command.
- Reject mutable refs / SHA-only — rejected in favor of the clean-to-update / pull-to-refresh ergonomics; SHA remains available as the reproducible opt-in.
Consequences
- Deliberate trade-off: for a mutable ref, the pin is per-machine (the local cache). Nothing shared records which commit each machine froze, so a fresh CI runner pulls current branch HEAD while a developer's cache holds an older copy — the build definition itself can drift across machines with no record to detect it. This is accepted for distributing org best-practices; a commit SHA is the documented way to get cross-machine reproducibility.
- A remote file's relative
references/includesand paths resolve within the same repo at the same commit. - Credentials reuse standard git credential helpers — no new secret surface.
- Resolution executes nothing; a remote file contributes task/service/cache/env definitions only, and commands run only when a task is invoked.
- Naming (settled, #20): the refresh command is
hammerkit includes pull. Its verb would collide withcache pull(ADR-0001, which syncs cache artifacts), so it is namespaced under theincludescommand group to disambiguate the two operations. - Syntax (settled, #20): a
references/includesvalue is a string-or-object discriminated union. A string is a local path (unchanged). An object{ git, ref?, path? }is a git source —git(repo URL) required,ref(branch/tag/commit SHA, default repo HEAD) andpath(subpath) optional. The value's type selects the resolver, so the local-path form is unchanged.