| name | agent-memory-skills |
| description | Self-improving agent architecture using ChromaDB for continuous learning, self-evaluation, and improvement storage. Agents maintain separate memory collections for learned patterns, performance metrics, and self-assessments without modifying their static .md configuration. |
| license | MIT |
Agent Memory & Continuous Self-Improvement Skills
Purpose: Enable agents to learn from experience, evaluate themselves continuously, and store improvements in ChromaDB collections separate from static configuration files.
Philosophy: Static configuration (.md) for capabilities; dynamic memory (ChromaDB) for learned experiences.
Architecture Overview
The Dual-Layer Model
┌──────────────────────────────────────────────────────────┐
│ Layer 1: Static Agent Configuration (.md files) │
│ - Core capabilities, workflows, prompt templates │
│ - Human-designed, expert-reviewed │
│ - Version controlled (Git) │
│ - Changes: Infrequent (weeks/months) │
└──────────────────────────────────────────────────────────┘
↓ loads at runtime
┌──────────────────────────────────────────────────────────┐
│ Layer 2: Dynamic Agent Memory (ChromaDB) │
│ - Learned improvements, preferences, patterns │
│ - Self-evaluation results, performance metrics │
│ - Agent-managed, auto-updated │
│ - Changes: Continuous (every task completion) │
└──────────────────────────────────────────────────────────┘
Memory Collection Structure
Each agent gets 3 ChromaDB collections:
agent_{name}_improvements: Learned patterns and strategies
agent_{name}_evaluations: Self-assessment results
agent_{name}_performance: Metrics over time
Collection 1: Improvements Storage
When to Store Improvements
Store when:
- ✅ Task completed successfully with clear learning
- ✅ User feedback received (positive or negative)
- ✅ New pattern discovered (not in static config)
- ✅ Confidence score ≥ 0.7 (high confidence learning)
Don't store:
- ❌ Failed tasks without clear lessons
- ❌ Routine operations following existing patterns
- ❌ Low confidence observations (< 0.5)
Improvement Schema
const improvement = {
document: `
When user asks for "latest" information, prioritize sources from 2025
over 2024. Use date filters: where: { year: { "$gte": 2025 } }
`,
id: `improvement_research_${Date.now()}`,
metadata: {
agent_name: "research-specialist",
category: "search_strategy",
learned_from: "feedback_2025-11-18",
confidence: 0.85,
success_rate: null,
usage_count: 0,
created_at: "2025-11-18T15:30:00Z",
last_used: null,
tags: ["recency", "date_filtering", "search"]
}
};
Storage Function
async function storeImprovement(agentName, improvement) {
const collectionName = `agent_${agentName}_improvements`;
const collections = await mcp__chroma__list_collections();
if (!collections.includes(collectionName)) {
await mcp__chroma__create_collection({
collection_name: collectionName,
embedding_function_name: "default",
metadata: {
agent: agentName,
purpose: "learned_improvements",
created_at: new Date().toISOString()
}
});
}
await mcp__chroma__add_documents({
collection_name: collectionName,
documents: [improvement.document],
ids: [improvement.id],
metadatas: [improvement.metadata]
});
console.log(`✅ Stored improvement for ${agentName}: ${improvement.category}`);
}
Retrieval Before Task
async function retrieveRelevantImprovements(agentName, taskDescription, limit = 5) {
const collectionName = `agent_${agentName}_improvements`;
try {
const results = await mcp__chroma__query_documents({
collection_name: collectionName,
query_texts: [taskDescription],
n_results: limit,
where: {
"$and": [
{ "confidence": { "$gte": 0.7 } },
{ "success_rate": { "$gte": 0.6 } }
]
},
include: ["documents", "metadatas", "distances"]
});
const relevant = results.ids[0]
.map((id, idx) => ({
id: id,
improvement: results.documents[0][idx],
metadata: results.metadatas[0][idx],
relevance: 1 - results.distances[0][idx]
}))
.filter(item => item.relevance > 0.6);
return relevant;
} catch (error) {
console.log(`No improvements found for ${agentName} (collection may not exist yet)`);
return [];
}
}
Collection 2: Self-Evaluation Storage
Continuous Self-Evaluation Pattern
After every task, agents run self-evaluation:
async function selfEvaluate(agentName, taskContext, taskResult) {
const evaluation = {
task_description: taskContext.description,
task_type: taskContext.type,
success: taskResult.success,
quality_score: taskResult.quality,
time_taken_ms: taskResult.duration,
tokens_used: taskResult.tokens,
strengths: identifyStrengths(taskResult),
weaknesses: identifyWeaknesses(taskResult),
insights: extractInsights(taskResult),
timestamp: new Date().toISOString(),
context: taskContext.additionalContext
};
await storeEvaluation(agentName, evaluation);
if (evaluation.insights.length > 0 && evaluation.quality_score >= 70) {
for (const insight of evaluation.insights) {
await storeImprovement(agentName, {
document: insight.description,
id: `improvement_${agentName}_${Date.now()}`,
metadata: {
agent_name: agentName,
category: insight.category,
learned_from: `task_${evaluation.timestamp}`,
confidence: insight.confidence,
created_at: evaluation.timestamp
}
});
}
}
return evaluation;
}
function identifyStrengths(taskResult) {
const strengths = [];
if (taskResult.time_taken_ms < taskResult.expected_duration) {
strengths.push("Completed faster than expected");
}
if (taskResult.validation_passed) {
strengths.push("All validations passed");
}
if (taskResult.user_feedback?.positive) {
strengths.push(taskResult.user_feedback.comment);
}
return strengths;
}
function identifyWeaknesses(taskResult) {
const weaknesses = [];
if (taskResult.errors.length > 0) {
weaknesses.push(`Encountered ${taskResult.errors.length} errors`);
}
if (taskResult.retries > 0) {
weaknesses.push(`Required ${taskResult.retries} retries`);
}
if (taskResult.user_feedback?.negative) {
weaknesses.push(taskResult.user_feedback.comment);
}
return weaknesses;
}
function extractInsights(taskResult) {
const insights = [];
if (taskResult.errors.some(e => e.type === "ConnectionTimeout") && taskResult.success) {
insights.push({
description: "When encountering ConnectionTimeout, retry with exponential backoff (3 attempts)",
category: "error_handling",
confidence: 0.8
});
}
if (taskResult.optimization_found) {
insights.push({
description: taskResult.optimization_found.description,
category: "optimization",
confidence: 0.9
});
}
return insights;
}
Evaluation Storage
async function storeEvaluation(agentName, evaluation) {
const collectionName = `agent_${agentName}_evaluations`;
await mcp__chroma__add_documents({
collection_name: collectionName,
documents: [
`Task: ${evaluation.task_description}. Result: ${evaluation.success ? 'Success' : 'Failure'}. ` +
`Quality: ${evaluation.quality_score}/100. Insights: ${evaluation.insights.map(i => i.description).join('; ')}`
],
ids: [`eval_${Date.now()}`],
metadatas: [{
agent_name: agentName,
task_type: evaluation.task_type,
success: evaluation.success,
quality_score: evaluation.quality_score,
time_taken_ms: evaluation.time_taken_ms,
tokens_used: evaluation.tokens_used,
strengths_count: evaluation.strengths.length,
weaknesses_count: evaluation.weaknesses.length,
insights_count: evaluation.insights.length,
timestamp: evaluation.timestamp
}]
});
}
Collection 3: Performance Metrics
Aggregate Performance Tracking
async function trackPerformanceMetrics(agentName) {
const collectionName = `agent_${agentName}_evaluations`;
const recentEvals = await mcp__chroma__get_documents({
collection_name: collectionName,
limit: 100,
include: ["metadatas"],
where: {
"timestamp": { "$gte": thirtyDaysAgo() }
}
});
const metrics = {
agent_name: agentName,
period: "30_days",
total_tasks: recentEvals.metadatas.length,
successful_tasks: recentEvals.metadatas.filter(m => m.success).length,
success_rate: 0,
avg_quality: average(recentEvals.metadatas.map(m => m.quality_score)),
quality_trend: calculateTrend(recentEvals.metadatas, 'quality_score'),
avg_time_ms: average(recentEvals.metadatas.map(m => m.time_taken_ms)),
avg_tokens: average(recentEvals.metadatas.map(m => m.tokens_used)),
total_insights: sum(recentEvals.metadatas.map(m => m.insights_count)),
improvements_stored: await countImprovements(agentName, thirtyDaysAgo()),
improving: false,
timestamp: new Date().toISOString()
};
metrics.success_rate = metrics.successful_tasks / metrics.total_tasks;
metrics.improving = metrics.quality_trend > 0 && metrics.success_rate > 0.7;
const perfCollection = `agent_${agentName}_performance`;
await mcp__chroma__add_documents({
collection_name: perfCollection,
documents: [
`Performance snapshot: ${metrics.success_rate * 100}% success, ` +
`quality ${metrics.avg_quality}/100, ${metrics.improvements_stored} improvements`
],
ids: [`perf_${Date.now()}`],
metadatas: [metrics]
});
return metrics;
}
function calculateTrend(evaluations, metric) {
if (evaluations.length < 2) return 0;
const recent = evaluations.slice(0, Math.floor(evaluations.length / 2));
const older = evaluations.slice(Math.floor(evaluations.length / 2));
const recentAvg = average(recent.map(e => e[metric]));
const olderAvg = average(older.map(e => e[metric]));
return recentAvg - olderAvg;
}
Complete Workflow: Agent with Memory
At Agent Initialization
async function initializeAgentMemory(agentName) {
const staticConfig = await loadAgentConfig(`/agents/${agentName}.md`);
const improvements = await retrieveAllImprovements(agentName);
return {
...staticConfig,
learned_improvements: improvements,
memory_enabled: true
};
}
Before Task Execution
async function executeTaskWithMemory(agentName, task) {
const relevantImprovements = await retrieveRelevantImprovements(
agentName,
task.description,
5
);
console.log(`📚 Retrieved ${relevantImprovements.length} relevant improvements`);
const taskResult = await executeTask(task, {
improvements: relevantImprovements.map(i => i.improvement)
});
const evaluation = await selfEvaluate(agentName, task, taskResult);
for (const improvement of relevantImprovements) {
await updateImprovementUsage(agentName, improvement.id, taskResult.success);
}
if (shouldRunDailyMetrics()) {