protoAgent: an open-source agent you run on your own machine, with your own models
At protoLabsAI we publish quants: the Ornith GGUFs, the ThinkingCap MTP builds, the NVFP4 conversions. We make those because we run our models locally, and we run them locally because of the thing we've spent the last six months building: protoAgent, an open-source agent runtime. Today it's MIT-licensed and on GitHub, PyPI, and as a desktop app for macOS, Windows, and Linux.
Repo: https://github.com/protoLabsAI/protoAgent
What it is
protoAgent is one long-lived agent that you own. It plans, remembers, uses tools, and hands work off to other agents. You talk to it from a desktop console, or from anything else through its OpenAI-compatible /v1 API or A2A.
Everything it keeps stays in SQLite on your disk: chats, memory, the knowledge base, tasks. There's no analytics, tracking, or telemetry. Model requests go only to the endpoint you configure, and if that endpoint is a llama.cpp or vLLM server on your own box, nothing leaves the machine.
Answers don't have to be text. The agent can render a chart from your data, build a small working app inline in the chat, or write a PDF you can download.
You can also give it a goal with a check, such as "make every test pass", and it keeps working until the check passes.
How it's built
- LangGraph core. The agent is a
create_agentgraph. Middleware hooks around the model call handle context compaction, per-turn token and cost accounting, and human-approval interrupts. Conversation state is checkpointed per thread. - Any OpenAI-compatible model. The server never calls a model SDK directly. It talks to an OpenAI-compatible endpoint: a local llama-server or vLLM, a LiteLLM gateway in front of several providers, or a supported Claude or ChatGPT subscription. Changing models is a config edit.
- Subagents and delegation. A
task()tool spins up subagents with narrower toolsets. Other agents on your network are reachable over A2A. Coding work goes to Claude Code, Codex, or any CLI agent that speaks the Agent Client Protocol. - Plugins instead of forks. Tools, skills, subagents, MCP servers, scheduled jobs, and console views all ship as plugins that install from a git URL and get pinned in a lockfile.
Running it on a local model
Serve a model with an OpenAI-compatible API. For example, our Ornith 1.5 9B GGUF with llama.cpp:
llama-server -hf protoLabsAI/Ornith-1.5-9B-MTP-GGUF --jinja -c 32768 --port 8080
Then start protoAgent:
uvx --from protolabs-agent protoagent serve
Open http://localhost:7870, pick Connect a model endpoint, enter http://localhost:8080/v1, and finish the setup wizard. If you want the full console without a terminal, use the desktop app instead.
What we use it for
We don't run it as a demo. Every day we use protoAgent for:
- A PM agent that works a project board, briefs coding agents, and merges PRs that pass review. Some of protoAgent's own PRs were written and merged this way.
- A coding agent that hands implementation work to Claude Code and Codex, then checks what comes back.
- A handful of narrower agents built from the same core: a career coach, a tabletop rules assistant, a fitness coach. Each one is mostly a different prompt plus a few plugins.
Here's how the PM flow looks. You ask for a feature in chat, and the agent answers with a spec form:
Once you submit it, the card goes onto the board, and a coding agent picks it up and builds it:
What was hard
Some of what we learned building on LangGraph, in case it saves you time:
- Streaming was where most bugs lived. Tokens, tool calls, and subagent progress have to reach the UI in order, through a gateway, over SSE and A2A. Most "the agent hung" reports turned out to be the stream, not the agent.
- Context windows were quietly wrong. Our lookup of each model's context size kept falling back to a default, and subagents didn't compact the way the main thread does. Long runs died with no clear error. Local servers make this worse, because the window you launched with isn't always the window the server reports.
- Small models loop. A model calls the same tool with the same arguments until the context is full. The fix was a detector in middleware; better prompts didn't solve it.
- Trace from day one. Optional Langfuse tracing is built in. Half our bugs only made sense once we could see the full trace.
Try it
- GitHub: https://github.com/protoLabsAI/protoAgent
- Desktop app: https://agent.protolabs.studio/download
- Docs: https://agent.protolabs.studio/docs/
- PyPI:
uvx --from protolabs-agent protoagent serve
Issues and PRs are welcome. We especially want reports from anyone running it on local models: which ones handle the tool loop well, and where it falls over.





