project-add
Skill0 starsChanged 4 months agoMITView on GitHub
Add or clone a project into the multi-project setup. Use with /project-add.
- Reads credentials
In this repository42 other files it gives its agents.
- .claude/CLAUDE.mdCLAUDE.md
- content-rewriteSkill
- content-writeSkill
- core-auditSkill
- core-bootstrapSkill
- core-commitSkill
- core-explainSkill
- core-finalizeSkill
- core-orchestrateSkill
- core-pullSkill
- core-setupSkill
- core-updateSkill
- design-convertSkill
- design-shipSkill
- design-tokensSkill
- dev-inspectSkill
- dev-learnSkill
- dev-manualSkill
- dev-optimizeSkill
- dev-securitySkill
- dev-shipSkill
- dev-tweakSkill
- game-debugSkill
- game-optimizeSkill
- game-shipSkill
- game-tweakSkill
- marketing-contentSkill
- marketing-researchSkill
- marketing-screenshotsSkill
- project-appSkill
- project-memorySkill
- project-planSkill
- project-removeSkill
- project-researchSkill
- project-seedSkill
- project-syncSkill
- project-todoSkill
- project-tunnelSkill
- team-issuesSkill
- team-outsourceSkill
- team-reviewSkill
- team-verifySkill
The file
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 2 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 43
Use the detected platform to resolve {projects_root} and {config_repo} from paths.yaml (see Configuration section below).
- Very specific: line 92
If GH_AVAILABLE=false: show only "Create new project" (Clone requires gh).
- Distinctive: line 124
No spaces or special characters
- Very specific: line 125
Not existing in {projects_root}
- Very specific: line 178
Check that {projects_root}/[name] does not already exist
- Very specific: line 335
If .gitignore does not exist, create it with the above entries.
- Very specific: line 391
Write a setup marker so a later /core-setup run starts in the right mode.
- Very specific: line 418
If GH_AVAILABLE=false: skip this phase.
- Very specific: line 446
Read user input → store as REPO_DESC (can be empty).
- Distinctive: line 448
Create GitHub repo and push:
- Very specific: line 470
Check with gh auth status before starting
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Project Add
Adds a project — create a new project or clone an existing GitHub repo — with symlinks (macOS) or junctions (Windows) to the shared claude-config.
Trigger
/project-add [name] or /project-add
Process
PHASE 0: Pre-flight Checks
Detect platform:
# Detect OS
case "$(uname -s)" in
Darwin) PLATFORM="macos" ;;
Linux) PLATFORM="linux" ;;
MINGW*|CYGWIN*|MSYS*) PLATFORM="windows" ;;
*) echo "Unsupported platform: $(uname -s)" >&2; exit 1 ;;
esacUse the detected platform to resolve {projects_root} and {config_repo} from paths.yaml (see Configuration section below).
Before anything is created, validate:
# Fallback: if config_repo is missing but ~/.claude is already linked to a
# real claude-config, adopt that location instead of aborting (handles
# non-standard install locations).
if [ ! -d "$CONFIG_REPO" ] && [ -L "$HOME/.claude/skills" ]; then
CONFIG_REPO="$(dirname "$(readlink "$HOME/.claude/skills")")"
echo "config_repo not at default — resolved via ~/.claude/skills → $CONFIG_REPO"
fi
# Check claude-config exists and is complete
test -d "{config_repo}"
test -d "{config_repo}/scripts"
# Check gh CLI authenticated (needed for clone mode and publish)
gh auth statusIf config check fails:
❌ claude-config not found or incomplete
Expected: {config_repo}
With folders: agents/, skills/, scripts/
Solution:
1. Clone claude-config repo to {config_repo}
2. Or set path via CLAUDE_CONFIG_REPO environment variable→ Stop command, do NOT create any folders
If gh auth fails:
→ Store: GH_AVAILABLE=false. Show: gh not available — clone mode and GitHub publish skipped.
If checks pass: → Continue to PHASE 1
PHASE 1: Mode Selection
If name provided via /project-add [name]:
→ Assume: new project mode. Validate the name immediately (same rules as PHASE 2 (new): lowercase letters/digits/hyphens, no spaces or special characters, not existing in {projects_root}). On validation error: show the error and stop. If valid: store name and go to PHASE 3 (skip PHASE 2 (new) name question).
If no name provided:
If GH_AVAILABLE=false: show only "Create new project" (Clone requires gh).
question: "What do you want to do?"
header: "Mode"
options:
- label: "Create new project"
description: "Create an empty project with claude-config symlinks"
- label: "Clone existing repo" # only show if GH_AVAILABLE=true
description: "Clone a GitHub repo and configure claude-config symlinks"
multiSelect: false→ New project: go to PHASE 2 (new) → Clone: go to PHASE 2 (clone)
PHASE 2 (new): Project Name
Ask name:
question: "What is the name of the new project?"
header: "Project"
options:
- label: "Type a name"
description: "Short, lowercase name without spaces (e.g. my-app)"
multiSelect: falseValidation:
- Lowercase letters, digits, hyphens
- No spaces or special characters
- Not existing in
{projects_root}
→ Go to PHASE 3
PHASE 2 (clone): Repo Selection
Two sub-options:
question: "How do you want to select the repo?"
header: "Repo"
options:
- label: "Browse my repos (Recommended)"
description: "Show list of your GitHub repos"
- label: "Enter manually"
description: "Type owner/repo or full GitHub URL"
multiSelect: falseBrowse mode:
gh repo list --limit 30 --json name,description,isPrivate,url --jq '.[] | "\(.name)\t\(.description // "-")\t\(if .isPrivate then "🔒" else "🌐" end)\t\(.url)"'Show as numbered list in plain text:
Available repos:
1. my-app — My cool app 🔒
2. website — Personal site 🌐
3. api-backend — REST API service 🔒
...
M. Load more
Q. Enter manually
Which repo? (number)- User chooses number → select that repo
- M → load next 30 (
--limit 30with offset) - Q → switch to manual entry
Manual mode:
User types owner/repo or full GitHub URL (e.g. https://github.com/owner/repo).
Parse to owner/repo format.
After repo selection:
- Extract project name from repo name
- Check that
{projects_root}/[name]does not already exist - Clone:
gh repo clone <owner/repo> {projects_root}/[name]→ Go to PHASE 3
PHASE 3: Setup Directories
Create project subdirectories (mkdir -p is safe for both modes):
mkdir -p {projects_root}/[name]/.claude/docs
mkdir -p {projects_root}/[name]/.claude/research
mkdir -p {projects_root}/[name]/.project/session
mkdir -p {projects_root}/[name]/.project/plans
mkdir -p {projects_root}/[name]/.project/featuresNew mode: creates everything from scratch.
Clone mode: project root already exists, only creates .claude/ and .project/ subdirs.
PHASE 4: Base Files
New mode:
Copy templates:
Write initial project files:
macOS / Linux:
cat > "{projects_root}/[name]/.project/project.json" << 'ENDJSON'
{
"schemaVersion": 2,
"seed": { "name": "[name]", "pitch": "", "content": "" },
"localUrl": "",
"theme": {
"colors": { "main": [], "accent": [], "semantic": [] },
"typography": { "families": { "heading": "", "body": "", "mono": "" }, "sizes": [] },
"spacing": { "base": "", "scale": [] },
"breakpoints": [],
"borderRadius": [],
"shadows": [],
"modes": {},
"cssVars": ""
},
"stack": { "framework": "", "language": "", "styling": "", "db": "", "auth": "", "hosting": "", "packages": [] },
"data": { "entities": [] },
"endpoints": [],
"team": { "mode": "solo" },
"thinking": []
}
ENDJSON
cat > "{projects_root}/[name]/.project/project-context.json" << 'ENDJSON'
{
"schemaVersion": 2,
"architecture": { "routes": [], "components": [], "endpoints": [], "entities": [], "diagram": "", "dataFlow": "" },
"context": { "structure": "", "routing": [], "patterns": [] },
"learnings": []
}
ENDJSONWindows (PowerShell):
$projectJson = '{
"schemaVersion": 2,
"seed": { "name": "[name]", "pitch": "", "content": "" },
"localUrl": "",
"theme": {
"colors": { "main": [], "accent": [], "semantic": [] },
"typography": { "families": { "heading": "", "body": "", "mono": "" }, "sizes": [] },
"spacing": { "base": "", "scale": [] },
"breakpoints": [], "borderRadius": [], "shadows": [], "modes": {}, "cssVars": ""
},
"stack": { "framework": "", "language": "", "styling": "", "db": "", "auth": "", "hosting": "", "packages": [] },
"data": { "entities": [] },
"endpoints": [], "team": { "mode": "solo" }, "thinking": []
}'
Set-Content -Path "{projects_root}\[name]\.project\project.json" -Value $projectJson -Encoding UTF8
$ctxJson = '{
"schemaVersion": 2,
"architecture": { "routes": [], "components": [], "endpoints": [], "entities": [], "diagram": "", "dataFlow": "" },
"context": { "structure": "", "routing": [], "patterns": [] },
"learnings": []
}'
Set-Content -Path "{projects_root}\[name]\.project\project-context.json" -Value $ctxJson -Encoding UTF8Replace [name] literally with the actual project name in both files.
# settings.local.json with default permissions
echo '{"permissions": {"allow": []}}' > {projects_root}/[name]/.claude/settings.local.json.gitignore with standard content:
# Dependencies
node_modules/
# Build output
dist/
build/
# Environment
.env
.env.local
.env.*.local
# IDE
.idea/
.vscode/
*.swp
# OS
.DS_Store
Thumbs.db
# Claude tooling & local project data — not committed to the project repo
# (managed by the shared claude-config / master repo, not this one).
# Wholesale entries (no trailing slash) so symlinks, real dirs and sub-paths all match.
.claude/
.project/
CLAUDE.md
AGENTS.mdClone mode:
Create settings.local.json:
echo '{"permissions": {"allow": []}}' > {projects_root}/[name]/.claude/settings.local.json.gitignore — append claude-specific entries if not already present:
Check each entry below; append only the ones not already present (a wholesale entry like .claude/ already covers every sub-path, so skip any that are redundant). Use no trailing slash — .claude/agents is a symlink file, and a trailing-slash pattern (.claude/agents/) would only match a directory and silently fail to ignore it:
# Claude tooling & local project data — not committed to the project repo
# (managed by the shared claude-config / master repo, not this one).
.claude/
.project/
CLAUDE.md
AGENTS.mdIf .gitignore does not exist, create it with the above entries.
PHASE 5: Config Symlinks
Link the shared claude-config into the project so skills/agents/hooks/scripts resolve at runtime. These four links are gitignored (PHASE 4) — per-device pointers, not tracked content. Runs for both new and clone mode.
macOS / Linux:
for d in agents hooks skills scripts; do
test -d "{config_repo}/$d" || { echo "WARN: {config_repo}/$d missing — skipping"; continue; }
ln -sfn "{config_repo}/$d" "{projects_root}/[name]/.claude/$d"
done
# Verify each link resolves
for d in agents hooks skills scripts; do
test -e "{projects_root}/[name]/.claude/$d" && echo "$d: OK" || echo "$d: BROKEN"
doneWindows (PowerShell — junctions, no admin needed):
foreach ($d in 'agents','hooks','skills','scripts') {
$target = "{config_repo}\$d"
if (!(Test-Path $target)) { Write-Warning "$target missing — skipping"; continue }
$link = "{projects_root}\[name]\.claude\$d"
if (Test-Path $link) { Remove-Item $link -Recurse -Force }
New-Item -ItemType Junction -Path $link -Target $target | Out-Null
}PHASE 6: Git Initialization
New mode:
cd {projects_root}/[name]
git init
git add .gitignoreClone mode:
Git init is skipped (repo is already initialized by gh repo clone). Instead, restore durable .project/ state if this project was synced from another device:
cd {projects_root}/[name]
git ls-remote --heads origin "claude/state*"- A
claude/state*branch matches → followshared/STATE-SYNC.md § 9(Clone restore): discover the branch (§ 2 precedence), add a detached temp worktree at its tip, runstate-files.py restore, write.project/session/state-sync.json, remove the worktree. Script path:{config_repo}/skills/project-sync/scripts/state-files.py. Show:State restored: {N} files from {branch} ({shortsha}). - No match → skip silently (scaffold-only clone, unchanged behavior).
PHASE 7: Project Configuration
Write a setup marker so a later /core-setup run starts in the right mode. Do NOT run or offer to run /core-setup as part of this flow — it belongs in a fresh session, never chained into project-add.
Determine intended core-setup mode:
- New mode →
setup_mode = "greenfield" - Clone mode →
setup_mode = "mature"(cloned repo may already have source code)
Write marker (always — no prompt): set stateRestored to true only when PHASE 6 clone-mode restored state from a claude/state* branch, else false. A later /core-setup --mode=mature reads it: restored learnings/backlog already exist, so the mature scan runs additively (learnings dedup, team.mode skip-if-set) and its "pre-existing learnings" modal defaults to Continue.
mkdir -p .project/session
cat > ".project/session/setup-pending.json" << ENDJSON
{
"source": "project-add",
"mode": "{setup_mode}",
"stateRestored": {state_restored},
"createdAt": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
ENDJSONShow: Setup marker written — a later /core-setup run starts directly in {setup_mode} mode.
PHASE 8: GitHub Publish
New mode:
If GH_AVAILABLE=false: skip this phase. Show: GitHub publish skipped — gh not authenticated. Go to PHASE 9.
question: "Do you want to publish the repo to GitHub?"
header: "Publish"
options:
- label: "Yes, create private repo (Recommended)"
description: "Publish as private GitHub repository"
- label: "Yes, create public repo"
description: "Publish as public GitHub repository"
- label: "No, later"
description: "Skip, publish manually later"
multiSelect: falseIf publish desired:
- Stage all files and create initial commit:
cd {projects_root}/[name]
git add -A
git commit -m "feat: initial commit - [name]"- Ask short description (optional — free text):
Show: Short GitHub description (optional, Enter to skip):
Read user input → store as REPO_DESC (can be empty).
- Create GitHub repo and push:
# Build description argument as bash array (empty = no flag)
if [ -n "$REPO_DESC" ]; then
DESC_FLAG=(--description "$REPO_DESC")
else
DESC_FLAG=()
fi
# Private repo
gh repo create [name] --private --source=. --push "${DESC_FLAG[@]}"
# OR public repo
gh repo create [name] --public --source=. --push "${DESC_FLAG[@]}"- Show repo URL after successful publish
Requirements for publish:
ghCLI installed and authenticated- Check with
gh auth statusbefore starting
Clone mode:
→ Skip (repo is already on GitHub)
Show: GitHub: [repo URL]
PHASE 9: Shell Alias
Ask:
question: "Do you want to create a shell alias to quickly open this project?"
header: "Alias"
options:
- label: "Yes, create alias"
description: "Add alias to ~/.bashrc that runs cd + claude"
- label: "No, skip"
description: "Don't create alias"
multiSelect: falseIf alias desired:
Suggest a short alias based on the project name (first letters, abbreviation, or initials). Let the user confirm or change it.
question: "Which alias do you want to use?"
header: "Alias"
options:
- label: "[suggestion] (Recommended)"
description: "alias [suggestion]='cd {projects_root}/[name] && claude'"
- label: "Different name"
description: "Type your own alias name"
multiSelect: falseValidation:
- Alias must not already exist in the target rc-file
- Lowercase letters only, max 4 characters (short and fast)
Add:
Detect shell and choose rc-file:
case "$SHELL" in
*/zsh) RC_FILE="$HOME/.zshrc" ;;
*/bash) RC_FILE="$HOME/.bashrc" ;;
*/fish) RC_FILE="$HOME/.config/fish/config.fish" ;;
*) RC_FILE="$HOME/.profile" ;;
esac
echo "alias [alias]='cd {projects_root}/[name] && claude'" >> "$RC_FILE"
# Reload the rc-file so the alias is registered (errors suppressed —
# interactive-only rc lines may warn in a non-interactive shell)
source "$RC_FILE" 2>/dev/null || trueNote:
sourceruns in the skill's subprocess, so the alias is not active in the user's current terminal (a separate process). It only takes effect in a new terminal or after the user runssource $RC_FILEthemselves — reflect that in the confirm message.
Confirm:
Alias created: [alias] → cd {projects_root}/[name] && claude
Added to: $RC_FILE
Active in new terminals — for this terminal, run: source $RC_FILEPHASE 10: Wrap Up
Output (new mode):
✅ Project [name] created
Structure:
{projects_root}/[name]/
├── .claude/
│ ├── docs/
│ ├── research/
│ └── CLAUDE.md (or yet to configure)
├── .project/
└── .gitignore
Alias: [alias] → cd {projects_root}/[name] && claude (if created)
GitHub: https://github.com/[user]/[name] (if published)Output (clone mode):
✅ Project [name] cloned and configured
Source: https://github.com/[owner]/[repo]
Structure:
{projects_root}/[name]/
├── .claude/
│ ├── docs/
│ ├── research/
│ └── CLAUDE.md (or yet to configure)
├── .project/
├── .gitignore (updated with claude entries)
└── [existing repo files]
Alias: [alias] → cd {projects_root}/[name] && claude (if created)
GitHub: https://github.com/[owner]/[repo]Configuration
Paths are configurable per device. Defaults are platform-dependent:
| Placeholder | macOS Default | Windows Default | Environment Variable |
{projects_root} | $HOME/projects | C:\Projects | CLAUDE_PROJECTS_ROOT |
{config_repo} | $HOME/claude-config | C:\Projects\claude-config | CLAUDE_CONFIG_REPO |
Resolution order (first match wins):
- Environment variable
.claude/paths.local.yaml(local per project, not in git)paths.yaml(skill root — shared defaults, platform section)
Restrictions
- Supported on macOS/Linux (symlinks) and Windows (junctions)
- Project name must be unique in
{projects_root} - Master config must exist in
{config_repo} - Clone mode requires
ghCLI authenticated - GitHub publish requires
ghCLI authenticated
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

