Skip to content

Using with pi

pi is a terminal coding agent. The Mellea Skills Compiler works with it in two independent ways:

  • Pi extension: run compile, validate, run, and certify as slash commands from inside a pi session.
  • Pi compilation backend: use pi instead of Claude Code as the agent that performs compilation from a clone of this repo. Setup is in Pi Setup in the repo README; see Choosing a provider below for provider configuration.

You can use either one without the other.

Neither is the pi export target. That one packages an already-compiled skill so pi can load it as a skill. See Exporting.


Pi extension

The extension adds four slash commands to pi. Each one calls the mellea-skills CLI and shows its output in the pi session. You don't need to install the CLI yourself, the extension sets it up the first time you use it.

Prerequisites

  • pi 1.2.0 or later, with a model provider set up (run pi and use /login, or set your provider's API key). To install pi:

    npm install -g --ignore-scripts @earendil-works/pi-coding-agent
    pi --version
    
  • git, and either uv or Python 3.11 to 3.14.3 (on Windows, the py launcher is enough). The extension uses these to install the compiler.

  • Already using pi? npm install -g replaces your global pi, and pi install writes to your shared agent folder (~/.pi/agent). To keep an existing pi setup as it is, install pi 1.2.0 into its own folder (npm install --ignore-scripts @earendil-works/pi-coding-agent there), put that folder's node_modules/.bin first on PATH, and set PI_CODING_AGENT_DIR to a separate folder before running pi install. Use pi install -l instead to install the extension for one project only.
  • Ollama (or vLLM), running, with the default models pulled. Compiled skills run on Ollama, so /mellea-run and /mellea-certify need it. /mellea-compile and /mellea-validate also run one fixture as a smoke check; without Ollama that check is skipped and you'll see ollama server not running. Install Ollama from ollama.com/download, start it, then pull the default models:

    ollama pull granite4.1:3b
    ollama pull ibm/granite3.3-guardian:8b
    

Ollama is expected at http://localhost:11434. If yours is elsewhere, set both OLLAMA_HOST (used by the compiled skill) and OLLAMA_API_URL (used for certification's risk and Guardian checks) to its URL before starting pi. For vLLM, see Choose Inference Engine.

Quick start

These steps install the extension from npm. If you have a clone of this repo, you can run pi install ./extensions/pi from its root instead to install your local copy of extensions/pi/.

  1. Install the extension:

    pi install npm:@ibm/mellea-skills-compiler-pi
    
  2. Make a folder with a skill to compile, for example the weather skill from this repo:

    mkdir -p my-skills/skills/weather && cd my-skills
    curl -fsSL -o skills/weather/spec.md \
      https://raw.githubusercontent.com/generative-computing/mellea-skills-compiler/main/skills/weather/spec.md
    
  3. Confirm pi has credentials for the provider you'll compile with:

    pi auth check --provider <provider>   # prints "ready" when configured
    

If it doesn't, see Verifying credentials below.

  1. Start pi in that folder, and check that mellea-skills.ts is listed under [Extensions] in the startup banner:

    pi
    
  2. Inside the pi session, run the commands. These are pi slash commands, not shell commands; type / to see them in autocomplete.

    /mellea-compile skills/weather/spec.md
    /mellea-validate skills/weather/weather_mellea
    /mellea-run skills/weather/weather_mellea --input "What's the weather like in Dublin?"
    /mellea-certify skills/weather/weather_mellea
    

The first command takes a few extra minutes while the compiler is cloned and installed under ~/.cache/mellea-skills-compiler/<version>/ (once per version; delete that folder to reset). Compiling writes a weather_mellea/ package next to the spec and can take from a couple of minutes to over half an hour depending on the model. Use a frontier-class model: smaller models often stop partway through a compile.

pi's status bar shows your session's model, not the one being compiled with. The compile prints the provider and model it used when it finishes, and records them in <package>/compile_metadata.json.

You can also pass a skill directory instead of a spec file, for example /mellea-compile skills/weather. The directory must contain a SKILL.md or spec.md, and the package is named after the directory (weather_mellea).

Paths are relative to the folder pi was started in. Flags are passed to the CLI unchanged (see the CLI reference). On /mellea-compile, --provider and --model override the session's provider and model: pass both, or pass only the one that matches your session. If the compile fails because of your provider, see Choosing a provider below.

On Windows, git must be on PATH, and long paths should be enabled (git config --global core.longpaths true). WSL also works.

Verifying credentials

Before running a compile, confirm pi has credentials for your provider:

pi auth check --provider anthropic          # direct Anthropic
pi auth check --provider anthropic-proxy    # your proxy provider
pi auth check --provider ollama             # local Ollama

Each should print ready when the credentials are correctly resolved. This only checks that credentials resolve; it does not contact the provider, so ready doesn't mean the endpoint is up.

invalid_state (from pi auth check --json) usually means pi couldn't load your models.json: it isn't valid JSON, or a headers value refers to an environment variable that isn't set in this terminal. An unset variable in apiKey shows as credentials_not_configured instead.

For Ollama, check the server directly:

curl -s http://127.0.0.1:11434/api/tags

Known limitations

  • No cancellation. Use pi's own interrupt to stop a running command.
  • No output in headless mode (pi -p), where pi exits 0 even if the command failed. Use the mellea-skills CLI directly in scripts.
  • A stopped compile can be resumed with /mellea-compile <spec> --repair-mode.
  • Compiling writes next to the spec. Compile from a copy if you don't want your skill folder changed.
  • The compile runs pi with --approve inside the extension's own copy of the compiler, so it can load the compiler's prompt templates. It does not do this in your own folders.
  • /mellea-run before /mellea-certify runs without Guardian checks, and shows a warning telling you to run mellea-skills ingest or mellea-skills certify. There is no ingest command in pi: run /mellea-certify on the compiled skill once, and later /mellea-run calls use its Guardian policy.

Choosing a provider

Configure credentials for the provider pi will use. Either run pi and use /login inside the session to authenticate interactively, or define the provider in models.json. Pi reads custom providers from models.json in its agent folder: ~/.pi/agent/models.json, or $PI_CODING_AGENT_DIR/models.json if you set that variable. It does not read a file from your working directory. The file can hold API keys, so keep it out of any git repository. The right choice depends on how you are accessing your model:

Situation Provider setting Notes
Direct Anthropic API key anthropic (default) Set ANTHROPIC_API_KEY
LiteLLM proxy / AWS Bedrock gateway a name you choose, e.g. anthropic-proxy Define it with baseUrl + apiKey in models.json
Ollama (local models) ollama Set baseUrl in models.json

Whichever provider you choose, make sure defaultProvider in settings.json, in the same agent folder (~/.pi/agent/ or $PI_CODING_AGENT_DIR), names it, and that defaultModel is one of that provider's models. To compile with a different provider, pass both --provider and --model. For example, for a proxy provider named anthropic-proxy:

{
  "defaultProvider": "anthropic-proxy",
  "defaultModel": "claude-sonnet-4-5"
}

Keep any other settings already in the file.

Direct Anthropic API

No models.json needed. Export your key and then compile as normal:

export ANTHROPIC_API_KEY="sk-ant-..."

LiteLLM proxy / AWS Bedrock gateway

If you access Claude through a LiteLLM proxy or an AWS Bedrock-based gateway, define your own provider for it rather than using the built-in anthropic. Using anthropic with a proxy key will produce an authentication error even if the key looks valid — anthropic expects a real ANTHROPIC_API_KEY, not a proxy credential.

anthropic-proxy below is not a built-in pi provider; it is the name you give your proxy, and any name works as long as you pass the same one to --provider. Add it to ~/.pi/agent/models.json, then check that pi --list-models shows it:

{
  "providers": {
    "anthropic-proxy": {
      "baseUrl": "<your-litellm-proxy-url>",
      "api": "anthropic-messages",
      "apiKey": "<your-litellm-proxy-key>",
      "models": [
        {
          "id": "claude-sonnet-4-5",
          "reasoning": true,
          "input": ["text", "image"],
          "contextWindow": 200000,
          "maxTokens": 64000
        }
      ]
    }
  }
}

Then compile with additional flag --provider anthropic-proxy.

Still seeing errors? Add the compat key

If you still get this error after switching to anthropic-proxy:

API Error: 400 {"error":{"message":"{\"message\":\"tools.0.custom.eager_input_streaming:
Extra inputs are not permitted\"}...

Add a "compat" block to your provider entry to disable eager tool input streaming:

{
  "providers": {
    "anthropic-proxy": {
      "baseUrl": "<your-litellm-proxy-url>",
      "api": "anthropic-messages",
      "apiKey": "<your-litellm-proxy-key>",
      "compat": { "supportsEagerToolInputStreaming": false },
      "models": [
        {
          "id": "claude-opus-4-6",
          "reasoning": true,
          "input": ["text", "image"],
          "contextWindow": 1050000,
          "maxTokens": 128000
        }
      ]
    }
  }
}

This disables a streaming feature that some AWS Bedrock-hosted deployments do not support.

Ollama (local models)

Note: Ollama support is experimental. Compilation quality may vary because the compiler prompts are tuned for Claude-class models. Use a capable ollama model (e.g. granite4.2:30b) for best results.

Terminal output during Ollama compile: The terminal will show a "Processing…" spinner with no further output for the duration of the compile. This is expected — intermediate messages are only printed after each full model response completes, and large local models are slow to respond. The compile is still running; do not interrupt it. Output will appear once the first response finishes.

Add this to ~/.pi/agent/models.json:

{
  "providers": {
    "ollama": {
      "api": "openai-completions",
      "apiKey": "ollama",
      "baseUrl": "http://127.0.0.1:11434/v1",
      "models": [
        {
          "_launch": true,
          "id": "granite4.2:30b",
          "input": ["text"]
        }
      ]
    }
  }
}

Then compile with additional flags --provider ollama --model granite4.2:30b --timeout 21600.

Local models are much slower than hosted Claude. A small skill such as weather took about 110 minutes with granite4.2:30b, longer than the default 75-minute --timeout, so raise it as shown above.

The compiler doesn't write its output to a file, so a long run's output is lost when the terminal closes. With the CLI, pipe the compile through tee to keep a log (append 2>&1 | tee compile.log). With the extension, the output appears in the pi session when the compile finishes.

Choosing an Ollama model

The compile reads roughly 200 KB of step instructions and has to follow strict rules about which files it may write, so it needs a large model that follows instructions reliably and calls tools rather than describing them. Results from compiling weather:

Model Result
granite4.2:30b Compiles successfully (about 110 min)
qwen3-coder Fast, but ignores file-placement rules and does not produce the required *_emission.json files, so the compile fails
granite3.3:8b Prints commands as text instead of calling tools; the compile stops immediately
granite4.2:3b Loses track of the working directory and writes files outside the repository

Models other than these have not been tested.

Check the compiled skill by running it

A successful compile means the package parses, passes the structural lints, and its fixtures import and run. It does not prove that the skill's tools work: fixtures do not make live network calls, and generated tools may catch errors and return them as ordinary strings. Run the compiled skill against a real input before relying on it.

Troubleshooting

Error Likely cause Fix
Authentication failed or 401 when using --provider anthropic Proxy key is not an ANTHROPIC_API_KEY Define a proxy provider in ~/.pi/agent/models.json with your proxy baseUrl and apiKey, and pass its name to --provider
tools.0.custom.eager_input_streaming: Extra inputs are not permitted Older Bedrock deployment does not support this streaming feature Already using your proxy provider? Add "compat": { "supportsEagerToolInputStreaming": false } to that provider block in models.json
Your provider is missing from pi --list-models models.json is in the wrong place or misnamed It must be models.json (plural) in ~/.pi/agent/, or in $PI_CODING_AGENT_DIR if set
pi auth check prints not ready Missing or mis-scoped credentials Re-run pi and use /login, or set the correct environment variable for that provider
Compile starts then silently produces no output Provider accepted the connection but the model rejected the request The provider error message is printed to the terminal at the end of the compile run — scroll up to find it
Mellea-fy skill compilation failed due to timeout with an Ollama model Local models take far longer than the default 75-minute limit Re-run with a larger --timeout, e.g. --timeout 21600 (6 hours)
config_emission.json not found or fixtures_emission.json not found The model wrote config.py / fixtures/ directly (blocked during pi runs) instead of emitting the JSON the compiler renders from Use a more capable model; see Choosing an Ollama model
Pi exited with return code 0 but produced no .../classification.json The model stopped without doing any work — it asked a question or replied with text instead of calling tools Use a model that supports tool calling reliably; see Choosing an Ollama model
--provider X doesn't match your default provider Y, so using your default --provider was passed without --model, and pi's defaultModel belongs to a different provider Pass --model as well to compile with the provider you named