askcii
Talk to an LLM from your shell — the Unix way.
askcii is a filter, not an application. It reads standard input, writes standard
output, reports errors on standard error, and returns meaningful exit codes. It
streams, it pipes, it scripts. It does not take over your terminal.
askcii 'explain the difference between fork and exec'
git diff --staged | askcii 'write a conventional commit message'
cat error.log | askcii --json 'summarize the failures' | jq -r .contentSupports Anthropic, OpenAI, Gemini, DeepSeek, Mistral, Perplexity, xAI, OpenRouter, and Ollama.
Install
gem install askciiThen create a profile:
askcii config add work --provider anthropic --model claude-sonnet-5 \
--key-env ANTHROPIC_API_KEY --defaultOr run askcii config add work with no flags to be prompted, or
askcii config edit to write the YAML by hand.
Why it composes
Most LLM CLIs are chat apps that happen to live in a terminal. askcii is built
to be a link in a pipeline:
-
Streams by default, with
$stdoutunbuffered, so| teeand| lessshow text as it arrives instead of in 4KB gulps. -
Dies quietly on
SIGPIPE.askcii '…' | head -5exits141with nothing on stderr, exactly likecatwould. -
Distinct exit codes, so
askcii … || handle $?can tell a typo from an outage. -
--jsoneverywhere, so you never have to parse a human-readable table. - Nothing interactive is required. Every command is scriptable; the prompts are a convenience, not the interface.
Usage
askcii [options] <prompt>... Ask a question (also reads stdin)
askcii <command> [options]
| Command | Purpose |
|---|---|
ask |
Ask a question (the default) |
config |
Manage provider profiles |
sessions |
Inspect and prune conversation history |
version |
Print the version |
Ask options
| Flag | Meaning |
|---|---|
-P, --profile NAME |
Use a named profile |
-m, --model MODEL |
Override the profile's model |
-s, --session NAME |
Continue a named conversation |
-p, --private |
Write nothing to disk |
-r, --last |
Print the last reply instead of asking |
--no-stream |
Buffer the reply, print it once complete |
--timeout SECS |
Abort the request after SECS seconds |
-j, --json |
Machine-readable output |
-v, --verbose |
Diagnostics on stderr |
Standard input
If stdin is not a terminal it is read and placed before the prompt, separated by a blank line — no wrapper prose is added. If you give no prompt argument, stdin becomes the prompt.
echo 'what is 2+2' | askcii # stdin is the prompt
git diff | askcii 'review this' # stdin is the context
askcii 'summarize' < report.txt # same thingSessions
Without --session, each run is a one-shot: no prior context is replayed, and
only the most recent exchange is kept so that -r still works. This is why your
history does not fill with thousands of single-use conversations.
askcii 'quick question' # one-shot, forgotten next time
askcii -r # still prints that reply
askcii -s refactor 'how should I split this module?'
askcii -s refactor 'show me the first step' # remembers
askcii -p 'nothing about this is recorded'Manage them:
askcii sessions list
askcii sessions show refactor
askcii sessions clear refactor
askcii sessions prune --older-than 30Configuration
Profiles live in $XDG_CONFIG_HOME/askcii/config.yml (default
~/.config/askcii/config.yml), created with mode 0600:
default_profile: work
profiles:
work:
provider: anthropic
model: claude-sonnet-5
api_key_env: ANTHROPIC_API_KEY
secure:
provider: openai
model: gpt-5.4
api_key_command: op read op://private/openai/key
local:
provider: ollama
model: llama3.2It is a plain file — edit it, template it, check it into your dotfiles.
askcii config list # '*' marks the default; shows where each key comes from
askcii config path
askcii config edit
askcii config default localAPI keys
Resolved in order, first match winning:
$ASKCII_API_KEY- the profile's
api_key_env(an environment variable name) - the profile's
api_key_command(a command whose stdout is the key) - the profile's
api_key(in the file — supported, discouraged) - the provider's conventional variable, e.g.
$ANTHROPIC_API_KEY
askcii config list reports which source each profile is using, so you can
confirm no key is sitting in the file:
* work anthropic/claude-sonnet-5 key: env:ANTHROPIC_API_KEY
local ollama/llama3.2 key: not required
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Usage error |
| 3 | Configuration error |
| 4 | Provider or network error |
| 130 | Interrupted |
| 141 | stdout closed early (e.g. piped to head) |
askcii 'question' || case $? in
2) echo 'I typed it wrong' ;;
3) echo 'not configured' ;;
4) echo 'provider is down, retrying later' ;;
esacRecipes
# Commit messages
git diff --staged | askcii -p 'write a conventional commit message' | git commit -F -
# Explain a failure, with the exit code preserved
some-command 2>&1 | askcii 'why did this fail?'
# Pull one field out
askcii --json 'name three shells' | jq -r .content
# Local model for anything sensitive
askcii -P local -p 'summarize' < confidential.txt
# Batch, without hammering one session
find . -name '*.rb' | while read -r f; do
askcii -p "one-line summary of $f" < "$f"
doneShell aliases:
alias explain='askcii -p "explain this command:"'
alias review='git diff | askcii "review this:"'Files
| Path | Contents |
|---|---|
$XDG_CONFIG_HOME/askcii/config.yml |
Profiles (mode 0600) |
$XDG_DATA_HOME/askcii/askcii.db |
History, SQLite (mode 0600) |
Override with $ASKCII_CONFIG and $ASKCII_DATABASE.
Shell completion and the manual
Completions for bash and zsh are in completions/; see the
README there. A man page ships as man/askcii.1:
man askciiUpgrading from 0.x
Version 1.0 reorganizes the CLI. Your data is migrated automatically the first time you run it — configurations move from SQLite into the YAML file, named after their old names.
| Before | Now |
|---|---|
askcii -c |
askcii config add (or config edit) |
askcii -m 2 |
askcii -P NAME — profiles have names; -m now means the model |
askcii --list-sessions |
askcii sessions list |
askcii --history |
askcii sessions show |
askcii --clear-history |
askcii sessions clear |
The old flags still work for now and print a deprecation notice. -p, -r, and
-v are unchanged.
Also fixed in 1.0: -p never worked (it crashed on every invocation), and user
prompts were never saved, so --session replayed only the assistant's half of
the conversation. Both are corrected — existing history is left as-is, so old
sessions will look one-sided.
Development
bin/setup
bundle exec rake test # 72 tests
bundle exec rake rubocop
bundle exec rake # both
bin/askcii 'test prompt'License
MIT