universal-agent-memory 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,641 +1,726 @@
1
1
  import Handlebars from 'handlebars';
2
+ import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
3
+ import { join, dirname } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { prepopulateMemory } from '../memory/prepopulate.js';
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
2
8
  export async function generateClaudeMd(analysis, config) {
3
- const template = getTemplate(config);
9
+ // Determine platform mode
10
+ const hasWebDatabase = !!config.memory?.shortTerm?.webDatabase;
11
+ const forceDesktop = config.memory?.shortTerm?.forceDesktop;
12
+ const isWebPlatform = hasWebDatabase && !forceDesktop;
13
+ // Use appropriate template
14
+ const template = isWebPlatform ? getWebTemplate() : getDesktopTemplate();
4
15
  const compiled = Handlebars.compile(template);
5
- const context = buildContext(analysis, config);
16
+ // Build comprehensive context from analysis + auto-population
17
+ const context = await buildContext(analysis, config);
6
18
  return compiled(context);
7
19
  }
8
- function buildContext(analysis, config) {
9
- // Detect web platform by checking memory config for web database setting
20
+ async function buildContext(analysis, config) {
21
+ const cwd = process.cwd();
22
+ // Detect web vs desktop
10
23
  const hasWebDatabase = !!config.memory?.shortTerm?.webDatabase;
11
24
  const forceDesktop = config.memory?.shortTerm?.forceDesktop;
12
25
  const isWebPlatform = hasWebDatabase && !forceDesktop;
13
- const isDesktopPlatform = !isWebPlatform;
14
- // Determine long-term memory provider
15
- let longTermProvider = 'qdrant';
26
+ // Long-term memory config
27
+ let longTermBackend = 'Qdrant';
16
28
  let longTermEndpoint = config.memory?.longTerm?.endpoint || 'localhost:6333';
17
- let longTermCollection = config.memory?.longTerm?.collection || 'agent_memory';
29
+ const longTermCollection = config.memory?.longTerm?.collection || 'agent_memory';
18
30
  if (config.memory?.longTerm?.provider === 'github') {
19
- longTermProvider = 'github';
31
+ longTermBackend = 'GitHub';
20
32
  longTermEndpoint = `${config.memory?.longTerm?.github?.repo || 'owner/repo'}/${config.memory?.longTerm?.github?.path || '.uam/memory'}`;
21
33
  }
22
34
  else if (config.memory?.longTerm?.provider === 'qdrant-cloud') {
23
- longTermProvider = 'qdrant-cloud';
35
+ longTermBackend = 'Qdrant Cloud';
24
36
  longTermEndpoint = config.memory?.longTerm?.qdrantCloud?.url || 'https://xxxxxx.aws.cloud.qdrant.io:6333';
25
37
  }
26
- // GitHub repo info for web memory
27
- const githubRepo = config.memory?.longTerm?.github?.repo || '';
28
- const githubMemoryPath = config.memory?.longTerm?.github?.path || '.uam/memory';
38
+ // Prepopulate memory from project
39
+ let prepopulated = null;
40
+ try {
41
+ prepopulated = await prepopulateMemory(cwd, { docs: true, git: true, skills: true, limit: 200 });
42
+ }
43
+ catch (e) {
44
+ console.warn('Failed to prepopulate memory:', e);
45
+ }
46
+ // Build repository structure
47
+ const repoStructure = buildRepositoryStructure(cwd, analysis);
48
+ // Discover skills, droids, commands
49
+ const discoveredSkills = prepopulated?.skills || [];
50
+ const skills = discoveredSkills.filter(s => s.type === 'skill');
51
+ const droids = discoveredSkills.filter(s => s.type === 'droid');
52
+ // Commands discovered from prepopulate (unused currently but kept for reference)
53
+ // const commands = discoveredSkills.filter(s => s.type === 'command');
54
+ // Build skill mappings table
55
+ const skillMappings = buildSkillMappings(skills);
56
+ // Build language droids table
57
+ const languageDroids = buildLanguageDroidsTable(droids, analysis.languages);
58
+ // Build discovered skills table
59
+ const discoveredSkillsTable = buildDiscoveredSkillsTable(skills);
60
+ // Extract troubleshooting from git history
61
+ const troubleshooting = buildTroubleshootingSection(prepopulated?.longTerm || []);
62
+ // Build architecture overview
63
+ const architectureOverview = buildArchitectureOverview(analysis);
64
+ // Build core components section
65
+ const coreComponents = buildCoreComponentsSection(analysis);
66
+ // Build key config files
67
+ const keyConfigFiles = buildKeyConfigFiles(analysis);
68
+ // Build essential commands
69
+ const essentialCommands = buildEssentialCommands(analysis);
70
+ // Build prepopulated knowledge section
71
+ const prepopulatedKnowledge = buildPrepopulatedKnowledge(prepopulated);
72
+ // Build cluster contexts
73
+ const clusterContexts = buildClusterContexts(analysis);
74
+ // Build project URLs
75
+ const projectUrls = buildProjectUrls(analysis);
76
+ // Build key workflows
77
+ const keyWorkflows = buildKeyWorkflows(analysis);
78
+ // Build infrastructure workflow
79
+ const infraWorkflow = buildInfraWorkflow(analysis);
80
+ // Build MCP plugins
81
+ const mcpPlugins = buildMcpPlugins(cwd);
82
+ // Build primary skills for decision loop
83
+ const primarySkills = buildPrimarySkills(skills);
84
+ // Build language examples
85
+ const languageExamples = buildLanguageExamples(analysis.languages);
29
86
  return {
87
+ // Project basics
30
88
  PROJECT_NAME: analysis.projectName || config.project.name,
31
89
  DESCRIPTION: analysis.description || config.project.description || '',
32
90
  DEFAULT_BRANCH: analysis.defaultBranch || config.project.defaultBranch || 'main',
33
- // Platform detection
34
- IS_WEB_PLATFORM: isWebPlatform,
35
- IS_DESKTOP_PLATFORM: isDesktopPlatform,
36
91
  // Issue tracker
37
- HAS_ISSUE_TRACKER: !!analysis.issueTracker,
38
- ISSUE_TRACKER_NAME: analysis.issueTracker?.name || 'GitHub Issues',
39
- ISSUE_TRACKER_URL: analysis.issueTracker?.url || '',
40
- // Memory config - ALWAYS shown, differs by platform
41
- SHORT_TERM_PATH: config.memory?.shortTerm?.path || './agents/data/memory/short_term.db',
42
- SHORT_TERM_MAX_ENTRIES: config.memory?.shortTerm?.maxEntries || 50,
43
- LONG_TERM_PROVIDER: longTermProvider,
92
+ ISSUE_TRACKER: analysis.issueTracker ?
93
+ `Use [${analysis.issueTracker.name}](${analysis.issueTracker.url || '#'}) for issue tracking.` :
94
+ null,
95
+ // Memory config
96
+ MEMORY_DB_PATH: config.memory?.shortTerm?.path || 'agents/data/memory/short_term.db',
97
+ MEMORY_QUERY_CMD: 'uam memory query',
98
+ MEMORY_STORE_CMD: 'uam memory store',
99
+ MEMORY_START_CMD: 'uam memory start',
100
+ MEMORY_STATUS_CMD: 'uam memory status',
101
+ MEMORY_STOP_CMD: 'uam memory stop',
102
+ SHORT_TERM_LIMIT: config.memory?.shortTerm?.maxEntries || 50,
103
+ LONG_TERM_BACKEND: longTermBackend,
44
104
  LONG_TERM_ENDPOINT: longTermEndpoint,
45
105
  LONG_TERM_COLLECTION: longTermCollection,
46
- GITHUB_REPO: githubRepo,
47
- GITHUB_MEMORY_PATH: githubMemoryPath,
48
- HAS_GITHUB_MEMORY: !!githubRepo,
49
- // Worktree config - ALWAYS enabled for desktop
106
+ SCREENSHOTS_PATH: 'agents/data/screenshots',
107
+ DOCKER_COMPOSE_PATH: existsSync(join(cwd, 'agents/docker-compose.yml')) ? 'agents/docker-compose.yml' :
108
+ existsSync(join(cwd, 'docker-compose.yml')) ? 'docker-compose.yml' : null,
109
+ // Worktree config
50
110
  WORKTREE_DIR: config.worktrees?.directory || '.worktrees',
51
- WORKTREE_PREFIX: config.worktrees?.branchPrefix || 'feature/',
52
- // URLs
53
- URLS: analysis.urls,
54
- HAS_URLS: analysis.urls.length > 0,
55
- // Clusters
56
- HAS_CLUSTERS: analysis.clusters?.enabled,
57
- CLUSTERS: analysis.clusters?.contexts || [],
58
- // Components
59
- COMPONENTS: analysis.components,
60
- HAS_COMPONENTS: analysis.components.length > 0,
111
+ WORKTREE_CREATE_CMD: 'uam worktree create',
112
+ WORKTREE_PR_CMD: 'uam worktree pr',
113
+ WORKTREE_CLEANUP_CMD: 'uam worktree cleanup',
114
+ WORKTREE_APPLIES_TO: 'Application code, configs, workflows, documentation, CLAUDE.md itself',
115
+ BRANCH_PREFIX: config.worktrees?.branchPrefix || 'feature/',
116
+ // Paths
117
+ SKILLS_PATH: '.factory/skills/',
118
+ DROIDS_PATH: '.factory/droids/',
119
+ COMMANDS_PATH: '.factory/commands/',
120
+ DOCS_PATH: analysis.directories.docs[0] || 'docs',
121
+ FIXES_PATH: existsSync(join(cwd, 'docs/fixes')) ? 'docs/fixes/' : null,
122
+ CHANGELOG_PATH: existsSync(join(cwd, 'docs/changelog')) ? 'docs/changelog' : null,
123
+ CHANGELOG_TEMPLATE: existsSync(join(cwd, 'docs/changelog/CHANGELOG_TEMPLATE.md')) ? 'docs/changelog/CHANGELOG_TEMPLATE.md' : null,
124
+ WORKFLOW_DOCS_PATH: existsSync(join(cwd, 'docs/workflows/GIT_WORKTREE_WORKFLOW.md')) ? 'docs/workflows/GIT_WORKTREE_WORKFLOW.md' : null,
61
125
  // Commands
62
126
  TEST_COMMAND: analysis.commands.test || 'npm test',
63
127
  LINT_COMMAND: analysis.commands.lint || 'npm run lint',
64
128
  BUILD_COMMAND: analysis.commands.build || 'npm run build',
129
+ HOOKS_INSTALL_CMD: existsSync(join(cwd, '.factory/scripts/install-hooks.sh')) ? '.factory/scripts/install-hooks.sh' : null,
130
+ // Skills and droids
131
+ PRIMARY_SKILLS: primarySkills,
132
+ SKILL_MAPPINGS: skillMappings,
133
+ DISCOVERED_SKILLS: discoveredSkillsTable,
134
+ LANGUAGE_DROIDS: languageDroids,
135
+ LANGUAGE_EXAMPLES: languageExamples,
136
+ // Repository structure
137
+ '@REPOSITORY_STRUCTURE': repoStructure,
138
+ STRUCTURE_DATE: new Date().toLocaleString('en-US', { month: 'long', year: 'numeric' }),
139
+ // Path migrations (if detected from git history)
140
+ PATH_MIGRATIONS: null, // TODO: detect from git mv history
141
+ // Clusters and URLs
142
+ CLUSTER_CONTEXTS: clusterContexts,
143
+ PROJECT_URLS: projectUrls,
144
+ KEY_WORKFLOWS: keyWorkflows,
145
+ ESSENTIAL_COMMANDS: essentialCommands,
146
+ // Architecture
147
+ ARCHITECTURE_OVERVIEW: architectureOverview,
148
+ DATABASE_ARCHITECTURE: analysis.databases.length > 0 ? buildDatabaseArchitecture(analysis) : null,
149
+ // Core components
150
+ CORE_COMPONENTS: coreComponents,
151
+ // Auth flow
152
+ AUTH_FLOW: analysis.authentication ? buildAuthFlow(analysis) : null,
153
+ // Gateway knowledge
154
+ GATEWAY_KNOWLEDGE: null, // Project-specific, detected from k8s/istio files
155
+ // Multi-environment
156
+ MULTI_ENV_CONFIG: null, // Project-specific
65
157
  // Infrastructure
66
- INFRA_PATH: analysis.directories.infrastructure[0] || 'infra/',
67
- HAS_TERRAFORM: analysis.infrastructure.iac === 'Terraform',
68
- HAS_KUBERNETES: analysis.infrastructure.containerOrchestration === 'Kubernetes',
69
- // Databases
70
- DATABASES: analysis.databases,
71
- HAS_DATABASES: analysis.databases.length > 0,
72
- // Auth
73
- HAS_AUTH: !!analysis.authentication,
74
- AUTH_PROVIDER: analysis.authentication?.provider,
75
- AUTH_DESCRIPTION: analysis.authentication?.description,
76
- // CI/CD
77
- HAS_CICD: !!analysis.ciCd,
78
- CICD_PLATFORM: analysis.ciCd?.platform,
79
- WORKFLOWS: analysis.ciCd?.workflows || [],
80
- // Existing agents
81
- DROIDS: analysis.existingDroids,
82
- HAS_DROIDS: analysis.existingDroids.length > 0,
83
- SKILLS: analysis.existingSkills,
84
- HAS_SKILLS: analysis.existingSkills.length > 0,
85
- COMMANDS: analysis.existingCommands,
86
- HAS_COMMANDS: analysis.existingCommands.length > 0,
158
+ HAS_INFRA: analysis.directories.infrastructure.length > 0,
159
+ INFRA_WORKFLOW: infraWorkflow,
160
+ CLUSTER_IDENTIFY: analysis.clusters?.enabled ? 'Identify which cluster(s) affected' : null,
87
161
  // Troubleshooting
88
- TROUBLESHOOTING_HINTS: analysis.troubleshootingHints,
89
- HAS_TROUBLESHOOTING: analysis.troubleshootingHints.length > 0,
90
- // Key files
91
- KEY_FILES: analysis.keyFiles,
92
- HAS_KEY_FILES: analysis.keyFiles.length > 0,
93
- // Security
94
- SECURITY_NOTES: analysis.securityNotes,
95
- HAS_SECURITY_NOTES: analysis.securityNotes.length > 0,
96
- // Languages/Frameworks
97
- LANGUAGES: analysis.languages.join(', '),
98
- FRAMEWORKS: analysis.frameworks.join(', '),
162
+ TROUBLESHOOTING: troubleshooting,
163
+ // Key config files
164
+ KEY_CONFIG_FILES: keyConfigFiles,
165
+ // MCP plugins
166
+ MCP_PLUGINS: mcpPlugins,
167
+ // Prepopulated knowledge
168
+ PREPOPULATED_KNOWLEDGE: prepopulatedKnowledge ? true : null,
169
+ RECENT_ACTIVITY: prepopulatedKnowledge?.recentActivity || null,
170
+ LEARNED_LESSONS: prepopulatedKnowledge?.learnedLessons || null,
171
+ KNOWN_GOTCHAS: prepopulatedKnowledge?.knownGotchas || null,
172
+ HOT_SPOTS: prepopulatedKnowledge?.hotSpots || null,
173
+ // Platform detection
174
+ IS_WEB_PLATFORM: isWebPlatform,
175
+ IS_DESKTOP_PLATFORM: !isWebPlatform,
99
176
  };
100
177
  }
101
- function getTemplate(_config) {
102
- return `<coding_guidelines>
103
-
104
- # {{#if IS_WEB_PLATFORM}}AGENT.md{{else}}CLAUDE.md{{/if}} - {{PROJECT_NAME}} Development Guide
105
-
106
- You are Autonomous Claude, a self-directed AI agent with full control over this environment. You operate continuously, making your own decisions.
107
- {{#if DESCRIPTION}}
108
-
109
- > {{DESCRIPTION}}
110
- {{/if}}
111
-
112
- ---
113
-
114
- ## MANDATORY RULES - READ BEFORE ANY ACTION ⛔
115
-
116
- **STOP! Before making ANY code/infrastructure changes, you MUST follow these rules:**
117
-
118
- {{#if IS_DESKTOP_PLATFORM}}
119
- ### 1. WORKTREE REQUIREMENT (NO EXCEPTIONS)
120
-
121
- \`\`\`
122
- FORBIDDEN: Direct commits to {{DEFAULT_BRANCH}} branch
123
- REQUIRED: Create worktree Make changes → Create PR → Merge via PR
124
- \`\`\`
125
-
126
- **Before ANY code change:**
127
-
128
- \`\`\`bash
129
- # Step 1: Create worktree
130
- uam worktree create <descriptive-slug>
131
-
132
- # Step 2: cd into worktree and make changes
133
- cd {{WORKTREE_DIR}}/NNN-<slug>/
134
-
135
- # Step 3: Commit and create PR
136
- uam worktree pr <id>
137
- \`\`\`
138
-
139
- **Applies to:** All code, configs, workflows, documentation
140
- {{else}}
141
- ### 1. BRANCH REQUIREMENT (NO EXCEPTIONS)
142
-
143
- \`\`\`
144
- ❌ FORBIDDEN: Direct commits to {{DEFAULT_BRANCH}} branch
145
- ✅ REQUIRED: Create branch → Make changes → Create PR → Merge via PR
146
- \`\`\`
147
-
148
- **Before ANY code change:**
149
-
150
- \`\`\`bash
151
- git checkout -b {{WORKTREE_PREFIX}}<descriptive-slug>
152
- # Make changes, commit, push
153
- git push -u origin {{WORKTREE_PREFIX}}<descriptive-slug>
154
- # Create PR via UI
155
- \`\`\`
156
- {{/if}}
157
-
158
- ### 2. MEMORY REQUIREMENT (AFTER SIGNIFICANT ACTIONS)
159
-
160
- \`\`\`bash
161
- # Store learnings after: fixes, discoveries, architecture decisions, gotchas
162
- uam memory store lesson "What you learned" --tags tag1,tag2 --importance 7
163
- \`\`\`
164
-
165
- **Must store memories for:**
166
- - Infrastructure changes (cost savings, scaling decisions, fixes)
167
- - Bug fixes and their root causes
168
- - Architecture decisions and rationale
169
- - Gotchas and workarounds discovered
170
- - Performance optimizations
171
-
172
- ### 3. TODO LIST REQUIREMENT
173
-
174
- - Create todo list for multi-step tasks (3+ steps)
175
- - Update status IMMEDIATELY after completing each item
176
- - Never let todos go stale (update every 5-10 tool calls)
177
-
178
- ### 4. VERIFICATION BEFORE COMPLETION
179
-
180
- - [ ] Used {{#if IS_DESKTOP_PLATFORM}}worktree{{else}}feature branch{{/if}} for code changes? (or explain why not applicable)
181
- - [ ] Stored significant learnings in memory?
182
- - [ ] Updated/completed todo list?
183
- - [ ] Created PR instead of direct commit?
184
-
185
- ---
186
-
187
- ## MEMORY SYSTEM
188
-
189
- > **CRITICAL**: Memory updates are MANDATORY, not optional. Every significant discovery, fix, or lesson learned MUST be stored before completing a task.
190
-
191
- {{#if IS_DESKTOP_PLATFORM}}
192
- ### Short-term Memory (SQLite: \`{{SHORT_TERM_PATH}}\`)
193
-
194
- Table: \`memories\`
195
- - \`id\`: INTEGER PRIMARY KEY
196
- - \`timestamp\`: TEXT (ISO8601)
197
- - \`type\`: TEXT (action|observation|thought|goal)
198
- - \`content\`: TEXT
199
-
200
- **BEFORE EACH DECISION**: Query recent entries (last {{SHORT_TERM_MAX_ENTRIES}}) to understand context:
201
- \`\`\`sql
202
- SELECT * FROM memories ORDER BY id DESC LIMIT {{SHORT_TERM_MAX_ENTRIES}};
203
- \`\`\`
204
-
205
- **AFTER EACH ACTION**: Record what you did and the outcome:
206
- \`\`\`sql
207
- INSERT INTO memories (timestamp, type, content) VALUES (datetime('now'), 'action', 'Description...');
208
- \`\`\`
209
-
210
- ### Long-term Memory ({{LONG_TERM_PROVIDER}}: \`{{LONG_TERM_ENDPOINT}}\`, collection: \`{{LONG_TERM_COLLECTION}}\`)
211
-
212
- **Start services**: \`uam memory start\`
213
-
214
- Vector schema:
215
- - \`id\`: UUID
216
- - \`vector\`: 384-dim embedding (all-MiniLM-L6-v2)
217
- - \`payload\`: {type, tags[], content, importance (1-10), timestamp}
218
-
219
- **Query memories** (semantic search):
220
- \`\`\`bash
221
- uam memory query "search term"
222
- \`\`\`
223
-
224
- **Store new memory** (MANDATORY for significant learnings):
225
- \`\`\`bash
226
- uam memory store <type> "content" --tags tag1,tag2 --importance N
227
- \`\`\`
228
-
229
- Memory types: \`fact\`, \`lesson\`, \`skill\`, \`discovery\`, \`preference\`
230
-
231
- ### MANDATORY Memory Triggers
232
-
233
- **ALWAYS store to long-term memory when you:**
234
- 1. Fix a bug or resolve an error (lesson)
235
- 2. Discover how a system/component works (discovery)
236
- 3. Learn a configuration requirement (fact)
237
- 4. Find a successful approach to a problem (skill)
238
- 5. Identify a coding pattern or convention (preference)
239
- 6. Complete infrastructure changes (fact)
240
- 7. Debug authentication/networking issues (lesson)
241
-
242
- **Memory storage is part of task completion.** A task is NOT complete until learnings are stored.
243
-
244
- ### Agent Services Setup
245
-
246
- \`\`\`bash
247
- # Start services (auto-creates collection and migrates memories)
248
- uam memory start
249
-
250
- # Check status
251
- uam memory status
252
-
253
- # Stop services
254
- uam memory stop
255
- \`\`\`
256
-
257
- {{else}}
258
- ### Short-term Memory (localStorage)
259
-
260
- You have access to browser localStorage for maintaining context across messages.
261
-
262
- Key: \`agent_context_{{PROJECT_NAME}}\`
263
-
264
- Structure:
265
- \`\`\`json
266
- {
267
- "memories": [
268
- {"timestamp": "ISO8601", "type": "action|observation|thought|goal", "content": "..."}
269
- ],
270
- "maxEntries": {{SHORT_TERM_MAX_ENTRIES}}
178
+ function buildRepositoryStructure(cwd, analysis) {
179
+ const lines = [];
180
+ const visited = new Set();
181
+ // Standard directories to look for
182
+ const standardDirs = [
183
+ { path: 'apps', comment: 'Deployable applications' },
184
+ { path: 'services', comment: 'Backend microservices' },
185
+ { path: 'packages', comment: 'Shared packages' },
186
+ { path: 'libs', comment: 'Shared libraries' },
187
+ { path: 'src', comment: 'Source code' },
188
+ { path: 'infra', comment: 'Infrastructure as Code' },
189
+ { path: 'infrastructure', comment: 'Infrastructure as Code' },
190
+ { path: 'terraform', comment: 'Terraform configurations' },
191
+ { path: 'k8s', comment: 'Kubernetes manifests' },
192
+ { path: 'helm', comment: 'Helm charts' },
193
+ { path: 'tools', comment: 'Development tools' },
194
+ { path: 'scripts', comment: 'Automation scripts' },
195
+ { path: 'tests', comment: 'Test suites' },
196
+ { path: 'test', comment: 'Test suites' },
197
+ { path: 'docs', comment: 'Documentation' },
198
+ { path: '.factory', comment: 'Factory AI configuration' },
199
+ { path: '.github', comment: 'GitHub configuration' },
200
+ { path: '.gitlab', comment: 'GitLab configuration' },
201
+ ];
202
+ for (const { path, comment } of standardDirs) {
203
+ const fullPath = join(cwd, path);
204
+ if (existsSync(fullPath) && statSync(fullPath).isDirectory()) {
205
+ visited.add(path);
206
+ lines.push(`├── ${path}/`.padEnd(35) + `# ${comment}`);
207
+ // List subdirectories
208
+ try {
209
+ const subdirs = readdirSync(fullPath, { withFileTypes: true })
210
+ .filter(d => d.isDirectory() && !d.name.startsWith('.'))
211
+ .slice(0, 8);
212
+ for (let i = 0; i < subdirs.length; i++) {
213
+ const prefix = i === subdirs.length - 1 ? '│ └── ' : '│ ├── ';
214
+ const subComment = getSubdirComment(path, subdirs[i].name, join(fullPath, subdirs[i].name));
215
+ lines.push(`${prefix}${subdirs[i].name}/`.padEnd(35) + (subComment ? `# ${subComment}` : ''));
216
+ }
217
+ }
218
+ catch {
219
+ // Ignore permission errors
220
+ }
221
+ lines.push('│');
222
+ }
223
+ }
224
+ // Add component directories from analysis
225
+ for (const comp of analysis.components) {
226
+ const dirPath = comp.path.split('/')[0];
227
+ if (!visited.has(dirPath) && existsSync(join(cwd, dirPath))) {
228
+ visited.add(dirPath);
229
+ lines.push(`├── ${dirPath}/`.padEnd(35) + `# ${comp.description || comp.name}`);
230
+ }
231
+ }
232
+ // Remove trailing separator
233
+ if (lines.length > 0 && lines[lines.length - 1] === '│') {
234
+ lines.pop();
235
+ }
236
+ return lines.join('\n');
271
237
  }
272
- \`\`\`
273
-
274
- **BEFORE EACH DECISION**: Review recent memories for context
275
- **AFTER EACH ACTION**: Add a memory describing what you did and the outcome
276
-
277
- ### Long-term Memory (GitHub: \`.uam/memory/\`)
278
-
279
- Memories stored as JSON files in the project repository under \`.uam/memory/\`
280
-
281
- File format: \`{YYYY-MM-DD}_{type}_{short-id}.json\`
282
- \`\`\`json
283
- {
284
- "id": "uuid",
285
- "timestamp": "ISO8601",
286
- "type": "fact|lesson|skill|discovery|preference",
287
- "content": "Learning or discovery",
288
- "tags": ["tag1", "tag2"],
289
- "importance": 8
238
+ function getSubdirComment(parentDir, subdir, fullPath) {
239
+ // Check for package.json, README, etc. to get description
240
+ const packageJsonPath = join(fullPath, 'package.json');
241
+ if (existsSync(packageJsonPath)) {
242
+ try {
243
+ const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
244
+ if (pkg.description)
245
+ return pkg.description.slice(0, 40);
246
+ }
247
+ catch {
248
+ // Ignore
249
+ }
250
+ }
251
+ // Default comments based on common patterns
252
+ const patterns = {
253
+ apps: {
254
+ api: 'REST API',
255
+ web: 'Web frontend',
256
+ mobile: 'Mobile app',
257
+ admin: 'Admin dashboard',
258
+ cms: 'CMS',
259
+ },
260
+ services: {
261
+ auth: 'Authentication service',
262
+ gateway: 'API Gateway',
263
+ },
264
+ '.factory': {
265
+ droids: 'Custom AI agents',
266
+ skills: 'Reusable skills',
267
+ commands: 'CLI commands',
268
+ scripts: 'Automation scripts',
269
+ },
270
+ '.github': {
271
+ workflows: 'CI/CD pipelines',
272
+ },
273
+ };
274
+ return patterns[parentDir]?.[subdir] || '';
290
275
  }
291
- \`\`\`
292
-
293
- Memory types: \`fact\`, \`lesson\`, \`skill\`, \`discovery\`, \`preference\`
294
-
295
- ### MANDATORY Memory Triggers
276
+ function buildSkillMappings(skills) {
277
+ if (skills.length === 0)
278
+ return null;
279
+ const lines = [];
280
+ for (const skill of skills) {
281
+ if (skill.name.includes('design') || skill.name.includes('ui')) {
282
+ lines.push(`| UI/Design work (buttons, modals, colors, layouts) | \`${skill.name}\` |`);
283
+ }
284
+ else if (skill.name.includes('frontend') || skill.name.includes('react')) {
285
+ lines.push(`| React/TypeScript/Frontend | \`${skill.name}\` |`);
286
+ }
287
+ else if (skill.name.includes('backend') || skill.name.includes('api')) {
288
+ lines.push(`| Backend/API development | \`${skill.name}\` |`);
289
+ }
290
+ }
291
+ return lines.length > 0 ? lines.join('\n') : null;
292
+ }
293
+ function buildLanguageDroidsTable(droids, languages) {
294
+ const languageDroids = droids.filter(d => d.name.includes('-pro') ||
295
+ d.name.includes('specialist') ||
296
+ languages.some(l => d.name.toLowerCase().includes(l.toLowerCase())));
297
+ if (languageDroids.length === 0 && languages.length > 0) {
298
+ // Generate suggested droids based on detected languages
299
+ const suggestions = [];
300
+ for (const lang of languages.slice(0, 5)) {
301
+ const langLower = lang.toLowerCase();
302
+ if (langLower.includes('typescript') || langLower.includes('javascript')) {
303
+ suggestions.push('| `javascript-pro` | ES6+, async patterns, Node.js, promises, event loops |');
304
+ }
305
+ else if (langLower.includes('python')) {
306
+ suggestions.push('| `python-pro` | Async/await, decorators, generators, pytest, type hints |');
307
+ }
308
+ else if (langLower.includes('c++') || langLower.includes('cpp')) {
309
+ suggestions.push('| `cpp-pro` | C++20 with RAII, smart pointers, STL, templates, move semantics |');
310
+ }
311
+ else if (langLower.includes('rust')) {
312
+ suggestions.push('| `rust-pro` | Ownership, lifetimes, async, error handling, macros |');
313
+ }
314
+ else if (langLower.includes('go')) {
315
+ suggestions.push('| `go-pro` | Concurrency, channels, interfaces, error handling |');
316
+ }
317
+ }
318
+ return suggestions.length > 0 ? [...new Set(suggestions)].join('\n') : null;
319
+ }
320
+ return languageDroids.map(d => `| \`${d.name}\` | ${d.description || `${d.platform} language specialist`} |`).join('\n') || null;
321
+ }
322
+ function buildDiscoveredSkillsTable(skills) {
323
+ if (skills.length === 0)
324
+ return null;
325
+ return skills.slice(0, 10).map(s => {
326
+ const purpose = s.description || `${s.platform} skill`;
327
+ const useWhen = s.name.includes('design') ? 'UI/design work' :
328
+ s.name.includes('test') ? 'Testing and QA' :
329
+ s.name.includes('review') ? 'Code review' :
330
+ 'Specialized tasks';
331
+ return `| \`${s.name}\` | ${purpose} | ${useWhen} |`;
332
+ }).join('\n');
333
+ }
334
+ function buildTroubleshootingSection(memories) {
335
+ // Extract fix-related memories
336
+ const fixes = memories.filter(m => m.tags?.includes('bug-fix') ||
337
+ m.tags?.includes('revert') ||
338
+ m.content.toLowerCase().includes('fix') ||
339
+ m.content.toLowerCase().includes('resolved')).slice(0, 15);
340
+ if (fixes.length === 0)
341
+ return null;
342
+ const lines = [];
343
+ for (const fix of fixes) {
344
+ // Extract symptom and solution from content
345
+ const content = fix.content;
346
+ let symptom = '';
347
+ let solution = '';
348
+ if (content.includes('Bug fixed:')) {
349
+ symptom = content.replace('Bug fixed:', '').split('.')[0].trim();
350
+ solution = content.split('.').slice(1).join('.').trim() || 'See commit for details';
351
+ }
352
+ else if (content.includes('Failed approach')) {
353
+ symptom = content.split(':')[1]?.split('.')[0]?.trim() || content.slice(0, 50);
354
+ solution = 'Avoid this approach';
355
+ }
356
+ else {
357
+ symptom = content.slice(0, 60) + (content.length > 60 ? '...' : '');
358
+ solution = 'See memory for details';
359
+ }
360
+ if (symptom) {
361
+ lines.push(`| ${symptom} | ${solution.slice(0, 60)} |`);
362
+ }
363
+ }
364
+ if (lines.length === 0)
365
+ return null;
366
+ return `| Symptom | Solution |\n|---------|----------|\n${lines.join('\n')}`;
367
+ }
368
+ function buildArchitectureOverview(analysis) {
369
+ const sections = [];
370
+ // Infrastructure overview
371
+ if (analysis.infrastructure.iac || analysis.infrastructure.containerOrchestration) {
372
+ sections.push('### Infrastructure\n');
373
+ if (analysis.infrastructure.iac) {
374
+ sections.push(`- **IaC**: ${analysis.infrastructure.iac}`);
375
+ }
376
+ if (analysis.infrastructure.containerOrchestration) {
377
+ sections.push(`- **Orchestration**: ${analysis.infrastructure.containerOrchestration}`);
378
+ }
379
+ if (analysis.infrastructure.cloud && analysis.infrastructure.cloud.length > 0) {
380
+ sections.push(`- **Cloud**: ${analysis.infrastructure.cloud.join(', ')}`);
381
+ }
382
+ sections.push('');
383
+ }
384
+ // Component overview
385
+ if (analysis.components.length > 0) {
386
+ sections.push('### Components\n');
387
+ for (const comp of analysis.components.slice(0, 8)) {
388
+ sections.push(`- **${comp.name}** (\`${comp.path}\`): ${comp.description || `${comp.language} ${comp.framework || 'application'}`}`);
389
+ }
390
+ sections.push('');
391
+ }
392
+ return sections.length > 0 ? sections.join('\n') : null;
393
+ }
394
+ function buildCoreComponentsSection(analysis) {
395
+ if (analysis.components.length === 0)
396
+ return null;
397
+ const sections = [];
398
+ for (const comp of analysis.components.slice(0, 6)) {
399
+ sections.push(`### ${comp.name} (\`${comp.path}\`)\n`);
400
+ sections.push(`- **Language**: ${comp.language}`);
401
+ if (comp.framework) {
402
+ sections.push(`- **Framework**: ${comp.framework}`);
403
+ }
404
+ if (comp.description) {
405
+ sections.push(`- ${comp.description}`);
406
+ }
407
+ sections.push('');
408
+ }
409
+ return sections.join('\n');
410
+ }
411
+ function buildDatabaseArchitecture(analysis) {
412
+ const lines = [];
413
+ for (const db of analysis.databases) {
414
+ lines.push(`- **${db.type}**: ${db.purpose || 'Primary database'}`);
415
+ }
416
+ return lines.join('\n');
417
+ }
418
+ function buildAuthFlow(analysis) {
419
+ if (!analysis.authentication)
420
+ return '';
421
+ const sections = [];
422
+ sections.push(`**Provider**: ${analysis.authentication.provider}\n`);
423
+ if (analysis.authentication.description) {
424
+ sections.push(analysis.authentication.description);
425
+ }
426
+ return sections.join('\n');
427
+ }
428
+ function buildKeyConfigFiles(analysis) {
429
+ const files = [];
430
+ // Add key files from analysis
431
+ for (const kf of analysis.keyFiles.slice(0, 15)) {
432
+ files.push({ file: kf.file, purpose: kf.purpose });
433
+ }
434
+ if (files.length === 0)
435
+ return null;
436
+ return files.map(f => `| \`${f.file}\` | ${f.purpose} |`).join('\n');
437
+ }
438
+ function buildEssentialCommands(analysis) {
439
+ const commands = [];
440
+ // Test command
441
+ if (analysis.commands.test && analysis.commands.test !== 'npm test') {
442
+ commands.push(`# Tests\n${analysis.commands.test}`);
443
+ }
444
+ // Lint command
445
+ if (analysis.commands.lint) {
446
+ commands.push(`# Linting\n${analysis.commands.lint}`);
447
+ }
448
+ // Build command
449
+ if (analysis.commands.build) {
450
+ commands.push(`# Build\n${analysis.commands.build}`);
451
+ }
452
+ // Infrastructure command
453
+ if (analysis.infrastructure.iac === 'Terraform') {
454
+ const infraPath = analysis.directories.infrastructure[0] || 'infra/terraform';
455
+ commands.push(`# Terraform\ncd ${infraPath} && terraform plan`);
456
+ }
457
+ return commands.length > 0 ? commands.join('\n\n') : null;
458
+ }
459
+ function buildClusterContexts(analysis) {
460
+ if (!analysis.clusters?.enabled || !analysis.clusters.contexts)
461
+ return null;
462
+ return analysis.clusters.contexts.map(c => `kubectl config use-context ${c.context} # ${c.name} (${c.purpose})`).join('\n');
463
+ }
464
+ function buildProjectUrls(analysis) {
465
+ if (analysis.urls.length === 0)
466
+ return null;
467
+ return analysis.urls.map(u => `- **${u.name}**: ${u.value}`).join('\n');
468
+ }
469
+ function buildKeyWorkflows(analysis) {
470
+ if (!analysis.ciCd?.workflows || analysis.ciCd.workflows.length === 0)
471
+ return null;
472
+ return analysis.ciCd.workflows.slice(0, 10).map(w => `├── ${w.file}`.padEnd(35) + `# ${w.purpose}`).join('\n');
473
+ }
474
+ function buildInfraWorkflow(analysis) {
475
+ if (analysis.directories.infrastructure.length === 0)
476
+ return null;
477
+ const infraPath = analysis.directories.infrastructure[0];
478
+ const planCmd = analysis.infrastructure.iac === 'Terraform' ? 'terraform plan' :
479
+ analysis.infrastructure.iac === 'Pulumi' ? 'pulumi preview' :
480
+ 'infrastructure plan';
481
+ return `1. **Create worktree** for infrastructure changes
482
+ 2. Update infrastructure in \`${infraPath}/\`
483
+ 3. Update CI/CD workflows in \`.github/workflows/\`
484
+ 4. Run \`${planCmd}\`
485
+ 5. Update secrets via GitHub Actions (not locally)
486
+ 6. **Create PR** with automated review`;
487
+ }
488
+ function buildMcpPlugins(cwd) {
489
+ const mcpPath = join(cwd, '.mcp.json');
490
+ if (!existsSync(mcpPath))
491
+ return null;
492
+ try {
493
+ const mcp = JSON.parse(readFileSync(mcpPath, 'utf-8'));
494
+ if (!mcp.mcpServers && !mcp.plugins)
495
+ return null;
496
+ const plugins = mcp.mcpServers || mcp.plugins || {};
497
+ const lines = [];
498
+ for (const [name, config] of Object.entries(plugins)) {
499
+ const desc = config.description ||
500
+ config.purpose ||
501
+ 'MCP plugin';
502
+ lines.push(`| \`${name}\` | ${desc} |`);
503
+ }
504
+ return lines.length > 0 ? lines.join('\n') : null;
505
+ }
506
+ catch {
507
+ return null;
508
+ }
509
+ }
510
+ function buildPrimarySkills(skills) {
511
+ const primary = skills.filter(s => s.name.includes('design') ||
512
+ s.name.includes('frontend') ||
513
+ s.name.includes('ui')).slice(0, 3);
514
+ if (primary.length === 0)
515
+ return null;
516
+ return primary.map(s => `│ ├─ Use ${s.name} for ${s.description || 'specialized work'} │`).join('\n');
517
+ }
518
+ function buildLanguageExamples(languages) {
519
+ const examples = [];
520
+ for (const lang of languages.slice(0, 3)) {
521
+ const langLower = lang.toLowerCase();
522
+ if (langLower.includes('c++') || langLower.includes('cpp')) {
523
+ examples.push(`# For C++ work\nTask(subagent_type: "cpp-pro", prompt: "Refactor X using RAII...")`);
524
+ }
525
+ else if (langLower.includes('python')) {
526
+ examples.push(`# For Python work\nTask(subagent_type: "python-pro", prompt: "Optimize async handlers...")`);
527
+ }
528
+ else if (langLower.includes('rust')) {
529
+ examples.push(`# For Rust work\nTask(subagent_type: "rust-pro", prompt: "Implement with proper lifetimes...")`);
530
+ }
531
+ }
532
+ return examples.length > 0 ? examples.join('\n\n') : null;
533
+ }
534
+ function buildPrepopulatedKnowledge(prepopulated) {
535
+ if (!prepopulated)
536
+ return null;
537
+ const { shortTerm, longTerm } = prepopulated;
538
+ // Recent activity from short-term
539
+ const recentActivity = shortTerm
540
+ .filter(m => m.type === 'action' || m.type === 'observation')
541
+ .slice(0, 10)
542
+ .map(m => `- ${m.content.slice(0, 100)}${m.content.length > 100 ? '...' : ''}`)
543
+ .join('\n');
544
+ // Learned lessons from long-term
545
+ const learnedLessons = longTerm
546
+ .filter(m => m.tags?.includes('bug-fix') || m.tags?.includes('lesson') || (m.importance && m.importance >= 7))
547
+ .slice(0, 10)
548
+ .map(m => `- **${m.tags?.slice(0, 2).join(', ') || 'General'}**: ${m.content.slice(0, 80)}...`)
549
+ .join('\n');
550
+ // Known gotchas (from reverts and high-importance fixes)
551
+ const knownGotchas = longTerm
552
+ .filter(m => m.tags?.includes('revert') || m.tags?.includes('failed-approach') || m.content.includes('avoid'))
553
+ .slice(0, 5)
554
+ .map(m => `- ⚠️ ${m.content.slice(0, 100)}`)
555
+ .join('\n');
556
+ // Hot spots
557
+ const hotSpotMemory = longTerm.find(m => m.id === 'git-hotspots');
558
+ const hotSpots = hotSpotMemory?.content || 'No hot spots detected yet.';
559
+ if (!recentActivity && !learnedLessons && !knownGotchas) {
560
+ return null;
561
+ }
562
+ return {
563
+ recentActivity: recentActivity || 'No recent activity recorded.',
564
+ learnedLessons: learnedLessons || 'No lessons recorded yet.',
565
+ knownGotchas: knownGotchas || 'No gotchas recorded yet.',
566
+ hotSpots,
567
+ };
568
+ }
569
+ function getDesktopTemplate() {
570
+ // Check locations in order:
571
+ // 1. User's project templates directory
572
+ // 2. Package's templates directory (for npm installed version)
573
+ const userTemplatePath = join(process.cwd(), 'templates/CLAUDE.template.md');
574
+ const packageTemplatePath = join(__dirname, '../../templates/CLAUDE.template.md');
575
+ if (existsSync(userTemplatePath)) {
576
+ return readFileSync(userTemplatePath, 'utf-8');
577
+ }
578
+ if (existsSync(packageTemplatePath)) {
579
+ return readFileSync(packageTemplatePath, 'utf-8');
580
+ }
581
+ // Fallback inline template for desktop
582
+ return `<coding_guidelines>
296
583
 
297
- **ALWAYS store to long-term memory when you:**
298
- 1. Fix a bug or resolve an error (lesson)
299
- 2. Discover how a system/component works (discovery)
300
- 3. Learn a configuration requirement (fact)
301
- 4. Find a successful approach to a problem (skill)
302
- 5. Identify a coding pattern or convention (preference)
303
- 6. Complete infrastructure changes (fact)
304
- 7. Debug authentication/networking issues (lesson)
584
+ # CLAUDE.md - {{PROJECT_NAME}} Development Guide
305
585
 
306
- **Memory storage is part of task completion.** A task is NOT complete until learnings are stored.
586
+ You are Autonomous Claude, a self-directed AI agent with full control over this virtual machine. You operate continuously, making your own decisions.
307
587
 
308
- When you discover something significant, recommend the user commit a memory file to \`.uam/memory/\`.
588
+ {{#if ISSUE_TRACKER}}
589
+ **Note**: {{{ISSUE_TRACKER}}}
309
590
  {{/if}}
310
591
 
311
592
  ---
312
593
 
313
- {{#if IS_DESKTOP_PLATFORM}}
314
- ## BROWSER USAGE
594
+ ## ⚠️⚠️⚠️ CRITICAL: MANDATORY DECISION LOOP ⚠️⚠️⚠️
315
595
 
316
- When using browser automation:
596
+ **FOLLOW THIS FOR EVERY ACTION. NO EXCEPTIONS.**
317
597
 
318
- - ALWAYS save a screenshot after EVERY browser action
319
- - Save screenshots to: \`agents/data/screenshots/\`
320
- - Filename format: \`{timestamp}_{action}.png\`
598
+ 1. **READ MEMORY FIRST**
599
+ - Query short-term: \`sqlite3 {{MEMORY_DB_PATH}} "SELECT * FROM memories ORDER BY id DESC LIMIT 20;"\`
600
+ - Query long-term: \`{{MEMORY_QUERY_CMD}} "<keywords>"\`
321
601
 
322
- ---
602
+ 2. **CHECK SKILLS** before implementing (see \`{{SKILLS_PATH}}\`)
323
603
 
324
- {{/if}}
325
- ## DECISION LOOP
326
-
327
- 1. **READ** short-term memory (recent context)
328
- 2. **QUERY** long-term memory (semantic search for relevant learnings)
329
- 3. **THINK** about what to do next
330
- 4. **ACT** - execute your decision
331
- 5. **RECORD** - write to short-term memory
332
- 6. **STORE** - add significant learnings to long-term memory (MANDATORY, not optional)
333
- {{#if IS_DESKTOP_PLATFORM}}
334
- 7. **IF BROWSER ACTION**: Save screenshot to \`/agents/data/screenshots/\`
335
- {{/if}}
604
+ 3. **CREATE WORKTREE** for ANY code changes
605
+ - \`{{WORKTREE_CREATE_CMD}} <slug>\`
606
+ - NEVER commit directly to {{DEFAULT_BRANCH}}
336
607
 
337
- **Task Completion Checklist:**
338
- - [ ] Short-term memory updated with action outcome
339
- - [ ] Long-term memory updated with any lessons/discoveries/facts learned
340
- - [ ] Tests pass (if code changes)
341
- - [ ] Documentation updated (if applicable)
608
+ 4. **UPDATE MEMORY** after significant actions
609
+ - \`{{MEMORY_STORE_CMD}} lesson "What you learned" --tags tag1,tag2 --importance 7\`
342
610
 
343
611
  ---
344
612
 
345
- {{#if HAS_SKILLS}}
346
- ## SKILLS
347
-
348
- You have access to reusable skills. Before attempting complex tasks:
349
-
350
- 1. Check if a skill exists for it (see \`.factory/skills/\`)
351
- 2. Follow the skill's patterns - they're tested and reliable
352
- 3. If you discover a better approach, consider creating/updating a skill
613
+ ## Memory System
353
614
 
354
- Available skills are auto-discovered. When you see a SKILL.md, follow its instructions.
355
-
356
- {{#each SKILLS}}
357
- - \`{{this}}\`
358
- {{/each}}
359
-
360
- ---
361
-
362
- {{/if}}
363
- **MANDATORY WORKFLOW REQUIREMENTS**:
364
-
365
- {{#if IS_DESKTOP_PLATFORM}}
366
- 1. **Git Worktrees**: ALL code changes MUST use isolated git worktrees (\`{{WORKTREE_PREFIX}}NNN-slug\` branches)
367
- 2. **PR-Based Merges**: NO direct commits to \`{{DEFAULT_BRANCH}}\`. All changes via PR with automated review
368
- 3. **CI/CD Pipelines**: ALWAYS use CI/CD pipelines to deploy. Create ephemeral pipelines when needed
369
- 4. **Automated Review**: PRs require signoff from reviewer agents before merge
370
- {{else}}
371
- 1. **Feature Branches**: ALL code changes MUST use isolated feature branches (\`{{WORKTREE_PREFIX}}description\`)
372
- 2. **PR-Based Merges**: NO direct commits to \`{{DEFAULT_BRANCH}}\`. All changes via PR
373
- 3. **Code Review**: PRs should be reviewed before merge
374
- {{/if}}
615
+ - **Short-term**: \`{{MEMORY_DB_PATH}}\` (SQLite, last {{SHORT_TERM_LIMIT}} entries)
616
+ - **Long-term**: {{LONG_TERM_BACKEND}} at \`{{LONG_TERM_ENDPOINT}}\`
375
617
 
376
618
  ---
377
619
 
620
+ ## Repository Structure
378
621
 
379
- ## Quick Reference
380
-
381
- {{#if HAS_CLUSTERS}}
382
- ### Cluster Contexts
383
-
384
- \`\`\`bash
385
- {{#each CLUSTERS}}
386
- kubectl config use-context {{this.context}} # {{this.name}} ({{this.purpose}})
387
- {{/each}}
622
+ \`\`\`
623
+ {{PROJECT_NAME}}/
624
+ {{{@REPOSITORY_STRUCTURE}}}
388
625
  \`\`\`
389
626
 
390
- {{/if}}
391
- {{#if HAS_URLS}}
392
- ### URLs
393
-
394
- {{#each URLS}}
395
- - **{{this.name}}**: {{this.value}}
396
- {{/each}}
627
+ {{#if ARCHITECTURE_OVERVIEW}}
628
+ ## Architecture
397
629
 
630
+ {{{ARCHITECTURE_OVERVIEW}}}
398
631
  {{/if}}
399
- {{#if HAS_KEY_FILES}}
400
- ### Key Files
401
632
 
402
- {{#each KEY_FILES}}
403
- - \`{{this.path}}\` - {{this.description}}
404
- {{/each}}
633
+ {{#if CORE_COMPONENTS}}
634
+ ## Components
405
635
 
636
+ {{{CORE_COMPONENTS}}}
406
637
  {{/if}}
407
- {{#if IS_DESKTOP_PLATFORM}}
408
- ### Essential Commands
409
-
410
- \`\`\`bash
411
- # Create worktree for new task (MANDATORY for all changes)
412
- uam worktree create <slug>
413
-
414
- # Testing
415
- {{TEST_COMMAND}}
416
638
 
417
- # Linting
418
- {{LINT_COMMAND}}
419
-
420
- # Building
421
- {{BUILD_COMMAND}}
422
- {{#if HAS_TERRAFORM}}
639
+ {{#if TROUBLESHOOTING}}
640
+ ## Troubleshooting
423
641
 
424
- # Terraform
425
- cd {{INFRA_PATH}} && terraform plan
642
+ {{{TROUBLESHOOTING}}}
426
643
  {{/if}}
427
- \`\`\`
428
644
 
429
- {{/if}}
430
645
  ---
431
646
 
432
- {{#if HAS_COMPONENTS}}
433
- ## Architecture
434
-
435
- {{#each COMPONENTS}}
436
- ### {{this.name}} (\`{{this.path}}\`)
437
-
438
- - **Language**: {{this.language}}
439
- {{#if this.framework}}- **Framework**: {{this.framework}}{{/if}}
440
- - {{this.description}}
647
+ ## Completion Checklist
441
648
 
442
- {{/each}}
443
- ---
649
+ - [ ] Tests pass
650
+ - [ ] Worktree used
651
+ - [ ] Memory updated
652
+ - [ ] PR created (not direct commit)
444
653
 
445
- {{/if}}
446
- {{#if HAS_DATABASES}}
447
- ## Data Layer
654
+ </coding_guidelines>
655
+ `;
656
+ }
657
+ function getWebTemplate() {
658
+ return `<coding_guidelines>
448
659
 
449
- {{#each DATABASES}}
450
- - **{{this.type}}**: {{this.purpose}}
451
- {{/each}}
660
+ # AGENT.md - {{PROJECT_NAME}} Development Guide
452
661
 
453
- ---
662
+ You are an AI agent helping with this project. Follow best practices and maintain context.
454
663
 
664
+ {{#if DESCRIPTION}}
665
+ > {{DESCRIPTION}}
455
666
  {{/if}}
456
- {{#if HAS_AUTH}}
457
- ## Authentication
458
-
459
- **Provider**: {{AUTH_PROVIDER}}
460
-
461
- {{AUTH_DESCRIPTION}}
462
667
 
463
668
  ---
464
669
 
465
- {{/if}}
466
- {{#if IS_DESKTOP_PLATFORM}}
467
- {{#if HAS_CICD}}
468
- ## CI/CD ({{CICD_PLATFORM}})
670
+ ## ⛔ MANDATORY RULES
469
671
 
470
- | Workflow | Purpose |
471
- |----------|---------|
472
- {{#each WORKFLOWS}}
473
- | \`{{this.file}}\` | {{this.purpose}} |
474
- {{/each}}
672
+ 1. **BRANCH REQUIREMENT**: Never commit directly to {{DEFAULT_BRANCH}}. Use feature branches.
673
+ 2. **MEMORY**: Store significant learnings to \`.uam/memory/\`
674
+ 3. **TODO LIST**: Create todo list for multi-step tasks (3+ steps)
475
675
 
476
676
  ---
477
677
 
478
- {{/if}}
479
- {{/if}}
480
- {{#if HAS_TROUBLESHOOTING}}
481
- ## Troubleshooting
678
+ ## Memory System
482
679
 
483
- | Symptom | Solution |
484
- |---------|----------|
485
- {{#each TROUBLESHOOTING_HINTS}}
486
- | {{this.symptom}} | {{this.solution}} |
487
- {{/each}}
680
+ ### Short-term (localStorage)
488
681
 
489
- ---
490
-
491
- {{/if}}
492
- ## Required Workflow (MANDATORY)
682
+ Key: \`agent_context_{{PROJECT_NAME}}\`
493
683
 
494
- {{#if IS_DESKTOP_PLATFORM}}
495
- ### Git Worktree Workflow (ALL Changes)
684
+ ### Long-term (GitHub: \`.uam/memory/\`)
496
685
 
497
- **Every code change MUST follow this workflow:**
686
+ Store memories as JSON files for persistent knowledge.
498
687
 
499
- \`\`\`
500
- 1. CREATE WORKTREE
501
- uam worktree create <slug>
502
- → Creates {{WORKTREE_PREFIX}}NNN-slug branch in {{WORKTREE_DIR}}/NNN-slug/
503
-
504
- 2. DEVELOP
505
- cd {{WORKTREE_DIR}}/NNN-slug/
506
- → Make changes, commit locally
507
-
508
- 3. CREATE PR (runs tests + triggers reviewers)
509
- uam worktree pr <id>
510
- → Runs all offline tests (blocks if fail)
511
- → Pushes to origin
512
- → Creates PR with auto-generated description
513
- → Triggers reviewer agents
514
-
515
- 4. AUTOMATED REVIEW
516
- → Reviewer agents run in parallel (quality, security, performance, tests)
517
- → PR labeled: reviewer-approved OR needs-work
518
- → Auto-merge on approval
519
-
520
- 5. CLEANUP
521
- uam worktree cleanup <id>
522
- → Removes worktree and deletes branch
523
- \`\`\`
524
- {{else}}
525
- ### Git Branch Workflow (ALL Changes)
688
+ ---
526
689
 
527
- **Every code change MUST follow this workflow:**
690
+ ## Repository Structure
528
691
 
529
692
  \`\`\`
530
- 1. CREATE BRANCH
531
- git checkout -b {{WORKTREE_PREFIX}}<description>
532
- → Creates isolated feature branch
533
-
534
- 2. DEVELOP
535
- → Make changes, commit locally
536
- → Keep commits atomic and well-described
537
-
538
- 3. CREATE PR
539
- git push -u origin {{WORKTREE_PREFIX}}<description>
540
- → Push to remote
541
- → Create PR via GitHub/GitLab UI
542
-
543
- 4. CODE REVIEW
544
- → Request review from team members
545
- → Address feedback
546
-
547
- 5. MERGE & CLEANUP
548
- → Merge PR after approval
549
- → Delete feature branch
693
+ {{PROJECT_NAME}}/
694
+ {{{@REPOSITORY_STRUCTURE}}}
550
695
  \`\`\`
551
- {{/if}}
552
696
 
553
- ### Before ANY Task
697
+ {{#if ARCHITECTURE_OVERVIEW}}
698
+ ## Architecture
554
699
 
555
- 1. Read relevant docs in \`/docs\` and component folders
556
- 2. Check for known issues in troubleshooting section
557
- {{#if IS_DESKTOP_PLATFORM}}
558
- 3. **Create a worktree for your changes**
559
- {{else}}
560
- 3. **Create a feature branch for your changes**
700
+ {{{ARCHITECTURE_OVERVIEW}}}
561
701
  {{/if}}
562
702
 
563
- ### For Code Changes
703
+ {{#if CORE_COMPONENTS}}
704
+ ## Components
564
705
 
565
- {{#if IS_DESKTOP_PLATFORM}}
566
- 1. **Create worktree**: \`uam worktree create <slug>\`
567
- {{else}}
568
- 1. **Create branch**: \`git checkout -b {{WORKTREE_PREFIX}}<description>\`
569
- {{/if}}
570
- 2. Update/create tests
571
- 3. Run \`{{TEST_COMMAND}}\`
572
- 4. Run linting and type checking
573
- {{#if IS_DESKTOP_PLATFORM}}
574
- 5. **Create PR**: \`uam worktree pr <id>\`
575
- {{else}}
576
- 5. **Create PR**: Push branch and open PR
706
+ {{{CORE_COMPONENTS}}}
577
707
  {{/if}}
578
708
 
579
- {{#if HAS_TERRAFORM}}
580
- ### For Infrastructure Changes
581
-
582
- {{#if IS_DESKTOP_PLATFORM}}
583
- 1. **Create worktree** for Terraform changes
584
- {{else}}
585
- 1. **Create branch** for Terraform changes
586
- {{/if}}
587
- 2. Update Terraform in \`{{INFRA_PATH}}\`
588
- 3. Update CI/CD workflows if needed
589
- 4. Run \`terraform plan\`
590
- 5. Update secrets via GitHub Actions (not locally)
591
- 6. **Create PR** with review
592
-
593
- {{/if}}
594
- ### Before Completing
595
-
596
- 1. All tests pass
597
- 2. PR created and reviewed
598
- 3. Update relevant documentation
599
-
600
709
  ---
601
710
 
711
+ ## Workflow
602
712
 
603
- {{#if HAS_DROIDS}}
604
- ## Augmented Agent Capabilities
605
-
606
- ### Custom Droids (\`.factory/droids/\`)
607
-
608
- {{#each DROIDS}}
609
- - \`{{this}}\`
610
- {{/each}}
611
-
612
- {{#if HAS_COMMANDS}}
613
- ### Commands (\`.factory/commands/\`)
614
-
615
- {{#each COMMANDS}}
616
- - \`/{{this}}\`
617
- {{/each}}
618
- {{/if}}
713
+ 1. Create feature branch: \`git checkout -b {{BRANCH_PREFIX}}<description>\`
714
+ 2. Make changes, commit, push
715
+ 3. Create PR via GitHub UI
619
716
 
620
717
  ---
621
718
 
622
- {{/if}}
623
- ## Completion Checklist
624
-
625
- \`\`\`
626
- [ ] Tests updated and passing
627
- [ ] Linting/type checking passed
628
- {{#if HAS_TERRAFORM}}
629
- [ ] Terraform plan verified (if infra changed)
630
- {{/if}}
631
- [ ] Documentation updated
632
- [ ] No secrets in code/commits
633
- \`\`\`
634
-
635
- ---
719
+ ## Quick Reference
636
720
 
637
- **Languages**: {{LANGUAGES}}
638
- **Frameworks**: {{FRAMEWORKS}}
721
+ - **Test**: \`{{TEST_COMMAND}}\`
722
+ - **Build**: \`{{BUILD_COMMAND}}\`
723
+ - **Lint**: \`{{LINT_COMMAND}}\`
639
724
 
640
725
  </coding_guidelines>
641
726
  `;