Skip to content

cv01d/oread-cli

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

oread-cli

A local-first LLM interface for roleplay and advanced story writing, with a Claude Code-style terminal UI. Step into a world, play opposite one or many characters, and let a memory-aware engine keep the story coherent across sessions. Runs on local Ollama models or cloud providers (Anthropic, OpenAI, Gemini, Cloudflare Workers AI, AWS Bedrock, and more).

This is a roleplay-only interface — there is no assistant/"chat" mode. Everything is built around characters, worlds, scenes, and continuity: persistent character identities, evolving relationships and trust, tracked world state (location, time, who's present, ongoing events), and cross-session carryover so a world remembers where you left off.

All memory is stored locally in SQLite. Cloud providers are opt-in. Nothing leaves your machine by default.

Features

  • Roleplay-first — characters, worlds, scenes, and narrative immersion; no assistant mode.
  • Single or multi-character worlds — play one companion or a full cast with a primary voice and supporting characters (/mode single|multi).
  • Live world & character authoring — reshape lore, scenes, rules, and characters with /world set|rule and /character set|add, then /world save to keep them as a reusable user world.
  • Continuity engine — per-session world state (location, time, who's present, ongoing events, mood), rolling summaries, character stances, and pinned/recalled context, assembled within a token budget.
  • Cross-session carryover — a world remembers earlier sessions; new sessions seed from the latest snapshot and the prompt notes where you left off (/recap).
  • Character-scoped memory — facts and relationships are stored per character, so different roleplays never bleed into one another.
  • Evolving relationships — trust shifts with each session's emotional tenor, and the character knows whether you're newly met, close, or estranged.
  • Guided onboarding — a fresh start drops you straight into a world picker instead of an empty prompt.
  • Many model backends — local Ollama plus Anthropic, OpenAI, Gemini, Cloudflare Workers AI, AWS Bedrock, Nomi, and Kindroid. Switch mid-scene; world, memory, and session stay put.
  • Local-first & private — all memory in local SQLite, cloud providers opt-in, encrypted key storage, no telemetry.

About

CLI emerged from this original project: https://github.com/4tlasX/oread-companion

The goal is to eventually make this the backend for the original GUI which will turn into a desktop app.

Screenshot 2026-04-06 at 10 37 07 PM Screenshot 2026-04-06 at 10 37 24 PM

Quick start

OLLAMA_MAX_LOADED_MODELS=2 ollama serve   # in a separate terminal

npm install
npm run build
npm link

oread

Running modes

oread                        # Terminal UI (default)
oread --api                  # Terminal UI + API server on :3002
oread --api --no-repl        # API server only (headless)
oread --api --port=4000      # Custom port

Slash commands

Worlds & Scenes

Command Description
/worlds Interactive world picker
/world <id> Load a world, start a new session, show recent sessions to resume
/world Show active world and current session
/world status Full world detail — setting, scene, rules, character lineup
/world set <field> <text> Edit the world: lore, scene, narrator, name
/world rule <add|remove> <text> Add or remove a hard rule the characters must obey
/world save [name] Save the current world (with your edits) as a reusable user world
/mode <single|multi> Single-character or multi-character roleplay

Characters

Command Description
/character Show the active character
/character list List the world's cast
/character <name> Switch the active character
/character set <field> <value> Edit a field — name, role, backstory, skills, interests, avoid, …
/character add <name> Add a new character and make them active

Sessions

Command Description
/sessions Interactive session picker
/session <id-or-name> Switch to a session by ID prefix or name
/session Show current session detail
/new [name] Create a new session with current world settings

Models

Command Description
/model Interactive model picker (lists all providers)
/model <name> Switch to a specific model directly
/models Alias for /model
/pull <name> Pull a model from Ollama or HuggingFace

Memory

Command Description
/memory Show session facts, summary, world state, stances
/memory global Show this character's cross-session global memory
/recap Recap what carried over into this world from earlier sessions
/forget <text> Remove matching facts from session
/search <query> Full-text search over session messages
/pin Pin the last assistant message (keeps it in context)
/unpin Unpin the last pinned message

Notes & Settings

Command Description
/notes View session notes
/notes set <text> Write session notes
/notes clear Clear session notes
/settings Show key settings
/settings <key.path> Inspect a specific setting
/set <key.path> <value> Change a setting (e.g. /set general.temperature 0.9)

API Keys

Command Description
/key set anthropic <key> Store Anthropic API key (encrypted)
/key set openai <key> Store OpenAI API key (encrypted)
/key set gemini <key> Store Gemini API key (encrypted)
/key set nomi <key> Store Nomi.ai API key (encrypted)
/key set kindroid <key> Store Kindroid.ai API key (encrypted)
/key set cloudflare <accountId>:<apiToken> Store Cloudflare credentials (encrypted)
/key set bedrock <accessKeyId>:<secretAccessKey>:<region> Store AWS Bedrock credentials (encrypted)
/key list Show configured providers
/key remove <provider> Delete a key

Keys can also be set via .env — see Environment below. The encrypted DB key takes priority over the env var if both are present.

Utilities

Command Description
/status Show full status — world, session, model, memory stats
/export Export session as markdown to data/exports/
/export <filename> Export with a specific filename
/help List all commands
/exit Exit

UI layout

  you   › Hello
  elara › I'm Elara, keeper of the Rusty Flagon...

──────────────────────────────────────────────────
 › your message here
──────────────────────────────────────────────────
[oread]  Fantasy Tavern  •  llama3.2  •  session

Role labels align to a fixed column. Status bar sits below the input — world, model, session update live after every command.

Model routing

Model names are routed automatically by prefix:

claude-*          → Anthropic          (ANTHROPIC_API_KEY or /key set anthropic)
gpt-*, o1-*, o3-* → OpenAI             (OPENAI_API_KEY or /key set openai)
gemini-*          → Gemini             (GEMINI_API_KEY or /key set gemini)
nomi-*            → Nomi.ai            (NOMI_API_KEY or /key set nomi)
kindroid-*        → Kindroid.ai        (KINDROID_API_KEY or /key set kindroid)
@cf/*             → Cloudflare Workers AI  (CF_ACCOUNT_ID + CF_API_TOKEN or /key set cloudflare)
bedrock:*         → AWS Bedrock        (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY + AWS_REGION or /key set bedrock)
anything else     → Ollama             (local, no key needed)

Bedrock model IDs carry a bedrock: prefix and use the unified Converse API, so Claude, Llama, Nova, and Mistral all stream through one path — e.g. bedrock:anthropic.claude-3-5-sonnet-20241022-v2:0 or, for cross-region inference profiles, bedrock:us.anthropic.claude-sonnet-4-20250514-v1:0. The region and the model's access entitlement come from your AWS credentials.

Switch mid-conversation with /model <name> — world, memory, and session stay the same.

Pulling models

/pull accepts Ollama model names, HuggingFace repo paths, and full HuggingFace resolve URLs:

/pull llama3.2
/pull hf.co/bartowski/Llama-3.2-3B-Instruct-GGUF
/pull https://huggingface.co/bartowski/Llama-3.2-3B-Instruct-GGUF/resolve/main/Llama-3.2-3B-Instruct-Q4_K_M.gguf

A progress bar replaces the input while downloading. ESC cancels. On completion the model is automatically set as active.

Worlds

A world is a self-contained roleplay setting: its lore and opening scene, the narrator's voice, hard rules the characters must obey, and a cast of one or more characters (name, role, backstory, traits). 19 built-in worlds span romance, mystery, sci-fi, fantasy, and slice-of-life companions.

data/templates/
  defaults/       # 19 built-in worlds (read-only)
  user/           # Your saved worlds — created via /world save
  active.json     # Currently active settings

Build your own without touching a file: load a world, reshape it live with /world set, /world rule, and /character set|add, then /world save to fork it into a reusable user world. You can also drop any compatible JSON straight into data/templates/user/, or set CHAT_TEMPLATES_DIR=/path/to/other/defaults to load worlds from another directory.

Memory & continuity

oread keeps a long roleplay coherent without you managing context by hand. After each turn, a small local extraction model (phi4-mini via Ollama) updates a layered memory in the background — it never blocks the reply:

  • World state — current location and in-story time, who's physically present, ongoing events, recent discoveries, and mood, with a lifecycle so stale events fade out.
  • Rolling summary — older turns are condensed so the thread survives well past the context window.
  • Character stances & debates — positions the character holds and open disagreements, so they don't silently flip-flop.
  • Global memory (per character) — durable facts promoted across sessions, scoped to the character that earned them so a sci-fi captain never recalls your vampire romance.
  • Relationships — trust and familiarity that evolve with each session's tenor; the character is told whether you're newly met, close, or estranged.
  • Carryover — when you return to a world, the newest snapshot seeds the new session and the prompt opens with "Earlier in this world…". /recap shows it; /memory inspects the rest.

Everything is assembled into the prompt within a token budget, newest and most relevant first. Toggle the background work with /set general.autoSummarize and /set general.crossSessionMemory.

API

When running with --api, the server exposes:

GET  /api/health
GET  /api/models
POST /api/models/pull              SSE download progress
POST /api/chat                     SSE streaming  { message, sessionId? }
GET/POST          /api/sessions
GET/PUT/DELETE    /api/sessions/:id
GET               /api/sessions/:id/messages
PATCH             /api/sessions/:id/messages/:messageId/pin
GET/PUT           /api/sessions/:id/notes
GET               /api/sessions/:id/world-state
GET               /api/sessions/:id/search?q=
GET/PUT/DELETE    /api/templates
GET/PUT/DELETE    /api/templates/active
POST              /api/templates/user
GET/PUT/DELETE    /api/memory/global
GET               /api/memory/search?q=
GET               /api/memory/relationships

Security

  • API keys encrypted with AES-256-GCM; secret auto-generated at data/.secret (chmod 600)
  • Set OREAD_SECRET env var to use your own passphrase
  • API server binds to 127.0.0.1 only — not reachable from the network without a reverse proxy
  • Export filenames are sanitized to prevent path traversal
  • LLM responses are sanitized via responseGuard: strips ANSI/terminal escape sequences and flags prompt-injection patterns before display or persistence
  • FTS5 queries are hardened against injection; UUID validation on all session API routes
  • settings_snapshot is stripped from all API responses
  • No telemetry; no outbound connections except Ollama (local) and configured cloud providers

Environment

OLLAMA_URL=http://localhost:11434
OLLAMA_CHAT_MODEL=llama3.2
OLLAMA_EXTRACTION_MODEL=phi4-mini
OLLAMA_MAX_LOADED_MODELS=2      # Keep chat + extraction models warm simultaneously
CHAT_TEMPLATES_DIR=             # Optional: load worlds from another directory
API_PORT=3002
OREAD_SECRET=                   # Optional: custom encryption passphrase

# Cloud provider API keys (alternative to /key set <provider> <key>)
ANTHROPIC_API_KEY=
OPENAI_API_KEY=
GEMINI_API_KEY=
NOMI_API_KEY=
KINDROID_API_KEY=

# Cloudflare Workers AI (both required as env var alternative)
CF_ACCOUNT_ID=                  # Cloudflare account ID
CF_API_TOKEN=                   # Cloudflare API token (Workers AI: Run permission)

# AWS Bedrock (all three required as env var alternative)
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=                     # e.g. us-east-1 — must have Bedrock model access enabled
AWS_SESSION_TOKEN=              # Optional: only for temporary STS credentials

# Character/model IDs for companion providers
NOMI_MODEL=                     # Nomi companion UUID
KINDROID_MODEL=                 # Kindroid AI ID

Copy .env.example to .env to configure.

Development

npm run build     # Compile JSX + bundle to dist/oread.js
npm run watch     # Rebuild on file changes
npm run dev       # Build + run

After any source change: npm run build then oread.

About

Custom LLM interface for roleplay and writing that supports cloud models via API(s) and local thru Ollama. Works best with models that support roleplay like Wayfarer.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors