Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Landing

<title>Vibe Action</title>

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta property="og:title" content="Vibe Action" />
<meta property="og:description" content="Command router for shell and LLM tasks" />

<link rel="icon" href="assets/images/favicon.png" />
Vibe
Action
v0.3.1
Command router for shell and LLM tasks
Execute shell commands and LLM prompts via simple YAML files. Define steps, connect them via tags, and batch LLM calls across your cluster.
Get Started
# Quick Start

## 1. Install Ollama (or a cloud provider)

## 2. Install Vibe Action cargo install vibe-action

## 3. AI-powered commit vibe-action project commit

## 4. Describe a screenshot vibe-action vision describe

## 5. Translate a file vibe-action text translate README.md

19actions
30+operators
5LLM providers
2IDE plugins
Execution
Turn any input into a running pipeline.
01
selection
Text, file, image or interactive prompt — from the CLI or an IDE.
→
02
shell
Shell commands run locally with live terminal output.
→
03
llm
tiny → vision tiers. Ollama locally, or cloud API. Parallel across the cluster.
→
04
output
Result prints to the terminal, copies to clipboard or fires a notification.
Why Vibe Action
CLI-first. No browser, no context switching.
01
Tag system
Steps connect via tag references. The engine builds a dependency graph and executes in topological order.
02
Operators
30+ operators chained in mods: fetch, text, ast, trim, uniq, join and more. Read, inspect, transform and write.
03
Guards
Conditional execution in pure YAML: when skips, fail bails, reg validates output. No shell scripting.
04
System tags
20+ built-in tags for environment context: user, OS, pwd, date and more.
05
Vision & Fetch
Describe screenshots, read images from URL or clipboard, load web pages and PDFs.
06
Action cache
Startup loads a validated snapshot instead of re-parsing YAML — the CLI responds instantly.
YAML Actions
Describe actions in YAML, not code.
01Write a YAML file with steps, data sources and guards.
02Graph. The engine resolves tag references into topological order.
03Run. Shell commands locally, LLM prompts on your cluster.
04Validate with reg. Replace selection, copy to clipboard, or show a dialog.
version: 0.0.2
name: extract
about: Extract matching lines from logs
api:
output: dialog
input: query_prompt
actions:

Introduction

Vibe Action is a command router that executes shell commands and LLM prompts defined in simple YAML pipelines.

Why Vibe Action

  • ⚡ One command = complex pipeline — chain shell scripts and LLM calls into a single action
  • 🔗 Tag system — connect steps via data references with an automatic dependency graph
  • 🧩 Operators — pipeline of value transformations in mods (read, inspect, transform, write)
  • 🛡️ Guards — when / fail predicates and reg output validation, all in YAML
  • 🖥️ System tags — runtime environment: OS, user, directories, time, and more
  • 📥 Unified input — query tags handle text, files, images, and interactive prompts from CLI or IDE
  • 🗂️ Action groups — load actions from external git repositories or local directories as nested vibe-action <group> <action> commands
  • 👁️ Vision support — screenshot description, person identification, image from URL or clipboard
  • 🤖 Batch LLM — parallel execution across cluster nodes with role-based routing (tiny, small, medium, large, vision)
  • ⏱️ Process guard — a new run supersedes the previous one, keeping shared state predictable
  • 🔔 Notifications — optional desktop notifications on completion
  • 🔐 Confirmations — ask before executing dangerous commands
  • 💬 Self-documenting — the built-in faq action answers questions about Vibe Action itself
  • 🔌 IDE integration — the api block drives the VS Code and IntelliJ plugins
  • 🔒 Open & flexible — open source. Local models via Ollama or cloud APIs (DeepSeek, Qwen, Kimi, Zhipu)
  • 🦀 Fast — built in Rust

Key Concepts

YAML pipelines

Describe your workflow in YAML, not code. Each file is one CLI command:

version: 0.0.2
name: extract
about: Extract matching lines from text and logs
api:
  output: dialog
  input: query_prompt
actions:
  - tag: llm_log
    run: large
    reg: '^[^\n]+$'
    val:
      - name: search
        data: query_raw
      - name: line
        data: arg_file
        mods: 'fetch|text'
        fail: 'is:empty:not'
        each: true
    action: |
      [Task]
      If the line matches the query — output the EXACT line unchanged.
      If it does not match — output only a single dash: "-"
      [Query]
      {search}

      [Line]
      {line}

Steps resolve their inputs from val candidates, execute in dependency order, and pass results forward by tag. See Pipeline YAML.

Val candidates

Every step declares where its data comes from: a tag, an argument, or a query. Candidates resolve in order — the first one whose guard passes wins. See Val Candidates.

Operators

mods chains operators left to right: fetch|text, split|filter:eq:-|uniq|join. Guards use inspect operators only. See the operator pages: Read, Inspect, Transform, Write.

How It Works

  1. You write a YAML file describing your workflow — steps, data sources, guards
  2. The engine loads pipelines from the actions directory and builds a CLI command per file
  3. Steps execute in dependency order — shell commands run locally, LLM prompts go to your cluster
  4. Outputs are validated against optional reg patterns
  5. The final result goes to the terminal, the editor, or the clipboard

Ready to try it? Head to Getting Started.

Getting Started

Prerequisites

  • Ollama (recommended), or API keys for DeepSeek, Qwen, Kimi, or Zhipu — for LLM inference
  • Rust (if building from source)

Supported Platforms

  • macOS — full support
  • Linux — full support

Install Ollama

# macOS / Linux
curl -fsSL https://ollama.com/install.sh | sh

# Pull models for different roles
ollama pull qwen2.5-coder:3b-instruct   # small
ollama pull qwen2.5-coder:7b-instruct   # medium
ollama pull qwen2.5-coder:14b-instruct  # large
ollama pull qwen2.5vl:7b                # vision

Install Vibe Action

Via Cargo (recommended):

cargo install vibe-action

Build from source:

git clone https://github.com/keygenqt/vibe-action.git
cd vibe-action
cargo build --release

First Run

On first run, Vibe Action creates the config and default actions:

$ vibe-action --help

This creates:

  • ~/.vibe-action/config.yaml — configuration
  • ~/.vibe-action/actions/ — built-in actions

Configure Cluster

Edit ~/.vibe-action/config.yaml to point to your Ollama instance:

cluster:
  - provider: ollama
    host: http://localhost:11434
    model: qwen2.5-coder:14b-instruct

Full field reference — roles, timeouts, multi-node clusters — see Configuration.

Run Your First Actions

# AI-powered commit
vibe-action commit

# Translate a file
vibe-action translate README.md

# Describe a screenshot
vibe-action describe screenshot.png

Full list of ready-to-use actions — Built-in Actions. System commands (status, clean, stop) and environment variables — CLI Reference.

Next Steps

Pipeline — YAML Format

Each action is a YAML file in ~/.vibe-action/actions/. The file name becomes the CLI subcommand. Custom files are loaded automatically alongside the built-in defaults.

Top-level fields

version: '0.0.2'
name: my-action
about: Short description for CLI help
notify: true

args:
  - name: arg_format
    short: 'f'
    input: string
    default: json
    help: 'Output format'

api:
  output: replace
  input: query_raw
  args:
    arg_format: query_raw

actions:
  - tag: tag_result
    run: small
    val:
      - name: content
        data: query_raw
    action: |
      [Task]
      Do something with {content}
FieldTypeRequiredDescription
versionstringyesPipeline schema version (must match PIPELINE_VERSION)
namestringyesAction name — becomes CLI subcommand
aboutstringyesShort description for --help
notifyboolnoDesktop notification on completion (default: false)
checkstringnoRegex to validate final pipeline result; fail if no match
argslistnoCLI argument definitions
apiobjectnoIDE plugin metadata (ignored by CLI runtime)
actionslistyesOrdered list of pipeline steps

Args

Each argument becomes a CLI flag and a val-candidate tag under its own name. Convention: prefix names with arg_ (e.g. arg_file → flag --arg_file, tag arg_file).

args:
  - name: arg_dry_run
    short: 'd'
    input: bool
    default: false
    help: 'Print message without executing'
FieldTypeRequiredDescription
namestringyesArgument name; used verbatim as tag and --<name> flag (convention: arg_ prefix)
shortcharnoShort flag (single ASCII letter)
inputstringyesstring, bool, number, path
defaultstringnoDefault value; makes the argument optional
helpstringnoHelp text for CLI usage

API block

Metadata for the IDE plugin: input source, output target, extra args. Ignored by the CLI runtime. Field reference and semantics — see IDE Plugin.

Actions

Each item is one pipeline step. Execution order is determined automatically by data dependencies (topological sort), not by list position.

actions:
  - tag: tag_result
    run: medium
    reg: '.+'
    ask: true
    when: 'is:empty:not'
    val:
      - name: content
        data: query_raw
        mods: 'fetch|text'
        when: 'is:path'
    action: |
      [Task]
      Process {content}
FieldTypeRequiredDescription
tagstringyesUnique identifier; referenced by other steps via data
runstringyesExecution engine (see below)
vallistnoVal candidates — see Val Candidates
whenstringnoAction-level guard (inspect operators); skip entire action if false
regstringnoRegex to validate step output; fails if no match
askboolnoPrompt user confirmation before execution (default: false)
actionstringyesTemplate with {name} placeholders from val candidates

Action-level when

An action-level when is evaluated before any candidates are resolved. If it fails, the entire action is skipped (dead tag). Accepts inspect operators only — the same set as candidate-level when and fail.

This is separate from candidate-level when, which controls individual candidate selection. Use the action-level guard to skip an entire step based on runtime conditions.

Run types

ValueEngine
valueLiteral passthrough — no execution, template as-is
cmdShell command via sh -c; values are shell-quoted
tinyLLM prompt — tiny model (1-3b)
smallLLM prompt — small model (3-7b)
mediumLLM prompt — medium model (7-14b)
largeLLM prompt — large model (14b+)
visionLLM prompt with extracted base64 images (vision model)

LLM sizes route to cluster nodes by role — see Configuration.

Output validation (reg)

If reg is set, the step’s output is tested against the regex. No match → hard error, pipeline aborts. Use it to enforce output format:

reg: '.+'           # must be non-empty
reg: '^[^\n]+$'     # must be a single line
reg: 'DIRTY|CLEAR'  # must be one of these words

Pipeline-level check

The top-level check field validates the final pipeline result (the output of the last action). Same behavior as reg — no match → hard error. Use it when you need to enforce the overall result format rather than individual step output.

Reserved prefixes

Action tags and argument names must not use query_* or system_* prefixes — those are reserved for providers. A bare query tag is also forbidden; use query_raw instead.

Self-referencing (data points to the action’s own tag) is a validation error.

Version management

The version field must match the engine’s PIPELINE_VERSION. For custom actions a mismatch is a validation error — bump version when the pipeline schema changes.

Built-in files are instead overwritten with the embedded default on version mismatch — see Built-in Actions.

Val Candidates

Val candidates are the data-binding mechanism in each action step. They resolve source tags into {name} placeholders that the action template expands.

Schema

val:
  - name: content
    data: query_raw
    when: 'is:path'
    mods: 'fetch|text'
  - name: content
    data: query_raw
    fail: 'is:empty:not'
    each: true
FieldTypeRequiredDescription
namestringyesPlaceholder name used as {name} in action
datastringnoSource tag or literal value
modsstringnoOperator pipe: op:arg|op:arg|... applied left to right
whenstringnoPre-mods soft guard (inspect operators); skip candidate if false
failstringnoPost-mods hard guard (inspect operators); bail if false
eachbool or objectnoFan-out config for list data (split/merge)

Resolution order

Candidates are evaluated in list order. For each unique name, the first candidate whose when passes (or has none) wins. Subsequent candidates with the same name are skipped.

If no candidate wins for a name, the name resolves to an empty string — the entire action becomes a dead tag and is skipped by the engine.

Data sources

data references a tag from one of these namespaces:

PrefixSourceExample
query_*Query provider (user input)query_raw
system_*System provider (runtime)system_language
arg_*CLI argumentarg_dry_run
tag_*Another action’s resulttag_project_path
(none)Mods-only candidate (no input)screenshot operator

When data references another action’s tag, a dependency is created. The engine resolves actions in topological order — the referenced action must complete before this one runs.

Guards

when — soft guard (skip)

Evaluated before mods are applied. If the result is falsy, the candidate is skipped (not an error). Use to avoid unnecessary work, especially for side-effect operators like screenshot:

val:
  - name: content
    data: query_raw
    when: 'is:path' # only resolve if input is a file path
    mods: 'fetch|text'
  - name: content
    data: query_raw # fallback: use raw text
    fail: 'is:empty:not' # hard error if empty

fail — hard guard (bail)

Evaluated after mods are applied. If the result is falsy, the pipeline aborts with an error. Use to enforce that a value is valid:

val:
  - name: content
    data: query_raw
    fail: 'is:empty:not' # bail if content is empty

Both when and fail accept inspect operators only — see Operators — Inspect.

Mods

Operator pipe applied left to right. Each operator receives the output of the previous one. The initial value comes from data.

mods: 'fetch|text'                    # fetch URL/file, then extract text
mods: 'resolve:dir|scan|ast|format:json'  # resolve dir, scan, parse AST, format
mods: 'split|filter:eq:-|uniq|join'  # split lines, drop "-", deduplicate, join

Operators are not inline in the action template — they live in mods. See Read, Inspect, Transform, and Write.

Operator arguments can reference other tags via {name} interpolation (e.g. mods: 'file:{tag_path}') — see Placeholders & Escapes.

each — fan-out

When each is set, the resolved value is split into items, and the action template is expanded once per item. Results are merged back into a single value.

Boolean form

each: true

Equivalent to split: '\n' / merge: '\n' — splits by newline, merges with newline.

Object form

each:
  split: '\n'
  merge: '\x1F'
FieldDescription
splitSeparator to split the value into items
mergeSeparator to join results back

Both support escape mnemonics (\n, \t, \s, \x1F).

How fan-out works

  1. Resolve the candidate value (after mods).
  2. Split the value by each.split → list of items.
  3. For each item, substitute {name} in the action template.
  4. Execute each expanded action independently.
  5. Join all results with each.merge → single string.
  6. Store under the action’s tag.

Example — process each changed file independently:

val:
  - name: file
    data: tag_changed_files
    mods: 'trim'
    each:
      split: '\n'
      merge: '\x1F'
action: |
  cd {path}
  git diff HEAD -- {file} 2>/dev/null | head -c 6000

Dead tags

If no candidate wins for any declared name, the entire action resolves to an empty string. The engine marks it as a dead tag and skips execution. Downstream actions that reference this tag receive an empty value.

This is intentional — it allows conditional actions like dry-run guards:

# This action only runs when arg_dry_run is false
val:
  - name: dry
    data: arg_dry_run
    when: 'contains:false' # skip if dry_run is true
  - name: path
    data: tag_project_path
  - name: msg
    data: tag_commit_message
action: cd {path} && git commit -m {msg}

When arg_dry_run is true, the dry candidate’s when fails → no candidate wins for dry → dead tag → action skipped.

Placeholders & Escapes

The placeholder system connects val candidates to action templates and operator arguments. Two escape mechanisms handle literal braces and YAML whitespace.

Action templates

In the action field, {name} is replaced with the resolved value of the matching val candidate:

val:
  - name: content
    data: query_raw
action: |
  [Task]
  Process {content}

Every {name} must reference a declared val candidate name. Undeclared names are a validation error.

Shell quoting

For run: cmd actions, placeholder values are automatically shell-quoted via shell_words::quote. You don’t need to add quotes manually:

# Correct — engine handles quoting
action: cd {path} && git commit -m {msg}

# Wrong — double-quoting breaks the command
action: cd "{path}" && git commit -m "{msg}"

For run: tiny/small/medium/large/vision, values are substituted as-is (no quoting).

Operator argument interpolation

Operator arguments in mods can reference tags via {name}:

mods: 'file:{tag_path}'

The engine replaces {name} with the current value of the referenced tag. The tag must already be resolved — if not, it’s an error (declare the dependency via data: in a val candidate).

Double-brace escape

When an LLM prompt needs literal braces (e.g. JSON templates, LaTeX), use double braces to escape them:

WrittenResolves toUse case
{name}value of namePlaceholder substitution
{{X}}{X}Literal braces in LLM output
{{X}}{X}Literal braces in operator args

In action templates

{{X}} → {X} in the prompt sent to the LLM. This lets you include JSON templates or other brace-based syntax without the engine treating them as placeholders:

action: |
  Output JSON: {{"name": "value", "count": 42}}

The LLM receives: "name": "value", "count": 42

In operator arguments

Same rule: {{X}} → {X}. This is how you pass literal braces through the operator pipe parser, which uses | and : as separators:

# Pass a JSON-like string through replace
mods: 'replace:{{key}}:value'
# Resolves to: replace {key} → value

Brace-escape in operator parsing

The operator pipe parser splits on | and :, but ignores separators inside braces. This means {X} and {{X}} protect their contents from being split:

# The : inside braces is NOT treated as a name/arg separator
mods: 'replace:{from:with}:to'
# name = "replace", arg = "{from:with}:to"
# After unescape: arg = "from:with:to"

Unescape rules for operator args

After splitting, each arg is unescaped in a single left-to-right pass:

InputOutputRule
{X}XUnwrap — removes braces, escapes :/|
{{X}}{X}Reduce — keeps braces, escapes :/|

Use single braces when you want the value without braces (most common). Use double braces when the operator needs a literal brace-wrapped value.

Escape mnemonics

In operator arguments and each config, these sequences are expanded after brace unescaping:

CodeExpands toPurpose
\nNewlineLine separator
\tTabTab character
\sSpaceShields from YAML trimmers

YAML trims trailing whitespace by default. \s prevents a trailing space from being eaten:

# Join with comma-space
mods: 'join:,\s'
# Result: "item1, item2, item3"
# Split on tab
mods: 'split:\t'
# each with escape mnemonics
each:
  split: '\n'
  merge: '\x1F'

ITEM_SEP (\x1F)

Internally, list items are separated by ITEM_SEP (\x1F, ASCII Unit Separator). This character never appears in normal text, so it’s safe as an internal delimiter.

  • Cross-step list data is joined with newlines for display.
  • The split operator produces ITEM_SEP-separated lists.
  • The join operator collapses ITEM_SEP-separated lists back to strings.
  • ITEM_SEP is sanitized to \n in final output.

In each config, merge: '\x1F' preserves list structure across fan-out steps — each item’s result stays separated for downstream list operators in the next action.

Quick reference

Context{name}{{X}}\n/\t/\s
Action templatePlaceholder substitutionLiteral {X} in LLMNot expanded
Operator argTag interpolation + unwrapReduce to {X}Expanded
each.split/mergeNot interpolatedNot reducedExpanded
when/failTag interpolation + unwrapReduce to {X}Expanded

Operators — Read

Read operators fetch data from the outside world into the pipeline. They are world → value: no input validation beyond existence; failure produces an Err (file not found, parse error, etc.).

Read operators are used in the mods field of a val candidate:

val:
  - name: content
    data: query_raw
    mods: 'fetch|text'

Operators

ast — parse source code to JSON

Parses a source file into a structured JSON AST via vibe-ast.

SyntaxDescription
astBrief output (auto-detect language)
ast:briefSignatures only — no function/class bodies
ast:fullFull output with bodies and imports
ast:<lang>Explicit language code (overrides auto-detection)

Supported language codes: rs, py, ts, js, java, go, cs, kt, swift, dart, sh, bat, ets, md.

In brief mode, function/class bodies, imports, tags, markers, and warnings are stripped. The path field is injected into the root JSON object.

List-aware: processes each file path independently, returns one JSON object per file. Empty result for a file (e.g. parse failure) is dropped from the output.

fetch — download URL or resolve local file

SyntaxDescription
fetchURL → temp file path; existing local file → resolved
  • URL (http:// / https://) → downloads to a temp file (deduped by URL hash, extension from MIME). Returns the temp file path.
  • Existing local file → resolves to absolute path.
  • Neither → passes the value through unchanged.

Per-item: works over list input.

resolve — resolve path to absolute

SyntaxDescription
resolveResolve any path (~, ./, ../)
resolve:dirResolve only if the path is a directory
resolve:fileResolve only if the path is a file

Returns an empty string if the path doesn’t exist or doesn’t match the filter. Per-item.

scan — scan directory for file paths

SyntaxDescription
scanScan directory tree, return list of file paths

Input must be a directory path (resolves ~, ./, ../). Returns items separated by ITEM_SEP (\x1F). Errors if the path is not a directory. List-aware across multiple directory paths.

screenshot — interactive screen capture

SyntaxDescription
screenshotOpens interactive area selection, returns path

Triggers the OS-native screenshot tool for area selection. Returns the saved image path (PNG). Ignores input value.

Platform support:

OSTools (tried in order)
macOSscreencapture -i -x
Linux (Wayland)Desktop-native first (gnome-screenshot, spectacle), then grim+slurp
Linux (X11)scrot -s, maim -s, gnome-screenshot -a, import

If the user cancels the selection (Esc), the operator returns an error. Temp screenshots older than 24 hours are cleaned up automatically.

text — extract text from files or content

SyntaxDescription
textExtract text from HTML/PDF/image file, or base64 passthrough

Processing order per item:

  1. Base64 image → passed through as-is.
  2. HTML string → converted to plain text (html2text).
  3. File path (resolved) → tried in order:
    • Image bytes → base64 encoded.
    • PDF bytes → text extracted (pdf_extract).
    • HTML content → converted to plain text.
    • Otherwise → raw file content as UTF-8.

Errors if the file doesn’t exist or the content type is unsupported. Per-item.

Chaining with other operators

Read operators typically appear at the start of a mods chain, fetching data that downstream transform/inspect/write operators then process:

# Fetch a URL, extract its text content
mods: 'fetch|text'

# Resolve a directory, scan it, parse AST, format as JSON
mods: 'resolve:dir|scan|ast|format:json'

# Read a file path, extract text, strip markdown fences
mods: 'fetch|text|strip'

See Transform and Inspect for downstream operators.

Operators — Inspect

Inspect operators are value → bool predicates. They return the string "true" or "false" per item and are used in when and fail guards on val candidates.

All inspect operators support the :not suffix to invert the result.

val:
  - name: content
    data: query_raw
    when: 'is:empty:not' # proceed only if non-empty
    fail: 'contains:ERROR' # bail if the value contains ERROR

Operators

contains — substring test

SyntaxDescription
contains:<X>True if value contains X
when: 'contains:TODO'
when: 'contains:error:not'    # true if value does NOT contain "error"

equals — exact equality

SyntaxDescription
equals:<X>True if value equals X exactly
when: 'equals:true'
when: 'equals:0:not'          # true if value is NOT "0"

matches — regex test

SyntaxDescription
matches:<re>True if value matches the regex

Invalid regex is a hard error.

when: 'matches:^[0-9]+$'          # true if value is digits only
when: 'matches:^(feat|fix):not'   # true if value does NOT start with feat/ or fix:

compare — numeric comparison

SyntaxDescription
compare:<mode>:<N>Compare value against numeric threshold

Modes:

ModeMeaning
gtvalue > N
ltvalue < N
gtevalue ≥ N
ltevalue ≤ N
  • Non-numeric value → "false" (not an error).
  • Non-numeric threshold → hard error.
  • Unknown mode → hard error.
when: 'compare:gt:0'         # true if value is a number greater than 0
when: 'compare:lte:100:not'  # true if value is NOT ≤ 100 (or non-numeric)

is — type/presence predicate

SyntaxDescription
is:<kind>True if value matches the given kind

Kinds:

KindChecks
emptyValue is empty string
numValue parses as a float
intValue parses as an integer
boolValue is "true" or "false"
urlValue parses as a valid URL
pathValue is an existing filesystem path
jsonValue parses as valid JSON
when: 'is:empty:not'    # proceed only if value is non-empty
when: 'is:path'         # proceed only if value is an existing path
when: 'is:json:not'     # true if value is NOT valid JSON

Inversion (:not)

All inspect operators accept :not as a suffix after the arg. It swaps "true" ↔ "false". Applied after the operator, not before:

# Equivalent ways to express "not empty":
when: 'is:empty:not'

Per-item evaluation

All inspect operators are per-item over lists. When the input is a list (separated by ITEM_SEP), each item is evaluated independently, and the results are joined back into a list of "true"/"false" strings.

This matters when when/fail guards evaluate list data — every item must pass for the candidate to proceed.

Operators — Transform

Transform operators are value → value pure functions. They never touch the outside world — no files, no network, no clipboard.

Most operators are list-aware: they adapt to the input kind. If the input contains ITEM_SEP (\x1F), it’s treated as a list; otherwise as a scalar. The operator documentation below notes the behavior for each kind.

Scalar operators

These accept scalar input only. List input is rejected.

base64 — encode / decode

SyntaxDescription
base64:encodeEncode value to base64
base64:decodeDecode base64 to string

Decode failure → empty string (not an error).

mods: 'base64:encode'
mods: 'base64:decode'

split — split string to list

SyntaxDescription
splitSplit by newline (default)
split:<sep>Split by separator

Accepts scalar only; always produces a list. Supports escape mnemonics in the separator (\n, \t, \s).

mods: 'split'           # split by newline
mods: 'split:,\s'       # split by comma-space

List → scalar operators

join — collapse list to string

SyntaxDescription
joinJoin with newline (default)
join:<sep>Join with custom separator

Supports escape mnemonics.

mods: 'join'             # newline-separated
mods: 'join:,\s'         # comma-space separated

item — Nth list element

SyntaxDescription
item:<N>Return element at index N (0-based)

Negative N counts from the end (item:-1 = last). Out of range → empty string. On scalar input: returns the whole string if N is 0, else empty.

mods: 'item:0'           # first element
mods: 'item:-1'          # last element

size — count / length

SyntaxDescription
sizeList → item count; scalar → byte length

Always returns a numeric string.

mods: 'size'

List filter operators

filter — keep / remove items by pattern

SyntaxDescription
filter:<X>Remove items containing X (substring)
filter:eq:<X>Remove items exactly equal to X
filter:not:<X>Keep items containing X (inverted)
mods: 'split|filter:eq:-'         # remove items equal to "-"
mods: 'split|filter:not:error'    # keep items containing "error"

grep — regex filter

SyntaxDescription
grep:<re>Keep items matching regex
grep:<re>:notRemove items matching regex

On scalar input: returns the whole string on match, else empty string.

mods: 'split|grep:^(feat|fix)'       # keep conventional commit lines
mods: 'split|grep:^\\s*$:not'        # remove blank lines

List sort / deduplicate operators

sort — alphabetical sort

SyntaxDescription
sortSort ascending (default)
sort:ascSort ascending
sort:descSort descending

On scalar: sorts characters.

mods: 'split|sort'
mods: 'split|sort:desc'

uniq — deduplicate

SyntaxDescription
uniqRemove duplicate items / characters

Preserves first occurrence order.

mods: 'split|uniq'

reverse — reverse order

SyntaxDescription
reverseList → reverse item order; scalar → reverse chars
mods: 'split|reverse'

List slice operators

take — first N elements

SyntaxDescription
take:<N>List → first N items; scalar → first N chars
mods: 'split|take:5'

tail — last N elements

SyntaxDescription
tail:<N>List → last N items; scalar → last N chars
mods: 'split|tail:3'

Per-item operators

These apply independently to each list item (or the whole scalar).

lower / upper — case conversion

SyntaxDescription
lowerTo lowercase
upperTo UPPERCASE
mods: 'split|lower'
mods: 'upper'

replace — substring replacement

SyntaxDescription
replace:<from>:<to>Replace all occurrences
mods: 'replace:old:new'

trim — trim whitespace / chars

SyntaxDescription
trimStrip whitespace from ends; remove empty list items
trim:<chars>Strip whitespace + chars; remove items equal to chars
mods: 'trim'            # strip whitespace, drop blanks
mods: 'trim:#'          # strip whitespace and '#', drop items equal to '#'

strip — remove Markdown fences

SyntaxDescription
stripRemove ```lang\\n...\\n```, ~~~, `, """ wrappers

Auto-detects the wrapper type. Returns the inner content, trimmed.

mods: 'strip'

default — fallback for empty

SyntaxDescription
default:<X>If value is empty → X, else passthrough

Per-item: each empty list item is replaced with X.

mods: 'default:N/A'

Format conversion

format — convert between data formats

SyntaxDescription
format:jsonConvert to JSON
format:json5Convert to JSON5
format:yamlConvert to YAML
format:tomlConvert to TOML

Auto-detects input format (tries JSON, JSON5, YAML, TOML in order). List-aware: each item is parsed independently, then wrapped into an array for JSON/JSON5 output, concatenated for YAML. TOML does not support top-level arrays.

mods: 'format:json'
mods: 'scan|ast|format:json'

Escape mnemonics

Operator arguments support \n, \t, \s escapes (e.g. join:,\s). Full escape system — see Placeholders & Escapes.

Operators — Write

Write operators are value → world (pass-through). They emit data to the outside world and return the input value unchanged, so downstream operators in the chain continue to see the original value.

Operators

clipboard_text — copy text to clipboard

SyntaxDescription
clipboard_textCopy value to system clipboard (pass-through)

Outer Markdown code fences are stripped before copying. This ensures clean text reaches the clipboard even when the pipeline result is wrapped in a code block.

JSON mode: no-op — see Output Modes.

val:
  - name: result
    data: tag_output
    mods: 'clipboard_text'

clipboard_image — copy image to clipboard

SyntaxDescription
clipboard_imageCopy base64 PNG image to system clipboard (pass-through)

Input must be a base64-encoded image string.

JSON mode: no-op — see Output Modes.

val:
  - name: image
    data: tag_screenshot
    mods: 'clipboard_image'

file — write value to file

SyntaxDescription
file:<path>Write value to file (overwrite)
file:<path>:appendAppend value to file

The path is unescaped for brace-escape sequences. Empty path is a hard error. Write failure is a hard error.

Always passes the input value through, regardless of write outcome.

# Overwrite
val:
  - name: saved
    data: tag_json
    mods: 'file:/tmp/output.json'

# Append
val:
  - name: log
    data: tag_entry
    mods: 'file:/tmp/log.txt:append'

Pass-through behavior

Write operators always return their input unchanged:

input → [write op] → input (side effect: write to clipboard/file)

This means write operators can appear anywhere in a mods chain, and subsequent operators see the original value:

# Save to file AND copy to clipboard
mods: 'file:/tmp/result.txt|clipboard_text'

See Output Modes for details.

Providers — Query

Query providers resolve query_* tags from user input — CLI positional args, clipboard, or IDE plugin data. They are resolved once at pipeline startup (before the engine loop) and stored in input_tags.

Contract

  • Each query_* provider receives the raw positional argument (if any).
  • Non-empty result wins. Empty input → "" — the val candidate is skipped and the next candidate for the same name is tried.
  • Exception: query_image returns Err if the input is not a valid image (hard failure, not empty).
  • Empty query value without a when guard is a startup error (ambiguous input). Add when: 'is:empty:not' to explicitly handle missing input.

Usage in a val candidate:

val:
  - name: content
    data: query_raw
    when: 'is:path'
    mods: 'fetch|text'
  - name: content
    data: query_raw
    fail: 'is:empty:not'

Tags

query_raw — raw input, no validation

TagBehavior
query_rawPositional arg as-is; empty if not provided

No type checking, no path resolution. Use when the input might be text, a path, a URL — anything.

query_prompt — interactive prompt marker

TagBehavior
query_promptReturns raw value; signals interactive fallback

This is a presence marker, not a data provider. When query_prompt appears in any val chain and the query slot is empty, the CLI triggers an interactive terminal prompt. In IDE mode, the plugin opens an input dialog.

The prompt itself fires at a fixed early point in the flow — not during val resolution.

query_clipboard — combined clipboard

TagBehavior
query_clipboardCombined clipboard content by priority: text → paths → image

Reads clipboard content trying each type in order. Token-limited to the largest num_ctx across all cluster nodes (prevents oversized clipboard input from blowing context windows).

query_clipboard_text — clipboard text

TagBehavior
query_clipboard_textRaw text from the clipboard

query_clipboard_path — clipboard file paths

TagBehavior
query_clipboard_pathCopied file paths from the clipboard

Multiple paths are newline-separated.

query_clipboard_image — clipboard image

TagBehavior
query_clipboard_imageClipboard image as base64 PNG string

query_file_path — file path from input

TagBehavior
query_file_pathExplicit input → existing file path; "" if not found

Resolves the positional arg to an absolute path. Supports file:// URI format from IDE plugins. Returns "" if no file exists at the path — this makes the when: 'is:empty:not' pattern work for conditional file-based candidates.

query_project_path — project root path

TagBehavior
query_project_pathInput → project root directory; "" if not found

Walks up from the input path looking for a project marker, then returns the root directory. Recognized markers:

.git, .hg, Cargo.toml, package.json, go.mod, pom.xml, build.gradle, .idea

Stops at the home directory or filesystem root. Returns "" if no marker is found.

query_line — first line of input

TagBehavior
query_lineFirst line of the input text; "" if empty

Useful for single-line IDE inputs (cursor line, selection first line).

query_image — image input

TagBehavior
query_imageInput (URL/file/base64) → validated base64; Err if invalid

Accepts three input forms:

  • URL (http:// / https://) → downloads, encodes to base64.
  • File path → reads file, encodes to base64.
  • Base64 string → decoded and validated.

Always validates that the bytes form a real image. Invalid input is a hard error — use a when guard or a fallback candidate to handle missing images gracefully.

Resolution flow

Query providers are resolved early, before the engine loop:

  1. apply_args() — CLI flags → input_tags.
  2. apply_query_tags() — each query_* in val candidates → input_tags.
  3. validate_query_tags() — reject empty query values without a when guard.

After this, input_tags is frozen and the engine begins resolving actions.

CLI vs IDE

TagCLI sourceIDE source
query_rawPositional arg or clipboardEditor selection text
query_promptInteractive terminal promptIDE input dialog
query_file_pathArg → existing file pathPath to current file
query_project_pathArg → project rootProject root path
query_lineFirst line of argCursor line
query_imageArg → URL/file/base64Screenshot or selected image

The IDE plugin fills the query slot based on the api.input field in the YAML manifest — see IDE Plugin.

Providers — System

System providers resolve system_* tags at runtime. They read environment/OS state — no input, no user interaction.

Contract

  • Always return Ok(String).
  • Missing value → empty string (""), never Err.
  • Resolved once per pipeline run, then cached for all actions.

Usage in a val candidate:

val:
  - name: lang
    data: system_language

Tags

Identity

TagValueExample
system_osOperating system namemacos, linux
system_archCPU architectureaarch64, x86_64
system_hostnameMachine hostnamezarubin-mini
system_userCurrent user name ($USER)keygenqt
system_uidCurrent user ID501
system_pidCurrent process ID42831
system_shellShell basename ($SHELL)zsh, bash
system_languageLanguage code from $LANGen, ru

system_language strips locale suffixes: en_US.UTF-8 → en. Falls back to en if $LANG is unset, C, or POSIX.

Code languages

TagValueExample
system_code_langsSupported code language extensionsrs, py, ts, js, …
system_code_shellSupported shell language extensionssh, bat

Both tags are newline-separated lists, one extension per line. Single source of truth: vibe_ast languages (crate::langs).

Time

TagValueExample
system_dateCurrent date, ISO 86012025-01-15
system_timeCurrent time14:30:05
system_datetimeCurrent date and time, ISO 86012025-01-15T14:30:05
system_timestampUnix epoch seconds1736945405

Hardware

TagValueExample
system_cpu_coresLogical CPU core count8
system_mem_availableAvailable memory in bytes4294967296

Directories

TagValueExample
system_dir_homeUser home ($HOME)/Users/keygenqt
system_dir_pwdCurrent working directory/Users/keygenqt/project
system_dir_configUser config directory~/Library/Application Support (macOS)
system_dir_dataUser data directoryPlatform-specific
system_dir_cacheUser cache directoryPlatform-specific
system_dir_downloadUser downloads directoryPlatform-specific
system_dir_tempTemporary directory/tmp, /var/folders/...

All directory tags use the dirs crate for cross-platform resolution. Missing directory → empty string.

Example

actions:
  - tag: tag_report
    run: small
    val:
      - name: lang
        data: system_language
      - name: os
        data: system_os
      - name: user
        data: system_user
      - name: date
        data: system_date
    action: |
      [Task]
      Generate a short system report.
      Language: {lang}.

      [Data]
      OS: {os}
      User: {user}
      Date: {date}

Built-in Actions

Vibe Action embeds two actions in the binary: docs and info.

Additional commands ship in the vibe-action-groups repository. The default config already connects it via action groups, so these commands are available out of the box as vibe-action <group> <action>.

Groups are declared in config.yaml — you can add your own repositories or local directories the same way. See Configuration for the groups block and the repository for its groups and sources.

Quick Reference

ActionAboutInputOutput
docsAsk a question about Vibe Actionquery_promptdialog
infoShow system information(none)dialog

Query type semantics (query_prompt, …) are described in Query Providers. Output targets (replace, clipboard, dialog) — in IDE Plugin.

Auto-update

On first run, built-in actions are written to ~/.vibe-action/actions/. On every start, the engine compares the on-disk version field with PIPELINE_VERSION (currently 0.0.2). If they differ, the file is overwritten with the embedded default. This keeps built-in actions in sync with the engine — but it also means manual edits to a built-in file are lost when its version bumps.

Grouped actions are never touched: only the embedded files (docs, info) are subject to the version check.

Override the actions directory with VIBE_ACTION_PATH — see CLI Reference.

Customizing

To modify a built-in action, copy it to a new file with a different name. The original will be reset on version bumps; your copy won’t.

See Custom Actions for writing pipelines from scratch, and Configuration for action groups.

Custom Actions

Add your own YAML files to ~/.vibe-action/actions/ — they are loaded automatically alongside the built-in defaults. The file name (without .yaml) becomes the CLI subcommand unless name overrides it.

Minimal action

version: '0.0.2'
name: hello
about: Say hello

actions:
  - tag: tag_greeting
    run: value
    val:
      - name: input
        data: query_raw
    action: 'Hello, {input}!'
vibe-action hello World
# → Hello, World!

File-path / text dual mode

A common pattern: if the input is a valid path, read the file; otherwise treat it as inline text.

actions:
  - tag: tag_content
    run: value
    reg: '.+'
    val:
      - name: content
        data: query_raw
        when: 'is:path'
        mods: 'fetch|text'
      - name: content
        data: query_raw
        fail: 'is:empty:not'
    action: '{content}'

CLI arguments

Define flags; each is available in val candidates as data: <name> (convention: prefix names with arg_):

args:
  - name: arg_style
    short: 's'
    input: string
    default: concise
    help: 'Output style'
vibe-action my-action --arg_style verbose

Argument values are accessed as data: arg_style in val candidates.

LLM prompt with system tags

Use system_* providers to adapt prompts to the user’s environment:

actions:
  - tag: tag_result
    run: medium
    val:
      - name: lang
        data: system_language
      - name: content
        data: query_raw
    action: |
      [Task]
      Respond in {lang}.
      {content}

Multi-step pipeline

Actions can chain results via data referencing other action tags. The engine resolves dependencies automatically:

actions:
  - tag: tag_path
    run: value
    val:
      - name: dir
        data: system_dir_download
      - name: pid
        data: system_pid
    action: '{dir}/output-{pid}.txt'

  - tag: tag_save
    run: value
    val:
      - name: content
        data: query_raw
        mods: 'file:{tag_path}'
    action: 'Saved to {tag_path}'

tag_save depends on tag_path — the engine runs tag_path first.

Shell commands

run: cmd executes via sh -c. Values are shell-quoted automatically:

actions:
  - tag: tag_files
    run: cmd
    val:
      - name: path
        data: query_project_path
    action: find {path} -type f -name '*.rs'

Fan-out with each

Process each item in a list independently, then merge results:

actions:
  - tag: tag_results
    run: small
    val:
      - name: item
        data: tag_items
        each:
          split: '\n'
          merge: '\n'
    action: |
      [Task]
      Summarize: {item}

IDE integration

Add an api block so the IDE plugin knows how to handle the action:

api:
  output: replace
  input: query_raw
  args:
    arg_file: query_file_path

See IDE Plugin for the full API reference.

Customizing built-in actions

Do not edit built-in files directly — they are reset on version bumps. See Built-in Actions.

Validation

All custom actions are validated on startup. Common errors:

ErrorFix
Version mismatchSet version to current PIPELINE_VERSION
Empty name or aboutAdd required fields
Duplicate tag across actionsUse unique tag names
data references own tagRemove self-reference
Bare query in dataUse query_raw instead
query_*/system_* prefix on tagRename the tag
Unknown operator in modsCheck operator name and spelling
Non-inspect operator in when/failUse inspect operators only
Undeclared {name} in actionAdd a val candidate with that name

Tips

  • Start simple — a single run: value or run: small action is enough for most use cases.
  • Use reg — validate output format early. A loose LLM can produce unexpected structure; reg: '.+' catches empty results.
  • Use fail guards — catch empty inputs before they reach the LLM: fail: 'is:empty:not'.
  • Use when guards — avoid unnecessary work (e.g. don’t take a screenshot if the clipboard already has an image).
  • Use ask: true — for destructive shell commands (git push, file deletion), require user confirmation.
  • Test with --help — your action and its args appear in the help output automatically.

Configuration

Vibe Action uses a single YAML config file at ~/.vibe-action/config.yaml. Created automatically on first run. Override the path with VIBE_CONFIG.

Config file structure

version: '0.0.3'

action:
  system: |-
    You are Vibe Action — a CLI tool, not a chatbot.
    Work fast. Just do the task.
    Output ONLY the requested result.
  retries: 2

groups:
  - git: https://github.com/github/vibe-action-groups.git
    path: /code
    name: code
    about: Work with code

cluster:
  - provider: ollama
    host: http://localhost:11434
    model: qwen2.5-coder:3b-instruct
    role: small
    timeout_secs: 30
    temperature: 0.1
    seed: 42
    num_ctx: 4096
    num_predict: 2048
    parallel: 1

Version

Top-level version tracks the config schema. The engine compares it with its internal CONFIG_VERSION on startup — a mismatch is a hard error.

Fix: bump version in your config, or delete ~/.vibe-action/config.yaml and restart (fresh defaults are written).

Action settings

FieldTypeDefaultDescription
systemstring(see code)Global system prompt for all LLM calls
retriesinteger2Retries for failed LLM steps (0 = off)

The default system prompt instructs the model to be brief and output only the requested result — no explanations, no Markdown fences unless asked.

Action groups

groups declares nested command namespaces: vibe-action <group> <action>. Each group sources its YAML actions from a git repository or a local directory.

FieldTypeRequiredDescription
gitstringgit sourceRepository URL, cloned once into the cache
pathstringlocal source; optional with gitDirectory with YAML actions, or subfolder inside the clone (/ = repo root)
refstringnoBranch, tag, or commit to pin (git source only)
namestringyesCLI group name
aboutstringyesShort description shown in help

Either git or path must be set. With a git source, path selects a subfolder of the clone and ref pins a specific branch, tag, or commit.

A git source is cloned once into the cache and re-used on later runs. vibe-action clean removes the cloned groups, so they are re-pulled on the next run.

Local directory group

groups:
  - path: /Users/me/vibe-actions/code
    name: code
    about: Work with code

Group validation

  • name must be non-empty: lowercase letters, digits, _, or -.
  • name must not collide with a system command or a top-level action.
  • about must be non-empty.
  • ref is only allowed with a git source.
  • With git, path must stay inside the clone (no ..).

Cluster

Define one or more LLM provider nodes. The engine routes each pipeline step to nodes whose role matches the step’s run size (see YAML Format).

Cluster node fields

FieldTypeRequiredDescription
providerstringyesollama, deepseek, qwen, kimi, zhipu
hoststringyesAPI endpoint URL
modelstringyesModel name
rolestringnotiny, small, medium, large, vision
timeout_secsintegeryesRequest timeout in seconds
temperaturefloatyes0.0–2.0, lower = more deterministic
seedintegeryesRandom seed for reproducibility
num_ctxintegeryesContext window size in tokens
num_predictintegeryesMax tokens to generate
api_keystringnoAPI key for cloud providers
parallelintegeryesConcurrent connections (default: 1)

Role-based routing

Each pipeline action declares a run size. The engine filters cluster nodes by matching role:

run valueMatches role
tinytiny
smallsmall
mediummedium
largelarge
visionvision
  • No node with the requested role → fallback: all nodes are used.
  • Node without a role → responds to every request.
  • Missing role at pipeline start → warning printed.

Multi-node example

cluster:
  - provider: ollama
    host: http://localhost:11434
    model: qwen2.5-coder:3b-instruct
    role: small
    timeout_secs: 30
    temperature: 0.0
    seed: 42
    num_ctx: 4096
    num_predict: 512
    parallel: 2
  - provider: deepseek
    host: https://api.deepseek.com/v1
    model: deepseek-v4-flash
    role: large
    timeout_secs: 120
    temperature: 0.1
    seed: 42
    num_ctx: 16384
    num_predict: 8192
    api_key: sk-...
    parallel: 2
  - provider: ollama
    host: http://localhost:11434
    model: qwen2.5vl:7b
    role: vision
    timeout_secs: 120
    temperature: 0.4
    seed: 42
    num_ctx: 8192
    num_predict: 8192
    parallel: 1

File layout

~/.vibe-action/
├── config.yaml
└── actions/
    ├── docs.yaml
    └── info.yaml
  • Config: ~/.vibe-action/config.yaml — override with VIBE_CONFIG.
  • Actions: ~/.vibe-action/actions/ — override with VIBE_ACTION_PATH.
  • Both directories are created on first run. Custom .yaml files in the actions directory are loaded automatically.
  • Cloned group repositories live in the application cache directory, not under ~/.vibe-action/.

Initialization order

  1. Output registry from VIBE_LOG_TYPE / VIBE_TRACE_LEVEL.
  2. Config file from VIBE_CONFIG or default path; create if missing.
  3. Validate config (version, cluster nodes).
  4. Load pipelines (scan actions dir and action groups, validate, cache).

Output Modes

Vibe Action routes all output through a single strategy selected at startup. No println! exists outside the output module — everything flows through print_template! / print_text! macros.

Selecting a mode

Set VIBE_LOG_TYPE before startup:

VIBE_LOG_TYPE=json vibe-action code review main.rs
ValueStrategyUse for
(unset)cliInteractive terminal (default)
clicliInteractive terminal
plainplainCI, piped output, scripts
jsonjsonIDE plugin / Kotlin-Compose UI
tracingtracingDebugging, detailed structured logs
(auto)testInternal test mode (VIBE_TEST=1)

Mode details

cli — terminal

ANSI-colored messages with semantic labels:

  • error — red bold error:
  • warning — yellow bold warning:
  • info — blue bold info:
  • progress — cyan bold, carriage-return overwrite for percentages
  • success — green framed block with Markdown rendering and syntax highlighting

Template placeholders support inline styling: {key|color|style} — e.g. {tag|bright_green|bold}.

Success blocks render Markdown via termimad and highlight code via syntect (base16-eighties dark theme). Language aliases are resolved automatically (arkts→typescript, csharp→cs, batch→bat, etc.).

plain — unformatted

No ANSI codes, no framing, no Markdown rendering. Errors and warnings go to stderr; everything else to stdout. Use in CI pipelines or when piping output to other tools.

json — structured

Each message is a JSON object on stdout:

{
  "level": "success",
  "value": {
    "message": "result text"
  }
}

Fields are the key-value pairs from the template. Outer Markdown code fences are stripped from string values.

Clipboard write operators (clipboard_text, clipboard_image) are no-ops in JSON mode — the plugin owns the buffer. Use api.output: clipboard in the YAML manifest to have the plugin copy the result — see IDE Plugin.

Messages are tagged with an export context for plugin routing:

ContextPurpose
actionsAction list / status
statusSystem status response
successFinal action result
confirmUser confirmation prompt

tracing — structured logs

Delegates to the tracing crate. Set VIBE_TRACE_LEVEL to control verbosity (only effective when VIBE_LOG_TYPE=tracing):

LevelShows
errorErrors only
warnWarnings + errors
infoFlow progress + results
debugEngine internals
traceMaximum verbosity

test — minimal

Only error and success pass through; all other kinds are no-ops. Activated automatically when VIBE_TEST=1. Used for integration test assertions.

Message model

Every message is an OutputMsg with:

  • kind — semantic level (plain, info, success, warning, error, debug, trace, progress)
  • template — layout string with {key} placeholders
  • fields — key-value map (JSON values)

The formatter resolves placeholders per mode: CLI applies {key|color|style} styling; plain/json substitute values without styling.

CLI Reference

Usage

vibe-action <action> [query] [args...]

vibe-action docs "How to use the 'contains' operator?"
vibe-action info
vibe-action --help

Each <action> maps to a YAML-defined action. Use --help to list all available actions and their arguments:

vibe-action --help
vibe-action docs --help

Action groups

Actions from external repositories or local directories are nested under a group command:

vibe-action <group> <action> [query] [args...]

vibe-action code review main.rs
vibe-action project commit .

Groups are declared in config.yaml and loaded on startup — see Configuration.

  • vibe-action <group> prints the group’s action list.
  • vibe-action <group> <action> --help prints action-specific help.

System commands

vibe-action status   # Show version, paths, action counts
vibe-action clean    # Remove stale cache, temp files, clipboard
vibe-action stop     # Stop all running vibe-action processes

Action arguments

Actions define their own CLI arguments in YAML. See YAML Format for the args schema.

vibe-action project commit -d         # dry-run flag (bool)
vibe-action data extract -f log.txt   # file argument (string)

Singleton guard

By default, only one vibe-action process runs at a time. Starting a new action automatically stops the previous one (graceful shutdown with a 3-second timeout, then force-kill). This keeps shared state (cache, local LLMs) predictable.

Disable with VIBE_SKIP_LOCK:

VIBE_SKIP_LOCK=1 vibe-action code review main.rs

Useful for parallel API clusters or when running multiple actions concurrently.

Interactive confirm

Actions with ask: true prompt for user approval before execution:

  • CLI — inquire confirm dialog with the command preview.
  • JSON mode — confirm protocol via stdin/stdout (30-second timeout, fail-closed).

Interactive prompt

Actions using query_prompt trigger an interactive input when no query is provided on the command line:

  • CLI — inquire text prompt labeled “Query”.
  • IDE — plugin opens an input dialog.

Desktop notifications

Actions with notify: true send a desktop notification on completion (CLI mode only):

  • macOS — via terminal-notifier (install: brew install terminal-notifier).
  • Linux — via notify-rust (freedesktop.org D-Bus spec).

Role mismatch warning

If a pipeline uses a run size (e.g. large) but no cluster node has the matching role, the engine warns and offers to continue with all available nodes (fallback). In CLI mode this is a confirm dialog; in JSON mode it uses the confirm protocol.

See Configuration for cluster role setup.

Environment variables

VariableDescriptionDefault
VIBE_CONFIGPath to config file~/.vibe-action/config.yaml
VIBE_ACTION_PATHPath to actions directory~/.vibe-action/actions/
VIBE_SKIP_LOCKDisable singleton guard for parallel executionNot set (guard enabled)
VIBE_TESTInternal test mode (1 = enabled)Not set

Output-related variables (VIBE_LOG_TYPE, VIBE_TRACE_LEVEL) and trace levels — see Output Modes.

Exit codes

CodeDescription
0Success
1Error (validation, shell command, LLM failure)
130Instance superseded by a newer run (auto-cancelled)

IDE Integration (VS Code & IntelliJ)

Vibe Action works perfectly from the terminal, but you can supercharge your workflow with the Vibe Action Cross IDE plugin.

Instead of manually configuring tasks.json in VS Code or External Tools in IntelliJ, the plugin provides a native UI panel inside your editor. It communicates directly with the vibe-action CLI to discover all available actions, letting you run them with visible, real-time feedback.

Why Use the Plugin?

  • Zero Configuration: no need to edit JSON/XML files. The plugin automatically fetches all available actions from the vibe-action CLI — including built-in commands, your custom YAML flows, and any modifications you’ve made to the defaults.
  • Context Awareness: automatically passes selected text, file paths, or project context to your actions using query tags.
  • Native UI: real-time progress feedback inside the IDE instead of waiting for terminal windows or system notifications.
  • Seamless Output: results can automatically replace selected code, be copied to the clipboard, or appear in a native dialog window.

Prerequisites

Vibe Action CLI must be installed and available on your system PATH.

cargo install vibe-action

Get the plugin: download the latest pre-built artifacts (.vsix and .zip) from the GitHub releases, or build them yourself from the vibe-action-cross repository source.

VS Code Setup

  1. Open VS Code.
  2. Go to the Extensions view (Cmd+Shift+X or Ctrl+Shift+X).
  3. Click the ... menu in the top-right corner of the Extensions panel.
  4. Select Install from VSIX….
  5. Navigate to the downloaded file and select vibe-action-<version>.vsix.
  6. Reload VS Code when prompted.

Alternatively, install via CLI:

code --install-extension vibe-action-<version>.vsix

Once installed, open the Vibe Action panel from the activity bar. You will see a list of all your available actions. Click any action to run it, or use the provided keyboard shortcuts.

IntelliJ IDEA Setup

  1. Open IntelliJ IDEA.
  2. Go to Settings/Preferences -> Plugins.
  3. Click the gear icon (⚙️) in the top-right corner of the Plugins window.
  4. Select Install Plugin from Disk….
  5. Navigate to the downloaded file and select vibe-action-<version>.zip.
  6. Restart IntelliJ IDEA when prompted.

Once installed, open the Vibe Action tool window (usually located on the right sidebar). The UI is rendered natively using Compose Multiplatform and matches the IntelliJ theme.

The api Block

The optional api block in a YAML action tells the plugin where to take input from and how to present the result. The CLI runtime ignores it.

version: 0.0.2
name: upper
about: Convert text to UPPERCASE
api:
  output: replace # replace | clipboard | dialog
  input: query_raw # any query tag, e.g. query_raw, query_prompt, query_image
  args: # Optional: extra inputs beyond the main query
    arg_file: query_file_path
actions:
  - tag: tag_upper
    run: value
    val:
      - name: text
        data: query_raw
        mods: 'upper'
    action: '{text}'

Output Targets (api.output)

  • replace — the plugin replaces the currently selected text in your editor with the action’s result.
  • clipboard — the plugin copies the result to your system clipboard.
  • dialog — the result is shown in a native IDE popup/dialog.

Note: prefer output: clipboard over the clipboard_text / clipboard_image operators in pipelines meant for the IDE — those operators are no-ops when the action is driven by the plugin.

Input Sources (api.input)

The input field names the query tag the plugin fills before executing the CLI: query_raw (raw text), query_prompt (interactive dialog), query_file_path, query_project_path, query_line, query_image, and others. The full list with CLI and IDE behavior lives in Query Providers.

If an action does not have an api block, the plugin simply executes it and falls back to standard CLI behavior.

Extra Inputs (api.args)

args maps argument names to query tags. Use it when a flow needs multiple inputs beyond the main query: each key is an argument name (matching an args entry), each value is a query tag. The IDE collects them and passes them to the CLI automatically.