Conversational Agent Shell
A terminal shell where conversation generates workspaces and you control them directly.
Single static binary · deterministic contracts · streaming · persistent sessions
The Idea · See It Work · How It Works · Keys · Quick Start
Most AI tools give you a chat window. You type, the model responds, you copy what you need and paste it somewhere else. The conversation and the artifact are separate things in separate places.
CAS is a different arrangement. Conversation is for generating things. Once generated, you control them directly.
You say write a project proposal. A workspace tab opens alongside the chat — tokens streaming into it as the model generates. When generation ends, you edit it directly, ask CAS to make changes, or both. The AI built the artifact. You wield it.
This resolves a debate in HCI running since 1997. Shneiderman argued that direct manipulation gives users control that delegation never can. Maes argued that agents reduce cognitive load that direct manipulation can't scale to. Both were right. CAS addresses it architecturally:
Agents generate. Users manipulate.
Tokens stream into the workspace as they are generated. The left panel is persistent conversation. The right panel is the workspace you control directly. Multiple workspaces open as tabs — [d] document, [c] code, [l] list.
Every message is classified before any model is invoked:
"write a project proposal" → create workspace (document)
"make a todo list for easter" → create workspace (list)
"create a python script" → create workspace (code)
"add a shopping section" → edit active workspace
"add error handling" → edit active workspace
"how long should this be?" → chat reply
"edit it directly" → chat ← self-edit exclusion fires first
"close the workspace" → close active tab
"run it" → execute active code workspace
"test this" → execute active code workspace
"combine the proposal and checklist" → merge workspaces into new document
Pure regex, sub-millisecond. Self-edit phrases are checked before edit patterns so "edit it directly" never triggers an unwanted LLM call.
Every workspace operation passes through a contract layer before execution:
contract.CheckPreconditions() // is this operation permitted?
contract.CheckInvariants() // are all invariants satisfied?
contract.CheckPostconditions() // did the output meet requirements?Contracts run in Go, external to the model. The model cannot modify, bypass, or reason about them. Any violation fails the operation — fail-closed always. Based on Bertrand Meyer's Design by Contract (1986).
| Type | Badge | Model (Ollama) | Model (Anthropic) |
|---|---|---|---|
| Document | [d] |
qwen3.5:9b |
claude-sonnet-4-6 |
| List | [l] |
qwen3.5:9b |
claude-sonnet-4-6 |
| Code | [c] |
qwen2.5-coder:7b |
claude-haiku-4-5-20251001 |
A placeholder tab appears immediately on create. Tokens stream into it via a buffered channel feeding one event per Bubble Tea tick. The workspace is live from the first token. No separate loading state.
Say run it or execute with an active code workspace. CAS detects the language from content (bash, Python, Go, JavaScript, Ruby), writes to a temp file, and executes in a sandboxed subprocess with:
- Process group isolation — timeout kills the entire tree, not just the leader
- Environment restriction — only
PATHis inherited, no secrets leak - 30-second default timeout
- stdout and stderr captured and displayed in the chat panel
No LLM call is needed — intent detection routes directly to the runner.
Drop .lua files in ~/.cas/plugins/ to add custom commands without recompiling:
-- ~/.cas/plugins/standup.lua
cas.command("standup", "Daily standup from workspaces", function()
local ws = cas.workspaces()
local lines = {}
for i, w in ipairs(ws) do
lines[i] = "- " .. w.title .. " (" .. w.type .. ")"
end
cas.reply("## Standup\n\n" .. table.concat(lines, "\n"))
end)Type standup in the chat and the plugin runs — no LLM call, sub-millisecond.
The Lua VM is sandboxed: no file I/O, no os.execute, no network. Plugins interact with CAS through a controlled API: cas.command(), cas.reply(), cas.workspaces(), cas.active().
With multiple workspaces open, CAS resolves which one you're addressing by fuzzy-matching title fragments:
"update the proposal" → targets "Project Proposal", not the most recent tab
"add the script code to the report" → edits "Report" with "Script" content as context
"combine the proposal and checklist" → creates a new workspace from both sources
"merge all workspaces" → synthesizes everything into one document
Edits that reference another workspace by name automatically include that workspace's content in the LLM prompt — the model can see both documents when making changes.
A Conductor module observes your usage across sessions and builds ~/.cas/profile.json:
{
"ws_types": {"document": 12, "list": 5, "code": 3},
"doc_types": {"proposal": 4, "report": 3, "note": 2},
"edit_verbs": {"add": 7, "fix": 2},
"session_count": 6,
"workspace_count": 20
}This feeds back into LLM system prompts automatically. More sessions → better context → better output. No configuration required.
SQLite (WAL mode) at ~/.cas/cas.db. Sessions, workspaces, and conversation history survive restarts. Previous workspaces restore as tabs on next launch. Full version history per workspace enables multi-step undo.
| Key | Action |
|---|---|
Enter |
Send message |
Tab |
Switch to workspace panel |
← → |
Move cursor in input |
Home / Ctrl+A |
Jump to start of input |
End / Ctrl+E |
Jump to end of input |
Backspace |
Delete character before cursor |
Delete |
Delete character after cursor |
Ctrl+W |
Delete previous word |
Ctrl+K |
Delete to end of line |
Ctrl+U |
Delete to start of line |
↑ / ↓ |
Scroll conversation history |
Ctrl+N |
Start a new session |
Ctrl+C |
Quit |
| Key | Action |
|---|---|
Tab |
Return to chat panel |
Esc |
Return to chat panel |
[ / ] |
Previous / next workspace tab |
e |
Enter inline edit mode |
Ctrl+Z |
Undo last change |
Ctrl+E |
Export to ~/cas-exports/ |
↑ / ↓ |
Scroll workspace content |
PgUp / PgDn |
Scroll by 10 lines |
Full terminal editor via charmbracelet/bubbles textarea. All standard cursor movement and editing keys work.
| Key | Action |
|---|---|
Esc |
Save and exit edit mode |
Ctrl+S |
Save without leaving edit mode |
Ctrl+C |
Discard changes and exit |
internal/
├── intent/ Zero-latency intent detection — regex, no LLM call
├── contract/ Design by Contract enforcement, fail-closed
├── workspace/ Lifecycle: create, update, undo, close, restore
├── shell/ Session manager: ProcessMessage, StreamMessage
├── llm/ Ollama + Anthropic streaming/sync, model routing
├── runner/ Code execution — sandboxed subprocess, timeout, env isolation
├── plugin/ Lua plugin runtime — sandboxed gopher-lua VM
├── store/ Store interface, SQLiteStore (WAL), MemoryStore
└── conductor/ Behavioral learning — observe, profile, user_context
ui/ Bubble Tea TUI: split panel, tabs, streaming, inline edit
tests/tui/ TUI integration tests (spawn real binary via tmux)
cmd/cas/ Entry point: --db, --memory flags
245 tests across all packages. 8 TUI integration tests that spawn the real binary in tmux and interact with it as a user would — catching runtime bugs that unit tests miss.
git clone https://github.com/goweft/cas.git
cd cas
go build -o cas ./cmd/casollama pull qwen3.5:9b
ollama pull qwen2.5-coder:7b
./casexport CAS_PROVIDER=anthropic
export ANTHROPIC_API_KEY=sk-ant-...
./cas./cas # restore last session (default)
./cas --memory # ephemeral session, no persistence
./cas --db /path/to.db # custom database path
CAS_MODEL_CODE=qwen3.5:27b ./cas # use 27b for code workspaces
CAS_MODEL_DOCUMENT=qwen3:14b ./cas # use 14b for documentsgo test ./...
# TUI integration tests — requires tmux + Ollama running
TUI_INTEGRATION=1 go test -v -tags=integration ./tests/tui/ -timeout 300sCtrl+E in workspace focus writes the active tab to ~/cas-exports/:
- Documents and lists →
.md - Code → extension detected from content (
.py,.go,.sh,.js,.rb,.txt)
The directory is created automatically if it doesn't exist.
Shneiderman & Maes (1997). "Direct Manipulation vs. Interface Agents." Interactions, 4(6).
Meyer (1988). Object-Oriented Software Construction. Prentice Hall. (Design by Contract)
Norman (1986). "Cognitive Engineering." In User Centered System Design.
Horvitz (1999). "Principles of Mixed-Initiative User Interfaces." CHI '99.