src/skills/incubate/SKILL.md
Clone or create repos for active development — the right hand of /learn. Workflow modes — default (long-term dev), --flash (issue → PR → offload), --contribute (fork + multi-PR). Use when user says "incubate [repo]", "work on [repo]", "clone for dev", or wants to set up a dev workflow. Do NOT trigger for study/exploration (use /learn), finding projects (use /trace), or session mining (use /dig).
npx skillsauth add Soul-Brews-Studio/oracle-skills-cli incubateInstall 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.
Clone or create repos for active development → set up branches, make changes, push PRs.
"/learn reads the book. /incubate writes the next chapter."
/incubate [url] # Clone via ghq, symlink, ready for dev
/incubate [slug] # Use slug from ψ/memory/slugs.yaml
/incubate [repo-name] # Finds in ghq or creates with default org
/incubate [url] --flash "fix desc" # Issue → branch → fix → PR → offload
/incubate [url] --contribute # Fork if needed → branch per feature → PRs
/incubate --status # List all active ψ/incubate/ with git status
/incubate --status --include-offloaded # Also list offloaded entries from .origins (#280)
/incubate --offload [slug] # Remove symlink, keep ghq clone
/incubate --offload [slug] --purge # Also drop entry from .origins manifest (#280)
/incubate --init # Restore all origins after git clone
| Flag | Scope | Duration | Cleanup |
|------|-------|----------|---------|
| (default) | Long-term dev | Weeks/months | Manual offload |
| --flash | Single fix | Minutes | Issue → PR → auto-offload + purge |
| --contribute | Multi-feature | Days/weeks | Offload when all PRs done |
| --status | Query | — | Read-only listing |
| --offload | Cleanup | — | Remove symlink (keep ghq) |
incubate → Long-term dev (manual cleanup)
↓
--contribute → Push → offload (keep ghq)
↓
--flash → Issue → Branch → PR → offload → purge (complete cycle)
ψ/incubate/
├── .origins # Manifest of incubated repos (committed)
└── OWNER/
└── REPO/
├── origin # Symlink to ghq source (gitignored)
└── REPO.md # Hub file — tracks incubation sessions (committed)
Offload source, keep hub:
unlink ψ/incubate/OWNER/REPO/origin # Remove symlink
# ghq clone preserved for future use
# Hub file (REPO.md) remains in ψ/incubate/OWNER/REPO/
Restore all origins after cloning (like git submodule init):
ROOT="$(pwd)"
while read repo; do
OWNER=$(dirname "$repo")
REPO=$(basename "$repo")
ghq get -u "https://github.com/$repo"
mkdir -p "$ROOT/ψ/incubate/$OWNER/$REPO"
ln -sf "$(ghq root)/github.com/$repo" "$ROOT/ψ/incubate/$OWNER/$REPO/origin"
echo "✓ Restored: $repo"
done < "$ROOT/ψ/incubate/.origins"
CRITICAL: Capture ABSOLUTE paths first:
date "+🕐 %H:%M %Z (%A %d %B %Y)" && ROOT="$(pwd)"
echo "Incubating from: $ROOT"
Clone or create, symlink origin, update manifest:
# Replace [URL] with actual URL
URL="[URL]"
ROOT="$(pwd)"
OWNER=$(echo "$URL" | sed -E 's|.*github.com/([^/]+)/.*|\1|')
REPO=$(echo "$URL" | sed -E 's|.*/([^/]+)(\.git)?$|\1|')
SLUG="$OWNER/$REPO"
# Auto-stash unstaged changes in source clone before pulling (#279).
# `ghq get -u` runs `git pull` under the hood and aborts on dirty trees,
# stranding the ritual. Detect + stash with a clear log + restore hint.
GHQ_ROOT_PRECHECK=$(ghq root 2>/dev/null)
SOURCE_PRECHECK="$GHQ_ROOT_PRECHECK/github.com/$SLUG"
if [ -d "$SOURCE_PRECHECK/.git" ]; then
if [ -n "$(git -C "$SOURCE_PRECHECK" status --porcelain 2>/dev/null)" ]; then
STASH_NAME="pre-incubate-$(date +%Y-%m-%d)"
echo "⚠️ Source clone has uncommitted changes — auto-stashing as '$STASH_NAME'"
git -C "$SOURCE_PRECHECK" stash push -u -m "$STASH_NAME"
echo " (run \`git -C $SOURCE_PRECHECK stash pop\` to restore)"
fi
fi
# Check if repo exists on GitHub
if gh repo view "$SLUG" --json name &>/dev/null; then
ghq get -u "https://github.com/$SLUG"
else
echo "Repo not found — creating private repo..."
gh repo create "$SLUG" --private --clone=false
ghq get "https://github.com/$SLUG"
GHQ_ROOT=$(ghq root)
LOCAL="$GHQ_ROOT/github.com/$SLUG"
if [ ! -f "$LOCAL/README.md" ]; then
echo "# $REPO" > "$LOCAL/README.md"
git -C "$LOCAL" add README.md
git -C "$LOCAL" commit -m "Initial commit"
git -C "$LOCAL" push origin main 2>/dev/null || git -C "$LOCAL" push origin master
fi
fi
GHQ_ROOT=$(ghq root)
mkdir -p "$ROOT/ψ/incubate/$OWNER/$REPO"
ln -sf "$GHQ_ROOT/github.com/$OWNER/$REPO" "$ROOT/ψ/incubate/$OWNER/$REPO/origin"
# Auto-add gitignore pattern if missing (#250)
GITIGNORE="$ROOT/.gitignore"
if [ -f "$GITIGNORE" ]; then
if ! grep -q 'ψ/incubate/\*\*/origin' "$GITIGNORE" 2>/dev/null; then
echo 'ψ/incubate/**/origin' >> "$GITIGNORE"
echo "✓ Added ψ/incubate/**/origin to .gitignore"
fi
else
# Also check ψ/.gitignore as fallback
PSI_GITIGNORE="$ROOT/ψ/.gitignore"
if [ -f "$PSI_GITIGNORE" ] && ! grep -q 'incubate/\*\*/origin' "$PSI_GITIGNORE" 2>/dev/null; then
echo 'incubate/**/origin' >> "$PSI_GITIGNORE"
echo "✓ Added incubate/**/origin to ψ/.gitignore"
fi
fi
# Update manifest
echo "$OWNER/$REPO" >> "$ROOT/ψ/incubate/.origins"
sort -u -o "$ROOT/ψ/incubate/.origins" "$ROOT/ψ/incubate/.origins"
echo "✓ Ready: $ROOT/ψ/incubate/$OWNER/$REPO/origin → source"
After clone/symlink, write .claude/INCUBATED_BY in the target repo (not the oracle repo):
TARGET_REPO="$GHQ_ROOT/github.com/$OWNER/$REPO"
mkdir -p "$TARGET_REPO/.claude"
# Check if this repo was previously /learn'd
LEARNED_FROM=""
if [ -d "$ROOT/ψ/learn/$OWNER/$REPO" ]; then
LEARNED_FROM="learned-from: ψ/learn/$OWNER/$REPO/"
fi
cat > "$TARGET_REPO/.claude/INCUBATED_BY" << BREADCRUMB
oracle: $(basename "$ROOT")
oracle-repo: $(git -C "$ROOT" remote get-url origin 2>/dev/null || echo "local")
date: $(date +%Y-%m-%d)
mode: ${MODE:-default}
source: https://github.com/$OWNER/$REPO
${LEARNED_FROM}
BREADCRUMB
echo "✓ Breadcrumb dropped: $TARGET_REPO/.claude/INCUBATED_BY"
The breadcrumb enables:
learned-from links /learn → /incubate (#232)Try ghq first, then create with default org:
NAME="[NAME]"
ROOT="$(pwd)"
DEFAULT_ORG="laris-co" # Configurable via --org flag
MATCH=$(ghq list | grep -i "/$NAME$" | head -1)
if [ -n "$MATCH" ]; then
OWNER=$(echo "$MATCH" | cut -d'/' -f2)
REPO=$(echo "$MATCH" | cut -d'/' -f3)
else
OWNER="$DEFAULT_ORG"
REPO="$NAME"
fi
# Then proceed with URL flow using OWNER/REPO
ls -la "$ROOT/ψ/incubate/$OWNER/$REPO/"
Check arguments for workflow flags:
| Argument | Mode | Action |
|----------|------|--------|
| (none) | Default | Clone + symlink + show status |
| --flash | Flash | Issue → branch → fix → PR → offload |
| --contribute | Contribute | Fork if needed → multi-feature PRs |
| --status | Status | List all incubations (skip clone) |
| --offload | Offload | Remove symlink (skip clone) |
Calculate ACTUAL paths (replace variables with real values):
REPO_DIR = [ROOT]/ψ/incubate/[OWNER]/[REPO]/
SOURCE_DIR = [ROOT]/ψ/incubate/[OWNER]/[REPO]/origin/ ← symlink to ghq
WORK_DIR = [GHQ_ROOT]/github.com/[OWNER]/[REPO]/ ← actual working directory
⚠️ IMPORTANT: Always use literal paths. Never pass shell variables to subagents.
After Step 0 (clone + symlink), the repo is ready for development.
Verify working state:
WORK_DIR="$ROOT/ψ/incubate/$OWNER/$REPO/origin"
echo "Branch: $(git -C "$WORK_DIR" branch --show-current)"
echo "Status: $(git -C "$WORK_DIR" status --short | wc -l) changed files"
echo "Remote: $(git -C "$WORK_DIR" remote get-url origin)"
echo "Last commit: $(git -C "$WORK_DIR" log --oneline -1)"
Skip to Step 2 (create/update hub file).
Complete contribution cycle: Issue → Branch → Fix → PR → Offload.
WORK_DIR="$ROOT/ψ/incubate/$OWNER/$REPO/origin"
# Compose issue title and description from user's intent
ISSUE_URL=$(gh issue create --repo "$OWNER/$REPO" --title "[TITLE]" --body "[DESCRIPTION]")
ISSUE_NUM=$(echo "$ISSUE_URL" | grep -oP '\d+$')
echo "Created: #$ISSUE_NUM"
BRANCH="issue-${ISSUE_NUM}-[short-description]"
git -C "$WORK_DIR" checkout -b "$BRANCH"
echo "Branch: $BRANCH"
Let the user describe what to fix. Make changes, then:
git -C "$WORK_DIR" add -A
git -C "$WORK_DIR" commit -m "[commit message]
Closes #$ISSUE_NUM"
git -C "$WORK_DIR" push -u origin "$BRANCH"
PR_URL=$(gh pr create --repo "$OWNER/$REPO" \
--title "[PR title]" \
--body "$(cat <<'EOF'
## Summary
[what was fixed]
Closes #$ISSUE_NUM
---
**From**: [Oracle Name]
Rule 6: "Oracle Never Pretends to Be Human"
Written by an Oracle — AI speaking as itself.
EOF
)" --head "$BRANCH")
PR_NUM=$(echo "$PR_URL" | grep -oP '\d+$')
echo "PR: #$PR_NUM (closes #$ISSUE_NUM)"
cd "$ROOT"
unlink "$ROOT/ψ/incubate/$OWNER/$REPO/origin"
rmdir "$ROOT/ψ/incubate/$OWNER" 2>/dev/null
rm -rf "$(ghq root)/github.com/$OWNER/$REPO"
echo "✓ Issue #$ISSUE_NUM → PR #$PR_NUM → Offloaded & Purged"
Update hub file before offload (Step 2), then offload.
For extended contribution over days/weeks. Forks if needed.
WORK_DIR="$ROOT/ψ/incubate/$OWNER/$REPO/origin"
ME=$(gh api user --jq '.login')
if ! gh repo view "$OWNER/$REPO" --json viewerPermission --jq '.viewerPermission' | grep -qE 'ADMIN|MAINTAIN|WRITE'; then
echo "No push access — forking..."
gh repo fork "$OWNER/$REPO" --clone=false
git -C "$WORK_DIR" remote add fork "https://github.com/$ME/$REPO.git"
echo "Fork remote added. Push to 'fork' instead of 'origin'."
fi
BRANCH="feat/[feature-name]"
git -C "$WORK_DIR" checkout -b "$BRANCH"
# ... make changes ...
git -C "$WORK_DIR" add -A
git -C "$WORK_DIR" commit -m "[commit message]"
REMOTE=$(git -C "$WORK_DIR" remote | grep fork || echo origin)
git -C "$WORK_DIR" push -u "$REMOTE" "$BRANCH"
gh pr create --repo "$OWNER/$REPO" \
--title "[PR title]" \
--body "[description]" \
--head "$ME:$BRANCH"
unlink "$ROOT/ψ/incubate/$OWNER/$REPO/origin"
rmdir "$ROOT/ψ/incubate/$OWNER" 2>/dev/null
echo "✓ Offloaded (ghq kept for PR feedback)"
No clone needed. List all active incubations with git status.
Add --include-offloaded to also list entries in .origins whose symlinks
have been removed (#280) — surfaces the historical record without losing it.
ROOT="$(pwd)"
INCLUDE_OFFLOADED="${1:-}" # pass "--include-offloaded" to enable
echo "🌱 Active Incubations"
echo ""
# Collect active slugs (those with live symlinks)
declare -A ACTIVE_SLUGS=()
for link in $(find "$ROOT/ψ/incubate" -name "origin" -type l 2>/dev/null); do
REPO_DIR=$(dirname "$link")
SLUG=$(echo "$REPO_DIR" | sed "s|$ROOT/ψ/incubate/||")
ACTIVE_SLUGS["$SLUG"]=1
TARGET=$(readlink "$link")
if [ -d "$TARGET" ]; then
BRANCH=$(git -C "$TARGET" branch --show-current 2>/dev/null)
CHANGES=$(git -C "$TARGET" status --short 2>/dev/null | wc -l)
echo " $SLUG"
echo " Branch: $BRANCH | Changes: $CHANGES"
echo " Path: $TARGET"
else
echo " $SLUG (broken symlink → $TARGET)"
fi
echo ""
done
ACTIVE_COUNT=${#ACTIVE_SLUGS[@]}
# --include-offloaded: also list .origins entries with no live symlink (#280)
if [ "$INCLUDE_OFFLOADED" = "--include-offloaded" ] && [ -f "$ROOT/ψ/incubate/.origins" ]; then
echo ""
echo "📦 Offloaded (in .origins, no live symlink)"
echo ""
OFFLOADED_COUNT=0
while IFS= read -r slug; do
[ -z "$slug" ] && continue
if [ -z "${ACTIVE_SLUGS[$slug]:-}" ]; then
GHQ_ROOT=$(ghq root 2>/dev/null)
GHQ_PATH="$GHQ_ROOT/github.com/$slug"
if [ -d "$GHQ_PATH" ]; then
echo " $slug (ghq preserved at $GHQ_PATH)"
else
echo " $slug (ghq absent — fully purged)"
fi
OFFLOADED_COUNT=$((OFFLOADED_COUNT + 1))
fi
done < "$ROOT/ψ/incubate/.origins"
echo ""
echo "Active: $ACTIVE_COUNT | Offloaded: $OFFLOADED_COUNT"
else
echo "Total: $ACTIVE_COUNT active incubation(s)"
if [ -f "$ROOT/ψ/incubate/.origins" ]; then
TOTAL_RECORDED=$(grep -cv '^$' "$ROOT/ψ/incubate/.origins" 2>/dev/null || echo 0)
OFFLOADED_HIDDEN=$((TOTAL_RECORDED - ACTIVE_COUNT))
if [ "$OFFLOADED_HIDDEN" -gt 0 ]; then
echo " ($OFFLOADED_HIDDEN offloaded — use --include-offloaded to view)"
fi
fi
fi
Done. No hub file update needed.
Remove symlink, keep ghq clone and hub file.
Add --purge to also remove the entry from .origins manifest (#280) —
useful when you want the offloaded slug to NOT count toward "Total" any more.
ROOT="$(pwd)"
SLUG="[OWNER/REPO or REPO]"
PURGE="${1:-}" # pass "--purge" to also remove from .origins
# Find the symlink
LINK=$(find "$ROOT/ψ/incubate" -name "origin" -type l | xargs -I{} dirname {} | grep -i "$SLUG" | head -1)
if [ -z "$LINK" ]; then
echo "Not found: $SLUG"
echo "Active incubations:"
find "$ROOT/ψ/incubate" -name "origin" -type l | xargs -I{} dirname {} | sed "s|$ROOT/ψ/incubate/||"
exit 1
fi
REPO_NAME=$(basename "$LINK")
unlink "$LINK/origin"
OWNER_DIR=$(dirname "$LINK")
rmdir "$OWNER_DIR" 2>/dev/null
DEFLATED_SLUG=$(echo $LINK | sed "s|$ROOT/ψ/incubate/||")
echo "✓ Offloaded: $DEFLATED_SLUG"
echo " Hub file remains: $LINK/$REPO_NAME.md"
echo " ghq clone preserved for future use"
# --purge: remove from .origins manifest (#280)
if [ "$PURGE" = "--purge" ] && [ -f "$ROOT/ψ/incubate/.origins" ]; then
TMPFILE=$(mktemp)
grep -v "^${DEFLATED_SLUG}$" "$ROOT/ψ/incubate/.origins" > "$TMPFILE" || true
mv "$TMPFILE" "$ROOT/ψ/incubate/.origins"
echo " ✂ Purged '$DEFLATED_SLUG' from .origins manifest"
echo " ⚠ This breadcrumb is gone — re-incubate to restore it (Principle 1: prefer --include-offloaded over --purge)"
fi
After any mode except --status, create or update the hub file:
# [REPO] Incubation Log
## Source
- **Origin**: ./origin/
- **GitHub**: https://github.com/OWNER/REPO
## Sessions
### [TODAY] — [mode]
- **Branch**: [branch-name]
- **Status**: active | offloaded | flash-completed
- **Changes**: [summary of what was done]
- **PRs**: #N, #M (if any)
Append new sessions. Never overwrite existing entries (Nothing is Deleted).
announce-mode → bash substitutes $ROOT/$OWNER/$REPO/$WORK_DIR to absolute paths; never print "Location: ψ/..." literally. See CONVENTIONS.md.
echo "🌱 Incubating: $REPO"
echo ""
echo " Mode: default (long-term dev)"
echo " Location: $ROOT/ψ/incubate/$OWNER/$REPO/"
echo " Working: $WORK_DIR"
echo " Branch: $(git -C "$WORK_DIR" branch --show-current)"
echo " Remote: $(git -C "$WORK_DIR" remote get-url origin)"
echo " Status: $(git -C "$WORK_DIR" status --short | wc -l) changed files"
echo ""
echo " Next: make changes, commit, push, create PR"
echo " Done: /incubate --offload $OWNER/$REPO"
⚡ Flash Complete: [REPO]
Issue: #N created
Branch: issue-N-description
PR: #M (closes #N)
Result: Offloaded & Purged
✓ Issue #N → PR #M → Done
announce-mode → bash substitutes; never print "Location: ψ/..." literally.
echo "🤝 Contributing: $REPO"
echo ""
echo " Location: $ROOT/ψ/incubate/$OWNER/$REPO/"
echo " Fork: ${FORK_URL:-[none]}"
echo " Branches: ${BRANCHES:-[list]}"
echo " PRs: ${PRS:-[list]}"
echo ""
echo " Next: continue working, or /incubate --offload when done"
The actual emission lives in the bash block under Mode: --status above —
echo " Path: $TARGET" resolves $TARGET via readlink, so paths are
absolute. Example rendering:
🌱 Active Incubations
OWNER/REPO
Branch: feat/x | Changes: 3
Path: /Users/nat/ghq/github.com/OWNER/REPO
Total: N active incubation(s)
The pattern is auto-added to .gitignore on first /incubate run (#250). If you need to add it manually:
# Ignore origin symlinks only (source lives in ghq)
# Note: no trailing slash — origin is a symlink, not a directory
ψ/incubate/**/origin
After incubation work, log to Oracle so it's discoverable via /trace:
Write to ψ/memory/learnings/YYYY-MM-DD_incubate-<slug>.md with frontmatter:
---
pattern: "Incubated [REPO]: [what was done — PR#, branch, outcome]"
date: <today>
source: incubate: OWNER/REPO
concepts: ["incubate", "development", <relevant-tags>]
---
# Incubated [REPO]
<body: what was done, PR#, branch, outcome>
The Oracle's auto-memory layer picks up new files in ψ/memory/learnings/ automatically — no separate API call needed.
This connects /incubate to the shared knowledge layer.
| Wrong | Right |
|-------|-------|
| git clone directly to ψ/ | ghq get then symlink |
| Flat: ψ/incubate/repo-name | Org structure: ψ/incubate/owner/repo |
| Copy files | Symlink always |
| Manual clone outside ghq | Everything through ghq |
| Delete ghq clone after work | Offload symlink only (Nothing is Deleted) |
--flash: complete cycle (issue → branch → PR → offload + purge) for quick fixes--contribute: fork-aware multi-feature workflow for external repos--status: query all active incubations without cloning--offload: remove symlink, keep ghq and hub fileorigin/ symlink structure allows easy offload without losing ghq clone.origins manifest enables --init restore after fresh git clone/learn: learn = LEFT hand (study), incubate = RIGHT hand (work)ARGUMENTS: $ARGUMENTS
testing
Cut a beta pre-release — bump CalVer with --beta, PR to beta branch, CI auto-tags + publishes to npm @beta. Use when user says 'release beta', 'cut beta', '/release-beta', or wants to publish a beta version for pre-release testing.
testing
Cut an alpha pre-release — bump CalVer, PR to alpha branch, CI auto-tags + publishes to npm @alpha. Use when user says 'release alpha', 'cut alpha', '/release-alpha', or wants to publish an alpha version.
tools
Talk to another oracle via maw federation. Uses fleet machine names (white, mba, clinic-nat, oracle-world, phaith). Auto-signs with current oracle's [host:handle] from CLAUDE.md. Global — works from any oracle repo.
development
Log information for future reference. Use when user says "fyi", "remember this", "note that", "for your info".