Reference
Tool reference
Every capability Mori can call. 204 tools, generated straight from the app's live registry. These descriptions are the exact ones her model reads, so what you see here is what she knows.
Tools from your connected MCP servers appear alongside these automatically, on every provider.
01 Coding & projects23 tools
Projects, git, worktrees, dev servers, previews, self-tests.
create_project_folder
Create a new named project folder
create_workspace
Make an isolated git-worktree WORKSPACE for a big or risky code job — its own branch + directory, so changes never clobber the main checkout (and parallel subagents don't collide). Afterward, shell/git/relative-file tools default to it. Use before a large refactor or an experiment.
enter_workspace
Switch into a workspace (by id, name, or branch) — shell/git/relative-file tools then default to its directory.
exit_workspace
Leave the current workspace — tools go back to their normal working directories.
git_branch
List all git branches (local + remote).
git_checkout
Switch to a branch, or create one with create="true".
git_commit
Stage all changes (unless add_all is "false") and commit with a message. Use after finishing a unit of work.
git_diff
Show the git diff of unstaged (or staged) changes. Use to review edits before committing.
git_init
Initialize a new git repository in a folder.
git_log
Show recent commits (one line each).
git_status
Show the git status of a repo (branch + changed/staged/untracked files). Use before committing or to see what changed.
list_workspaces
List the isolated git-worktree workspaces and which one is active.
merge_workspace
Merge a workspace's branch back into its base (commits pending work first, then a no-ff merge). Set delete_after='true' to remove the worktree once merged.
open_preview
Show the user what you built in the Mori Preview window. Pass a project folder or an .html file path to render it live, OR a localhost URL (e.g. http://localhost:3000) to show a running dev server. ALWAYS call this right after building a web project so the user instantly sees the result without opening anything.
open_project_in_vscode
Open a folder/project in VS Code (opens the folder AND reveals its main file)
remove_workspace
Remove a workspace's worktree directory (refuses if it has uncommitted changes unless force='true'). The branch is kept.
run_python
Run a Python 3 snippet and get its output — for data work, quick math, scripts, using Python libraries. (JavaScript orchestration → run_script; shell commands → run_terminal_command.)
run_script
Write JavaScript that orchestrates MANY steps in ONE turn — the fast path for anything multi-step over files/data/APIs. Inside, an async `mori` object bridges to the machine: await mori.readFile({path}), mori.writeFile({path,content}), mori.listDir({path}), mori.searchFiles({path,query,file_pattern}), mori.httpRequest({url,method,headers,body}), mori.runTerminal({command}), mori.readPdf({path}), mori.ocrImage({path}), mori.queryCsv({path,sql}). Loop, branch, transform, aggregate — normal JS. ONLY what you console.log() comes back to you (intermediate results stay out of your context, so this is far faster than many separate tool calls). Limits: 5-min/50-call cap, no secrets in env, and NO sends/purchases/memory here — those stay as their own tools so approvals apply. Use for: 'rename every file matching X', 'pull these 10 URLs and summarize', 'crunch this CSV then write a report'. Use normal tools for single actions.
scaffold_simple_html_project
Create a simple HTML project with index.html, style.css, and script.js
scaffold_simple_js_project
Create a simple Node.js project with package.json and src/index.js
scaffold_web_app
START HERE for any website/web-app build: scaffolds a designed Vite + React + Tailwind v4 project — design tokens, shadcn-style components, Lucide icons, Inter, scroll motion, and a reference layout. Then build the real content inside that system (README-DESIGN.md is the contract). Never hand-roll blank HTML/CSS for a web project.
vscode_create_project
Create a new project with HTML/CSS/JS files and open it in VS Code. A complete workflow shortcut — creates files, opens VS Code, opens the main file.
vscode_open_and_write
Create a file with content and open it in VS Code immediately.
02 Files & data64 tools
Read, write, search, transform. Plus PDFs, spreadsheets, zips, and deliverables.
append_to_file
Append text to the end of a file (creating it if needed). Use for logs, notes, or adding to an existing file without rewriting it.
brain_traverse
Walk Mori's typed knowledge graph outward from an entity — follow relationships (works_at, part_of, built_with, …) up to depth 2-3 to answer 'what connects X to Y' / 'everything related to X'.
brain_whoknows
Find the people/entities most connected to a topic in Mori's knowledge graph.
business_status
Report which of the user's business accounts are connected (X, Meta, LinkedIn, Stripe, Resend, Shopify) and how many drafts await approval. Use before business tasks so you know what's actually wired up.
cancel_schedule
Cancel a scheduled task by its label or id.
copy_file
Copy a file to a new location
create_document
Generate a polished, ready-to-send DOCUMENT (Word .docx or .pdf) — reports, letters, briefs, proposals, memos. Write the FULL body yourself as rich Markdown (use # / ## headings, **bold**, bullet/numbered lists, > quotes, and | tables |). Saves a real file the user can open. Prefer this over write_file when the user wants an actual document/report/deliverable.
create_file
Create a new file with optional content
create_folder
Create a directory (and parent directories if needed)
create_goal
Create a DURABLE GOAL — a long-lived objective that spans many tasks and sessions (e.g. 'finish the product launch', 'keep the docs accurate'). Goals persist across restarts and devices. Use for multi-session objectives, NOT for one-off tasks.
create_slides
Generate a PowerPoint DECK (.pptx) — pitch decks, presentations, reports as slides. Saves a file the user can open in PowerPoint/Keynote.
create_spreadsheet
Generate a real SPREADSHEET (Excel .xlsx or .csv) — tables, budgets, trackers, data exports. Saves a file the user can open in Excel/Numbers/Sheets.
create_task
Add a task card to Mori's task board (the durable Kanban — survives restarts, visible on every device). Use when work should be tracked/queued rather than done immediately, or to break a goal into pieces.
create_zip
Zip a folder or file into a .zip archive — use this to PACKAGE a site/app/project you built before emailing or uploading it. Pass the folder or file as source: a full path, a name, or 'the site/app you just made'. Returns the .zip path, and the zip is remembered — so right after, you can send_email it (attachmentPath: 'the zip you just made') or upload it. Typical flow: build the site (files) → create_zip the folder → send_email the zip.
delete_file
Delete a file or directory (use with caution)
download_file
Download a file from a URL to disk. Defaults to the Downloads folder if no path is given.
draft_social_post
Draft a social-media post for the user's BRAND/BUSINESS account and add it to their approval queue. Use when they ask you to write/schedule a post, run their socials, or plan content. It does NOT publish — everything waits for the user's one-click approval in Settings → Business (nothing goes out autonomously). Only for real, disclosed brand accounts via official channels — NEVER fake personas, bought engagement, or manipulation.
edit_file
Make a PRECISE, surgical edit to an existing file by replacing an exact snippet. STRONGLY PREFER this over write_file when changing a file that already exists — it edits in place instead of rewriting the whole file, which is faster and avoids losing or breaking other code. Read the file first, then pass old_string copied EXACTLY (including indentation/whitespace). old_string must be unique in the file unless replace_all is true.
export_session
Export a conversation transcript to a file in the user's Downloads folder — clean Markdown or a self-contained styled HTML page. Live credentials are always scrubbed; redact additionally strips injection-shaped lines. Defaults to the CURRENT conversation.
forget
Remove saved memories matching the given text (stale or wrong facts).
generate_image
CREATE a brand-new image from a text description — the tool for ANY 'make/generate/create/draw/design an image|picture|logo|icon|poster|wallpaper|art|illustration|mockup|concept|thumbnail', 'make me a picture of…', 'draw…', 'render…', 'give me an image of…', or 'design a logo for…'. Runs a real image model (Gemini 2.5 Flash Image by default) on the user's OpenRouter key. The result is SHOWN inline and saved to the Desktop, and it becomes 'the image you just made' so you can immediately email/Discord it. Do NOT describe a picture in words when the user wants an actual image — call this. Write a VIVID, specific prompt (subject, style, composition, lighting, colors, mood); expand a terse ask like 'a cat logo' into a rich prompt yourself. Only claim it worked when the tool confirms it saved.
get_file_info
Get a file or folder's size, type, and modified/created times, without reading its contents.
list_business_drafts
List the social posts currently in the approval queue (pending or approved). Use to review what you have drafted for the user before they approve.
list_changes
List every file Mori has changed recently, newest first — the answer to "what did you just change?". Use this BEFORE undo_changes so you can tell the user exactly what would be restored. Unlike list_checkpoints this needs no path: it reads the change journal across all files. Marks anything whose snapshot has rotated away as NOT restorable, so you never promise an undo that cannot happen.
list_checkpoints
List the saved checkpoints (auto-backups) for a file, newest first — so you know what rollback_file would restore.
list_dev_servers
List the dev servers you currently have running (pid, command, uptime).
list_files
List files and folders in a directory
list_goals
List all durable goals with status, progress, blockers and next actions.
list_memories
List everything you currently remember about the user/project.
list_schedules
List the tasks you have scheduled to run on their own — each row carries the job id, next run, last run, and enabled state. Cron jobs live separately: schedule_cron with action "list".
list_tasks
List Mori's task board (optionally one lane) with ids, lanes, priorities, blockers.
memory_view
Open ONE of your memory files in full (frontmatter + body). Your memory index lists every memory by name — call this when an index line or a "↳ linked" pointer looks relevant but its body was not injected.
memory_write
Your persistent memory (one fact per memory file). add a NEW fact — one fact per memory, description = ONE findable line (it becomes the recall key); update or delete an existing memory by name. Never save what the repo or filesystem already records. When a fact changes, UPDATE its file — never add a twin; when the user corrects you, delete or fix the stale file.
move_file
Move or rename a file
ocr_image
Read the TEXT inside an image (png/jpg/screenshot) using the OS's built-in OCR — for screenshots, photos of documents, scanned pages, error dialogs. Give it a file path; get the recognized text back.
query_csv
Run a real SQL SELECT over a CSV file — filter, aggregate, group, sort actual data instead of eyeballing it. The table is '?', e.g. "SELECT city, COUNT(*) AS n FROM ? GROUP BY city ORDER BY n DESC LIMIT 10". Numeric columns are auto-typed so SUM/AVG work. Use for any data question about a .csv.
read_any
Open ANY file and understand it — the smart, universal reader. Hand it a path and it auto-detects the type and does the right thing: code in any language (reads the text), images (SEES them with vision), PDFs and Word/PowerPoint/Excel (extracts the text), CSVs (previews + points you at query_csv), zips/archives (lists what's inside), audio/video (metadata), a folder (lists it), or raw binary (identifies it). This is your DEFAULT when the user gives you a file or you don't know the type. For a specific known type you can still use read_file / read_pdf / read_image / query_csv directly.
read_file
Read the contents of a file. Large files are returned in line-numbered chunks — pass offset to continue where the previous read stopped.
read_image
LOOK at an image file with your own eyes — the actual picture is attached to the conversation so you can see layouts, photos, charts, UI, colors, anything visual. Use for 'what's in this image', design reviews, checking a screenshot you took (take_screenshot returns a path — read_image it to verify your own work). For pulling text out of an image, ocr_image is cheaper.
read_pdf
Extract the TEXT from a PDF file so you can read, summarize, or answer questions about it. Use for any .pdf the user mentions — reports, papers, invoices, contracts. If the PDF is scanned images (no text layer), it says so — use ocr_image on a page screenshot instead.
remember
Save a durable fact or preference about the user/project to long-term memory so you recall it in FUTURE sessions (their name, stack, preferences, key project details). Use for lasting facts — not transient task steps.
resolve_entity
Resolve a vague reference ('the guy from the demo', 'that site', 'my resume') to the real entity — a path, email address, URL, or build — BEFORE acting on it. If no confident match comes back, ask the user ONE short question instead of guessing.
rollback_file
Undo Mori's last change to a file — restores it to the state right before the most recent write/edit/delete. Mori auto-checkpoints every file before changing it, so this is a real undo. The current state is itself checkpointed first (so a rollback can be undone).
save_playbook
Record HOW you solved a non-trivial, multi-step task — a reusable recipe. Different from remember (which is for facts): this saves the working APPROACH so you handle similar requests faster and more consistently next time. Call it after you finish something involved (a build, a multi-step automation, a tricky workflow).
schedule_cron
Schedule an unattended run with REAL cron precision — a 5-field cron expression ('30 8 * * 1-5' = weekdays 8:30am), 'at:<epoch-ms>' one-shot, or 'every:<minutes>'. This is THE tool for one-shots and cron expressions — 'in 2 minutes' or 'at 3pm today' means compute the epoch-ms and pass schedule 'at:<epoch-ms>' (e.g. at:1753048800000); schedule_task is only for recurring daily-at-a-clock-time jobs. The main-process clock survives window close; missed runs fire once on wake, never replayed per slot. Call with action 'list' to see every cron job with its id, schedule, lastRun, nextRun, and enabled state. Same unattended safety rules as schedule_task (no sends/purchases/irreversible actions).
schedule_task
Schedule a RECURRING task that you'll run on your own and report back — recurring daily-at-a-clock-time only, e.g. 'every morning at 8am brief me on my calendar', 'every Monday summarize my unread email'. For one-shots ('in 2 minutes', 'at 3pm today') or cron expressions ('30 8 * * 1-5'), use schedule_cron instead. These run UNATTENDED, so use them for prep/reporting (briefs, summaries, drafts, reminders) — they will NOT send messages, make purchases, or do irreversible actions without you present. Give a clear prompt of what to do each run. The result returns the job id + next-fire time — quote the id back to the user (list_schedules and cancel_schedule use it).
search_files
Search a directory tree for a string or regex and return matching file:line results. Use this to find where code lives before editing it.
search_history
Search ALL of your past conversations with this user for something discussed before — a decision, a fact, a project detail, 'what did we say about X last week'. Returns matching snippets with the chat title + date. Use this to recall context beyond your live memory. Zero cost to your context window.
search_sessions
Search PAST conversations with this user ('what did we do last week', 'that site we built') — full-transcript recall over the raw session text (falls back to summaries), so even a passing mention weeks ago is findable. Complements memory: memory = facts, sessions = what happened when.
skill_manage
Create, update, or delete one of your skills — durable how-to procedures you follow in future sessions. AUTHOR A SKILL when you complete something non-trivial that took 5+ tool calls, recover from a dead end, or the user corrects your approach: capture the WINNING procedure, not the story. Writes may go to a pending queue for the user's approval.
skill_view
Open one of your skills (how-to procedures) in full. Your turn context lists the skills you have — call this when a listed skill looks relevant but its body wasn't injected.
skills_hub_browse
Browse the Skills Hub catalog — ready-made procedures you can install for yourself (Apple reminders and calendar, GitHub PR flow, email discipline, OCR and documents, video summaries, ASCII and Mermaid diagrams, CSV and SQL work, deploys and incidents). Works offline. Shows which are already installed. Use when the user asks what skills are available, or when a task keeps needing a procedure you do not have.
skills_hub_install
Install a catalog skill so it is available every future turn. Name it by slug or identifier (from skills_hub_search). Refuses to overwrite a skill the user wrote by hand unless force is set. Ask the user first — this adds a permanent procedure to their setup.
skills_hub_publish
Validate one of the user's own skills against the SKILL.md contract and produce the shareable file text, ready to paste into a repo or send to someone. No network involved. Refuses anything missing a name, description or procedure.
skills_hub_search
Search the Skills Hub catalog by what a skill DOES, not just its title — the procedure text is searched too, so 'rollback', 'transcript' or 'null rate' find the right skill. Use before installing, and whenever you suspect a ready-made procedure exists for the task in front of you.
skills_hub_uninstall
Remove a skill that was installed from the Skills Hub. Only hub installs can be removed this way — built-in seeds and skills the user wrote by hand are refused, deliberately.
undo_changes
Undo EVERY file change Mori made in the last N minutes, restoring each file to the state it had before Mori's first change in that window. This is the "undo all of that" the user means after a bad edit — rollback_file only handles one path at a time and needs you to already know it. ALWAYS run list_changes first and tell the user what will be restored; this rewrites their real files. Reports restored and failed files separately — never describe a partial undo as a clean one.
unzip_file
Extract a .zip archive to a folder.
update_file
Update an existing file with new content
update_goal
Update a goal after meaningful work: progress %, status (active|paused|complete|blocked|failed), blocker, next action, or completion evidence. Always record evidence when marking complete.
update_task
Move/update a board task: change lane, record the latest action, set a blocker or result. Use lane=completed with a result when done; lane=waiting_user when you need the user.
video_analyze
WATCH a video and answer a question about it. Give a local file path or a public video URL and what you want to know: frames are sampled across the whole clip and looked at with vision, then the findings are combined into one answer. Use for 'what happens in this clip', reviewing a screen recording, checking a render you made, reading on-screen text. Frames only - there is no audio in the analysis. Requires ffmpeg on the machine; it says so plainly if it is missing.
video_generate
Generate a video from a text prompt, or animate a still image into one (pass image_url). Submits the job to the configured video backend and waits for it to finish, then returns the video URL. Needs a video provider and key set in Settings; without one it says so instead of pretending. Provider delivery URLs expire, so save anything worth keeping.
write_file
Write content to a file (creates or overwrites)
03 Web & browser40 tools
Search, extract, operate sites, shop to the approval gate.
browser_compose
Open a compose/create view on a website in the default browser. Supports: X/Twitter (new tweet), Gmail (new email). After opening, use focus_default_browser + type_text to type content.
browser_search_site
Search a specific website by opening the search results URL directly in the default browser. Supports: Amazon, GitHub, Google, YouTube, Reddit, X/Twitter, Wikipedia, npm, LinkedIn, and more. Uses direct search URLs — no UI interaction needed.
chrome_act
Perform a REAL input inside the user's logged-in Chrome via the extension — a genuine mouse click, keystroke/typing, form fill, dropdown select (by visible option text OR value), key press, hover (opens JS menus/tooltips), or scroll — on an element by its [index] from the last chrome_read_page. action = click | type | select | press | hover | scroll. Checkboxes/radios toggle via click. Returns the action outcome + a fresh page read. Only works on sites the user approved once in the side panel. NEVER type credentials and NEVER click a final Pay / Place order / Buy now / Confirm purchase button — fill everything and STOP at the pay step for the user (this is enforced).
chrome_navigate
Navigate the ACTIVE tab of the user's real Chrome via the extension: a full http(s) URL, or 'back' / 'forward' through history. Navigation alone needs no site approval — reading the destination does, so follow with chrome_read_page.
chrome_read_page
Read the ACTUAL page in the user's real Chrome (their logins, their sessions) via the Mori Chrome extension: full structured extraction — title, headings, every interactive element (indexed), links, page text. Pass url to navigate first, omit to read what's open. Use when the page context or a login matters; plain lookups should use web_search/web_extract instead. TELL the user before using Chrome. The first Chrome action each turn asks the user for an OK.
chrome_screenshot
Screenshot the visible tab of the user's real Chrome via the extension (downscaled). Use to SEE a page when the structured read isn't enough (canvas apps, visual checks).
chrome_tabs
Manage the user's real Chrome tabs via the Mori Chrome extension: list every open tab (with tabIds), open a new tab at a URL, switch to a tab, or close one. Use list first to see what's open, then switch to bring the tab you need forward — chrome_read_page/chrome_act always work on the ACTIVE tab. Close works on ANY tab the user names, including ones they opened themselves; on your own initiative only close tabs you opened. action = list | open | switch | close.
deep_research
Do THOROUGH, autonomous research on a question — Mori breaks it into angles, sends parallel researcher sub-agents to search the live web and READ the best sources, then synthesizes a clear answer WITH a Sources list. Use for anything that needs real, cited findings across multiple sources (market/competitor research, 'find the best X and why', deep how-does-Y-work). For a single quick fact use web_search instead.
focus_default_browser
Focus/bring to foreground the user's real default browser window (Chrome, Edge, Firefox, Brave). Use after opening a URL to interact with the browser.
github_code
Search real code across GitHub and return the MATCHING LINES — answers "how do people actually call this API", which no README does. Scope with repo/language/path. Note: GitHub requires a token for code search; without one, use github_read on a specific repo instead.
github_issues
Search or READ GitHub issues and pull requests — where the reasoning lives. A maintainer explaining in a CLOSED issue why the obvious fix breaks something is worth more than the file it is about. Search with query (+repo to scope); then read one in full with repo + number to get its whole comment thread. Closed issues are included by default on purpose.
github_read
Read a GitHub repo directly: without "path" returns metadata + README + the full file tree; with "path" returns that file's contents (via the CDN — effectively unlimited). The real way to study how a library works.
github_releases
Read a repo's releases and release notes — what ACTUALLY changed between versions, which a version number cannot tell you. Omit tag for the latest few; pass tag for one version in full. Projects without GitHub Releases are pointed at their CHANGELOG instead.
github_search
Search GitHub repositories by keywords (sorted by stars). REAL research: find libraries, reference implementations, prior art. Follow up with github_read to read the winning repo.
hn_search
Search Hacker News discussions — prior art, library sentiment, "has anyone hit this" discourse. Returns stories with points/comments; web_extract a link to read further.
http_request
Call a URL or API directly and get the raw response back — JSON APIs, RSS/XML feeds, raw file contents, webhooks, status endpoints. Use this (not web_search) when you have an exact URL or API endpoint and want its actual payload. Supports method, headers, and body. 15s timeout, response capped at 200KB, local/private addresses blocked.
open_browser
Open a specific or default browser
open_site_by_name
Open a well-known website by friendly name. Supports: Google, YouTube, GitHub, Reddit, Twitter/X, Discord, Amazon, Netflix, Twitch, LinkedIn, Facebook, Instagram, TikTok, Wikipedia, Gmail, Notion, Figma, Spotify, WhatsApp, Telegram, Slack, StackOverflow, npm, ChatGPT, Claude, Hacker News, Vercel, Codepen, Replit, and more. For unknown sites, opens https://www.{name}.com.
open_url
Open a URL in the default browser
operator_add_to_cart
Add a product to the cart in the operator browser. PREFER passing query = the product's name/title (it matches the right item even if numbering shifted); index is a fallback. Opens the product and clicks Add to Cart. After this you MUST STOP — never proceed to checkout or payment; the user completes the purchase themselves.
operator_click
Click an element in the built-in browser by its [index] from the last page read (operator_goto / operator_read_results). Returns the fresh page state after the click. Works with no extension and no browser key. Refuses the final pay / place-order control — the user makes that tap themselves.
operator_close
Close the operator browser when finished.
operator_fill
Fill a WHOLE FORM in the built-in browser in one call, then read every field back and report which ones verified. This is the tool for "fill in this form" / applications / checkout details. Give one line per field: "index = value".
operator_goto
Navigate the built-in browser to a URL and read the page back — page text PLUS a numbered list of every interactive element ([index] tag label). Those indices are what operator_click / operator_type / operator_fill / operator_select act on. Needs no extension and no browser of the user's own.
operator_press
Press a key in the built-in browser — Enter, Escape, Tab, ArrowDown, PageDown. It goes to whatever holds focus, so click or type into the element you mean first. (Enter and Space activate the focused control, so they are refused on a pay button exactly like a click.)
operator_read_results
Re-read the page the built-in browser is on: any product listings, the page text, and a numbered list of every interactive element ([index] tag label) for operator_click / operator_type / operator_fill / operator_select to act on. Use it after the page loads more, after navigating, or whenever an index looks stale.
operator_screenshot
Capture what the operator browser currently shows (for you to inspect the page).
operator_search
Open a real controllable browser and search a shopping site, then return the top listings (title, price, rating). Use this for "find the best X", "compare prices", "shop for Y". Supported sites: amazon, ebay, walmart, bestbuy, target, etsy, google. After this, COMPARE the results and present the best options to the user.
operator_select
Choose an option in a dropdown (<select>) in the built-in browser, by the element [index] from the last page read. Pass the option value exactly as the page lists it. Reads the dropdown back afterwards to confirm the choice stuck.
operator_status
Get the operator browser current URL and page title.
operator_type
Type text into ONE field in the built-in browser, by its [index] from the last page read, then read the field back and report whether the text actually landed. Set submit=true to press Enter afterwards (searches, login forms). For several fields at once use operator_fill.
package_lookup
Look up packages on npm / PyPI / crates.io: version, description, weekly downloads, deps, install command. Exact name gives full metadata; keywords search (npm/crates).
search_google
Search Google for a query and open results in browser
send_bulk_email
Send the SAME email to a LIST of recipients (up to 25 per run) through whichever transport this computer uses (macOS and Windows: the user's signed-in Gmail in Chrome, needing no setup; a configured SMTP account only as a fallback, and on Linux) — sequential, throttled, with a per-recipient sent/failed ledger returned at the end. MANDATORY FLOW: (1) draft it, (2) show the user the FULL recipient list + subject + body and ask for approval, (3) ONLY after they explicitly say yes, call this tool. It will refuse if the user's latest message isn't an approval. Never call it unattended or on a schedule.
send_email
Send a real email — the reliable ONE-STEP way to email someone, INCLUDING with a file ATTACHMENT (PDF, image, doc). Use this whenever asked to email/send something to an address. The transport differs by platform and you do NOT need to care which: BOTH macOS and Windows send through the Gmail the user is already signed into in Chrome — no setup, no app password, nothing to configure. (A configured SMTP account is used only as a fallback when no browser session is available.) NEVER tell the user to set up SMTP or an app password in order to send an email; if a send fails for want of a session, the fix is to open Chrome and sign into Gmail. ATTACHMENTS: whenever the user references a file to send, pass that reference as attachmentPath — you do NOT need a full path. It accepts a full path, JUST a filename ('Nighttime_Routine.pdf' or even 'the nighttime routine pdf'), or a phrase like 'the pdf you just made' / 'the file you just created'. Mori resolves it by searching Desktop/Downloads/Documents and by remembering the last file it created this session — so right after you build a PDF you can send it without restating the path. Returns JSON {ok, status, message}: status 'sent' = really sent (say so confidently); 'not_signed_in' = Mori could not send it itself — OUTPUT THE `message` FIELD WORD FOR WORD, do not summarise or reword it (a paraphrase turned this into a confusing 'email isn't connected, log in' once, which is exactly wrong), because it names the exact next step for this platform. 'not_signed_in' specifically means there is no Gmail session in Chrome — the fix is ALWAYS to open Chrome and sign into Gmail, never an app password; 'no_chrome' = Chrome could not be reached at all, same fix; 'attach_failed' = the file couldn't be found or the attachment couldn't be confirmed — report exactly what it says, do NOT claim it sent; 'unknown' = the send could NOT be confirmed, which means it did NOT happen — tell the user plainly that it was not sent and offer to retry. NEVER say 'sent', 'done', 'email's out' or anything equivalent unless status is exactly 'sent'. If ok is false, nothing was sent, no matter what the rest of the message says.
stack_answers
Search StackOverflow and return the top-voted FULL answer for a technical question or error message — ground truth for debugging, not search snippets.
upload_to_drive
Upload a file to the user's signed-in Google Drive (My Drive) through the browser. Use this when asked to upload/put/save/back-up a file to Google Drive. Pass the file as a full path, a bare filename, or 'the zip/file you just made' — Mori resolves it. Returns JSON {ok, status, message}: 'sent' = upload confirmed; 'not_signed_in' = tell the user to sign into Drive in Chrome; 'attach_failed' = file not found / couldn't drive the uploader. Only claim it uploaded when status is 'sent'. Common flow: build a site → create_zip → upload_to_drive the zip.
use_mori_chrome
Run a whole web task in the user's REAL, logged-in Chrome via the Mori Chrome extension — real clicks, keystrokes and form fills in their actual sessions (Gmail, GitHub, dashboards, retailer accounts). STRONGLY PREFER this whenever a task genuinely needs a real browser: authenticated pages, anything 'on my account/dashboard/inbox', checkout/purchase flows (it fills the cart and STOPS before final pay — never pays), data behind a JS or login wall, and sites that block headless browsers (LinkedIn, Instagram, X, etc.). For plain public lookups use web_search/web_extract instead. Pass the full task as 'task'. GRACEFUL: if the extension isn't connected it does NOT fail — it returns a short recommendation to relay ('connect Mori Chrome, or I can use the built-in browser'); it also tries to wake Chrome automatically when it's simply closed.
web_extract
Fetch web pages and return their clean readable TEXT (article body, stripped of scripts/markup). Use when you have URLs and want to READ them — deeper than a web_search snippet. Pass up to 5 URLs in 'urls' to read them ALL IN PARALLEL (one call, one wait) — do that whenever research has several promising sources. Long pages are NOT lost: the full text is saved to a cache file and the result ends with the exact read_file call (path + offset) that pages through the rest, so never treat a truncated extract as the whole document. Raise char_limit if you want more inline. For raw JSON/APIs use http_request instead.
web_search
Search the web and READ the results back as text — the way to ANSWER questions with current/live info you don't reliably know: crypto/stock prices, 'today/now/latest/current' values, exchange rates, weather, sports scores, breaking news, or any fact you're unsure of. It returns the page's answer box + snippets so you can read the REAL number/fact and report it. ALWAYS use this for live or uncertain data instead of answering from memory (a remembered price/stat is a fabrication). Unlike search_google (which only opens a tab), this gives you the text to read.
04 Terminal18 tools
The login shell. Builds, installs, scripts, processes.
cli_end
End an interactive CLI session and kill the program. Do this when finished — sessions hold a real process open.
cli_list
List the interactive CLI sessions currently open, with what each is running and whether it is still alive.
cli_read
Read new output from an interactive CLI session without sending anything — use it to keep waiting on a program that is still working (after a cli_send returned state "timeout"), or to catch up on one running in the background. Returns only what arrived since the last read unless all=true.
cli_send
Type something into a running interactive CLI session and get back what it says. This is a CONVERSATION: send one message, read the reply, decide what to send next — exactly as you would use the program yourself. Returns JSON {ok, state, output}: 'idle' = it answered and is waiting again; 'exited' = the program ended; 'timeout' = still busy, call cli_read to keep waiting. Send control keys as literal escapes in text when needed (e.g. \u0003 for Ctrl-C). Do NOT invent what the program said — only report what comes back in output.
cli_start
Start an INTERACTIVE command-line program and talk to it, the way a person would in a terminal. Use this — NOT terminal_run — for anything that prints a prompt and waits: another AI coding agent (claude, gemini, codex, aider), a REPL (python3 -i, node, irb), a database shell (psql, sqlite3, mysql), ssh, or any wizard that asks questions. terminal_run pipes its input, so those programs see no terminal and either refuse to start or silently drop into a broken non-interactive mode; this runs them under a REAL pseudo-terminal, so isatty() is true and they behave exactly as they do for a human. Returns JSON {ok, session, state, output}: state 'idle' means the program has finished printing and is WAITING FOR YOU — reply with cli_send; 'exited' means it ended (read output for why). The session persists across turns, so variables, logins and context survive between calls. macOS/Linux only for now — it refuses honestly elsewhere.
install_npm_dependencies
Run npm install in a project directory
kill_process
Terminate a process by PID. Use to stop a runaway or stuck process (get the PID from list_processes).
list_processes
List running processes (pid, CPU, memory). Optionally filter by name.
run_terminal_command
Execute a shell command and return the output. Use for npm, git, build tools, tests. Default timeout 300s (max 600 via timeout_seconds). For servers/watchers that never exit, use start_dev_server instead — never run them here.
runtime_setup
Install a runtime the task needs (node, npm, python, git, ollama) through the machine's own package manager — Homebrew on macOS, winget on Windows. Asks the user first unless Full Auto. If no package manager exists it returns the official download URL instead of piping scripts into a shell. For ollama, pass 'model' to pull a local model (e.g. 'llama3.2') — needed before local inference works. After installing, verify with runtime_status.
runtime_status
Check which runtimes this machine has — node, npm, python, git, ollama (plus Homebrew/winget). Call this BEFORE assuming a runtime exists, and whenever a command fails with 'command not found'. A missing runtime is NEVER a reason to fail the task: report it and use runtime_setup.
start_dev_server
Start a project's dev server (e.g. vite/next/expo) and leave it RUNNING in the background. Returns the pid and the local URL (e.g. http://localhost:5173) once it prints one. Use open_preview or http_request against that URL to check it. Stop it later with stop_dev_server.
stop_dev_server
Stop a running dev server by pid, or by a fragment of its command/folder. Omit to stop all.
terminal_close
Close a named terminal session and reap its shell (and, for docker/ssh, the container/connection). Always close sessions you no longer need.
terminal_list
List all open terminal sessions as JSON: name, backend, current working directory, whether a command is running (busy), and when it was created.
terminal_open
Open a NAMED, persistent shell session that survives across turns (cd, env vars, and running processes all persist). Reuse the same name to keep working in it. Backend 'local' = the user's own shell; 'docker' = a hardened throwaway container (needs Docker); 'ssh' = a remote host (needs key auth). The user's MoriTerminal UI shares these exact sessions with you.
terminal_read
Read the most recent output lines from a named session without running anything — useful to check on a long-running command or catch up on a session the user has been typing into.
terminal_run
Run a command in a named session (opened via terminal_open) and wait for it to finish. Returns the exit code and bounded output (head+tail; the middle of very long output is elided). State persists between calls in the same session. For servers that never exit, prefer start_dev_server.
05 Apps & system19 tools
Open, focus, and drive desktop applications.
close_app
Quit a whole running APPLICATION by its app/process name (e.g. "Preview", "Slack"). Never use this to close a web page or browser tab — that is chrome_tabs with action=close; quitting the browser would take all of the user's other tabs with it.
create_calendar_event
Add an event to the user's calendar (macOS Calendar). Give a title and an ISO start time; duration defaults to 60 minutes.
create_reminder
Add a reminder to the user's Reminders app (macOS) — for 'remind me to call mom tomorrow at 5'. Optional ISO due time; otherwise it lands undated in the default list.
focus_app
Bring a running application window to the foreground
focus_app_window
Find a running application by process name and bring its window to the foreground. Returns NOT_RUNNING if the app is not open.
get_calendar_events
Read the user's upcoming calendar events (macOS Calendar) — for 'what's on my calendar', daily briefs, scheduling around their day. Returns events in the next N days.
ha_call_service
Actually DO something in the house: turn a light on or off, set a temperature, lock a door, open a cover, run a scene or script. Calls a Home Assistant service. This is a real change in the user's home, so say what you are about to do. Domains that execute code on the Home Assistant host (shell_command, command_line, python_script, pyscript, hassio, rest_command) are refused. Verify with ha_get_state afterwards when it matters.
ha_get_state
Read one Home Assistant entity in full: its state plus every attribute (brightness, colour, temperature, battery, position, last_changed). Use after ha_list_entities when you need the detail behind a single device, or to VERIFY that a change you made actually took effect.
ha_list_entities
List the devices in the user's Home Assistant: lights, switches, sensors, locks, climate, media players, scenes, scripts. Returns entity_id + current state + friendly name. Start here when they say 'the kitchen lights' or 'is the garage open' and you don't know the exact entity_id yet. Filter by domain (light, switch, sensor, climate, lock, cover, media_player, scene, script, automation) or by area/room name.
ha_list_services
List the Home Assistant services (actions) you can call, with their parameters — light.turn_on, climate.set_temperature, cover.open_cover, media_player.volume_set, scene.turn_on and so on. Use when you know the device but not the right service or field names. Filter by domain to keep it short.
is_app_running
Check if an application is currently running. Returns RUNNING:count or NOT_RUNNING.
music_control
Control music playback: play, pause, playpause, next, previous, or now_playing (returns the current track). Works with Spotify and Apple Music — auto-picks whichever is running, or pass 'app'.
open_app
Open any desktop application by friendly name. Supports: Discord, Chrome, Edge, Firefox, Brave, VS Code, Notepad, Calculator, Paint, Explorer, PowerShell, CMD, Terminal, Spotify, VLC, Slack, Telegram, Teams, Zoom, Steam, Word, Excel, OBS, Task Manager, and more. The backend handles Windows path resolution automatically.
open_cmd
Open Command Prompt
open_new_vscode_window
Open a new VS Code window
open_powershell
Open PowerShell
open_terminal
Open Windows Terminal or Command Prompt
open_vscode
Open Visual Studio Code
system_control
Control the machine itself: set_volume (0-100, pass 'value'), mute, unmute, dark_mode_on, dark_mode_off, sleep_displays, lock_screen, wifi_on, wifi_off. Use when the user says 'turn it down', 'dark mode', 'lock my screen', etc.
06 Screen & input37 tools
See the screen, click, type. The computer-use layer.
ask_user
Ask the user a short question with concrete options, instead of guessing at a fork. Use when a wrong assumption would waste real work — "portfolio or shop?", "which of these two files?", "deploy to prod or staging?". Shows a dialog and returns their choice. Do NOT use it for anything you can find out yourself by looking, and do NOT use it to ask "what would you like?" — if there is nothing concrete to choose between, decide, state your assumption, and carry on. Needs at least 2 real options.
click_element
Click an element from the last screen_elements list, by id (preferred) or by (partial) name. Resolves to the element center and clicks it. Call screen_elements first; re-list after the screen changes.
configure_app
Change SAFE, cosmetic/UX app settings for the user by chat. You can set ONLY these: theme (say "dark", "light", or a preset name: Porcelain, Mori, Midnight, Paper, Terminal, Sakura, Slate), thinking stage (spark|flow|forge|trance), spoken replies on/off, ElevenLabs voice id, sidebar density (simple|standard|pro), chat font size (sm|md|lg), scheduled-run notification level (info|warning|alert), and the active model id for the CURRENT provider. Pass only the fields you want to change; omit the rest. Changes apply and persist immediately. This can NOT touch autonomy/permissions, provider API keys, spend caps, bot tokens/ownership, or the account. Those are refused, and you should tell the user to change them in Settings themselves.
discover_clis
Scan this machine for installed command-line tools (git, gh, docker, npm/pnpm/bun, python/uv, aws, gcloud, ffmpeg, imagemagick, psql, jq, terraform, kubectl and more) and remember the result for the rest of the session. Run once near the start of terminal-heavy work so you reach for tools that actually exist.
get_active_window
Get info about the currently active/foreground window (title, process name, PID).
hotkey
Press a keyboard hotkey/shortcut using SendKeys format (e.g. "^s" for Ctrl+S, "%{F4}" for Alt+F4, "{ENTER}", "^a" for Ctrl+A).
inspect_screen
FALLBACK ONLY — Capture and inspect the current screen state. Do NOT use this as a first action. Use direct tools first. Only use when you need to observe the screen after direct tools have failed.
learn_cli
Read an installed CLI's --help and save what you learned as a skill (goes to the pending queue for user approval). Use for tools you'll drive repeatedly whose flags you don't know cold. 'cli' must be a bare command name.
list_windows
List every open window: which app owns it, whether it is minimized/maximized/normal, its position and size, and its title. Use before arranging windows, or to find what the user means by "that window".
mcp_catalog
Browse Mori's curated MCP connector directory (GitHub, Sentry, Linear, Notion, Supabase, Figma, Playwright, Context7, Stripe and more). Lists name, category, what it does, auth model, and whether it is spend-guarded. Use when the user asks what Mori can connect to, or before mcp_connect. Optional 'category': dev, data, productivity, design, web, memory, reasoning, research, payments.
mcp_connect
Stage a connector from the MCP directory into the user's config, DISABLED, with placeholder credentials. Tell the user exactly what to do next (fill keys in mcp.json or complete the provider's own sign-in, then enable in Settings). NEVER ask the user to paste keys into chat. 'connector' is a name or id from mcp_catalog.
mouse_click
Move mouse to (x, y) and perform a left click. Use for clicking buttons, links, input fields, etc.
mouse_double_click
Move mouse to (x, y) and perform a double left click.
mouse_drag
Drag the mouse from one screen point to another (press, move, release) — for drag-and-drop, sliders, moving items between panes, drawing. Coordinates are absolute screen pixels.
mouse_move
Move the mouse cursor to screen coordinates (x, y).
mouse_right_click
Move mouse to (x, y) and perform a right click (context menu).
move_window
Move and resize an app's main window. Origin is the top-left of the primary display. Use for tiling or "put the browser on the left half".
press_keys
Press keyboard key combinations (e.g. {ENTER}, ^c for Ctrl+C)
read_clipboard
Read the current text on the system clipboard — whatever the user last copied. Use when they say 'the thing I copied', 'paste it here', 'what's on my clipboard', or hand you content by copying it.
run_self_test
Run Mori's built-in DIAGNOSTICS — actually exercises the terminal, file access, keyboard, mouse, app-detection, active-window, and screen-capture subsystems on THIS machine and reports which pass/fail. Use when the user asks you to 'test yourself', 'run diagnostics', 'check what works', 'are your tools working', or when troubleshooting why actions keep failing (especially on Windows).
run_subtask
Delegate an INDEPENDENT chunk of a big job to an isolated SUBAGENT with its own fresh context — use for parallelizable or self-contained pieces (research one of several topics, build one module of a larger app, draft one document of a set) so your own context stays focused. The subagent has your full tools, works autonomously without asking questions, and returns a compact result (with file paths for anything it created). Call up to THREE run_subtask calls in a single response to run them IN PARALLEL. Pass everything it needs in 'goal' + 'context' — it cannot see this conversation. It cannot spawn further subtasks or edit memory. Optionally give it a specialist 'role': researcher (gathers facts, read-only), coder (implements and runs code), critic (reviews and finds problems, read-only), designer (shapes look/feel/UX).
run_swarm
SWARM MODE ONLY — fan a fleet of INDEPENDENT subtasks out to parallel isolated subagents (up to 8 at once) and get one merged report. Use when a job decomposes into many self-contained pieces: one task per module, per page, per topic. Pass 'tasks' as a JSON array of strings (or one per line), each a complete self-contained instruction — workers cannot see this conversation or each other. Shared 'context' (paths, constraints, style) is given to every worker. Results return in task order with a success tally. Not available outside Swarm.
run_workflow
Run a defined multi-step WORKFLOW end to end. Each step is drawn live in the chat as it happens, steps that can run at the same time do, and a step that cannot run is reported as skipped with the reason rather than silently dropped. Use this when the user names a workflow, or when a job clearly matches one. Available: deep-research, build-and-verify, review-pass, study-repo-and-build.
screen_elements
PREFERRED way to drive apps: list the interactive elements (buttons, fields, links, menus…) of the frontmost window as a numbered list, read from the OS accessibility tree. Works with ANY model — no screenshot or vision needed. Then act with click_element. Re-run after every navigation: ids go stale when the screen changes.
scroll
Scroll the mouse wheel. Positive = scroll down, negative = scroll up. Amount is in "clicks" (1-10 typical).
send_discord_file
DELIVER a FILE (zip, pdf, doc, image, spreadsheet, anything) to the owner over Discord — the reliable way to actually hand over something you built or found when the conversation is on Discord. Defaults to the CURRENT Discord chat, so you usually just pass the file. The file ref resolves like email attachments: a full path, a bare filename ('site.zip'), or a phrase like 'the zip you just made' / 'the file you just created'. Optionally add a short caption. Prefer this over email when the owner is on Discord, and use it instead of only saying a file is 'saved on disk'. Returns a confirmation; only claim it was sent when it confirms.
send_discord_message
Send a Discord message to a person or channel (works while the Discord bot is running). Use when the owner asks you to message / DM / tell / reply-to someone on Discord. Resolve the recipient by @mention, username, user ID, or channel ID.
send_keys_to_app
Focus a running application and send keyboard keys to it. Use SendKeys format (e.g. "^k" for Ctrl+K, "{ENTER}", "^a").
set_role
List or activate a role preset (UI/UX Designer, App Builder, Full-Stack Coder, Researcher, Marketer, Everyday Assistant). A preset bundles a default gear, an output register, and the connectors worth setting up. Call with no 'role' to list; with 'role' to activate (or 'off' to clear). Suggest the preset's default gear and offer mcp_connect for its connectors — never stage them unasked.
set_window_state
Minimize, maximize or restore an app's main window. Use for "minimize Chrome", "maximize the editor", "bring back Notepad".
show_notification
Show a native desktop notification
take_screenshot
FALLBACK ONLY — Capture a screenshot of the current screen. Do NOT use this as a first action. Use direct tools (open_app, open_url, create_file, etc.) first. Only use screenshots when direct tools have failed and you need to see the screen state.
type_into_app
Focus a running application and type/paste text into it. Better than type_text for long text or special characters because it uses clipboard paste.
type_text
Type text using keyboard simulation
update_plan
Show the user your plan for a multi-step task, and keep it current as you work. Call this ONCE early with the whole plan (3-8 short steps), then again to move the marker: mark a step "done" and the next one "active" as you go. The plan is shown in the app and survives across turns, so the user can always see where you are in a long job. Use it for anything with several stages (building something, research, a multi-site task). Do not use it for a single-step request — a one-item plan is noise.
wait
Wait/pause for a specified number of milliseconds before the next action.
write_clipboard
Put text ON the system clipboard so the user can paste it anywhere with Cmd/Ctrl+V — great for handing them a link, a snippet, a password-free config, or anything they'll paste into another app. Verified after writing.
07 Other3 tools
Memory, messaging, scheduling, and everything else.
tool_call
Run a catalog tool that is not in your visible schema (found via tool_search / tool_describe). Same permissions and approval gates as calling it directly.
tool_describe
Get the full parameter schema of one tool from the catalog (found via tool_search) before calling it with tool_call.
tool_search
Your tool schema shows only the core tools — MANY more exist (git suite, calendar, PDFs/OCR/CSV, music/system control, browser operator, zip, drive, workspaces, MCP servers…). Search the full catalog by capability, e.g. "calendar event", "ocr image", "zip folder". Returns matching tool names + descriptions. Then call tool_describe for the schema and tool_call to run it.