Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion packages/cli/src/install/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
buildHookCommand,
} from '../adapters/index.js';
import { configureOpencodePermissions } from './adapters.js';
import { getDirName, getConfigDirFromHome, verifyInstalled } from './shared.js';
import { getDirName, getConfigDirFromHome, verifyInstalled, removeBuiltInSkills } from './shared.js';
import type { InstallResult } from './shared.js';
import * as path from 'node:path';
import ora from 'ora';
Expand All @@ -24,6 +24,15 @@ export function cleanupOrphanedFiles(configDir: string): void {
'hooks/statusline.js',
];

// Clean up legacy agents/skills/ directory (skills moved to skills/)
const legacySkillsDir = path.join(configDir, 'agents', 'skills');
if (fs.existsSync(legacySkillsDir)) {
const removed = removeBuiltInSkills(legacySkillsDir);
if (removed > 0) {
console.log(` ${chalk.green('\u2713')} Removed ${removed} legacy skills from agents/skills/`);
}
}

for (const relPath of orphanedFiles) {
const fullPath = path.join(configDir, relPath);
if (fs.existsSync(fullPath)) {
Expand Down
17 changes: 6 additions & 11 deletions packages/cli/src/install/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
copyDirRecursive,
verifyInstalled,
verifyFileInstalled,
removeBuiltInSkills,
} from './shared.js';
import type { InstallResult } from './shared.js';
import { getCommitAttribution } from './adapters.js';
Expand Down Expand Up @@ -262,21 +263,15 @@ async function install(
}
}

// Copy skills to agents/skills/ directory
// Copy skills to skills/ directory
const skillsSrc = path.join(src, 'skills');
if (fs.existsSync(skillsSrc)) {
spinner = ora({ text: 'Installing skills...', color: 'cyan' }).start();
const skillsDest = path.join(targetDir, 'agents', 'skills');
const skillsDest = path.join(targetDir, 'skills');

// Remove old MAXSIM built-in skills before copying new ones (preserve user custom skills)
if (fs.existsSync(skillsDest)) {
const builtInSkills = ['tdd', 'systematic-debugging', 'verification-before-completion'];
for (const skill of builtInSkills) {
const skillDir = path.join(skillsDest, skill);
if (fs.existsSync(skillDir)) {
fs.rmSync(skillDir, { recursive: true });
}
}
removeBuiltInSkills(skillsDest);
}

// Copy skills directory recursively
Expand All @@ -300,10 +295,10 @@ async function install(
const installedSkillDirs = fs.readdirSync(skillsDest, { withFileTypes: true })
.filter(e => e.isDirectory()).length;
if (installedSkillDirs > 0) {
spinner.succeed(chalk.green('\u2713') + ` Installed ${installedSkillDirs} skills to agents/skills/`);
spinner.succeed(chalk.green('\u2713') + ` Installed ${installedSkillDirs} skills to skills/`);
} else {
spinner.fail('Failed to install skills');
failures.push('agents/skills');
failures.push('skills');
Comment on lines 295 to +301
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

installedSkillDirs counts all subdirectories under the shared skills/ directory, including pre-existing user skills. This makes the “Installed X skills” message inaccurate and can mask an install problem (e.g., if MAXSIM skills failed to copy but user skills already exist, the count is still > 0). Consider validating/counting only the MAXSIM-installed skills (the built-in list) when reporting success/failure.

Copilot uses AI. Check for mistakes.
}
}

Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/install/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ export function writeManifest(
}
}
}
// Include skills in manifest (agents/skills/<skill-name>/*)
const skillsManifestDir = path.join(agentsDir, 'skills');
// Include skills in manifest (skills/<skill-name>/*)
const skillsManifestDir = path.join(configDir, 'skills');
if (fs.existsSync(skillsManifestDir)) {
const skillHashes = generateManifest(skillsManifestDir);
for (const [rel, hash] of Object.entries(skillHashes)) {
manifest.files['agents/skills/' + rel] = hash;
manifest.files['skills/' + rel] = hash;
}
Comment on lines +105 to 111
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

writeManifest() now hashes everything under configDir/skills and records it as MAXSIM-managed. Since skills/ is a shared, user-editable directory, this will cause saveLocalPatches() to back up (and report) user skills as “modified MAXSIM files” on the next install. Limit manifest entries to MAXSIM-owned skill directories (same set you remove/overwrite during install) rather than the entire skills/ tree.

Copilot uses AI. Check for mistakes.
}

Expand Down
33 changes: 33 additions & 0 deletions packages/cli/src/install/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,39 @@ export function verifyFileInstalled(filePath: string, description: string): bool
return true;
}

/**
* Built-in MAXSIM skill names — used during install, uninstall, and orphan cleanup
* to identify MAXSIM-owned skill directories (preserving user custom skills).
*/
export const BUILT_IN_SKILLS = [
'tdd',
'systematic-debugging',
'verification-before-completion',
'code-review',
'simplify',
'memory-management',
'using-maxsim',
'batch-execution',
'subagent-driven-development',
'writing-plans',
Comment on lines +133 to +135
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BUILT_IN_SKILLS includes entries that don't exist in the bundled templates (templates/skills/ currently has: code-review, memory-management, simplify, systematic-debugging, tdd, using-maxsim, verification-before-completion). Keeping extra names here can lead to unintended deletion of user-created skills with those names during install/uninstall/cleanup. Update the constant to exactly match the skills MAXSIM actually installs (or derive the list from the templates directory at build/runtime).

Suggested change
'batch-execution',
'subagent-driven-development',
'writing-plans',

Copilot uses AI. Check for mistakes.
] as const;

/**
* Remove MAXSIM built-in skill directories from a given parent directory.
* Returns the number of skill directories removed.
*/
export function removeBuiltInSkills(skillsParentDir: string): number {
let count = 0;
for (const skill of BUILT_IN_SKILLS) {
const skillDir = path.join(skillsParentDir, skill);
if (fs.existsSync(skillDir)) {
fs.rmSync(skillDir, { recursive: true });
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removeBuiltInSkills() uses fs.rmSync(..., { recursive: true }) even though this module already provides safeRmDir() specifically to handle cross-platform removal issues (e.g., Windows EPERM/read-only files). Consider using the same removal helper here (or fs.rmSync with the options needed for Windows) so uninstall/cleanup doesn't fail on Windows when deleting skill directories.

Suggested change
fs.rmSync(skillDir, { recursive: true });
safeRmDir(skillDir);

Copilot uses AI. Check for mistakes.
count++;
}
}
return count;
}

export interface InstallResult {
settingsPath: string | null;
settings: Record<string, unknown> | null;
Expand Down
36 changes: 30 additions & 6 deletions packages/cli/src/install/uninstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import chalk from 'chalk';

import type { RuntimeName } from '../adapters/index.js';
import { readSettings, writeSettings } from '../adapters/index.js';
import { getDirName, getGlobalDir, getOpencodeGlobalDir } from './shared.js';
import { getDirName, getGlobalDir, getOpencodeGlobalDir, removeBuiltInSkills } from './shared.js';

/**
* Uninstall MAXSIM from the specified directory for a specific runtime
Expand Down Expand Up @@ -93,7 +93,31 @@ export function uninstall(isGlobal: boolean, runtime: RuntimeName = 'claude', ex
console.log(` ${chalk.green('\u2713')} Removed maxsim/`);
}

// 3. Remove MAXSIM agents
// 3. Remove MAXSIM skills from skills/ directory
const skillsDir = path.join(targetDir, 'skills');
if (fs.existsSync(skillsDir)) {
const skillCount = removeBuiltInSkills(skillsDir);
if (skillCount > 0) {
removedCount++;
console.log(
` ${chalk.green('\u2713')} Removed ${skillCount} MAXSIM skills from skills/`,
);
}
}

// 3b. Remove legacy MAXSIM skills from agents/skills/ directory
const legacySkillsDir = path.join(targetDir, 'agents', 'skills');
if (fs.existsSync(legacySkillsDir)) {
const legacySkillCount = removeBuiltInSkills(legacySkillsDir);
if (legacySkillCount > 0) {
removedCount++;
console.log(
` ${chalk.green('\u2713')} Removed ${legacySkillCount} legacy MAXSIM skills from agents/skills/`,
);
}
}

// 4. Remove MAXSIM agents
const agentsDir = path.join(targetDir, 'agents');
if (fs.existsSync(agentsDir)) {
const files = fs.readdirSync(agentsDir);
Expand All @@ -112,7 +136,7 @@ export function uninstall(isGlobal: boolean, runtime: RuntimeName = 'claude', ex
}
}

// 4. Remove MAXSIM hooks
// 5. Remove MAXSIM hooks
const hooksDir = path.join(targetDir, 'hooks');
if (fs.existsSync(hooksDir)) {
const maxsimHooks = [
Expand All @@ -137,7 +161,7 @@ export function uninstall(isGlobal: boolean, runtime: RuntimeName = 'claude', ex
}
}

// 5. Remove MAXSIM package.json (CommonJS mode marker)
// 6. Remove MAXSIM package.json (CommonJS mode marker)
const pkgJsonPath = path.join(targetDir, 'package.json');
if (fs.existsSync(pkgJsonPath)) {
try {
Expand All @@ -154,7 +178,7 @@ export function uninstall(isGlobal: boolean, runtime: RuntimeName = 'claude', ex
}
}

// 6. Clean up settings.json
// 7. Clean up settings.json
const settingsPath = path.join(targetDir, 'settings.json');
if (fs.existsSync(settingsPath)) {
const settings = readSettings(settingsPath);
Expand Down Expand Up @@ -248,7 +272,7 @@ export function uninstall(isGlobal: boolean, runtime: RuntimeName = 'claude', ex
}
}

// 7. For OpenCode, clean up permissions from opencode.json
// 8. For OpenCode, clean up permissions from opencode.json
if (isOpencode) {
const opencodeConfigDir = isGlobal
? getOpencodeGlobalDir()
Expand Down
4 changes: 2 additions & 2 deletions templates/agents/maxsim-debugger.md
Original file line number Diff line number Diff line change
Expand Up @@ -1273,8 +1273,8 @@ When any trigger condition below applies, read the full skill file via the Read

| Skill | Read | Trigger |
|-------|------|---------|
| Systematic Debugging | `.agents/skills/systematic-debugging/SKILL.md` | Always — you are a debugger, this is your primary skill |
| Verification Before Completion | `.agents/skills/verification-before-completion/SKILL.md` | Before claiming a bug is fixed or a debug session is complete |
| Systematic Debugging | `skills/systematic-debugging/SKILL.md` | Always — you are a debugger, this is your primary skill |
| Verification Before Completion | `skills/verification-before-completion/SKILL.md` | Before claiming a bug is fixed or a debug session is complete |

**Project skills override built-in skills.**

Expand Down
10 changes: 5 additions & 5 deletions templates/agents/maxsim-executor.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Before executing, discover project context:

**Self-improvement lessons:** Read `.planning/LESSONS.md` if it exists — accumulated lessons from past executions on this codebase. Apply them proactively to avoid known mistakes before they become deviations.

**Project skills:** Check `.agents/skills/` directory if it exists:
**Project skills:** Check `skills/` directory if it exists:
1. List available skills (subdirectories)
2. Read `SKILL.md` for each skill (lightweight index ~130 lines)
3. Load specific `rules/*.md` files as needed during implementation
Expand Down Expand Up @@ -612,11 +612,11 @@ Do not rely on memory of the skill content — always read the file fresh.

| Skill | Read | Trigger |
|-------|------|---------|
| TDD Enforcement | `.agents/skills/tdd/SKILL.md` | Before writing implementation code for a new feature, bug fix, or when plan type is `tdd` |
| Systematic Debugging | `.agents/skills/systematic-debugging/SKILL.md` | When encountering any bug, test failure, or unexpected behavior during execution |
| Verification Before Completion | `.agents/skills/verification-before-completion/SKILL.md` | Before claiming any task is done, fixed, or passing |
| TDD Enforcement | `skills/tdd/SKILL.md` | Before writing implementation code for a new feature, bug fix, or when plan type is `tdd` |
| Systematic Debugging | `skills/systematic-debugging/SKILL.md` | When encountering any bug, test failure, or unexpected behavior during execution |
| Verification Before Completion | `skills/verification-before-completion/SKILL.md` | Before claiming any task is done, fixed, or passing |

**Project skills override built-in skills.** If a skill with the same name exists in `.agents/skills/` in the project, load that one instead.
**Project skills override built-in skills.** If a skill with the same name exists in `skills/` in the project, load that one instead.

</available_skills>

Expand Down
4 changes: 2 additions & 2 deletions templates/agents/maxsim-phase-researcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Before researching, discover project context:

**Project instructions:** Read `./CLAUDE.md` if it exists in the working directory. Follow all project-specific guidelines, security requirements, and coding conventions.

**Project skills:** Check `.agents/skills/` directory if it exists:
**Project skills:** Check `skills/` directory if it exists:
1. List available skills (subdirectories)
2. Read `SKILL.md` for each skill (lightweight index ~130 lines)
3. Load specific `rules/*.md` files as needed during research
Expand Down Expand Up @@ -559,7 +559,7 @@ When any trigger condition below applies, read the full skill file via the Read

| Skill | Read | Trigger |
|-------|------|---------|
| Verification Before Completion | `.agents/skills/verification-before-completion/SKILL.md` | Before concluding research with confidence ratings |
| Verification Before Completion | `skills/verification-before-completion/SKILL.md` | Before concluding research with confidence ratings |

**Project skills override built-in skills.**

Expand Down
4 changes: 2 additions & 2 deletions templates/agents/maxsim-plan-checker.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Before verifying, discover project context:

**Self-improvement lessons:** Read `.planning/LESSONS.md` if it exists — accumulated lessons from past executions. Use planning insights as an additional verification dimension: flag plans that repeat known gap patterns or ignore documented codebase conventions.

**Project skills:** Check `.agents/skills/` directory if it exists:
**Project skills:** Check `skills/` directory if it exists:
1. List available skills (subdirectories)
2. Read `SKILL.md` for each skill (lightweight index ~130 lines)
3. Load specific `rules/*.md` files as needed during verification
Expand Down Expand Up @@ -707,7 +707,7 @@ When any trigger condition below applies, read the full skill file via the Read

| Skill | Read | Trigger |
|-------|------|---------|
| Verification Before Completion | `.agents/skills/verification-before-completion/SKILL.md` | Before issuing final PASS/FAIL verdict on a plan |
| Verification Before Completion | `skills/verification-before-completion/SKILL.md` | Before issuing final PASS/FAIL verdict on a plan |

**Project skills override built-in skills.**

Expand Down
6 changes: 3 additions & 3 deletions templates/agents/maxsim-planner.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Before planning, discover project context:

**Self-improvement lessons:** Read `.planning/LESSONS.md` if it exists — accumulated lessons from past executions on this codebase. Apply planning insights proactively: avoid known gaps, include wiring tasks for patterns that historically broke, reference codebase-specific conventions in task actions.

**Project skills:** Check `.agents/skills/` directory if it exists:
**Project skills:** Check `skills/` directory if it exists:
1. List available skills (subdirectories)
2. Read `SKILL.md` for each skill (lightweight index ~130 lines)
3. Load specific `rules/*.md` files as needed during planning
Expand Down Expand Up @@ -1199,8 +1199,8 @@ When any trigger condition below applies, read the full skill file via the Read

| Skill | Read | Trigger |
|-------|------|---------|
| TDD Enforcement | `.agents/skills/tdd/SKILL.md` | When identifying TDD candidates during task breakdown |
| Verification Before Completion | `.agents/skills/verification-before-completion/SKILL.md` | When writing <verify> sections for tasks |
| TDD Enforcement | `skills/tdd/SKILL.md` | When identifying TDD candidates during task breakdown |
| Verification Before Completion | `skills/verification-before-completion/SKILL.md` | When writing <verify> sections for tasks |

**Project skills override built-in skills.**

Expand Down
2 changes: 1 addition & 1 deletion templates/workflows/execute-phase.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ Execute each wave in sequence. Within a wave: parallel if `PARALLELIZATION=true`
- .planning/STATE.md (State)
- .planning/config.json (Config, if exists)
- ./CLAUDE.md (Project instructions, if exists — follow project-specific guidelines and coding conventions)
- .agents/skills/ (Project skills, if exists — list skills, read SKILL.md for each, follow relevant rules during implementation)
- skills/ (Project skills, if exists — list skills, read SKILL.md for each, follow relevant rules during implementation)
</files_to_read>

<success_criteria>
Expand Down
6 changes: 3 additions & 3 deletions templates/workflows/plan-phase.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Answer: "What do I need to know to PLAN this phase well?"
**Phase requirement IDs (MUST address):** {phase_req_ids}

**Project instructions:** Read ./CLAUDE.md if exists — follow project-specific guidelines
**Project skills:** Check .agents/skills/ directory (if exists) — read SKILL.md files, research should account for project skill patterns
**Project skills:** Check skills/ directory (if exists) — read SKILL.md files, research should account for project skill patterns
</additional_context>

<output>
Expand Down Expand Up @@ -212,7 +212,7 @@ Planner prompt:
**Phase requirement IDs (every ID MUST appear in a plan's `requirements` field):** {phase_req_ids}

**Project instructions:** Read ./CLAUDE.md if exists — follow project-specific guidelines
**Project skills:** Check .agents/skills/ directory (if exists) — read SKILL.md files, plans should account for project skill rules
**Project skills:** Check skills/ directory (if exists) — read SKILL.md files, plans should account for project skill rules
</planning_context>

<downstream_consumer>
Expand Down Expand Up @@ -277,7 +277,7 @@ Checker prompt:
**Phase requirement IDs (MUST ALL be covered):** {phase_req_ids}

**Project instructions:** Read ./CLAUDE.md if exists — verify plans honor project guidelines
**Project skills:** Check .agents/skills/ directory (if exists) — verify plans account for project skill rules
**Project skills:** Check skills/ directory (if exists) — verify plans account for project skill rules
</verification_context>

<expected_output>
Expand Down
4 changes: 2 additions & 2 deletions templates/workflows/quick.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Task(
- ./CLAUDE.md (if exists — follow project-specific guidelines)
</files_to_read>

**Project skills:** Check .agents/skills/ directory (if exists) — read SKILL.md files, plans should account for project skill rules
**Project skills:** Check skills/ directory (if exists) — read SKILL.md files, plans should account for project skill rules

</planning_context>

Expand Down Expand Up @@ -259,7 +259,7 @@ Execute quick task ${next_num}.
- ${QUICK_DIR}/${next_num}-PLAN.md (Plan)
- .planning/STATE.md (Project state)
- ./CLAUDE.md (Project instructions, if exists)
- .agents/skills/ (Project skills, if exists — list skills, read SKILL.md for each, follow relevant rules during implementation)
- skills/ (Project skills, if exists — list skills, read SKILL.md for each, follow relevant rules during implementation)
</files_to_read>

<constraints>
Expand Down