Skip to content

fix(init): install Claude skills as loadable SKILL.md folders - #36

Merged
gold-silver-copper merged 9 commits into
mainfrom
harmony-2708
Oct 24, 2026
Merged

gold-silver-copper merged 9 commits into
mainfrom
harmony-2708

Conversation

@gold-silver-copper

@gold-silver-copper gold-silver-copper commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

meta init claude wrote each skill as a flat .claude/skills/meta-*.md file. Claude Code only loads skills from .claude/skills/<name>/SKILL.md with name/description frontmatter, so none of the six meta skills were ever loaded (in harmony, Claude's skill list has no meta-* entries). The worktree skill also used a command that doesn't exist (meta worktree) and told agents to skip worktrees for quick fixes.

What changes

Install layout (src/init.rs)

  • The skill sources move to .claude/skills/meta-<name>/SKILL.md with frontmatter (descriptions from gitkb/meta's claude-plugin/skills). They are embedded with a small skill! macro and installed at the same path.
  • With --update or --force, the old flat meta-<name>.md each folder replaces is deleted, so re-running in an existing repo leaves one copy. Plain meta init claude skips existing files, so it leaves them alone. Only those six filenames are touched; other files in .claude/skills/ stay.

Before / after in a repo:

.claude/skills/meta-git.md            ->  .claude/skills/meta-git/SKILL.md

meta init claude --help (src/main.rs) ran the full install, including registering the gitkb/claude-plugins marketplace in the user's global Claude settings. It now only prints the init help.

Skill text, checked against meta … --help and the source of meta_cli, meta_git_cli, meta_git_lib, meta_project_cli and loop_lib:

  • meta-worktree: rewritten. meta git worktree … everywhere, remove (not destroy), positional commit-ish (not --from-ref), --no-deps/--recursive/--dry-run/--strict, list [<name>] --metadata-only. "Skip worktrees for quick single-file fixes" is replaced by: every change gets a worktree; read-only work may stay in the primary checkout. Also corrected: --ttl (not --ephemeral) is what prune acts on, remove refuses dirty repos without --force, post-destroy hook runs on remove. --from-pr never applies to the root repo and only warns when nothing matches, so the old GitHub Actions example could pass on unchanged code: it is removed, and the skill gives a root-PR recipe instead (git fetch origin <b>:<b>, then create <name> --repo .:<b> --repo <child> --strict; tried in a scratch repo with and without an existing local branch, and prune --dry-run leaves it alone: a set holding only the root repo is "orphaned" to prune, which force-removes it). diff --stat is a no-op (diff always prints a stat summary of committed changes). Worktree commands must run from the primary checkout; context detection and worktree exec skip repos nested inside another repo of the set; --include/--exclude match the absolute path, which contains the set name.
  • meta-safety: meta --strict git worktree …; --strict covers worktree checks only and doesn't roll back; removed --ordered (no such flag; dependency order comes from the MCP tool meta_execution_order).
  • meta-exec: with meta-rust installed every meta exec -- cargo … goes to it (only build/test work); parallel is the default (--sequential exists); --silent hides errors too; include/exclude are substring matches on paths; meta --exclude X exec -- cargo update (the old example passed --exclude to cargo); meta --primary exec; removed --ordered.
  • meta-git: meta git update only clones missing repos (pull with meta git pull); commit commits staged changes; snapshot restore stashes tracked changes only and asks to confirm without --force; removed meta git setup-ssh (it's a pass-through to a git command that doesn't exist).
  • meta-plugins: no meta project sync (use meta git update); plugin discovery is .meta/plugins/ and ~/.meta/plugins/; Rust plugin only if installed.
  • meta-workspace: meta project list --recursive --json, "every repo at this level" instead of "ALL repos", meta git clone --depth is shallow depth (--meta-depth limits recursion).

Verification

  • cargo fmt --check, cargo clippy --all-targets -D warnings, and the init:: unit tests (10, incl. new test_update_replaces_flat_skill_files and test_default_install_keeps_flat_skill_files) pass locally.
  • Scratch meta repo, this build, PATH without claude:
    • meta init claude --help → prints help, creates nothing.
    • meta init claude → six .claude/skills/meta-*/SKILL.md + rules + settings.
    • meta init claude --update over the six flat files plus a custom.md → only folders remain, custom.md kept.
  • Fresh claude -p (no tools) asked to list skills starting with meta-: lists all six in both scratch repos; in a repo with the old flat files: NONE.

Notes

  • Not changed here (CLI behavior, other repos): meta git update --help says it pulls existing repos but only clones missing ones; --from-pr ignores the root repo; context detection skips nested set members; diff --stat is accepted but unused; prune treats a root-only set as orphaned. The skills describe current behavior. The two installed rule files (.claude/rules/meta-*.md) also have small inaccuracies (meta git snapshot restore without --force prompts; meta git commit commits staged changes, not "all dirty repos"; --include is a substring match); left for a follow-up so the rules and their gitkb/meta copies change together.
  • Companion PRs: fix(skills): copy Claude skills from meta_cli and test the new layout meta#102 (single source + tests/init.bats; same branch name, so its CI builds this branch) and gitkb/harmony#154 (worktree policy in AGENTS.md). Harmony needs a meta release with this change, then meta init claude --update.

Task: tasks/harmony-2708

@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 2d929bd3-272a-4a05-bd9f-bf3c59e9a465
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

Claude Code only loads skills from .claude/skills/<name>/SKILL.md with
name/description frontmatter, so the flat meta-*.md files that
`meta init claude` wrote were never loaded. Install each skill as its
own folder and delete the old flat file it replaces.

Fix the skill text against the CLI: `meta git worktree` (not
`meta worktree`), `remove`, no `--ordered`, `meta project sync` or
`meta git setup-ssh`, `meta git update` only clones, parallel is the
default. The worktree skill now says every change gets a worktree.

`meta init claude --help` ran the install (and registered the plugin
marketplace in the user's Claude settings); it now only prints help.

Implements [[tasks/harmony-2708]]
Windows checks the skill files out with CRLF line endings.

Implements [[tasks/harmony-2708]]
…ew findings

Plain `meta init claude` skips existing files, so it now leaves old flat
skill files alone too. Skill text: the root is only kept for --tag,
worktree create needs --repo, meta-rust has no ordering, --primary still
reads config from the cwd.

Implements [[tasks/harmony-2708]]
--from-pr never applies to the root repo (add a root-PR recipe), drop the
Actions example that relied on it, diff --stat is a no-op, run worktree
commands from the primary checkout, context detection skips nested repos,
include/exclude match the absolute path, snapshot restore asks without
--force, --silent hides errors, clone --depth is shallow depth.

Implements [[tasks/harmony-2708]]
…ew findings

Close the worktree exec code fence. Snapshot restore resets branches,
meta exec still offers commands to plugins, quote commands with shell
syntax.

Implements [[tasks/harmony-2708]]
prune treats a set holding only the root repo as orphaned and
force-removes it. Also: remove skips nested repos' dirty check, cargo
examples fail with meta-rust.

Implements [[tasks/harmony-2708]]
@gold-silver-copper
gold-silver-copper merged commit 737eee9 into main Oct 24, 2026
7 checks passed
gold-silver-copper added a commit that referenced this pull request Oct 24, 2026
- A real .claude/skills/<name>/ folder holding only SKILL.md is meta's
  only when that SKILL.md is the shipped text (no release shipped the
  #36 layout, and its text is today's), so another tool's same-named
  skill is kept even with --force.
- Rule files are not written through a symlinked .claude/, .claude/rules/
  or rule file; they are reported as skipped.

Implements [[tasks/harmony-2714]]
gold-silver-copper added a commit that referenced this pull request Oct 24, 2026
… folders (#38)

feat(init): install skills into .meta/skills and link them into agent…

… folders

meta init claude now writes each skill to .meta/skills/<name>/SKILL.md
and links it into .claude/skills/ and .agents/skills/ (Codex and other
agents), as atc and git-kb do with .atc/skills/ and .kb/skills/. Other
agent folders from atc's registry (.cursor, .opencode, .pi, .omp, .grok)
get links when the agent's folder exists.

--update turns both older layouts into links: flat .claude/skills/*.md
files and real .claude/skills/<name>/ folders holding only SKILL.md.
Anything else at a link path (another tool's link, a folder with more
files, a file) is reported and left alone; no symlink is followed or
removed. Where a symlink can't be made (Windows without Developer Mode),
the skill folder is copied with a .meta-skill-copy marker, and a later
--update replaces it with a link.

A repo whose config is the legacy .meta file can't have the .meta/
folder: init refuses before writing anything and suggests
git mv .meta .meta.json. The meta-repo check now uses
find_meta_config_in, so a .meta/ folder is not taken for config.

install_skills takes the tool name, skill bundle and agent folder list
as inputs so it can move into a shared crate later.

Implements [[tasks/harmony-2714]]

fix(init): never write through symlinks; own legacy folders only in .…

…claude

Review fixes:
- A symlink anywhere in .meta/skills/<name>/SKILL.md stops the install,
  and an agent skills folder reached through a symlink is skipped, so
  no other tool's files are written or removed through a link.
- A real folder holding only SKILL.md counts as meta's only in
  .claude/skills/, where older releases wrote it.
- A plain file holding exactly meta's link target (git's checkout of a
  link with core.symlinks=false) is replaced, so --update repairs such
  Windows clones.
- The copy fallback copies .meta/skills/<name>/SKILL.md, not the
  embedded text, so a kept or newer committed skill is what agents see.

Implements [[tasks/harmony-2714]]

fix(init): own old skill folders only by their shipped text; guard rules

- A real .claude/skills/<name>/ folder holding only SKILL.md is meta's
  only when that SKILL.md is the shipped text (no release shipped the
  #36 layout, and its text is today's), so another tool's same-named
  skill is kept even with --force.
- Rule files are not written through a symlinked .claude/, .claude/rules/
  or rule file; they are reported as skipped.

Implements [[tasks/harmony-2714]]

fix(init): never write settings.json through a symlink

Implements [[tasks/harmony-2714]]

fix(init): remove old flat skill files only when meta shipped them

--update and --force removed any regular .claude/skills/meta-<name>.md.
Now only files whose first line is the heading of a skill meta shipped
(every release's flat files start with one of seven known headings) are
removed; anything else is reported and kept. Also create .claude/rules/
after the skills step, so a refused install leaves no half-made .claude/.

Implements [[tasks/harmony-2714]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant