raffi 0.25.0

A simple fuzzel launcher based on YAML file
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
---
title: Addon Configuration
description: Configuration reference for built-in addons (currency, calculator, unit conversion, color converter, world clock, developer tools, file browser, script filters, web searches, text snippets, clipboard history, system commands, window switcher, media controls, audio switcher, kill process, Bluetooth)
---

import { Image } from 'astro:assets';
import keywordSuggestionScreenshot from '../../../assets/screenshots/keyword-suggestion.png';
import keywordHelpScreenshot from '../../../assets/screenshots/keyword-help.png';
import emojiScreenshot from '../../../assets/screenshots/emoji-picker.png';

The native UI includes several built-in addons that can be configured under the `addons` section of `raffi.yaml`. All addons except the clipboard history browser are enabled by default.

## Keywords

Script filters, web searches, text snippets, the emoji picker, the clipboard
history browser, system commands, the window switcher, media controls, the audio switcher, the process killer, Bluetooth, the password store, Bitwarden, Slack and developer tools are reached by
typing their keyword followed by a space. Typing `sn` on its own searches your
launchers as usual, while `sn ` enters the snippet source.

While you type a keyword, Raffi lists the matching keywords at the top of the
results with a short description of what each one does. Pressing Enter or Tab on
one of those rows completes your input to `sn ` and drops you into the addon, so
you never have to remember the exact keyword.

Suggestions start once you have typed three characters, so a single `s` keeps
your launcher results uncluttered. A keyword typed in full, such as `sn`, is
suggested right away. Change the threshold with `keyword_min_chars`:

```yaml
addons:
  keyword_min_chars: 1   # suggest from the first character
```

The file browser (`/`, `~/`) and the currency converter (`$`) are prefix
triggers rather than keywords, and are not affected.

Press **Ctrl+/** in the native UI to open help, with addon keywords and actions
in one section and keyboard shortcuts in another. Typing filters both sections.
Opening help temporarily clears the current query; Escape or **Ctrl+/** restores
it. Enter or Tab on a keyword row applies its completion.

<Image src={keywordSuggestionScreenshot} alt="Keyword suggestion appearing before the trigger is fully typed" width={800} />

<Image src={keywordHelpScreenshot} alt="Keyword help overlay with details for the selected shortcut" width={800} />

<Image src={emojiScreenshot} alt="Emoji picker with a selected character and Unicode information" width={800} />

## Currency Converter

Converts between currencies using exchange rates from the Frankfurter API. Rates are cached for one hour.

### Configuration

**`addons.currency.enabled`** `boolean` (default: `true`)

Enable or disable the currency converter addon.

  ```yaml
  addons:
    currency:
      enabled: true

```

**`addons.currency.trigger`** `string` (default: `$`)

Character that activates currency conversion.

  Common values: `$`, `€`, `£`, `¥`

  ```yaml
  addons:
    currency:
      trigger: "€"

```

**`addons.currency.default_currency`** `string` (default: `USD`)

Source currency used when none is specified in the query.

  Must be a valid 3-letter ISO currency code (e.g., `USD`, `EUR`, `GBP`, `JPY`).

  ```yaml
  addons:
    currency:
      default_currency: EUR

```

**`addons.currency.currencies`** `array[string]`

List of available currencies for conversion.

  If omitted, all currencies supported by the Frankfurter API are available. Specify a subset to limit options.

  ```yaml
  addons:
    currency:
      currencies: ["EUR", "USD", "GBP", "JPY", "CHF"]

```

### Usage Examples

With trigger `$` and default currency `USD`:

```
$10 to eur          → Converts 10 USD to EUR
$50 gbp to usd      → Converts 50 GBP to USD
$100eur to jpy      → Converts 100 EUR to JPY
```

With trigger `€` and default currency `EUR`:

```
€10 to usd          → Converts 10 EUR to USD
€50 to gbp          → Converts 50 EUR to GBP
```

### Complete Example

```yaml
addons:
  currency:
    enabled: true
    trigger: "€"
    default_currency: EUR
    currencies: ["EUR", "USD", "GBP", "JPY"]
```

## Calculator

Evaluates mathematical expressions as you type. Results can be copied to the clipboard with Enter (requires `wl-copy`, `xclip` or `xsel`).

### Configuration

**`addons.calculator.enabled`** `boolean` (default: `true`)

Enable or disable the calculator addon.

  ```yaml
  addons:
    calculator:
      enabled: true

```

### Supported Operations

- Basic arithmetic: `+`, `-`, `*`, `/`, `%`, `^`
- Functions: `sqrt`, `sin`, `cos`, `tan`, `log`, `ln`, `exp`, `abs`, `floor`, `ceil`
- Constants: Standard mathematical constants

### Usage Examples

```
2 + 2               → 4
10 * 5              → 50
sqrt(16)            → 4
sin(0.5)            → ~0.479
2^8                 → 256
```

No trigger character is needed; simply type a valid expression.

## Unit Conversion

Converts lengths, weights, volumes, temperatures, data sizes, durations,
speeds and areas as you type, such as `10 km to mi`. See
[Unit Conversion](../../features/unit-conversion/) for the supported units.

### Configuration

**`addons.units.enabled`** `boolean` (default: `true`)

Enable or disable unit conversion.

```yaml
addons:
  units:
    enabled: false
```

## Color Converter

Shows a color typed as `#ff8800`, `rgb(255 136 0)` or `hsl(32 100% 50%)` in
hex, rgb and hsl, with the nearest CSS color name. See
[Color Converter](../../features/color-converter/) for the accepted formats.

### Configuration

**`addons.color.enabled`** `boolean` (default: `true`)

Enable or disable the color converter.

```yaml
addons:
  color:
    enabled: false
```

## World Clock

Shows the time in another place (`time tokyo`, `time in new york`) or converts
a time between places (`15:00 paris to nyc`). Needs the system `tzdata`
package. See [World Clock](../../features/world-clock/) for place names and rules.

### Configuration

**`addons.world_clock.enabled`** `boolean` (default: `true`)

Enable or disable the world clock.

```yaml
addons:
  world_clock:
    enabled: false
```

## File Browser

Browses the filesystem with fuzzy filtering. Selecting a directory navigates into it; selecting a file opens it with `xdg-open` unless `action` says otherwise. Hidden files can be toggled with Ctrl+H.

### Configuration

**`addons.file_browser.enabled`** `boolean` (default: `true`)

Enable or disable the file browser addon.

  ```yaml
  addons:
    file_browser:
      enabled: true

```

**`addons.file_browser.show_hidden`** `boolean` (default: `false`)

Show hidden files by default.

  Can be toggled at runtime with Ctrl+H.

  ```yaml
  addons:
    file_browser:
      show_hidden: true

```

**`addons.file_browser.sort`** `string` (default: `name`)

Initial order of the listing: `name` (alphabetical), `modified` (newest first; `date` is accepted too) or `created` (newest first). Directories stay before files. Cycle with Ctrl+S at runtime.

  ```yaml
  addons:
    file_browser:
      sort: modified

```

**`addons.file_browser.sort_reverse`** `boolean` (default: `false`)

Reverse the active sort: Z to A, or oldest first for `modified`/`created`. Directories stay before files. Ctrl+S cycles the mode and leaves this setting alone.

  ```yaml
  addons:
    file_browser:
      sort: modified
      sort_reverse: true

```

**`addons.file_browser.show`** `string` (default: `all`)

Which entries the listing starts with: `all`, `files` or `directories` (`dirs` and `directory` work too). Cycle with Ctrl+. at runtime. When directories are hidden you can still type or Tab-complete a directory path to enter it.

  ```yaml
  addons:
    file_browser:
      show: files

```

**`addons.file_browser.fido_style`** `boolean` (default: `true`)

Edit paths the way Emacs fido-mode does. Backspace on a trailing `/` goes up to the parent directory and selects the one you left, and typing `~/` or `/` right after a `/` starts over from your home directory or the root. Set to `false` to edit the path as plain text.

  ```yaml
  addons:
    file_browser:
      fido_style: false

```

**`addons.file_browser.action`** `string` (default: `open`)

Action run when pressing Enter (or clicking) on a file. Enter on a directory always navigates into it, and Ctrl+O always opens the selection with `xdg-open`. Accepts `open` (xdg-open), `copy` (copy the full path), `insert` (type the full path into the focused app), or a shell command where `{value}` is replaced by the full path (also available as `$RAFFI_VALUE`).

**`addons.file_browser.secondary_action`** `string` (default: `copy`)

Action run when pressing Ctrl+Enter (or Ctrl+click) on a file or directory. Accepts the same values as `action`.

**`addons.file_browser.file_manager`** `string` (default: autodetected)

Command that Ctrl+B uses to open the browsed directory. The directory is appended as the last argument, or replaces `{value}` when present. Nautilus, Dolphin, Nemo and Caja (given as a bare program name or path) open with the selected entry highlighted through `--select`. When unset, raffi uses the desktop's own file manager (Dolphin, Nautilus, Thunar, Nemo, Caja, PCManFM...) if installed, then the first installed one, then `xdg-open`.

  ```yaml
  addons:
    file_browser:
      action: "code {value}"
      secondary_action: insert
      file_manager: dolphin

```

**`addons.file_browser.preview_command`** `string` (default: the bundled previewer when `python3` is installed)

Command that previews the selected entry in the preview pane. When unset, raffi runs the previewer it bundles from `scripts/file-preview`; `none` turns rich previews off. The path is appended as the last argument and exported as `$RAFFI_VALUE`; the command prints ANSI text or a [preview object](../../features/script-filters/#preview-object) as JSON, and prints nothing or exits non-zero to keep the built-in preview. See [Rich Previews](../../features/file-browser/#rich-previews).

  ```yaml
  addons:
    file_browser:
      preview_command: "~/.config/raffi/scripts/file-preview.py"

```

### Usage

- Type `/` to browse from root
- Type `~` to browse from home directory
- Text after the last `/` filters the current directory (e.g., `/home/us` filters `/home/` by "us")
- Enter: Navigate into directory, or run `action` on a file (open by default)
- Ctrl+Enter: Run `secondary_action` on a file or directory (copy path by default)
- Tab: Autocomplete selected entry into search bar
- Backspace on a trailing `/`: Go up to the parent directory
- `~/` or `/` after a `/`: Start over from home or the root
- Ctrl+H: Toggle hidden file visibility
- Ctrl+O: Open the selected file or directory with `xdg-open`
- Ctrl+B: Open the current directory in a file manager
- Ctrl+Y: Copy the selected path to the clipboard, regardless of configured actions
- Ctrl+Alt+Y: Copy a supported image file to the clipboard
- Ctrl+S: Cycle the sort order (name, modified, created)
- Ctrl+.: Cycle the listing between all entries, files only and directories only

Directories are listed first in accent color.

### Example

```yaml
addons:
  file_browser:
    enabled: true
    show_hidden: false
```

## Script Filters

Script filters allow external commands to provide dynamic results using the [Alfred Script Filter JSON format](https://www.alfredapp.com/help/workflows/inputs/script-filter/json/).

### Configuration

**`addons.script_filters`** `array[object]` (default: `[]`)

List of script filter configurations.

  Each entry defines a keyword-triggered dynamic source.

### Script Filter Fields

**`name`** `string` (required)

Display name shown during loading.

  ```yaml
  addons:
    script_filters:
      - name: "Timezones"

```

**`keyword`** `string` (required)

Text that activates the script filter. Type it followed by a space, so `tz `
enters the filter while `tz` keeps searching launchers.

  ```yaml
  addons:
    script_filters:
      - keyword: "tz"

```

**`command`** `string` (required)

Executable to run.

  Supports tilde and environment variable expansion.

  ```yaml
  addons:
    script_filters:
      - command: "batz"

```

**`args`** `array[string]` (default: `[]`)

Arguments passed to the command before the user's query.

  ```yaml
  addons:
    script_filters:
      - command: "my-script"
        args: ["-j", "--verbose"]

```

**`icon`** `string`

Fallback icon name for results without their own icon.

  ```yaml
  addons:
    script_filters:
      - icon: "clock"

```

**`action`** `string` (default: `copy`)

Action to perform on Enter.

  Special values:

- `copy` - Copy to clipboard via `wl-copy`/`xclip`/`xsel`
- `insert` - Type into focused app via `wtype`/`ydotool`

  Any other string is executed as a shell command via `sh -c`, with `{value}` replaced by the selected value.

  ```yaml
  addons:
    script_filters:
      - action: "copy"                    # Copy to clipboard
      - action: "xdg-open {value}"        # Open in browser
      - action: "notify-send {value}"    # Show notification

```


**`secondary_action`** `string`

Action to perform on Ctrl+Enter.

  Accepts the same values as `action`. If omitted, Ctrl+Enter behaves the same as Enter.

  ```yaml
  addons:
    script_filters:
      - action: "copy"
        secondary_action: "xdg-open {value}"

```

**`env`** `object` (default: `{}`)

Environment variables passed to the script process.

  ```yaml
  addons:
    script_filters:
      - command: "my-script"
        env:
          API_KEY: "secret"
          TZ_FORMAT: "short"

```

**`min_query_length`** `integer`

Minimum number of characters required after the keyword before the script executes.

  When the query is shorter than this value, results are cleared and the script is not run. Useful for scripts that are slow or expensive with short queries.

  ```yaml
  addons:
    script_filters:
      - command: "my-script"
        min_query_length: 2   # only execute after 2 chars typed

```

**`dynamic_preview`** `boolean` (default: `true`)

Re-run the script with `RAFFI_PREVIEW=1` for the selected item and show the preview object it prints in the preview pane. Scripts that do not support it are detected and skipped after one run. See [Dynamic Previews](../../features/script-filters/#dynamic-previews).

  ```yaml
  addons:
    script_filters:
      - command: "my-script"
        dynamic_preview: false   # only use the items' preview field

```

### JSON Output Format

The script must output JSON matching this structure:

```json
{
  "items": [
    {
      "title": "New York",
      "subtitle": "EST (UTC-5) — 14:30",
      "arg": "America/New_York",
      "icon": { "path": "/usr/share/icons/clock.png" }
    }
  ]
}
```

**JSON Fields:**

- `title` (required): Main text displayed for the item
- `subtitle` (optional): Secondary text shown below the title
- `arg` (optional): Value used in actions (falls back to `title` if omitted)
- `icon.path` (optional): Absolute path to a PNG or SVG icon
- `preview` (optional): Preview text or file path, or a preview object (see [Dynamic Previews](../../features/script-filters/#dynamic-previews))
- `variables` (optional): String map exported as environment variables to the preview call and to the actions

The `title` and `subtitle` fields support ANSI color codes for colored text rendering.

### Example: Timezone Converter

```yaml
addons:
  script_filters:
    - name: "Timezones"
      keyword: "tz"
      command: "batz"        # https://github.com/chmouel/batzconverter
      args: ["-j"]
      icon: "clock"
```

Usage: Type `tz paris` to see current time in Paris.

### Example: Bookmarks with Actions

```yaml
addons:
  script_filters:
    - name: "Bookmarks"
      keyword: "bm"
      command: "my-bookmark-script"
      args: ["-j"]
      action: "copy"                    # Enter: Copy URL
      secondary_action: "xdg-open {value}"  # Ctrl+Enter: Open in browser
      icon: "bookmark"
```

## Web Searches

Quick web searches via URL templates. Type a keyword followed by your query to open your browser with search results.

### Configuration

**`addons.web_searches`** `array[object]` (default: `[]`)

List of web search configurations.

### Web Search Fields

**`name`** `string` (required)

Display name shown in the search row (e.g., "Search Google for...").

  ```yaml
  addons:
    web_searches:
      - name: "Google"

```

**`keyword`** `string` (required)

Text that activates the web search. Type it followed by a space, so `g `
enters the search while `g` keeps searching launchers.

  ```yaml
  addons:
    web_searches:
      - keyword: "g"

```

**`url`** `string` (required)

URL template with `{query}` placeholder.

  The `{query}` placeholder is replaced with the search terms, automatically percent-encoded.

  ```yaml
  addons:
    web_searches:
      - url: "https://google.com/search?q={query}"

```

**`icon`** `string`

Icon name from your icon cache.

  ```yaml
  addons:
    web_searches:
      - icon: "google"

```

### Example: Common Search Engines

```yaml
addons:
  web_searches:
    - name: "Google"
      keyword: "g"
      url: "https://google.com/search?q={query}"
      icon: "google"

    - name: "DuckDuckGo"
      keyword: "ddg"
      url: "https://duckduckgo.com/?q={query}"
      icon: "duckduckgo"

    - name: "GitHub"
      keyword: "gh"
      url: "https://github.com/search?q={query}&type=repositories"
      icon: "github"

    - name: "Wikipedia"
      keyword: "wiki"
      url: "https://en.wikipedia.org/wiki/Special:Search?search={query}"
      icon: "wikipedia"
```

### Usage Examples

```
g rust traits       → Opens Google search for "rust traits"
ddg wayland        → Opens DuckDuckGo search for "wayland"
gh iced            → Opens GitHub search for "iced" repositories
```

## Text Snippets

Reusable text values that can be searched and copied/typed. Snippets can come from inline definitions, external files, commands, or directories.

### Configuration

**`addons.text_snippets`** `array[object]` (default: `[]`)

List of text snippet source configurations.

### Text Snippet Fields

**`name`** `string` (required)

Display name shown during loading (for command sources).

  ```yaml
  addons:
    text_snippets:
      - name: "Emails"

```

**`keyword`** `string` (required)

Text that activates this snippet source. Type it followed by a space, so `em `
enters the source while `em` keeps searching launchers.

  ```yaml
  addons:
    text_snippets:
      - keyword: "em"

```

**`icon`** `string`

Default emoji, icon name, or image path displayed next to each snippet.
A per-snippet `icon` overrides it; an unavailable icon falls back to this
default. `no_icons` hides both. Paths support tilde and environment variables.

  ```yaml
  addons:
    text_snippets:
      - icon: "mail"

```

**`snippets`** `array[object]`

Inline list of snippets.

  Each snippet has:

- `name` (string, required): Display name
- `value` (string, required): Snippet content, which may contain
  [dynamic placeholders](../../features/text-snippets/#dynamic-placeholders)
  such as `{clipboard}` or `{date +1d}`
- `keyword` (string, optional): Abbreviation ranked first when typed exactly
- `icon` (string, optional): Emoji (for example `🏠`), icon name, or image path

  ```yaml
  addons:
    text_snippets:
      - snippets:
          - name: "Personal Email"
            icon: "📨"
            value: "user@example.com"
          - name: "Work Email"
            value: "user@company.com"

```


**`file`** `string`

Path to a YAML file containing snippets.

  The file must contain a list of objects with `name` and `value` fields. Supports tilde and environment variable expansion. File contents are cached per session.

  ```yaml
  addons:
    text_snippets:
      - file: "~/.config/raffi/snippets.yaml"

```

  File format:

  ```yaml
  - name: "Greeting"
    value: "Hello, world!"
  - name: "Signature"
    value: "Best regards, User"

```

**`command`** `string`

Executable that outputs Alfred Script Filter JSON.

  The `title` field maps to snippet name, `arg` to snippet value, and the optional `keyword` field to the snippet keyword. An optional `icon.path` sets the item icon. `{shell:...}` placeholders are disabled for command output. Supports tilde and environment variable expansion.

  ```yaml
  addons:
    text_snippets:
      - command: "my-snippet-gen"

```

**`directory`** `string`

Path to a directory of `.snippet` files.

  Each `.snippet` file format:

  ```
  Description (first line)
  keyword: !abbr (optional)
  icon: 🏠 (optional)
  ---
  Actual snippet content (everything after the separator)
  ```

  The optional headers can appear in either order. Supports tilde and environment variable expansion. Files are cached per session.

  ```yaml
  addons:
    text_snippets:
      - directory: "~/.local/share/snippets"

```

**`args`** `array[string]` (default: `[]`)

Arguments passed to the command.

  ```yaml
  addons:
    text_snippets:
      - command: "my-snippet-gen"
        args: ["-j", "--verbose"]

```

**`action`** `string` (default: `copy`, or `hypr_paste` on Hyprland)

Action to perform on Enter. Inside Hyprland, an unset `action` becomes
`hypr_paste` when Raffi finds a window to paste into, and `copy` otherwise.

  Special values:

- `copy` - Copy to clipboard via `wl-copy`/`xclip`/`xsel` (default outside Hyprland)
- `insert` - Type into focused app via `wtype`/`ydotool`
- `hypr_paste` - On Hyprland, copy with `wl-copy`, close Raffi, wait for the
  original window to regain focus, and send Ctrl+V to that window (Ctrl+Shift+V
  for terminals, see `general.terminal_classes`). Requires
  Hyprland's Lua API, `hyprctl`, and `wl-clipboard`. Leaves the snippet on the
  clipboard unless `restore_clipboard` is enabled; does not reposition
  `{cursor}`. Marks the snippet sensitive so CopyQ and other clipboard managers
  that honor the hint skip storing it. See
  [Hyprland paste](../../features/text-snippets/#default-actions).

  Any other string is executed as a shell command via `sh -c`, with `{value}` replaced by the snippet value. The value is also exported as `$RAFFI_VALUE`; prefer `"$RAFFI_VALUE"` when the snippet may contain quotes or shell syntax, since `{value}` is substituted as raw text.

  ```yaml
  addons:
    text_snippets:
      - action: "copy"                    # Copy to clipboard
      - action: "insert"                  # Type into app
      - action: "hypr_paste"              # Paste into the original window on Hyprland
      - action: 'notify-send "$RAFFI_VALUE"'  # Custom command

```


**`secondary_action`** `string` (default: `insert`)

Action to perform on Ctrl+Enter.

  Accepts the same values as `action`. Defaults to `insert` if omitted.

  ```yaml
  addons:
    text_snippets:
      - action: "insert"          # Enter: Type
        secondary_action: "copy"  # Ctrl+Enter: Copy

```

**`restore_clipboard`** `boolean` (default: `false`)

For `action: "hypr_paste"` or `secondary_action: "hypr_paste"`, save the
previous plain-text clipboard and restore it one second after the shortcut
if Raffi's clipboard marker is still present. Requires `wl-paste`. Saving or
restoration failures do not block pasting. Snapshots are limited to 100 KiB of
UTF-8 text without NUL bytes; unavailable or non-text selections are skipped.
Rich-text formatting and images are not preserved. The delay is best effort
and may be too short for slow applications. This setting does not affect other
actions.

**`placeholders`** `boolean` (default: `true`)

Expand [dynamic placeholders](../../features/text-snippets/#dynamic-placeholders) in snippet values. Set to `false` to use values exactly as written.

  ```yaml
  addons:
    text_snippets:
      - file: "~/.config/raffi/literal-snippets.yaml"
        placeholders: false

```

**Note:** Exactly one of `snippets`, `file`, `command`, or `directory` should be specified per entry.

### Example: Inline Snippets

```yaml
addons:
  text_snippets:
    - name: "Emails"
      keyword: "em"
      icon: "mail"
      action: "copy"
      snippets:
        - name: "Personal Email"
          value: "user@example.com"
        - name: "Work Email"
          value: "user@company.com"
```

### Example: File-Based Snippets

```yaml
addons:
  text_snippets:
    - name: "Templates"
      keyword: "tpl"
      icon: "document"
      file: "~/.config/raffi/snippets.yaml"
```

### Example: Command-Based Snippets

```yaml
addons:
  text_snippets:
    - name: "Dynamic"
      keyword: "dyn"
      icon: "terminal"
      command: "my-snippet-gen"
      args: ["-j"]
```

### Example: Directory-Based Snippets

```yaml
addons:
  text_snippets:
    - name: "Code Snippets"
      keyword: "sn"
      icon: "code"
      directory: "~/.local/share/snippets"
```

### Example: Custom Actions

```yaml
addons:
  text_snippets:
    - name: "URLs"
      keyword: "url"
      icon: "web-browser"
      action: "xdg-open {value}"        # Enter: Open in browser
      secondary_action: "copy"          # Ctrl+Enter: Copy URL
      snippets:
        - name: "GitHub"
          value: "https://github.com"
        - name: "Documentation"
          value: "https://docs.example.com"
```

## Clipboard History

Browses the clipboard history stored by CopyQ. See
[Clipboard History](../../features/clipboard-history/) for setup and usage.

### Configuration

**`addons.clipboard.enabled`** `boolean` (default: `false`)

Turns the clipboard browser on. CopyQ must be installed and running.

**`addons.clipboard.trigger`** `string` (default: `clip`)

Keyword that opens the history. Type it followed by a space.

**`addons.clipboard.image_trigger`** `string` (default: `clipimg`)

Keyword that opens the history showing only images. **Ctrl+I** switches
between images only and all items in either case.

**`addons.clipboard.min_chars`** `integer` (default: `3`)

Hide text entries shorter than this many characters, not counting surrounding
whitespace. `0` lists everything. Images and files are always listed.

**`addons.clipboard.backend`** `string` (default: `copyq`)

Clipboard manager to read from. `copyq` is the only supported value.

**`addons.clipboard.action`** `string` (default: `copy`)

What Enter does: `copy` puts the item back on the clipboard with all its
formats, `hypr_paste` also pastes it into the previous window on Hyprland.

**`addons.clipboard.secondary_action`** `string` (default: `hypr_paste`)

What Ctrl+Enter does. Accepts the same values as `action`. Outside Hyprland a
`hypr_paste` action shows an error and does not copy.

### Example

```yaml
addons:
  clipboard:
    enabled: true
    trigger: "cb"
    action: hypr_paste
    secondary_action: copy
```

## System Commands

Lists lock, suspend, hibernate, log out, reboot and shut down. See
[System Commands](../../features/system-commands/) for usage.

### Configuration

**`addons.system.enabled`** `boolean` (default: `true`)

**`addons.system.trigger`** `string` (default: `sys`)

Keyword that opens the list. Type it followed by a space. Web searches with
the same keyword take precedence.

**`addons.system.commands`** `object`

Replaces built-in commands. Keys are `lock`, `suspend`, `hibernate`, `logout`,
`reboot` and `shutdown`; values are argument lists run without a shell. An
empty list hides the entry.

**`addons.system.hide`** `list` (default: `[]`)

Entries to leave out, using the same names as `commands`.

### Example

```yaml
addons:
  system:
    trigger: "power"
    commands:
      lock: ["hyprlock"]
    hide: [hibernate]
```

## Window Switcher

Lists the open windows on Hyprland, niri or sway and focuses the one you
pick. See [Window Switcher](../../features/window-switcher/) for usage.

### Configuration

**`addons.windows.enabled`** `boolean` (default: `true`)

**`addons.windows.trigger`** `string` (default: `win`)

Keyword that opens the list. Type it followed by a space. Web searches with
the same keyword take precedence.

### Example

```yaml
addons:
  windows:
    trigger: "w"
```

## Browser Tabs

Lists the tabs of your browsers through the Vicinae browser extension, and
switches to or closes the one you pick. See
[Browser Tabs](../../features/browser-tabs/) for setup and usage.

### Configuration

**`addons.browser_tabs.enabled`** `boolean` (default: `true`)

**`addons.browser_tabs.trigger`** `string` (default: `tabs`)

Keyword that opens the list. Type it followed by a space. Web searches with
the same keyword take precedence.

**`addons.browser_tabs.favicon_service`** `twenty | google | none` (default: `twenty`)

Where to download site icons the browser has not stored itself. `twenty` uses
twenty-icons.com and `google` uses Google's favicon service, so the domains
of your open tabs are sent to that service. `none` keeps Raffi offline: it
uses only the icons found in the browser profiles, and the page preview of
the selected tab is not fetched from the site either.

### Example

```yaml
addons:
  browser_tabs:
    trigger: "t"
    favicon_service: none
```

## Media Controls

Plays, pauses, skips or stops the running media players through `playerctl`.
See [Media Controls](../../features/media-controls/) for usage.

### Configuration

**`addons.media.enabled`** `boolean` (default: `true`)

**`addons.media.trigger`** `string` (default: `media`)

Keyword that opens the controls. Type it followed by a space. Web searches
with the same keyword take precedence.

**`addons.media.close_on_action`** `boolean` (default: `false`)

Close Raffi after an action. By default Raffi stays open and refreshes the
list, so you can press Next several times in a row.

### Example

```yaml
addons:
  media:
    trigger: "mu"
    close_on_action: true
```

## Audio Switcher

Changes the volume, sets the default output or input and mutes devices
through `pactl`. See [Audio Switcher](../../features/audio-switcher/) for usage.

### Configuration

**`addons.audio.enabled`** `boolean` (default: `true`)

**`addons.audio.trigger`** `string` (default: `audio`)

Keyword that opens the device list. Type it followed by a space. Web searches
with the same keyword take precedence.

**`addons.audio.close_on_action`** `boolean` (default: `false`)

Close Raffi after an action. By default Raffi stays open and refreshes the
list.

**`addons.audio.volume_step`** `integer` (default: `5`)

Percent "Volume up" and "Volume down" change the output volume by. At least 1.

**`addons.audio.max_volume`** `integer` (default: `100`)

Highest output volume "Volume up" and a typed volume such as `vol 40` will
set. Raise it above 100 to allow boosting.

### Example

```yaml
addons:
  audio:
    trigger: "snd"
    close_on_action: true
    volume_step: 10
```

## Installed Apps

Lists the applications installed on the system next to your launchers.
See [Installed Apps](../../features/installed-apps/) for usage.

### Configuration

**`addons.apps.enabled`** `boolean` (default: `false`)

Add the `.desktop` applications to the launcher list. When no launcher is
configured at all, the apps are listed whatever this is set to.

**`addons.apps.actions`** `boolean` (default: `true`)

Also list each app's desktop actions, such as "Firefox: New Private Window".

### Example

```yaml
addons:
  apps:
    enabled: true
    actions: false
```

## Run in Terminal

Runs a typed command in a terminal window, or in a new tab of a running
kitty or WezTerm.
See [Run in Terminal](../../features/terminal/) for usage.

### Configuration

**`addons.terminal.enabled`** `boolean` (default: `true`)

**`addons.terminal.trigger`** `string` (default: `>`)

Keyword that starts a command. Type it followed by a space, then the command.

**`addons.terminal.command`** `list of strings` (default: found automatically)

Terminal command line the shell command is appended to, such as
`[alacritty, -e]` or `[wezterm, start, --]`. When unset, Raffi uses
`xdg-terminal-exec`, then `$TERMINAL`, then the first of kitty, foot,
alacritty, wezterm, ghostty, konsole, gnome-terminal, xfce4-terminal and
xterm that is installed. The same terminal opens desktop apps marked
`Terminal=true`.

**`addons.terminal.hold`** `boolean` (default: `true`)

Keep the window open after the command exits, showing its exit status, until
Enter is pressed.

**`addons.terminal.open_in`** `tab | window` (default: `tab`)

`tab` opens the command in a new tab of the running kitty or WezTerm, when
that is the terminal used, and falls back to a new window when none is
running. `window` always opens a new window. Desktop apps marked
`Terminal=true` always open a window.
See [Tabs in kitty and WezTerm](../../features/terminal/#tabs-in-kitty-and-wezterm).

**`addons.terminal.kitty_socket`** `string` (default: `listen_on` from `kitty.conf`)

kitty remote control address, written as for kitty's `listen_on`, such as
`unix:${XDG_RUNTIME_DIR}/kitty`. kitty adds its process id to the address,
unless it contains `{kitty_pid}`, and Raffi picks the newest of your kitty
processes listening there. Only Unix sockets are used; a `tcp:` address
opens a window.

### Example

```yaml
addons:
  terminal:
    trigger: "!"
    command: [foot]
    hold: false
    open_in: window
```

## Kill Process

Stops your own processes with `kill`.
See [Kill Process](../../features/kill-process/) for usage.

### Configuration

**`addons.kill.enabled`** `boolean` (default: `true`)

**`addons.kill.trigger`** `string` (default: `kill`)

Keyword that opens the process list. Type it followed by a space. Web searches
with the same keyword take precedence.

### Example

```yaml
addons:
  kill:
    trigger: "pk"
```

## Bluetooth

Turns Bluetooth on and off and connects paired devices with `bluetoothctl`.
See [Bluetooth](../../features/bluetooth/) for usage.

### Configuration

**`addons.bluetooth.enabled`** `boolean` (default: `true`)

**`addons.bluetooth.trigger`** `string` (default: `bt`)

Keyword that opens the Bluetooth list. Type it followed by a space. Web
searches with the same keyword take precedence.

**`addons.bluetooth.close_on_action`** `boolean` (default: `false`)

Close Raffi after an action. By default Raffi stays open and refreshes the
list.

### Example

```yaml
addons:
  bluetooth:
    trigger: "blue"
    close_on_action: true
```

## Password Store

Copies or types passwords from [pass](https://www.passwordstore.org/).
See [Password Store](../../features/password-store/) for usage.

### Configuration

**`addons.pass.enabled`** `boolean` (default: `true`)

**`addons.pass.trigger`** `string` (default: `pass`)

Keyword that opens the entry list. Type it followed by a space. Web
searches with the same keyword take precedence.

**`addons.pass.store_dir`** `string` (default: `$PASSWORD_STORE_DIR`, else `~/.password-store`)

Password store directory. `~` is expanded.

**`addons.pass.pinentry`** `raffi` | `agent` (default: `raffi`)

Who asks for the GPG passphrase when gpg-agent doesn't have it cached:
Raffi's own masked prompt, or gpg-agent's pinentry after Raffi closes. Use
`agent` for smartcards and YubiKeys, or when loopback pinentry is disabled.

**`addons.pass.username_fields`** `string[]` (default: `[login, user, username]`)

`key: value` lines read as the username, tried in this order: the first
field found in the entry wins, wherever its line sits. Without one, the
entry's file name is used.

**`addons.pass.clipboard_timeout`** `integer` (default: `45`)

Seconds before a copied secret is cleared from the clipboard. `0` never
clears it.

**`addons.pass.type_delay_ms`** `integer` (default: `200`)

Milliseconds to wait after Raffi closes before typing, so the previous
window has the focus back.

### Example

```yaml
addons:
  pass:
    store_dir: ~/work/password-store
    pinentry: agent
    clipboard_timeout: 20
```

## Bitwarden

Copies or types passwords from a Bitwarden vault with
[rbw](https://github.com/doy/rbw). The vault lock timeout is set in rbw
(`rbw config set lock_timeout`), not here.
See [Bitwarden](../../features/bitwarden/) for usage.

### Configuration

**`addons.bitwarden.enabled`** `boolean` (default: `true`)

**`addons.bitwarden.trigger`** `string` (default: `bw`)

Keyword that opens the vault list. Type it followed by a space. Web
searches with the same keyword take precedence.

**`addons.bitwarden.clipboard_timeout`** `integer` (default: `45`)

Seconds before a copied secret is cleared from the clipboard. `0` never
clears it.

**`addons.bitwarden.type_delay_ms`** `integer` (default: `200`)

Milliseconds to wait after Raffi closes before typing.

### Example

```yaml
addons:
  bitwarden:
    trigger: vault
    clipboard_timeout: 20
```

## Slack

Opens Slack conversations and people, searches messages, lists unread
conversations, and sets your status, presence and notification snooze, in
one workspace. Native UI only, off by default.
See [Slack](../../features/slack/) for usage and for getting a token.

### Configuration

**`addons.slack.enabled`** `boolean` (default: `false`)

**`addons.slack.trigger`** `string` (default: `slack`)

Keyword that opens the Slack list. Type it followed by a space.

**`addons.slack.token_command`** `string`

Shell command printing the Slack token on its first line: a user token
(`xoxp-`) from your own Slack app, or the session token (`xoxc-`) of a
logged-in browser. Run when the Slack list first opens. Required.

**`addons.slack.cookie_command`** `string`

Shell command printing the value of the browser's `d` cookie. Required
with a session (`xoxc-`) token, ignored with a user token.

**`addons.slack.open_in`** `"desktop" | "browser"` (default: `desktop`)

Where Enter opens conversations and messages: the Slack desktop app
(`slack://` links) or `app.slack.com`. Ctrl+Enter uses the other one.

**`addons.slack.unread_conversations`** `string[]` (default: `[]`)

Conversations checked by `slack unread` when Slack does not say which
conversations have unread messages, as with user tokens: `#channel`,
`@handle` for the direct conversation, or a conversation id. At most 30.

### Example

```yaml
addons:
  slack:
    enabled: true
    token_command: "pass show slack/token"
    cookie_command: "pass show slack/cookie"
    open_in: browser
    unread_conversations: ["#ops", "@alice"]
```

## Developer Tools

Lists base64, URL, hash, epoch, JSON and case transforms of the text typed
after `dev `, and generates UUIDs (`uuid`) and passwords (`pw`, `pw 32`) inline.
See [Developer Tools](../../features/developer-tools/) for usage.

### Configuration

**`addons.devtools.enabled`** `boolean` (default: `true`)

Turns off both the transform list and the generators.

**`addons.devtools.trigger`** `string` (default: `dev`)

Keyword that opens the transform list. Type it followed by a space. Web
searches with the same keyword take precedence.

**`addons.devtools.password_length`** `integer` (default: `20`)

Length of passwords generated by `pw` without a length, from 8 to 128.

### Example

```yaml
addons:
  devtools:
    trigger: "tx"
    password_length: 32
```

## Complete Addon Example

```yaml
addons:
  currency:
    enabled: true
    trigger: "$"
    default_currency: USD
    currencies: ["USD", "EUR", "GBP", "JPY"]

  calculator:
    enabled: true

  units:
    enabled: true

  color:
    enabled: true

  world_clock:
    enabled: true

  devtools:
    enabled: true
    trigger: "dev"
    password_length: 20

  windows:
    enabled: true
    trigger: "win"

  browser_tabs:
    enabled: true
    trigger: "tabs"
    favicon_service: twenty

  media:
    enabled: true
    trigger: "media"
    close_on_action: false

  audio:
    enabled: true
    trigger: "audio"
    close_on_action: false

  kill:
    enabled: true
    trigger: "kill"

  bluetooth:
    enabled: true
    trigger: "bt"
    close_on_action: false

  file_browser:
    enabled: true
    show_hidden: false

  script_filters:
    - name: "Timezones"
      keyword: "tz"
      command: "batz"
      args: ["-j"]
      icon: "clock"
      min_query_length: 2
      env:
        TZ_FORMAT: "short"

    - name: "Bookmarks"
      keyword: "bm"
      command: "my-bookmark-script"
      args: ["-j"]
      action: "copy"
      secondary_action: "xdg-open {value}"
      icon: "bookmark"

  web_searches:
    - name: "Google"
      keyword: "g"
      url: "https://google.com/search?q={query}"
      icon: "google"

    - name: "GitHub"
      keyword: "gh"
      url: "https://github.com/search?q={query}&type=repositories"
      icon: "github"

  text_snippets:
    - name: "Emails"
      keyword: "em"
      icon: "mail"
      action: "insert"
      secondary_action: "copy"
      snippets:
        - name: "Personal Email"
          value: "user@example.com"
        - name: "Work Email"
          value: "user@company.com"

    - name: "Templates"
      keyword: "tpl"
      icon: "document"
      file: "~/.config/raffi/snippets.yaml"
```