Skip to content

Repository files navigation

Claude assets

Personal collection of Claude Code skills, agents, and hooks.

Layout

  • skills/ — Agent Skills: one directory per skill with a SKILL.md entrypoint (YAML frontmatter with a description, then instructions) plus optional supporting files. The directory name becomes the /<name> command; Claude can also load a skill automatically when its description matches the task. Deploys to ~/.claude/skills/<name>/ — symlinked entries are officially supported.
  • agents/ — Subagents: one Markdown file per agent with YAML frontmatter (name, description, optional tools, model) followed by the agent's system prompt. Identity comes from the name field, not the filename. Deploys to ~/.claude/agents/.
  • hooks/ — Hooks: scripts run at lifecycle events (PreToolUse, Stop, SessionStart, …). There is no autoload directory: linking a script into ~/.claude/hooks/ only places the file — it must also be registered by path under hooks in settings.json to run.
  • examples/ — scratch material, git-ignored

The project catalog

hooks/project-catalog.py is a SessionStart hook that gives a session awareness of the other projects on the machine — one line each: name, path, one-line role, last activity — the more recent of your last Claude session there and the repository's last ref movement, both read by stat() so nothing waits on git. That is existence awareness only; content awareness stays an action, and project-catalog.py show <name> is that action, reading the named project's git state and README live rather than storing a copy that would drift.

Its data — names, paths, roles — lives in ~/.claude/catalog/projects.yaml and never in this repository, which is public. The upsert subcommand refuses to write anywhere inside its own checkout, so the separation is structural rather than remembered; CATALOG_REDACT=1 renders entries not marked visibility: public as bare names. That directory is meant to be a clone of a private repository — which is why the refusal is scoped to this checkout rather than to any git worktree: a guard that refused every repository would refuse the supported backup. Entries are written by the index-project skill, from inside the project being catalogued — the one-line role is a judgment call, and the session with that project loaded is the only one able to make it.

check holds every entry to those same rules — including entries typed into the file by hand, which no write path ever sees — and the index says when the file it just read breaks them. Writing an entry never pushes: a network write per entry is not the tool's decision to make. It does say when the catalog holds changes that exist only on this machine, and project-catalog.py backup commits and pushes them in one step.

Enabling it takes the two steps every hook takes:

./manage.py enable project-catalog     # symlink into ~/.claude/hooks/
./manage.py enable index-project       # and the skill that writes entries

then a SessionStart entry in ~/.claude/settings.json pointing at ~/.claude/hooks/project-catalog.py — linking the script alone does nothing. It is a user-wide asset: a catalog of every project is not a thing to --target into one project's .claude/.

Legacy slash commands (a bare commands/<name>.md) are still understood by the tooling, but no commands/ directory is kept — new work should be a skill, which covers the same /<name> invocation and more.

Usage

manage.py enables/disables assets by symlinking them into ~/.claude/ (user-wide) or, with --target, a project's .claude/ directory:

./manage.py status                        # list assets and their state
./manage.py enable --all                  # link everything
./manage.py enable my-skill               # link selected assets by name
./manage.py enable agents/my-agent        # qualify with kind/ if a name is ambiguous
./manage.py disable my-skill              # remove the symlink
./manage.py --target ../app/.claude enable my-skill

It only ever removes symlinks pointing into this repo — real files and foreign symlinks at a link path are reported, never deleted (enable --force replaces foreign symlinks only).

Development

just setup           # create .venv from requirements.txt, install the git hook
just check           # every check over the whole tree, untracked files included
just check changed   # the same checks over what differs from HEAD
just test            # this repository's own behaviour
just verify          # check, then test

Requires just and Python 3 with the venv module (apt install python3-venv on Debian/Ubuntu). Checks are defined once in .pre-commit-config.yaml — just check and the installed git hook both read it, so they cannot differ in what they look for, only in how much of the tree they look at. Lints: ruff for Python, pymarkdown for Markdown, scripts/lint-assets.py for asset frontmatter (skills need a description, agents a name and description), plus the upstream hygiene hooks and a liveness check for the Bash guard. Dependency versions are pinned in requirements.txt.

Note that just check can modify files: the whitespace hooks fix what they find and fail the run, so a red check may leave a changed tree to inspect and commit.

The Bash guard

.claude/hooks/bash_guard.py is a PreToolUse hook registered in .claude/settings.json. It gates what a permission prefix cannot express — a flag that arrives late, a command inside a wrapper — deciding on parsed argv per subcommand. Here it carries the standard git rules, docker's publish and host-global sweeps, manage.py's two acts that reach outside this clone, and an rm that is silent only under the rebuildable directories.

It is an instantiation of the template shipped at skills/specify/references/handoff-assets/bash_guard.py; everything above its REGISTRY banner is meant to stay identical to it, and improvements there are copied down by hand. just test runs its full case suite, and every commit runs --liveness — a hook that stops loading fails open silently, so it is gated twice.

About

My claude related stuff

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages