Teaching Claude Code to Write and Grow Its Own Skills: A Self-Replicating Agent Environment
Last time I wrote about splitting Claude Code's memory into four layers. This is the follow-up: a setup where Claude Code itself discovers "reusable procedures" and accumulates them as skills over time. After running this for a few months, ~/.claude/skills/auto/ now holds 64 auto-generated skills. In this article I'll cover the design of that self-replication, the mechanisms that prevent overproduction, and the generation curve I observed while operating it.
The problem: rebuilding the same procedure from scratch every time. Claude Code is capable, but across sessions it forgets "how I got around this error last time." How to fix launchd's exit 78, the steps to bake a favicon with png-to-ico, how to trim the RSC payload in Next.js - these procedures I should have already solved once were being rebuilt from scratch every single time. I could hand-write additions to CLAUDE.md, but that turns into a "whoever notices, writes it" workflow, and that doesn't last. So I flipped the idea around and decided to make Claude do the work of finding the procedures too.
Design: two-tier generation + Curator
Skill generation is split into two tiers.
| Tier | Timing | Cost | Owner |
|---|---|---|---|
| In-session generation | Any time during work | Free / instant | Claude itself, following CLAUDE.md instructions |
| Nightly batch generation | Daily cron at 3:30 | Consumes Max quota | skill-harvest.sh (claude -p headless) |
Then a Curator (skill-curate.sh) runs weekly to periodically organize the accumulated skills. The key is separating generation and organization into different processes.
Tier 1: in-session generation (free / instant)
CLAUDE.md says this (excerpt).
## スキル自己生成(auto-skills)
作業の中で再利用価値のある手順を見つけたら、頼まれなくても自分でスキル化する。
ただし乱造はしない。
### 生成トリガー(いずれか該当時のみ)
- 5回以上ツールを使う非自明なタスクを最後までやり切った
- エラー・行き止まりにぶつかった後、動く回避策を見つけた
- ユーザーにアプローチを修正された(同じ修正を繰り返さないため)
- 再利用できる手順・コマンド列・ワークフローを発見した
The crux is "but don't overproduce," plus narrowing the triggers down to four. Without writing this, Claude turns everything into a skill and the space fills up with noise almost immediately.
Tier 2: nightly batch generation (catching what was missed)
Procedures that never got written down during a session get picked up from the conversation logs by a nightly batch. The skill-harvest.sh pipeline looks like this.
- Read
.harvest-watermark(the previous processing position) - Extract the diff after the watermark from the conversation logs (
raw/conversations/*.md) - Extract frequent patterns headless via
claude -p(only adopt those appearing more than 5 times) - Deduplicate against all 64 existing skills by kebab-name
- Monitor token usage with a cost-guard hook; abort if the threshold is exceeded
- Write out new candidates to
<name>/SKILL.mdwith three sections: frontmatter + Procedure / Pitfalls / Verification - Trigger the Curator at the end to retire old skills
- Update the watermark and append to the log
claude -p is the headless invocation I mentioned in the previous article. It runs on the Max quota, so API-key charges are zero.
Isolated namespace: why split things into auto/
Auto-generated skills do not go in the same place as hand-written skills or plugin-bundled skills. They're pushed into an isolated namespace, ~/.claude/skills/auto/. Two reasons.
npx skills update -gonly manages lock-registered skills. The ones inauto/aren't added to the lock → they don't get wiped by the daily update.- The Curator only targets things that are "under
auto/andauthor: auto" → it never touches hand-written or bundled skills.
That author: auto is the Curator's target-detection key, and it's required in the frontmatter.
---
name: <kebab-case>
description: <発火条件を具体的に>
author: auto # ← Curatorの対象判定キー。必須
created: <YYYY-MM-DD>
version: 1.0.0
status: active # active | stale(Curatorが自動設定)
---
Organizing: the Curator "never deletes - only proposes"
Left ungoverned, skills rot. The Curator runs weekly like this.
- Before running, take a
tar.gzsnapshot into.snapshots/ - Unused for 30 days → demote to
status: stale - Unused for 90 days → move to
.archive/(never actually deleted - restorable by command) - Consolidation of duplicates and low-quality skills is written to
.curator-proposals.mdas proposals only (not applied automatically)
Not letting the Curator auto-delete is the core of the safe design. "Untouched for 30 days" doesn't necessarily mean the skill is bad (you just haven't done that kind of work). So it stops at demotion and archival, leaving the final call to a human.
What I learned from operating it
Generation is concentrated early, then tapers off
Looking at the distribution of created:, in the first three days after introduction (5/28–30) 28 skills were verbalized in one burst, after which the pace dropped to a few per day. This matches intuition - the "unverbalized procedures" accumulated in the past get released early, and after that only newly encountered procedures get added.
- 12 created: 2026-05-30
- 9 created: 2026-05-29
- 7 created: 2026-06-09
- 6 created: 2026-06-11
- 5 created: 2026-06-10
- 5 created: 2026-05-28
"Don't overproduce" actually works
Here's this morning's harvest log.
会話ログを精査した結果、以下の理由から該当なし。
- Codex CLI のセットアップ → codex-cli-setup が既存
- /insights を CLAUDE.md に反映 → insights-to-claude-md が既存
- カード債務の支払い優先順位 → 個人の財務状況に依存、再利用手順に非該当
該当なし
[2026-06-15 04:11:21] harvest done (exit 0, created=0)
created=0. It rejected duplicates of existing skills, rejected one-off content tied to personal circumstances, and terminated normally with 0 generated. This is proof that the "don't overproduce" design can process a miss as a correct miss. If it generated recklessly here, those 64 would balloon to 200 and turn to noise fast.
Pitfalls I hit
From the Pitfalls sections of actual skills, the ones that mattered.
claude -phits the token cap when the full system prompt loads → suppress withMAX_THINKING_TOKENS=10000- Forgetting to advance the watermark and re-extracting the same log → always check the log's last completed offset
- Grepping on kebab-name alone misses fuzzy duplicates → description embedding comparison is room for improvement (not implemented)
launchdfires at 3:30, but the job is skipped while the Mac is asleep → recommendpmset wakeon schedule- Loading all MCP servers headless makes startup slow → keep a harvest-only minimal config at a separate path
Minimal setup: if you're starting today
You don't need the full pipeline. Just adding one block to CLAUDE.md gets Tier 1 running.
- Create
~/.claude/skills/auto/ - Write in
CLAUDE.md: "When you find a reusable procedure, turn it into a skill yourself. But don't overproduce," plus the four trigger conditions - Require
author: autoin the frontmatter (a marker for organizing later)
That alone means skills grow a little with every piece of work. You can add the nightly batch and the Curator later, once skills have accumulated and you feel like organizing them - that's soon enough.
Summary
- Split skill generation into two tiers: in-session (free) and nightly batch (catching what was missed)
- Spell out "don't overproduce" in the prompt and narrow the triggers. A 0-generated miss is normal
- Isolate auto-generation in
auto/, and makeauthor: autothe Curator's target key - The Curator never deletes - only demotes, archives, and proposes. The final call stays with a human
- Start with a single block in
CLAUDE.md
Next time I'll write about how these skills grew too numerous and Claude Code itself got heavy - the audit that cut context injection from 228KB to 48KB.
Lily (@bokuwalily) - solo developer. I build automation infrastructure with Claude Code while mass-producing iOS apps and web services. The apps I've built are collected in my portfolio. I share new releases and behind-the-scenes development on X @bokuwalily. OSS: github.com/bokuwalily. I wrote about how I used this setup to run an "environment" instead of "work" and got back to 1.2M yen/month, free on note. Your ❤️ and shares mean a lot!
Written by Lily - I ship iOS apps and automate my content stack with Claude Code. Follow along: Portfolio · X · GitHub
Comments
No comments yet. Start the discussion.