promote-config
Skill2 starsChanged 34 days agoMITView on GitHub
Relocate a named craft config between scopes — promote local-scope to user-scope by default, or demote user-scope to local-scope with --demote. Triggers — "craft:promote-config", "promote a named config", "promote a craft config to user scope", "move a craft config to user scope", "demote a craft config to local scope".
In this repository20 other files it gives its agents.
- architectureSkill
- decisionsSkill
- designSkill
- documentationSkill
- impact-triageSkill
- implementationSkill
- initSkill
- integrateSkill
- lessonsSkill
- metricsSkill
- planningSkill
- proposeSkill
- pruneSkill
- refactoringSkill
- requirementsSkill
- reviewSkill
- runSkill
- tuneSkill
- validationSkill
- workspaceSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 30
If either test fails, surface a diagnostic and stop — the plugin installation is incomplete.
- Very specific: line 46
Every decision — direction, source-existence, destination-exists refuse-vs-force, and $HOME-containment — is made by promote-plan.js, never …
- Very specific: line 71
Ensure the destination directory exists, then copy the source bytes into a mktemp file created INSIDE that same directory — trailing-X …
- Distinctive: line 106
Remove the source so the config lives at exactly one scope:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
craft:promote-config — relocate a named config between scopes
Standalone, session-owned skill. You (the session) ask the plan computer where the config should go, stage the source bytes at that destination, land through the existing lint-then-move bin, and finalize by removing the source. No worker agent is spawned.
Input: $ARGUMENTS — <name> (required), plus optional --demote and --force.
This is a MOVE by default: the source is removed once the destination copy lands clean, so the config lives at exactly one scope afterward, never both.
Preamble — plugin-root probe (read-only)
Confirm both entrypoints this skill composes exist:
test -f "${CRAFT_ROOT:-${CLAUDE_PLUGIN_ROOT}}/engine/bin/promote-plan.js"
test -f "${CRAFT_ROOT:-${CLAUDE_PLUGIN_ROOT}}/engine/bin/init-land.js"If either test fails, surface a diagnostic and stop — the plugin installation is incomplete.
Parse $ARGUMENTS:
<name>— required. Absent ⇒ STOP: "a config name is required".--demote— direction flag. Absent ⇒ promote (local→user, the default). Present ⇒ demote (user→local).--force— overwrite flag, forwarded verbatim when the caller supplied it.
Procedure
Step 1 — Plan
Every decision — direction, source-existence, destination-exists refuse-vs-force,
and $HOME-containment — is made by promote-plan.js, never re-derived here:
plan_out="$(node "${CRAFT_ROOT:-${CLAUDE_PLUGIN_ROOT}}/engine/bin/promote-plan.js" "$name" [--demote] [--force])"(append --demote and/or --force only when the caller passed them).
Non-zero exit ⇒ STOP — surface the stderr diagnostic verbatim (no source config to
relocate, a destination that already exists without --force, a $HOME
containment escape, or an invalid name). Nothing is touched.
On exit 0, parse the three key=value lines from $plan_out:
source=<absolute source path>
dest=<absolute destination path>
scope=<user|local — the destination scope>Bind source, dest, scope from these lines.
Step 2 — Stage
Ensure the destination directory exists, then copy the source bytes into a
mktemp file created INSIDE that same directory — trailing-X template built
only from the already-validated $name:
dest_dir="$(dirname "$dest")"
mkdir -p "$dest_dir"
manifest_tmp="$(mktemp "$dest_dir/.craft-${name}.tmp.XXXXXX")"
cp "$source" "$manifest_tmp"Reuse $manifest_tmp verbatim from here on — never re-splice $name into a fresh
path. mktemp's unpredictable suffix plus its O_EXCL creation is what closes the
TOCTOU window between lint and move.
Step 3 — Land
Delegate the atomic lint-then-move to the existing land bin — the same one
craft:init uses:
node "${CRAFT_ROOT:-${CLAUDE_PLUGIN_ROOT}}/engine/bin/init-land.js" "$manifest_tmp" "$name" --scope "$scope"init-land.js lints $manifest_tmp at the destination root before it moves
anything, so a config referencing a repo-relative path (e.g. context: docs/x.md)
is REFUSED when promoted to ~/.claude — a user-scope config must be
self-contained.
Non-zero exit ⇒ STOP — surface the stderr diagnostic; remove $manifest_tmp; the
source is untouched (the relocation never reaches Step 4).
Step 4 — Finalize (move)
On exit 0 from Step 3, the destination copy already lints clean and is in place. Remove the source so the config lives at exactly one scope:
rm "$source"Report the relocation with the greppable token (defined ONLY here — it does not
join the skills/run/SKILL.md token family):
PROMOTE-CONFIG(<name>): local→useror, for a --demote run:
PROMOTE-CONFIG(<name>): user→localError semantics
| Condition | Behaviour |
Missing <name> | STOP: "a config name is required" |
| No source config at the from-scope | STOP; promote-plan.js names the missing scope and name on stderr; nothing touched |
Destination already exists, no --force | STOP; promote-plan.js refuses with a destination-exists diagnostic naming the --force escape hatch |
Destination already exists, --force passed | Land proceeds; init-land.js's atomic rename overwrites the prior destination file |
Source or destination user-scope path escapes $HOME containment | STOP; promote-plan.js reports a containment failure; nothing touched |
| Ref-bearing / non-portable source config | init-land.js REFUSES at the destination lint before any move; $manifest_tmp is removed; source is untouched |
Plugin root missing (promote-plan.js or init-land.js absent) | STOP; surface which entrypoint is missing; do not invoke either bin |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

