remem-ai 0.6.70

Local-first coding agent memory for Claude Code and OpenAI Codex
Documentation
use rmcp::schemars::{self, JsonSchema};
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct SearchParams {
    #[schemars(description = "Search query (semantic search)")]
    pub query: Option<String>,
    #[schemars(description = "Max results to return (default 20)")]
    pub limit: Option<i64>,
    #[schemars(description = "Project name filter")]
    pub project: Option<String>,
    #[schemars(description = "Observation type filter")]
    pub r#type: Option<String>,
    #[schemars(description = "Result offset for pagination")]
    pub offset: Option<i64>,
    #[schemars(description = "Include stale or archived memories (default false)")]
    pub include_stale: Option<bool>,
    #[schemars(description = "Include policy-suppressed memories (default false)")]
    pub include_suppressed: Option<bool>,
    #[schemars(
        description = "Git branch filter (e.g. 'main', 'feat/auth'). Only returns memories from this branch. Old data without branch info is always included."
    )]
    pub branch: Option<String>,
    #[schemars(
        description = "Enable multi-hop search (default false). When true, performs entity graph expansion: finds entities in first-hop results, then searches for memories mentioning those entities. Use for questions that span multiple topics/people, e.g. 'What do Melanie\\'s kids like?' or 'What events has Caroline participated in?'"
    )]
    pub multi_hop: Option<bool>,
    #[schemars(
        description = "Include retrieval scoring and visibility explanation for standard search (default false). Not supported with multi_hop=true."
    )]
    pub explain: Option<bool>,
    #[schemars(
        description = "Optional task-aware retrieval intent. Accepted values: resume_work/resume-work, explain_decision/explain-decision, debug_failure/debug-failure, apply_preference/apply-preference, review_change/review-change, explore_history/explore-history. When set, MCP search compiles a GH-934 RetrievalPlan and applies its execution policy."
    )]
    pub task_intent: Option<String>,
    #[schemars(
        description = "Agent role for task-aware retrieval planning: coder, reviewer, planner, or researcher (default coder). Only used when task-aware routing is requested."
    )]
    pub role: Option<String>,
    #[schemars(
        description = "Risk class for task-aware retrieval planning: low, medium, or high (default medium). High risk disables raw fallback and only requests router-approved rerank."
    )]
    pub risk: Option<String>,
    #[schemars(
        description = "Total token budget recorded in the task-aware RetrievalPlan (default 4000). Must be greater than zero."
    )]
    pub token_budget: Option<u32>,
    #[schemars(
        description = "Allow superseded history in the task-aware RetrievalPlan. This does not replace include_stale; use include_stale=true when the search result set should include inactive rows."
    )]
    pub include_superseded: Option<bool>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct CurrentStateParams {
    #[schemars(description = "Stable state key, such as a durable topic key.")]
    pub state_key: String,
    #[schemars(
        description = "Project name filter. Defaults to repo-owned state plus global user state."
    )]
    pub project: Option<String>,
    #[schemars(description = "Memory type filter, e.g. decision or preference.")]
    pub r#type: Option<String>,
    #[schemars(description = "Explicit state-key owner scope, e.g. repo or user.")]
    pub owner_scope: Option<String>,
    #[schemars(description = "Explicit state-key owner key, e.g. a repo path or user:default.")]
    pub owner_key: Option<String>,
    #[schemars(description = "Resolve the state that applied at this Unix epoch.")]
    pub as_of_epoch: Option<i64>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct TimelineParams {
    #[schemars(description = "Anchor observation ID")]
    pub anchor: Option<i64>,
    #[schemars(description = "Search query to find anchor")]
    pub query: Option<String>,
    #[schemars(description = "Observations before anchor (default 5)")]
    pub depth_before: Option<i64>,
    #[schemars(description = "Observations after anchor (default 5)")]
    pub depth_after: Option<i64>,
    #[schemars(description = "Project name filter")]
    pub project: Option<String>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct UserRecallParams {
    #[schemars(description = "Task or topic query for user-context recall.")]
    pub query: String,
    #[schemars(description = "Project key/path filter. If omitted, cwd is normalized.")]
    pub project: Option<String>,
    #[schemars(description = "Current working directory used to derive the project key.")]
    pub cwd: Option<String>,
    #[schemars(description = "Optional task intent, e.g. review, implement, debug, plan.")]
    pub task_intent: Option<String>,
    #[schemars(description = "Current file paths relevant to the task.")]
    pub current_files: Option<Vec<String>>,
    #[schemars(description = "Host profile, e.g. codex-cli or claude-code.")]
    pub host: Option<String>,
    #[schemars(description = "Explicit user-context owner scope.")]
    pub owner_scope: Option<String>,
    #[schemars(description = "Explicit user-context owner key.")]
    pub owner_key: Option<String>,
    #[schemars(description = "Stable current-state keys to resolve exactly.")]
    pub state_keys: Option<Vec<String>>,
    #[schemars(description = "Include personal/sensitive/restricted claims for explicit audit.")]
    pub include_sensitive: Option<bool>,
    #[schemars(description = "Include policy-suppressed claims and memories for explicit audit.")]
    pub include_suppressed: Option<bool>,
    #[schemars(description = "Maximum included recall items.")]
    pub limit: Option<i64>,
    #[schemars(description = "Maximum compact context characters.")]
    pub budget_chars: Option<usize>,
}

/// Experimental MCP adapter for the versioned Context Bundle v1 request.
/// Keep this wire shape closed and covered by schema snapshots: additions or
/// renames require an explicit compatibility decision.
#[derive(Debug, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub(super) struct ContextBundleParams {
    #[schemars(description = "Context Bundle request schema version; v1 requires 1.")]
    pub schema_version: u32,
    #[schemars(description = "Task description used for SessionStart relevance selection.")]
    pub task: String,
    #[schemars(description = "Exact project key/path. Defaults to the project derived from cwd.")]
    pub project: Option<String>,
    #[schemars(
        description = "Working directory used for canonical loading and project derivation."
    )]
    pub cwd: Option<String>,
    #[schemars(description = "Optional worktree identity recorded in the versioned request.")]
    pub worktree: Option<String>,
    #[schemars(description = "Optional Git branch scope filter.")]
    pub branch: Option<String>,
    #[schemars(
        description = "Agent role: coder, reviewer, planner, or researcher (default coder)."
    )]
    pub role: Option<String>,
    #[schemars(
        description = "As-of epoch-seconds scope pin. Experimental v1 accepts only 0/omitted until historical canonical loading is implemented."
    )]
    pub as_of_epoch: Option<i64>,
    #[schemars(description = "Total token budget for the bundle (default 4000).")]
    pub token_budget: Option<u32>,
    #[schemars(description = "Risk class: low, medium, or high (default medium).")]
    pub risk: Option<String>,
    #[schemars(
        description = "Allow superseded memories in scope. Experimental v1 accepts only false/omitted until canonical loading supports history."
    )]
    pub include_superseded: Option<bool>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct GetObservationsParams {
    #[schemars(description = "List of observation IDs to fetch")]
    pub ids: Vec<i64>,
    #[schemars(description = "Project name filter")]
    pub project: Option<String>,
    #[schemars(description = "Source type: 'memory' or 'observation' (default: 'memory')")]
    pub source: Option<String>,
    #[schemars(description = "Include policy-suppressed memories (default false)")]
    pub include_suppressed: Option<bool>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct CommitLookupParams {
    #[schemars(description = "Full or short git commit SHA to look up")]
    pub sha: String,
    #[schemars(description = "Optional project filter")]
    pub project: Option<String>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct SessionCommitsParams {
    #[schemars(description = "Content session ID or remem memory session ID")]
    pub session_id: String,
    #[schemars(description = "Optional project filter")]
    pub project: Option<String>,
    #[schemars(description = "Max linked commits to return (default 20, max 100)")]
    pub limit: Option<i64>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct SaveMemoryParams {
    #[schemars(description = "Memory text content")]
    pub text: String,
    #[schemars(description = "Optional title")]
    pub title: Option<String>,
    #[schemars(description = "Project name")]
    pub project: Option<String>,
    #[schemars(
        description = "Optional host session id. When provided, Stop summary promotion can suppress exact duplicate candidates from the same session."
    )]
    pub session_id: Option<String>,
    #[schemars(description = "Optional host identifier, e.g. codex-cli, claude-code, api, cli.")]
    pub host: Option<String>,
    #[schemars(
        description = "Stable topic identifier for cross-session dedup. Same project+topic_key updates existing memory instead of creating new one. Format: kebab-case descriptive key, e.g. 'fts5-search-strategy', 'auth-middleware-design'."
    )]
    pub topic_key: Option<String>,
    #[schemars(
        description = "Memory type: decision, discovery, bugfix, architecture, preference. Defaults to 'discovery'."
    )]
    pub memory_type: Option<String>,
    #[schemars(description = "List of related file paths")]
    pub files: Option<Vec<String>>,
    #[schemars(
        description = "Optional local markdown path for backup copy. Relative paths are resolved from current working directory. The resolved path must fall within the remem data directory (REMEM_DATA_DIR); paths outside that boundary are rejected."
    )]
    pub local_path: Option<String>,
    #[schemars(
        description = "Memory scope: 'project' (default, only this project) or 'global' (visible in all projects). Use 'global' only for explicitly cross-project preferences or knowledge."
    )]
    pub scope: Option<String>,
    #[schemars(
        description = "Git branch label. If omitted, the server auto-detects from the MCP process current working directory. Pass an explicit value to override (e.g. when the calling agent is not running inside the project's git checkout)."
    )]
    pub branch: Option<String>,
    #[schemars(
        description = "Explicit episode/source event time (Unix epoch seconds) used to resolve relative dates. Preferred for historical backfills; created_at_epoch is used only when this is omitted."
    )]
    pub reference_time_epoch: Option<i64>,
    #[schemars(
        description = "Optional override for the memory's creation timestamp (Unix epoch seconds). Use only for backfilling historical entries; defaults to now when omitted."
    )]
    pub created_at_epoch: Option<i64>,
    #[schemars(
        description = "Override the local markdown backup toggle. Default behavior (when omitted) is controlled by the server config."
    )]
    pub local_copy_enabled: Option<bool>,
    #[schemars(
        description = "Override the session claim toggle. Defaults to true; set false to preserve legacy save behavior without claim rows."
    )]
    pub claim_enabled: Option<bool>,
    #[schemars(
        description = "Optional claim source label. Defaults to manual_save for MCP calls."
    )]
    pub claim_source: Option<String>,
    #[schemars(
        description = "Explicitly acknowledge an instruction-pattern match in direct save text after human review. Must match the detected pattern id, e.g. override_previous_instructions."
    )]
    pub acknowledge_pattern: Option<String>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct GovernMemoryParams {
    #[schemars(description = "Curated memory IDs to mutate. Use dry_run=true first to preview.")]
    pub ids: Vec<i64>,
    #[schemars(description = "Project name filter. Defaults to the MCP process current project.")]
    pub project: Option<String>,
    #[schemars(description = "Governance action: delete, reject, stale, or acknowledge-pattern.")]
    pub action: String,
    #[schemars(
        description = "Pattern id required when action is acknowledge-pattern, e.g. override_previous_instructions."
    )]
    pub acknowledge_pattern: Option<String>,
    #[schemars(description = "Explicit user-visible reason for the mutation.")]
    pub reason: Option<String>,
    #[schemars(description = "Actor initiating the mutation, e.g. user, codex, claude.")]
    pub actor: Option<String>,
    #[schemars(
        description = "Preview affected memories without writing status changes or audit events."
    )]
    pub dry_run: Option<bool>,
    #[schemars(description = "Required true for non-dry-run destructive governance mutations.")]
    pub confirm_destructive: Option<bool>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct TimelineReportParams {
    #[schemars(description = "Project name (required)")]
    pub project: String,
    #[schemars(description = "Full report with timeline and monthly breakdown (default false)")]
    pub full: Option<bool>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct WorkStreamsParams {
    #[schemars(description = "Project name filter")]
    pub project: Option<String>,
    #[schemars(description = "Status filter: active, paused, completed, abandoned")]
    #[schemars(schema_with = "workstream_status_schema")]
    pub status: Option<String>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct UpdateWorkStreamParams {
    #[schemars(description = "WorkStream ID to update")]
    pub id: i64,
    #[schemars(description = "New status: active, paused, completed, abandoned")]
    #[schemars(schema_with = "workstream_status_schema")]
    pub status: Option<String>,
    #[schemars(description = "Next action to take")]
    pub next_action: Option<String>,
    #[schemars(description = "Current blockers")]
    pub blockers: Option<String>,
}

fn workstream_status_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
    schemars::json_schema!({
        "type": "string",
        "enum": ["active", "paused", "completed", "abandoned"],
        "nullable": true
    })
}

#[derive(Debug, Serialize)]
pub(super) struct SearchResult {
    pub id: i64,
    pub r#type: String,
    pub title: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub topic_key: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub preview: Option<String>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub temporal_facts: Vec<String>,
    pub source: String,
    pub source_type: String,
    pub updated_at: String,
    pub project: String,
    pub status: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub staleness: Option<crate::memory::MemoryStalenessLabel>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct SearchRawParams {
    #[schemars(
        description = "Raw FTS query across every user/assistant turn captured by the raw archive. Unlike `search`, this bypasses all curation and returns literal chat content. Use when `search` comes back empty or you need to recall an exact phrase from past conversations."
    )]
    pub query: String,
    #[schemars(description = "Project name filter")]
    pub project: Option<String>,
    #[schemars(
        description = "Git branch filter. Returns raw rows for this branch plus older rows without branch metadata."
    )]
    pub branch: Option<String>,
    #[schemars(description = "Role filter: 'user' or 'assistant' (default: both)")]
    pub role: Option<String>,
    #[schemars(description = "Max results to return (default 20)")]
    pub limit: Option<i64>,
    #[schemars(description = "Result offset for pagination")]
    pub offset: Option<i64>,
    #[schemars(
        description = "Only rows at or after this time (Unix epoch, ISO8601 datetime, or YYYY-MM-DD)"
    )]
    pub since: Option<String>,
    #[schemars(
        description = "Only rows at or before this time (Unix epoch, ISO8601 datetime, or YYYY-MM-DD; a date includes that full UTC day)"
    )]
    pub until: Option<String>,
}

#[derive(Debug, Deserialize, JsonSchema)]
pub(super) struct ListRawSessionsParams {
    #[schemars(
        description = "Only sessions with messages at or after this time (Unix epoch, ISO8601 datetime, or YYYY-MM-DD)"
    )]
    pub since: Option<String>,
    #[schemars(
        description = "Only sessions with messages at or before this time (Unix epoch, ISO8601 datetime, or YYYY-MM-DD; a date includes that full UTC day)"
    )]
    pub until: Option<String>,
    #[schemars(description = "Project name filter")]
    pub project: Option<String>,
    #[schemars(
        description = "Sample up to N role=user message texts per session, ascending by time (default 0 = no samples)"
    )]
    pub sample: Option<i64>,
}

#[derive(Debug, Serialize)]
pub(super) struct RawSearchHit {
    pub id: i64,
    pub source_type: String,
    pub session_id: String,
    pub project: String,
    pub role: String,
    pub preview: String,
    pub source: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub branch: Option<String>,
    pub created_at: String,
}