Module System
HQ uses a module system to pull external git repositories into an HQ instance. Each module maps a repository (or subdirectories within one) to one or more destinations inside the HQ directory. A declarative manifest lists the modules, and a lock file pins them to specific commits for reproducible syncs.
The module system is implemented in hq-cli (
hq modules …). Content packs installed withhq installare recorded in the same manifest.
Manifest
On a fresh HQ the manifest lives at modules/modules.yaml. An existing flat modules.yaml at the HQ root is still read if present. The manifest holds a version and an array of module entries:
version: '1'modules: - name: ralph-methodology repo: https://github.com/indigoai-us/ralph-methodology branch: main strategy: link paths: - src: docs dest: knowledge/public/Ralph - name: knowledge-workers repo: git@github.com:indigoai-us/knowledge-workers.git strategy: merge paths: - src: . dest: knowledge/public/workersFields (git-repo modules)
| Field | Required | Description |
|---|---|---|
name | yes | Unique module identifier |
repo | yes | Git URL (https:// or git@) |
branch | no | Branch to track (defaults to main) |
strategy | yes | link, merge, or copy |
paths | yes | Array of { src, dest } mappings. src is a path inside the module repo; dest is a path relative to the HQ root |
access | no | public, team, or role:<name> |
Entries with strategy: package are content packs written by hq install. They carry source, version, installed_at, and (for git sources) resolved_sha instead of repo and paths. hq modules sync skips them; packs are wired by the pack installer.
Lock File
modules.lock at the HQ root maps each module name to a commit SHA:
version: '1'locked: ralph-methodology: abc123def456... knowledge-workers: 789fed321cba...hq modules sync rewrites the lock with the commit each module ended on. hq modules sync --locked checks out the recorded commits instead of pulling the branch head, so syncs are deterministic across machines.
Strategies
Link
The link strategy creates relative symlinks from each dest to the matching src inside the module clone at modules/<name>/.
knowledge/public/Ralph → ../../modules/ralph-methodology/docs- An existing symlink at
destis replaced. - A real file or directory at
destis left alone, and the CLI prints a warning. - Symlinks are relative, so they keep working if the whole HQ directory moves.
link is the default for hq modules add.
Merge
The merge strategy copies files from the module into dest and records a SHA256 hash per file in .hq-sync-state.json at the HQ root.
For each file:
- Hash the source file.
- If the destination exists, hash it and look up the hash recorded at the last sync.
- If the destination changed since the last sync and differs from the source, skip it as a conflict. Local edits are kept.
- Otherwise copy the file and record the new hash.
Use merge when the destination needs to be editable locally but should still receive upstream updates.
Copy
copy is accepted in the manifest but currently runs the merge implementation.
Commands
hq modules add <repo-url>
Adds an entry to the manifest. It does not clone anything; run hq modules sync afterward.
| Option | Default | Description |
|---|---|---|
--as <name> | Repo name from the URL | Module name |
--branch <branch> | main | Branch to track |
--strategy <strategy> | link | link, merge, or copy |
--path <src:dest> | .:workers/<name> | Path mapping (repeatable) |
The URL must start with https:// or git@. The default name is the last path segment with any .git suffix removed (for example https://github.com/indigoai-us/knowledge-workers.git becomes knowledge-workers).
hq modules sync
For each git-repo module in the manifest:
- Clone the repo into
modules/<name>/, or fetch it if the clone exists. - Pull the tracked branch, or check out the locked commit with
--locked. - Apply the module’s strategy to each path mapping.
- Record the resulting commit in
modules.lock.
hq modules sync # sync to the latest commit on each branchhq modules sync --locked # sync to the commits recorded in modules.lockThe first run adds modules/ to .gitignore.
hq modules list
Lists every module in the manifest with its repo or source, strategy, and current commit.
hq modules listhq modules update [module-name]
Fetches and pulls the module clone, then writes the new HEAD commit to modules.lock. With no name, all modules are updated. It does not re-apply strategies; run hq modules sync --locked afterward to apply the new commits.
hq modules update ralph-methodologyhq modules updateUtilities
findHqRoot() walks up from the current directory until it finds a .claude/ or workers/ directory, so module commands work from any subdirectory of HQ.
parseRepoName() extracts the module name from an HTTPS or SSH GitHub URL.
Adding a Module
hq modules add https://github.com/indigoai-us/knowledge-design-styles \ --as knowledge-design-styles \ --path "docs:knowledge/public/design-styles"hq modules syncqmd updatehq modules sync adds modules/ to .gitignore, so the clones (and a manifest stored at modules/modules.yaml) are not tracked by HQ git.