Skip to main content
Glama

당신이 사용하는 모든 AI는 각기 다른 버전의 당신을 기억합니다. 하나가 배운 것은 다음 것을 열 때 사라지므로, 당신은 다른 세션을 시작할 때 같은 결정, 관계, 선호, 그리고 이력을 반복하게 됩니다.

afair는 그들에게 하나의 공유 저장소를 제공합니다. Model Context Protocol(MCP)을 통해 연결되므로, 같은 메모리를 Claude, 코딩 에이전트, 그리고 다음에 사용하는 어떤 도구에서도 사용할 수 있습니다.

커져 가는 메모리는 보통 또 하나의 유지 관리 대상이 됩니다. afair는 그 수고를 없애 줍니다. 백그라운드 에이전트가 도구가 기록한 내용을 읽고, 함께 속하는 것들을 발견하며, 유용한 이해를 최신 상태로 유지하고, 오래된 잡음은 관심 밖으로 사라지게 합니다. 구조는 고정된 템플릿이 아니라 당신의 삶을 따릅니다. 당신이 분류하거나 태그를 달거나 큐레이션할 필요가 없습니다.

결과는 계속 눈에 보입니다. afair가 무엇을 믿는지 읽고, 출처까지 추적하고, 당신을 잘못 이해했을 때 바로잡을 수 있습니다. 수정 사항은 조용히 기존 내용을 대체하는 대신 이력의 일부가 됩니다.

들어가는 것은 당신의 모든 삶입니다. 당신의 일, 사랑하는 사람들, 그리고 AI가 그냥 알았으면 하는 개인적인 것들.

데이터는 추가 전용이며 당신의 것입니다. afair는 오픈소스이고 단일 테넌트이며, 언제든지 전체를 내보낼 수 있습니다. 이름은 "as far as I remember"의 줄임말이며, 그런 조심스러운 표현이 필요 없게 만들기 위해 설계되었습니다.

두 가지 사용 방법

직접 실행하기. 이 저장소가 전체입니다. AGPLv3. 자신의 머신이나 서버에서 직접 호스팅하면 모든 계층을 끝까지 소유하게 됩니다. 영원히 무료입니다. 빠른 시작은 아래에 있습니다.

아니면 afair.ai가 대신 실행하게 하세요. 자신만의 격리된 EU 인스턴스, 백업, 내보내기, 업데이트를 대신 처리해 주는 관리형 호스팅이 곧 제공됩니다. **afair.ai**에서 얼리 액세스 목록에 참여하세요.

어느 쪽이든 같은 코드입니다. 호스팅 제품은 이 저장소의 한 배포본일 뿐, 별도의 독점 포크가 아닙니다.

Related MCP server: Hippocampus

세 가지 명령

afair는 정확히 세 가지 도구를 제공하며, 이들은 영구히 고정됩니다:

  • remember 는 지속할 가치가 있는 것을 저장합니다: 결정, 중요한 사람, 놓칠 수 없는 날짜, 선호.

  • recall 은 그 순간에 관련된 것을 가져옵니다.

  • observe 는 AI가 방금 한 일을 기록하여 저장소가 따라잡게 합니다.

짧은 설정 스니펫을 AI에 전달하면 AI가 스스로 이 명령들을 호출합니다. 호출이 있어야만 저장소에 도달합니다.

직접 실행하기

Python 3.12+ 및 uv가 필요합니다.

uv sync
cp .env.example .env
# add ANTHROPIC_API_KEY, or a key for any other provider (the model is yours to pick)
uv run python -m afair

서버는 http://127.0.0.1:8765에서 실행됩니다. CLI 또는 데스크톱 클라이언트(Claude Code, Codex, Cursor, GitHub Copilot)를 서버에 연결하기만 하면 됩니다. 클라우드에서 실행되는 웹 클라이언트(Claude.ai, ChatGPT)는 공개 HTTPS 배포와 빠른 OAuth 설정이 필요하며, 이는 docs/self-hosting.md에 설명되어 있습니다. 모든 환경 변수는 .env.example에 인라인으로 문서화되어 있습니다. 클라이언트별 연결 가이드는 docs/clients에 있습니다. afair는 기본적으로 개인용입니다. 저장소는 두 개의 환경 변수를 통해 단일 조직(인스턴스 하나, 팀 하나)에 속하게 할 수도 있습니다 (docs/self-hosting.md 참조).

코딩 에이전트로 설치하기

이미 Claude Code, Codex 또는 다른 코딩 에이전트를 사용 중인가요? 아래 프롬프트를 전달하면 에이전트가 스스로 설정합니다: 클론, 의존성, 구성, MCP 연결, 그리고 왕복 동작을 증명합니다.

이 머신에 afair(https://github.com/afairai/afair의 오픈소스 MCP 메모리 서버)를 설치하고 이 도구를 연결해 주세요. 저장소를 클론하고 uv sync를 실행하고 .env.example.env로 복사한 다음, LLM 공급자 API 키를 넣을 수 있게 저에게 요청하세요. 그런 다음 uv run python scripts/install_clients.py를 실행하여 MCP 클라이언트를 연결하고 afair 지침 스니펫을 추가하세요. 서버를 시작하는 명령(uv run python -m afair)과 계속 실행하게 하는 방법을 알려주세요. 서버가 실행되면 테스트 사실을 remember하고 recall하여 동작을 증명하세요. docs/self-hosting.mddocs/clients/를 따르세요. API 키는 .env에만 넣고 다른 곳에는 넣지 마세요.

바로 로컬에서 실행되며 기본적으로 CLI 및 데스크톱 클라이언트를 지원합니다. 웹 클라이언트(Claude.ai, ChatGPT)에 연결하려면 docs/self-hosting.md의 공개 배포 노트를 따르세요.

AI에게 사용법 가르치기

서버를 연결하는 것이 절반이고, 나머지 절반은 AI가 스스로 도구를 사용하게 만드는 것입니다. 짧은 지침 스니펫을 클라이언트의 영구 지침(CLAUDE.md, AGENTS.md, Custom Instructions 또는 .cursorrules)에 붙여넣으면, 매번 프롬프트하지 않아도 AI가 대화 시작 시 맥락을 recall하고, 지속할 가치가 있는 것을 remember하며, 자신이 한 일을 observe합니다. 같은 스니펫이 모든 클라이언트에서 작동합니다. Claude Code, Codex, Cursor의 경우 scripts/install_clients.py가 연결 구성과 스니펫을 모두 작성해 줍니다. GitHub Copilot의 경우 연결 구성을 작성하고 저장소별 스니펫 단계 하나를 출력합니다(Copilot은 작업공간별 지침을 읽습니다).

호환 도구

Claude Code, Claude.ai, ChatGPT, Codex CLI, Cursor, Windsurf, Copilot 및 Streamable HTTP를 통해 MCP를 지원하는 모든 도구.

아키텍처

네 개의 계층, 하나의 진실 원천:

  • Substrate. FTS5 및 sqlite-vec를 갖춘 추가 전용 SQLite, 콘텐츠 주소 지정 방식. 로그는 절대 다시 쓰이지 않습니다.

  • Interpretation. 기반 위에 구축된 버전별 뷰. 저장된 이벤트 하나도 건드리지 않고 재생성할 수 있습니다.

  • MCP surface. 버전별로 관리되며 추가 전용입니다. 한 번 출시된 시그니처는 계속 작동합니다.

  • Agents. 백그라운드 워커가 증거를 추출하고, 함께 속하는 것을 발견하며, 인용이 포함된 살아 있는 종합을 유지합니다. 클러스터 이름과 경계는 증거가 바뀜에 따라 바뀔 수 있습니다. 사용자는 카테고리를 정의하지 않습니다.

전체 설계와 이를 지탱하는 여덟 가지 불변 조건은 VISION.md에 있습니다. 이유를 알고 싶다면 거기서 시작하세요.

문서

문서

내용

VISION.md

전체 설계와 여덟 가지 불변 조건. 이유를 알고 싶다면 여기서 시작하세요.

docs/self-hosting.md

나만의 저장소 실행: 로컬, Docker 또는 공개 배포와 CLI/웹 클라이언트 및 OAuth 설정.

docs/clients

클라이언트별 연결 가이드(Claude Code, Codex, Cursor, VS Code + CLI용 GitHub Copilot, Gemini CLI, Windsurf, Antigravity, Claude.ai, ChatGPT, Perplexity) 및 하나의 범용 지침 스니펫.

CONTRIBUTING.md

개발 환경 설정, 네 가지 검사, 변경이 깨뜨릴 수 없는 불변 조건.

SECURITY.md

취약점 신고 방법과 afair가 지켜야 할 보안 모델.

docs/adr

아키텍처 결정 기록: 불변 조건이 존재하는 이유, 엔티티 그래프가 신념 계층인 이유.

CHANGELOG.md

릴리스 이력.

기여하기

풀 리퀘스트를 환영합니다. CONTRIBUTING.md에서 설정, 통과해야 하는 검사, 변경이 깨뜨릴 수 없는 불변 조건을 확인하세요. 보안 문제를 발견했나요? SECURITY.md를 확인하고 비공개로 신고해 주세요.

라이선스

afair는 GNU Affero General Public License v3.0(LICENSE)으로 배포됩니다. 자유롭게 자체 호스팅하고, 포크하고, 수정할 수 있습니다. 수정 버전을 다른 사람을 위한 네트워크 서비스로 운영한다면, 변경 사항을 같은 라이선스로 공개해야 합니다. afair.ai의 호스팅 서비스는 이 코드의 한 배포본일 뿐, 별도의 독점 포크가 아닙니다.

한 줄로: 자유롭게 사용하고, 자유롭게 직접 호스팅하며, 다른 사람을 위한 서비스로 운영한다면 공유하세요.

독일에서 제작

독일에서 제작되었습니다. 호스팅 인스턴스는 EU 관할 하에 EU에서 실행됩니다.

Available Tools

3 tools
observeA

Log a structured event from your own agent activity to the user's vault.

This tool is for YOU (the AI agent) to record what YOU did. Different from remember (which is for content the USER chose to save). observe is your auto-journal so that future sessions of you, or other AI agents the user works with, know what happened. The user wants visibility into what their AI does, partly so they can audit, partly so the next session has continuity.

Default to verbose observation. The user's salience worker and mode-switcher read observe events to decide attention state; richer observe data leads to better cognitive routing on subsequent recalls.

WHEN TO CALL:

  • After completing a substantive task: shipping code, sending an email, making a decision, finishing a meeting, running an analysis, editing a file.

  • When you start a significant work session ("started_task").

  • On any agent action whose existence the user might want to recall later ("what did Claude do yesterday in this project?").

  • On error or failure that's worth tracking for diagnosis.

WHEN NOT TO CALL:

  • For every micro-step, don't observe each individual file read.

  • For purely conversational acks.

  • For things the user explicitly typed (that's remember territory if durable, nothing if not).

ARGUMENTS:

  • event: A JSON object. The only REQUIRED key is "action" (a non-empty string verb that names what kind of thing happened). Recognized optional keys: "subject": what was acted upon (filename, person, ticket, ...) "result": outcome ("success", "failed: X", free text) "actor": on WHOSE BEHALF this was logged, when a shared credential relays for many people (an org agent acting for a specific member). A free-form identifier kept verbatim ("slack:U123", "alice@corp"). Distinct from the server-derived client (which tool wrote it): actor is attribution content you set, client is derived. Omit for a personal vault. Same content on behalf of different actors is stored as distinct events. Beyond those, ANY additional fields are preserved verbatim. Use whatever shape fits your agent's natural mental model. A JSON-string- serialized object is also accepted and parsed, and a bare string becomes the action — the event is never rejected on shape.

    Examples: {"action": "edit_file", "subject": "events.py", "result": "added inline-vs-spill logic"} {"action": "sent_email", "subject": "sajinth@example.com", "result": "follow-up on roadmap", "thread_id": "..."} {"action": "deployed", "subject": "afair-prod", "result": "v0.1.3", "duration_s": 47} {"action": "drafted_message", "subject": "Mara", "result": "birthday note for Saturday"}

RETURN: {"ok": true, "event_id": "...", "content_hash": "sha256:..."}

ParametersJSON Schema
NameRequiredDescriptionDefault
eventYesAn agent-self-logged event. ``action`` is required; other keys are recognized or preserved verbatim. Configured to allow arbitrary additional fields so different AI clients can use whatever shape fits their mental model. The extras are size- and nesting-bounded — see ``_bound_extras``.

Output Schema

ParametersJSON Schema
NameRequiredDescription
okYes
event_idYes
content_hashYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full behavioral disclosure burden. It explains the logging is for audit and continuity, mentions the salience worker reads events, and describes event shape tolerance (JSON, string). However, it doesn't mention rate limits, storage quotas, or if logging is synchronous—minor gaps for a logging tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Description is front-loaded with a clear purpose statement, followed by structured sections (WHEN TO/NOT, ARGUMENTS, RETURN). Every sentence adds nuance—no fluff. Examples and edge cases (bare string accepted) are included efficiently.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's low complexity (1 parameter, required, nested), presence of output schema, and thorough description, this is fully complete. It explains return format, event shaping, and usage context. No gaps remain for an agent to misuse the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description adds value by explaining the 'actor' field's attribution purpose versus client derivation, listing recognized optional keys with examples, and detailing how arbitrary fields are handled. This exceeds bare schema requirements.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the tool's purpose with a specific verb ('Log a structured event') and resource ('own agent activity to the user's vault'), clearly distinguishing it from siblings like 'remember' and 'recall'. It explains this is for the AI agent's auto-journal, not user-saved content.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit 'WHEN TO CALL' and 'WHEN NOT TO CALL' sections are provided, with concrete examples like after completing substantive tasks, and exclusions for micro-steps or conversational acks. It also contrasts with 'remember' for user-chosen content.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

recallA

Read the user's memory vault, afair, the persistent substrate they share across every session and every AI tool. CALL THIS BEFORE you respond to anything where the user's history might be relevant. Always.

The user installed afair so their context doesn't have to be repeated to every new conversation. A session where you have access to afair and don't call it is worse than a session without afair, because you're silently failing to use the memory they chose to maintain.

WHEN TO CALL:

  • At the START of every substantive task. Don't ask "do you want me to check?" Just check. Recall is cheap; missing context isn't.

  • Before answering questions that benefit from prior context: preferences, past decisions, names, ongoing projects, history with people (at work and outside it), important dates, recurring themes, deadlines, commitments.

  • When the user asks "do you remember X?", "what did we say about Y?", "remind me of Z?".

  • When the user wants the FULL content of a specific event ("show me the whole document"): use by_id or by_content_hash with full_payload=True.

  • When you want a snapshot of the vault's contents ("what's in there?"): use stats=True.

  • On topic shifts mid-conversation. New topic = fresh recall.

WHEN NOT TO CALL:

  • Pure compute questions ("what's 2+2", "translate this") that don't depend on the user's history.

  • When you just retrieved the same query a moment ago in this session.

  • Trivial conversational responses where no memory could help.

ARGUMENTS (all optional; combine as needed):

  • query: Natural-language search. Examples: "what did Sajinth say about the roadmap", "deadlines for the API project", "what does Mara like to drink", "when is my sister's birthday".

  • by_id: ULID of one specific event. Returns that event in full. Use after a prior recall hit when you need the whole content.

  • by_content_hash: sha256-prefixed hash of one specific event. Same lookup semantics as by_id.

  • scope: Optional substring filter. Reserved, currently no-op until Phase 3.5 emergent context detection lands.

  • depth: One of "auto" (default), "shallow", "normal", "deep". "auto" → system picks based on query shape (identifiers and single tokens → shallow; multi-token natural language → normal hybrid). Recommended default. "shallow" → FTS5 keyword only. Cheapest. "normal" → Hybrid FTS5 + vector. Local embedding inference, ~120ms. "deep" → Hybrid like normal, but the flat history lens: temporal relevance decay is OFF, so past-dated and superseded memories rank by match strength alone. Use for history / as-of questions ("what did I know back then", "show me past appointments"). Default recall instead de-prioritizes memories whose moment has passed, without dropping them.

  • limit: Max hits to return. Omitted → 10 in compact verbosity, 20 otherwise. Server cap 100 (larger values are clamped, not rejected).

  • verbosity: "compact" (default), "standard", or "full". Controls how much of each hit's interpretation/conflicts/linked-list detail is served — NOT the payload (see full_payload). "compact" → the AI-useful minimum: capped summary + payload text, top canonical entities and edges, only the top caveat-bearing conflicts. Use this by default. "standard"→ the full interpretation minus the redundant raw entity list and null edge validity bounds. "full" → every field, plus the durability rationale (interpretation.salience / salience_components / why_durable: a short "why this memory ranks as durable" line). Use standard/full, or by_id + full_payload, when you need salient_facts / raw entities / the complete conflict history. by_id/by_content_hash always serve full.

  • cursor: Opaque paging token for search/browse. Pass the next_cursor from a prior recall back here verbatim to get the next page. Best-effort: rankings are recomputed per call. A bad cursor serves page 1 with a note.

  • full_payload: Default false. When true, each hit's payload is the full untruncated content (for text-large events, the blob is read back into text). When false, text payloads are clipped (~500 chars standard/full, ~300 compact). Lookup modes (by_id, by_content_hash) imply full_payload=true.

  • stats: Default false. When true, the response includes a summary field with total_events, by_kind, by_origin counts, useful for "what's the lay of the land" queries. Combines with any other mode.

  • feedback: Optional dict reporting on hits from a PRIOR recall. Shape: {"useful_event_ids": [event_id, ...], "not_useful_event_ids": [event_id, ...], "missing_topic": "free-text note if expected content was absent"} This is the signal the self-improvement tuner reads to validate parameter changes (sharper salience, smarter mode-switching, better surprise calibration). After a recall, the NEXT time you call recall, include feedback referring to the prior hits. Don't ask whether to. Just send it. Empty payload is a no-op.

  • decide: Confirm/reject pending review proposals. Accepts a SINGLE decision or a LIST of up to 50 (batch-drain the queue in one call). Each: {"proposal_id": "...", "verdict": "confirm"|"reject"|"retract", "to_kind": "..."}. The per-decision outcomes come back in decisions (see RETURN). A bad decision in a batch is reported as that item's outcome (status "error"); the rest still apply.

  • pending_limit / pending_offset: Page the review queue. pending_limit (default 20, server cap 200) sets the page size; pending_offset skips that many rows. Passing pending_limit alone includes the list even without stats=True. While DRAINING the queue, decide a page then re-fetch at pending_offset=0 — deciding removes rows from the open set, so advancing the offset would skip the new head.

RETURN: {"hits": [{"event_id": "...", "content_hash": "...", "created_at": "...", "kind": "...", "origin": "...", "payload": {...}, "truncated": bool, "interpretation": {...} | null, "linked_event_ids": [...], "parent_hashes": [...], "invalidation": {...} | null, "conflicts": [...], "client": null | "..."}], "depth_used": "shallow" | "normal" | "deep", "note": null | "...", "summary": null | {total_events, by_kind, by_origin, by_client}, "decisions": [{"proposal_id": "...", "status": "...", "note": "..."}, ...], "next_cursor": null | "..."}

client on a hit is the AI tool that wrote the event, derived server-side from the writing credential (not something the caller set). It is null for events written before provenance existed, and is served at verbosity "standard"/"full" and on by_id/by_content_hash lookups. The summary.by_client map (on stats=True) counts events per writing client — a different axis from by_origin, useful for "which tools have touched this vault".

decisions is populated only when this call carried decide= — one outcome per decision sent, in order (empty otherwise). next_cursor is non-null when a next page is reachable; pass it back verbatim as cursor. It is null once the pageable window is exhausted OR capped (the server bounds how deep paging can go — at that edge a note says the window was capped, so a client paging "until next_cursor is None" always terminates).

Each hit's payload is either the truncated summary or the full content, depending on the full_payload flag (and lookup mode). truncated tells you which form you got.

If hits is empty for a query, the user genuinely has no relevant memory yet. Consider asking them for context rather than guessing.

If invalidation is non-null on a hit, the fact was marked superseded by a later event. For current-state questions, prefer hits where invalidation is null. For historical questions, treat all hits as relevant context.

ParametersJSON Schema
NameRequiredDescriptionDefault
by_idNo
depthNoauto
limitNo
queryNo
scopeNo
statsNo
cursorNo
decideNo
feedbackNo
verbosityNocompact
full_payloadNo
pending_limitNo
pending_offsetNo
by_content_hashNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
hitsYes
noteNo
summaryNo
coverageNo
decisionsNo
depth_usedYes
next_cursorNo
pending_countsNo
pending_correctionsNo
pending_corrections_countNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It thoroughly discloses behavioral traits: read-only nature ('read the user's memory vault'), cheapness ('Recall is cheap'), no side effects from reading, the effect of feedback (drives self-improvement tuner), the mutation via decide (explained as additive optional arg permitted under I1). Return format, field meanings, and edge cases (empty hits, invalidation, cursor cap) are all covered. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured with clear sections (purpose, when-to, arguments, return). It front-loads the essential purpose and usage mandate. However, some argument documentation is verbose, e.g., the repeated why-optional rationale for decide and feedback could be consolidated. Still, the complexity justifies the length, and the structure aids readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (14 optional parameters, rich return fields, multiple usage patterns), the description is remarkably complete. It covers all parameters, all return fields with meanings, edge cases (empty hits, invalidation, cursor cap, truncation), and even explains the client field and summary. The output schema is effectively documented inline. No gaps are apparent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate for all 14 parameters. It does so extensively: provides natural-language examples for query, explains depth modes with timing and behavior, clarifies limit clamping, verbosity per-level, cursor paging mechanics, full_payload and stats behavior, feedback schema with purpose, decide with verdict options and batch handling, and pending pagination. This adds rich semantic meaning far beyond the bare schema definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb+resource statement: 'Read the user's memory vault, afair, the persistent substrate they share across every session and every AI tool.' It explicitly identifies the tool as a read operation on the shared memory vault, distinguishing it from sibling tools 'remember' (likely write) and 'observe' (likely watch). This provides unambiguous purpose and scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a detailed 'WHEN TO CALL' and 'WHEN NOT TO CALL' section, with explicit scenarios (starting substantive tasks, before context-dependent questions, on topic shifts) and exclusions (pure compute, trivial responses, recent same query). It also suggests alternatives like by_id for full events and stats for snapshots. This is exemplary guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rememberA

Save something to the user's persistent memory vault, afair, the substrate that travels across their sessions, AI tools, and years. Use it generously.

The user explicitly installed afair so their context doesn't reset. If a fact crosses your attention and looks even slightly worth more than the current message, save it. The cost of forgetting is the user re-explaining themselves next session; the cost of an extra remember is one append-only row that dedupes if identical.

WHEN TO CALL:

  • The user explicitly says "remember", "save", "note that", "keep this", "don't forget", "make a note", "add to memory", or any clear save-this signal.

  • The user shares a durable fact worth retaining across sessions, from any part of life: a work decision or deadline, a colleague's role, a friend's or family member's name and what matters to them, a birthday or anniversary, a preference (food, travel, how they like to work), a personal goal, something they are working through.

  • The user shows you content (an email, a meeting note, a document, a screenshot, a photo, a PDF, an audio clip) whose substance has reason to outlive this conversation.

  • You make a significant decision together with the user that should survive into future sessions.

  • The user corrects an earlier fact ("actually Sajinth is at Athara, not elvah"). Write the new fact AND pass the old event's content_hash in invalidates to mark it superseded.

DEFAULT: when in doubt, remember. Don't ask for permission. Don't narrate "I'll remember this for you." Just call it.

WHEN NOT TO CALL:

  • Conversational filler ("ok thanks", "got it", "sounds good").

  • Content the user is actively dictating to another destination.

  • Things you can easily re-derive from current code or state.

  • Personal details about other people that the user has not asked you to track.

ARGUMENTS:

  • content: A discriminated union. Either: {"type": "text", "text": "..."} for any text, OR {"type": "binary", "data_b64": "...", "mime": "image/png", "filename_hint": "screenshot.png"} for binary. Max 10 MB raw bytes. A JSON-string-serialized object (the same shape sent as a string) is also accepted and parsed, and a bare string is stored as text — the write is never rejected on shape.

  • context: Optional. Where this came from or what it relates to. Examples: "email thread with Sajinth", "Tuesday standup", "dinner with Mara", "Mum's birthday weekend". Aids future recall.

  • type_hint: Optional. What kind of thing this is, if you have a guess. Examples: "email", "meeting_minutes", "decision", "screenshot". Advisory only. The system may classify differently.

  • parent_hashes: Optional. Content hashes of events this one references (corrections, replies, threads).

  • invalidates: Optional. List of content_hashes that this new fact supersedes. Each target gets its own append-only invalidation event referencing it. Use when the user corrects a prior fact or a meeting outcome supersedes an earlier plan.

  • asserted_by: Optional. Who asserted this, one of "user" (the human stated it directly) or "model" (you inferred or synthesized it). Advisory provenance only: it is stored and served, but a self-reported "user" can NEVER raise the trust of a derived fact above the normal agent-derived level — operator-grade trust is earned only through the recall(decide=...) review loop. Omit if you're unsure.

  • actor: Optional. On WHOSE BEHALF this memory is written, when a single credential relays for many people (an organization's shared agent writing for different members). A free-form identifier kept verbatim — "slack:U0BKXTGBWLD", "alice@corp", "Alice from Sales". Omit for a personal vault or when the credential already identifies the writer.

DISAMBIGUATION — three different questions, don't conflate them: - client (served on recall hits): WHICH TOOL wrote this, derived server-side from the credential. You never set it. - actor (this argument): ON WHOSE BEHALF, when the credential is shared. You set it. Advisory only; it never substitutes for client and never raises trust. If absent, client is the best attribution. - asserted_by: whether a HUMAN or the MODEL asserted the fact. Same content written on behalf of different actors is stored as distinct events (attribution is content); identical content + same actor dedupes.

RETURN: {"ok": true, "event_id": "...", "content_hash": "sha256:...", "deduplicated": false, "invalidated": ["sha256:...", ...]}

  • deduplicated=true means an event with identical content+context already existed; nothing was added but the existing event_id is returned.

  • invalidated lists the content_hashes that were marked superseded in this call.

The substrate is the user's vault, not yours. Be a thoughtful librarian: save signal worth keeping; don't hoard ephemera.

ParametersJSON Schema
NameRequiredDescriptionDefault
actorNo
contentYes
contextNo
type_hintNo
asserted_byNo
invalidatesNo
parent_hashesNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
okYes
event_idYes
invalidatedNo
content_hashYes
deduplicatedYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and excels. It explains beyond what annotations might cover: deduplication behavior (identical content+actor), return schema details (event_id, content_hash, deduplicated flag, invalidated list), size limits (10 MB for inline, up to 1 GB via blob-ref), compound event atomicity, and the 'asserted_by' trust model. No contradictions exist.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is comprehensive and well-organized with clear sections (WHEN TO CALL, WHEN NOT TO CALL, ARGUMENTS, RETURN, etc.). It is front-loaded with the tool's purpose and bias. However, it is verbose in some parts (e.g., the full code examples in parameter descriptions and the disambiguation section) and could be tightened slightly without losing clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 7 parameters (1 required), 0% schema coverage, no annotations, and the presence of an output schema, the description is fully complete. It explains every parameter in detail, covers the complex content union with 4 variants, clarifies compound event atomicity vs. parent_hashes, and documents the return schema. The output schema exists and the description doesn't repeat it but rather adds behavioral context. No gaps remain.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Even though schema description coverage is 0%, the description provides rich, detailed meaning for all 7 parameters. For content, it enumerates 4 discriminated union variants (text, binary, blob-ref, compound) with behavioral intent. It gives concrete examples for context, type_hint, parent_hashes, invalidates, and actor, and includes a detailed disambiguation block for client vs. actor vs. asserted_by. This far exceeds baseline requirements.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses specific verbs like 'save' and 'remember', clearly identifies the resource as the user's persistent memory vault (afair), and distinguishes itself from siblings by explicitly contrasting with recall (for retrieval) and observe (implied passive). It thoroughly explains the tool's role as a durable, cross-session storage.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit WHEN TO CALL examples (user says 'remember', shares durable facts, shows content, makes decisions, corrects facts with invalidates) and WHEN NOT TO CALL categories (conversational filler, content destined elsewhere, re-derivable facts, unrequested personal details). Also includes a clear DEFAULT bias toward remembering without asking permission.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 3 tool updatesv0.1.0
    • First observedobserve
    • First observedrecall
    • First observedremember

TDQS

A4.9/5.0
Disambiguation5/5

Each tool has a completely distinct and clear purpose: remember saves user facts, recall retrieves them, and observe logs agent actions. There is no possible confusion between the tools.

Naming Consistency5/5

All three tool names are imperative verbs (remember, recall, observe) that directly describe their action, forming a consistent and predictable pattern. No naming convention conflicts.

Tool Count5/5

Three tools is exactly right for a memory vault server: one to write user memories, one to read them, and one to log agent activity. Each tool earns its place without any redundancy or scope creep.

Completeness5/5

The tool set covers the full memory lifecycle: creation (remember), retrieval/search (recall), and agent activity logging (observe). There are no obvious gaps—the domain is self-contained and complete for a vault that persists across sessions.

Maintenance

ActivityActive
ResponsivenessSyncing

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Self-hosted semantic memory for AI agents. Save worklogs, decisions, and notes via MCP, then recall them across sessions by meaning rather than keyword. Backed by Postgres + pgvector with local embeddings (multilingual-e5-base).
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Open-source MCP memory server providing persistent, cross-platform context for AI tools via a knowledge graph with encrypted storage.
    4
    13
    AGPL 3.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Local-first, file-based memory layer for AI agents — one shared Markdown vault across Claude, Codex, Gemini, Cursor and any MCP client. Provides read/write memory tools with an audit trail, per-agent trust levels, and Git sync; no cloud and no lock-in.
    2
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/afairai/afair'

If you have feedback or need assistance with the MCP directory API, please join our Discord server