Skip to content

devlog/api-plumbing/a-tiny-ai-cli-for-your-terminal-and-editor-91.md

A Tiny AI CLI for Your Terminal and Editor

Turn a terminal prompt into an API request

I want a small command that accepts a prompt, reads piped input, and prints an answer. No conversation database or terminal interface: just something I can call while reviewing a diff or debugging a failing test.

We will build that wrapper with Python and the OpenAI SDK. Fluxo supplies one key and one base URL, https://api.fluxorelay.com, across providers. Claude Sonnet 5.5 and DeepSeek V4 Flash are two concrete options; we will discover their API identifiers instead of guessing them.

If you want to follow along using the same service, create a Fluxo account and generate an API key.

Create an isolated Python workspace

These commands assume Bash, Python 3.9 or newer, and an empty working directory. Keep this shell open because subsequent commands use its virtual environment and exported variables.

mkdir fluxo-cli && cd fluxo-cli — python3 -m venv .venv

source .venv/bin/activate — python -m pip install openai

Read the key without displaying it or embedding it in shell history. The SDK expects the OpenAI-compatible API prefix, so the configured URL adds /v1 to Fluxo's base URL.

read -r -s -p 'Fluxo API key: ' OPENAI_API_KEY; printf '\n'; export OPENAI_API_KEY

export OPENAI_BASE_URL='https://api.fluxorelay.com/v1'

These exports last for this shell session. Avoid putting the key into the script, a committed environment file, or a command you might paste into an issue.

Write the wrapper with one shell command

The following command writes fluxo.py. Each quoted argument becomes one source line, including the indentation. Using printf keeps the command copyable without depending on Markdown code blocks.

printf '%s\n' 'import argparse' 'import os' 'import sys' 'from openai import OpenAI, OpenAIError' '' 'parser = argparse.ArgumentParser(description="Send a prompt and optional stdin to Fluxo.")' 'parser.add_argument("prompt", nargs="* من".replace(" من", ""))' 'parser.add_argument("--model", default=os.getenv("FLUXO_MODEL"))' 'parser.add_argument("--list-models", action="store_true")' 'args = parser.parse_args()' 'if not os.getenv("OPENAI_API_KEY"):' ' parser.error("Set OPENAI_API_KEY first.")' 'client = OpenAI(timeout=60.0, max_retries=0)' 'try:' ' if args.list_models:' ' for model in client.models.list():' ' print(model.id)' ' sys.exit(0)' ' if not args.model:' ' parser.error("Set FLUXO_MODEL or pass --model.")' ' prompt = " ".join(args.prompt)' ' data = sys.stdin.read() if not sys.stdin.isatty() else ""' ' content = "\n\n".join(part for part in (prompt, data) if part.strip())' ' if not content:' ' parser.error("Provide a prompt or pipe input.")' ' response = client.chat.completions.create(model=args.model, messages=[{"role": "user", "content": content}])' ' print(response.choices[0].message.content or "")' 'except OpenAIError as error:' ' print(f"Fluxo request failed: {error}", file=sys.stderr)' ' sys.exit(1)' > fluxo.py

The wrapper reads redirected input only when stdin is not a terminal. That prevents an ordinary prompt from hanging while waiting for keyboard input. Errors go to stderr with a nonzero exit status, so shell scripts can detect failures.

Discover a model ID and send a prompt

Ask the endpoint for its model identifiers: — python fluxo.py --list-models

Copy the exact identifier corresponding to your chosen model, then enter it at this prompt. Display names and API identifiers can differ.

read -r -p 'Model ID from the list: ' FLUXO_MODEL; export FLUXO_MODEL

python fluxo.py 'Explain Python context managers in three sentences.'

Use --model followed by another returned identifier to switch models for one request. The environment variable remains your default.

Pipe a Git diff into a review request

From this repository, stage a change and run:

git diff --cached | python fluxo.py 'Review this diff for correctness. Cite the affected functions and explain any likely bugs.'

For a saved traceback, redirect a file instead:

python fluxo.py 'Explain this failure and suggest the smallest fix.' < traceback.txt

Check the input before sending it: a diff or traceback can contain credentials. Also keep inputs bounded; this wrapper sends the entire stream in one request and does not manage context limits.

Keep the wrapper small and predictable

Requests use a 60-second timeout and disable automatic retries, making repeated attempts an explicit decision. Output is plain text, ready for redirection into a scratch file or an editor buffer.

Fluxo bills real tokens, including cache reads and writes, without a monthly fee. The same service also works with Claude Code, Codex, and Gemini CLI. Inviting another developer can earn you a referral share when they pay. If setup fails and you need help, leave a note on the contact page after signing in.

Next in the buffer

Sign up in a minute and get credit to try every model mentioned here. Sign up →