From fenix
Complete memory protocol for AI agents using Fenix. Defines when and how to search, save, and link memories for cross-session continuity.
How this skill is triggered — by the user, by Claude, or both
Slash command
/fenix:fenix-memory-protocolThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Memories are how context survives between conversations. Without them, every session starts from zero — decisions get repeated, context gets lost, and work gets duplicated.
Memories are how context survives between conversations. Without them, every session starts from zero — decisions get repeated, context gets lost, and work gets duplicated.
This skill defines the complete protocol for using Fenix's intelligent memory system (memory_save and memory_search).
Fenix uses semantic search powered by AI embeddings — not keyword matching. This means:
"what did we decide about auth?" finds memories about authentication even if the word "auth" doesn't appearWhen you save a memory, Fenix automatically checks for similar existing memories:
This means you don't need to worry about creating duplicates. Save freely — the system handles dedup.
When a memory reaches version ≥5 or content ≥8000 characters, Fenix automatically summarizes it to keep it concise. You don't need to manage this.
<EXTREMELY_IMPORTANT> At the start of EVERY conversation, run at least these searches before doing anything else:
memory_search(query: "Session State") — find where the user left offmemory_search(query: "{topic of user's request}") — find relevant contextmemory_search(query: "{work item key}") — if a specific item is mentioned (e.g., "PROJ-123")
</EXTREMELY_IMPORTANT>What to do with results:
Before choosing an approach, search for prior decisions:
memory_search(query: "decision {topic}")
memory_search(query: "architecture {component}")
Previous decisions may be locked (explicitly chosen by the user) — these are non-negotiable. If you need to deviate from a locked decision, you MUST discuss it with the user first.
Before writing code for a task, search for implementation context:
memory_search(query: "{task key} implementation")
memory_search(query: "{feature name} context")
This surfaces constraints, dependencies, and past learnings that affect the current work.
When a technical decision is made, save it right away:
memory_save(
title: "Decision — {short description}",
content: "## Decision\n{what was decided}\n\n## Why\n{rationale and trade-offs considered}\n\n## Alternatives rejected\n{what was not chosen and why}\n\n## Classification\n{locked | agent-discretion}",
tags: ["decision", "{work-item-key}", "{topic}"],
work_item_id: "{uuid if applicable}"
)
Locked vs Agent Discretion:
When you evaluate trade-offs between approaches:
memory_save(
title: "Trade-off — {short description}",
content: "## Options\n{option A vs B vs C}\n\n## Analysis\n{pros/cons of each}\n\n## Chosen\n{which one and why}",
tags: ["trade-off", "{work-item-key}", "{topic}"]
)
When something blocks progress:
memory_save(
title: "Blocker — {short description}",
content: "## Blocker\n{what's blocking}\n\n## Impact\n{what can't proceed}\n\n## Possible resolutions\n{ideas to unblock}",
tags: ["blocker", "{work-item-key}"]
)
When you discover something during implementation that would be lost between sessions:
memory_save(
title: "Context — {short description}",
content: "## What\n{the insight or finding}\n\n## Why it matters\n{how this affects future work}",
tags: ["context", "{work-item-key}", "{topic}"]
)
<EXTREMELY_IMPORTANT> Before the conversation ends, you MUST save a session state memory. This is the single most important memory you create — it's how the next session picks up where this one left off. </EXTREMELY_IMPORTANT>
memory_save(
title: "Session State — {WORK-KEY} {short description}",
content: "## Current position\n{phase: planning/development/review/delivery}\n{current task/story}\n\n## Work completed\n- {item 1}\n- {item 2}\n\n## Decisions made\n- {decision 1} [locked|agent-discretion]\n- {decision 2} [locked|agent-discretion]\n\n## Blockers\n- {blocker or 'None'}\n\n## Next concrete step\n{exactly what to do when resuming — be specific}",
tags: ["session-state", "{work-item-key}", "{current-phase}"],
work_item_id: "{uuid}",
sprint_id: "{uuid if in active sprint}"
)
Use consistent tags so memories can be found reliably.
| Tag | When to use |
|---|---|
planning | During product or technical planning |
development | During implementation |
review | During code review |
delivery | During finalization and delivery |
Use the work item key as-is: PROJ-123, FEAT-45, TASK-67
For hierarchical context, prefix with type:
epic:PROJ-100feature:PROJ-110story:PROJ-123| Tag | Domain |
|---|---|
architecture | System design, patterns, structure |
api-design | API contracts, endpoints, schemas |
database | Schema, migrations, queries |
testing | Test strategy, coverage, fixtures |
performance | Optimization, benchmarks, profiling |
security | Auth, permissions, vulnerabilities |
deployment | CI/CD, infrastructure, environments |
dependencies | Third-party libraries, version management |
breaking-changes | Changes that affect existing behavior |
| Tag | What it marks |
|---|---|
decision | A choice that was made with rationale |
trade-off | An evaluated comparison between options |
blocker | Something preventing progress |
context | Background information or insight |
session-state | End-of-session continuity snapshot |
Always link memories to relevant Fenix entities when available:
| Parameter | When to set |
|---|---|
work_item_id | Working on a specific epic, feature, story, task, or bug |
sprint_id | Working within an active sprint |
documentation_item_id | Memory relates to a documentation page |
team_id | Memory is team-specific (required for multi-team users) |
Entity links enable Fenix to build a knowledge graph — memories connected to work items, sprints, and docs create navigable context across the project.
When you're not sure what exists:
memory_search(query: "{general topic}", limit: 10)
When you know what you're looking for:
memory_search(query: "Decision — authentication middleware for {project}")
For complex topics, run multiple searches:
memory_search(query: "Session State PROJ-123") → current position
memory_search(query: "decision PROJ-123") → past decisions
memory_search(query: "architecture {module name}") → technical context
"what approach did we choose for handling file uploads""file upload decision PROJ-123 architecture storage"Write queries like you're asking a colleague, not searching a database.
| Anti-pattern | Problem | Do this instead |
|---|---|---|
| Saving every small change | Noise drowns out signal | Save decisions, trade-offs, blockers, and session state — not trivial details |
| Using vague titles | Hard to find later | Be specific: "Decision — use PostgreSQL JSONB for dynamic fields" not "Database decision" |
| Skipping entity links | Memories float disconnected | Always link to the work item you're working on |
| Saving implementation details | Code is the source of truth for code | Save the why, not the what. The code shows what changed; the memory explains why |
| Not searching before saving | Creates duplicates (even with auto-dedup, scattered partial memories are worse than one good one) | Search first, then save or update |
| Giant memory dumps | Hard to search, triggers early consolidation | Keep memories focused. One topic per memory. |
The memory graph connects memories through explicit relation edges created at save time. Use traversal to discover clusters of related context that semantic search might miss.
| Approach | Use when |
|---|---|
memory_search(query) | You know what you're looking for (semantic query) |
memory_graph(memory_id, depth: 2) | You have an ID and want to explore its neighborhood |
memory_relations(memory_id) | You want a quick 1-hop check of a specific memory |
memory_search(query, include_graph: true) | Search + graph context in one call |
At session start, after finding the session state memory:
1. memory_search(query: "Session State {work key}")
→ get session state memory ID
2. memory_graph(memory_id: "{id}", depth: 2)
→ explore connected decisions, trade-offs, blockers from past sessions
This surfaces memories that are linked but might not match the semantic query.
memory_graph(
memory_id: "{decision memory ID}",
depth: 2,
relation_types: ["extends", "caused_by", "supersedes"]
)
relation_types or graph_limit to bound)similar | extends | caused_by | supersedes | contradicts | depends_onIf memory_graph or memory_relations returns a timeout:
depth (try 1 instead of 2+)relation_types to narrow traversalgraph_limit to cap total nodes returnednpx claudepluginhub fenix-assistant/fenix-plugin --plugin fenixSearches and retrieves memories from Cortex persistent memory using WRRF retrieval. Use for past decisions, patterns, bugs, or architecture context.
PROACTIVELY query Forgetful MCP (mcp__forgetful__* tools) when starting work on any project, when user references past decisions or patterns, when implementing features that may have been solved before, or when needing context about preferences. Save important decisions, patterns, and architectural insights to memory.
Manages persistent semantic memory across sessions: store/retrieve knowledge/TODOs/issues, hybrid semantic search, hierarchy/tags organization, and maintenance tools.