skillctx-ify
skillctx-ify
Migrate a skill to use skillctx for skill variable resolution.
When to Use
- Making a skill portable (removing hardcoded values)
- Setting up a new skill to use skillctx
- User says "skillctx-ify" or "migrate skill to skillctx"
Prerequisites
- Python 3.10+ (for the resolver script)
- Target skill must be installed and discoverable by the agent host
Workflow
Phase 1: Scan and classify
-
Locate the target skill: Find the skill directory by name. Follow symlinks to the actual directory.
-
Check for prior migration: Check for
<!-- skillctx:begin -->marker in the skill's SKILL.md. If found, checkmetadata.skillctx.versionin frontmatter.- If version matches current: report already migrated, stop.
- If version is older: suggest running
skillctx-syncto update.
-
Read the skill files: Read SKILL.md and all referenced files in the skill directory. Also read
references/known-patterns.mdfor classification guidance. -
Identify candidates: Scan the content for hardcoded values that are user-specific or environment-specific — usernames, Slack channel IDs, filesystem paths, org names, etc. For each candidate, determine:
- Is this actually a skill variable or a generic/example string? Use context (tool calls vs prose), repetition, and specificity to decide.
- What category does it belong to in
vars? Use existing config categories as a guide. Defaults:identity,slack,paths,blog. - What should the binding key be named? See Binding Key Naming below.
-
Read existing config: Read
${XDG_CONFIG_HOME:-~/.config}/skillctx/config.jsonif it exists. If not, note it needs to be created. Reuse existing vars when the value already exists in the config — don't create duplicates.
Phase 2: Confirm and rewrite
-
Present proposed changes to user in a table like this:
Hardcoded value File:line Binding key Var dotpath New? CABC123DEFSKILL.md:42 channel_idvars.slack.channel_idyes aliceSKILL.md:10 github_usernamevars.identity.github_usernameno (exists) Wait for user confirmation before proceeding.
-
Rewrite skill files:
a) Replace hardcoded values with
{binding_key}placeholders. The placeholder is a literal string in the skill file — it gets resolved at runtime by the resolver script.Before:
Post to #eng-standup (CABC123DEF)After:Post to {channel_name} ({channel_id})b) Inject the setup block near the top of SKILL.md (after the frontmatter and title), wrapped in comment markers:
<!-- skillctx:begin --> ## Setup Locate this skill's directory (the folder containing this SKILL.md), then run the resolver script from there: python <skill-dir>/scripts/skillctx-resolve.py resolve <skill-name> The resolver outputs each binding as `key: value` (one per line). For list values, it outputs JSON (e.g., `orgs: ["org-a", "org-b"]`). Substitute each `{binding_key}` placeholder below with the resolved value. If any values are missing or the user requests changes, use: python <skill-dir>/scripts/skillctx-resolve.py set <skill-name> <key> <value> <!-- skillctx:end -->c) Update the skill's description to remove migrated values and replace them with placeholders.
d) Add
metadata.skillctx.version: "0.1.0"to the skill's frontmatter.
Phase 3: Write-back
-
Copy resolver script: Copy
scripts/resolve.py(from this skill's directory) into the target skill'sscripts/directory asskillctx-resolve.py. Createscripts/if it doesn't exist. Make it executable. -
Update config file: Write the updated config with new vars and bindings. Create the directory (
mkdir -p) if needed. -
Report: Show what was extracted, bindings created, and files changed.
Binding Key Naming
Binding keys are the names used as {placeholders} in the skill and as keys in skills.<name> in the config. They should be:
- Descriptive of the role, not the value. Use
channel_idnotstandup_channel_id— the skill doesn't care which channel, just that it has one. - Scoped to the skill's perspective. If a skill posts to one channel,
channel_idis fine. If it uses two channels for different purposes, disambiguate:post_channel_id,alert_channel_id. - snake_case, lowercase, no prefixes like
var_orctx_. - Stable. Once a skill is migrated, renaming keys breaks existing configs. Choose names that won't need to change if the underlying value changes.
Examples:
| Hardcoded value | Good binding key | Bad binding key | Why |
|---|---|---|---|
CABC123DEF |
channel_id |
slack_standup_id |
role > source |
alice |
github_username |
user |
too vague |
~/Sync/notes |
notebook_path |
dropbox_path |
tied to provider |
["acme", "widgets-inc"] |
github_orgs |
orgs_list |
redundant suffix |
Error Handling
| Error | Action |
|---|---|
| Skill directory not found | Report error, suggest checking the skill name |
| Skill already migrated (current version) | Report and stop |
| Skill already migrated (older version) | Suggest running skillctx-sync |
| No candidates found | Report that skill has no hardcoded values. Add empty binding entry to config. |
| Config file malformed | Report the JSON parse error, suggest manual fix |