Closed-network mode: the local model (gemma4 12b) reads README and agent.py with read_file and answersClosed-network mode: outbound calls blocked, local model only; theme turns black and amber, external features disappearModel picker: local Ollama models, server status, free memoryOpen-network home dashboard: session groups, cost, schedules, notifications
Why
I wanted to take apart, my own way, an agent that uses tools from the terminal the way Claude Code does. I studied projects like OpenClaw but set one constraint: the core is a single library: and wrote the agent loop myself.
What I built
Agent core: Five tools (read, write, edit, glob, grep) at first, then web search, a skill system (SKILL.md), persistent memory, image input and local RAG.
App: A native macOS app on pywebview (Windows supported). Multi-session with groups, keyword and semantic search, conversation branching, export, and a voice conversation mode.
Models: Eight Claude models plus local models via Ollama. New models are picked up from the Models API automatically; the local tab handles downloads, a memory gauge and server on/off.
Closed-network mode: every outbound call is blocked and only local models run. The theme changes and external-feature buttons disappear so the mode is obvious at a glance. A mode enabled by environment variable cannot be turned off from the UI.
Auth: Pay-as-you-go API key or a Claude subscription token. Several accounts can be registered and switched with one click.
Decisions
Parallel tools: Read-only tools in a turn are batched and run concurrently; a write or side-effect tool breaks the batch so order is preserved.
Working rules in the prompt: No guessing, read before editing, confirm the change landed, finish the job, and report verified vs. unverified separately. I kept the same rules while building this portfolio.
Serverless RAG: Embedding and search run locally with fastembed + numpy. No index server, so installation is one pip install -e ".[rag]".
Shared engine: Core I/O handlers are separated so the CLI and GUI share the same engine.
Troubleshooting
Local models differ in structured output and thinking support, so the per-model capability table is read from API responses instead of being hard-coded.
Long sessions kept breaking until automatic compaction at 90% context, prompt caching and network retry were added.
Verification
The tool loop and RAG were run end to end with real models. The captures above are from September 2026: closed-network mode with the local model (gemma4 12b) reading files and answering.