Whalefall π
April 19, 2026 Β· View on GitHub
A local LLM agent harness: drive any OpenAI-compatible model through built-in tools, MCP plugins, skill documents, and subagents β in a single process, with honest permissions and full trace persistence.
Whalefall (ι²Έθ½, "whale-fall") is a deep-sea phenomenon: when a giant whale sinks to the seabed, its body sustains an entire ecosystem of scavengers and bone-eating worms for decades. This project takes that metaphor literally β one big language model underwrites a swarm of smaller tool calls, keeping an agent productive turn after turn.
Inspired by the overall shape of Claude Code, rewritten from scratch in pure Python, with every moving piece inspectable and every side-effect explicit.
Highlights
- Single-process main loop β
LLM β tool_calls β tool_results β next turn, fully async streaming, every chunk landed to disk viaTraceWriter. - 16+ built-in tools β
read / write / edit / bash / glob / grep / web_fetch / web_search / ask / todo / notebook_edit / agent / plan_mode / skill / mcp_discover / ..., covering the CC feature matrix with ~85% of the functionality. - First-class MCP support β stdio / SSE / streamable-HTTP; plugins self-register via
@mcp.tool(); your tools can live in a private fork without forking this repo. - Hierarchical skill filtering β markdown SOP docs under
skills/; agents pick what they can see viaallowed_skill_paths(path prefixes with proper/boundary semantics). - Subagents β the
agenttool spawns a child loop with its own permissions/context/MCP subset; parent auto-summarizes child transcripts for traceability. - 8-step permission pipeline β hook / bypass / skip / always-allow / rule / mode / deny / prompt; explicitly-declared write tools need user approval unless bypassed.
- BashGuard β an
ll-lite classifier that flags destructiverm -rf /, pipes tosh, hidden network calls, etc. before the shell sees them. - Triple-layer context compression β
microcompact(truncate old tool results),auto_compact(summarize after 92% of context),precompact(eager summary before the next turn if projected to overflow). - Write-ahead persistence β every user / assistant / tool message hits SQLite the instant it's produced, so a crash mid-tool at most loses the assistant text still in the decoder buffer; on reload, orphan
tool_callswith no matchingtool_resultare filtered out so the next turn starts from a consistent state. - Full transcript archive β alongside the capped SQLite history (FIFO'd when it exceeds
max_history_messages), Whalefall appends every message to.runtime/transcripts/<sid>.jsonlwhich is never truncated β great for audit & replay. - Prompt-cache friendly layout β
render_system_prompt_split()separates the static prefix (identity + agent body + guardrails + tool blurbs) from the dynamic tail (date/cwd/env). Static bytes are stable across turns so Anthropic/OpenAI prefix caches can actually hit. --resume-last//resume-lastβ CLI remembers the last active session id in~/.whalefall/runtime/state/last_session.txt; a single flag resumes it in place, matching what the Web UI already does vialocalStorage.- Web UI with live tool trace β FastAPI + WebSocket; soft-reload config on the fly (
π) or hot-replace code viaos.execv(β»οΈ) β no need to leave the browser. - Explicit system prompt β the default identity can be swapped wholesale via
AgentLoop.run_*(system_prompt=...). Zero filesystem sniffing: nothing is auto-read fromcwd; you always know exactly what the model sees.
See src/whalefall/README.md for the ~700-line design document.
Quickstart
1. Install
git clone https://github.com/Parker617/whalefall.git
cd whalefall
pip install -e '.[web]'
2. Configure your LLM
cp src/whalefall/llm/config/llm_config.ini.example src/whalefall/llm/config/llm_config.ini
# Edit the file β paste in your OpenAI / DashScope / DeepSeek / Ollama key
3. (Optional) Configure MCP
No config needed for first run. If src/whalefall/mcp/config.yaml is absent, Whalefall auto-loads a built-in demo server (echo / add / time_now) so you can verify the wiring end-to-end.
To connect your own MCP servers (stdio / SSE / streamable-HTTP):
cp src/whalefall/mcp/config.yaml.example src/whalefall/mcp/config.yaml
# Replace <PROJECT_ROOT> with the absolute path of the repo,
# and add your own servers alongside or instead of `demo:`
To add a new built-in tool, drop a module into src/whalefall/mcp/plugins/ and import it from mcp/server/app.py.
4. Run
# CLI one-shot
whalefall "list every python file under src/ and count them"
# Interactive REPL
whalefall
# Sub-agent modes
whalefall --agent explore "find every todo comment"
whalefall --agent plan "design a migration from v1 to v2 of this schema"
whalefall --agent verify "audit the analysis above"
# Pick up where you left off
whalefall --resume-last
# or in an interactive session: /resume-last /sessions /resume <sid>
# Web UI
whalefall --web --port 8000
# open http://localhost:8000
5. (Optional) Customize the system prompt
Whalefall does not scan any markdown file from cwd (no auto-discovery). The system prompt is assembled from each agent's agent/roles/definitions/<name>/AGENT.md body. Two ways to inject custom rules:
- Edit the agent definition. Change the body of
definitions/general/AGENT.md, or drop a new folderdefinitions/my_project/AGENT.mdand call it viawhalefall --agent my_project .... This is the long-term choice. - Replace the identity on a single call. Pass a markdown string as
system_prompt=when callingAgentLoop.run_*(); it replaces the defaultBASE_IDENTITYblock and suppresses the auto-generated env info, leaving your markdown fully in control. Useful for workflow nodes where each step needs its own persona.
from whalefall.agent.loop import AgentLoop
loop = AgentLoop(...)
answer = loop.run(
user_query="...",
system_prompt="# You are a data-quality auditor.\nReply with VERDICT: ...",
)
Architecture at a glance
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β UI β CLI / Web (FastAPI + WebSocket) / Python API β
βββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββ
β
ββββββββββββββΌββββββββββββββ
β QueryEngine β session + .runtime/ persistence
ββββββββββββββ¬ββββββββββββββ
β
ββββββββββββββΌββββββββββββββ
β AgentLoop β main turn loop + 8 hook events
ββββββββββ¬βββββββ¬βββββββββββ
βββββββββββββββ ββββββββββββββββ
ββββββββββΌββββββββββ ββββββββββββββΌββββββββββββββ
β LLMClient β β ToolDispatcher β
β (openai async) β β builtin + MCP + subagentβ
ββββββββββββββββββββ ββββββββββββββ¬ββββββββββββββ
β
βββββββββββββββββββΌββββββββββββββββββ
ββββββββββΌββββββ ββββββββββΌβββββββ βββββββββΌβββββββββ
β BuiltinTools β β MCPClient β β AgentTool β
β (read/write/ β β (stdio/SSE/ β β (spawn child β
β bash/...) β β http) β β AgentLoop) β
ββββββββββββββββ βββββββββββββββββ ββββββββββββββββββ
How does Whalefall compare?
| Feature | Whalefall | Claude Code | SmolAgents | LiteLLM |
|---|---|---|---|---|
| Local stateful main loop | β | β | partial | β |
| Built-in file / bash tools | β (16+) | β | partial | β |
| MCP (stdio + SSE + HTTP) | β | β | β | β |
Subagents (agent tool) | β | β | β | β |
| Skill markdown documents | β | β | β | β |
| Permission pipeline | β (8 steps) | β | β | β |
| Web UI with live trace | β | β | β | β |
| OpenAI-compatible (works with Ollama, DeepSeek, etc.) | β | β | β | β |
| Language | Python | TypeScript | Python | Python |
| Runs offline against local LLM | β | β | β | β |
Whalefall isn't trying to replace Claude Code β CC is more polished and has deeper IDE integration. Whalefall's niche is you own every byte of the loop: you can read the whole thing in an afternoon, patch any sharp edge, and run it against whichever model you choose.
Documentation
- Design reference:
src/whalefall/README.mdβ full architecture walkthrough, agent type reference, system-prompt layers, CC parity table. - Examples:
src/whalefall/tests/β every public module has an end-to-end test that doubles as usage documentation. - Skill authoring:
src/whalefall/skills/general/weather/SKILL.mdfor a real example;src/whalefall/skills/demo/nested/for directory-layout patterns.
Status
Whalefall is alpha. APIs may change, but the on-disk format of .runtime/ is intended to be forward-compatible. Bug reports and PRs welcome β especially from anyone who's written their own CC-style harness and wants to compare notes.
License
MIT β use it, fork it, ship it, no warranty.
Inspired by Anthropic's Claude Code (MIT). No code copied; design cues and feature checklist derived from the public release.