CtrlK
BlogDocsLog inGet started
Tessl Logo

peteski22/setup-project

Configure Claude Code for this project - detects languages and sets up rules, skills, and validators

49

Quality

62%

Does it follow best practices?

Impact

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

SKILL.md

name:
setup-project
description:
Configure Claude Code for this project - detects languages and sets up rules, skills, and validators
disable-model-invocation:
Yes
allowed-tools:
Bash, Read, Write, Glob

Project Setup

Automatically configure Claude Code for the current project. Supports monorepos with multiple languages in subdirectories.

Step 0: Resolve plugin root

The skill loader provides the base directory in the header: Base directory for this skill: <path>. Derive the plugin root from that:

PLUGIN_ROOT = <base directory>/../../

For example, if the skill base directory is ~/.claude/plugins/cache/pragma/skills/setup-project, then PLUGIN_ROOT is ~/.claude/plugins/cache/pragma.

Verify the plugin root is valid by checking for the plugin manifest:

PLUGIN_ROOT="<base directory>/../.."
[[ -f "$PLUGIN_ROOT/.claude-plugin/plugin.json" ]] && echo "OK" || echo "ERROR: Plugin root invalid - .claude-plugin/plugin.json not found at $PLUGIN_ROOT"
true

Note: Replace <base directory> with the actual path from the skill loader header above. For example, if the header says Base directory for this skill: /home/user/.claude/plugins/cache/pragma/skills/setup-project, then PLUGIN_ROOT="/home/user/.claude/plugins/cache/pragma/skills/setup-project/../..".

If the check fails, stop and show:

Plugin root could not be resolved. The pragma plugin may not be installed correctly.

Reinstall:
  /plugin marketplace add peteski22/agent-pragma
  /plugin install pragma@agent-pragma

STOP if check fails. Do not proceed.

Step 1: Detect project metadata

Get org and repo name from git remote:

git remote get-url origin 2>/dev/null | sed -E 's|.*[:/]([^/]+)/([^/]+)(\.git)?$|\1 \2|'

Store {org} and {repo} for templating.

Step 2: Scan for languages (root and subdirectories)

Check root directory AND immediate subdirectories for language markers.

# Root level
[[ -f go.mod ]] && echo "root:go"
( [[ -f pyproject.toml ]] || [[ -f setup.py ]] ) && echo "root:python"
[[ -f package.json ]] && echo "root:javascript"
[[ -f tsconfig.json ]] && echo "root:typescript"
[[ -f Cargo.toml ]] && echo "root:rust"

# Subdirectories (one level deep)
for dir in */; do
  [[ -f "${dir}go.mod" ]] && echo "${dir%/}:go"
  ( [[ -f "${dir}pyproject.toml" ]] || [[ -f "${dir}setup.py" ]] ) && echo "${dir%/}:python"
  [[ -f "${dir}package.json" ]] && echo "${dir%/}:javascript"
  [[ -f "${dir}tsconfig.json" ]] && echo "${dir%/}:typescript"
  [[ -f "${dir}Cargo.toml" ]] && echo "${dir%/}:rust"
done
true

This produces output like:

  • root:go (single-language project)
  • backend:python, frontend:typescript (monorepo)

Step 3: Check for existing configs

3a: Check for modular rule files

Check for rule files generated by a previous run:

[[ -d .claude/rules ]] && ls .claude/rules/*.md 2>/dev/null | while read -r f; do echo "rules:$f"; done
true

If any exist, read them. If they have <!-- Assembled by /setup-project comment, safe to overwrite. Otherwise, ask before overwriting.

3b: Clean up legacy .claude/CLAUDE.md files

Check for old-style assembled CLAUDE.md files from previous versions of /setup-project:

for f in .claude/CLAUDE.md */.claude/CLAUDE.md; do
  [[ -f "$f" ]] && echo "legacy:$f"
done
true

If any are found, read them. If they contain the <!-- Assembled by /setup-project marker, delete them — the new modular rules in .claude/rules/ replace them. If they do not contain the marker (user-authored), warn the user and ask before removing.

Step 4: Create .claude/rules/ files

Create the directory:

mkdir -p .claude/rules

Generate modular rule files. Each file is standalone with its own header comment.

4a: Universal rules

Write .claude/rules/universal.md with:

  1. Header comment
  2. Content from $PLUGIN_ROOT/claude-md/universal/base.md

Header:

<!-- Assembled by /setup-project from agent-pragma -->
<!-- Org/Repo: {org}/{repo} -->
<!-- Re-run /setup-project to regenerate -->

4b: Local supplements rules

Write .claude/rules/local-supplements.md with content describing how CLAUDE.local.md works:

Header:

<!-- Assembled by /setup-project from agent-pragma -->
<!-- Re-run /setup-project to regenerate -->

Content:

<!-- This file is documentation only. It does not contain executable validation commands. -->
<!-- Validators: skip this file when searching for "Validation Commands" sections. -->

## Local Supplements

`CLAUDE.local.md` at the project root contains per-user, per-project instructions. Claude Code auto-loads it and adds it to `.gitignore`; if you create the file manually, verify it is in your `.gitignore`.

### Validation Command Overrides

Rules from `CLAUDE.local.md` are generally additive, but can override validation commands. Add a "Validation Commands" section to `CLAUDE.local.md` to specify custom lint/test scripts:

```markdown
## Validation Commands

- **Lint:** `./scripts/backend-lint.sh`
- **Test:** `./scripts/backend-test.sh`
```

These override the defaults in the language rules. Precedence (highest → lowest): CLAUDE.local.md > path-scoped rules > universal rules > built-in defaults.

**Common scenarios for overriding validation commands:**

- **Wrapper scripts:** Your project has `./scripts/lint.sh` that runs multiple tools (ruff + mypy + security scans) in sequence
- **Tool versioning:** Use a specific linter version not available in the default environment
- **Integration tests:** Run integration tests as part of the validation process before commits
- **Security scanning:** Add custom vulnerability checks (e.g., `bandit`, `semgrep`) before commits
- **CI/CD parity:** Match the exact validation commands used in your CI pipeline
- **Monorepo isolation:** Different validation commands for different subdirectories

### Other Uses

- Custom environment setup notes.
- Personal workflow preferences.
- Machine-specific paths or configurations.

In git worktrees, use `@import` (a Claude Code directive that includes another CLAUDE.md file) in `CLAUDE.local.md` to reference a shared local rules file rather than duplicating it per worktree (e.g., `@import ../shared-local-rules.md`).

Create local supplements file and ensure it is gitignored:

test -f CLAUDE.local.md || touch CLAUDE.local.md
grep -qxF 'CLAUDE.local.md' .gitignore 2>/dev/null || echo 'CLAUDE.local.md' >> .gitignore

Step 5: Create language-specific rule files

For each detected language (whether at root or in a subdirectory), create a path-scoped rule file in .claude/rules/.

File naming: .claude/rules/{lang}.md (e.g., go.md, python.md, typescript.md).

Always add paths frontmatter to scope language rules to matching file extensions. This prevents language-specific rules from applying to unrelated files (e.g., Go rules applying to .py files when both languages are detected at root).

If the language was detected at root (e.g., root:go), scope to the extension at the repo root:

---
paths:
  - "**/*.go"
---

If the language was detected in a subdirectory (e.g., backend:python), scope to the subdirectory and extension:

---
paths:
  - "backend/**/*.py"
---

If the same language appears at root and in subdirectories, or in multiple subdirectories, combine the paths:

---
paths:
  - "backend/**/*.py"
  - "scripts/**/*.py"
---

File extension mapping:

  • go*.go
  • python*.py
  • typescript*.ts and *.tsx (use two separate paths entries, not brace expansion)
  • javascript*.js and *.jsx (use two separate paths entries, not brace expansion)
  • rust*.rs

Assemble each language rule file with:

  1. Header comment
  2. Paths frontmatter (always — scoped by extension, and by subdirectory when applicable)
  3. Language-specific rules from $PLUGIN_ROOT/claude-md/languages/{lang}/{lang}.md

Header:

<!-- Assembled by /setup-project from agent-pragma -->
<!-- Language: {lang} -->
<!-- Re-run /setup-project to regenerate -->

Step 6: Create opencode.json for OpenCode compatibility

OpenCode uses opencode.json at the project root to load custom instructions. Create or update this file so OpenCode auto-loads the same .claude/rules/*.md files that Claude Code loads natively.

Check for existing opencode.json:

test -f opencode.json && echo "opencode-json:exists" || echo "opencode-json:missing"

If missing, create it:

{
  "$schema": "https://opencode.ai/config.json",
  "instructions": [".claude/rules/*.md"]
}

If it exists, read it and merge the instructions field:

  1. Invalid JSON: If the file cannot be parsed as valid JSON, back it up to opencode.json.bak and create a fresh opencode.json with the content above. Inform the user that the original was backed up.
  2. instructions already contains .claude/rules/*.md: No changes needed.
  3. instructions exists and is an array but does not contain .claude/rules/*.md: Append .claude/rules/*.md to the existing array.
  4. instructions exists but is not an array (e.g., a string): Convert it to an array containing the original value plus .claude/rules/*.md.
  5. instructions field is missing: Add it with [".claude/rules/*.md"].

Do not overwrite other fields in an existing opencode.json (e.g., model, provider, agent).

Step 7: Verify plugin skills and agents

All skills and agents are provided by the pragma plugin — no symlinks needed.

Check star-chamber prerequisites:

command -v uv >/dev/null 2>&1 && echo "uv:ok" || echo "uv:missing"

Store the result - if uv:missing, include a warning in Step 9 output.

Build go-structural (ONLY if Go was detected in Step 2):

Skip this entirely if no go language was detected in Step 2 output (e.g. if the only output was root:python, there is no Go — do not build go-structural).

If and only if Go was detected (any line matching *:go in Step 2 output):

cd "$PLUGIN_ROOT/tools/go-structural" && go build -o go-structural . && echo "go-structural:ok" || echo "go-structural:build-failed"

If go is not available or the build fails, note in Step 9 output that go-structural is unavailable.

Step 8: Offer reference configs

For each language detected in Step 2, read $PLUGIN_ROOT/claude-md/languages/{lang}/setup.md if it exists. This file defines:

  • Lint Config Detection — which config files to check for (any match means the project already has lint tooling configured).
  • Reference Config — which reference config to offer and where to copy it from (paths are relative to $PLUGIN_ROOT).

For each language that has a setup.md:

  1. Read the file and extract the config filenames from the "Lint Config Detection" section.
  2. Check if any of those files exist in the project. Use glob matching for wildcard patterns (e.g., .eslintrc.*, .prettierrc*).
  3. If any config file exists, skip — the project already has lint tooling.
  4. If none exist, extract the reference config path from the "Reference Config" section and offer to copy from $PLUGIN_ROOT/<path>, replacing {org} and {repo} template variables with values from Step 1.

Skip languages that have no setup.md file.

Step 9: Output summary

## Setup Complete

**Project:** {org}/{repo}

**Structure detected:**
  - Root: [languages or "none"]
  - backend/: Python
  - frontend/: TypeScript

**Created:**
  - .claude/rules/universal.md
  - .claude/rules/local-supplements.md
  - .claude/rules/python.md (scoped to backend/**)
  - .claude/rules/typescript.md (scoped to frontend/**)
  - opencode.json (OpenCode instructions — loads .claude/rules/*.md)

**Skills available (via pragma plugin):**
  - /implement - implement with auto-validation
  - /review - review changes against all validators
  - /validate - run all validators
  - /star-chamber - multi-LLM advisory council

**Agents available (via pragma plugin):**
  - security - auto-invokes on trust boundary changes
  - star-chamber - auto-invokes on architectural decisions

**Usage:**
  /implement <task>    - implement with validation loop
  /review              - validate current changes

**Star-Chamber:** Run `/star-chamber` — first invocation launches interactive provider setup.

If uv is missing, include this warning:

⚠️  **Warning:** uv is not installed. /star-chamber requires uv to run.

Install uv:
  curl -LsSf https://astral.sh/uv/install.sh | sh

Or see: https://docs.astral.sh/uv/getting-started/installation/

Then continue with:

**Recommended:**
  - **Optional:** If you want other contributors to benefit from the same rules, commit the generated `.claude/rules/` files. Otherwise, add `.claude/rules/` to `.gitignore` to keep them local.
  - `CLAUDE.local.md` has been created for personal/machine-specific rules (custom validation commands, local environment notes, personal workflow preferences). It is auto-loaded by Claude Code and gitignored.

SKILL.md

tile.json