[38;5;244m┌─[0m [38;5;40mroot@joaocosta:~#[0m [38;5;245mcat posts/16.md[0m [38;5;244m───────────────────────────────────────────[0m

[38;5;40m#[0m [1mAI command generation in the fish shell[0m
[38;5;245mpublished 2025-05-28 · 2 min read · https://joaocosta.dev/blog/16[0m

I want to share a cool little fish function that I started using to
suggest/improve the commands I'm writting.

[38;5;38m##[0m [1mWhy not just use github copilot cli[0m

So, I tried using [38;5;40mGithub's copilot cli[0m
[38;5;244m(https://docs.github.com/en/copilot/using-github-copilot/using-github-copilot-in-the-command-line)[0m,
but it just felt slow/cumbersome. Even when using aliases, it just broke my
workflow.

[38;5;244m┄──────────────────────────────────────────────────────────────────────── bash [0m
[38;5;245m│[0m alias cop="gh copilot suggest -t shell"
[38;5;245m│[0m alias copg="gh copilot suggest -t git"
[38;5;245m│[0m alias cope="gh copilot explain"
[38;5;244m┄──────────────────────────────────────────────────────────────────────────────[0m

[38;5;38m##[0m [1mWhat I came up with[0m

A friend at work complained that VSCode started annoying him with copilot stuff
in the terminal, so I went to check it out. Basically, Microsoft started showing
a prompt to open copilot in Code's terminal with a ctrl+i keybind. This gave me
the idea to do something similar.

In [38;5;40mfish[0m [38;5;244m(https://fishshell.com/)[0m we have access to a [38;5;38mcommandline[0m built-in that
allows manipulating the content of the prompt. I already used, for example, to
prepend [38;5;38msudo[0m to a command when I forget it:

[38;5;244m┄──────────────────────────────────────────────────────────────────────── fish [0m
[38;5;245m│[0m # pipe bindings
[38;5;245m│[0m # append | less and execute
[38;5;245m│[0m bind \el -M insert 'commandline -a "| less" && commandline -f execute'
[38;5;245m│[0m # prefix yes | and execute
[38;5;245m│[0m bind \ey -M insert 'commandline -C 0 && commandline -i "yes | " && commandline -f execute'
[38;5;245m│[0m # prefix sudo
[38;5;245m│[0m bind \es -M insert 'commandline -C 0 && commandline -i "sudo "'
[38;5;244m┄──────────────────────────────────────────────────────────────────────────────[0m

So I wrote this function. This gets the current content of the command line,
generates an AI based suggestion, and replaces it with the result:

[38;5;244m┄──────────────────────────────────────────────────────────────────────── fish [0m
[38;5;245m│[0m function ai_cmd_suggest
[38;5;245m│[0m     set -l base_prompt
[38;5;245m│[0m     if test (count $argv) -ge 1
[38;5;245m│[0m         set base_prompt "$argv[1]"
[38;5;245m│[0m     else
[38;5;245m│[0m         return 1
[38;5;245m│[0m     end
[38;5;245m│[0m 
[38;5;245m│[0m     set -l current_content (commandline)
[38;5;245m│[0m 
[38;5;245m│[0m     set -l prompt "Only provide a single fish shell command as your response. Do not include any explanations, markdown formatting (like ```), or extra text. $base_prompt\n```fish\n$current_content\n```"
[38;5;245m│[0m     set -l new_cmd (echo "$prompt" | ask | string trim)
[38;5;245m│[0m 
[38;5;245m│[0m     # Replace the current commandline content with the AI's suggestion
[38;5;245m│[0m     set -l cmd_line "# $current_content
[38;5;245m│[0m $new_cmd"
[38;5;245m│[0m     commandline "$cmd_line"
[38;5;245m│[0m     commandline --cursor (string length "$cmd_line") # Move cursor to end
[38;5;245m│[0m end
[38;5;244m┄──────────────────────────────────────────────────────────────────────────────[0m

The [38;5;38mask[0m command is just an alias/script that I use to wrap-around [38;5;40msimonw's llm
tool[0m [38;5;244m(https://llm.datasette.io/en/stable/)[0m. I use it to interact with Google's
Gemini models:

[38;5;244m┄──────────────────────────────────────────────────────────────────────── bash [0m
[38;5;245m│[0m #!/bin/sh
[38;5;245m│[0m 
[38;5;245m│[0m cat | llm -m 'gemini-2.0-flash' "$@"
[38;5;244m┄──────────────────────────────────────────────────────────────────────────────[0m

[38;5;135m###[0m [1mHow to use it[0m

I set 2 keybindings for the script. These keybindings contain the actual prompt.

[38;5;244m┄──────────────────────────────────────────────────────────────────────── fish [0m
[38;5;245m│[0m bind \ei -M insert 'ai_cmd_suggest "Suggest a command for the following description:"'
[38;5;245m│[0m bind \eI -M insert 'ai_cmd_suggest "Improve and/or fix the following command:"'
[38;5;244m┄──────────────────────────────────────────────────────────────────────────────[0m

With this, I can:

[38;5;40m→[0m Write the description for a command and then press [38;5;38malt+i[0m to replace it with a
  command.
[38;5;40m→[0m Write a command and then press [38;5;38malt+I[0m to replace it with a fixed/improved
  version of the original.

[38;5;38m##[0m [1mConclusion[0m

This has been working pretty well and seems to be faster than Github's copilot
tool. Although the processing is pretty fast, a loading spinner would be cool,
but for now this is good enough. Stay safe :P

[38;5;244m└─[0m [38;5;40m→[0m view online: [38;5;40mhttps://joaocosta.dev/blog/16[0m
