Skip to main content

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
ExtensionWhat it does
pi-safe-compactSafer context compaction on long sessions
@narumitw/pi-plan-modeA plan-then-execute mode
pi-background-tasksLong-running commands without blocking the session
@juicesharp/rpiv-todoTask 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​

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.

On this page