Skip to content

CLI reference

loofah [--base DIR] [--vault-path DIR] [--json] <command>
OptionEnvironment variableBehavior
--base DIRLOOFAH_BASEUse DIR as the vault directory.
--vault-path DIRLOOFAH_VAULT_PATHUse an explicit vault directory.
--jsonNoneEmit a versioned JSON response or machine-readable JSON error.

--vault-path takes precedence over --base. Without either option, the CLI uses Loofah’s platform application-data directory, following the vault_path redirect in its global.json when the vault has been relocated.

meetings remains a compatibility alias for sessions. Plain-text invocations emit a deprecation warning when the alias is used; --json output remains machine-readable.

CommandOptionsResult
sessions list--query TEXT, --limit 1..200, --offset NUMBER, --tag NAME, --untaggedMeetings ordered by the application query layer. Defaults to 20 results. --tag filters to meetings carrying that tag (case-insensitive); repeatable, and all given tags must match. --untagged keeps only meetings without tags and cannot be combined with --tag. Each meeting’s JSON includes its normalized tags.
sessions search [QUERY]--speaker TEXT, --kind title|note|summary|transcript, --limit 1..50, --offset NUMBERFull-text hits across titles, notes, summaries, and transcript words, newest meetings first. Requires a query and/or --speaker; --speaker limits hits to meetings where that person spoke. --kind is repeatable and defaults to all.
sessions get IDNoneMetadata, canonical note, summaries, and action items.
sessions new--title TEXT (required), --note FILE, --created-at RFC3339, --started-at RFC3339, --ended-at RFC3339, --tag NAME, --author NAME, --skill NAMECreates a meeting note in the vault and prints its id. --note seeds the note body from FILE, or from stdin when FILE is -. --created-at backdates the meeting on the timeline and in its folder name — useful when importing historical notes; --started-at and --ended-at set the meeting’s start and end. All three take an RFC 3339 timestamp such as 2024-05-01T09:00:00Z (offsets are normalized to UTC); invalid values are rejected before anything is written. --tag is repeatable and both tags the meeting and registers new tags in the vault’s tag list. --author records who wrote the note in the meeting’s metadata; when writing on behalf of someone other than the vault owner (an agent, for example claude-code), always set it — the app marks such meetings as not written by the owner. Left unset, the note counts as the vault owner’s own. --skill additionally records the skill used to produce the note (for example meeting-summarizer); it requires --author and is omitted when no skill was involved.
sessions note ID--kind note|summary|all, --set FILE, --append FILEThe selected note documents. Defaults to note. With --set or --append (mutually exclusive, and incompatible with --kind), replaces or extends the note body from FILE or stdin (-); fails when the meeting does not exist.
sessions transcript IDNoneThe full transcript as [HH:MM:SS] Speaker: ... lines, one per speaker turn.
sessions tag add ID TAG...NoneAdds one or more tags to the meeting and registers new ones in the vault’s tag registry. Tags are normalized (trimmed, # stripped, lowercased) and stored deduplicated and sorted; adding a tag the meeting already has is a no-op. Prints the meeting’s resulting tag list.
sessions tag remove ID TAG...NoneRemoves one or more tags from the meeting. Removing an absent tag is a no-op, and removed tags stay in the vault’s tag registry. Prints the meeting’s resulting tag list.
sessions path IDNonePrints the absolute path of the meeting’s session directory.
sessions attach ID FILE--name NAMEStores FILE as a note attachment of the meeting and prints the resulting attachment id. --name overrides the stored filename (defaults to the file’s name). Notes reference attachments as ![alt](attachments/<id>) with the id URL-encoded; the printed attachment id is authoritative — it may differ from the input name when an existing attachment of the same name forces a deduplicated one.
sessions export ID--format markdown|json, --output FILE, --forceA complete meeting export, including transcripts. Defaults to Markdown on stdout. Existing files require --force, which is only valid together with --output.
Terminal window
loofah tags list

Lists every tag registered in the vault’s tags.json, one name per line (--json returns each tag’s id and name). The registry is append-only: tags stay listed after the last meeting carrying them loses the tag.

Terminal window
loofah import recording.m4a --title "Weekly sync"
loofah import recording.m4a --transcribe
loofah import recording.m4a --into MEETING_ID

Creates a meeting from an audio file and prints its id. The audio is converted to the vault’s 16 kHz MP3 format, exactly as the desktop app’s import does, so a running app picks the meeting up automatically. Accepts wav, mp3, ogg, mp4, m4a, flac, webm, and aac files; --title defaults to the audio file’s name.

--created-at, --started-at, and --ended-at take RFC 3339 timestamps (normalized to UTC, rejected before anything is written when invalid) and set the new meeting’s metadata — --created-at backdates it on the timeline and in its folder name, which is what you want when importing a historical recording. --author NAME records who created the meeting; agents importing on a user’s behalf should always set it, and --skill NAME additionally records the skill used, if any (see sessions new). Because they describe a new meeting, all of these are rejected together with --into.

With --into MEETING_ID, the audio is imported into that existing meeting instead of creating a new one — for example a note created earlier with sessions new. The meeting keeps its title (--title is rejected together with --into), and the command fails without touching anything when the meeting does not exist or already has a recording; the CLI never replaces existing audio.

With --transcribe, the imported audio is transcribed immediately (see the transcribe command below). When transcription fails after a successful import, the command still reports the meeting id — plain output prints the id, --json adds a transcript_error object to data — and exits non-zero.

Terminal window
loofah transcribe MEETING_ID

Transcribes the meeting’s audio recording on-device with the speech-to-text model configured in the desktop app and replaces the meeting’s transcript, exactly as the app’s own batch transcription does. Prints the new transcript id (--json returns the meeting id plus a transcript object). Progress is written to stderr. The app’s audio retention setting is honored: with retention set to “none”, the recording is deleted as soon as the transcript is saved, just like in the app.

The command fails with a clear message and a non-zero exit code when the meeting or its audio is missing, when no speech-to-text model is configured, when the configured provider or model is not supported by the CLI (only on-device soniqo-* models are), or when the model has not been downloaded yet — the CLI never downloads models, so open the desktop app once to download it. On-device transcription requires macOS on Apple Silicon.

Successful --json responses contain:

FieldMeaning
schema_versionCLI JSON contract version. Currently 1.
commandStable command identifier such as meetings.list.
dataCommand result.
paginationPage metadata when the command is paginated.

Pagination includes offset, limit, returned, optional total, and optional next_offset.

Terminal window
loofah --json doctor

Checks the resolved vault path and read access to its sessions without changing meeting data. It exits with status 0 when ready is true and status 1 when ready is false. Inside a vault it also restores the root AGENTS.md agent guide when the file is missing or stale.

Terminal window
loofah mcp

Starts the read-only MCP server over stdio. Do not write other output to the server’s stdout.

Terminal window
loofah --help
loofah sessions --help
loofah sessions list --help
loofah --version