Hexagram
I kept my conventions in a project-boilerplate directory and copied it into every new repo. Five
projects later the five copies disagreed with each other and with the original, and none of them had
been read since the day they were pasted. A copy nobody opens governs nothing.
Hexagram is that boilerplate turned into a Claude Code plugin. It installs once per machine, every repo sees the same version, and changing a rule is one edit in one place. The architecture it points at is the Deterministic Hexagon; the rest of it is the conventions that surround the architecture. Source at github.com/imgabrieldev/hexagram, MIT.
Install
/plugin marketplace add imgabrieldev/hexagram
/plugin install hexagram@hexagram
Restart, and that is the setup. The repo is its own marketplace, so there is nothing else to add.
What it carries
Fifteen skills. A skill loads when the task matches its description instead of sitting in context every session, which is why fifteen of them cost roughly nothing until one of them is the thing you are actually doing.
| skill | |
|---|---|
architecture | the Deterministic Hexagon, specified here |
language | everything that lands in a repo is English, and what counts as an exception |
testing | what to test at which layer, and whether a test kills the mutant its name describes |
clean-code | naming, function and file size, error handling |
diagrams | C4, Excalidraw in an Obsidian vault, and who owns the file |
naming | what a thing is called and where it lives, and which renames are a data migration |
git | committing, branching, submodule ordering, rewriting history |
terraform | infrastructure as code, which does not use the hexagon |
lint | format, lint and type checks, with the stack detected rather than configured |
workflow | pitch, research, decision, plan, implement, postmortem |
research | when a decision depends on something you do not know yet |
postmortem | when something shipped, or a claim turned out wrong |
pitch | the document that opens a piece of work, and the out-list that keeps it bounded |
init-project | scaffolds a repo with the parts that have to live on disk |
setup-machine | brings a machine up to the house plugin set |
Plus a hook that checks commit messages against the house rules, and a template that
/hexagram:init-project writes into a repo: the docs vault, a commit-msg hook, a statusline, a
gitignore, and a CLAUDE.md that points at the skills instead of restating them.
What a plugin cannot carry, and why
This is the part I would want to read first, because the limits decide how you use the thing.
A CLAUDE.md. It loads from the repo, from ~/.claude/, or from managed policy, and a plugin is
none of those. So /hexagram:init-project writes a small one that names the project and points at the
skills.
Rules that auto-load from a URL. MCP resources and prompts are opt-in: the model has to reach for
them. An MCP server’s instructions do load at session start, but briefly. Skills are the closest
thing, and they beat a CLAUDE.md that loads every session whether the task needs it or not.
A git commit-msg hook, on its own. A plugin cannot write to your git config, so installing one
is never automatic. It happens because you ran /hexagram:init-project, which copies the hook and
sets core.hooksPath for that repo. You can also do it by hand and machine-wide with
git config --global core.hooksPath ~/.githooks, and there is a trap in that: core.hooksPath
replaces .git/hooks rather than adding to it, and git warns about nothing. Machine-wide, it silently disables
any hook already sitting in a .git/hooks anywhere. lefthook and pre-commit install theirs there.
husky is safe, because it sets core.hooksPath in the repo’s own config, which beats --global. It
also defeats init.templateDir, whose seeded hooks land in .git/hooks and stop being read. Use one
or the other, never both.
The statusline. A plugin’s settings.json accepts agent and subagentStatusLine, and nothing
else.
Staying current
plugin.json carries no version field, on purpose. The plugin tracks the commit SHA, so a push is
the release. Pin a version and every machine sits on “already at the latest version” until someone
remembers to bump it, which is the failure this avoids.
Keeping machines current turned out to be the interesting problem, and the answer is a SessionStart
hook that fetches and installs in the background, at most once a day, and asks for a restart on the
next session. HEXAGRAM_NO_SELF_UPDATE=1 turns it off.
Claude Code has its own path for this, and it does not cover the case:
- Marketplace auto-update is a setting on the installing machine. It is absent from the
marketplace.jsonschema at both levels, so nothing a publisher commits can turn it on for you. - Third-party marketplaces default to off. Only the official Anthropic ones default to on.
- Even switched on, it is gated behind Claude Code’s own binary
self-updater. Where that
updater is disabled, and it is disabled inside the desktop app and on package-manager installs
because something else owns the binary there, plugin auto-update goes with it. The documented escape
is
FORCE_AUTOUPDATE_PLUGINS=1alongsideDISABLE_AUTOUPDATER. Others have hit the same wall: #86139 measured twelve days of a marketplace that never advanced.
So the hook is the only update path the publishing side controls, and that is why a plugin this small
ships one at all. If you would rather the platform did the work, enable auto-update for the
marketplace in /plugin, set the variable where the self-updater is off, and set
HEXAGRAM_NO_SELF_UPDATE=1 so the two do not overlap.
One thing no update can reach, by design: a session already running keeps the version it started with.
When not to install this
These are my conventions, and some of them are load-bearing opinions rather than neutral defaults.
Everything that lands in a repo is English, including commit messages, which is a real cost if your
team works in another language. The scaffold assumes a docs vault you may not want, and the
commit-msg hook it installs rewrites your commit message on the way in rather than asking.
Take the architecture on its own if that is the part you came for. It is the same spec, and it costs nothing to read.