Skip to main content

An expressive command-line utility and provider-agnostic library for LLMs.

Project description

Overview

q is an expressive command-line utility and provider-agnostic library for LLMs.

I built q as a personal utility script before the emergence of agentic coding tools like Claude Code. It has since been optimized for its particular niche: quick terminal interaction, shell script integration, and multi-model experimentation.

Installation

Install using any pip-compatible package manager (e.g. pip, pipx, uv, etc.).

pipx install q-bot

Requires Python 3.12+.

Command-Line Usage

q follows the Unix philosophy of composable, single-purpose utilities.

Every character from a to z maps to a command or option. A command performs a specific LLM task, while an option modifies a command's behavior. Together, they can express a wide variety of LLM operations precisely and concisely.

Run q -h to see all commands and options.

Examples

Shell Command Generation and Execution

Use -s to generate shell commands and copy them to the clipboard. q automatically detects the operating system and shell to generate compatible commands.

$ q -s auto hide the dock # on macOS
defaults write com.apple.dock autohide -bool true; killall Dock

Use -x to automatically execute the generated command.

$ q -sx count number of commits
> git rev-list --count HEAD
95

With no prompt, -s re-runs the last shell command, reads the error, and fixes it.

$ git push
fatal: The current branch dev has no upstream branch.
$ q -sx
> git push --set-upstream origin dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.

[!IMPORTANT] This requires a small shell hook to expose your previous command to q. Run q -s for more instructions.

Code Generation

Use -c to generate idiomatic code snippets and copy them to the clipboard. The default language is set in the config.

$ q -c square all keys in a dict
squared_keys = {k**2: v for k, v in d.items()}

Use -l to specify the language, and -o to write the output to a file.

$ q -c binary search -l rust -o search.rs
Response saved to search.rs

Use -f to provide an input file as context.

$ q -c add docstrings to all functions -f lib.py -o lib_doc.py
Response saved to lib_doc.py

Image Generation

Use -i to generate an image.

$ q -i a cat in space
Image saved to q_a_cat_in_space.png

Web Search

Use -w to search the web for real-time information with source attribution.

$ q -w nba champions
The New York Knicks are the 2026 NBA champions. (nba.com)

Explanation

Use -e to get an explanation of any command, snippet, or concept.

$ q -e 'find . -type d -name .git -exec dirname {} \; | sort'
This walks the current directory tree, finds every .git directory, strips the trailing /.git to yield the repository root path, and then sorts the results lexicographically.

Text Generation

Use -t to generate text without a system prompt.

$ q -t write a sentence with only words starting with q
Quick quails quietly quench quivering quagmires.

Meta Help

Use -h to ask q a question about itself. This is a great way to learn about its capabilities.

$ q -h is -- -k transient or persistent
-k is transient. It overrides the API key for a single command and is not saved to the .env file.

[!IMPORTANT] Each query consumes a large number of input tokens because it sends q's source code as context.

Sessions

Each terminal or script that runs q maintains an isolated session that persists multi-turn conversation history across calls. Sessions are automatically deleted when the parent shell process exits.

Invoking q without a command reuses the previous one in the session. Use -n to clear the session history for a new conversation or one-shot prompt. Use -z to undo previous exchanges.

Model Selection

q defines three capability tiers per provider: low, med, and high. Each maps to a comparable model and parameters on every provider, with lower tiers faster and cheaper, and higher tiers more capable. Tiers abstract away model and parameter selection, making it easy to switch providers or scale capability up and down.

Each command defines a default tier (viewable with q -hv), and the default provider is set in the config. Use -m to override the default model selection by tier, provider, or specific model name.

$ q -c quicksort -m high                        # override tier, use default provider
$ q -c quicksort -m anthropic                   # override provider, use default tier
$ q -c quicksort -m anthropic:high              # override both provider and tier
$ q -c quicksort -m anthropic:claude-opus-4-8   # override provider and specify model

Use -v to inspect the resolved provider, model, and parameters.

Configuration

q maintains persistent state and configuration files in ~/.q/:

  • ~/.q/.env - One API key per provider, prompted the first time each provider is called.
  • ~/.q/config.json - Default provider (openai) and code_lang (python), created automatically on first run.
  • ~/.q/sessions/ - One <pid>.json file per active session, deleted automatically when stale.

Use -k to override the default API key for a single invocation, useful for switching accounts or testing a key without persisting it.

Library Usage

The q library is built on two principles:

  • Clients are single-capability. Each client does one thing (e.g. text generation, image generation, web search, etc.) and has a static return type. No mode switching or tool selection logic is necessary.
  • Agents are provider- and capability-agnostic. Every agent accepts any client and inherits its return type, regardless of what the underlying client does or which provider it calls.

This leads to a simple, explicit architecture that requires little boilerplate to use or extend.

Clients

A client is a wrapper around a provider's API for one capability.

Clients extend Client[T] and are instantiated with an API key, model name, and optionally provider- and model-specific argument overrides. All clients expose a generate method which invokes the LLM, retries transient failures, and returns a value of type T.

Client[T](api_key: str, model: str, **model_args)
async Client[T].generate(messages: list[Message]) -> T

The following built-in clients are provided for each provider and capability:

Client T Description openai anthropic
TextClient str text generation
WebClient str web-grounded text generation
ImageClient bytes image generation

Dynamic Loading

Client classes are typically imported from their provider module, but can also be dynamically loaded at runtime by specifying a provider and client name using the load_client_class utility.

from q.providers import load_client_class

client_class = load_client_class('openai', 'ImageClient')
client = client_class(api_key, model, **model_args)

This is useful for building multi-provider systems or provider-agnostic tooling.

Agents

An agent is a wrapper around a client that manages messages and provides a consistent interface for prompting.

ChatAgent[T] is a conversational agent with persistent message history.

ChatAgent[T](client: Client[T], system: str | None = None, messages: list[Message] | None = None)
async ChatAgent[T].prompt(text: str) -> T
ChatAgent[T].drop_exchanges(n: int = 1) -> None

BatchAgent[T] processes multiple inputs in parallel without message history.

BatchAgent[T](client: Client[T], system: str | None = None)
async BatchAgent[T].batch_prompt(text_list: list[str], n_threads: int = 8) -> list[T]

Examples

Basic Usage

from pathlib import Path
from q.providers.openai import ImageClient
from q.agents import ChatAgent

client = ImageClient(api_key, "gpt-image-2", quality="high")
agent = ChatAgent(client)
image_bytes = await agent.prompt("a cat in space")
Path("cat.png").write_bytes(image_bytes)

Batch Processing

from q.providers.anthropic import TextClient
from q.agents import BatchAgent

client = TextClient(api_key, "claude-opus-4-8")
agent = BatchAgent(client, system="Identify the language of the text.")
inputs = ["How are you?", "¿Cómo estás?", "Comment ça va?"]
langs = await agent.batch_prompt(inputs)

Multi-Agent Orchestration

from q.providers import load_client_class
from q.agents import ChatAgent

client1 = load_client_class('openai', 'TextClient')(openai_key, "gpt-5.5")
client2 = load_client_class('anthropic', 'TextClient')(anthropic_key, "claude-opus-4-8")

system = "You are an AI speaking with another AI. Discuss the future of AI."
agent1 = ChatAgent(client1, system=system)
agent2 = ChatAgent(client2, system=system)

text = "What are your thoughts on the future of AI?"
for _ in range(5):
    text = await agent1.prompt(text)
    print("agent1:", text)
    text = await agent2.prompt(text)
    print("agent2:", text)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

q_bot-2.0.0.dev8.tar.gz (22.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

q_bot-2.0.0.dev8-py3-none-any.whl (22.2 kB view details)

Uploaded Python 3

File details

Details for the file q_bot-2.0.0.dev8.tar.gz.

File metadata

  • Download URL: q_bot-2.0.0.dev8.tar.gz
  • Upload date:
  • Size: 22.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for q_bot-2.0.0.dev8.tar.gz
Algorithm Hash digest
SHA256 9535933c69de1fd69bb1a36a4162f106170efc7d6f6e4ceb851fb0284add5fb9
MD5 836ca370735bba1a1d0f684d62f2c820
BLAKE2b-256 f10a336f67805265b98bab80586191ddc1fab715aaa10a2c44e2726bbd74cd21

See more details on using hashes here.

File details

Details for the file q_bot-2.0.0.dev8-py3-none-any.whl.

File metadata

  • Download URL: q_bot-2.0.0.dev8-py3-none-any.whl
  • Upload date:
  • Size: 22.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for q_bot-2.0.0.dev8-py3-none-any.whl
Algorithm Hash digest
SHA256 2d03dc2676135f2f1d5b81f751fe8c2e1b7013fa0910edb86a52dadbb464fcc6
MD5 c22df3492603d0832de74e7090eb28f1
BLAKE2b-256 37b60cd834750a395ef7254809fe1984fa046ba1fbafd79806b4e81417e779f8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page