From 8c2c54b0a4fefaec4b87aac5c1b3275edcd4197e Mon Sep 17 00:00:00 2001 From: Kacper Date: Thu, 18 Dec 2025 20:11:05 +0100 Subject: [PATCH] feat: load context files as system prompt for higher priority MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context files from .automaker/context/ (CLAUDE.md, CODE_QUALITY.md, etc.) are now passed as system prompt instead of prepending to user prompt. This ensures the agent follows project-specific rules like package manager preferences (pnpm vs npm) and coding conventions. Changes: - Add getContextDir() utility to automaker-paths.ts - Add loadContextFiles() method to load .md/.txt files from context dir - Pass context as systemPrompt in executeFeature() and followUpFeature() - Add debug logging to confirm system prompt is provided 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- apps/server/src/lib/automaker-paths.ts | 7 ++ apps/server/src/services/auto-mode-service.ts | 80 ++++++++++++++++++- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/apps/server/src/lib/automaker-paths.ts b/apps/server/src/lib/automaker-paths.ts index cfd87305..e11c6d7b 100644 --- a/apps/server/src/lib/automaker-paths.ts +++ b/apps/server/src/lib/automaker-paths.ts @@ -53,6 +53,13 @@ export function getImagesDir(projectPath: string): string { return path.join(getAutomakerDir(projectPath), "images"); } +/** + * Get the context files directory for a project (user-added context files) + */ +export function getContextDir(projectPath: string): string { + return path.join(getAutomakerDir(projectPath), "context"); +} + /** * Get the worktrees metadata directory for a project */ diff --git a/apps/server/src/services/auto-mode-service.ts b/apps/server/src/services/auto-mode-service.ts index b676c0c9..8edfd6dd 100644 --- a/apps/server/src/services/auto-mode-service.ts +++ b/apps/server/src/services/auto-mode-service.ts @@ -23,7 +23,7 @@ import { isAbortError, classifyError } from "../lib/error-handler.js"; import { resolveDependencies, areDependenciesSatisfied } from "../lib/dependency-resolver.js"; import type { Feature } from "./feature-loader.js"; import { FeatureLoader } from "./feature-loader.js"; -import { getFeatureDir, getAutomakerDir, getFeaturesDir } from "../lib/automaker-paths.js"; +import { getFeatureDir, getAutomakerDir, getFeaturesDir, getContextDir } from "../lib/automaker-paths.js"; const execAsync = promisify(exec); @@ -559,6 +559,9 @@ export class AutoModeService { // Build the prompt - use continuation prompt if provided (for recovery after plan approval) let prompt: string; + // Load project context files (CLAUDE.md, CODE_QUALITY.md, etc.) - passed as system prompt + const contextFiles = await this.loadContextFiles(projectPath); + if (options?.continuationPrompt) { // Continuation prompt is used when recovering from a plan approval // The plan was already approved, so skip the planning phase @@ -592,6 +595,7 @@ export class AutoModeService { ); // Run the agent with the feature's model and images + // Context files are passed as system prompt for higher priority await this.runAgent( workDir, featureId, @@ -604,6 +608,7 @@ export class AutoModeService { projectPath, planningMode: feature.planningMode, requirePlanApproval: feature.requirePlanApproval, + systemPrompt: contextFiles || undefined, } ); @@ -756,6 +761,9 @@ export class AutoModeService { // No previous context } + // Load project context files (CLAUDE.md, CODE_QUALITY.md, etc.) - passed as system prompt + const contextFiles = await this.loadContextFiles(projectPath); + // Build complete prompt with feature info, previous context, and follow-up instructions let fullPrompt = `## Follow-up on Feature Implementation @@ -874,6 +882,7 @@ Address the follow-up instructions above. Review the previous work and make the // Use fullPrompt (already built above) with model and all images // Note: Follow-ups skip planning mode - they continue from previous work // Pass previousContext so the history is preserved in the output file + // Context files are passed as system prompt for higher priority await this.runAgent( workDir, featureId, @@ -886,6 +895,7 @@ Address the follow-up instructions above. Review the previous work and make the projectPath, planningMode: 'skip', // Follow-ups don't require approval previousContent: previousContext || undefined, + systemPrompt: contextFiles || undefined, } ); @@ -1084,6 +1094,65 @@ Address the follow-up instructions above. Review the previous work and make the } } + /** + * Load context files from .automaker/context/ directory + * These are user-defined context files (CLAUDE.md, CODE_QUALITY.md, etc.) + * that provide project-specific rules and guidelines for the agent. + */ + private async loadContextFiles(projectPath: string): Promise { + // Use path.resolve for cross-platform absolute path handling + const contextDir = path.resolve(getContextDir(projectPath)); + + try { + // Check if directory exists first + await fs.access(contextDir); + + const files = await fs.readdir(contextDir); + // Filter for text-based context files (case-insensitive for Windows) + const textFiles = files.filter((f) => { + const lower = f.toLowerCase(); + return lower.endsWith(".md") || lower.endsWith(".txt"); + }); + + if (textFiles.length === 0) return ""; + + const contents: string[] = []; + for (const file of textFiles) { + // Use path.join for cross-platform path construction + const filePath = path.join(contextDir, file); + const content = await fs.readFile(filePath, "utf-8"); + contents.push(`## ${file}\n\n${content}`); + } + + console.log( + `[AutoMode] Loaded ${textFiles.length} context file(s): ${textFiles.join(", ")}` + ); + + return `# ⚠️ CRITICAL: Project Context Files - READ AND FOLLOW STRICTLY + +**IMPORTANT**: The following context files contain MANDATORY project-specific rules and conventions. You MUST: +1. Read these rules carefully before taking any action +2. Follow ALL commands exactly as shown (e.g., if the project uses \`pnpm\`, NEVER use \`npm\` or \`npx\`) +3. Follow ALL coding conventions, commit message formats, and architectural patterns specified +4. Reference these rules before running ANY shell commands or making commits + +Failure to follow these rules will result in broken builds, failed CI, and rejected commits. + +${contents.join("\n\n---\n\n")} + +--- + +**REMINDER**: Before running any command, verify you are using the correct package manager and following the conventions above. + +--- + +`; + } catch { + // Context directory doesn't exist or is empty - this is fine + return ""; + } + } + /** * Analyze project to gather context */ @@ -1731,6 +1800,7 @@ This helps parse your summary correctly in the output logs.`; planningMode?: PlanningMode; requirePlanApproval?: boolean; previousContent?: string; + systemPrompt?: string; } ): Promise { const finalProjectPath = options?.projectPath || projectPath; @@ -1838,6 +1908,13 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set. false // don't duplicate paths in text ); + // Debug: Log if system prompt is provided + if (options?.systemPrompt) { + console.log( + `[AutoMode] System prompt provided (${options.systemPrompt.length} chars), first 200 chars:\n${options.systemPrompt.substring(0, 200)}...` + ); + } + const executeOptions: ExecuteOptions = { prompt: promptContent, model: finalModel, @@ -1845,6 +1922,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set. cwd: workDir, allowedTools: allowedTools, abortController, + systemPrompt: options?.systemPrompt, }; // Execute via provider