Pi with mittwald AI Hosting
Pi is a command-line coding agent with read, bash, edit and write tools, an extension system, and a terminal UI. Providers are declared in a JSON file, which makes an OpenAI-compatible endpoint like mittwald AI Hosting straightforward to add.
Installation
The installer script pins all dependencies and lets you update Pi later with pi update:
curl -fsSL https://pi.dev/install.sh | sh
Or with npm, which needs Node.js 22.19 or newer:
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
Or with Homebrew:
brew install pi-coding-agent
Check the install:
pi --version
Choosing between Pi and opencode
Both are CLI coding agents that work with mittwald AI Hosting; the difference is how
much they load before your own work starts. Measured directly against the mittwald
gateway, Pi's first request sends a 2,640-character system prompt (as a
developer-role message) plus JSON schemas for its 4 built-in tools — read, bash,
edit, write — totaling 3,024 characters, for a full first request body of about
6 KB. That's a small, fixed toolset and a compact prompt, so less of the model's
context window is spent before you start working.
opencode ships more capability out of the box — a plugin array, agent packs with per-agent model overrides, and a step limit per agent. On disk, Pi installs to about 142 MB and opencode to about 160 MB, a modest difference either way.
If you want a small, scriptable agent and prefer to add MCP servers and extensions only as you need them, start with Pi. If you'd rather have a fuller, batteries-included setup from the first run, see opencode.
Pointing Pi at mittwald AI Hosting
Pi reads providers from ~/.pi/agent/models.json. Add a provider block:
{
"providers": {
"mittwald": {
"name": "mittwald AI Hosting",
"baseUrl": "https://llm.aihosting.mittwald.de/v1",
"api": "openai-completions",
"apiKey": "sk-...",
"models": [
{
"id": "Qwen3.8-27B-NVFP4",
"name": "Qwen3.8-27B-NVFP4",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 256000,
"maxTokens": 32768,
"samplingParams": {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 20,
"presence_penalty": 0
}
},
{
"id": "Qwen3.6-35B-A3B-FP8",
"name": "Qwen3.6-35B-A3B-FP8",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 256000,
"maxTokens": 32768
}
]
}
}
}
Replace sk-... with your AI Hosting API key. You create it in the AI-Hosting
section of your mStudio project — see
Gaining access. An mStudio API
token from your profile settings is a different credential and will not work here.
The api value must be openai-completions — that is what selects the
OpenAI-compatible request format.
Make it the default in ~/.pi/agent/settings.json:
{
"defaultProvider": "mittwald",
"defaultModel": "Qwen3.8-27B-NVFP4"
}
Per-model samplingParams are optional. Pi merges them into every request body, so
fields like presence_penalty reach the model unchanged. The recommended values for
each model are on its page in the AI models documentation.
The Qwen3.8-27B-NVFP4 entry uses the values for thinking mode, because the model
thinks by default and Pi leaves it that way. Pi sends its thinking level (medium
unless you change defaultThinkingLevel) as reasoning_effort. The level off sends
no field at all, so the model keeps thinking.
Verifying the connection
The models you declared should now be listed:
pi --list-models
Then force a tool call, since a plain chat reply would succeed even with tool calling broken:
pi --provider mittwald --model Qwen3.8-27B-NVFP4 --no-session \
-p "Create a file called hello.txt containing the word hello, then read it back."
Expected: Pi writes the file, reads it back, and reports the contents. Run this in a
scratch directory — the agent writes files where you start it. --no-session keeps
the run ephemeral, so it doesn't leave a saved conversation behind.
Recommended extensions and MCP servers
Extensions
Extensions install from npm and are recorded in settings.json under packages:
pi install npm:pi-safe-compact
pi list
| Extension | What it does |
|---|---|
pi-safe-compact | Safer context compaction on long sessions |
@narumitw/pi-plan-mode | A plan-then-execute mode |
pi-background-tasks | Long-running commands without blocking the session |
@juicesharp/rpiv-todo | Task tracking inside a session |
Toggle what is enabled with pi config.
MCP servers
Pi supports MCP natively since version 0.99.0; you don't need an extension for it.
Declare servers in ~/.pi/agent/mcp.json:
{
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
},
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"]
},
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp"]
}
}
}
Or add them from the shell, and check that every server connects:
pi mcp add context7 -- npx -y @upstash/context7-mcp
pi mcp list
Pi connects all enabled servers in the background when a session starts. By default,
their tools aren't declared to the model one by one; the model reaches them through
Pi's codemode tool, which keeps the tool schemas out of every request. See
MCP Servers
in the Pi documentation for the exposure setting and remote servers.
The pi-mcp-adapter extension still exists, but it replaces the built-in MCP support:
with it installed, Pi no longer reads mcp.json.
For mittwald infrastructure access, see MCP Integration.
Skills
Pi discovers skills automatically, or you can load one explicitly:
pi --skill ./path/to/skill
Disable discovery for a run with --no-skills.
Troubleshooting
A declared model is missing from pi --list-models
The provider block has a JSON syntax error, or api is not openai-completions.
Validate the file: python3 -m json.tool ~/.pi/agent/models.json.
MCP servers are ignored
Run pi mcp list. It connects to every enabled server and prints its state, tools,
and errors. If the list is fine but a session has no MCP tools, check pi list for
pi-mcp-adapter: that extension replaces the built-in MCP support, and Pi then
ignores mcp.json. A project's .pi/mcp.json is only read once you trust the
project.
The agent keeps repeating the same tool call
The agent reads the same files again and again and never gets to an edit. Every
iteration counts against your token quota. Pi 1.4.0 has no step or turn limit: neither
the settings
nor the command-line options
offer one. In the terminal UI, press Escape to stop the current task. For
unattended runs with -p, cap the run time from the shell, for example with GNU
coreutils' timeout 15m pi -p "...".
Neither stops a loop from starting. Loops happen mostly with thinking off. With
Qwen3.8-27B-NVFP4, keep thinking on for planning and tool work, as the configuration
above does; if you turned it off, for example with chat_template_kwargs in
samplingParams, turn it back on. See
Agent loops in non-thinking mode.
A .pi/ directory appears even with --no-session
That's expected if the pi-background-tasks extension is installed — it writes
per-run task state under .pi/tasks/ regardless of the session flag, because
--no-session only disables the conversation transcript, not extension-local state.
Safe to delete; run agents in a scratch directory if you don't want it left behind.
Next steps
- Hermes Agent — another CLI agent
- opencode — a third
- MCP Integration — manage mittwald infrastructure from the agent
- AI models — the full model list
Disclaimer
Third-party tools, MCP servers and external links are provided for convenience without endorsement or warranty. Use them at your own risk, review licenses and privacy policies, and scope access conservatively (least privilege). Avoid sending sensitive data to external services unless required and permitted.