Skip to main content
Glama
Cloto-dev

CPersona

Official
by Cloto-dev

store

Idempotent

Save a message to agent memory for later recall. Returns stored, skipped, or rejected so callers can branch on dedup hits, length caps, or refusals.

Instructions

Store a message in agent memory for future recall. Every response carries result — the one field to branch on: 'stored' (a new row was written; {ok:true, result:'stored', id:, embedded:}, embedded true iff a local blob was persisted or the remote index push succeeded — false under EMBEDDING_MODE=none; the response also carries truncated:true when content exceeded the length cap and was shortened, and nodes:{status:'queued'} when the text runs past the embedding window and its overflow-tree nodes were queued for construction — absent when it fits, when the embedding server cannot report tokens, or with the task queue disabled), 'skipped' (nothing written and nothing wrong: {ok:true, result:'skipped', reason:...}; the msg_id / content dedup branches echo the pre-existing row's id, the OR IGNORE fallback reason='duplicate (unique index)' omits id by design — TOCTOU seam), or 'rejected' (nothing written because the request was refused: {ok:false, result:'rejected', reason:...} — empty content, content that sanitizes to empty, or an operating-context project_id refusal, which also carries error). Note for pre-2.5.2b1 callers: ok is no longer unconditionally true, and skipped:true is gone — a rejection used to look like a success. reason is human-readable, not a stable machine token. Under pause_persistence the write is skipped (result:'skipped') and the response carries persisted:false (id:'no-persist', embedded:false) — branch on persisted to tell a paused write apart from a dedup hit.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
channelNoMemory channel for context separation (e.g. 'chat', 'discord'). Default: '' (shared).
messageYesClotoMessage to store. Legacy source shapes are normalized server-side where unambiguous (e.g. lowercase type words, Rust serde externally-tagged dicts, bare 'user'/'assistant' strings); unknown shapes are stored verbatim and surfaced by check_health(invalid_source_type).
agent_idYesAgent identifier
project_idNov2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution.
session_keyNoOpaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.
associationsNoAssociative memory to declare alongside this call: entities the text mentions, with their aliases, and subject–predicate–object relations. Stored verbatim; the server extracts nothing and infers nothing. On store, the stored memory is recorded as mentioning every entity named here and anchors every relation. Malformed items are reported in the response's associations.dropped and skipped; the memory is stored regardless. Optional.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changedv2.6.1
    • changedInput schema / properties / associations / properties / entities / description
      Previous value: -"Entities to register (if new) and mark as mentioned. Names are compared after normalization (NFKC, case-folded, whitespace collapsed)."New value: +"Entities to register (if new) and mark as mentioned. Names and aliases are compared after normalization (NFKC, case-folded, whitespace collapsed), so two that normalize alike name one entity."
    • addedInput schema / properties / session_key / maxLength
      Added value: +256
  2. Changed2 schema fields changedv2.5.12
    • addedInput schema / properties / associations
      Added value: +{
      +  "description": "Associative memory to declare alongside this call: entities the text mentions, with their aliases, and subject–predicate–object relations. Stored verbatim; the server extracts nothing and infers nothing. On store, the stored memory is recorded as mentioning every entity named here and anchors every relation. Malformed items are reported in the response's associations.dropped and skipped; the memory is stored regardless. Optional.",
      +  "properties": {
      +    "entities": {
      +      "description": "Entities to register (if new) and mark as mentioned. Names are compared after normalization (NFKC, case-folded, whitespace collapsed).",
      +      "items": {
      +        "properties": {
      +          "aliases": {
      +            "description": "Other names for the same entity. An alias resolves to at most one entity per scope; a second claim on it is dropped.",
      +            "items": {
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "name": {
      +            "description": "The canonical name, kept as written.",
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "name"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "relations": {
      +      "description": "Declared relations. subject / object are entity names (registered if new) or record refs 'mem:<id>' / 'ep:<id>' of this agent; predicate is free text, normalized. A predicate from the role vocabulary (supports, supersedes, corrects, qualifies, contradicts, temporal_predecessor) on a record → record relation is read by reconstruct as that role.",
      +      "items": {
      +        "properties": {
      +          "object": {
      +            "type": "string"
      +          },
      +          "predicate": {
      +            "type": "string"
      +          },
      +          "subject": {
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "subject",
      +          "predicate",
      +          "object"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "type": "object"
      +}
    • changedInput schema / properties / message / properties / source / type
      Previous value: -"object"New value: +[
      +  "object",
      +  "string",
      +  "null"
      +]
  3. Changed1 schema field changedv2.5.10
    • addedInput schema / properties / session_key
      Added value: +{
      +  "default": "",
      +  "description": "Opaque session identity you declare: a partition hint, not authentication and not a data filter. Selects which no-persist pause applies to this call. Omit to share one bucket with every caller that omits it. Full text on recall.",
      +  "type": "string"
      +}
  4. Changed2 schema fields changedv2.5.4
    • changedInput schema / properties / message / properties / source / properties / type / description
      Previous value: -"Producer role — this enum IS the contract; send one of these. Legacy producers that cannot are folded server-side at the write seam ('ai' / 'assistant' are normalized to 'Agent'; 'session' is normalized to 'System' (type words are matched case-insensitively)), and shapes outside that table are stored verbatim for check_health(invalid_source_type) to surface."New value: +"Producer role — send one of 'User', 'Agent', 'System'. Legacy producers that cannot are folded server-side at the write seam ('ai' / 'assistant' are normalized to 'Agent'; 'session' is normalized to 'System' (type words are matched case-insensitively)), and shapes outside that table are stored verbatim for check_health(invalid_source_type) to surface."
    • removedInput schema / properties / message / properties / source / properties / type / enum
      Removed value: -[
      -  "User",
      -  "Agent",
      -  "System"
      -]
  5. Changed4 schema fields changedv2.5.2
    • changedInput schema / properties / message / properties / content / description
      Previous value: -"The text to store. Empty content is skipped."New value: +"The text to store. Content that is empty — or that sanitizes to empty — is refused with ok:false, result:'rejected'."
    • changedInput schema / properties / message / properties / metadata / description
      Previous value: -"Free-form JSON object for producer-specific context. Empty when unused."New value: +"Free-form JSON object for producer-specific context. Empty when unused. Serialised size is capped at 8000 characters (same cap for source); an oversized field is refused with result='rejected' rather than truncated, because a truncated JSON document is not a JSON document."
    • changedInput schema / properties / message / properties / source / properties / type / description
      Previous value: -"Producer role. 'Assistant' / 'ai' are normalized to 'Agent'; 'session' is normalized to 'System'."New value: +"Producer role — this enum IS the contract; send one of these. Legacy producers that cannot are folded server-side at the write seam ('ai' / 'assistant' are normalized to 'Agent'; 'session' is normalized to 'System' (type words are matched case-insensitively)), and shapes outside that table are stored verbatim for check_health(invalid_source_type) to surface."
    • changedInput schema / properties / project_id / description
      Previous value: -"v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (echoed as resolved_project_id)."New value: +"v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (the resolution is echoed as resolved_project_id; an unmapped agent yields operating_context_warning). bug-186: resolution requires a configured operating context. With none — the default, and equally the outcome of a sidecar that fails to parse — the sentinel is NOT resolved: it is stored and filtered as the literal project_id '@auto', resolved_project_id echoes '@auto', and no warning is raised. Read resolved_project_id before relying on the resolution."
  6. Changed3 schema fields changedv2.5.1
    • changedInput schema / properties / message / description
      Previous value: -"ClotoMessage to store (id, content, source, timestamp, metadata)"New value: +"ClotoMessage to store. Legacy source shapes are normalized server-side where unambiguous (e.g. lowercase type words, Rust serde externally-tagged dicts, bare 'user'/'assistant' strings); unknown shapes are stored verbatim and surfaced by check_health(invalid_source_type)."
    • addedInput schema / properties / message / properties
      Added value: +{
      +  "content": {
      +    "description": "The text to store. Empty content is skipped.",
      +    "type": "string"
      +  },
      +  "id": {
      +    "description": "Caller-supplied message id used for msg_id-based dedup (γ-project-scoped). Optional.",
      +    "type": "string"
      +  },
      +  "metadata": {
      +    "description": "Free-form JSON object for producer-specific context. Empty when unused.",
      +    "type": "object"
      +  },
      +  "source": {
      +    "description": "Attribution of who produced the content. Canonical shape is {type, id, name}. Type is the discriminator; id / name identify the concrete producer. Store null / empty {} only when the producer is genuinely unknown. A null source is normalized to {} at the write seam, so both persist (and recall) as the anonymous {}.",
      +    "properties": {
      +      "id": {
      +        "description": "Stable producer id (e.g. discord user id, agent id). Empty when anonymous.",
      +        "type": "string"
      +      },
      +      "name": {
      +        "description": "Human-readable label for display. Empty when unknown.",
      +        "type": "string"
      +      },
      +      "type": {
      +        "description": "Producer role. 'Assistant' / 'ai' are normalized to 'Agent'; 'session' is normalized to 'System'.",
      +        "enum": [
      +          "User",
      +          "Agent",
      +          "System"
      +        ],
      +        "type": "string"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  "timestamp": {
      +    "description": "UTC ISO-8601 timestamp with offset (e.g. '2026-07-22T12:00:00+00:00'). Defaults to server-time UTC when omitted. Aware non-UTC offsets are accepted; naive strings are surfaced by check_health(timestamp_format_drift).",
      +    "type": "string"
      +  }
      +}
    • changedInput schema / properties / project_id / description
      Previous value: -"v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool."New value: +"v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool. v2.5.1: pass '@auto' to resolve this agent's default from the server's operating context (echoed as resolved_project_id)."
  7. Changed1 schema field changedv2.4.34
    • addedInput schema / properties / project_id
      Added value: +{
      +  "description": "v2.4.17 isolation axis. Optional — omit or pass '' to store in the global pool. Reads via γ semantics: a recall with project_id='X' returns 'X' rows + global pool.",
      +  "type": "string"
      +}
  8. First observedv0.1.0

TDQS

A4.1/5.0
Behavior5/5

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

Annotations only declare readOnlyHint=false, idempotentHint=true, destructiveHint=false; the description goes far beyond, disclosing dedup behavior, exact rejection conditions (empty/sanitized-empty content, operating-context project_id refusal), truncation under the length cap, embedding-mode effects, and pause_persistence semantics. Nothing it claims conflicts with the annotations.

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

Conciseness3/5

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

Front-loaded with a clean one-line purpose, and most content is substantive rather than padding. However the response contract is delivered as a single dense run-on with deeply nested parentheticals, which impedes scanning despite the useful information.

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?

There is no output schema, so the description must carry the return contract itself — and it does exhaustively, enumerating 'stored'/'skipped'/'rejected' with their exact fields, edge cases, and a migration note. For a 6-param, nested-object tool this leaves nothing an agent needs missing.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents every parameter at length (project_id '@auto' resolution, session_key partition semantics, message fields). The description adds little parameter-level detail beyond that, so baseline 3 applies.

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 opening sentence gives a precise verb+resource ('Store a message in agent memory for future recall'), and 'for future recall' implicitly delineates it from retrieval siblings like recall and reconstruct. An agent can distinguish it from declare_associations, list_memories, and archive_episode without opening any schema.

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

Usage Guidelines3/5

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

Usage is implied rather than stated: it explains that under pause_persistence the write is skipped and to 'branch on persisted', and to read resolved_project_id before relying on resolution. However, there is no explicit when-to-use/when-not guidance, and the overlap with the sibling declare_associations (the tool itself accepts associations) is never addressed.

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