Presets
Saved command bundles, available across every verb.
Use presets to save provider, model, and verb-specific flags under a name. Presets exist for every verb category — AI generation (text, image, video, speech, transcription), web (search, scrape, answer, map, crawl, research, findall), and data (enrich, lookup, verify).
marmot preset create <name> --mode <mode> [flags…]
marmot preset update <name> [flags…]
marmot preset rename <old> <new>
marmot preset delete <name>
marmot preset list
marmot preset get <name>
marmot @<name> "..." # sigil — auto-routes to the right verb
marmot search @<name> "..." # explicit verb still worksFor multi-stage workflows that chain several verb invocations together, see Pipelines — they share the same @<name> sigil routing.
The @name sigil
The shorthand @<name> expands to --preset <name>. As of 0.4.7, it also routes to the verb that matches the preset's mode when no explicit verb is given. So a search-mode preset dispatches to marmot search, an enrich-mode preset to marmot enrich, and so on:
marmot preset create linkedin --mode search --provider parallel --include-domains linkedin.com
marmot @linkedin "Daniel Francis Abel Police" # → marmot searchMode → verb mapping covers all 15 modes. Three AI exceptions remap because the verb name differs from the mode name: speech → speak, transcription → transcribe, text → default-run (no verb token needed).
Explicit verbs still win — marmot scrape @some-search-preset url keeps scrape as the verb and surfaces a clean mode-mismatch error rather than silently swapping. Only the first matching @… token is consumed, so marmot run "@user said hi" keeps the literal in the prompt.
Identity: every preset has a stable preset_id
As of 0.6.0, each preset carries a stable preset_id UUID assigned at creation. Sessions and the privacy-safe usage log reference presets by preset_id rather than by slug. Renaming a preset is therefore a no-op at the data layer — sessions and historical usage records keep working without any rewrites.
The preset_id is auto-generated; users only ever interact with the slug. Display surfaces (marmot session get, marmot session list, chat-mode export) resolve preset_id → current slug at render time. Orphan ids (the preset was deleted) render as the raw UUID or (deleted).
Rename
marmot preset rename <old> <new>Validates that <new> follows the slug regex (^[a-z0-9]+([-_][a-z0-9]+)*$), is not already taken, and that <old> exists. Atomic config rewrite. Output:
{
"ok": true,
"action": "rename",
"from": "linkedin-people",
"to": "linkedin-folks",
"preset_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}Because the preset_id is stable, sessions that bound to the old slug continue to resolve correctly; the next marmot session get displays the new slug. Historical usage records keep their original preset_id and resolve to the new slug at display time.
Create
marmot preset create <name> --mode <mode> [flags…] # flag-driven
marmot preset create # interactive walkthrough
marmot preset create <name> # interactive, name pre-filledNames follow the slug regex ^[a-z0-9]+([-_][a-z0-9]+)*$ — lowercase letters and digits with single - or _ separators (no leading, trailing, or consecutive separators).
Update
marmot preset update <name> [flags…] # flag-driven (patches the supplied fields)
marmot preset update <name> # interactive walkthrough — current values shown as defaultsPatches the supplied flags onto an existing preset. A preset's mode is fixed; delete and recreate it if the mode needs to change.
Interactive walkthrough
Run marmot preset create (no args) or marmot preset create <name> (name only) to enter an interactive walk that prompts for each preset-able field. Same for marmot preset update <name> with no field flags.
The walk:
-
Name — only on
create, only if not passed positionally. Validates the slug regex on the fly; re-prompts on invalid. -
Mode — only on
create. Pick from the 15 modes; render shows the verb each mode dispatches to (text → marmot run,speech → marmot speak, …). -
Provider, model, retries, timeout — common to every mode. Skip any to use the configured default. The model picker is searchable: alphabetized, shows a scrollable window of 10 entries, and accepts typed input to filter by lowercase substring match across model id and label. Pick
Other / type a custom valueto enter a model id that isn't in the cached list. -
Mode-specific fields — the walker iterates the field list for the chosen mode in declaration order. Each field type has its own prompt:
Field type Prompt string / path / number text input. On update, the current value is pre-filled — press Enter to keep it, or edit in place to change. Oncreate, empty input = skip.bool three-way select: enable / disable / skip-or-keep enum select from the enum members list (file, image, stop, urls) on create: loop until empty input; onupdate: Keep / Append / Replace -
Mutually-exclusive groups — for fields like text mode's
schema | schemaFile | schemaModule, the walker asks which one (if any) once and only walks the chosen branch. -
Review — pretty-prints the assembled preset. Confirm to save, or cancel to discard.
The flow only triggers on a TTY. Piping marmot preset create < /dev/null or running it in a non-interactive environment errors clearly: pass --mode and field flags directly instead.
$ marmot preset create
◆ Preset name
│ ▍ tech-search
│
◆ Mode (which verb is this preset for?)
│ ● search → marmot search
│
◆ Provider
│ ▍ parallel
…
◆ Save this preset?
│ ● Yes
│
└ Saved preset "tech-search".Modes and their preset-shaped flags
Common to every mode: --provider, --retries, --timeout. AI modes also accept --model. Web and data modes do not — provider implies the API surface.
AI modes
| Mode | Verb | Mode-specific flags |
|---|---|---|
text | (default) | --prompt, --prompt-file, --system, --system-file, --schema, --schema-file, --schema-module, --file (list), --image (list), --temperature, --max-tokens, --top-p, --seed, --stop (list), --reasoning, --provider-option, --output, --stream, --text, --json, --session |
image | image | --prompt, --prompt-file, --size, --quality, --style, --negative, --seed, --n, --provider-option, --output, --binary, --b64, --json, --preview, --session |
video | video | --prompt, --prompt-file, --image (list), --aspect, --resolution, --duration, --fps, --audio / --no-audio, --n, --seed, --provider-option, --output, --binary, --b64, --json, --session |
speech | speak | --text (positional), --prompt-file, --voice, --format, --speed, --instructions, --provider-option, --output, --binary, --b64, --json, --play, --wait, --session |
transcription | transcribe | --audio (positional), --language, --format, --prompt (concat), --provider-option, --output, --text, --json, --session |
Web modes
| Mode | Verb | Mode-specific flags |
|---|---|---|
search | search | --query, --limit, --depth, --freshness, --after-date, --before-date, --include-domains, --exclude-domains, --include-content, --cache, --refresh, --output, --raw, --session |
scrape | scrape | --urls (list), --format, --query, --cache, --refresh, --output, --raw, --session |
answer | answer | --query, --max-citations, --include-search, --cache, --refresh, --output, --raw, --session |
map | map | --url, --search, --limit, --cache, --refresh, --output, --raw, --session |
crawl | crawl | --url, --max-pages, --max-depth, --instructions (concat), --include-paths, --exclude-paths, --allow-external, --wait, --async, --output, --raw, --session |
research | research | --query, --depth, --schema, --schema-file, --instructions (concat), --wait, --async, --poll-interval, --max-wait, --output, --raw, --session |
findall | findall | --objective, --limit, --schema, --schema-file, --entity-type, --match-conditions, --wait, --async, --output, --raw, --session |
Data modes
| Mode | Verb | Mode-specific flags |
|---|---|---|
enrich | enrich | --type (person / org), --email, --email-hash, --linkedin, --phone, --name, --first-name, --last-name, --middle-name, --company, --provider-id, --domain, --website, --ticker, --min-likelihood, --require, --fields, --cache, --refresh, --output, --raw, --session |
lookup | lookup | --type (person / org / email), --q, --limit, --cursor, --title, --seniority, --location, --domain, --industry, --employees, --tech, --email-type, --department, --company, --cache, --refresh, --output, --raw, --session |
verify | verify | --email, --cache, --refresh, --output, --raw, --session |
As of 0.7.0 every data-verb identifier is preset-able — the realistic use is partial baking (e.g. --company acme.com in a preset, --first-name Jane at runtime). All identifier fields are scalar-replace: a runtime flag fully replaces a preset value.
Use
marmot search --preset <name> "..."
marmot @<name> "..."Explicit flags interact with preset values via three rules — see Merge rules below for details. In short: scalars replace, lists append, prompt-like text concatenates. So this call uses the saved provider but bumps the limit:
marmot @linkedin "Daniel Francis Abel Police" --limit 50Merge rules
When both a preset and a runtime flag set the same field, the value is merged according to the field's shape:
| Shape | Behavior | Examples |
|---|---|---|
| Scalar | Runtime flag replaces preset value. | --provider, --model, --temperature, --seed, --stream (all booleans). |
| List | Preset list followed by runtime list (append). | --file, --image, --stop. |
| Prompt-like text | Joined with \n\n so preset + runtime compose. | --system, positional prompt, preset's prompt field. |
Two intentional asymmetries:
--provider-optionis list-shaped (key=valuerepeatable) but stays as scalar replace — the runtime list replaces the preset list entirely. Append would silently produce duplicate keys.- For a preset boolean set to
true, the matching--no-Xruntime flag flips it tofalse. (E.g.--no-streamoverrides a preset'sstream: true.) For positive overrides of--no-X-only flags like--no-cache, web/data verbs accept a--cachepartner.
Permanent exclusions
A preset cannot set:
--api-key— security; provider keys live in~/.marmot/config.jsonunderproviders.<slug>.apiKeyEnvVar, not in presets.--preset— recursion would let a preset apply itself.- Stdin-only modifiers (
--file-mime,--image-mime,--text-stdin) — they only have meaning when stdin is piped at runtime.
Schemas validate this with strict mode: writing one of these into a preset errors at parse.
Path resolution for preset paths
Preset fields holding filesystem paths (systemFile, promptFile, schemaFile, schemaModule, file, image, output) resolve at use time:
- Absolute paths used as-is.
~expanded to the user's home directory.- Relative paths resolved against the invocation cwd, not against the config file's directory.
So a preset stored in ~/.marmot/config.json with systemFile: "./prompts/coding.md" looks for ./prompts/coding.md from wherever you ran marmot. For portability, prefer ~/... or absolute paths in global presets.
Examples
# Search preset bound to LinkedIn results via Parallel
marmot preset create linkedin-people \
--mode search --provider parallel --include-domains linkedin.com --limit 25
marmot @linkedin-people "Daniel Francis Abel Police"
# Deep research with a fixed schema
marmot preset create research-fintech \
--mode research --provider parallel --depth deep \
--schema-file ~/schemas/research-output.json
marmot @research-fintech "competitive analysis on stripe vs adyen"
# People enrichment via PDL with a likelihood floor
marmot preset create enrich-people-pdl \
--mode enrich --provider pdl --type person --min-likelihood 8
marmot @enrich-people-pdl --email tcook@apple.com
# AI image preset
marmot preset create square-1024 \
--mode image --provider openai --size 1024x1024 --quality hd
marmot @square-1024 "a marmot in the alps"Delete
marmot preset delete <name>Returns {removed: false} if the name didn't exist (not an error).
List and show
marmot preset list # human table on TTY, JSON when piped
marmot preset list --json # always JSON envelope
marmot preset list --markdown # markdown pipe-table
marmot preset get <name> # human key/value sections on TTY, JSON when piped
marmot preset get <name> --json
marmot preset get <name> --markdownThe default output is TTY-aware: a column-aligned table when stdout is an interactive terminal, the JSON envelope (today's structure preserved) when piped or redirected. Pass --json or --markdown to force a specific format. --json and --markdown are mutually exclusive.
Config keys
Presets live under the top-level presets map in ~/.marmot/config.json:
{
"presets": {
"linkedin-people": {
"mode": "search",
"provider": "parallel",
"limit": 25,
"includeDomains": "linkedin.com"
},
"research-fintech": {
"mode": "research",
"provider": "parallel",
"depth": "deep",
"schemaFile": "~/schemas/research-output.json"
}
}
}Presets store flags only, never credentials.