skills/project-config-composer/SKILL.md
Auto-generate a minimal per-project .opencode/ configuration from a stack fingerprint + recommendations. Creates opencode.jsonc, project agents, rules, and instructions that reference global resources. Used by /init-project provision.
npx skillsauth add Thomashighbaugh/opencode project-config-composerInstall 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.
Takes a stack fingerprint and resource recommendations and auto-generates a lean, production-quality .opencode/ configuration for the target project.
/init-project provision after @stack-detector + stack-recommender have run.opencode/ from an updated fingerprint.opencode/ only contains project-specific overrides, new files, and references.Takes two inputs (either from previous pipeline steps or direct arguments):
{
"fingerprint": { ... },
"projectType": "webapp",
"detected": true
}
{
"recommends": {
"archetype": "nextjs-webapp",
"skills": [...],
"agents": [...],
"rules": [...],
"commands": [...],
"notes": [...],
"gaps": [...]
}
}
The composer creates the following structure under the project's .opencode/:
.opencode/
├── opencode.jsonc # Project-level config (extends global, selects resources)
├── rules/
│ ├── project-conventions.md # Auto-generated conventions from detected stack
│ ├── project-testing.md # Testing guidelines specific to detected frameworks
│ ├── {category}-{name}.md # Fine-grained rules from rule-templates (if recommended)
│ └── ... # One per recommended fine_rule
├── tools/
│ ├── {name}.ts # TypeScript tools from tool-templates (if recommended)
│ └── ... # One per recommended tool
├── agents/ # Project-specific agent wrappers (if needed)
│ └── ... (only if gaps identified)
└── instructions/ # AGENTS.md fragment for project-specific docs
└── README.md # Brief note about what was generated
The main project config file. It:
"$schema" to the opencode config schema⚠️ CRITICAL: Only valid schema keys allowed. The OpenCode config schema (
https://opencode.ai/config.json) setsadditionalProperties: false. Generated files MUST contain ONLY the following valid top-level keys:$schema,shell,logLevel,server,command,skills,references,watcher,snapshot,plugin,share,autoupdate,disabled_providers,enabled_providers,model,small_model,default_agent,username,agent,provider,mcp,formatter,lsp,instructions,permission,tools,attachment,enterprise,tool_output,compaction,experimental. Keys likeextends,agents(plural),project,rules,state,context,cacheare NOT valid and will cause validation errors.
{
"$schema": "https://opencode.ai/config.json",
"instructions": [
"AGENTS.md",
"./rules/project-conventions.md",
"./rules/project-testing.md"
],
"resource_tags": {
"include": ["typescript", "react", "nextjs", "tailwind", "prisma", "vitest"],
"exclude": ["python", "rust", "go"]
},
"permission": {
"edit": "allow",
"bash": "allow"
}
}
If an archetype was matched:
{
"$schema": "https://opencode.ai/config.json",
"instructions": [
"AGENTS.md",
"./rules/project-conventions.md"
],
"resource_tags": {
"include": ["typescript", "react", "nextjs", "tailwind"],
"exclude": ["python"]
}
}
Auto-generated from the detected stack:
---
name: project-conventions
description: Auto-generated conventions for [framework] project
---
# Project Conventions
## Tech Stack
- **Language:** TypeScript (strict mode)
- **Framework:** Next.js 15 (App Router)
- **CSS:** Tailwind CSS v4
- **Database:** PostgreSQL via Prisma
- **Testing:** Vitest (unit) + Playwright (e2e)
## Code Conventions
- Use `async/await` over raw promises
- Preher server components by default; client components only when needed
- Route handlers in `app/api/` directory
- Prisma schema follows singular table naming: `user`, `post`, `comment`
- All API routes must be validated with Zod schemas
## Naming
- Components: PascalCase
- Hooks: camelCase with `use` prefix
- Utilities: camelCase
- Types/Interfaces: PascalCase with `Type`/`Interface` suffix where disambiguation helps
## Imports
- Absolute imports using `@/` alias
- Group: external → internal → types
When the recommendations include tools[], the composer generates TypeScript tool files from the local template catalog at ~/.config/opencode/tool-templates/:
TOOL_TEMPLATES_DIR="$HOME/.config/opencode/tool-templates"
PROJECT_TOOLS_DIR="$PROJECT_DIR/.opencode/tools"
For each recommended tool, the composer:
$TOOL_TEMPLATES_DIR/{category}/{name}.ts{{PLACEHOLDERS}} with values from the stack fingerprint (e.g., {{PROJECT_NAME}}, {{LANGUAGE}}, {{FRAMEWORK}})$PROJECT_TOOLS_DIR/{name}.tsopencode.jsonc under the tools arrayTemplate placeholders:
| Placeholder | Source | Example |
|-------------|--------|---------|
| {{PROJECT_NAME}} | Fingerprint or directory name | my-app |
| {{LANGUAGE}} | fingerprint.language.primary | typescript |
| {{FRAMEWORK}} | fingerprint.framework.name | nextjs |
| {{TEST_FRAMEWORK}} | fingerprint.testing.frameworks[0].name | vitest |
| {{PACKAGE_MANAGER}} | fingerprint.packageManager.name | pnpm |
| {{BUILD_TOOL}} | fingerprint.buildTool.name | tsc |
| {{ORM}} | fingerprint.database.orm | prisma |
| {{DATABASE}} | fingerprint.database.database | postgresql |
Example output (from tool-templates/typescript/type-check.ts):
// Auto-generated from tool-template: typescript/type-check.ts
// Project: my-app (TypeScript, Next.js)
import { execSync } from 'child_process'
export default {
name: 'type-check',
description: 'Run TypeScript type checking for my-app',
handler: () => {
execSync('npx tsc --noEmit', { stdio: 'inherit' })
}
}
When the recommendations include fine_rules[], the composer generates granular rule files from the local template catalog at ~/.config/opencode/rule-templates/:
RULE_TEMPLATES_DIR="$HOME/.config/opencode/rule-templates"
PROJECT_RULES_DIR="$PROJECT_DIR/.opencode/rules"
For each recommended fine_rule, the composer:
$RULE_TEMPLATES_DIR/{category}/{name}.md{{PLACEHOLDERS}} with values from the stack fingerprint$PROJECT_RULES_DIR/{category}-{name}.mdopencode.jsonc under instructionsExample output (from rule-templates/framework/nextjs.md):
---
name: nextjs-conventions
description: Auto-generated Next.js framework conventions for my-app
tags: [nextjs, react, conventions, framework]
---
# Next.js Conventions
## App Router
- Use `app/` directory for routes (App Router detected)
- Server Components by default; add `'use client'` only when needed
- Route handlers in `app/api/` directory
- Layouts in `app/layout.tsx`, nested layouts in route groups
If a gap in global resources is detected, the composer generates a minimal project-specific wrapper agent. For example, if no global rule exists for Prisma conventions:
---
description: Project-specific Prisma schema review and database migration guidance
model: opencode/deepseek-v4-flash-free
mode: subagent
---
<Agent_Prompt>
<Role>
You are a database and Prisma specialist for this project.
</Role>
<Conventions>
- Table names are singular: User, Post, Comment
- All models have `id`, `createdAt`, `updatedAt`
- Use `@default(autoincrement())` for primary keys
- Relations use cascade delete by default
</Conventions>
</Agent_Prompt>
Check for --minimal flag: when present, generate only opencode.jsonc with resource_tags and extends — skip rules, tools, agents, and instructions. Produces a ~10-line config instead of a full scaffold. Use for quick project setup where per-project rules aren't needed yet.
PROJECT_DIR="." # or specified path
mkdir -p "$PROJECT_DIR/.opencode/rules"
mkdir -p "$PROJECT_DIR/.opencode/tools"
mkdir -p "$PROJECT_DIR/.opencode/agents"
mkdir -p "$PROJECT_DIR/.opencode/instructions"
extends — it is NOT a valid config key (archetype manifests use it internally, project configs do not)agents (plural), project, rules, state, context, or cache — these are NOT valid config keysopencode.jsonc without confirming with the user firstAfter writing the config file, validate it against the actual OpenCode schema:
# Fetch the schema and validate all top-level keys
SCHEMA_URL="https://opencode.ai/config.json"
CONFIG_FILE=".opencode/opencode.jsonc"
# Extract top-level keys from the schema definition
VALID_KEYS=$(curl -s "$SCHEMA_URL" | python3 -c "
import json,sys
schema = json.load(sys.stdin)
# Navigate to Config definition
config = schema
if '\$defs' in schema and 'Config' in schema['\$defs']:
config = schema['\$defs']['Config']
valid = list(config.get('properties', {}).keys())
print(' '.join(valid))
")
# Check config for invalid keys
python3 -c "
import json, re, sys
with open('$CONFIG_FILE') as f:
raw = f.read()
# Strip comments
raw = re.sub(r'//.*', '', raw)
raw = re.sub(r'/\*[\s\S]*?\*/', '', raw)
config = json.loads(raw)
valid_keys = set('''$VALID_KEYS'''.split())
invalid = [k for k in config if k not in valid_keys]
if invalid:
print(f'ERROR: Invalid config keys: {invalid}')
print('Remove these keys. Valid keys: {\$schema, ' + ', '.join(sorted(valid_keys - {'\\\$schema'})) + '}')
sys.exit(1)
else:
print('OK: All keys valid')
"
# If validation fails, fix the config and re-validate before proceeding
For each detected technology, generate a brief conventions rule file:
If the recommendations include tools[]:
~/.config/opencode/tool-templates/{category}/{name}.ts{{PLACEHOLDERS}} with fingerprint values$PROJECT_DIR/.opencode/tools/{name}.tstools entry to opencode.jsonc referencing the generated fileIf a tool template doesn't exist locally, suggest running /init-project find-tools to search registries.
If the recommendations include fine_rules[]:
~/.config/opencode/rule-templates/{category}/{name}.md{{PLACEHOLDERS}} with fingerprint values$PROJECT_DIR/.opencode/rules/{category}-{name}.mdopencode.jsonc under instructionsIf a rule template doesn't exist locally, suggest running /init-project find-rules to search registries.
For each identified gap, create a minimal agent that fills the missing capability.
## Generated .opencode/ Configuration
### Files Created
- `.opencode/opencode.jsonc` — Project config (extends archetype/standalone)
- `.opencode/rules/project-conventions.md` — Stack-specific conventions
- `.opencode/rules/project-testing.md` — Testing guidelines
- `.opencode/tools/{n}.ts` — N project-specific TypeScript tools (from tool-templates)
- `.opencode/rules/{category}-{name}.md` — M fine-grained convention rules (from rule-templates)
### Recommendations Applied
- ✅ 3 skills activated via resource_tags
- ✅ 2 agents available for subdelegation
- ✅ 1 archetype matched (nextjs-webapp)
- ✅ N tools generated from tool-templates
- ✅ M fine-grained rules generated from rule-templates
### Gaps Identified
- ⚠️ No global skill for Next.js App Router → created project agent wrapper
- ⚠️ No global rule for Prisma conventions → added to project rules
- ⚠️ No tool template for {missing_tool} → suggest `/init-project find-tools`
- ⚠️ No rule template for {missing_rule} → suggest `/init-project find-rules`
### Next Steps
1. Review generated files and customize as needed
2. Run `/project commit` to commit initial config
3. Start using OpenCode with stack-aware defaults
@stack-detector → stack-recommender → project-config-composer → .opencode/ output
/init-project provision
# Automatically: detect → recommend → compose
User says "Set up a Next.js project with Prisma" → @stack-detector produces
a synthetic fingerprint → stack-recommender maps resources → project-config-composer
generates the config — all in one pipeline.
.opencode/agents/ or .opencode/rules/ files without user confirmation.opencode/instructions/README.md that explains what was generated and how to customizetools
Create valid, type-safe TypeScript tools for OpenCode — generates correct boilerplate, typed interfaces, and handler stubs. Use when building new tools for global config or per-project .opencode/tools/.
testing
Explore multiple solution branches in parallel, evaluate each, and recommend the best path. Use when the user explicitly invokes /ideation tree-of-thoughts or asks for "tree of thought" / "branching exploration".
testing
Run multiple independent reasoning passes and find consensus. Use when the decision is critically important, the stakes are high, or the user explicitly requests "run it multiple times" / "check consistency" / "self-consistency".
testing
Optimization by PROmpting — generate candidate prompt variations, test each against a benchmark, and report the best performer. Use when the user invokes /ideation opro or asks for "prompt optimization" / "OPRO".