oh-my-claudecode
Splits a complex task across several specialized Claude Code agents working in parallel, then keeps going until the result is checked. You describe what you want in plain language instead of memorizing commands.
What xenitv1-maestro runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
Claude Code
> /plugin marketplace add xenitv1/claude-code-maestro> /plugin install maestro@maestro-marketplace
Cursor
Cursor also runs Claude Code hooks from .claude/settings.json, so copy these hooks there to use them in Cursor.
What fires, and when
SessionStart
Fires once when a session begins, and again after a context compaction. It is where a plugin sets up its environment, or restores state the compaction dropped.
node "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.js"PreCompact
*node "${CLAUDE_PLUGIN_ROOT}/hooks/pre-compact.js"node "${CLAUDE_PLUGIN_ROOT}/hooks/brain-sync.js"SubagentStop
echo {}Stop
node "${CLAUDE_PLUGIN_ROOT}/hooks/stop.js"node "${CLAUDE_PLUGIN_ROOT}/hooks/brain-sync.js"PostToolUse
*node "${CLAUDE_PLUGIN_ROOT}/hooks/brain-sync.js"PostToolUseFailure
*node "${CLAUDE_PLUGIN_ROOT}/hooks/brain-sync.js"UserPromptSubmit
Fires before Claude sees each prompt you send. A plugin can use it to inject context, so the same instruction reaches the model every turn instead of only at session start.
node "${CLAUDE_PLUGIN_ROOT}/hooks/brain-sync.js"In the plugin's words
How xenitv1-maestro describes its own hook set.
Maestro plugin hooks for AI memory (LTM) and Ralph Wiggum persistence
Where it lives
#!/usr/bin/env node
/**
* Brain Sync Hook - Auto-Memory System
* Runs after every tool use, extracts AI memory to brain.jsonl
*
* @event PostToolUse
*/
const fs = require('fs');
const path = require('path');
const {
findProjectRoot,
getMaestroDir,
getClaudeProjectsDir,
normalizeProjectPath,
ensureMaestroDir,
loadState,
saveState,
isReadOnlyTool,
logDebug,
cleanAnsi,
getTimestamp,
readStdin,
outputJson
} = require('./lib/utils');
const {
readPreservedBrain,
writeBrain,
dedupe
} = require('./lib/brain');
const LOG_PREFIX = '[BRAIN-SYNC]';
// Maximum file size to read (50MB) - for full read
// Files larger than this will use streaming
const MAX_JSONL_SIZE = 50 * 1024 * 1024;
const STREAMING_THRESHOLD = 50 * 1024 * 1024; // Use streaming for files > 50MB
/**
* Detect active Claude CLI session from cwd.
*/
function getActiveSession(projectRoot) {
logDebug(LOG_PREFIX, `Project root: ${projectRoot}`);
try {
// STALE CONTEXT GUARD: Detect if project is empty
// Only check if it's a directory (might be a newly created empty folder)
if (fs.existsSync(projectRoot) && fs.lstatSync(projectRoot).isDirectory()) {
const rootEntries = fs.readdirSync(projectRoot);
const hasProjectFiles = rootEntries.some(e => !['.git', '.maestro', '.claude'].includes(e));
if (!hasProjectFiles) {
logDebug(LOG_PREFIX, 'Project directory empty (except meta) - treated as FRESH START. Skipping legacy session recovery.');
return { sessionId: null, mainJsonl: null, subagentDir: null };
}
}
const claudeProjectsDir = getClaudeProjectsDir();
if (!fs.existsSync(claudeProjectsDir)) {
return { sessionId: null, mainJsonl: null, subagentDir: null };
}
// Normalize project path for matching
const cwdNormalized = normalizeProjectPath(projectRoot);
let projectDir = null;
// Find matching project directory (case-insensitive for Windows compatibility)
const entries = fs.readdirSync(claudeProjectsDir);
// 1. Try exact match first
for (const entry of entries) {
if (entry.toLowerCase() === cwdNormalized.toLowerCase()) {
projectDir = path.join(claudeProjectsDir, entry);
break;
}
}
// 2. Try prefix match if exact match fails (case-insensitive)
if (!projectDir) {
for (const entry of entries) {
const entryLower = entry.toLowerCase();
const cwdLower = cwdNormalized.toLowerCase();
if (cwdLower && (entryLower.startsWith(cwdLower) || cwdLower.startsWith(entryLower))) {
projectDir = path.join(claudeProjectsDir, entry);
break;
}
}
}
if (!projectDir) {
return { sessionId: null, mainJsonl: null, subagentDir: null };
}
// Try to find session from .jsonl files
const jsonlFiles = fs.readdirSync(projectDir)
.filter(f => f.endsWith('.jsonl'))
.map(f => ({
name: f,
path: path.join(projectDir, f),
mtime: fs.statSync(path.join(projectDir, f)).mtimeMs
}))
.sort((a, b) => b.mtime - a.mtime);
if (jsonlFiles.length > 0) {
const latestJsonl = jsonlFiles[0];
const sessionId = latestJsonl.name.replace('.jsonl', '');
const mainJsonl = latestJsonl.path;
const subagentDir = path.join(projectDir, sessionId, 'subagents');
logDebug(LOG_PREFIX, `Session: ${sessionId}`);
return { sessionId, mainJsonl, subagentDir };
}
// Fallback: read sessions-index.json
const indexFile = path.join(projectDir, 'sessions-index.json');
if (fs.existsSync(indexFile)) {
const indexData = JSON.parse(fs.readFileSync(indexFile, 'utf-8'));
const sessions = indexData.entries || [];
if (sessions.length > 0) {
// Get most recent session
const latestSession = sessions.sort((a, b) =>
(b.fileMtime || 0) - (a.fileMtime || 0)
)[0];
const sessionId = latestSession.sessionId;
const subagentDir = path.join(projectDir, sessionId, 'subagents');
const mainJsonl = path.join(projectDir, `${sessionId}.jsonl`);
logDebug(LOG_PREFIX, `Session (from index): ${sessionId}`);
return { sessionId, mainJsonl, subagentDir };
}
}
return { sessionId: null, mainJsonl: null, subagentDir: null };
} catch (err) {
logDebug(LOG_PREFIX, `Session detection error: ${err.message}`);
return { sessionId: null, mainJsonl: null, subagentDir: null };
}
}
/**
* Read JSONL file incrementally using offset tracking.
*/
function readJsonlIncremental(filePath, sessionId, callback) {
const syncState = loadState('sync', findProjectRoot()) || {};
const fileKey = `${sessionId}:${path.basename(filePath)}`;
const startOffset = syncState[fileKey] || 0;
const stats = fs.statSync(filePath);
if (stats.size < startOffset) {
// File was rotated or cleared
logDebug(LOG_PREFIX, `File ${fileKey} shrunk, resetting offset`);
}
const currentStart = stats.size < startOffset ? 0 : startOffset;
if (currentStart >= stats.size) {
logDebug(LOG_PREFIX, `No new content in ${fileKey}`);
return Promise.resolve();
}
logDebug(LOG_PREFIX, `Reading ${fileKey} from offset ${currentStart}`);
// Open file for reading
const fd = fs.openSync(filePath, 'r');
const bufferSize = 64 * 1024;
const buffer = Buffer.alloc(bufferSize);
let bytesRead;
let leftover = '';
let currentOffset = currentStart;
while ((bytesRead = fs.readSync(fd, buffer, 0, bufferSize, currentOffset)) > 0) {
currentOffset += bytesRead;
const chunk = leftover + buffer.toString('utf-8', 0, bytesRead);
const lines = chunk.split('\n');
leftover = lines.pop(); // Last line might be incomplete
for (const line of lines) {
if (line.trim()) {
try {
callback(JSON.parse(line));
} catch (err) { /* Skip invalid */ }
}
}
}
fs.closeSync(fd);
// Save new offset
syncState[fileKey] = currentOffset;
s#!/usr/bin/env node
/**
* Pre-Compact Hook - Compact Summary Capture
* Captures compact summaries before/after manual /compact command
* and persists them to brain.jsonl for cross-session memory.
*
* @event PreCompact
* @matcher manual - Triggered by /compact command
*/
const fs = require('fs');
const path = require('path');
const {
findProjectRoot,
getMaestroDir,
ensureMaestroDir,
getClaudeProjectsDir,
normalizeProjectPath,
loadState,
saveState,
logDebug,
readStdin,
outputJson
} = require('./lib/utils');
const {
readBrain,
writeBrain,
appendToBrain,
extractLastSummary,
writeCompactToBrain
} = require('./lib/brain');
const LOG_PREFIX = '[PRE-COMPACT]';
/**
* Find the current active session transcript.
*/
function getCurrentTranscript() {
try {
const claudeProjectsDir = getClaudeProjectsDir();
if (!fs.existsSync(claudeProjectsDir)) {
return null;
}
const projectRoot = findProjectRoot();
const cwdNormalized = normalizeProjectPath(projectRoot);
let projectDir = null;
// Find matching project directory (case-insensitive for Windows compatibility)
const entries = fs.readdirSync(claudeProjectsDir);
for (const entry of entries) {
if (entry.toLowerCase() === cwdNormalized.toLowerCase()) {
projectDir = path.join(claudeProjectsDir, entry);
break;
}
}
// Prefix match fallback (case-insensitive)
if (!projectDir) {
for (const entry of entries) {
const entryLower = entry.toLowerCase();
const cwdLower = cwdNormalized.toLowerCase();
if (cwdLower && (entryLower.startsWith(cwdLower) || cwdLower.startsWith(entryLower))) {
projectDir = path.join(claudeProjectsDir, entry);
break;
}
}
}
if (!projectDir) {
return null;
}
// Find most recent JSONL file
const jsonlFiles = fs.readdirSync(projectDir)
.filter(f => f.endsWith('.jsonl'))
.map(f => ({
name: f,
path: path.join(projectDir, f),
mtime: fs.statSync(path.join(projectDir, f)).mtimeMs
}))
.sort((a, b) => b.mtime - a.mtime);
if (jsonlFiles.length > 0) {
return jsonlFiles[0].path;
}
return null;
} catch (err) {
logDebug(LOG_PREFIX, `Error finding transcript: ${err.message}`);
return null;
}
}
/**
* Main hook entry point.
*/
async function main() {
const projectRoot = findProjectRoot();
logDebug(LOG_PREFIX, '='.repeat(60));
logDebug(LOG_PREFIX, 'PRE-COMPACT HOOK TRIGGERED');
logDebug(LOG_PREFIX, `Project Root: ${projectRoot}`);
try {
// Read hook input
const hookInput = await readStdin();
logDebug(LOG_PREFIX, `Hook input: trigger=${hookInput.trigger}, custom_instructions=${hookInput.custom_instructions ? 'yes' : 'no'}`);
// Only process manual compacts
if (hookInput.trigger !== 'manual') {
outputJson({});
return;
}
// Get current transcript
const transcriptPath = hookInput.transcript_path || getCurrentTranscript();
logDebug(LOG_PREFIX, `Current transcript: ${transcriptPath ? path.basename(transcriptPath) : 'none'}`);
if (!transcriptPath) {
outputJson({});
return;
}
// Extract last summary from transcript
const summary = extractLastSummary(transcriptPath);
logDebug(LOG_PREFIX, `Summary found: ${summary ? 'yes (' + summary.length + ' chars)' : 'no'}`);
if (summary) {
// Write to brain.jsonl
writeCompactToBrain(summary, projectRoot);
// Also save to state for reference if needed
saveState('last-compact', {
summary: summary.substring(0, 5000),
timestamp: Date.now(),
trigger: 'manual'
}, projectRoot);
// Output context for the new session
outputJson({
type: 'compact_capture',
hookSpecificOutput: {
hookEventName: 'PreCompact',
additionalContext: `
✅ Current summary captured and saved to brain.jsonl.
Note: Compaction will now continue and a new summary will be generated.
`
}
});
logDebug(LOG_PREFIX, 'Pre-compact hook completed successfully');
} else {
// It's normal to not find a summary in PreCompact because it hasn't been generated yet for this compaction.
// But we output OK anyway.
outputJson({});
logDebug(LOG_PREFIX, 'No pre-existing compact summary found in current transcript.');
}
} catch (err) {
logDebug(LOG_PREFIX, `Hook error: ${err.message}`);
logDebug(LOG_PREFIX, `Stack: ${err.stack}`);
outputJson({});
}
}
main();
#!/usr/bin/env node
/**
* Session Start Hook for Maestro Plugin
* Reads brain.jsonl and project context when a new session begins.
* Analyzes package.json for tech stack info and stores in LTM.
*
* @event SessionStart
*/
const fs = require('fs');
const path = require('path');
const {
findProjectRoot,
getMaestroDir,
ensureMaestroDir,
readFileSafe,
getFileHash,
readStdin,
logDebug,
outputJson
} = require('./lib/utils');
const {
formatBrainForContext,
writeTechToBrain,
extractLastSummary,
writeCompactToBrain
} = require('./lib/brain');
const LOG_PREFIX = '[SESSION-START]';
// Framework detection patterns
const FRAMEWORK_PATTERNS = {
'next.js': { deps: ['next'], files: ['next.config.js', 'next.config.mjs', 'next.config.ts'] },
'react': { deps: ['react', 'react-dom'], files: [] },
'vue': { deps: ['vue'], files: ['vue.config.js', 'nuxt.config.js'] },
'nuxt': { deps: ['nuxt'], files: ['nuxt.config.js', 'nuxt.config.ts'] },
'angular': { deps: ['@angular/core'], files: ['angular.json'] },
'svelte': { deps: ['svelte'], files: ['svelte.config.js'] },
'express': { deps: ['express'], files: [] },
'fastify': { deps: ['fastify'], files: [] },
'nestjs': { deps: ['@nestjs/core'], files: ['nest-cli.json'] },
'electron': { deps: ['electron'], files: [] },
'tauri': { deps: ['@tauri-apps/api'], files: ['tauri.conf.json'] },
'astro': { deps: ['astro'], files: ['astro.config.mjs'] },
'remix': { deps: ['@remix-run/react'], files: ['remix.config.js'] },
'gatsby': { deps: ['gatsby'], files: ['gatsby-config.js'] }
};
// Important dependencies to track
const IMPORTANT_DEPS = {
// State management
'zustand': 'State (Zustand)',
'redux': 'State (Redux)',
'recoil': 'State (Recoil)',
'jotai': 'State (Jotai)',
'mobx': 'State (MobX)',
'@tanstack/react-query': 'Data Fetching (React Query)',
'swr': 'Data Fetching (SWR)',
// Styling
'tailwindcss': 'Styling (Tailwind)',
'styled-components': 'Styling (Styled Components)',
'@emotion/react': 'Styling (Emotion)',
'sass': 'Styling (SASS)',
'@mui/material': 'UI (Material UI)',
'@chakra-ui/react': 'UI (Chakra)',
'antd': 'UI (Ant Design)',
'shadcn-ui': 'UI (shadcn)',
// Database
'prisma': 'ORM (Prisma)',
'@prisma/client': 'ORM (Prisma)',
'drizzle-orm': 'ORM (Drizzle)',
'typeorm': 'ORM (TypeORM)',
'mongoose': 'ODM (Mongoose)',
'sequelize': 'ORM (Sequelize)',
// Auth
'next-auth': 'Auth (NextAuth)',
'@clerk/nextjs': 'Auth (Clerk)',
'@supabase/supabase-js': 'Backend (Supabase)',
'firebase': 'Backend (Firebase)',
// Testing
'jest': 'Testing (Jest)',
'vitest': 'Testing (Vitest)',
'@testing-library/react': 'Testing (RTL)',
'playwright': 'E2E (Playwright)',
'cypress': 'E2E (Cypress)',
// Build tools
'vite': 'Build (Vite)',
'webpack': 'Build (Webpack)',
'esbuild': 'Build (esbuild)',
'turbo': 'Monorepo (Turborepo)',
// Utilities
'zod': 'Validation (Zod)',
'yup': 'Validation (Yup)',
'axios': 'HTTP (Axios)',
'date-fns': 'Dates (date-fns)',
'dayjs': 'Dates (Day.js)',
'lodash': 'Utils (Lodash)',
'framer-motion': 'Animation (Framer)'
};
/**
* Check if tech stack needs re-analysis (package.json changed).
*/
function shouldReanalyzeTech(projectRoot) {
const pkgPath = path.join(projectRoot, 'package.json');
const hashFile = path.join(getMaestroDir(projectRoot), '.tech_hash');
const currentHash = getFileHash(pkgPath);
if (!currentHash) {
return false; // No package.json
}
if (fs.existsSync(hashFile)) {
try {
const storedHash = fs.readFileSync(hashFile, 'utf-8').trim();
if (storedHash === currentHash) {
return false; // No change
}
} catch (err) {
// Continue with reanalysis
}
}
return true;
}
/**
* Save current package.json hash.
*/
function saveTechHash(projectRoot) {
const pkgPath = path.join(projectRoot, 'package.json');
const hashFile = path.join(ensureMaestroDir(projectRoot), '.tech_hash');
const hash = getFileHash(pkgPath);
if (hash) {
try {
fs.writeFileSync(hashFile, hash, 'utf-8');
} catch (err) {
logDebug(LOG_PREFIX, `Error saving tech hash: ${err.message}`);
}
}
}
/**
* Analyze package.json and extract tech stack info.
*/
function analyzePackageJson(projectRoot) {
const pkgPath = path.join(projectRoot, 'package.json');
if (!fs.existsSync(pkgPath)) {
logDebug(LOG_PREFIX, 'No package.json found');
return null;
}
try {
const pkgContent = fs.readFileSync(pkgPath, 'utf-8');
const pkg = JSON.parse(pkgContent);
const result = {
name: pkg.name || 'unknown',
version: pkg.version || '0.0.0',
description: pkg.description || '',
frameworks: [],
frameworkVersions: {},
keyDeps: [],
devTools: [],
scripts: {},
nodeVersion: null,
packageManager: null,
type: pkg.type || 'commonjs'
};
// Combine all dependencies
const allDeps = {
...pkg.dependencies,
...pkg.devDependencies
};
// Detect frameworks
for (const [framework, patterns] of Object.entries(FRAMEWORK_PATTERNS)) {
// Check dependencies
for (const dep of patterns.deps) {
if (allDeps[dep]) {
if (!result.frameworks.includes(framework)) {
result.frameworks.push(framework);
}
// Capture version
const version = allDeps[dep].replace(/[\^~>=<]/g, '');
result.frameworkVersions[dep] = version;
break;
}
}
// Check config files
for (const cfgFile of patterns.files) {
if (fs.existsSync(path.join(projectRoot, cfgFile))) {
if (!result.frameworks.includes(framework)) {
result.frameworks.push(framework);
}
break;
}
}
}
// Always capture React version if present
if (allDeps['react'] && !result.frameworkVersions['react']) {
result.frameworkVersions['react'] = allDeps['reac#!/usr/bin/env node
/**
* Stop Hook for Maestro Plugin (Ralph Wiggum Controller)
* Controls whether Claude can exit or must continue iterating.
*
* @event Stop, SubagentStop
*/
const {
findProjectRoot,
logDebug,
readStdin,
outputJson
} = require('./lib/utils');
const Ralph = require('./lib/ralph');
const LOG_PREFIX = '[STOP]';
/**
* Main hook entry point.
*/
async function main() {
const projectRoot = findProjectRoot();
logDebug(LOG_PREFIX, '='.repeat(60));
logDebug(LOG_PREFIX, 'STOP HOOK TRIGGERED');
try {
const hookInput = await readStdin();
const inputData = JSON.stringify(hookInput);
// Check if this is a SubagentStop event
const hookEvent = hookInput.hookEventName || '';
const isSubagentStop = hookEvent === 'SubagentStop' ||
inputData.toLowerCase().includes('subagent');
if (isSubagentStop) {
logDebug(LOG_PREFIX, 'SUBAGENT STOP detected - allowing subagent to complete');
outputJson({});
process.exit(0);
return;
}
// Check Ralph Wiggum iteration state
const decision = Ralph.getBlockDecision();
if (!decision.block) {
// Allow exit
logDebug(LOG_PREFIX, `Exit allowed: ${decision.reason}`);
// Cleanup if completed
if (decision.completed) {
logDebug(LOG_PREFIX, 'Ralph Wiggum completed - cleaning up state');
Ralph.clearState();
}
outputJson({});
process.exit(0);
return;
}
// Block exit - Ralph wants more iterations
logDebug(LOG_PREFIX, `Exit BLOCKED: ${decision.reason} (${decision.current}/${decision.max})`);
// Build continuation message
const continuationMessage = `
🔄 RALPH WIGGUM 2.0: ELITE PERSISTENCE ACTIVE
## 📊 Iteration Status
**Progress:** ${decision.current} / ${decision.max}
## ⚠️ TASK COMPLETION BLOCKED
Ralph Wiggum requires more iterations to ensure quality standards are met.
### Next Steps:
1. Continue testing and fixing issues
2. Run tests again to verify fixes
3. Check verification matrix coverage
4. Ensure all critical tests pass
The task will remain blocked until:
- All tests pass OR
- Maximum iterations reached OR
- Manual completion signal received
---
**To manually complete:** Create .maestro/ralph.complete file
**To stop early:** Delete .maestro/ralph.active file
`;
// Block the exit with continuation prompt
outputJson({
block: true,
message: continuationMessage.trim(),
iteration: decision.current,
maxIterations: decision.max
});
process.exit(0);
} catch (err) {
logDebug(LOG_PREFIX, `Error: ${err.message}`);
outputJson({});
}
}
main();
Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.
Elite-tier orchestration framework for Claude Code CLI. Supercharges AI development through specialized agents, modular skills, intelligent hooks, and persistent memory systems. Author: xenitV1 • X/Twitter Philosophy: "Why over How.
Splits a complex task across several specialized Claude Code agents working in parallel, then keeps going until the result is checked. You describe what you want in plain language instead of memorizing commands.
Turns a rough feature idea into a written spec through guided questions, then has the agent build it and checks the result against that spec. Instead of hand-checking whether the work is finished, you get an automatic evaluation gate that runs in your coding agent.
A plugin that runs coding tasks through multiple AI backends (Codex, Claude, Gemini, OpenCode) with a structured development workflow, parallel execution, browser automation and multi-session task checkpointing.
Coordinates AI agents with mechanical protocol enforcement, a workflow gate, memory validation and a session hook. Includes a catalog of specialist agents and has no runtime dependencies.
Bernstein is a Claude Code plugin for orchestrating AI agents. It adds skills to list and inspect agents, review and approve tasks, create tasks, track costs and budgets, and show alerts for failed or stalled work.
A Claude Code plugin that enforces finishing multi-step tasks with evidence and verification at each stage. It works as a procedure for Opus or any Claude model, not as chance.
Adjusts how third-party models behave inside Claude Code so they run closer to a native Opus session, covering subagent lifecycle, session hooks and tool interception. It does not replace your gateway, provider mapping or account setup.
Runs a PDCA workflow with phase gating, spec checks, and delegation to sub-agents for planning, QA, and deployment. Fires at session start and on prompts, edits, task creation, and phase transitions.