| get_agent_contextA | Load an agent's system prompt and contract from the RC. Reads system-prompt.md and contract.md from agents/{agent_slug}/.
If the agent is not found, lists all available agents.
Args:
agent_slug: Folder name of the agent (e.g. "archivist", "librarian").
|
| log_agent_runA | Log a completed agent run to the database for audit and dashboard tracking. Records that an agent did a piece of work so it appears in the dashboard's
Agents view and in get_agent_runs. Call it after writing an output file, per
the output contract. When a session_id is supplied it also writes a "result"
event to session_events, closing the loop for /metis pipeline calls.
Args:
agent_slug: Slug of the agent that performed the work (e.g. "librarian").
task_summary: Brief description of what the agent did.
input_path: Path to the input file(s), if any (default empty string).
output_path: Path to the output file(s) produced, if any (default empty).
complexity: The run status stored in the `status` column — typically
"completed", "partial", or "failed" (default "standard").
input_tokens: Input tokens consumed, for cost tracking (default 0).
output_tokens: Output tokens produced, for cost tracking (default 0).
model: Model identifier used, e.g. "claude-sonnet-4-6" (default empty).
session_id: Pipeline session ID from session_bootstrap(); when set, also
records a result event in session_events (default empty string).
Returns:
A confirmation message naming the agent and task that were logged.
|
| get_agent_runsA | Retrieve recent agent run history from the database. Returns the log of past agent work — what ran, when, its status, and token
usage — for the dashboard or for reviewing recent activity. These rows are
written by log_agent_run. Results come back newest first.
Args:
limit: Maximum number of runs to return, newest first (default 10).
since: ISO date or datetime string; only runs at or after this time are
returned. Empty string (default) returns runs from all dates.
agent_slug: Filter to a single agent by slug, e.g. "librarian" or
"metis". Empty string (default) returns all agents.
Returns:
A text block listing the matching runs (run_id, agent, task summary,
status, timestamp, token counts, model).
|
| search_literatureA | Search the user's literature database. Searches your curated/seeded literature catalogue by structured facets
(disease, method, geography, keyword). For your Zotero/manual reference
metadata use search_library; for full PDF body text use search_fulltext;
for semantic RAG over indexed PDFs use search_pdf_knowledge.
Searches the library_seeded SQLite table. Use this to find papers
by disease focus, methodology, geography, or any keyword.
Args:
query: Search term, matched as a case-insensitive substring.
field: Column to search -- one of "all", "disease", "method",
"geography", or "article".
limit: Maximum number of results to return (default 20).
Returns:
A single TextContent holding a markdown table of matching rows from the
library_seeded table, or an error/"no results" message if the database,
table, or column is missing or nothing matches.
|
| search_notesA | Search markdown notes across domains, projects, and library. Case-insensitive substring search with surrounding context lines.
Args:
query: Search term.
scope: Where to search -- "all", "domains", "projects", "library".
limit: Maximum results (default 15).
max_chars_per_result: Truncate each result's context to this many characters (default 500).
Pass 0 for no truncation.
|
| create_projectA | Register a new project in the Metis platform. Called when a researcher confirms they want a Claude conversation or project
tracked permanently in Metis. Creates the project record in the DB so it
appears in the Work tab and is available for task linking and memory search.
Args:
title: Human-readable project name, e.g. "Statistics Course".
description: What this project is about (one sentence).
domain: Research domain, e.g. "education", "epidemiology". Optional.
source: Origin — "claude_project" (default), "claude_cowork", or "manual".
|
| get_project_statusA | Status of your registered projects. Reads the project REGISTRY (the `projects` table — the source of truth that
the dashboard Work tab shows), not just the folders on disk, and adds task
completion counts. Empty project_id lists ALL active projects; a specific
project_id (exact or partial) shows that one, enriched from its folder card
if a `projects/active/<name>/` folder exists.
Args:
project_id: Project id (or part of one). Empty string = all active projects.
|
| archive_projectA | Archive a project — marks it inactive but keeps all data. Sets status='archived' in projects table. Project disappears from
active view but remains available for brainstorm context and search.
Args:
project_id: The project_id to archive.
|
| unarchive_projectA | Restore an archived project to active status. Args:
project_id: The project_id to restore.
|
| remove_projectA | Remove a project from Metis entirely. Deletes project record and associated tasks from DB.
If delete_files=True, also deletes the external_path folder from disk
(only if path is within RC root — safety check enforced).
Args:
project_id: The project_id to remove.
delete_files: If True, delete the project folder from disk. Default False.
|
| load_project_contextA | Load the full context block for a project — ready to paste into Claude. Returns the project's context_doc, recent session history, and next step
formatted as a structured brief. Use this at the start of any work session
on a specific project so Claude has full background.
Args:
project_id: The project slug (e.g. "hat-dashboard", "article-1").
|
| update_project_memoryA | Append a session summary to a project's history and refresh its prompt memory. Call this at the end of any work session on a project. The history feeds
into load_project_context() so future sessions automatically know what
happened before.
Args:
project_id: The project slug.
what_was_done: 1-3 sentence summary of what was accomplished this session.
next_steps: Optional: what needs to happen next. Updates the next_step field.
|
| detect_projectsA | Scan a folder for unregistered git repos and article folders. Useful for onboarding — finds existing project folders that are not yet
tracked in Metis. Call create_project() for each item you want to register.
Args:
scan_path: Absolute path to scan. Defaults to the parent of METIS_RC_ROOT.
|
| save_reviewA | Save an agent's output as a review file and record the run. This is the standard way a Metis agent persists its work: it writes the
markdown to outputs/reviews/{agent_slug}/{date}_{task_slug}.md and, by
default, logs the run so the dashboard's Agents tab tracks it. Use it at the
end of any substantive agent task so the result is filed and discoverable.
Args:
agent_slug: Slug of the agent that produced the review
(e.g. "epidemiologist", "writing-partner").
task_slug: Short kebab-case slug identifying the task; becomes part of
the filename (e.g. "article1-methodology").
content: The full review content as markdown.
log_run: Whether to also record this as an agent run for the dashboard.
Defaults to True.
Returns:
A confirmation with the path of the saved review file.
|
| get_tasksA | Query tasks from the SQLite database with optional filters. Args:
status: Filter by status -- "open", "done", "blocked", or "" for all.
project_id: Filter by project. Empty = all projects.
owner: Filter by owner. Empty = all owners.
limit: Maximum results (default 25).
|
| create_taskA | Create a new task in the SQLite database. Args:
title: Short task description.
project_id: Which project this task belongs to.
owner: Who is responsible (default "Metis").
notes: Additional details or context.
due_date: Optional due date in YYYY-MM-DD format.
recurrence: Optional repeat — "daily", "weekly", "monthly", or "yearly".
When a recurring task is completed, the next occurrence is created automatically.
parent_task_id: Optional parent task — set this to make this a subtask.
|
| update_taskA | Update an existing task — its status, title, owner, notes, due date, or recurrence. The companion to create_task and get_tasks: use this to mark a task done or
blocked, reschedule it, reassign it, or edit its details. Only the fields you
pass are changed; empty arguments leave the existing value untouched. Marking
a recurring task "done" automatically creates its next occurrence. Find a
task_id with get_tasks; use delete_task to remove a task entirely.
Args:
task_id: ID of the task to update (as shown by get_tasks). Required.
status: New status — "open", "done", or "blocked". Empty = unchanged.
title: New title. Empty = unchanged.
owner: New owner. Empty = unchanged.
notes: New notes/details. Empty = unchanged.
due_date: New due date in "YYYY-MM-DD" format. Empty = unchanged.
recurrence: New repeat — "daily", "weekly", "monthly", or "yearly".
Empty = unchanged; pass "none" to clear an existing recurrence.
Returns:
A confirmation listing the changed fields (and the next-occurrence id if a
recurring task was completed), or a note if the task_id was not found.
|
| delete_taskA | Permanently delete a task from the database. The destructive complement to create_task — removes the task row entirely.
Use this for tasks created in error or no longer relevant; to instead mark
work finished (and continue a recurring series), use update_task with
status="done". Find the task_id with get_tasks. This cannot be undone.
Args:
task_id: ID of the task to delete (as shown by get_tasks). Required.
Returns:
A confirmation that the task was deleted, or a note if no task with that
id exists.
|
| capture_ideaA | Store an idea in the SQLite ideas table. Auto-extracts tags from content. Links to domains/projects if keywords match.
Unless `auto_cross_pollinate=False`, automatically surfaces up to 5 cross-
pollination matches from library / meetings / news / older ideas in the same
response — so the user sees connections without a second tool call.
Args:
content: The idea text.
source: Where the idea came from (default "manual").
image_path: Optional path to an associated image.
auto_cross_pollinate: When True (default), include connection matches in the response.
|
| get_ideasA | List captured ideas from your knowledge base, newest first. Use this to review what you've been thinking about over a chosen time
window — the ideas you logged with capture_idea — so you can revisit,
connect, or act on them. Pairs with capture_idea (to add) and
cross_pollinate (to surface related work).
Args:
scope: Time window to retrieve. One of "today", "week" (last 7 days),
"month" (last 30 days), or "all". Defaults to "week".
limit: Maximum number of ideas to return, newest first. Defaults to 20.
Returns:
A formatted list of matching ideas with their timestamps and tags, or a
friendly note if none were found in that window.
|
| add_journal_entryA | Store a journal entry with auto-extracted mood and energy. Args:
content: The journal entry text.
image_path: Optional path to an associated image.
|
| daily_noteA | Append to (or read) today's daily note — one rolling note per day. Unlike add_journal_entry (which creates a new row each time), daily_note
keeps a single entry per calendar day and appends timestamped lines to it —
the Reflect/Tana "daily note" pattern for fast, low-friction capture.
Args:
text: Line to append. Leave empty to just read today's note so far.
|
| get_journalA | List journal entries from your knowledge base, newest first. Use this to look back over your dated journal/log entries — reflections,
progress notes, and session handoffs — optionally from a given start date.
Helpful for "what was I working on lately?" and for rebuilding context at
the start of a session.
Args:
date_from: Earliest entry date to include, as "YYYY-MM-DD". Empty
string (the default) applies no date filter and returns the most
recent entries.
limit: Maximum number of entries to return, newest first. Defaults to 10.
Returns:
A formatted list of journal entries with their dates, or a note if none
match.
|
| get_contactsA | Retrieve all contacts from the contacts table. |
| update_contactA | Add or update a contact record. Args:
name: Contact's full name (used as unique key).
notes: Notes about this contact.
role: Contact's role or affiliation.
birthday: Birthday in YYYY-MM-DD format.
|
| get_glossaryA | Retrieve all glossary terms. |
| add_glossary_termA | Add a glossary term, or update its definition if it already exists. Maintains a personal glossary of field-specific terms and acronyms so
Metis can give consistent definitions across sessions. Upserts on the
term (an existing term keeps its created_at but takes the new definition).
Retrieve entries with get_glossary.
Args:
term: The term, acronym, or phrase to define; serves as the unique key,
so reusing an existing term overwrites its definition.
definition: The definition text to store for this term.
Returns:
A confirmation message naming the term that was added or updated.
|
| find_connectionsA | Search library, meetings, and news for items related to given text. Searches library_seeded, meetings, and news_briefs tables for related
content using keyword matching.
Args:
content: Text snippet to find connections for.
limit: Maximum results per source (default 5).
|
| cross_pollinateA | Find cross-domain connections for given text. Searches library_seeded, meetings, news_briefs, and ideas tables
for related items. Returns top 5 with source type, title, and snippet.
Args:
content: Text to find cross-domain connections for.
|
| assemble_brainstorm_contextA | Assemble context from multiple sources for brainstorming. Gathers recent content from selected sources, respecting an 8000 char
limit per source. Returns assembled context string with source labels.
Args:
sources: List of sources to include: "library", "meetings", "news", "ideas", "journal".
date_filters: Optional dict with source-specific date filters, e.g. {"ideas": "2026-03-01"}.
|
| check_data_safetyA | Scan content for PII patterns and classify sensitivity level. Returns safety status, classification, and specific warnings.
Args:
content: Text content to scan.
file_path: Optional file path for context-based classification.
|
| scan_tracked_filesA | Scan all tracked files and report which have changed since last scan. Reads tracked_files table, checks actual file modification times,
and updates last_scanned timestamps.
|
| add_tracked_fileA | Add a single file to the tracked-files list and start watching it. Registers one file so Metis notices when it changes and can read it later
via read_file; tracked files surface on the dashboard's Planning tab. The
file's current modification time is recorded and watch is set on. Re-adding
an existing path updates it (and keeps the old label unless a new one is
given). To register a whole project at once, use connect_project_folder.
Args:
path: Absolute path to the file to track; the file must exist or an
error is returned.
label: Optional category label for the file (default empty string);
on re-add, an empty label leaves the existing label unchanged.
Returns:
A confirmation message naming the tracked file (and its label, if any),
or a "file not found" / error message.
|
| connect_project_folderA | Register all relevant files in a project folder so Metis can read them. Walks the folder recursively and adds every file with a recognised extension
(.R, .Rmd, .md, .py, .js, .ts, .sql, .json, .yaml, .qmd, .tex, .csv) to
the tracked_files table. Call this once per project; after that, use
read_file() to read any individual file.
Args:
folder_path: Absolute path to the project root folder.
label: Short label for all files from this project (e.g. "MLM Course").
max_files: Safety limit — stop after registering this many files (default 200).
|
| read_fileA | Read the content of a file and return it as text. Works for any text file: R scripts, markdown, Python, JSON, CSV, etc.
The file does not need to be pre-registered in tracked_files.
Args:
path: Absolute path to the file to read.
max_chars: Maximum characters to return (default 8000). For large files,
increase this or ask for a specific section.
|
| list_folderA | List files in a folder. Args:
folder_path: Absolute path to the folder.
pattern: Glob pattern to filter files (e.g. "*.R", "*.md"). Default: all files.
|
| list_basketA | List files in the Metis basket (legacy & inspiration documents). The basket is a flat holding area for any document kept as a reference for
future work. The private/ subfolder is NEVER listed — it contains personal
or patient data. |
| promote_basket_itemA | Move a basket item to a stable project folder (promote from basket to active storage). Refuses to touch basket/private/ items.
Args:
source_path: Absolute path to the file in basket/ to promote.
target_path: Absolute destination path (file or folder).
|
| remove_tracked_fileA | Stop tracking a file so Metis no longer watches it for changes. Removes a single file from the tracked-files list (the files the dashboard
Planning tab scans for activity). Use this when a file is no longer relevant
or was added by mistake. The file on disk is never touched — only its
tracking record is deleted. The inverse of add_tracked_file.
Args:
path: Absolute path of the file to stop tracking. Must match the path
exactly as it was registered.
Returns:
A confirmation that tracking stopped, or a note if the path was not in
the tracking list.
|
| generate_daily_insightA | Assemble recent activity into context for the daily insight. Gathers the raw material for a "what's happening across your research"
digest: the last 7 days of agent_runs summaries, last 3 days of high-signal
news_briefs, last 14 days of meeting titles, and last 7 days of new library
additions. It stores a placeholder row in daily_insights; the Metis agent
does the actual synthesis from the returned context. Read the stored result
later with get_daily_insight.
Takes no arguments.
Returns:
A text block of the assembled recent context (and the sources drawn on)
for the agent to synthesize into a daily insight.
|
| save_daily_briefA | Save a composed daily brief so the dashboard widget shows it. This is the write-back half of the daily-brief round-trip. Claude Desktop (or
Claude Code) composes the brief from generate_daily_insight() context, then
calls this to upsert the finished prose into the daily_insights table — the
same table the dashboard's morning-brief widget reads via get_daily_insight().
Desktop and the dashboard share one database, so no files are involved: once
saved, the brief appears in the dashboard on next load.
Args:
content: The finished daily-brief prose (markdown ok). Required.
sources: Comma-separated list of what the brief drew on (optional).
date: YYYY-MM-DD; empty = today.
model: Model identifier that composed it, for provenance (optional).
Returns:
Confirmation with the date saved and a pointer to the dashboard widget.
|
| get_daily_insightA | Retrieve a stored daily insight. Args:
date: Date in YYYY-MM-DD format. Empty = today.
|
| get_new_publicationsA | Retrieve new publications, optionally filtered by topic. Args:
topic: Filter by topic tag. Empty = all topics.
limit: Maximum results (default 20).
unread_only: If True, only return unread publications (default True).
|
| mark_publications_readA | Mark new publications as read by their IDs. Clears items from the "new publications" queue once the user has seen them,
stamping each with a read time so they stop resurfacing. Use the IDs
returned by get_new_publications.
Args:
ids: List of new_publications row IDs to mark as read; an empty list is
a no-op.
Returns:
A confirmation message with the count of publications marked as read.
|
| get_user_topicsA | Return all active topics from user_topics. |
| add_user_topicA | Add a topic to track for new publications. Args:
topic: Topic name (unique).
description: Optional description of what to look for.
|
| archive_library_itemA | Archive a library item (mark as no longer active but keep in DB). Sets status='archived' in library_seeded table. Item stays available
for search and cross-pollination but disappears from default view.
Args:
relative_path: The relative_path primary key in library_seeded table.
|
| remove_library_itemA | Remove a library item from the Metis index, optionally deleting the file. De-indexes a paper or document by deleting its row from library_seeded. By
default the file on disk is left untouched (index-only removal); set
delete_file=True to also delete the file, which is guarded so only paths
inside the PKM root can be removed. To hide rather than remove an item, use
archive_library_item instead.
Args:
relative_path: The relative_path primary key identifying the row in the
library_seeded table.
delete_file: If True, also delete the underlying file from disk (subject
to the within-PKM-root safety check); if False (default), only the
index row is removed.
Returns:
A confirmation message of what was removed, or a not-found / error
message if the item or table is missing.
|
| search_literature_extendedA | Search literature with optional inclusion of archived items. Searches library_seeded table across basename, relevance_note, disease,
geography, method fields. By default excludes archived items.
Args:
query: Search term.
include_archived: Include items with status='archived'. Default False.
limit: Max results. Default 20.
|
| export_knowledge_markdownA | Export the library as a cross-linked Obsidian-style Markdown vault. Writes one Markdown note per library item (YAML frontmatter + abstract) plus
an index, with [[wikilinks]] between items that share a tag — the
claude-obsidian / LLM-Wiki pattern. Gives you a portable, human-readable,
git-diffable view of the knowledge graph you can open in Obsidian. Read-only
on the database; writes only Markdown.
Args:
out_dir: Destination folder. Default: outputs/knowledge-export/ under the RC root.
|
| get_user_configA | Return the full Metis user configuration from user-config.yaml. Returns the complete YAML content (research interests, data sensitivity,
specialist contexts, etc.). For a lightweight profile summary (name,
interests, news_topics), use get_user_profile() instead.
Creates the config file with defaults if it does not exist yet.
|
| add_specialist_contextA | Add a specialist context to the user profile, or update it if it exists. Specialist contexts tell Metis which domains the user works in so routing
and search can be tailored. This appends to specialist_contexts in
user-config.yaml (creating the file with defaults if absent); if a context
with the same name already exists, its description is updated instead of
duplicated. Related tools: toggle_context, list_contexts.
Args:
name: Short label for the context, e.g. "Epidemiological dashboards";
also the key used to detect and update an existing context.
description: One or two sentences describing what this context covers.
active_by_default: If True (default), the context is added to
active_contexts immediately; if False, it is stored but left
inactive (and removed from active_contexts if already present).
Returns:
A confirmation message stating whether the context was added (and
activated) or an existing one was updated.
|
| toggle_contextA | Activate or deactivate a specialist context. Args:
name: Context name to toggle (must exist in specialist_contexts).
active: True to activate, False to deactivate.
|
| list_contextsA | List all user contexts (general + specialist) with active status. |
| write_user_configA | Write the full user-config.yaml produced by the first-run config wizard. Merges the provided YAML into the existing config so that specialist_contexts
and active_contexts set by earlier tools are preserved.
Args:
yaml_content: Complete YAML string as produced by the wizard (all sections).
|
| write_user_preferencesA | Write user-preferences.json produced by the first-run config wizard. Merges the provided JSON into any existing preferences so incremental wizard
saves do not overwrite earlier sections.
Args:
json_content: JSON string with preference keys (news_topics, journals,
pubmed_query, openalex_query, theme, density, etc.).
|
| ingest_ideas_documentA | Import an ideas document (Word/text/markdown) and capture each idea. Reads the file, splits it into discrete items (paragraphs, bullet points,
or numbered items), and calls capture_idea() for each non-empty item.
Supports .txt, .md, and .docx files.
Args:
file_path: Absolute or METIS_RC_ROOT-relative path to the ideas file.
|
| remove_first_run_markerA | Delete the .first-run marker file to signal that the config wizard is complete. Called at the end of the first-run wizard after all config files are written.
Safe to call even if the marker does not exist. |
| generate_imageA | Generate an image using AI and save it to the PKM. Saves to {pkm_root}/outputs/images/YYYY-MM-DD_[slug].png
Args:
prompt: Description of the image to generate.
backend: "gemini" (default) or "huggingface"
model: "flash" (gemini-3.1-flash-preview-image-generation),
"imagen" (imagen-4.0-generate-001),
"flux" (FLUX.1-schnell via HuggingFace)
width: Image width in pixels (default 1024).
height: Image height in pixels (default 1024).
output_filename: Optional custom filename (without extension).
|
| list_generated_imagesA | List recently generated images in the PKM. Reads from {pkm_root}/outputs/images/ directory.
Returns filename, date, and prompt (from JSON sidecar if present).
Args:
limit: Maximum number of images to return (default 20, newest first).
|
| record_thinking_eventA | Record one signal about how you think and work, to personalise Metis. Each event is a small piece of evidence — you acted on a brainstorm, rated
an idea highly, flagged an agent's output — that feeds your evolving
"thinking profile". Over time these signals let Metis tailor its routing,
suggestions, and tone to your preferences. Call it whenever a meaningful
preference moment occurs; read the accumulated profile with
get_thinking_profile.
Args:
event_type: The kind of signal. Must be one of: "brainstorm_acted_on",
"brainstorm_ignored", "idea_rated_high", "idea_linked_project",
"journal_revisited", "agent_output_accepted", "agent_output_flagged".
source_type: Domain or category the signal belongs to (e.g. "biology").
Optional; defaults to empty.
content_id: ID of the related content record (idea, journal entry, etc.)
if applicable. Optional; defaults to 0 (none).
agent_slug: Agent identifier this signal relates to, used for the
"agent_output_*" event types. Optional.
context: Free-text note giving context for the event. Optional.
Returns:
A confirmation that the signal was recorded, or an error listing the
valid event types if an invalid one was supplied.
|
| get_thinking_profileA | Read and return the current thinking profile from system/thinking-profile.yaml. Falls back to default structure if the file does not exist. |
| update_thinking_profileA | Recompute and update the thinking profile from the last 90 days of events. Computes:
- connection_preferences: acted-on rates per domain_pair (source_type)
- preferred_idea_sources: frequency of source_type in high-rated idea events
- agent_feedback: accepted/flagged rates per agent_slug
Writes updated system/thinking-profile.yaml. Safe to call multiple times.
|
| reset_thinking_profileA | Clear all thinking_profile_events and reset thinking-profile.yaml to defaults. This erases all recorded preference signals and restores the default profile.
|
| propose_skill_improvementA | An agent proposes a change to its own skill file. The proposal is queued for human review. The skill file is NOT modified
until the user calls approve_proposal().
Args:
agent_slug: The agent's slug (e.g. 'librarian', 'writing-partner')
proposed_content: The full proposed replacement content of the skill file
rationale: Why this change is being proposed (1–3 sentences)
Returns:
Confirmation with the proposal ID for the user to review
|
| get_pending_proposalsA | List all skill improvement proposals awaiting review. Returns proposals sorted by most recent first, with agent slug, rationale,
and a diff summary (first 200 chars of proposed content). |
| approve_proposalA | Approve a pending skill improvement proposal and apply it. Writes the proposed content to the agent's skill.md file and marks
the proposal as approved. Creates a backup of the current skill file first.
Args:
proposal_id: The numeric ID from get_pending_proposals()
|
| reject_proposalA | Reject a pending skill improvement proposal without applying it. The skill file is not changed. The proposal is marked rejected with an
optional reason.
Args:
proposal_id: The numeric ID from get_pending_proposals()
reason: Optional note explaining why the proposal was rejected
|
| write_reflexionA | Stage 11: Record an agent self-critique entry to the reflexion_log. Called at the end of every agent run to capture experience: what worked,
what could be better, what context was missing, what tools were needed.
Entries are reviewed by the weekly Coach loop for self-improvement proposals.
Args:
session_id: Pipeline session ID from session_bootstrap().
agent_slug: Which agent is writing the reflexion (e.g. 'librarian').
went_well: What went well in this run (1–2 sentences).
could_improve: What could have been done better (1–2 sentences).
missing_context: What context or data was unavailable but needed.
tool_wishes: Tools or capabilities that would have helped.
|
| transcribe_recordingA | Transcribe a meeting recording using Whisper. Optionally applies speaker diarization with pyannote.audio if installed
and HF_TOKEN is set. Saves the transcript alongside the audio file and
updates the meetings table.
Args:
recording_id: The meeting_id from the meetings table (shown in Meetings tab)
Returns:
Transcript text (with speaker labels if diarization succeeded) and
the path where it was saved.
|
| search_memoryA | Search the memory palace by keyword. Looks across Metis's long-term memory to recall past context — what was
decided, found, or noted before. It searches the memory_entries table
(title, summary, topics) and also greps journal/**/*.md files on disk, so
both structured memory and freeform journal notes are covered.
Args:
query: Keyword or phrase to match against entry titles, summaries,
topics, and journal note text.
entry_type: Optional filter limiting results to one kind of entry —
"session", "journal", "idea", "decision", or "topic". Empty string
(default) searches all types.
Returns:
A text block of matching memory entries and journal hits, or a message
when nothing matches.
|
| add_memory_entryA | Add a new memory entry to the memory palace. Use this for a human-curated 'memory palace' note (title + summary + topics,
optionally saved as a markdown file). For machine/agent event logging use
store_episodic_memory; for a distilled concept/definition use
store_semantic_memory.
Inserts into the memory_entries table. If detail is provided, also writes
a markdown file under journal/{entry_type}s/.
Args:
title: Short title for the entry.
summary: One-paragraph summary, stored in the DB and shown in search.
topics: Comma-separated topic tags, e.g. "metis-setup,mcp-server".
entry_type: One of "session", "journal", "idea", "decision", or "topic".
detail: Full markdown content for the optional .md file.
computer: Hostname of the computer this entry is from (optional).
Returns:
A single TextContent confirming the saved entry (title, generated ID,
type, topics, and the markdown file path if one was written), or an
error message if the database is missing or the write fails.
|
| get_topic_memoryA | Return all memory entries tagged with a specific topic, newest first. Args:
topic: Topic tag to filter by (e.g. "metis-setup", "phd-research").
|
| list_recent_memoryA | Return the n most recent memory entries (default 10). Useful at the start of a session to recall what was last worked on.
Args:
n: Number of entries to return (default 10).
|
| session_bootstrapA | Stage 1: Find or create a session for the current computer. Checks for an active session (same computer, last active within 2 hours).
If found: resumes it and returns the last 5 events.
If not: creates a new session and seeds context from recent memory.
Args:
client: Which Claude client is calling ('code'|'chat'|'cowork'|'dashboard').
|
| save_session_eventA | Stage 8: Persist one atomic event to session_events (write-through guarantee). Call this after every tool call, file write, and classification decision.
Event types: 'turn' | 'tool_call' | 'result' | 'file_write' | 'redline' | 'classification'
Args:
session_id: Session ID from session_bootstrap().
event_type: Category of event being recorded.
content: Event content (truncated to 2000 chars).
|
| run_metisA | Master /metis entry point — runs the 11-stage pipeline and returns a routing decision. Every /metis invocation passes through here. The pipeline:
1. Bootstraps or resumes the session
2. Classifies content (PUBLIC/INTERNAL/CONFIDENTIAL/SENSITIVE)
3. Data Guardian: blocks SENSITIVE requests outright
4. Cybersecurity: blocks prompt injection and suspicious URLs
5. Parses intent and selects the appropriate agent(s)
6. Allocates model and token budget
7. Assembles minimum surgical context from memory
8. Persists the turn to session_events
9. Returns routing decision — agents execute and then call:
save_session_event(..., 'result', output)
log_agent_run(..., session_id=session_id)
write_reflexion(session_id, agent_slug, ...)
Stages 10 (logging) and 11 (reflexion) are called by the executing agent
after completing their work.
Args:
request: The researcher's request text.
session_id: Existing session ID if resuming. Leave empty to auto-bootstrap.
client: Which Claude client is calling ('code'|'chat'|'cowork'|'dashboard').
max_turns: Maximum pipeline turns before graceful truncation (default 20).
|
| store_episodic_memoryA | Store an event in episodic memory and index it for vector search. Logs a time-stamped EVENT (something that happened) and indexes it for vector
search. For a distilled, timeless concept/definition use store_semantic_memory;
for a human-curated palace note use add_memory_entry.
Episodic memory is a chronological log of things that happened — ideas,
notes, papers read, tasks completed, agent runs.
Args:
content: The text content of the event to remember.
event_type: One of 'idea', 'note', 'task', 'paper', 'meeting', or
'agent_run'.
session_id: Current pipeline session ID (optional).
metadata: JSON string with extra fields such as title, tags, or source.
Returns:
A single TextContent confirming the stored event (its row id and type),
or an error message if the database is missing, fastembed is not
installed, or the write fails.
|
| store_semantic_memoryA | Store a distilled knowledge node in semantic memory. Stores a distilled CONCEPT/definition (timeless 'what I know'). For a
time-stamped event use store_episodic_memory; for a human-curated palace
note use add_memory_entry.
Semantic memory holds the 'what I know' layer — concepts, definitions,
and their relationships. Used by retrieval to surface relevant knowledge
without relying on raw event history.
Args:
concept: Short name for the concept, e.g. 'RDT sensitivity' or
'fAChE inhibition'.
definition: A one-to-three-sentence definition or explanation.
related_concepts: Comma-separated names of related concepts.
source_type: Where this came from: 'paper', 'note', 'idea', or
'user_defined'.
source_id: ID of the source record, e.g. a paper DOI or idea_id.
Returns:
A single TextContent confirming the stored node (its row id and concept
name), or an error message if the database is missing, fastembed is not
installed, or the write fails.
|
| store_procedural_memoryA | Store a successful workflow pattern in procedural memory. Procedural memory captures 'how to do things' — repeatable processes,
workflows that worked well, or step-by-step patterns for recurring tasks.
Args:
procedure_name: Short name for this procedure (e.g. 'Domain literature search').
steps: Markdown-formatted steps for the procedure.
trigger_context: What situation should trigger using this procedure.
|
| set_working_memoryA | Write a key/value pair to the current session's working memory. Working memory is an ephemeral scratchpad — it persists for the session
but is not indexed for vector search. Use it for state that agents need
mid-pipeline (e.g. intermediate results, decisions made so far).
Args:
session_id: Pipeline session ID from session_bootstrap().
key: Variable name (e.g. 'current_article', 'user_intent').
value: Value to store (any string, JSON, or text).
|
| get_working_memoryA | Retrieve working memory for a session, or the most recent entries if no session given. Args:
session_id: Pipeline session ID. Leave empty to get the 20 most recent entries
across all sessions.
|
| semantic_searchA | Search across memory layers using vector similarity + keyword RRF fusion. Searches your personal MEMORY layers (episodic/semantic/procedural — things
you or Metis recorded), NOT your document library. For documents/PDFs use
search_pdf_knowledge; for reference metadata use search_library.
Retrieval pipeline (M5.8):
1. Embed the query.
2. Run vector similarity search on each requested layer.
3. Run keyword LIKE search on each layer.
4. Fuse results using Reciprocal Rank Fusion (RRF, k=60).
5. Return top_k deduplicated results ranked by fused score.
Args:
query: Natural language search query to embed and keyword-match.
layers: Comma-separated memory layers to search, drawn from 'episodic',
'semantic', and 'procedural'.
top_k: Number of fused results to return (default 5).
Returns:
A single TextContent listing the top fused results (layer, title, score,
timestamp, and a content preview), or a "no results" / error message.
|
| probe_tool_resultA | M5.7.1 — Probe external tool result for injection patterns. Call this before inserting any externally-sourced content into agent context:
web scrapes, RSS items, PDF extracts, YouTube transcripts, GitHub readmes.
Args:
content: The external content to probe.
source_label: Human-readable label for logging (e.g., "PubMed abstract", "RSS item").
Returns:
JSON with {probed_content, flagged, patterns_found}.
|
| get_constitutionA | M5.7.3 — Load the Metis constitutional policy for agent context. Returns a compact summary of behavioral rules appropriate for the
complexity level. Prepend to any agent's system context to enforce
shared policy across all agent types.
Args:
level: 'quick' | 'standard' | 'deep' | 'chain'
|
| validate_pipeline_stageA | M5.7.4 — Validate a sub-agent output before passing to the next pipeline stage. Treats sub-agent output with the same suspicion as external tool output.
Rejects if any required keys are missing or empty.
Args:
output_json: JSON string of the sub-agent output dict.
required_keys: Comma-separated list of required keys (e.g., "title,summary,agent_slug").
|
| _obsidian_vaultA | Resolve the configured Obsidian vault path, if one is set and valid. Looks up the user's external Obsidian vault so note-indexing tools
(e.g. kg_index_notes) know where to read .md notes from. Checks the
METIS_OBSIDIAN_VAULT environment variable first, then the
integrations.obsidian_vault (or top-level obsidian_vault) key in
user-config.yaml.
Takes no arguments.
Returns:
A Path to the vault directory if it is configured and exists on disk,
otherwise None.
|
| kg_pathsA | Find connection paths between two knowledge library notes via BFS. Args:
from_path: Relative path from knowledge/library/ (e.g. 'concepts/elimination-framework.md')
to_path: Target note path.
max_hops: Maximum path length (default 4).
Returns all paths found up to max_hops, ranked by length.
|
| kg_communityA | Return the connected cluster around a given knowledge library note. Performs BFS flood-fill from the given note up to `depth` hops,
returning all reachable notes grouped by distance. Useful for surfacing
related concepts when working on a specific topic.
Args:
note_path: Relative path from knowledge/library/ (e.g. 'disease-areas/[condition].md')
depth: Maximum hop distance to explore (default 2).
|
| start_spanA | Open a new tracing span. Returns the span_id to pass to end_span(). Args:
name: Human-readable span label (e.g. 'stage_1_bootstrap', 'tool:search_library').
kind: Span type — 'internal' | 'tool' | 'agent' | 'llm'. Default: 'internal'.
session_id: Session identifier (from session_bootstrap). Optional.
run_id: FK to agent_runs.run_id. Optional.
parent_id: Parent span_id for nested spans. Optional.
tags: JSON string of extra key/value metadata. Optional.
Returns the span_id string — pass it to end_span() when the work is done.
|
| end_spanA | Close an open span. Computes duration from start_ms to now. Args:
span_id: The span_id returned by start_span().
status: 'ok' | 'error'. Default: 'ok'.
error: Error message if status='error'. Optional.
Returns a summary line: '{name} — {duration_ms}ms [{status}]'
|
| log_spanA | Record a completed span in one call (no separate start/end needed). Useful for logging retrospective timing data (e.g. 'that DB query took 42ms').
Args:
name: Span label.
duration_ms: How long the work took in milliseconds.
kind: 'internal' | 'tool' | 'agent' | 'llm'. Default: 'internal'.
session_id: Session identifier. Optional.
run_id: FK to agent_runs. Optional.
parent_id: Parent span_id. Optional.
status: 'ok' | 'error'. Default: 'ok'.
tags: JSON string of metadata. Optional.
Returns the new span_id.
|
| get_spansA | Fetch recent agent spans, optionally filtered by session or run. Args:
session_id: Filter to this session. Optional.
run_id: Filter to this agent_runs.run_id. Optional.
limit: Max rows to return. Default: 50.
Returns a JSON array of span objects.
|
| anonymize_textA | Scrub PII from text and return anonymized version + replacement map. Replaces:
- Patient/case IDs → [PARTICIPANT_001]
- GPS coordinates → [GPS_001]
- Belgian national IDs → [NID_001]
- Email addresses → [EMAIL_001]
- Phone numbers → [PHONE_001]
- Name-like tokens (opt.) → [NAME_001]
Args:
content: Text to anonymize.
mode: 'full' — replace; 'preview' — mark without replacing.
replace_names: Also replace CAPITALIZED name-like tokens (heuristic).
Returns JSON with keys 'anonymized' (str) and 'replacements' (dict).
|
| scan_outgoingA | Output rail: check a drafted response for leaked PII before it's sent. The output-side complement to the read-side hook. Agents call this on any
response that might contain individual-level data; it enforces the
constitution's no-pii-output rule. Returns a verdict, what was found, and a
masked version safe to send.
Args:
text: The drafted response text to check.
Returns JSON: {safe: bool, found: {type: count}, masked: str}.
|
| redact_data_fileA | Read a sensitive data file and return a REDACTED preview (masked values). The redaction half of /safe-analysis: where check_data_safety only *detects*
sensitive data and the read-hook *asks*, this returns a masked version so an
approved read shares no raw identifiers. Sensitive columns (patient/case IDs,
names, GPS, etc.) are pseudonymised consistently — the same value always maps
to the same placeholder, so record linkage survives while identity does not.
PII patterns (emails, phones, IDs) are scrubbed from all remaining cells.
Local I/O only — nothing leaves the machine except the masked preview you see.
Args:
path: Absolute local path to a CSV/TSV/text data file.
max_rows: Rows to include in the masked preview (default 20).
Returns JSON: redacted preview rows, the columns masked, and a per-type count.
|
| diff_anonymizationA | Return a unified diff comparing original and anonymized text. Args:
original: Original (pre-anonymization) text.
anonymized: Anonymized text from anonymize_text().
Returns a plain unified-diff string suitable for display.
|
| log_consent_eventA | Append a row to the consent_ledger table. Call this whenever an agent processes data so there is an audit trail
of what was processed, when, and under what classification.
Args:
action: Short description — e.g. 'scan_document', 'anonymize_patient_data'.
data_classification: 'PUBLIC' | 'INTERNAL' | 'CONFIDENTIAL' | 'SENSITIVE'.
agent_slug: Which agent performed the action.
notes: Free-text context.
session_id: Current session identifier.
|
| get_consent_ledgerA | Retrieve recent consent events from the audit ledger. Returns the data-handling consent trail — what data was approved or
classified, by which agent, and when — so you can review or report on how
sensitive data has been treated. Reads the consent_ledger that
log_consent_event writes to.
Args:
limit: Number of most recent ledger rows to return, newest first
(default 30).
Returns:
A JSON text block listing the consent events (id, timestamp, action,
data_classification, agent_slug, notes).
|
| set_network_policyA | Set the current network access policy for all agents. 'strict' — No internet access. Only local DB, files, and MCP tools.
'normal' — Default. Librarian and News Radar may access allowed domains.
'offline' — Airplane mode. All external requests blocked.
Args:
policy: One of 'strict' | 'normal' | 'offline'.
|