
Lovstudio Skill Creator
- 12 installs
- Updated August 4, 2026
- lovstudio/dev-skills
Helps with ai & agent building tasks.
About
lovstudio-skill-creator is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- lovstudio-skill-creator
- AI & Agent Building
- AI-coding skill
Lovstudio Skill Creator by the numbers
- 12 all-time installs (skills.sh)
- +2 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #11,592 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/lovstudio/dev-skills --skill lovstudio-skill-creatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 12 |
|---|---|
| Last updated | August 4, 2026 |
| Repository | lovstudio/dev-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
lovstudio-skill-creator
Scaffold a new lovstudio skill either as an independent GitHub repo under lovstudio/{name}-skill or as a bundled entry inside lovstudio/dev-skills. The default is still the independent repo model; use dev-skills for Lovstudio meta/dev tooling that should ship as part of the developer skill bundle.
Architecture
<configured workspace>/
├── lovstudio-general-skills/ ← general skills index (lovstudio/general-skills repo)
│ ├── skills.yaml ← machine-readable manifest (paid flag lives here)
│ └── README.md ← human-readable catalog
├── lovstudio-dev-skills/ ← aggregate repo for meta/dev skills
│ ├── skills.yaml
│ ├── .claude-plugin/marketplace.json
│ └── skills/{name}/
│ ├── SKILL.md
│ ├── README.md
│ ├── scripts/
│ └── references/
├── skills/ ← independent per-skill source repos
│ └── {name}-skill/
│ ├── SKILL.md
│ ├── README.md
│ ├── CHANGELOG.md ← managed by skill-optimizer
│ ├── scripts/ ← standalone Python CLI scripts
│ └── references/ ← optional progressive-disclosure docs
└── ...
<agent skills dir>/lovstudio-{name} ← install or symlink to the source checkoutKey facts:
- Default GitHub repo name:
lovstudio/{name}-skill(with-skillsuffix) - Default local source root:
LOVSTUDIO_SKILL_CREATOR_REPOS_ROOT, profile
lovstudio.skill_repos_root, or the current directory.
- General skills checkout path: configured by the maintainer's local checkout.
- Dev-skills source root:
LOVSTUDIO_SKILL_CREATOR_DEV_SKILLS_ROOT, profile
lovstudio.dev_skills_root, or a detected dev-skills checkout.
- Dev-skills catalog entry uses
repo: lovstudio/dev-skillsandskill_path: skills/{name} - Agent runtimes read an installed directory named
lovstudio-{name}/. - Frontmatter
name:lovstudio-{name}(Agent Skills-compatible). Legacy
lovstudio:{name} names are kept only for older skills and should not be copied into new templates.
- Frontmatter
depends_on: optional list of required skill names from those
skills' own SKILL.md frontmatter. Use it when one skill must reuse another instead of duplicating implementation. In skills.yaml, use catalog names such as find-logo.
paid: true/falselives only inlovstudio-general-skills/skills.yaml, never in SKILL.md- User-specific paths, brand profiles, design guides, and output directories
must be initialized through explicit CLI flags, environment variables, or ~/.lovstudio/skills/profile.json. Do not hard-code personal workspace paths in reusable workflows.
Skill Creation Process
Step 1: Understand the Skill
Ask the user what the skill should do. Use AskUserQuestion — one question at a time, in the order below. Do not skip or reorder. The distribution model decides the architecture, so it has to come before any implementation question.
Required question order:
Q1. Commercial / protection model — ALWAYS ask first
Even for "obvious" simple skills, ask. Users may have future monetization plans you can't infer from the initial request.
这个 skill 的分发定位?
>
1. Free (public) — 任何人 git clone 就能用。适合引流、通用工具、开源贡献。
2. Paid, 普通 IP — 核心逻辑是流程/模板/prompt 编排,用户 grep 出来不心疼。用加密分发 + license 鉴权。
3. Paid, 敏感 IP — 含算法参数/业务规则/调好的 prompt/API 密钥,用户反编译会心疼。用 cloud-split:核心逻辑放云端,本地只有瘦客户端。
>
提示:不确定 → 选 2。未来升级到 3 比降级容易。
这个答案决定后续流程分支:
- 选 1 → 走标准公开 repo 流程
- 选 2 → 走 encrypted skill 流程(README 里坦诚说明 "加密 = 鉴权闸门,不保证反提取")
- 选 3 → 停下来读 `references/cloud-split.md`,然后走 cloud-split 流程
Q1.5. Repository target — ask after Q1
This is separate from the commercial/protection model. It answers "where does the source live and how is it distributed?"
这个 skill 放在哪里分发?
>
1. Independent repo (default) — <configured repos root>/{name}-skill/→lovstudio/{name}-skill→ generallovstudio/general-skillsindex.
2. dev-skills bundle — <configured dev-skills root>/{name}/→lovstudio/dev-skills→ bundled install vianpx skills add lovstudio/dev-skills
or Claude Code plugin marketplace.
>
判断:面向技能作者/开发流程/内部工程规范的免费工具 → 选 2。通用用户工具、
付费 skill、cloud-split thin client → 选 1。
Consistency rules:
- If Q1 is Paid or Cloud-split, do not use dev-skills. Use an
independent repo so licensing, encryption, and cloud-split thin-client packaging stay isolated.
- Use dev-skills for free Meta / Dev Tools skills such as
skill-creator,
skill-optimizer, project-port, or project refactor/init helpers.
Q2. Problem & shape
- 解决什么问题?输入 → 输出是什么?
- 2-3 个具体使用示例
- 触发短语(中文 + English)
Q2.5. Decompose into protected vs public layers ⟵ MANDATORY, do not skip
Before any file is created, decompose the skill into two layers and show the user the decomposition for confirmation. This step catches two common failures: (a) cloud-split chosen with empty protected layer (over-engineering), (b) encrypted chosen but real secrets exist (under-protection).
Present like this:
我先拆解一下这个 skill 的结构:
>
公开层(瘦客户端 SKILL.md 会暴露这些):
- [具体列出:对话流、输入解析、输出渲染、错误处理]
>
保护层(需要藏起来的):
- [具体列出:算法/阈值/规则/prompt 工程/密钥/数据]
- 或明确写 "无 — 这个 skill 没有需要保护的核心逻辑"
>
按这个拆解,你选的 [Q1 答案] [合理 / 不合理,建议改成 X]。确认继续?
Consistency check — if decomposition contradicts Q1, challenge it:
| Q1 选择 | 保护层内容 | 判断 |
|---|---|---|
| Free | 任何 | ✓ 无需保护问题 |
| Encrypted | 非空 | ⚠️ 警告:encrypted 不防 L2 grep,真敏感的请升级 cloud-split |
| Encrypted | 空 | ✓ 合理(典型场景:付费模板/工作流) |
| Cloud-split | 非空且有实质 | ✓ 合理 |
| Cloud-split | 空或琐碎 | ✗ 停下,反问用户是否过度设计,建议降级到 encrypted 或 free |
对琐碎 demo(如"两数之和")尤其要质询 —— cloud-split 的服务端成本 + 部署复杂度 对"其实没东西可保护"的 skill 是净负收益。除非用户明确说"做模板/教学样本", 否则建议降级。
Q2.7. Naming — de-business the name ⟵ MANDATORY for paid skills
Bad naming leaks the logic through the API surface. Even with cloud-split, if the skill name + op name + input schema together describe the business logic, grep on jsonl reveals intent.
Rule: name the capability domain, not the specific logic.
| ✗ 逻辑自述(坏) | ✓ 能力域(好) |
|---|---|
sum-gt-ten | threshold-check |
extract-chinese-poem-style | text-style-analyzer |
detect-viral-headline | text-scorer |
calculate-compatibility | profile-matcher |
Propose 2-3 de-businessed names and let the user pick via AskUserQuestion. For the op names inside the handler, same rule — op: "score" beats op: "check_if_sum_exceeds_10".
Skip this step only if Q1 == Free and the user doesn't care about future paid upgrades.
Q3. Implementation type
- 纯指令 SKILL.md,还是需要 Python CLI 脚本?
- (如果 Q1 选了 3:这一问跳过。cloud-split 的"实现"就是云端 handler,不是本地脚本。)
Q4. User initialization layer — mandatory for reusable skills
Ask whether the skill needs user-specific workspace, output, identity, brand, or design-guide settings. If yes, design the initialization layer before writing scripts:
这个 skill 是否需要读取用户自己的工作区、品牌资料、设计规范或输出目录?
>
1. No user config — 只处理当前输入文件/当前目录。
2. User profile — 需要用户初始化自己的 workspace/brand/output。
3. LovStudio internal only — 明确只服务 Mark/LovStudio 私有工作区。
Rules:
- Option 1: no absolute user paths in SKILL.md or scripts.
- Option 2: follow
references/user-config.md; use CLI flags > env vars >
shared profile > safe defaults > ask once.
- Option 3: mark
compatibilityand README as author-only, and keep all
LovStudio paths in one configuration section instead of scattering them.
Protection model — what each tier actually buys you
Be honest about what each tier protects against. Do not market encrypted skills as "IP protection" — it's a gate, not a vault.
| Tier | Protects against | Does NOT protect against |
|---|---|---|
| Free | 无 | 无 |
| Paid / encrypted | 路人 git clone 就能用(L1) | 技术用户从本地对话日志取回明文(L2) |
| Paid / cloud-split | L1 + L2 + 反汇编客户端 | 反向推理 I/O 做劣质 clone |
核心逻辑真正不下发到用户机器的 只有 cloud-split。其他 tier 都不要对用户承诺"加密保护"。
Step 2: Plan Contents
Analyze the examples and identify:
1. Scripts — deterministic operations → scripts/ 2. References — domain knowledge Claude needs while working → references/ 3. Assets — files used in output (templates, fonts, etc.) → assets/
Rules:
- Python scripts must be standalone single-file CLIs with
argparse - No package structure, no
setup.py, no__init__.py - CJK text handling is a core concern if the skill deals with documents
- Any user-specific path, brand asset, design guide, or output root needs a
configuration plan. Read references/user-config.md and include references/user-config.md in the scaffold for public/reusable skills.
Step 3: Initialize
Run the init script. Independent repo is the default:
python3 "$SKILL_DIR/scripts/init_skill.py" <name>For a dev-skills bundled skill:
python3 "$SKILL_DIR/scripts/init_skill.py" <name> --target dev-skillsIndependent repo creates <configured repos root>/{name}-skill/ with:
{name}-skill/
├── SKILL.md ← frontmatter + TODO workflow
├── README.md ← human-readable docs with version badge
└── scripts/ ← empty, ready for implementationDev-skills creates <configured dev-skills root>/{name}/ with the same skill-internal structure.
Pass --paid if this is a paid skill (adjusts README + metadata hints). Do not combine --paid with --target dev-skills; use an independent repo for paid distribution.
If Q1 chose cloud-split (tier 3): after running init_skill.py, don't put your real logic in scripts/. Instead: 1. Read references/cloud-split.md end-to-end before writing any code (this is not optional — the rules for non-leaky payloads are there, not here) 2. Start from `threshold-check` as the reference pattern, NOT paid-add. paid-add is an architecture demo with an intentionally leaky payload (for teaching). Copying its return shape into a real skill defeats the whole point of cloud-split. 3. Write the handler in the configured web repo's supabase/functions/skill_call/handlers/<name>.ts — return a minimal symbolic payload ({verdict: "A" | "B"} style), not descriptive strings or narrative display fields 4. Write the thin SKILL.md per the threshold-check template — rendering via a symbol → text table, never via a computed algorithm 5. MANDATORY pre-flight audit — before registering the handler in the dispatcher, before deploying, before telling the user "done": run the checklist in references/cloud-split.md → "MANDATORY pre-flight audit" section. Report each item's result to the user. If any item fails, rewrite before moving on. 6. Skip the normal Step 4 "write scripts" — there usually aren't any for cloud-split skills (unless you need client-side rendering of server output)
Why the audit is mandatory: a real incident during skill-creator development produced a cloud-split skill whose handler returned {score, verdict: "below", display: "2+6=8 (below 10)"}. Architecture was correct; protection was zero. The audit catches this class of bug before it ships.
Step 4: Implement
1. Write scripts in scripts/ — test by running directly 2. Write SKILL.md — instructions for AI assistants:
- Frontmatter
descriptionis the trigger mechanism — cover what + when +
concrete trigger phrases (中文 + English)
- Body contains workflow steps, CLI reference, field mappings
- Use
AskUserQuestionfor interactive prompts before running scripts - Add a user configuration section when the workflow touches paths,
personal data, brand assets, or workspace conventions
- Never assume personal workspace paths or a fixed agent runtime path in
reusable workflow steps
- Keep SKILL.md under 500 lines; split to
references/if longer
3. Write README.md — docs for humans on GitHub:
- Version badge (source of truth for version)
- Install command using the user's chosen agent skills directory
- Dependencies
- Usage examples, options table
- ASCII diagrams if useful
See references/templates.md for SKILL.md / README.md templates. See references/user-config.md for the portable profile/env contract. See references/skill-standard.md for the current LovStudio skill standard.
Step 5: Publish
Follow the branch matching Q1.5.
Independent Repo Target
5a. Initialize & push the skill's own repo
cd <configured-repos-root>/<name>-skill
git init
git add -A
git commit -m "feat: initial release of <name> skill"
# Free skill (public):
gh repo create lovstudio/<name>-skill --public --source=. --push
# Paid skill (private):
gh repo create lovstudio/<name>-skill --private --source=. --push5b. Register in the general-skills index
Edit the configured lovstudio-general-skills/skills.yaml — append under the right category (category order in the yaml determines display order on the website):
- name: <name>
repo: lovstudio/<name>-skill
paid: false # or true for paid skills
category: "<Category>" # must match an existing category heading
version: "0.1.0"
description: "<One-line description matching SKILL.md tagline>"Also add a row to the configured lovstudio-general-skills/README.md under the matching category section. Then PR against lovstudio/general-skills:
cd <general-skills-checkout>
git checkout -b add/<name>
git add skills.yaml README.md
git commit -m "add: <name> skill"
git push -u origin HEAD
gh pr create --fill5c. Install for local availability
Make the skill immediately usable by installing or symlinking the source checkout into the user's agent skills directory as lovstudio-<name>.
5d. Trigger lovstudio.ai cache refresh (optional)
After the skill is indexed in skills.yaml, the lovstudio.ai /agent page caches the index for 1 hour (Next.js ISR). Trigger on-demand revalidation so the new skill appears immediately:
if [ -n "$LOVSTUDIO_REVALIDATE_SECRET" ]; then
curl -sfX POST https://lovstudio.ai/api/revalidate \
-H "x-revalidate-secret: $LOVSTUDIO_REVALIDATE_SECRET" \
-H "content-type: application/json" \
-d '{"tags":["skills-index"]}' \
&& echo "✓ cache refreshed" \
|| echo "⚠ revalidate failed (will appear within 1h)"
fiKnown tags (see lovstudio/web:src/data/skills.ts):
skills-index— the yaml index (invalidates all list pages)skill:<id>— detail for a single skillskill-cases:<id>— cases.json for a skill
Dev-Skills Target
Use this for free Meta / Dev Tools skills that belong in the lovstudio/dev-skills bundle.
5a. Commit inside dev-skills
cd <dev-skills-checkout>
git checkout -b add/<name>
git add skills/<name>5b. Register in dev-skills metadata
Edit the configured lovstudio-dev-skills/skills.yaml:
- name: <name>
repo: lovstudio/dev-skills
skill_path: skills/<name>
name_zh: <中文名>
paid: false
category: "Dev Tools" # or "Meta"
version: "0.1.0"
description: "<Agent-facing trigger description>"
tagline_en: "<Human-facing English tagline>"
tagline_zh: "<Human-facing Chinese tagline>"Also update .claude-plugin/marketplace.json so the correct plugin includes "./skills/<name>":
- Meta skills →
plugins[].name == "meta" - Dev tooling →
plugins[].name == "dev-tools"
Then render the READMEs:
python3 scripts/render-readme.py5c. Install for local availability
Install or symlink the bundled skill directory into the user's agent skills directory as lovstudio-<name>.
5d. Commit and push
git add skills.yaml README.md README.en.md .claude-plugin/marketplace.json
git commit -m "add: <name> skill"
git push -u origin HEAD
gh pr create --fillDo not register dev-skills-only skills in the general-skills index unless the user explicitly asks for the main Lovstudio skills index to list the bundle entry.
Step 6: Test & Iterate
1. In a new conversation, invoke lovstudio-<name> or a documented trigger phrase — confirm it triggers 2. Notice struggles → edit SKILL.md / scripts in the source repo 3. Commit & push in the chosen target repo (independent repo or dev-skills)
Design Patterns
Interactive Pre-Execution (MANDATORY for generation/conversion skills)
**IMPORTANT: Use `AskUserQuestion` to collect options BEFORE running.**
Use `AskUserQuestion` with the following template:
[options list]
### Mapping User Choices to CLI Args
[table mapping choices to --flags]Progressive Disclosure
Keep SKILL.md lean. Split to references when:
- Multiple themes/variants →
references/themes.md - Complex API docs →
references/api.md - Large examples →
references/examples.md
Reference from SKILL.md: "For theme details, see references/themes.md"
Context-Aware Pre-Fill
For skills that fill or generate content: 1. Check user memory and conversation context first 2. Pre-fill what you can 3. Only ask for fields you truly don't know
What NOT to Include
INSTALLATION_GUIDE.md— clutter; install instructions go in README.md- Test files — scripts are tested by running, not with test frameworks
__pycache__/,*.pyc,.DS_Store— add to.gitignorepaidfield in frontmatter — it lives only inlovstudio-general-skills/skills.yaml- Hard-coded personal workspace paths or private LovStudio brand files in
reusable workflows
Migration Notes
For historical repo-layout migrations, read references/migration.md.
Changelog
All notable changes to this skill are documented here. Format: Keep a Changelog · Versioning: SemVer
[2.7.0] - 2026-05-07
Added
- make scaffold roots profile driven
- resolve source roots from LOVSTUDIO_SKILL_CREATOR_* env vars or shared profile before safe fallbacks
- remove personal workspace and fixed agent runtime paths from generated templates
[2.6.1] - 2026-05-07
Fixed
- publish LovStudio skill standard reference
- add references/skill-standard.md as the canonical standardization document
[2.6.0] - 2026-05-07
Added
- standardize config env vars on LOVSTUDIO_SKILLS namespace
- replace AGENT_SKILL_* in generated templates
- keep defaults under ~/.lovstudio/skills
[2.5.0] - 2026-05-07
Added
- move default skill profile under ~/.lovstudio
- keep AGENT_SKILL_PROFILE as the portable override
- default generated brand/design config paths to ~/.lovstudio/skills
[2.4.0] - 2026-05-07
Added
- switch public config contract to AGENT_SKILL profile
- replace LovStudio-prefixed profile paths in new-skill templates
- keep LovStudio paths as private authoring examples, not reusable runtime API
[2.3.0] - 2026-05-06
Added
- add portable user configuration scaffolding
- switch new templates to Agent Skills-compatible lovstudio-<name> frontmatter
- generate references/user-config.md for new skills
- move historical migration notes into references/migration.md for progressive disclosure
[2.2.0] - 2026-05-06
Added
- Document optional SKILL.md frontmatter
depends_onfor required skill-level dependencies. - Scaffold templates now include commented
depends_onguidance so new skills can declare reuse relationships explicitly.
[2.1.0] - 2026-05-06
Added
- Add
dev-skillsas a first-class repository target for free Meta / Dev Tools skills. init_skill.pynow supports--target dev-skillsand--dev-skills.- Document
repo: lovstudio/dev-skills+skill_path: skills/<name>registration and marketplace plugin updates.
[2.0.0] - 2026-04-18
Changed
- Rewrite for per-skill-repo architecture. Each skill is now an independent repo at
lovstudio/{name}-skillinstead of a subdirectory of a monorepo. - Default scaffold path:
~/lovstudio/coding/skills/{name}-skill/(wasskills/lovstudio-{name}/). - Install hint:
git cloneeach skill repo (replacesnpx skills add lovstudio/skills). init_skill.py: accepts--paid, auto-creates.gitignore, and printsgh repo create+ symlink + index-registration next-steps instead of monorepo-dev-flow hints.
Added
- Step 5b: PR to
lovstudio/skillscentral index (skills.yaml+README.md). - Step 5d: lovstudio.ai ISR cache revalidation via
skills-indextag. - Migration note for legacy skills still in the monorepo structure.
Removed
- Step 0 (repo choice):
lovstudio/pro-skillswas archived 2026-04-16.paidnow lives only inlovstudio-general-skills/skills.yamlas catalog metadata, not as a skill property.
[1.2.0] - 2026-04-15
Added
- Add Step 0: repo selection (lovstudio/skills vs lovstudio/pro-skills)
- Step 5c: create PR to chosen target repo instead of push to main
[1.1.1] - 2026-04-14
Fixed
- Add publish workflow: symlink chain + git push to Step 5
[1.1.0] - 2026-04-14
Added
- Fix init_skill.py repo detection — prefer lovstudio-skills over cwd
- README template now includes version badge
- Remove CHANGELOG from 'What NOT to Include' (managed by skill-optimizer)
lovstudio-skill-creator
Scaffold new skills for the lovstudio ecosystem. Skills can be created as independent GitHub repos at lovstudio/{name}-skill or as bundled entries inside `lovstudio/dev-skills`. New scaffolds use Agent Skills-compatible lovstudio-<name> frontmatter and a portable user configuration layer for workspace, output, and brand settings.
Part of lovstudio general skills — by lovstudio.ai
Install
git clone https://github.com/lovstudio/skill-creator-skill "${LOVSTUDIO_SKILLS_INSTALL_DIR:?Set LOVSTUDIO_SKILLS_INSTALL_DIR}/lovstudio-skill-creator"What It Does
┌────────────────────────────────────────────────────────────┐
│ You: "封装成 wcx skill" │
└────────────────────────────┬───────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ init_skill.py wcx │
│ │
│ <configured repos root>/wcx-skill/ │
│ ├── SKILL.md ← AI reads this │
│ ├── README.md ← Humans read this on GitHub │
│ ├── .gitignore │
│ ├── references/user-config.md │
│ └── scripts/ ← Python CLI scripts │
└────────────────────────────┬───────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ Implement → gh repo create lovstudio/wcx-skill --push │
│ → PR into lovstudio-general-skills/skills.yaml + lovstudio-general-skills/README.md │
│ → install or symlink as lovstudio-wcx │
└────────────────────────────────────────────────────────────┘
Dev-skills bundle target:
┌────────────────────────────────────────────────────────────┐
│ init_skill.py tanstack-query --target dev-skills │
│ │
│ <configured dev-skills root>/tanstack-query/ │
│ ├── SKILL.md │
│ ├── README.md │
│ ├── .gitignore │
│ └── scripts/ │
│ │
│ Register in dev-skills/skills.yaml with: │
│ repo: lovstudio/dev-skills │
│ skill_path: skills/tanstack-query │
└────────────────────────────────────────────────────────────┘Quick Start
# Scaffold
python3 "$SKILL_DIR/scripts/init_skill.py" wcx
# → <configured repos root>/wcx-skill/
# ├── SKILL.md (TODO placeholders)
# ├── README.md (version badge + install stub)
# ├── .gitignore
# ├── references/user-config.md
# └── scripts/# Scaffold a free Meta / Dev Tools skill into lovstudio/dev-skills
python3 "$SKILL_DIR/scripts/init_skill.py" tanstack-query --target dev-skills
# → <configured dev-skills root>/tanstack-query/Then:
1. Implement scripts/ and fill the TODOs in SKILL.md / README.md 2. For independent repos: cd <configured repos root>/wcx-skill && git init && git add -A && git commit -m "feat: initial release" 3. For independent repos: gh repo create lovstudio/wcx-skill --public --source=. --push 4. For dev-skills: edit the configured lovstudio-dev-skills/skills.yaml, update .claude-plugin/marketplace.json, then run python3 scripts/render-readme.py 5. Install or symlink into your agent skills directory as lovstudio-<name>
Architecture
The lovstudio skill ecosystem:
| Layer | Location | Purpose |
|---|---|---|
| General skills index | lovstudio/general-skills repo & configured checkout | skills.yaml + human README; consumed by agentskills.io & lovstudio.ai/agent |
| Per-skill repo | lovstudio/{name}-skill & configured repos root | All skill code + SKILL.md + README.md + CHANGELOG.md |
| Dev skills bundle | lovstudio/dev-skills & configured dev-skills root | Free Meta / Dev Tools skills installed together |
| Local agent runtime | agent-specific skills directory | Installed or symlinked lovstudio-{name} directory |
paid: true/false lives only in lovstudio-general-skills/skills.yaml — never in SKILL.md.
User-specific paths, brand profiles, design guides, and output directories must come from explicit CLI flags, environment variables, or ${LOVSTUDIO_SKILLS_PROFILE:-$HOME/.lovstudio/skills/profile.json}. Reusable skills must not hard-code personal workspace paths or private LovStudio workspace assumptions.
Differences from Official skill-creator
| Official | Lovstudio | |
|---|---|---|
| README.md | Explicitly forbidden | Required — repos are on GitHub |
| Frontmatter | name + description | + license, compatibility, optional depends_on, metadata.version, tags |
| Naming | Name matches installed skill dir | lovstudio-<name> frontmatter / {name}-skill source repo / lovstudio-<name> installed dir |
| Scripts | Any format | Standalone Python CLI with argparse |
| Distribution | .skill package | Independent repo or lovstudio/dev-skills bundle |
| Interactive | Optional | AskUserQuestion mandatory for generation/conversion skills |
| General catalog | — | skills.yaml + README.md in lovstudio/general-skills |
| User config | Optional | Required when paths, brand, profile, or workspace conventions are user-specific |
License
MIT
Cloud-Split Skill Pattern
Protection pattern for paid skills whose core IP must not touch the user's disk. Core logic lives on Lovstudio's servers; the distributed SKILL.md is a thin client that only orchestrates calls.
When to use
| Signal | Use cloud-split? |
|---|---|
| Pure workflow/template, no secrets | No → use encrypted |
| Trivial algorithm, low margin | No → encrypted + accept L2 leakage |
| Flagship skill, high margin | Yes |
| Contains API keys / credentials | Yes (must) |
| Carefully tuned prompt engineering | Yes |
| Proprietary data / formulas | Yes |
Rule of thumb: if a user grep'ing ~/.claude/projects/*.jsonl and finding the implementation would hurt, cloud-split. Otherwise don't pay the complexity tax.
Why this works
Encrypted skills decrypt to stdout → Claude reads → the plaintext is logged to ~/.claude/projects/*.jsonl forever. Anyone with file access can grep it.
Cloud-split never puts the implementation on the user's disk. The client only sees:
- A public thin SKILL.md that says "call this CLI command"
- The CLI's structured JSON output (data, not instructions)
Grep'ing jsonl reveals only the API contract, not the logic behind it — same level of exposure as any third-party API call.
Architecture
User: /<skill-name> <args>
↓
Claude reads thin SKILL.md
↓
`lovstudio-skill-helper call <skill> --op <op> --input '<json>'`
↓ HMAC-signed HTTP POST
Supabase Edge Function `skill_call`
↓ verify license + entitlement + device activation
handlers/<skill-name>.ts (this is what lives server-side)
↓ pure computation, may call DBs/third-party APIs
← returns { output: {...} } pure data, no instructions
Claude renders the data per the thin SKILL.md's instructionsDesign rules (non-negotiable)
Rule 1: Handler returns DATA, not INSTRUCTIONS
✓ Good:
return { grid: [[1,2],[3,4]], colors: ["#f00","#0f0"], fonts: ["Inter"] };✗ Bad:
return { next_step: "Now tell Claude to: 1. Draw grid. 2. Apply colors..." };Why: anything you return ends up in jsonl. Instructions = leaked prompt. Data = harmless.
Rule 2: No LLM calls in the handler
The whole point is to avoid server-side token costs. Handler does deterministic work: DB queries, algorithm execution, template rendering, third-party APIs.
If a step needs LLM judgment, return "judgment rules" as data and let the client's Claude (user's tokens) apply them.
Rule 3: Client SKILL.md is the "transport layer"
The thin SKILL.md describes:
- How to parse user input into the
--inputJSON - What CLI command to run
- How to render the returned JSON
It does NOT describe:
- The algorithm
- Why you chose these parameters
- Any "know-how"
If it feels like you're duplicating logic between SKILL.md and the handler, you're doing it wrong — logic goes in the handler only.
Rule 4: Handler surface is stable, versioned
The op names + input/output shapes are a public API to your client. Breaking changes need a new op (e.g. sum_v2) or a version bump in skill_version.
Rule 5: De-business the API surface AND the payload values
This is as important as keeping logic server-side. The skill name + op name + input field names + output field values all appear in ~/.claude/projects/*.jsonl. Any of these can leak the logic.
5a. Field names: capability domain, not specific logic
| ✗ Leaky | ✓ Neutral |
|---|---|
viral-headline-detector + op: check_viral | text-scorer + op: score |
zodiac-compatibility + op: compute_match | profile-matcher + op: match |
sum-gt-ten + op: check_sum_exceeds | threshold-check + op: evaluate |
input: {threshold_value: 10} | input: {params: {...}} (opaque bag) |
Field names should describe shape, not meaning. {params, options, result, verdict, score} are good generic names; {chinese_poem_style, viral_score, fraud_probability} leak intent.
5b. Payload values: symbolic, not descriptive
Field names alone aren't enough. The values themselves must not reveal the rule. Contrast:
| ✗ Self-describing output | ✓ Opaque output |
|---|---|
{score: 8, verdict: "below", display: "2+6=8 (below 10)"} | {verdict: "B"} |
{matched: true, compatibility: 0.87} | {verdict: "A"} |
{is_viral: false, reason: "too generic"} | {verdict: "B", code: "G1"} |
Why: if the output contains {score: 8} paired with input [2, 6], an observer infers algorithm = sum. If the output contains "below" against input threshold 10, an observer infers the comparison semantics. A directional word, a numeric derivation, or a narrative display string — any of these tells the pirate the rule.
Return the minimum the client needs to render. Symbolic tokens ("A", "B", "G1") beat descriptive strings. The thin-client SKILL.md owns the symbol → human text mapping — that mapping is public (it has to be), but it's the safe side of the split.
5c. Input: take opaque bags when possible
If your handler accepts {params: {threshold: 10, weights: [...], mode: "strict"}}, the field name params is neutral — but threshold, weights, mode inside all leak your rule shape.
When feasible:
- Hardcode defaults server-side so the client doesn't need to pass them
- Accept a single opaque config key that the client doesn't understand
- Or: version the input shape (
{config_version: "v2", values: [...]}) and
keep the schema server-side
Perfect opacity is rare in practice. Aim for: an observer who reads 100 jsonl calls cannot reconstruct a working clone without additional guesswork.
5d. The self-test
Imagine a competitor with zero source access who reads only the jsonl logs of 20 calls. Can they: 1. Guess what the skill does? (acceptable if name is domain-level) 2. Guess the algorithm well enough to reimplement it? (NOT acceptable — if yes, you've failed cloud-split)
If failing, iterate on:
- Collapsing multi-field outputs into single symbolic codes
- Moving input config server-side (don't let client pass it)
- Renaming field values to non-semantic tokens
File layout
<name>-skill/ ← public repo (thin client)
├── SKILL.md ← transport-layer instructions
├── README.md
└── (no scripts/ needed unless for pure-client rendering)
web/supabase/functions/skill_call/
├── index.ts ← dispatcher (one per project, shared)
└── handlers/
└── <name>.ts ← your handler (this is the IP)The handler lives in the private web repo. The thin client lives in a public (or private, same as before) <name>-skill repo. Users only see the thin client.
MANDATORY pre-flight audit — run after writing, before deploying
After you write the handler and the thin client, stop and run this audit. If any answer is "yes", rewrite before proceeding. Do NOT deploy, do NOT register the skill, do NOT tell the user "done" until every item is "no".
Handler output audit — for each field in the return value:
- [ ] Does the field name describe business meaning? (e.g.
compatibility,
viral_score, fraud_level) → rename to {verdict, code, tier, result}
- [ ] Does the value allow reverse-engineering the rule when paired with
the input? (e.g. score: 8 with input [2, 6] → algorithm = sum) → collapse to a symbolic token ("A", "B", "G1")
- [ ] Is there a
displayormessagestring that narrates the computation?
→ delete it. Rendering is the client's job, and narration leaks everything (see the threshold-check incident below)
- [ ] Are numeric intermediate results returned? → remove unless genuinely
required for client rendering
Thin client SKILL.md audit:
- [ ] Does the SKILL.md describe what the rule is (not just how to call
and render)? → remove rule descriptions
- [ ] Do the "input parsing rules" section reveal default parameter values
the server uses? → move defaults server-side, have the client omit the field
- [ ] Does the rendering section translate a descriptive server value
(e.g. "above"/"below") into user text? → change server to return symbols; put the symbol→text mapping in the client's render table
- [ ] Do the trigger phrases in frontmatter describe the business logic
(e.g. "check if sum exceeds N")? → generalize them
Self-test (30-second version): Imagine a pirate reading 10 jsonl entries of this skill being used. Can they guess the rule well enough to reimplement it? If yes, the protection is theater. Iterate until no.
Known failure case: threshold-check v0.1.0 (2026-04)
A naive first cut of threshold-check returned {score: 8, verdict: "below", display: "2+6=8 (below 10)"}. Every field leaked: score revealed the algorithm, verdict revealed the comparison, display narrated the full rule. The cloud-split architecture was followed to the letter, but the protection was zero. Fixed version returns only `{verdict: "A" | "B"}` — same architecture, real protection.
Lesson: cloud-split is necessary but not sufficient. Without Rule 5 + this audit, you get the infrastructure cost without the protection benefit.
Implementation steps
1. Write the handler
web/supabase/functions/skill_call/handlers/<name>.ts:
export async function run(op: string, input: unknown): Promise<unknown> {
if (op === "primary_op") {
const typedInput = input as { field1: string; field2: number };
// ... your IP here ...
return { result: "...", /* pure data only */ };
}
throw new Error(`unknown op: ${op}`);
}2. Register handler in dispatcher
web/supabase/functions/skill_call/index.ts:
import { run as runYourSkill } from "./handlers/<name>.ts";
const HANDLERS: Record<string, Handler> = {
"paid-add": runPaidAdd,
"<name>": runYourSkill, // ← add this
};3. Ensure the skill exists in the DB
-- If not already present:
INSERT INTO public.skills (name, category) VALUES ('<name>', '<Category>');
-- Grant it to a license for testing (use your own license_id):
INSERT INTO public.license_skill_grants (license_id, skill_id, source)
SELECT <license_id>, id, 'dev_test' FROM public.skills WHERE name = '<name>';4. Deploy
cd ~/lovstudio/coding/web
supabase functions deploy skill_call --project-ref nouchjcfeoobplxkwasg5. Write the thin-client SKILL.md
---
name: lovstudio-<name>
description: <one line> ... Trigger when user says "...".
version: 0.1.0
---
# <name>
Thin client. Real implementation is server-side.
## How to invoke
Given user input `<describe shape>`:
1. Parse into JSON, e.g. `{"field1": "...", "field2": 42}`.
2. Run:lovstudio-skill-helper call <name> --op primary_op --input '<json>'
3. The CLI prints JSON with shape:{ "result": "...", ... }
4. <Describe how to render result. Be specific so Claude can't improvise.>
## Error handling
- `not activated` → activation prompt
- `not entitled to this skill` → upgrade/purchase prompt
- other → show verbatim
## Why the thin client
Unlike encrypted skills, cloud-split skills keep the real implementation on
the server. This thin SKILL.md is only the transport layer.6. Test end-to-end
lovstudio-skill-helper call <name> --op primary_op --input '{"field1":"x","field2":42}'Expected: JSON output on stdout. Error on stderr for auth/entitlement issues.
Security notes
- The license HMAC signing protects against anyone without the license key
from calling the endpoint — so server CPU cost is bounded by your paid users
- Nonces prevent replay attacks; don't skip the
used_noncesinsert in
_shared/auth.ts
- Handlers should validate input shape aggressively — treat all input as
adversarial (paid users may still probe your handler for bugs)
- Rate-limit per license at the Edge Function level if abuse becomes an issue
(Supabase Edge Functions have per-request DB access; a simple invocations log + count check works)
What cloud-split does NOT solve
- Fake-out via reimplementation: a motivated user can observe your I/O
shape and rebuild an inferior clone. Your moat is quality, not secrecy.
- User's API latency budget: each call is ~200-500ms HTTP round-trip. For
interactive skills, batch where possible.
- Offline usage: cloud-split skills don't work offline. If offline is
critical, you're stuck with encrypted + accepting L2 leakage.
Reference implementations
✓ threshold-check — copy this pattern
Minimal end-to-end with actual protection. Start here.
- Handler:
web/supabase/functions/skill_call/handlers/threshold-check.ts
— returns {verdict: "A" | "B"}, nothing else
- Thin client:
skills/threshold-check-skill/SKILL.md
— transport + symbol→text table, zero rule description
- CLI command:
lovstudio-skill-helper call threshold-check --op evaluate --input '{"params": {"values": [2, 6], "threshold": 10}}'
Key patterns to copy:
- Handler returns a single symbolic field, no derived values, no narration
- Thin client has a rendering table, not a rendering algorithm
- No "what the rule is" text anywhere public
⚠ paid-add — architecture demo only, do NOT copy the return shape
paid-add exists to demonstrate the cloud-split infrastructure (CLI + Edge Function + handler dispatch + HMAC auth). Its return value ({result, display, marker}) leaks the algorithm on purpose — it's a teaching demo, not a protection example.
If you're writing a real protected skill, copy threshold-check's return shape, not paid-add's. The architecture is identical; only the payload discipline matters for protection.
Migration Notes
2026-05: dev-skills aggregate target
Some free developer/meta skills should live directly in lovstudio/dev-skills instead of requiring a dedicated repo. Use --target dev-skills for those:
python3 ~/.claude/skills/lovstudio-skill-creator/scripts/init_skill.py tanstack-query --target dev-skillsThe skill directory is:
~/lovstudio/coding/lovstudio-dev-skills/skills/tanstack-query/skills.yaml must include:
repo: lovstudio/dev-skills
skill_path: skills/tanstack-query2026-04: independent per-skill repos
The ecosystem was refactored from a monorepo (lovstudio/skills containing skills/lovstudio-<name>/) + mirror (lovstudio/pro-skills) into independent per-skill repos + central index. The old lovstudio/pro-skills was archived.
If working on a legacy skill still in the old structure, migrate it first:
# 1. Extract from monorepo subdirectory
cp -r ~/projects/lovstudio-skills/skills/lovstudio-<name> \
~/lovstudio/coding/skills/<name>-skill
cd ~/lovstudio/coding/skills/<name>-skill
# 2. Fresh git history
rm -rf .git
git init && git add -A && git commit -m "import: <name> from monorepo"
# 3. Create independent repo
gh repo create lovstudio/<name>-skill --public --source=. --pushLovStudio Skill Standard
This standard applies to public, paid, bundled, and internal LovStudio skills. Its goal is portability first: a skill may carry LovStudio branding, but it must not silently depend on Mark's local machine, workspace layout, or private brand assets unless the skill is explicitly marked author-only.
Naming
- Use Agent Skills-compatible names: lowercase letters, numbers, and hyphens.
- Prefer
lovstudio-<name>inSKILL.mdfrontmatter. - Avoid
lovstudio:<name>for new skills. Treat colon names as legacy aliases. - Source repos may still be named
<name>-skill, but installed/distributed
skill directories should resolve to lovstudio-<name>/ so the directory and frontmatter name can match in user environments.
Runtime Portability
Skills must not assume these paths in execution instructions or scripts:
/Users/mark/...~/lovstudio/...~/.claude/...except in human-facing install examples~/.agents/...except in maintainer docs
Use this precedence whenever a skill needs user-specific paths, identity, brand assets, or workspace settings:
1. Explicit CLI flags. 2. Environment variables. 3. User profile file. 4. Safe defaults such as the current working directory or an output directory under $HOME/Documents. 5. Ask the user once and explain what setting is missing.
User Profile Contract
Portable skills may read a shared JSON profile at:
${LOVSTUDIO_SKILLS_PROFILE:-$HOME/.lovstudio/skills/profile.json}Recommended fields:
{
"user": {
"name": "Your Name",
"language": "zh-CN",
"timezone": "Asia/Shanghai"
},
"workspace": {
"root": "$HOME/projects",
"output_dir": "$HOME/Documents/lovstudio-skill-output"
},
"brand": {
"name": "Your Brand",
"site": "https://example.com",
"profile": "$HOME/.lovstudio/skills/brand.json",
"design_guide": "$HOME/.lovstudio/skills/design-guide.md"
}
}Environment variables override profile fields:
| Variable | Meaning |
|---|---|
LOVSTUDIO_SKILLS_PROFILE | Path to the shared profile JSON |
LOVSTUDIO_SKILLS_HOME | Shared LovStudio skills config/data directory |
LOVSTUDIO_SKILLS_INSTALL_DIR | User's local agent skills installation directory |
LOVSTUDIO_SKILLS_WORKSPACE_ROOT | User workspace root |
LOVSTUDIO_SKILLS_OUTPUT_DIR | Default generated output directory |
LOVSTUDIO_SKILLS_BRAND_PROFILE | Brand profile JSON or Markdown |
LOVSTUDIO_SKILLS_DESIGN_GUIDE | Design guide path |
Skill-specific variables should use LOVSTUDIO_<SKILL_NAME>_*, for example LOVSTUDIO_MAINTAIN_PARTNERS_SITE_ROOT. Avoid broad names such as PARTNERS_SITE_ROOT and avoid pseudo-generic namespaces such as AGENT_SKILL_* unless LovStudio is intentionally publishing a separate, vendor-neutral standard.
Default files live under ~/.lovstudio/skills/ because these skills are distributed by LovStudio. That directory is a storage namespace, not the public API. Users can override it with LOVSTUDIO_SKILLS_PROFILE.
Brand Coupling
Brand-aware skills should split their behavior into:
- Generic workflow: reusable by any user or brand.
- LovStudio defaults: optional profile/reference loaded only when configured.
- User initialization: a documented path for replacing LovStudio/Mark values
with the user's own brand, workspace, design guide, and output directory.
If a skill is truly LovStudio-internal, say so in compatibility and README. Internal skills may use LovStudio paths, but they should still keep them in one configuration section rather than scattering absolute paths across workflows.
Scripts
- Scripts should accept explicit paths via CLI flags.
- Scripts should not import from private absolute paths.
- Scripts may use the shared profile contract, but missing profile values must
produce actionable errors.
- Prefer
argparsefor Python CLIs.
Migration Labels
Use these labels when auditing existing skills:
portable: no local or brand-specific assumptions.config-needed: useful to public users, but needs a profile/env layer.lovstudio-defaults: generic core with optional LovStudio defaults.author-only: intentionally tied to Mark/LovStudio private workspace.legacy-name: still useslovstudio:<name>or mismatched directory naming.
Templates
SKILL.md Template
---
name: lovstudio-<name>
description: >
<What it does — 1-2 sentences.>
<When to trigger — specific scenarios, file types, user phrases.>
Also trigger when the user mentions "<中文触发词>", "<english trigger>".
license: MIT
compatibility: >
Portable Agent Skills format. Requires Python 3.8+ and <library>.
User-specific paths, brand assets, and workspace settings must come from
explicit CLI flags, environment variables, or the shared user profile.
# Optional: declare required skill-level dependencies by exact SKILL.md
# frontmatter name. Example:
# depends_on:
# - lovstudio-<other-skill>
metadata:
author: lovstudio
version: "0.1.0"
tags: <space-separated tags>
---
# <name> — <Short Title>
<1-2 sentence overview.>
## User Configuration
This skill must not assume Mark's local workspace, `~/lovstudio`,
`/Users/mark`, or a fixed Claude install path. If user-specific paths or brand
settings are needed, follow `references/user-config.md`.
## When to Use
- <Scenario 1>
- <Scenario 2>
## Workflow (MANDATORY)
### Step 0: Resolve skill root and user config
SKILL_DIR="${SKILL_DIR:-$HOME/.claude/skills/lovstudio-<name>}"
If user-specific fields are missing, ask once and map the answer to CLI flags,
environment variables, or the shared profile described in
`references/user-config.md`.
### Step 1: <First action>
python3 "$SKILL_DIR/scripts/<script>.py" --flag value
### Step 2: Ask the user
**Use `AskUserQuestion` to collect options BEFORE running.**
### Step 3: Execute
python3 "$SKILL_DIR/scripts/<script>.py" --input <path> --output <path>
## CLI Reference
| Argument | Default | Description |
|----------|---------|-------------|
| `--input` | (required) | ... |
| `--output` | `output.ext` | ... |
## Dependencies
pip install <library> --break-system-packages
README.md Template
# lovstudio-<name>

<One-line description.>
Part of [lovstudio general skills](https://github.com/lovstudio/general-skills) — by [lovstudio.ai](https://lovstudio.ai)
## Install
git clone https://github.com/lovstudio/<name>-skill "${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}/lovstudio-<name>"
Requires: Python 3.8+ and `pip install <library>`
## Configuration
This skill is portable by default. User-specific paths and brand settings should
be provided through CLI flags, environment variables, or:
${LOVSTUDIO_SKILLS_PROFILE:-$HOME/.lovstudio/skills/profile.json}
See `references/user-config.md`.
## Usage
SKILL_DIR="${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}/lovstudio-<name>" python3 "$SKILL_DIR/scripts/<script>.py" --input file.ext --output result.ext
## Options
| Option | Default | Description |
|--------|---------|-------------|
| `--input` | (required) | ... |
| `--output` | `output.ext` | ... |
## License
MITDev-Skills README Install Block
Use this block instead of the independent git clone install when the skill lives directly in lovstudio/dev-skills:
~~~markdown
Install
npx skills add lovstudio/dev-skillsOr through Claude Code plugin marketplace:
/plugin marketplace add lovstudio/dev-skills
/plugin install dev-tools@lovstudio-dev~~~
Notes
- Version source of truth:
README.mdbadge.SKILL.mdfrontmatter
metadata.version is kept in sync by skill-optimizer.
- New skills use Agent Skills-compatible frontmatter names:
lovstudio-<name>. Legacy lovstudio:<name> skills should be migrated opportunistically, not copied into new templates.
- User-specific paths, workspaces, brand profiles, and design guides must be
initialized through references/user-config.md, environment variables, or CLI flags. Do not hard-code /Users/mark, ~/lovstudio, or private LovStudio workspace paths in reusable workflow steps.
- Start at
0.1.0, not1.0.0— per repo release conventions (stay in 0.x
unless explicitly promoted).
paidis not in SKILL.md frontmatter. It lives only in
~/lovstudio/coding/lovstudio-general-skills/skills.yaml.
depends_onmay appear in SKILL.md frontmatter when a skill requires another
skill. Use the dependency skill's exact SKILL.md name; when registering the same relationship in skills.yaml, use the catalog skill name.
- Dev-skills entries use
repo: lovstudio/dev-skillsand
skill_path: skills/<name> in ~/lovstudio/coding/lovstudio-dev-skills/skills.yaml.
User Configuration Reference
Use this reference when creating or refactoring skills that currently assume a specific local machine, workspace, brand, or output path.
Rule
Reusable skills must not depend on Mark's machine layout. Do not scatter these values through SKILL.md, scripts, or README examples:
/Users/mark/...~/lovstudio/...- private LovStudio web, vault, brand, or design-guide paths
~/.claude/...as a required runtime path
Resolution Order
When a skill needs user-specific settings, resolve them in this order:
1. Explicit CLI flags. 2. Environment variables. 3. Shared user profile JSON. 4. Safe defaults such as the current working directory or $HOME/Documents. 5. Ask the user once and tell them which setting is missing.
Shared Profile
Default profile path:
${LOVSTUDIO_SKILLS_PROFILE:-$HOME/.lovstudio/skills/profile.json}Recommended shape:
{
"user": {
"name": "Your Name",
"language": "zh-CN",
"timezone": "Asia/Shanghai"
},
"workspace": {
"root": "$HOME/projects",
"output_dir": "$HOME/Documents/lovstudio-skill-output"
},
"brand": {
"name": "Your Brand",
"site": "https://example.com",
"profile": "$HOME/.lovstudio/skills/brand.json",
"design_guide": "$HOME/.lovstudio/skills/design-guide.md"
}
}Environment variable overrides:
| Variable | Meaning |
|---|---|
LOVSTUDIO_SKILLS_PROFILE | Shared profile JSON path |
LOVSTUDIO_SKILLS_HOME | Shared LovStudio skills config/data directory |
LOVSTUDIO_SKILLS_WORKSPACE_ROOT | Workspace root |
LOVSTUDIO_SKILLS_OUTPUT_DIR | Default output directory |
LOVSTUDIO_SKILLS_BRAND_PROFILE | Brand profile JSON or Markdown |
LOVSTUDIO_SKILLS_DESIGN_GUIDE | Design guide path |
Refactor Pattern
Replace this:
Read `/Users/mark/lovstudio/design/design-guide.md`.
Write output to `/Users/mark/lovstudio/output`.With this:
Resolve brand settings from `LOVSTUDIO_SKILLS_DESIGN_GUIDE` or the shared profile.
Resolve output from `--output`, `LOVSTUDIO_SKILLS_OUTPUT_DIR`, or the shared profile.
If neither exists, ask the user once and default to `$HOME/Documents`.Classification
portable: no local or brand-specific assumptions.config-needed: reusable, but needs a profile/env layer before public use.lovstudio-defaults: generic core with optional LovStudio defaults.author-only: intentionally tied to Mark/LovStudio private workspace.legacy-name: still useslovstudio:<name>or mismatched directory naming.
#!/usr/bin/env python3
"""
Initialize a new lovstudio skill scaffold.
Usage:
python3 init_skill.py <name>
python3 init_skill.py <name> --paid
python3 init_skill.py <name> --target dev-skills
python3 init_skill.py <name> --dev-skills
python3 init_skill.py <name> --path /custom/path
Examples:
python3 init_skill.py fill-form
→ <configured repos root>/fill-form-skill/
python3 init_skill.py any2pptx
→ <configured repos root>/any2pptx-skill/
python3 init_skill.py tanstack-query --target dev-skills
→ <configured dev-skills root>/tanstack-query/
Default base directories resolve from --path, LOVSTUDIO_SKILL_CREATOR_* env
vars, the shared profile JSON, then a safe current-directory fallback.
"""
import argparse
import json
import os
import re
import sys
from pathlib import Path
from typing import Optional, Tuple
SKILL_MD = '''---
name: lovstudio-{name}
description: >
TODO: What this skill does (1-2 sentences).
TODO: When to trigger — specific scenarios, file types, user phrases.
Also trigger when the user mentions "TODO_CN", "TODO_EN".
license: MIT
compatibility: >
Portable Agent Skills format. TODO: Requires Python 3.8+ and <library>.
User-specific paths, brand assets, and workspace settings must come from
explicit CLI flags, environment variables, or the shared user profile.
# Optional: declare required skill-level dependencies by exact SKILL.md
# frontmatter name. Example:
# depends_on:
# - lovstudio-<other-skill>
metadata:
author: lovstudio
version: "0.1.0"
tags: TODO
---
# {name} — TODO: Short Title
TODO: 1-2 sentence overview.
## User Configuration
This skill must not assume a private workspace, personal absolute paths, or a
fixed agent runtime path. If user-specific paths or brand settings are needed,
follow `references/user-config.md`.
## When to Use
- TODO: Scenario 1
- TODO: Scenario 2
## Workflow (MANDATORY)
**You MUST follow these steps in order:**
### Step 0: Resolve skill root and user config
- Use `SKILL_DIR` if the environment provides it.
- Otherwise infer the installed skill directory from the current skill context.
- When running scripts manually, set it explicitly:
```bash
export SKILL_DIR="/path/to/lovstudio-{name}"
```
If user-specific fields are missing, ask once and map the answer to CLI flags,
environment variables, or the shared profile described in
`references/user-config.md`.
### Step 1: TODO
```bash
python3 "$SKILL_DIR/scripts/TODO.py" --help
```
### Step 2: Ask the user when needed
**IMPORTANT: Use `AskUserQuestion` to collect options BEFORE running.**
### Step 3: Execute
```bash
python3 "$SKILL_DIR/scripts/TODO.py" --input <path> --output <path>
```
## CLI Reference
| Argument | Default | Description |
|----------|---------|-------------|
| `--input` | (required) | TODO |
| `--output` | `output.ext` | TODO |
## Dependencies
```bash
pip install TODO --break-system-packages
```
'''
README_MD = '''# lovstudio-{name}

TODO: One-line description.
Part of [lovstudio general skills](https://github.com/lovstudio/general-skills) — by [lovstudio.ai](https://lovstudio.ai)
## Install
```bash
git clone https://github.com/lovstudio/{name}-skill "${{LOVSTUDIO_SKILLS_INSTALL_DIR:?Set LOVSTUDIO_SKILLS_INSTALL_DIR}}/lovstudio-{name}"
```
Requires: Python 3.8+ and `pip install TODO`
## Configuration
This skill is portable by default. User-specific paths and brand settings should
be provided through CLI flags, environment variables, or:
```bash
${{LOVSTUDIO_SKILLS_PROFILE:-$HOME/.lovstudio/skills/profile.json}}
```
See `references/user-config.md`.
## Usage
```bash
SKILL_DIR="${{LOVSTUDIO_SKILLS_INSTALL_DIR:?Set LOVSTUDIO_SKILLS_INSTALL_DIR}}/lovstudio-{name}"
python3 "$SKILL_DIR/scripts/TODO.py" --input file.ext --output result.ext
```
## Options
| Option | Default | Description |
|--------|---------|-------------|
| `--input` | (required) | TODO |
| `--output` | `output.ext` | TODO |
## License
MIT
'''
DEV_SKILLS_README_MD = '''# lovstudio-{name}

TODO: One-line description.
Part of [lovstudio dev-skills](https://github.com/lovstudio/dev-skills) — by [lovstudio.ai](https://lovstudio.ai)
## Install
```bash
npx skills add lovstudio/dev-skills
```
Or through Claude Code plugin marketplace:
```text
/plugin marketplace add lovstudio/dev-skills
/plugin install dev-tools@lovstudio-dev
```
Requires: Python 3.8+ and `pip install TODO`
## Configuration
This skill is portable by default. User-specific paths and brand settings should
be provided through CLI flags, environment variables, or:
```bash
${{LOVSTUDIO_SKILLS_PROFILE:-$HOME/.lovstudio/skills/profile.json}}
```
See `references/user-config.md`.
## Usage
```bash
SKILL_DIR="${{LOVSTUDIO_SKILLS_INSTALL_DIR:?Set LOVSTUDIO_SKILLS_INSTALL_DIR}}/lovstudio-{name}"
python3 "$SKILL_DIR/scripts/TODO.py" --input file.ext --output result.ext
```
## Options
| Option | Default | Description |
|--------|---------|-------------|
| `--input` | (required) | TODO |
| `--output` | `output.ext` | TODO |
## License
MIT
'''
GITIGNORE = '''__pycache__/
*.pyc
*.pyo
.DS_Store
.venv/
venv/
node_modules/
.env
.env.local
'''
USER_CONFIG_MD = '''# User Configuration
This skill follows the portable agent skill profile contract. It must not
assume a private workspace, personal absolute paths, or private brand assets.
## Resolution Order
1. Explicit CLI flags.
2. Environment variables.
3. Shared profile JSON.
4. Safe defaults such as the current working directory or `$HOME/Documents`.
5. Ask the user once for missing required fields.
## Shared Profile
Default profile path:
```bash
${{LOVSTUDIO_SKILLS_PROFILE:-$HOME/.lovstudio/skills/profile.json}}
```
Example:
```json
{{
"user": {{
"name": "Your Name",
"language": "zh-CN",
"timezone": "Asia/Shanghai"
}},
"workspace": {{
"root": "$HOME/projects",
"output_dir": "$HOME/Documents/lovstudio-skill-output"
}},
"brand": {{
"name": "Your Brand",
"site": "https://example.com",
"profile": "$HOME/.lovstudio/skills/brand.json",
"design_guide": "$HOME/.lovstudio/skills/design-guide.md"
}}
}}
```
Environment variable overrides:
| Variable | Meaning |
|----------|---------|
| `LOVSTUDIO_SKILLS_PROFILE` | Path to the shared profile JSON |
| `LOVSTUDIO_SKILLS_HOME` | Shared LovStudio skills config/data directory |
| `LOVSTUDIO_SKILLS_WORKSPACE_ROOT` | User workspace root |
| `LOVSTUDIO_SKILLS_OUTPUT_DIR` | Default generated output directory |
| `LOVSTUDIO_SKILLS_BRAND_PROFILE` | Brand profile JSON or Markdown |
| `LOVSTUDIO_SKILLS_DESIGN_GUIDE` | Design guide path |
## Implementation Notes
- Scripts should accept explicit paths via CLI flags.
- Missing profile fields should produce actionable errors.
- LovStudio maintainer defaults belong in an optional profile, not in the workflow.
'''
def _expand_path(value: str) -> Path:
return Path(os.path.expandvars(value)).expanduser()
def _nested(data: dict, dotted: str) -> Optional[str]:
cur = data
for part in dotted.split("."):
if not isinstance(cur, dict) or part not in cur:
return None
cur = cur[part]
return str(cur) if cur else None
def _load_profile() -> Tuple[Path, dict]:
profile = _expand_path(
os.environ.get("LOVSTUDIO_SKILLS_PROFILE")
or str(Path.home() / ".lovstudio/skills/profile.json")
)
if not profile.exists():
return profile, {}
try:
return profile, json.loads(profile.read_text())
except json.JSONDecodeError as exc:
print(f"ERROR: invalid JSON in {profile}: {exc}", file=sys.stderr)
sys.exit(1)
def _profile_first(data: dict, keys: Tuple[str, ...]) -> Optional[str]:
for key in keys:
value = _nested(data, key)
if value:
return value
return None
def _default_dev_skills_base(cwd: Path) -> Optional[Path]:
if cwd.name == "skills" and (cwd.parent / "skills.yaml").exists():
return cwd
if (cwd / "skills.yaml").exists() and (cwd / "skills").is_dir():
return cwd / "skills"
return None
def resolve_base(target: str, cli_path: str) -> Path:
if cli_path:
return _expand_path(cli_path)
profile_path, profile = _load_profile()
if target == "dev-skills":
env_key = "LOVSTUDIO_SKILL_CREATOR_DEV_SKILLS_ROOT"
profile_keys = (
"lovstudio.dev_skills_root",
"skills.dev_skills_root",
"workspace.dev_skills_root",
)
else:
env_key = "LOVSTUDIO_SKILL_CREATOR_REPOS_ROOT"
profile_keys = (
"lovstudio.skill_repos_root",
"skills.repos_root",
"workspace.skill_repos_root",
"workspace.skills_root",
)
if os.environ.get(env_key):
return _expand_path(os.environ[env_key])
profile_value = _profile_first(profile, profile_keys)
if profile_value:
return _expand_path(profile_value)
cwd = Path.cwd()
if target == "repo":
return cwd
dev_base = _default_dev_skills_base(cwd)
if dev_base:
return dev_base
print(
"ERROR: dev-skills target needs --path, LOVSTUDIO_SKILL_CREATOR_DEV_SKILLS_ROOT, "
f"or a dev_skills_root value in {profile_path}",
file=sys.stderr,
)
sys.exit(1)
def main():
ap = argparse.ArgumentParser(description="Initialize a new lovstudio skill")
ap.add_argument("name", help="Skill short name (no prefix / no -skill suffix)")
ap.add_argument(
"--target",
choices=("repo", "dev-skills"),
default="repo",
help="Scaffold target: independent per-skill repo (default) or lovstudio/dev-skills bundle",
)
ap.add_argument(
"--dev-skills",
action="store_true",
help="Shortcut for --target dev-skills",
)
ap.add_argument(
"--path",
default="",
help=(
"Custom base directory. Defaults resolve from LOVSTUDIO_SKILL_CREATOR_* env, "
"the shared profile JSON, then a safe current-directory fallback."
),
)
ap.add_argument("--paid", action="store_true", help="Mark as paid in hints (actual paid flag lives in lovstudio-general-skills/skills.yaml)")
args = ap.parse_args()
# Normalize: strip common prefixes / suffix users might paste
name = args.name
for pfx in ("lovstudio:", "lovstudio-"):
if name.startswith(pfx):
name = name[len(pfx):]
if name.endswith("-skill"):
name = name[: -len("-skill")]
if not re.fullmatch(r"[a-z0-9]+(?:-[a-z0-9]+)*", name):
print(
"ERROR: skill name must use lowercase letters, numbers, and single hyphens only",
file=sys.stderr,
)
sys.exit(1)
target = "dev-skills" if args.dev_skills else args.target
if target == "dev-skills" and args.paid:
print("ERROR: --target dev-skills is only for free Meta / Dev Tools skills. Use the default independent repo target for paid skills.", file=sys.stderr)
sys.exit(1)
base = resolve_base(target, args.path)
base.mkdir(parents=True, exist_ok=True)
skill_dir = base / name if target == "dev-skills" else base / f"{name}-skill"
if skill_dir.exists():
print(f"ERROR: {skill_dir} already exists", file=sys.stderr)
sys.exit(1)
skill_dir.mkdir()
(skill_dir / "scripts").mkdir()
(skill_dir / "references").mkdir()
(skill_dir / "SKILL.md").write_text(SKILL_MD.format(name=name))
readme = DEV_SKILLS_README_MD if target == "dev-skills" else README_MD
(skill_dir / "README.md").write_text(readme.format(name=name))
(skill_dir / "references" / "user-config.md").write_text(USER_CONFIG_MD.format(name=name))
(skill_dir / ".gitignore").write_text(GITIGNORE)
print(f"✓ Created {skill_dir}/")
print(f" SKILL.md — AI-facing frontmatter + workflow")
print(f" README.md — human-facing GitHub docs")
print(f" references/ — user configuration contract")
print(f" scripts/ — add Python CLI scripts here")
print(f" .gitignore")
print()
print("Next steps:")
if target == "dev-skills":
dev_root = skill_dir.parents[1]
print(f" 1. cd {dev_root}")
print(f" 2. Implement skills/{name}/ and fill TODO placeholders in SKILL.md / README.md")
print(" 3. Add to skills.yaml:")
print(f" - name: {name}")
print(" repo: lovstudio/dev-skills")
print(f" skill_path: skills/{name}")
print(" paid: false")
print(' category: "Dev Tools" # or "Meta"')
print(" version: \"0.1.0\"")
print(f" 4. Add ./skills/{name} to .claude-plugin/marketplace.json under meta or dev-tools")
print(" 5. python3 scripts/render-readme.py")
print(f" 6. Install or symlink {skill_dir} into your agent's skills directory as lovstudio-{name}")
print(f" 7. git add skills.yaml README.md README.en.md .claude-plugin/marketplace.json skills/{name}")
print(f" git commit -m 'add: {name} skill'")
else:
print(f" 1. cd {skill_dir}")
print(f" 2. Implement scripts/ and fill TODO placeholders in SKILL.md / README.md")
print(f" 3. git init && git add -A && git commit -m 'feat: initial release of {name} skill'")
visibility = "--private" if args.paid else "--public"
print(f" 4. gh repo create lovstudio/{name}-skill {visibility} --source=. --push")
print(f" 5. Install or symlink {skill_dir} into your agent's skills directory as lovstudio-{name}")
paid_flag = "true" if args.paid else "false"
print(f" 6. Register in your general-skills checkout skills.yaml (paid: {paid_flag})")
if __name__ == "__main__":
main()