.claude/skills/dev/SKILL.md
Create a feature branch + worktree, do the work, then automatically merge back to the current branch
npx skillsauth add songyunseop/oh-my-til .claude/skills/devInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Create a feature branch, do the work in a worktree, then automatically merge back to the current branch and clean up.
/dev "brief feature description"
/dev --branch custom-name "feature description"
/dev --abort [branch-name]
Extract the following from $ARGUMENTS:
--abort): a quoted string describing what to implement concisely--branch hotfix/urgent → branch name hotfix/urgent)--abort Handling# 1. If branch-name is provided: find the worktree for that branch
# 2. If branch-name is omitted: print the worktree list and guide the user to re-run with a branch name
git worktree list
Output when branch-name is not specified:
Current registered worktrees:
{git worktree list output}
Specify the branch to clean up and run again:
/dev --abort feat/my-feature
When branch-name is specified:
# Check for unmerged commits
git log "$BASE_BRANCH".."$BRANCH_NAME" --oneline
# Warn if commits exist
Confirmation message when there are unmerged commits:
[WARNING] This branch has {N} unmerged commit(s):
{commit list}
These commits cannot be recovered after deletion. Do you want to proceed?
→ Use AskUserQuestion to request confirmation and wait for the user's response. Do not proceed with deletion until a response is received.
After user confirmation:
WORKTREE_DIR=$(echo "$BRANCH_NAME" | tr '/' '-')
WORKTREE_PATH="../${PROJECT_NAME}-${WORKTREE_DIR}"
git worktree remove --force "$WORKTREE_PATH"
# Attempt safe delete → force delete only after user confirmation above
git branch -d "$BRANCH_NAME" || git branch -D "$BRANCH_NAME" # -D only after confirmation above
Detect the type of change from the feature description to determine the prefix:
| Detected keywords | prefix | Example |
|-------------------|--------|---------|
| "fix", "bug", "error" | fix/ | fix/pty-path-bug |
| "refactor", "cleanup", "improve" | refactor/ | refactor/mcp-server |
| "docs", "README", "comment" | docs/ | docs/update-readme |
| anything else (default) | feat/ | feat/add-dashboard |
Slug generation rules:
fix/pty-bug)Replace / in the branch name with - for the worktree path:
WORKTREE_DIR=$(echo "$BRANCH_NAME" | tr '/' '-')
WORKTREE_PATH="../${PROJECT_NAME}-${WORKTREE_DIR}"
# Example: feat/add-dashboard → ../oh-my-til-feat-add-dashboard
Claude Code's Bash tool does not preserve shell state (including cd) between calls. Therefore:
$WORKTREE_PATH$WORKTREE_PATH$PROJECT_ROOT/Users/.../oh-my-til-feat-xxx/src/main.ts)Check all conditions below. Abort and notify the user if any one fails.
Verify the working tree is clean
git status --porcelain
Abort if there are uncommitted changes.
Check the current branch
git branch --show-current
main: "Do not work directly on main. Run from a release or other branch"release/* branch, print: "[INFO] Running from release branch ({name}). Merge target: {name}"BASE_BRANCH (merge target)Save the project root
PROJECT_ROOT=$(git rev-parse --show-toplevel) # absolute path
PROJECT_NAME=$(basename "$PROJECT_ROOT")
Abort if the feature description is empty
At any step that requires user confirmation, always wait for the user's response before proceeding. Do not automatically advance to the next phase after printing a confirmation message. Use the AskUserQuestion tool to present choices and only continue after the user responds.
Print the auto-generated branch name and proceed immediately:
[Phase 1/8] Creating branch
Branch: {BRANCH_NAME}
Worktree path: {WORKTREE_PATH}
Base branch: {BASE_BRANCH}
Proceed to Phase 2 without additional confirmation. Use --branch to specify the branch name manually.
[Phase 2/8] Creating worktree...
# Check for path conflict
If the path already exists — three branches:
(a) If the path is registered in git worktree list:
An existing worktree was found: {path}
Reuse it, or delete and recreate? (Reuse / Delete and recreate)
→ Use AskUserQuestion to present the choices and wait for the user's response.
(b) If the path is not in git worktree list but the directory exists (stale worktree):
git worktree prune # clean up stale entries
rm -rf "$WORKTREE_PATH" # after user confirmation
(c) If the same branch is already checked out in another worktree:
[ERROR] Branch {BRANCH_NAME} is already in use by another worktree: {path}
Specify a different branch name: /dev --branch other-name "description"
Normal creation:
git worktree add "$WORKTREE_PATH" -b "$BRANCH_NAME"
Worktree created: {WORKTREE_PATH}
[Phase 3/8] Installing dependencies + implementing...
Install dependencies
cd "$WORKTREE_PATH" && npm install
Rebuild native modules (optional)
cd "$WORKTREE_PATH" && npm run rebuild-pty
Note: rebuild-pty requires the ELECTRON_VERSION environment variable. Failure when it is not set is expected. Unit tests (npm test) and builds (npm run build) work without native modules, so on failure only print the warning below and continue with implementation:
[WARN] rebuild-pty failed (ELECTRON_VERSION not set). No impact on unit tests/builds.
Implement based on the feature description
$WORKTREE_PATH using absolute paths for browsing/editingCLAUDE.md structure sectionREADME.md, README.ko.md (if applicable)[Phase 4/8] Running tests + build verification... (attempt {N}/3)
Run from the worktree directory:
cd "$WORKTREE_PATH" && npm test && npm run build
Retry rules on failure:
npm test && npm run build fails[Phase 4/8] Verification failed. Fixing and retrying... (attempt {N}/3)
[FAIL] Verification failed (exceeded 3 attempts)
Path: {WORKTREE_PATH}
Branch: {BRANCH_NAME}
Last error: {error summary}
You can continue working manually in the worktree, or
clean up with /dev --abort {BRANCH_NAME}
Do not proceed to Phase 5 or beyond in this case.After automated verification passes — determine if real plugin testing is needed:
Check the changed file paths from git diff --name-only. If any file matching the patterns below is included, ask the user to run a real plugin test:
| Pattern | Reason |
|---------|--------|
| src/obsidian/main.ts | Plugin lifecycle |
| src/obsidian/settings.ts | Settings tab UI |
| src/obsidian/terminal/** | Terminal rendering/PTY |
| src/mcp/server.ts, src/mcp/tools.ts | MCP server runtime |
| src/obsidian/dashboard/** | Dashboard UI |
| skills/** | Skill prompts (Claude Code behavior) |
| rules/** | Rule prompts |
| styles.css | UI styles |
If such files exist:
npm run deploy -- --refresh-skills <vault-path>/update-plugin <vault-path> skill[Phase 4/8] Automated tests passed. Runtime-relevant changes detected.
Changed files:
- {list of runtime-related files}
Deployed to vault. Please reload the plugin in Obsidian and verify the feature directly.
Confirm when done.
→ Use AskUserQuestion to present "Testing complete / Issue found" choices and wait for the user's response.
If no runtime-related files are changed (pure logic/test/docs changes only): automatically proceed to Phase 5.
[Phase 5/8] Committing changes...
After verification passes:
✨ feat: new feature🐛 fix: bug fix♻️ refactor: refactoring✅ test: tests📝 docs: documentation[Phase 6/8] Verifying before merge...
Check the state of BASE_BRANCH before merging:
# 1. Verify BASE_BRANCH is still the current branch
CURRENT=$(git -C "$PROJECT_ROOT" branch --show-current)
# Abort if CURRENT != BASE_BRANCH (preserve worktree)
# 2. Verify BASE_BRANCH is clean
git -C "$PROJECT_ROOT" status --porcelain
# Abort if there are uncommitted changes (preserve worktree)
# 3. Check remote sync status
git -C "$PROJECT_ROOT" fetch origin "$BASE_BRANCH" 2>/dev/null
git -C "$PROJECT_ROOT" status -sb
If there are new commits from remote (behind N):
[WARN] {BASE_BRANCH} is {N} commit(s) behind the remote.
Pull first? (Pull then merge / Merge as-is / Abort)
→ Use AskUserQuestion to present the choices and wait for the user's response. Do not proceed to merge until a response is received.
All checks pass:
[OK] Pre-merge verification passed. BASE_BRANCH: {BASE_BRANCH} (clean, up-to-date)
[Phase 7/8] Merging {BRANCH_NAME} → {BASE_BRANCH}...
# Merge (fast-forward preferred; merge commit if not possible)
git -C "$PROJECT_ROOT" merge "$BRANCH_NAME"
On merge conflict — auto-resolution scope:
package-lock.json, *.lock, binary files, or cases where both sides changed the same line differently[FAIL] Could not automatically resolve merge conflict.
Conflict files: {list}
Worktree ({WORKTREE_PATH}) is preserved.
Resolve the conflicts manually and complete the merge.
Post-merge verification after successful merge:
cd "$PROJECT_ROOT" && npm test && npm run build
[WARN] Post-merge verification failed. Fixing and retrying... (attempt {N}/3)
[FAIL] Post-merge verification failed (exceeded 3 attempts)
Merge to {BASE_BRANCH} is complete, but tests/builds are failing.
Recovery options:
1. Fix manually and commit
2. Revert the merge: git revert -m 1 HEAD
3. Undo the merge (caution: also removes subsequent commits): git reset --hard HEAD~1
Worktree ({WORKTREE_PATH}) is preserved.
Do not proceed to Phase 8 in this case.[Phase 8/8] Cleaning up worktree + branch...
Automatic cleanup after all verifications pass:
# Remove the worktree (--force needed due to untracked files like node_modules)
git worktree remove --force "$WORKTREE_PATH"
# Attempt safe delete
git branch -d "$BRANCH_NAME"
If git branch -d fails (not fully merged):
[WARN] Branch {BRANCH_NAME} was flagged as not fully merged.
Force delete? (Delete / Keep)
→ Use AskUserQuestion to present the choices and wait for the user's response.
Force delete with -D or keep the branch based on user confirmation.
Completion message:
[DONE] Work complete!
{BRANCH_NAME} → {BASE_BRANCH} merged
Commit: {commit hash} {commit message}
Changed files: {N}
Tests: passed
Build: passed
Worktree + branch cleaned up
| Situation | Response | Worktree |
|-----------|----------|----------|
| Existing worktree at path | Ask to reuse or delete and recreate | Preserved |
| Stale directory at path | Run git worktree prune then clean up | Recreated after cleanup |
| Same branch checked out in another worktree | Guide to different name and abort | — |
| npm install fails | Print error log and abort | Preserved |
| rebuild-pty fails | Expected failure. Print warning, continue | Preserved |
| Test/build fails (>3 attempts) | Report status and abort | Preserved |
| Pre-commit hook fails | Fix hook error and attempt new commit | Preserved |
| Pre-merge: branch changed | Explain situation and abort | Preserved |
| Pre-merge: new commits on remote | Ask pull / continue / abort | Preserved |
| Merge conflict (auto-resolve fails) | Guide user and abort | Preserved |
| Post-merge test fails (>3 attempts) | Provide 3 recovery options and abort | Preserved |
| branch -d fails | Confirm with user then -D or keep | Removed |
Principle: Do not delete the worktree on failure. Preserve it so the user can continue working manually or clean up with --abort.
package.json is located)main branch (project rule: no direct work on main)node_modules is needed inside the worktree, so npm install is run there--abort warns and requests confirmation if there are unmerged commitsresearch
Today I Learned — research a topic, learn interactively, then save as TIL markdown. Use when the user wants to learn about a topic, says 'teach me', 'what is X', 'deep dive into X', or asks to study something and save it as a TIL note.
testing
SRS-based TIL review session (spaced repetition). Use when the user says 'quiz me', 'review what I learned', 'flashcard session', 'test my knowledge', or wants to do spaced repetition review of their TIL notes.
tools
Install or update the Oh My TIL plugin in an Obsidian vault
documentation
Save learning content as a TIL file and batch-update Daily notes, MOC, and backlog. Use when the user says 'save this', 'write up what I learned', 'document this as a TIL', or wants to persist a learning conversation as a note.