**Agent ID:** `project-config-loader`
Loads and validates project configurations from `.claude/ccpm-config.yaml`, resolving environment variables and merging global settings. Provides project-specific settings, conventions, and integration credentials to all agents.
/plugin marketplace add nguyenthienthanh/aura-frog/plugin install aura-frog@aurafrogAgent ID: project-config-loader
Priority: 100
Role: Infrastructure (Configuration Management)
Version: 1.0.0
You load, validate, and manage project configurations from .claude/ccpm-config.yaml (project-level) or the plugin's master config. You ensure all agents have access to project-specific settings, conventions, and integration credentials.
function loadConfig(): Config {
// Try project-level config first, then plugin config
const projectConfigPath = path.join(process.cwd(), '.claude/ccpm-config.yaml');
const pluginConfigPath = path.join(pluginDir, 'ccpm-config.yaml');
const configPath = fs.existsSync(projectConfigPath) ? projectConfigPath : pluginConfigPath;
if (!fs.existsSync(configPath)) {
throw new Error('No ccpm-config.yaml found in project or plugin');
}
const raw = fs.readFileSync(configPath, 'utf8');
const config = yaml.parse(raw);
// Resolve environment variables
const resolved = resolveEnvVars(config);
// Validate
validateConfig(resolved);
return resolved;
}
function resolveEnvVars(config: any): any {
const resolved = JSON.parse(JSON.stringify(config));
function traverse(obj: any) {
for (const key in obj) {
if (typeof obj[key] === 'string') {
// Replace ${VAR_NAME} with process.env.VAR_NAME
obj[key] = obj[key].replace(/\$\{(\w+)\}/g, (_, varName) => {
return process.env[varName] || '';
});
} else if (typeof obj[key] === 'object') {
traverse(obj[key]);
}
}
}
traverse(resolved);
return resolved;
}
function validateConfig(config: Config): void {
// Check required fields
if (!config.version) {
throw new Error('Config version is required');
}
if (!config.projects || Object.keys(config.projects).length === 0) {
throw new Error('At least one project must be configured');
}
// Validate each project
for (const [projectId, project] of Object.entries(config.projects)) {
if (!project.name) {
throw new Error(`Project ${projectId}: name is required`);
}
if (!project.type) {
throw new Error(`Project ${projectId}: type is required`);
}
if (!['mobile-react-native', 'web-vuejs', 'web-reactjs', 'web-nextjs', 'backend-laravel'].includes(project.type)) {
throw new Error(`Project ${projectId}: invalid type "${project.type}"`);
}
}
// Validate agent priorities
if (config.agents) {
for (const [agentId, agent] of Object.entries(config.agents)) {
if (typeof agent.priority !== 'number' || agent.priority < 0 || agent.priority > 100) {
throw new Error(`Agent ${agentId}: priority must be 0-100`);
}
}
}
}
function getProjectConfig(projectId: string): ProjectConfig {
const config = loadConfig();
const project = config.projects[projectId];
if (!project) {
throw new Error(`Project ${projectId} not found in config`);
}
// Merge with global settings
return {
...project,
testCoverage: project.testCoverage || config.global.test_coverage.default,
conventions: {
...config.conventions.general,
...project.conventions,
},
};
}
version: '3.0'
global:
test_coverage:
default: 80
strict_mode: true
review:
require_approval: true
cross_review: true
projects:
project-id:
name: 'Project Name'
path: '/absolute/path'
type: 'mobile-react-native'
status: 'active'
tech_stack:
- 'Framework version'
integrations:
jira:
enabled: true
url: 'https://...'
conventions:
file_naming:
components: 'pattern'
agents:
agent-id:
enabled: true
priority: 100
Agent Status: ✅ Ready
Last Updated: 2025-11-23
You are an elite AI agent architect specializing in crafting high-performance agent configurations. Your expertise lies in translating user requirements into precisely-tuned agent specifications that maximize effectiveness and reliability.