LLM llm

LLM utilities — chat, translation, image OCR, corpospeak rewriting, and session history
Pixelbadger Toolkit — pbtk llm — ← all topics

Prerequisites

Commands in this topic call an LLM provider, selected with --provider. The provider is openai by default; claude is also supported. Each provider reads its own API key from the environment:

$ export OPENAI_API_KEY=sk-...
$ export ANTHROPIC_API_KEY=sk-ant-...

When --model is omitted, each command uses the provider's default model: gpt-6-luna for openai (gpt-image-1 for generate-image) and claude-sonnet-5-5 for claude. Pass --model to override.

Provider capabilities

Each command checks that the selected provider supports what it needs before any API key is read, input file is opened, history is accessed or network call is made. An unsupported combination prints an Error: message and exits with status 1.

CapabilityCommandsopenaiclaude
Text chatchat, translate, corpospeakYesYes
Image inputocaaar, paintYesYes
Image generationgenerate-imageYesNo
Tool callingpaintYesYes
--reasoning-effort valueschat, paintlow, medium, highlow, medium, high, xhigh, max

Session History

Every llm command automatically persists conversation history — including the system prompt — to a shared SQLite database at ~/.pbtk/history.db. Each invocation creates a new session and stores the full message exchange along with token usage counts.

Sessions are identified by an integer ID that is consistent across all commands, making it possible to inspect history from chat, translate, ocaaar, and corpospeak in a single unified view.

Use llm history list to see all sessions and llm history delete to remove one.

chat

Sends a message to the LLM chat completion API and prints the response. Every invocation is recorded as a session in the history database. Ongoing conversations are resumed by passing the session ID returned from a previous call.

$ pbtk llm chat --message "Hello, how are you?"
$ pbtk llm chat --message "Continue our conversation" --session-id 42 --model gpt-4o-mini
$ pbtk llm chat --message "Solve this hard problem" --reasoning-effort high
$ pbtk llm chat --message "Hello, how are you?" --provider claude
flowchart LR MSG["--message"] --> COMP["Send to\nLLM chat API"] SID["--session-id\n(optional)"] -->|"load prior\nmessages"| COMP RE["--reasoning-effort\n(optional)"] --> COMP PROV["--provider\n(default: openai)"] --> COMP COMP --> RESP(["stdout: assistant reply"]) COMP --> HIST["Session stored\nin ~/.pbtk/history.db"] COMP --> SID_OUT(["stderr: Session: <id>"])

When --session-id is omitted a new session is created. When provided, all prior messages from that session are loaded and prepended to the API request so the model has full context. The session ID is always written to stderr after the call — capture it to continue the conversation later.

Sessions created by other commands (e.g. translate) can be continued with chat --session-id since all commands share the same history database. History is provider-agnostic, so a session started with one --provider can be continued with the other.
OptionRequiredDefaultDescription
--messageYes—The user message to send
--session-idNo—Session ID to continue a previous conversation
--providerNoopenaiLLM provider: openai or claude
--modelNoProvider default (gpt-6-luna or claude-sonnet-5-5)Model to use
--reasoning-effortNo—Reasoning effort level. Values depend on the provider: openai accepts low, medium, high; claude accepts low, medium, high, xhigh, max

translate

Translates a given text into a specified target language using the LLM. The output is the translated text printed to stdout. Each invocation creates a new history session.

$ pbtk llm translate --text "Hello, how are you?" --target-language Spanish
$ pbtk llm translate --text "Hello" --target-language French --provider claude --model claude-haiku-5-5
flowchart LR T["--text"] --> CALL["LLM\nchat completion"] LANG["--target-language"] --> CALL PROV["--provider\n(default: openai)"] --> CALL CALL --> OUT(["stdout: translated text"]) CALL --> HIST["Session stored\nin ~/.pbtk/history.db"]
OptionRequiredDefaultDescription
--textYes—The text to translate
--target-languageYes—Target language (e.g. Spanish, French, Japanese)
--providerNoopenaiLLM provider: openai or claude
--modelNoProvider default (gpt-6-luna or claude-sonnet-5-5)Model to use

ocaaar

OCR as a Pirate. Sends an image file to the LLM vision API, extracts any text found in the image, and returns it rewritten in pirate speak. Each invocation creates a new history session; the image is recorded as a reference path rather than binary data.

$ pbtk llm ocaaar --image-path ./sign.jpg
flowchart LR IMG["--image-path\n(local image file)"] --> ENC["Base64 encode\nimage"] PROV["--provider\n(default: openai)"] --> CALL ENC --> CALL["LLM vision\nchat completion\n(extract text + pirate-speak prompt)"] CALL --> OUT(["stdout: pirate-speak text"]) CALL --> HIST["Session stored\nin ~/.pbtk/history.db"]
The image is base64-encoded and sent inline with the API request. Supported formats are JPEG, PNG, GIF, and WebP. Both openai and claude support image input.
OptionRequiredDefaultDescription
--image-pathYes—Path to the image file to process
--providerNoopenaiLLM provider: openai or claude
--modelNoProvider default (gpt-6-luna or claude-sonnet-5-5)Model to use (must support image input)

corpospeak

Rewrites source text in the communication style appropriate for a chosen enterprise audience, optionally learning from example messages to match an individual's idiolect. Input can be a literal string or a file path. Each invocation creates a new history session.

$ pbtk llm corpospeak --source "API performance is great" --audience csuite
$ pbtk llm corpospeak --source "New feature deployed" --audience engineering --user-messages "Hey team" "Let's ship this"

Audiences

csuite

Executive language, strategic framing.

engineering

Technical, precise, low jargon.

product

User-focused, outcome-driven.

sales

Value propositions, persuasive tone.

marketing

Brand voice, engaging copy.

operations

Process-oriented, practical.

finance

Metrics-focused, precise numbers.

legal

Formal, risk-aware language.

hr

People-centric, inclusive tone.

customer-success

Empathetic, supportive language.

flowchart LR SRC["--source\n(text or file path)"] --> CALL["LLM\nchat completion\n(audience-tuned prompt)"] AUD["--audience"] --> CALL UM["--user-messages\n(optional idiolect examples)"] --> CALL PROV["--provider\n(default: openai)"] --> CALL CALL --> OUT(["stdout: rewritten text"]) CALL --> HIST["Session stored\nin ~/.pbtk/history.db"]

When --user-messages is provided, the examples are included in the prompt so the model can infer and mimic the writer's personal style. Each value can be a literal string or a path to a file containing example text. Multiple values are accepted.

OptionRequiredDefaultDescription
--sourceYes—Source text to rewrite (or file path)
--audienceYes—Target audience slug (see list above)
--user-messagesNo—Example messages to learn idiolect from (text or file paths, repeatable)
--providerNoopenaiLLM provider: openai or claude
--modelNoProvider default (gpt-6-luna or claude-sonnet-5-5)Model to use

generate-image

Generates an image from a text prompt using the OpenAI image API (gpt-image-1 by default) and writes it to the given file. Uses the OPENAI_API_KEY environment variable. This command does not create a history session.

Image generation is supported only by the openai provider. --provider claude is rejected before any work is done, for example: Error: The 'generate-image' action requires image generation which is not supported by the 'claude' provider.
$ pbtk llm generate-image --prompt "A pirate ship at sunset" --out-file ./ship.png
OptionRequiredDefaultDescription
--promptYes—Prompt describing the image to generate
--out-fileYes—Path to write the generated image to
--providerNoopenaiLLM provider. Only openai supports image generation
--modelNoProvider default (gpt-image-1 for openai)Image model to use
--overwriteNooffReplace --out-file if it already exists (otherwise the command fails)

paint

The model paints a 256×256 full-colour canvas through tools in an agentic loop while the terminal redraws it live. The canvas starts white. Each model turn can call the tools below, and every write that changes pixels is shown on screen as it happens. Works with openai (uses the OpenAI Responses API) and claude. Uses the OPENAI_API_KEY or ANTHROPIC_API_KEY environment variable. This command does not create a history session.

The tools available to the model:

ToolPurpose
read_canvasReturns the full canvas as a PNG image
read_regionReturns the exact hex colour values of a region (width and height up to 32)
set_pixelsSets individual pixels from a list of {x, y, color} entries (up to 4096 per call)
fill_rectFills a rectangle with one colour
draw_lineDraws a line between two points (thickness 1–16)
fill_ellipseFills an ellipse given its centre and radii
finishEnds the run with a summary

Colours are written as #RRGGBB. Coordinates start at the top-left corner, with x increasing to the right and y increasing downwards. Invalid tool arguments are returned to the model as an error result and the run continues.

The run ends when one of these happens:

The output file is written when the run ends in any of these ways. If the provider returns an API error, or you press Ctrl+C, the command exits with status 1 and writes nothing. Ctrl+C restores the terminal and keeps the last frame on screen.

Pass --animation-out to also save an animated GIF of the painting. The first frame is the blank canvas, and there is one more frame after every tool call that paints. Every frame is the full 256×256 canvas, whatever the size of the terminal. Each frame lasts 150 ms, the final frame is held for 2 s, and the GIF loops forever. Runs keep at most 500 frames; longer runs keep every second frame. Like the PNG, the GIF is written only when the run ends cleanly.

On an interactive terminal that supports truecolour, the display uses the alternate screen and repaints only the cells that changed. When the run ends, the final image is printed to the normal screen so it stays in your scrollback. When output is redirected, or the terminal does not support truecolour, the command falls back to Spectre rendering. Redirected output prints one line per tool call and the final image once.

$ pbtk llm paint --prompt "A pixelbadger"
$ pbtk llm paint --prompt "A lighthouse at night" --provider claude --max-steps 60 --out-file ./lighthouse.png
$ pbtk llm paint --prompt "A pixelbadger" --animation-out ./badger.gif
$ pbtk llm paint --prompt "A pixelbadger" --model gpt-6.1-sol --reasoning-effort high
OptionRequiredDefaultDescription
--promptYes—What to paint
--providerNoopenaiLLM provider: openai or claude
--modelNoProvider default (gpt-6-luna or claude-sonnet-5-5)Model to use (must support tool calling and image input)
--max-stepsNo40Maximum number of model turns (1–200)
--out-fileNo—Write the final canvas to this PNG file
--animation-outNo—Write an animated GIF of the painting to this file
--overwriteNooffReplace --out-file or --animation-out if it already exists
--reasoning-effortNo—Reasoning effort level. Values depend on the provider: openai accepts low, medium, high; claude accepts low, medium, high, xhigh, max
If --out-file or --animation-out already exists and --overwrite is not given, the command stops before the first model call, for example: Error: Output file already exists: <path>. Use --overwrite to replace it. The two paths must differ: --out-file and --animation-out must be different paths.

history list

Prints a tabular summary of all stored sessions in reverse chronological order, showing the session ID, originating command, creation timestamp, and cumulative token usage.

$ pbtk llm history list

Example output:

ID     Command         Created (UTC)             Tokens (in/out)
--------------------------------------------------------------------
3      corpospeak      2026-05-28 14:30:00       200/90
2      translate       2026-05-28 11:15:00       80/35
1      chat            2026-05-28 09:00:00       350/120

The database file is at ~/.pbtk/history.db. It is created automatically on first use and shared by all llm commands.

history delete

Deletes a session and all of its stored messages from the history database. This operation is permanent.

$ pbtk llm history delete --session-id 42
OptionRequiredDefaultDescription
--session-idYes—ID of the session to delete

Command Reference

Command Required options Optional options Output
llm chat --message --session-id --provider --model --reasoning-effort Assistant reply to stdout; session ID to stderr
llm translate --text --target-language --provider --model Translated text to stdout
llm ocaaar --image-path --provider --model Pirate-speak OCR result to stdout
llm corpospeak --source --audience --user-messages --provider --model Rewritten text to stdout
llm generate-image --prompt --out-file --provider --model --overwrite Image file written to --out-file
llm paint --prompt --provider --model --max-steps --out-file --animation-out --overwrite --reasoning-effort Live canvas on the terminal; final image to the normal screen, to --out-file if given, and an animated GIF to --animation-out if given
llm history list — — Session table to stdout
llm history delete --session-id — Confirmation message to stdout