From bc83fde4ad39c977a2ac83bbd3ff2bfe6f5f9ac5 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 27 Jul 2026 12:53:12 +0200 Subject: [PATCH] claude-plugins: ship a hyperhive-authored notes-hygiene skill by default --- .../.claude-plugin/marketplace.json | 16 +++++++ .../notes-hygiene/.claude-plugin/plugin.json | 7 +++ .../skills/notes-hygiene/SKILL.md | 48 +++++++++++++++++++ flake.nix | 1 + nix/agent-modules/claude-settings.nix | 34 +++++++++---- nix/agent-modules/packages.nix | 4 +- nix/packages/claude-plugins.nix | 48 +++++++++++++++++++ nix/packages/default.nix | 5 ++ 8 files changed, 152 insertions(+), 11 deletions(-) create mode 100644 claude-plugins/.claude-plugin/marketplace.json create mode 100644 claude-plugins/plugins/notes-hygiene/.claude-plugin/plugin.json create mode 100644 claude-plugins/plugins/notes-hygiene/skills/notes-hygiene/SKILL.md create mode 100644 nix/packages/claude-plugins.nix diff --git a/claude-plugins/.claude-plugin/marketplace.json b/claude-plugins/.claude-plugin/marketplace.json new file mode 100644 index 00000000..af3d093c --- /dev/null +++ b/claude-plugins/.claude-plugin/marketplace.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", + "name": "hyperhive", + "description": "hyperhive-authored Claude Code plugins, shipped hive-wide via the default hyperhive.claudeMarketplaces/claudePlugins nix options (nix/agent-modules/claude-settings.nix). Built as a nix store path and added with `claude plugin marketplace add ` - no forge repo or git remote needed. Add a new plugins// subtree + one entry below to ship another.", + "owner": { + "name": "hyperhive" + }, + "plugins": [ + { + "name": "notes-hygiene", + "description": "Read-before-write discipline and dated-archive convention for durable agent notes/state files - use before archiving, overwriting, or pruning any notes/state file.", + "source": "./plugins/notes-hygiene", + "category": "productivity" + } + ] +} diff --git a/claude-plugins/plugins/notes-hygiene/.claude-plugin/plugin.json b/claude-plugins/plugins/notes-hygiene/.claude-plugin/plugin.json new file mode 100644 index 00000000..f0918a04 --- /dev/null +++ b/claude-plugins/plugins/notes-hygiene/.claude-plugin/plugin.json @@ -0,0 +1,7 @@ +{ + "name": "notes-hygiene", + "description": "Read-before-write discipline and dated-archive convention for durable agent notes/state files.", + "author": { + "name": "hyperhive" + } +} diff --git a/claude-plugins/plugins/notes-hygiene/skills/notes-hygiene/SKILL.md b/claude-plugins/plugins/notes-hygiene/skills/notes-hygiene/SKILL.md new file mode 100644 index 00000000..d78e643a --- /dev/null +++ b/claude-plugins/plugins/notes-hygiene/skills/notes-hygiene/SKILL.md @@ -0,0 +1,48 @@ +--- +name: notes-hygiene +description: Enforces safe handling of an agent's own durable state/notes files (e.g. state/notes.md, state/TODO.md, or anything else under state/ meant to survive a container restart) - read the file before archiving, overwriting, or pruning it, split resolved work into small dated archive files instead of growing one giant live file, and never shell-pipe-append (>>) into a notes file. Use this whenever you are about to write to a durable notes/state file, especially right before a context-compaction checkpoint, when told to "flush state" or "write down anything relevant", or when a live notes file has grown large and needs an archive pass. +--- + +# Notes Hygiene + +Durable notes/state files (your `CLAUDE.md`, `state/notes.md`, `state/TODO.md`, +and anything else under `state/`) are your memory across container resets and +context compactions. They only work if you actually read them before you +change them - writing blind is how history gets silently destroyed or +duplicated. + +## Before writing to any durable notes file + +1. **Read it first.** Never overwrite or append to a notes/state file based + on memory or assumption of its current contents - the file may have moved + on since your last read (another turn, another agent touched shared + space, a prior session ended mid-edit). Read (or re-read the relevant + section) immediately before editing. +2. **Never pipe-append.** Don't do `echo "..." >> state/notes.md` (or + equivalent) from a shell command. That's a blind write with no chance to + see - and reconcile with - what's already there. Use your file-edit tool + (read, then edit/write) instead. +3. **Prefer a targeted edit over a full rewrite** for anything long-lived: an + edit is less likely to accidentally clobber unrelated content than + regenerating the whole file from your current context. + +## Keeping a notes file lean + +- Split into a **live file** (only what's currently active/gated/relevant - + this is what you re-read every turn, keep it short) and an **archive** + (resolved/closed work, moved out of the hot path, never deleted). +- Archive in **dated, per-topic chunks** - `YYYY-MM-DD-.md` - not one + ever-growing archive blob. `ls` on the archive dir should read like a + timeline. +- When you finish a piece of work, collapse its entry in the live file to a + one-line "done" summary and move the full detail into a new dated + archive file. +- A live file well past ~500 lines (or into four figures) is overdue for an + archive pass - do it at a natural checkpoint (finishing a task, a + context-compaction prompt, or whenever you notice it). + +## Full convention + +The hive-wide version of these rules (read-only reference - don't duplicate +it into your own notes) lives at `/knowledge/notes-hygiene.md`; read that for +the complete rationale. diff --git a/flake.nix b/flake.nix index 4146a87a..5c127078 100644 --- a/flake.nix +++ b/flake.nix @@ -94,6 +94,7 @@ assets frontend reference-docs + claude-plugins ; }; }; diff --git a/nix/agent-modules/claude-settings.nix b/nix/agent-modules/claude-settings.nix index fe5c1943..5aac9f8b 100644 --- a/nix/agent-modules/claude-settings.nix +++ b/nix/agent-modules/claude-settings.nix @@ -228,7 +228,10 @@ in options.hyperhive.claudeMarketplaces = lib.mkOption { type = lib.types.listOf lib.types.str; - default = [ "anthropics/claude-plugins-official" ]; + default = [ + "anthropics/claude-plugins-official" + "${config.hyperhive.packages.claude-plugins}" + ]; example = [ "anthropics/claude-plugins-official" "anthropics/claude-plugins-community" @@ -242,14 +245,24 @@ in reference a marketplace (e.g. `foo@claude-plugins-official`). Rendered to `/etc/hyperhive/claude-marketplaces.json`. - Defaults to Anthropic's official marketplace; agents get it - out of the box without any per-agent.nix wiring. + Defaults to Anthropic's official marketplace plus hyperhive's + own `claude-plugins` nix package (see + `nix/packages/claude-plugins.nix`) — a local-path marketplace + built as a plain nix store path, registered under the name + `hyperhive` (from its `marketplace.json`, not the store path + itself, so plugin specs stay stable across rebuilds). No forge + repo or git remote needed to ship a hive-authored skill; agents + get both marketplaces out of the box without any per-agent.nix + wiring. ''; }; options.hyperhive.claudePlugins = lib.mkOption { type = lib.types.listOf lib.types.str; - default = [ "skill-creator@claude-plugins-official" ]; + default = [ + "skill-creator@claude-plugins-official" + "notes-hygiene@hyperhive" + ]; example = [ "formatter@my-marketplace" "thinking-tools@anthropics" @@ -264,15 +277,18 @@ in `/etc/hyperhive/claude-plugins.json`; the harness reads it via `plugins::install_configured`. - Defaults to Anthropic's `skill-creator`, which teaches an agent - to write, refine, and evaluate its own skills — agents get it - out of the box, matching the default marketplace above. + Defaults to Anthropic's `skill-creator` (teaches an agent to + write, refine, and evaluate its own skills) plus hyperhive's own + `notes-hygiene` skill (read-before-write + dated-archive + discipline for durable notes/state files) — agents get both out + of the box, matching the default marketplaces above. Note that a per-agent definition REPLACES this default rather than extending it (ordinary NixOS list-option semantics, same as `claudeMarketplaces`). An agent that wants extra plugins AND the - default should list `skill-creator@claude-plugins-official` - alongside them. + defaults should list both + `skill-creator@claude-plugins-official` and + `notes-hygiene@hyperhive` alongside them. ''; }; diff --git a/nix/agent-modules/packages.nix b/nix/agent-modules/packages.nix index af3052b8..ca465fee 100644 --- a/nix/agent-modules/packages.nix +++ b/nix/agent-modules/packages.nix @@ -13,8 +13,8 @@ per-binary daemon/CLI packages (`hive-agent`, `hive-agent-mcp`, `hive-bash-daemon`, `hive-forge`, `hive-forge-notify`, `hive-matrix-daemon`, - `hive-metric`, `hive-screen-mcp`) plus the `assets`, `frontend` and - `reference-docs` trees. Wired by the flake's agent-base/ruth + `hive-metric`, `hive-screen-mcp`) plus the `assets`, `frontend`, + `reference-docs` and `claude-plugins` trees. Wired by the flake's agent-base/ruth nixosModules to `hyperhive.packages..*`; override an individual key per-agent to swap in a patched binary. ''; diff --git a/nix/packages/claude-plugins.nix b/nix/packages/claude-plugins.nix new file mode 100644 index 00000000..b83896a0 --- /dev/null +++ b/nix/packages/claude-plugins.nix @@ -0,0 +1,48 @@ +{ + stdenv, +}: + +# hyperhive-authored Claude Code plugin marketplace (source tree at +# ../../claude-plugins), shipped as a standalone derivation and spliced +# into the *default* `hyperhive.claudeMarketplaces`/`claudePlugins` lists +# (nix/agent-modules/claude-settings.nix) as a local marketplace source. +# `claude plugin marketplace add` accepts a plain filesystem path (verified: +# `claude plugin marketplace add --help` → "Add a marketplace from a URL, +# path, or GitHub repo"), and registers it under the marketplace.json's own +# `name` field ("hyperhive") rather than the path — so +# `@hyperhive` is a stable plugin spec regardless of the store +# path's hash. The built store path IS the marketplace: no forge repo, no +# git remote, no PAT/PR ceremony needed to ship a skill hive-wide. +# +# Every hive-authored skill lives under its own `plugins//` subtree +# in the source tree; add one there plus a matching entry in +# `.claude-plugin/marketplace.json`'s `plugins` list to ship another. +# +# Pure data: nothing to build, `$out` is the tree as-is (mirrors +# ./reference-docs.nix). `cp -r . "$out"` (not `cp -r ./* $out`) because +# the marketplace/plugin manifests live under `.claude-plugin/` — a +# hidden directory a shell glob (`*`) would silently skip. +stdenv.mkDerivation { + pname = "hyperhive-claude-plugins"; + version = "0.1.0"; + # Narrow src keeps this derivation's input hash decoupled from the rest + # of the tree — a skill edit only re-hashes this. + src = ../../claude-plugins; + + dontBuild = true; + dontConfigure = true; + + installPhase = '' + runHook preInstall + mkdir -p $out + cp -r . "$out"/ + runHook postInstall + ''; + + dontFixup = true; + + meta = { + description = "hyperhive-authored Claude Code plugin marketplace (skills shipped hive-wide)"; + homepage = "https://forge.darkest.space/hyperhive/hyperhive"; + }; +} diff --git a/nix/packages/default.nix b/nix/packages/default.nix index 8a8746fe..b3759bb9 100644 --- a/nix/packages/default.nix +++ b/nix/packages/default.nix @@ -139,6 +139,11 @@ in # so the binary derivation stays cached when a prompt edit ripples # through. assets = pkgs.callPackage ./assets.nix { }; + # hyperhive-authored Claude Code plugin marketplace (source tree at + # ../../claude-plugins) — a local-path marketplace spliced into the + # default `hyperhive.claudeMarketplaces`/`claudePlugins` lists. See + # ./claude-plugins.nix for the "why a store path, not a repo" rationale. + claude-plugins = pkgs.callPackage ./claude-plugins.nix { }; # The repo docs/ markdown tree as a standalone derivation — # agents read it in-container (added as a claude additional # directory) and the website repo reuses it as a flake input,