yaak 0.1.3

Translate natural language to bash commands using an OpenAI-compatible LLM
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>yaak &mdash; documentation</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400;1,700&family=DM+Mono:wght@300;400;500&family=Source+Serif+4:ital,opsz,wght@0,8..60,300;0,8..60,400;0,8..60,600;1,8..60,300;1,8..60,400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<style>
  /* ============ HERO ============ */
  .page-hero {
    padding: 80px 32px 48px;
    border-bottom: 3px double var(--rule);
  }

  .page-hero-inner {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: end;
    gap: 32px;
  }

  .page-kicker {
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 3px;
    color: var(--red);
    margin-bottom: 16px;
    animation: fadeIn 0.5s ease both;
  }

  .page-title {
    font-family: 'Playfair Display', serif;
    font-weight: 900;
    font-size: clamp(40px, 7vw, 72px);
    line-height: 0.95;
    letter-spacing: -2px;
    animation: fadeIn 0.5s ease 0.05s both;
  }
  .page-title em { font-style: italic; font-weight: 400; color: var(--red); }

  .page-meta {
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    color: var(--ink-faint);
    text-align: right;
    letter-spacing: 0.5px;
    line-height: 1.8;
    animation: fadeIn 0.5s ease 0.1s both;
  }

  /* ============ DOCS LAYOUT ============ */
  .docs-layout {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: 48px;
    padding: 48px 32px 100px;
  }

  .toc {
    position: sticky;
    top: 32px;
    align-self: start;
    animation: fadeIn 0.5s ease 0.15s both;
  }

  .toc-label {
    font-family: 'DM Mono', monospace;
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 2.5px;
    color: var(--ink-faint);
    margin-bottom: 16px;
  }

  .toc-list {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0;
  }

  .toc-item a {
    display: block;
    padding: 10px 0;
    border-bottom: 1px solid var(--rule);
    text-decoration: none;
    font-family: 'DM Mono', monospace;
    font-size: 12px;
    color: var(--ink-dim);
    transition: color 0.2s;
  }
  .toc-item a:hover { color: var(--red); }
  .toc-item:first-child a { border-top: 1px solid var(--rule); }

  /* ============ CONTENT ============ */
  .docs-content {
    display: flex;
    flex-direction: column;
    gap: 0;
  }

  .doc-section {
    border-bottom: 1px solid var(--rule);
    padding: 40px 0;
    animation: fadeIn 0.5s ease both;
  }
  .doc-section:first-child { padding-top: 0; }

  .doc-section h2 {
    font-family: 'Playfair Display', serif;
    font-size: 28px;
    font-weight: 900;
    letter-spacing: -0.5px;
    margin-bottom: 20px;
  }
  .doc-section h2 em { font-style: italic; font-weight: 400; color: var(--red); }

  .doc-section h3 {
    font-family: 'Playfair Display', serif;
    font-size: 18px;
    font-weight: 700;
    margin-top: 28px;
    margin-bottom: 12px;
    letter-spacing: -0.3px;
  }

  .doc-section p {
    font-size: 15px;
    line-height: 1.7;
    color: var(--ink-light);
    font-weight: 300;
    max-width: 640px;
    margin-bottom: 16px;
  }

  .doc-section code {
    font-family: 'DM Mono', monospace;
    font-size: 13px;
    background: var(--code-bg);
    color: var(--code-green);
    padding: 2px 6px;
    border-radius: 3px;
  }

  .doc-code {
    font-family: 'DM Mono', monospace;
    font-size: 13px;
    background: var(--code-bg);
    color: var(--code-fg);
    padding: 18px 22px;
    border-radius: 6px;
    line-height: 1.8;
    overflow-x: auto;
    margin-bottom: 16px;
  }
  .doc-code .t-green { color: var(--code-green); }
  .doc-code .t-dim { color: #777; }
  .doc-code .t-amber { color: var(--code-amber); }

  .flag-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
    margin-bottom: 16px;
  }
  .flag-table th {
    font-family: 'DM Mono', monospace;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 2px;
    color: var(--ink-faint);
    text-align: left;
    padding: 10px 12px;
    border-bottom: 2px solid var(--rule);
  }
  .flag-table td {
    padding: 10px 12px;
    border-bottom: 1px solid rgba(209, 201, 192, 0.4);
    color: var(--ink-light);
    font-weight: 300;
    vertical-align: top;
  }
  .flag-table td:first-child {
    font-family: 'DM Mono', monospace;
    font-size: 13px;
    color: var(--ink);
    font-weight: 400;
    white-space: nowrap;
  }
  .flag-table td:nth-child(2) {
    font-family: 'DM Mono', monospace;
    font-size: 13px;
    color: var(--ink-dim);
  }

  /* Stagger sections */
  .doc-section:nth-child(1) { animation-delay: 0.15s; }
  .doc-section:nth-child(2) { animation-delay: 0.20s; }
  .doc-section:nth-child(3) { animation-delay: 0.25s; }
  .doc-section:nth-child(4) { animation-delay: 0.30s; }
  .doc-section:nth-child(5) { animation-delay: 0.35s; }
  .doc-section:nth-child(6) { animation-delay: 0.40s; }
  .doc-section:nth-child(7) { animation-delay: 0.45s; }
  .doc-section:nth-child(8) { animation-delay: 0.50s; }
  .doc-section:nth-child(9) { animation-delay: 0.55s; }

  /* ============ RESPONSIVE ============ */
  @media (max-width: 768px) {
    .docs-layout {
      grid-template-columns: 1fr;
      gap: 32px;
    }
    .toc { position: static; }
    .page-hero-inner { grid-template-columns: 1fr; }
    .page-meta { text-align: left; }
    .flag-table { font-size: 13px; }
  }
</style>
</head>
<body>

<!-- NAV -->
<nav>
  <a href="index.html" class="nav-brand">yaak</a>
  <button class="hamburger" id="hamburger" aria-label="Open menu" aria-expanded="false">
    <span></span><span></span><span></span>
  </button>
  <div class="nav-right">
    <a href="index.html">Home</a>
    <a href="docs.html" class="active">Docs</a>
    <a href="changelog.html">Changelog</a>
    <a href="https://github.com/hanneshapke/yaak" class="nav-gh">
      <svg width="14" height="14" fill="currentColor" viewBox="0 0 16 16"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
      Star on GitHub
    </a>
  </div>
</nav>

<!-- MOBILE MENU OVERLAY -->
<div class="mobile-menu" id="mobileMenu">
  <a href="index.html" class="mobile-menu-link">Home</a>
  <a href="docs.html" class="mobile-menu-link">Docs</a>
  <a href="changelog.html" class="mobile-menu-link">Changelog</a>
  <a href="https://github.com/hanneshapke/yaak" class="mobile-menu-link nav-gh">
    <svg width="14" height="14" fill="currentColor" viewBox="0 0 16 16"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
    Star on GitHub
  </a>
</div>

<!-- PAGE HERO -->
<section class="page-hero">
  <div class="container">
    <div class="page-hero-inner">
      <div>
        <div class="page-kicker">Reference</div>
        <h1 class="page-title">Docu<em>mentation</em></h1>
      </div>
      <div class="page-meta">
        CLI version: 0.0.12<br>
        License: Apache-2.0
      </div>
    </div>
  </div>
</section>

<!-- CONTENT -->
<div class="container">
  <div class="docs-layout">

    <!-- TOC -->
    <aside class="toc">
      <div class="toc-label">Sections</div>
      <ul class="toc-list">
        <li class="toc-item"><a href="#install">Installation</a></li>
        <li class="toc-item"><a href="#config">Configuration</a></li>
        <li class="toc-item"><a href="#usage">Usage</a></li>
        <li class="toc-item"><a href="#flags">All flags</a></li>
        <li class="toc-item"><a href="#language">Language</a></li>
        <li class="toc-item"><a href="#context">Context mode</a></li>
        <li class="toc-item"><a href="#cache">Cache mode</a></li>
        <li class="toc-item"><a href="#safety">Safety</a></li>
        <li class="toc-item"><a href="#providers">Providers</a></li>
        <li class="toc-item"><a href="#troubleshooting">Troubleshooting</a></li>
      </ul>
    </aside>

    <!-- DOCS -->
    <main class="docs-content">

      <!-- INSTALL -->
      <section class="doc-section" id="install">
        <h2>Install<em>ation</em></h2>
        <h3>Quick install (macOS / Linux)</h3>
        <div class="doc-code">
          <span class="t-green">$</span> curl -fsSL https://getyaak.ai/install.sh | bash
        </div>
        <p>Downloads the latest release binary, verifies the SHA256 checksum, and installs to <code>~/.local/bin</code>.</p>
        <p>Pin a specific version or change the install directory:</p>
        <div class="doc-code">
          <span class="t-green">$</span> YAAK_VERSION=v0.0.8 curl -fsSL https://getyaak.ai/install.sh | bash<br>
          <span class="t-green">$</span> YAAK_INSTALL_DIR=/usr/local/bin curl -fsSL https://getyaak.ai/install.sh | bash
        </div>
        <h3>Homebrew (macOS / Linux)</h3>
        <div class="doc-code">
          <span class="t-green">$</span> brew install hanneshapke/yaak/yaak
        </div>
        <h3>Cargo</h3>
        <div class="doc-code">
          <span class="t-green">$</span> cargo install yaak
        </div>
        <p>Prebuilt binaries are also available on the <a href="https://github.com/hanneshapke/yaak/releases">GitHub Releases</a> page for Linux (x86_64), macOS (x86_64, aarch64), and Windows (x86_64).</p>
      </section>

      <!-- CONFIG -->
      <section class="doc-section" id="config">
        <h2>Config<em>uration</em></h2>
        <p>yaak resolves settings in this priority order: <strong>CLI flags &rarr; environment variables &rarr; config file &rarr; defaults</strong>.</p>

        <h3>Interactive wizard</h3>
        <p>The fastest way to get started. Run <code>yaak --config</code> to pick a language, provider, model, and enter your API key.</p>
        <div class="doc-code">
          <span class="t-green">$</span> yaak --config
        </div>

        <h3>Config file</h3>
        <p>Stored at <code>~/.config/yaak/config.toml</code>. On macOS, <code>~/Library/Application Support/yaak/config.toml</code> is also checked.</p>
        <div class="doc-code">
          <span class="t-dim"># ~/.config/yaak/config.toml</span><br>
          api_base = <span class="t-green">"https://api.openai.com/v1"</span><br>
          api_key = <span class="t-green">"sk-..."</span><br>
          model = <span class="t-green">"gpt-4o-mini"</span><br>
          language = <span class="t-green">"en"</span> <span class="t-dim"># en, de, es, fr, pt, zh, ja, ko</span>
        </div>

        <h3>Environment variables</h3>
        <div class="doc-code">
          <span class="t-green">$</span> export YAAK_API_BASE="https://api.openai.com/v1"<br>
          <span class="t-green">$</span> export YAAK_API_KEY="sk-..."<br>
          <span class="t-green">$</span> export YAAK_MODEL="gpt-4o-mini"<br>
          <span class="t-green">$</span> export YAAK_LANGUAGE="en" <span class="t-dim"># optional: en, de, es, fr, pt, zh, ja, ko</span>
        </div>
      </section>

      <!-- USAGE -->
      <section class="doc-section" id="usage">
        <h2>Us<em>age</em></h2>
        <p>Describe what you want in plain English. yaak sends it to your LLM, shows you the generated command, and lets you execute, copy, or abort.</p>
        <div class="doc-code">
          <span class="t-green">$</span> yaak find all rust files modified this week<br>
          <span class="t-dim">Thinking ....</span><br>
          <span class="t-dim">  Command:</span> <span class="t-green">find . -name "*.rs" -mtime -7</span><br>
          <span class="t-amber">? What next?:</span> Execute / Refine / Copy / Abort
        </div>

        <h3>Reverse / Explain mode</h3>
        <p>Pass <code>--reverse</code> or <code>--explain</code> to get a detailed, token-by-token breakdown of any command.</p>
        <div class="doc-code">
          <span class="t-green">$</span> yaak --explain 'find . -name "*.log" -mtime +30 -delete'
        </div>

        <h3>Copy to clipboard</h3>
        <p>Use <code>--copy</code> to send the generated command straight to your clipboard without executing.</p>
        <div class="doc-code">
          <span class="t-green">$</span> yaak --copy compress all png files in this directory
        </div>

        <h3>Command history</h3>
        <p>yaak saves every generated command. Browse, search, or re-run from history.</p>
        <div class="doc-code">
          <span class="t-green">$</span> yaak --history <span class="t-dim"># show recent commands</span><br>
          <span class="t-green">$</span> yaak --last <span class="t-dim"># re-execute the last command</span><br>
          <span class="t-green">$</span> yaak --search "docker" <span class="t-dim"># search by keyword</span>
        </div>

        <h3>Shell completions</h3>
        <div class="doc-code">
          <span class="t-green">$</span> yaak --completions bash > ~/.bash_completion.d/yaak<br>
          <span class="t-green">$</span> yaak --completions zsh > ~/.zfunc/_yaak<br>
          <span class="t-green">$</span> yaak --completions fish > ~/.config/fish/completions/yaak.fish
        </div>
      </section>

      <!-- FLAGS -->
      <section class="doc-section" id="flags">
        <h2>All <em>flags</em></h2>
        <table class="flag-table">
          <thead>
            <tr><th>Flag</th><th>Short</th><th>Description</th></tr>
          </thead>
          <tbody>
            <tr><td><code>--config</code></td><td><code>-c</code></td><td>Interactive configuration wizard</td></tr>
            <tr><td><code>--api-base</code></td><td><code>-u</code></td><td>API base URL</td></tr>
            <tr><td><code>--api-key</code></td><td><code>-k</code></td><td>API key</td></tr>
            <tr><td><code>--model</code></td><td><code>-m</code></td><td>Model name</td></tr>
            <tr><td><code>--yes</code></td><td><code>-y</code></td><td>Skip confirmation prompt</td></tr>
            <tr><td><code>--reverse</code></td><td><code>-r</code></td><td>Explain a command instead of generating</td></tr>
            <tr><td><code>--explain</code></td><td><code>-e</code></td><td>Alias for --reverse</td></tr>
            <tr><td><code>--copy</code></td><td><code>-C</code></td><td>Copy generated command to clipboard</td></tr>
            <tr><td><code>--context</code></td><td></td><td>Include project type and file listing in prompt</td></tr>
            <tr><td><code>--cache</code></td><td></td><td>Reuse cached result (exact or BM25 fuzzy match)</td></tr>
            <tr><td><code>--no-cache</code></td><td></td><td>Force fresh API call, ignore cache</td></tr>
            <tr><td><code>--history</code></td><td><code>-H</code></td><td>Show recent command history</td></tr>
            <tr><td><code>--last</code></td><td><code>-l</code></td><td>Re-execute the most recent command</td></tr>
            <tr><td><code>--search</code></td><td><code>-s</code></td><td>Search command history by keyword</td></tr>
            <tr><td><code>--language</code></td><td><code>-L</code></td><td>UI language: en, de, es, fr, pt, zh, ja, ko</td></tr>
            <tr><td><code>--version</code></td><td><code>-v</code></td><td>Print version number</td></tr>
            <tr><td><code>--update</code></td><td><code>-U</code></td><td>Update yaak to the latest version</td></tr>
            <tr><td><code>--feedback</code></td><td></td><td>Open the feedback page in your browser</td></tr>
            <tr><td><code>--completions</code></td><td></td><td>Generate shell completions (bash/zsh/fish)</td></tr>
            <tr><td><code>--limit</code></td><td></td><td>Number of history entries to show (default: 20)</td></tr>
          </tbody>
        </table>
      </section>

      <!-- LANGUAGE -->
      <section class="doc-section" id="language">
        <h2>Multi-<em>language</em> support</h2>
        <p>yaak supports 8 languages for all UI elements &mdash; prompts, error messages, menus, and labels. The configuration wizard includes a language selection step, or you can set it directly.</p>

        <table class="flag-table">
          <thead>
            <tr><th>Code</th><th>Language</th></tr>
          </thead>
          <tbody>
            <tr><td><code>en</code></td><td>English</td></tr>
            <tr><td><code>de</code></td><td>Deutsch</td></tr>
            <tr><td><code>es</code></td><td>Espa&ntilde;ol</td></tr>
            <tr><td><code>fr</code></td><td>Fran&ccedil;ais</td></tr>
            <tr><td><code>pt</code></td><td>Portugu&ecirc;s</td></tr>
            <tr><td><code>zh</code></td><td>&#20013;&#25991; (Chinese)</td></tr>
            <tr><td><code>ja</code></td><td>&#26085;&#26412;&#35486; (Japanese)</td></tr>
            <tr><td><code>ko</code></td><td>&#54620;&#44397;&#50612; (Korean)</td></tr>
          </tbody>
        </table>

        <h3>Setting the language</h3>
        <p>Language is resolved in priority order: <strong>CLI flag &rarr; environment variable &rarr; config file &rarr; system locale &rarr; English</strong>.</p>
        <div class="doc-code">
          <span class="t-dim"># CLI flag</span><br>
          <span class="t-green">$</span> yaak -L de list files in current directory<br><br>
          <span class="t-dim"># Environment variable</span><br>
          <span class="t-green">$</span> export YAAK_LANGUAGE=fr<br><br>
          <span class="t-dim"># Config file (~/.config/yaak/config.toml)</span><br>
          language = <span class="t-green">"es"</span><br><br>
          <span class="t-dim"># Or select during setup</span><br>
          <span class="t-green">$</span> yaak --config
        </div>

        <h3>LLM explanations</h3>
        <p>When a non-English language is active, yaak also instructs the LLM to write explanations, summaries, and cautions in that language (used with <code>--explain</code> mode). The structured output format is preserved for correct parsing.</p>
      </section>

      <!-- CONTEXT -->
      <section class="doc-section" id="context">
        <h2>Context <em>mode</em></h2>
        <p>yaak always includes your current working directory in the system prompt. For richer context, pass <code>--context</code> to also include:</p>
        <p><strong>Project type detection</strong> &mdash; Cargo.toml, package.json, go.mod, Makefile, Dockerfile, and 15+ other markers.</p>
        <p><strong>Git branch</strong> &mdash; if you're in a git repository.</p>
        <p><strong>File listing</strong> &mdash; top-level non-hidden files (up to 30).</p>
        <div class="doc-code">
          <span class="t-dim"># Without --context: LLM guesses how to build</span><br>
          <span class="t-green">$</span> yaak build the project<br><br>
          <span class="t-dim"># With --context: LLM knows it's a Rust project</span><br>
          <span class="t-green">$</span> yaak --context build the project<br>
          <span class="t-dim">  Command:</span> <span class="t-green">cargo build --release</span>
        </div>
        <p>Context is opt-in to avoid leaking sensitive filenames to the LLM provider.</p>
      </section>

      <!-- CACHE -->
      <section class="doc-section" id="cache">
        <h2>Cache <em>mode</em></h2>
        <p>Every generated command is saved to <code>~/.config/yaak/cache.json</code>, keyed by model and description. Use <code>--cache</code> to skip the API call when a matching entry exists.</p>
        <p>yaak tries an <strong>exact match</strong> first. If none is found, it falls back to <strong>BM25 fuzzy matching</strong> — a term-frequency ranking algorithm that finds similar cached descriptions even when the wording differs. Stop words are stripped and terms are scored by relevance across all cached entries for the same model.</p>
        <div class="doc-code">
          <span class="t-dim"># First call hits the API</span><br>
          <span class="t-green">$</span> yaak list all docker containers<br><br>
          <span class="t-dim"># Exact match — returns instantly</span><br>
          <span class="t-green">$</span> yaak --cache list all docker containers<br>
          <span class="t-dim">(cached)</span><br>
          <span class="t-dim">  Command:</span> <span class="t-green">docker ps -a</span><br><br>
          <span class="t-dim"># Fuzzy match — similar wording also hits the cache</span><br>
          <span class="t-green">$</span> yaak --cache show docker containers<br>
          <span class="t-dim">(cached) (similar: "list all docker containers")</span><br>
          <span class="t-dim">  Command:</span> <span class="t-green">docker ps -a</span>
        </div>
        <p>Use <code>--no-cache</code> to force a fresh API call and skip saving the result.</p>
      </section>

      <!-- SAFETY -->
      <section class="doc-section" id="safety">
        <h2>Safe<em>ty</em></h2>
        <p>yaak blocks destructive commands before execution. The following patterns are detected and rejected, including <code>sudo</code> variants and piped/chained sequences:</p>
        <div class="doc-code">
          rm &nbsp;&bull;&nbsp; rmdir &nbsp;&bull;&nbsp; mkfs &nbsp;&bull;&nbsp; dd &nbsp;&bull;&nbsp; shred &nbsp;&bull;&nbsp; wipefs<br>
          > /dev/ &nbsp;&bull;&nbsp; chmod 000 &nbsp;&bull;&nbsp; :(){ :|:& };:
        </div>
        <p>If a destructive command is detected, yaak prints a warning and exits without executing.</p>
        <div class="doc-code">
          <span class="t-green">$</span> yaak delete all files in this directory<br>
          <span class="t-dim">  Command:</span> rm -rf ./*<br>
          <span style="color: var(--red-light);">blocked:</span> Destructive command blocked: `rm` is not allowed.
        </div>
      </section>

      <!-- PROVIDERS -->
      <section class="doc-section" id="providers">
        <h2>Compatible <em>providers</em></h2>
        <p>yaak auto-detects the provider from the API base URL and uses the appropriate request format.</p>

        <h3>Anthropic (native Messages API)</h3>
        <p>Detected when the API base contains <code>anthropic.com</code>. Uses the Messages API with streaming.</p>
        <div class="doc-code">
          <span class="t-green">$</span> yaak -u https://api.anthropic.com/v1 -k sk-ant-... find large log files
        </div>

        <h3>Google Gemini (native Gemini API)</h3>
        <p>Detected when the API base contains <code>generativelanguage.googleapis.com</code>. Uses the Gemini streaming API with SSE.</p>
        <div class="doc-code">
          <span class="t-green">$</span> yaak -u https://generativelanguage.googleapis.com/v1beta -k AIza... find large log files
        </div>

        <h3>OpenAI-compatible</h3>
        <p>All other providers use the <code>/v1/chat/completions</code> endpoint with streaming.</p>
        <table class="flag-table">
          <thead>
            <tr><th>Provider</th><th>API base</th><th>Key required</th></tr>
          </thead>
          <tbody>
            <tr><td>OpenAI</td><td><code>https://api.openai.com/v1</code></td><td>Yes</td></tr>
            <tr><td>Ollama</td><td><code>http://localhost:11434/v1</code></td><td>No</td></tr>
            <tr><td>Groq</td><td><code>https://api.groq.com/openai/v1</code></td><td>Yes</td></tr>
            <tr><td>Together AI</td><td><code>https://api.together.xyz/v1</code></td><td>Yes</td></tr>
            <tr><td>OpenRouter</td><td><code>https://openrouter.ai/api/v1</code></td><td>Yes</td></tr>
            <tr><td>Doubleword</td><td><code>https://api.doubleword.ai/v1</code></td><td>Yes</td></tr>
            <tr><td>LM Studio</td><td><code>http://localhost:1234/v1</code></td><td>No</td></tr>
            <tr><td>vLLM</td><td><code>http://localhost:8000/v1</code></td><td>No</td></tr>
            <tr><td>LocalAI</td><td><code>http://localhost:8080/v1</code></td><td>No</td></tr>
          </tbody>
        </table>
      </section>

      <!-- TROUBLESHOOTING -->
      <section class="doc-section" id="troubleshooting">
        <h2>Trouble<em>shooting</em></h2>

        <h3>zsh: no matches found: it?</h3>
        <p>zsh treats <code>?</code>, <code>*</code>, and other characters as glob wildcards. When you type <code>yaak what time is it?</code>, zsh tries to expand <code>it?</code> as a file pattern and fails.</p>
        <p><strong>Quick fix</strong> — quote your description:</p>
        <div class="doc-code">
          <span class="t-green">$</span> yaak "what time is it?"
        </div>
        <p><strong>Permanent fix</strong> — add a <code>noglob</code> alias to your <code>~/.zshrc</code>:</p>
        <div class="doc-code">
          <span class="t-green">$</span> echo 'alias yaak="noglob yaak"' >> ~/.zshrc<br>
          <span class="t-green">$</span> source ~/.zshrc
        </div>
        <p>The <code>noglob</code> prefix tells zsh to skip glob expansion for yaak, so <code>?</code>, <code>*</code>, and other special characters just work without quoting.</p>

        <h3>bash: similar issues</h3>
        <p>bash does not expand <code>?</code> if no matching files exist, so this is usually only a problem in zsh. If you do hit issues in bash, quote your description the same way.</p>
      </section>

    </main>
  </div>
</div>

<!-- FOOTER -->
<footer>
  <span>yaak &mdash; open source, Apache-2.0 licensed</span>
  <span>Built with Rust &amp; <a href="#">your favorite LLM</a></span>
</footer>

<script>
// Hamburger menu toggle
const hamburger = document.getElementById('hamburger');
const mobileMenu = document.getElementById('mobileMenu');

hamburger.addEventListener('click', () => {
  const isOpen = mobileMenu.classList.toggle('open');
  hamburger.classList.toggle('active');
  hamburger.setAttribute('aria-expanded', isOpen);
  document.body.style.overflow = isOpen ? 'hidden' : '';
});

mobileMenu.querySelectorAll('.mobile-menu-link').forEach(link => {
  link.addEventListener('click', () => {
    mobileMenu.classList.remove('open');
    hamburger.classList.remove('active');
    hamburger.setAttribute('aria-expanded', 'false');
    document.body.style.overflow = '';
  });
});
</script>

</body>
</html>