Memos

repository·main·Indexed 11 days ago

https://github.com/usememos/memos

An open-source, self-hosted note-taking application designed for rapid, Markdown-native note capture using a timeline-based interface.

Tokens
28.3K
Snippets
58
Records
111
Agent score
98%

What's inside Memos

  1. Overview of Memos features and deployment

    main

    Memos is a Markdown-native, lightweight, self-hosted note-taking application designed for quick capture via a timeline-first interface.

    Deployment Options

    • Docker: Recommended for most users.
    • Docker Compose: Recommended for production environments.
    • Kubernetes: Supported via Helm charts and manifests.
    • Native Binary: A single Go binary for easy distribution.
    • Build from source: For developers and customization.

    Supported Databases

    • SQLite
    • MySQL
    • PostgreSQL

    Integration

    Developers can extend Memos using its REST and gRPC APIs.

  2. Overview of the Memos MCP Server

    main

    The Memos MCP server provides a curated toolset for interacting with memos and attachments via the Model Context Protocol.

    Key Characteristics:

    • Endpoint: POST /mcp (supports Streamable HTTP).
    • Transport: Stateless, JSON-response mode via Streamable HTTP (no SSE or session tracking).
    • Implementation: Tool calls execute in-process by translating MCP requests into matching /api/v1/... REST API calls. This ensures the MCP server reuses the existing API's authentication, authorization, and business logic.
    • Security: Includes origin safety checks to prevent DNS-rebinding from browsers. Requests are capped at 256 MiB.
  3. Understand MCP tool result shapes and error handling

    main

    Result Shapes

    To ensure compatibility with strict MCP clients, all successful tool results are wrapped in an object-shaped structuredContent envelope:

    • JSON Object: Returned unchanged.
    • Empty Response: Becomes { "ok": true }.
    • Bare Array: Becomes { "result": [...] }.
    • Scalar Value: Becomes { "result": value }.

    Error Handling

    Failures are returned as MCP tool errors (CallToolResult with IsError: true) rather than JSON-RPC protocol errors. Error results omit structuredContent to prevent schema validation failures in strict clients.

    Failure ScenarioError Message Format
    Invalid JSON argumentstool error: decode message
    Schema validation failuretool error: <validation message>
    Missing path parametertool error: missing required path parameter "..."
    Missing request bodytool error: missing required request body "body"
    API non-2xx responsetool error: "<code> <reason phrase>: <api message>" (e.g. 404 Not Found: ...)
    Undecodable JSON responsetool error: decode message
  4. Understand Memos tag syntax and recognition

    main

    Memos uses a custom tag syntax based on Unicode UAX #31 and Emoji 17.0. Tags are identified by a # (U+0023) introducer followed by a sequence of characters.

    Key Syntax Rules:

    • Introducer: A # symbol. It can appear anywhere in text (e.g., hello#tag is valid) but is not recognized if it is part of a Markdown link, code span, or escaped (e.g., \#tag).
    • Hierarchy: The / character acts as a hierarchy separator. A tag like #book/fiction automatically implies the existence of the ancestor tag book.
    • Allowed Characters: Tags support alphanumeric characters, underscores, and Memos-specific extensions like -, +, and &. They also support fully-qualified emojis.
    • Apostrophes: Standard ASCII (') and right-curly () apostrophes are supported as 'joiners' between valid characters but cannot start or end a tag.
    • Case Sensitivity & Normalization: Memos is case-sensitive and does not perform canonical normalization. #Work and #work are treated as two distinct tags. Similarly, #café and #café (different Unicode combining marks) are distinct.
    #book/fiction/history  -> Tags: book, book/fiction, book/fiction/history
    #C++                 -> Tag: C++
    #R&D                 -> Tag: R&D
    #tag's               -> Tag: tag's
  5. How tag hierarchy works in Memos

    main

    The slash / is a structural hierarchy separator. When a tag with slashes is used, Memos expands it into a set of tags including all its ancestor prefixes. This affects how tags are counted and filtered.

    Example Behavior: If you write #book/fiction/history in a memo:

    1. The direct tag value is book/fiction/history.
    2. The memo tag set (the list of tags associated with that memo) includes: book, book/fiction, and book/fiction/history.

    Implications:

    • Filtering: Filtering for an ancestor tag (e.g., book) will return any memo that contains a descendant (e.g., book/fiction).
    • Counting: A tag count represents the number of memos whose tag set contains that specific value.
    • Rendering: Hierarchy expansion is a logical concept; it does not insert extra # tags into your Markdown source during export or rendering.
    Source occurrence:  #book/fiction/history
    Direct tag value:   book/fiction/history
    Memo tag set:       book, book/fiction, book/fiction/history
  6. Understand the Memos Color System

    main

    The Memos color system uses the OKLCH color space for perceptual uniformity and accessibility. It is built using CSS custom properties that automatically adapt between light and dark themes.

    To switch themes, the system looks for a .dark class on a parent element (typically <html> or <body>).

    Theme Toggling:

    document.documentElement.classList.toggle("dark");
  7. Username identity and database collation

    main

    Username equality in Memos is defined as exact ASCII byte equality. To ensure consistent behavior across different storage backends, Memos requires case-sensitive binary collation for the username column.

    If you are implementing a custom storage backend or managing the database directly, you must use the following collations to prevent Alice and alice from being treated as the same user:

    • MySQL: utf8mb4_bin
    • PostgreSQL: C
    • SQLite: BINARY

    Identity Resolution Logic:

    1. Preserve the username exactly as written.
    2. Look up the exact username within the operation's visibility and account-status scope.
    3. If a match is found, use the resulting internal user ID for durable effects.
    4. If no match is found, treat the text as ordinary source text.
  8. How ConfirmDialog handles async operations and errors

    main

    The ConfirmDialog is built to be async-aware. When onConfirm is called:

    1. It enters a loading state.
    2. If the onConfirm promise resolves, the dialog automatically calls onOpenChange(false) to close.
    3. If the onConfirm promise rejects, the dialog remains open. This allows the user to see error feedback (like a toast) and attempt the action again.

    It also implements a 'Close Guard' to prevent users from accidentally dismissing the dialog via backdrop clicks or escape keys while an asynchronous operation is in progress.

  9. Understand Memos Tagging and Hierarchy

    main

    Tags in Memos are derived from Markdown source text and are not independent entities. They cannot be created or renamed without editing the memos that contain them.

    Tag Structure

    • Tag Occurrence: A span of text starting with a # (the Tag introducer) followed by the tag spelling.
    • Direct Tag Value: The identifier emitted from a single occurrence. For example, #book/fiction produces the direct value book/fiction.
    • Implied Ancestor Tags: Memos uses a slash-delimited hierarchy. A direct tag like book/fiction/history automatically implies the ancestor tags book and book/fiction.
    • Tag Segment: The components between slashes. A leading slash produces no tag; a trailing or repeated slash terminates the identifier.

    Tag Behavior

    • Memo Tag Set: The collection of all direct and implied tags for a single memo (exposed as Memo.tags).
    • Tag Count: The number of memos containing a specific tag value. A single memo containing #book/fiction increments the count for both book and book/fiction by one.
    • Comparison: Tags are compared by their emitted Unicode code-point sequences. They are case-sensitive and do not undergo normalization.
  10. Understand Memos Configuration Provisioning

    main

    Memos uses a deployment-configuration model where configuration is supplied via mounted JSON files in /etc/secrets. This configuration is loaded during process startup and is authoritative for the lifetime of the process, shadowing any existing settings stored in the database.

    Key Concepts

    • Stored configuration: Settings currently in the idp and system_setting database tables.
    • Deployment configuration: Settings decoded from files in /etc/secrets during startup.
    • Effective configuration: The final configuration used by the application. Deployment configuration shadows stored configuration if they share the same Stable key (the uid for identity providers or the key for instance settings).

    Lifecycle and Behavior

    • Immutability: Once loaded, deployment configuration is immutable for the process lifetime. To apply changes, you must restart the process.
    • Shadowing: If a file provides a setting, the database version of that setting is ignored. If a file is removed and the process is restarted, the database-backed setting becomes authoritative again.
    • No Reconciliation: Memos does not attempt to sync file contents to the database or delete database records when files are removed.
  11. How tags are identified in Markdown text

    main

    Memos uses a specific process to identify tags within Markdown to ensure consistency between the backend, renderer, and editor.

    1. Tag Candidate: An introducer (#) followed by a sequence of characters that matches the lexical grammar.
    2. Literal-source run: The candidate must exist within a contiguous range of original Markdown source that has no intervening Markdown escapes, character references, or syntax tokens.
    3. Eligibility Check: The candidate must reside in Eligible Text (a run classified as textual content by GFM 0.29-gfm or explicitly exposed as ordinary text by a Memos extension).
    4. Opaque Nodes: Certain Markdown nodes (like code blocks or specific extension nodes) are considered Opaque Markdown nodes and are ineligible for tag recognition to prevent accidental tag extraction from code or metadata.
  12. How GFM task lists are rendered

    main

    GitHub Flavored Markdown (GFM) task lists are processed by remarkSplitMixedTaskLists before rendering to ensure consistent layout. The rendering logic follows these rules:

    • List Splitting: Mixed task/bullet lists are split into separate lists so that regular bullets do not inherit task list styling.
    • Tight vs. Loose Lists: Single-block split items are rendered as tight list items to prevent accidental <p> wrappers.
    • Grid Layout: The ListItem component uses a two-column grid layout:
      • Column 1: Contains the checkbox and controls.
      • Column 2: Contains a single task-body wrapper.
    • Content Preservation: All task text, emphasis, links, tags, and nested content are contained within the task-body wrapper. This ensures that inline markdown does not break out into separate grid items.
    • Paragraph Handling: Loose task items maintain their paragraph structure inside the task-body wrapper.