plugin

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.

Left: three repositories each holding its own drifted copy of the rules, versions v1, v1-prime and v2. Right: three repositories with no local copy, all resolving to one installed plugin. a copy per repo repo rules v1 repo rules v1' repo rules v2 three copies, three opinions one install per machine hexagram repo repo repo no local copy to drift

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
architecturethe Deterministic Hexagon, specified here
languageeverything that lands in a repo is English, and what counts as an exception
testingwhat to test at which layer, and whether a test kills the mutant its name describes
clean-codenaming, function and file size, error handling
diagramsC4, Excalidraw in an Obsidian vault, and who owns the file
namingwhat a thing is called and where it lives, and which renames are a data migration
gitcommitting, branching, submodule ordering, rewriting history
terraforminfrastructure as code, which does not use the hexagon
lintformat, lint and type checks, with the stack detected rather than configured
workflowpitch, research, decision, plan, implement, postmortem
researchwhen a decision depends on something you do not know yet
postmortemwhen something shipped, or a claim turned out wrong
pitchthe document that opens a piece of work, and the out-list that keeps it bounded
init-projectscaffolds a repo with the parts that have to live on disk
setup-machinebrings 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.json schema 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=1 alongside DISABLE_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.