Packs and opt-in¶
A pack is a directory in the hub's packs/, laid out like the target repository:
packs/agents/AGENTS.md becomes AGENTS.md, packs/claude/.claude/settings.json
becomes .claude/settings.json. Every file in it is delivered. Only packs/ is
delivered; the rest of the hub configures it.
packs/
agents/
AGENTS.md
.agents/project.md
.agents/prompts/review.md
claude/
CLAUDE.md
.claude/settings.json
A pack's name is lowercase words of letters and digits joined by single hyphens, at most 64 characters.
Which packs a target gets¶
The hub assigns packs in targets.yml; the target adds packs in its opt-in file. The
final list, in order:
defaults.packsoftargets.yml;- the
packsof every entry oftargets.ymlthat matches the target, in file order; - the
packsof the target's opt-in file.
Duplicates are dropped; the first occurrence stays. Each pack's requires from
hub.yml is added and placed before it. When two packs ship the same path, the later
one wins: a pack can override a file of a pack it requires.
# hub.yml
packs:
agents:
description: AGENTS.md for every coding agent, a project profile to fill in
claude:
description: Claude Code instructions, skills and settings
requires: [agents]
python-library:
formerly: [python-lib]
The hub sets the minimum: a target can add packs and ignore paths, but it can't remove a pack the hub assigns. The central choice stays with the organisation, and every exception is visible in the target itself.
Opt-in¶
A target receives nothing until it has the opt-in file, .engineering-assets.yml at its
root (opt_in_file in hub.yml renames it), or the hub subscribes it (below). An empty
file is consent.
packsadds packs. A pack that does not exist in the hub blocks the target withopt-in-invalid.ignorelists paths or globs touchmark must never create, update or delete there. A path without glob characters covers everything beneath it;**matches any number of directories.- Editing
packsorignoreis a new choice of the team, so it lifts every decline the repository made: see memory. enabled: falseopts the repository out, whatever the hub says.
The opt-in file belongs to each repository: touchmark check rejects a pack that ships
it.
When the hub subscribes¶
Consent by file suits a hub that offers packs to teams. A hub that keeps its own
organisation's repositories in line can subscribe them instead: opt_in: assumed on an
entry of targets.yml (or in its defaults) makes every repository the entry selects
count as opted in without the file, as if it had an empty one.
| The repository has | It gets |
|---|---|
no opt-in file, and no entry that selects it says assumed |
nothing (skipped:not-opted-in) |
no opt-in file, and an entry that selects it says assumed |
the packs of targets.yml, nothing ignored |
| an opt-in file | the packs of targets.yml and of the file, minus what it ignores |
an opt-in file with enabled: false |
nothing (skipped:opted-out); its open sync pull request is closed |
One entry with assumed is enough: entries add up, as their packs do. The consent moves,
the choice does not: the first sync pull request of a subscribed repository says the hub
subscribed it and how to opt out, and closing it is a decline like any other. Deleting
the opt-in file of a subscribed repository returns it to the hub's subscription; only
enabled: false opts it out. See targets.yml.
Renaming and retiring¶
- Rename a pack by moving its directory and listing the old name under
formerly. The old name's history then counts as the new pack's own, and files it shipped stay managed.checkrejects aformerlyname that is still a current pack, or that two packs claim. - Retire a file by deleting it from the pack: targets whose copy is still the hub's
get it deleted (
retired); targets that changed it keep it (retired-local). - Stop assigning a pack by taking it out of
targets.yml: its files stay in the targets, listed asorphaned.
What makes a good pack¶
- Shared instructions, local facts. Keep tracker keys, branch patterns, the pull request language and build commands out of shared files. Put them in a project profile each team fills in (a seed file), and have the shared instructions point to it.
- Seed files. A file a team is expected to fill in ships as a skeleton. Once edited, it is the repository's own.
- At least 64 bytes per file, regular files only:
checkrejects smaller files, symlinks and submodules, a top-level.lfsconfig, and two paths that differ only by case. - No descriptions inside the pack. Every file in it is delivered: describe a pack in
hub.yml, not in a README inside it.
See Write packs for the workflow.