perfmemory
Skill5 starsChanged 6 months agoMITView on GitHub
Manage the PerfMemory lessons-learned layer — search for past fixes before debugging, store debug sessions and attempts during debugging, and ingest existing knowledge from debug manifests or lessons-learned documents. Use when the user mentions perfmemory, lessons learned, debug memory, ingesting debug manifests, or searching for past fixes.
We split this skill into the rules it gives an agent
44 rules. About 0 are common, 20 are distinctive, and 24 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈20
Distinctive · estimate
This author's own choices. Worth a look.
24
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 25
Before storing any debug session or attempt, agents MUST check taxonomy.yaml for canonical values.
- Distinctive: line 51
If the error/value clearly fits an existing category but uses different wording, use the existing canonical name (the alias system handles …
- Very specific: line 53
If the value is genuinely new and doesn't fit any existing category, inform the user: "This value is not in the taxonomy.
- Distinctive: line 56
NEVER silently insert a non-canonical value without checking.
- Distinctive: line 67
Instead of starting every debug workflow from scratch, agents check memory first and apply known fixes proactively.
- Distinctive: line 76
When a new symptom is encountered, it is embedded and compared against stored vectors
- Very specific: line 120
When graph is enabled, each match includes a source field:
- Distinctive: line 138
Use this workflow when an agent encounters an error and wants to check if a similar issue has been solved before.
- Very specific: line 170
If confirmed_count > 1 and is_verified = true: apply the fix directly
- Very specific: line 171
If confirmed_count = 1 or is_verified = false: present to user for confirmation
- Very specific: line 172
Check the source field: matches found by "both" vector and graph are highest confidence
- Very specific: line 177
If the user approves a fix, apply it and pass the attempt_id as matched_attempt_id when storing the new attempt (Workflow B)
- Distinctive: line 182
If still no results, proceed with normal debugging workflow
- Very specific: line 186
If vector search returned no_match but you have an error_category, check the knowledge graph for cross-project patterns:
- Distinctive: line 198
If matches are returned:
- Very specific: line 201
When enrich = true (default), each match includes symptom_text, diagnosis, fix_description, sampler_name, api_endpoint, confirmed_count, …
- Very specific: line 205
If a match looks promising, use get_related_issues (Step 4) to explore its neighborhood for additional related fixes
- Distinctive: line 210
When a match from Step 2 or Step 3 looks relevant, explore its graph neighborhood to discover additional related fixes that may not have …
- Very specific: line 236
Use this workflow during an active debug session to record what was tried and what worked.
- Very specific: line 243
Before calling: Check taxonomy.yaml for the correct canonical values:
- Very specific: line 293
Before calling: Check taxonomy.yaml → error_categories for an existing canonical name or alias that matches the error.
- Distinctive: line 296
If genuinely new, ask the user before proceeding.
- Very specific: line 329
If matched_attempt_id was provided, the response will also include confirmed_match_id and new_confirmed_count showing the updated …
- Distinctive: line 351
Use this workflow to bulk-load lessons from existing documents into perfmemory.
- Distinctive: line 361
Read the manifest file
- Very specific: line 366
Call store_debug_session with the parsed metadata
- Very specific: line 376
Call store_debug_attempt for each iteration
- Very specific: line 377
Call close_debug_session with the final outcome
- Distinctive: line 401
Read the lessons-learned document
- Distinctive: line 402
Create a single debug session to group all lessons:
- Very specific: line 421
Call close_debug_session with final_outcome = "resolved"
- Distinctive: line 442
When a human confirms that a stored lesson is correct and reliable:
- Distinctive: line 450
When a lesson becomes outdated (API changed, issue no longer occurs):
- Distinctive: line 495
Use this after finding a match to discover additional related fixes, or to understand the structural context of a known issue before …
- Very specific: line 512
When enrich = true, each neighbor includes symptom_text, diagnosis, fix_description, sampler_name, api_endpoint, confirmed_count, …
- Distinctive: line 519
Use this as a fallback when vector search returns no matches, or proactively when starting work on a new project to check for known …
- Very specific: line 534
When enrich = true, each match includes symptom_text, diagnosis, fix_description, sampler_name, api_endpoint, confirmed_count, is_verified, …
- Very specific: line 542
If store_debug_session or store_debug_attempt fails, report the error immediately.
- Very specific: line 543
Do NOT retry — these are code-based MCP tools (per mcp-error-handling.mdc).
- Very specific: line 544
If find_similar_attempts fails, proceed with normal debugging (memory is advisory).
- Very specific: line 545
If graph tools (find_cross_project_patterns, get_related_issues) fail or return "Graph layer is not enabled", fall back to vector-only …
- Distinctive: line 547
If the database is unreachable, skip all perfmemory operations and inform the user.
- Distinctive: line 548
Do not block the debugging workflow because memory is unavailable.
- Distinctive: line 549
Never modify the perfmemory MCP source code to work around errors.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
PerfMemory — Lessons Learned Memory Layer
When to Use This Skill
- User asks to search memory for past fixes before debugging
- User asks to store a debug session or attempt in memory
- User asks to ingest a debug manifest or lessons-learned document into memory
- User asks to review, verify, or archive stored lessons
- User asks for memory statistics or session details
- The
jmeter-debuggingskill references PerfMemory integration steps
Taxonomy Compliance
Before storing any debug session or attempt, agents MUST check taxonomy.yaml for
canonical values. Do NOT invent new freeform values for taxonomy-controlled fields.
Rules
error_category— Checktaxonomy.yaml→error_categoriesfor an existing canonical name or alias that matches the error. Use the canonical name. If the error fits an existing category (even approximately), use it. Do NOT create a new category name without confirming with the user first.environment— Accepts either a specific environment name fromtaxonomy.yaml→environments(e.g., "QA1", "STG-East") or a canonical type fromenvironment_types(e.g.,qa,staging). The MCP resolves the input via a 3-step process: (1) match specific environment name, (2) match canonical type, (3) literal fallback. Theenv_typecolumn is auto-derived — do NOT pass it manually tostore_debug_session.auth_flow_type— Use values fromtaxonomy.yaml→auth_flow_types. Common values:none,oauth_pkce,entra_id,saml,token_chain,custom_sso. If unsure, check the taxonomy aliases list before guessing.system_under_test— Use the canonical application name fromtaxonomy.yaml→applications[].name. If the application is registered, use its exact canonical name.
What to Do When a Value Doesn't Match
- If the error/value clearly fits an existing category but uses different wording, use the existing canonical name (the alias system handles resolution).
- If the value is genuinely new and doesn't fit any existing category, inform the user: "This value is not in the taxonomy. Should I use [closest existing category] or would you like to add a new entry to taxonomy.yaml first?"
- NEVER silently insert a non-canonical value without checking.
Reference
What PerfMemory Does
PerfMemory is a persistent memory layer backed by PostgreSQL + pgvector + Apache AGE. It stores structured debug sessions, attempts, and vector embeddings of symptoms so AI agents can recall past fixes via semantic similarity search and graph traversal. Instead of starting every debug workflow from scratch, agents check memory first and apply known fixes proactively.
How It Works
- Symptom text is embedded into a vector using the configured embedding provider
- The vector is stored alongside structured metadata (diagnosis, fix, outcome, etc.)
- Graph nodes and edges are created in the Apache AGE knowledge graph, linking attempts to projects, error patterns, and fix patterns
- When a new symptom is encountered, it is embedded and compared against stored vectors
- Graph traversal finds structurally related issues across projects — even when the symptom text is phrased differently
- Matches are ranked by a combined vector + graph score and returned with their fix details
Structured Symptom Text Template
The symptom_text field is the ONLY field that gets embedded as a vector. Its structure
directly affects search quality. Always use this format:
[Error Category] on [Sampler Name] — [Response Code].
[Error Message / Symptom Description].
[Brief Diagnosis Context].Good example:
Missing Correlations (OAuth Parameters) on TC01_S02_GET /oauth2/authorize
— java.net.URISyntaxException. Illegal character in query caused by unresolved
${oauth_redirect_uri}, ${oauth_client_id}, ${oauth_response_mode}, ${oauth_nonce},
${oauth_state}. The redirect URL from GET /home contains all OAuth parameters
URL-encoded in the goto query parameter but no extractors existed.Bad example (too vague):
OAuth error on login page. Variables not found.Similarity Score Interpretation
| Score Range | Recommendation | Action |
> 0.85 or source: "both" | apply_known_fix | Apply the fix directly, especially if confirmed_count > 1 |
| 0.60 - 0.85 | review_suggestions | Present matches to user or review before applying |
| < 0.60 | no_match | No useful matches — proceed with normal debugging |
The default threshold is set in perfmemory-mcp/config.yaml under search.similarity_threshold.
Match Source Field
When graph is enabled, each match includes a source field:
| Source | Meaning |
vector | Found via pgvector cosine similarity only |
graph | Found via Apache AGE graph traversal only |
both | Found by both vector search and graph traversal (highest confidence) |
Related Rules
prerequisites.mdc—test_run_idis required for all workflowsskill-execution-rules.mdc— Follow steps in order, do not skipmcp-error-handling.mdc— MCP tool error handling (no retry for code-based tools)
Workflow A — Search Memory Before Debugging
Use this workflow when an agent encounters an error and wants to check if a similar issue has been solved before. This is called BEFORE starting a debug loop.
Collect Inputs
REQUIRED:
symptom_text = [the current error symptom — use the structured template above]
OPTIONAL:
system_under_test = [filter to a specific system, e.g. "Shopping Cart"]
system_alias = [filter by app alias/short name, e.g. "OSP", "CART"]
service_name = [filter by microservice name, e.g. "cart-service"]
error_category = [filter to a specific category, e.g. "Missing Correlations"]Step 1 — Search for Similar Attempts
find_similar_attempts(
symptom_text = {symptom_text},
system_under_test = {system_under_test}, # optional
system_alias = {system_alias}, # optional — resolves to system_under_test
service_name = {service_name}, # optional
error_category = {error_category} # optional — aliases resolved automatically
)Step 2 — Interpret Results
If recommendation = apply_known_fix (similarity > 0.85 or source = "both"):
- Review the top match's
diagnosisandfix_description - If
confirmed_count > 1andis_verified = true: apply the fix directly - If
confirmed_count = 1oris_verified = false: present to user for confirmation - Check the
sourcefield: matches found by "both" vector and graph are highest confidence
If recommendation = review_suggestions (similarity 0.60 - 0.85):
- Present the top 2-3 matches to the user with their diagnosis and fix
- Let the user decide which (if any) to apply
- If the user approves a fix, apply it and pass the
attempt_idasmatched_attempt_idwhen storing the new attempt (Workflow B)
If recommendation = no_match:
- Try
find_cross_project_patternsiferror_categoryis known (Step 3) - If still no results, proceed with normal debugging workflow
Step 3 — Cross-Project Pattern Search (Graph)
If vector search returned no_match but you have an error_category, check the
knowledge graph for cross-project patterns:
find_cross_project_patterns(
error_category = {error_category},
current_project = {system_under_test}, # optional — excludes own project
response_code = {response_code}, # optional — omit to match all response codes
enrich = true # optional — fetches full attempt details
)If matches are returned:
- Review the
graph_pathfield to understand how the match was found (e.g.,ErrorPattern(Missing Correlations/*)orSIMILAR_TO(hops<=2)) - When
enrich = true(default), each match includessymptom_text,diagnosis,fix_description,sampler_name,api_endpoint,confirmed_count,is_verified,system_alias,service_name,test_case_id, andtest_case_namefrom the relational store — enough context to decide whether to apply the fix - If a match looks promising, use
get_related_issues(Step 4) to explore its neighborhood for additional related fixes
Step 4 — Explore Graph Neighborhood (Optional)
When a match from Step 2 or Step 3 looks relevant, explore its graph neighborhood to discover additional related fixes that may not have surfaced in the initial search:
get_related_issues(
attempt_id = {matched_attempt_id},
include_same_project = true, # set false for cross-project only
enrich = true # optional — fetches full neighbor details
)This returns:
- error_patterns: The error categories and response codes linked to this attempt
- fix_patterns: The fix types and component types that resolved it
- neighbors: Other attempts connected via SIMILAR_TO edges, with full details
when
enrich = true(symptom, diagnosis, fix, confidence signals)
Use this when:
- A match was found but you want to see if there are related fixes for the same class of issue
- You want to understand the full context of an error pattern before applying a fix
- You want to check if the same fix type has been applied successfully in other projects
Workflow B — Store Lessons During Debugging
Use this workflow during an active debug session to record what was tried and what
worked. This is integrated into the jmeter-debugging skill at specific steps.
Step 1 — Open a Debug Session
Called once at the start of debugging.
Before calling: Check taxonomy.yaml for the correct canonical values:
system_under_test→ useapplications[].nameif the app is registeredenvironment→ use a specific name fromenvironments(e.g., "QA1", "STG-East") or a canonical type fromenvironment_types(e.g., "qa", "staging"). The MCP auto-derivesenv_typefrom the input — do NOT passenv_typemanually.auth_flow_type→ use a value fromauth_flow_types(none, oauth_pkce, entra_id, saml, etc.)
REQUIRED:
system_under_test = [what is being tested, e.g. "Shopping Cart"]
test_run_id = [the artifact test run ID]
OPTIONAL:
system_alias = [short name/alias, e.g. "OSP"]
service_name = [microservice name, e.g. "cart-service"]
script_name = [the JMX filename]
auth_flow_type = [none, oauth_pkce, oauth_auth_code, saml, token_chain,
custom_sso, entra_id, msal_pkce, other]
auth_alias = [human-readable auth label, e.g. "Corporate SSO"]
environment = [specific env name (e.g. "QA1", "STG-East") or
canonical type (e.g. "qa", "staging") — env_type is
auto-derived via taxonomy resolution]
created_by = [PTE name or "cursor"]
notes = [freeform session notes]
strict_taxonomy = [true/false — override config-level strictness]store_debug_session(
system_under_test = {system_under_test},
test_run_id = {test_run_id},
system_alias = {system_alias},
service_name = {service_name},
script_name = {script_name},
auth_flow_type = {auth_flow_type},
auth_alias = {auth_alias},
environment = {environment},
created_by = {created_by},
notes = {notes},
strict_taxonomy = {strict_taxonomy}
)Save: session_id from the response.
Check: taxonomy_warnings in the response — if present, review and note for future taxonomy updates.
Step 2 — Store Each Debug Attempt
Called after each debug iteration (after applying a fix and observing the result).
Before calling: Check taxonomy.yaml → error_categories for an existing canonical
name or alias that matches the error. Use the canonical name. Do NOT invent new error
category names — if the error fits an existing category (even approximately), use it.
If genuinely new, ask the user before proceeding.
store_debug_attempt(
session_id = {session_id},
iteration_number = {iteration_count},
symptom_text = {structured symptom — use the template},
outcome = {resolved | failed | environment_issue | test_data_issue |
authentication_issue | needs_investigation},
error_category = {from taxonomy.yaml error_categories — use canonical name},
severity = {Critical | High | Medium},
response_code = {HTTP status code or exception name},
hostname = {host where the error occurred},
sampler_name = {the failing JMeter sampler},
api_endpoint = {the failing URL/endpoint},
diagnosis = {root cause determination — plain language},
fix_description = {what fix was applied — plain language},
fix_type = {add_extractor | move_extractor | edit_request_body |
edit_header | edit_correlation | other},
component_type = {json_extractor | regex_extractor | jsr223_postprocessor |
jsr223_preprocessor | http_sampler | test_plan | other},
test_case_id = {optional — e.g. "TC01"},
test_case_name = {optional — e.g. "User Login Flow"},
test_step_id = {optional — e.g. "S03"},
test_step_name = {optional — e.g. "Submit Credentials"},
manifest_excerpt = {optional — raw manifest iteration text},
matched_attempt_id = {optional — UUID of a memory match that was applied}
)Save: attempt_id from the response.
Check: taxonomy_warnings in the response for unrecognized error categories.
If matched_attempt_id was provided, the response will also include
confirmed_match_id and new_confirmed_count showing the updated confidence.
Step 3 — Close the Debug Session
Called once when debugging completes (resolved or not).
close_debug_session(
session_id = {session_id},
final_outcome = {resolved | unresolved | environment_issue |
test_data_issue | authentication_issue |
iteration_limit_reached | needs_investigation},
resolution_attempt_id = {attempt_id of the fix that resolved the issue},
notes = {summary of remaining issues if unresolved}
)Workflow C — Ingest Existing Knowledge
Use this workflow to bulk-load lessons from existing documents into perfmemory. Supports two source formats.
Source 1: Debug Manifests
Debug manifests are markdown files at artifacts/{test_run_id}/analysis/debug_manifest.md
generated by the jmeter-debugging skill. Each iteration maps to one attempt.
Ingestion Steps:
- Read the manifest file
- Parse the header for session metadata:
Test Run ID→test_run_idScript→script_nameStatus→ inferfinal_outcome
- Call
store_debug_sessionwith the parsed metadatasystem_under_test: ask the user if not obvious from the manifestauth_flow_type: infer from the content (OAuth, SAML, CDSSO references)environment: infer from hostnames (e.g.,-stg.= "STG-East" or "staging")
- For each
## Iteration Nsection, parse:- Error Identified →
error_category,sampler_name,response_code,error_message - Diagnosis →
diagnosis - Fix Applied →
fix_description,fix_type,component_type - Result After Fix →
outcome(resolved if it improved, failed if it didn't)
- Error Identified →
- Build
symptom_textusing the structured template from the parsed fields - Call
store_debug_attemptfor each iteration - Call
close_debug_sessionwith the final outcome
Field Mapping Reference:
| Manifest Field | PerfMemory Field |
| Iteration number | iteration_number |
| Sampler name from "Error Identified" | sampler_name |
| Response Code from "Error Identified" | response_code |
| Error Category from "Error Identified" | error_category |
| "Diagnosis" section | diagnosis |
| "Fix Applied" section | fix_description |
| Fix component type (JSR223, JSON Extractor, etc.) | component_type |
| Fix action (add extractor, edit body, etc.) | fix_type |
| "Result After Fix" section | outcome |
Source 2: Lessons-Learned Documents
Lessons-learned documents are curated pattern files (e.g. .md files)
that contain numbered lessons with symptoms, causes, and fixes. These represent
human-reviewed knowledge and are stored as verified attempts.
Ingestion Steps:
- Read the lessons-learned document
- Create a single debug session to group all lessons:
store_debug_session( system_under_test = {inferred or ask user}, test_run_id = {document filename or ask user}, notes = "Ingested from lessons-learned document: {filename}" ) - For each numbered lesson (e.g.,
## 1. Always Use follow_redirects...):- Parse the lesson title as the
error_category - Parse the description for
symptom_text(the problem pattern) - Parse the Fix section for
fix_description - Infer
fix_typeandcomponent_typefrom the fix content - Set
outcome = "resolved"(these are known-good patterns) - Call
store_debug_attempt
- Parse the lesson title as the
- For pre-debug checklist items (e.g., "Prerequisites: Pre-Debug Validation"):
- Each checklist item becomes a separate attempt
- Set
error_category = "Pre-Debug Validation" - Set
outcome = "resolved"
- Call
close_debug_sessionwithfinal_outcome = "resolved" - Mark all attempts as human-verified:
verify_attempt(attempt_id = {each_attempt_id})
Symptom text for lessons-learned entries should capture the general pattern, not a specific sampler or test case:
JMeter Cookie/Redirect Handling — auto_redirects=true delegates redirect handling
to Java's HttpURLConnection which does not use JMeter's CookieManager. SSO cookies
are lost during redirect chains, causing authentication to fail silently.Maintenance Operations
Verify an Attempt (Human Review)
When a human confirms that a stored lesson is correct and reliable:
verify_attempt(attempt_id = {attempt_id})Archive an Attempt (Outdated Lesson)
When a lesson becomes outdated (API changed, issue no longer occurs):
archive_attempt(
attempt_id = {attempt_id},
reason = {why this lesson is no longer valid}
)Archived attempts remain in the database for audit but are excluded from search results.
View Memory Stats
get_memory_stats(
system_under_test = {optional — filter to a specific system}
)Review a Session
get_session_detail(session_id = {session_id})Browse Sessions
list_sessions(
system_under_test = {optional},
system_alias = {optional — filter by app alias},
service_name = {optional — filter by microservice},
environment = {optional — specific name (e.g. "QA1") or canonical type
(e.g. "qa"). Smart resolution: checks specific names first,
then canonical types, then literal match.},
env_type = {optional — direct filter on canonical type (e.g. "qa",
"staging"). No resolution — exact column match.},
final_outcome = {optional},
limit = 20
)Explore Graph Neighborhood
View the graph connections for a specific attempt (requires graph.enabled: true).
Use this after finding a match to discover additional related fixes, or to understand
the structural context of a known issue before applying a fix.
get_related_issues(
attempt_id = {attempt_id},
max_hops = 2, # optional — graph traversal depth
include_same_project = true, # optional — include same-project neighbors
enrich = true # optional — fetches full neighbor details
)Returns:
- error_patterns: list of
{error_category, response_code}linked to this attempt - fix_patterns: list of
{fix_type, component_type}that resolved it - neighbors: other attempts connected via SIMILAR_TO edges
When enrich = true, each neighbor includes symptom_text, diagnosis,
fix_description, sampler_name, api_endpoint, confirmed_count, is_verified,
system_alias, service_name, test_case_id, and test_case_name.
Cross-Project Pattern Search
Find if an error class has been resolved in other projects (requires graph.enabled: true).
Use this as a fallback when vector search returns no matches, or proactively when
starting work on a new project to check for known patterns.
find_cross_project_patterns(
error_category = {error_category},
current_project = {system_under_test}, # optional — excludes own project
response_code = {response_code}, # optional — omit to match all response codes
fix_type = {fix_type}, # optional
max_hops = 2, # optional
limit = 5, # optional
enrich = true # optional — fetches full attempt details
)When enrich = true, each match includes symptom_text, diagnosis,
fix_description, sampler_name, api_endpoint, confirmed_count, is_verified,
system_alias, service_name, test_case_id, and test_case_name.
Error Handling
- If
store_debug_sessionorstore_debug_attemptfails, report the error immediately. Do NOT retry — these are code-based MCP tools (permcp-error-handling.mdc). - If
find_similar_attemptsfails, proceed with normal debugging (memory is advisory). - If graph tools (
find_cross_project_patterns,get_related_issues) fail or return "Graph layer is not enabled", fall back to vector-only results. Graph is supplementary. - If the database is unreachable, skip all perfmemory operations and inform the user. Do not block the debugging workflow because memory is unavailable.
- Never modify the perfmemory MCP source code to work around errors.
In this repository23 other files it gives its agents.
- .cursor/rules/browser-automation-guardrails.mdcCursor rule
- .cursor/rules/implementation-standards.mdcCursor rule
- .cursor/rules/jmeter-script-guardrails.mdcCursor rule
- .cursor/rules/mcp-error-handling.mdcCursor rule
- .cursor/rules/prerequisites.mdcCursor rule
- .cursor/rules/project-and-coding-guidelines.mdcCursor rule
- .cursor/rules/skill-execution-rules.mdcCursor rule
- .cursor/rules/technology-reference-policy.mdcCursor rule
- ado-test-case-conversionSkill
- comparison-report-workflowSkill
- jmeter-correlation-namingSkill
- jmeter-debuggingSkill
- jmeter-entraid-debuggingSkill
- jmeter-har-conversionSkill
- jmeter-hitl-editingSkill
- jmeter-script-validatorSkill
- jmeter-swagger-conversionSkill
- msteams-notificationSkill
- performance-testing-workflowSkill
- playwright-browser-automationSkill
- report-revision-workflowSkill
- sharepoint-uploadSkill
- subagent-orchestratorSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

