mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-20 06:00:06 +08:00
* docs(tutorials): run Pi with OpenRouter Switch the Pi tutorial from Anthropic to OpenRouter, add fd to the Pi image so Pi does not try to download it from GitHub inside the sandbox, and rename the page to Run Pi with OpenRouter with a dev redirect from the old URL. Signed-off-by: Johnny Greco <jogreco@nvidia.com> * docs(tutorials): drop redirect for dev-only Pi page Signed-off-by: Johnny Greco <jogreco@nvidia.com> * docs(tutorials): make the Pi tutorial easier to follow Add prerequisites and steps, explain providers and the profile fields in plain terms, inspect the sandbox while Pi is still running, and add clean-up and troubleshooting sections. Signed-off-by: Johnny Greco <jogreco@nvidia.com> * docs(tutorials): clarify Pi's providers and sandbox additions Signed-off-by: Johnny Greco <jogreco@nvidia.com> * docs(tutorials): make the Pi tutorial more conversational Signed-off-by: Johnny Greco <jogreco@nvidia.com> --------- Signed-off-by: Johnny Greco <jogreco@nvidia.com>
234 lines
7.0 KiB
Plaintext
234 lines
7.0 KiB
Plaintext
---
|
|
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
title: "Run Pi with OpenRouter"
|
|
description: "Build a Pi coding-agent image, configure OpenRouter access, and run Pi inside an OpenShell sandbox."
|
|
keywords: "Generative AI, Cybersecurity, Tutorial, Pi Coding Agent, OpenRouter, Sandbox, Provider Profile"
|
|
---
|
|
|
|
In this tutorial, we'll run [Pi](https://pi.dev), a terminal coding agent,
|
|
inside an OpenShell sandbox. Pi works with many model providers out of the box,
|
|
including [OpenRouter](https://openrouter.ai), which we use here.
|
|
|
|
We'll build a Pi image, give the sandbox access to OpenRouter, and start Pi.
|
|
The sandbox lets Pi reach OpenRouter but nothing else on the network, and Pi
|
|
never sees your real API key.
|
|
|
|
## Prerequisites
|
|
|
|
You'll need:
|
|
|
|
- A working OpenShell installation with an active gateway. Refer to
|
|
[Installation](/about/installation).
|
|
- Docker or Podman to build the image.
|
|
- An OpenRouter API key.
|
|
|
|
<Steps toc={true}>
|
|
|
|
## Build the Pi Image
|
|
|
|
Pi doesn't publish a container image, so we'll build one from its npm package,
|
|
based on Pi's [container guide](https://pi.dev/docs/latest/containerization).
|
|
Save this Dockerfile as `Dockerfile.pi`:
|
|
|
|
```dockerfile
|
|
FROM node:24-bookworm-slim
|
|
|
|
ARG PI_VERSION=latest
|
|
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends bash ca-certificates fd-find git ripgrep \
|
|
&& ln -s /usr/bin/fdfind /usr/local/bin/fd \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
RUN npm install -g --ignore-scripts "@earendil-works/pi-coding-agent@${PI_VERSION}"
|
|
|
|
RUN mkdir -p /workspace && chown node:node /workspace
|
|
USER node
|
|
WORKDIR /workspace
|
|
|
|
ENV PI_CODING_AGENT_DIR=/tmp/pi-agent
|
|
```
|
|
|
|
We add two things to Pi's guide because the sandbox limits what Pi can reach:
|
|
|
|
- We install `fd`. Pi uses `fd` and `ripgrep` to search files, and if they're
|
|
missing, it downloads them from GitHub on first use. The sandbox blocks that
|
|
download, so the image includes both.
|
|
- We set `PI_CODING_AGENT_DIR` so Pi keeps its settings and sessions in `/tmp`,
|
|
one of the few places the sandbox lets Pi write.
|
|
|
|
Now build the image:
|
|
|
|
```shell
|
|
docker build -t pi-agent:local -f Dockerfile.pi .
|
|
```
|
|
|
|
<Note>
|
|
If your gateway uses Podman, build with
|
|
`podman build -t localhost/pi-agent:local -f Dockerfile.pi .` and use
|
|
`localhost/pi-agent:local` in the commands below. If your gateway runs on
|
|
another machine, push the image to a registry the gateway can pull from, and
|
|
use that image reference with `--from`.
|
|
</Note>
|
|
|
|
## Give Pi Access to OpenRouter
|
|
|
|
A sandbox has no network access until you grant it. To let Pi reach
|
|
OpenRouter, we'll create a provider, which stores your API key and opens access
|
|
to the service. Pi only ever sees a placeholder for the key. OpenShell swaps in
|
|
the real key only when Pi calls OpenRouter.
|
|
|
|
A provider is built from a provider profile, which describes the service. Save
|
|
this one as `provider-openrouter.yaml`:
|
|
|
|
```yaml
|
|
id: openrouter
|
|
display_name: OpenRouter
|
|
description: Direct OpenRouter inference access
|
|
category: inference
|
|
inference_capable: true
|
|
|
|
credentials:
|
|
- name: api_key
|
|
description: OpenRouter API key
|
|
env_vars:
|
|
- OPENROUTER_API_KEY
|
|
required: true
|
|
auth_style: bearer
|
|
header_name: authorization
|
|
|
|
discovery:
|
|
credentials:
|
|
- api_key
|
|
|
|
endpoints:
|
|
- host: openrouter.ai
|
|
port: 443
|
|
protocol: rest
|
|
access: read-write
|
|
enforcement: enforce
|
|
|
|
binaries:
|
|
- /usr/local/bin/node
|
|
```
|
|
|
|
Here's what the main sections do:
|
|
|
|
- `credentials` declares the API key. Pi finds the placeholder in
|
|
`OPENROUTER_API_KEY`.
|
|
- `endpoints` allows only `openrouter.ai`, and OpenShell sends the key nowhere
|
|
else.
|
|
- `binaries` allows only `node` to use this access. Pi runs on Node.js, so
|
|
that includes Pi.
|
|
|
|
Check the profile, import it, and create a provider named `openrouter`:
|
|
|
|
```shell
|
|
openshell profile lint -f provider-openrouter.yaml
|
|
openshell profile import -f provider-openrouter.yaml
|
|
|
|
OPENROUTER_API_KEY=your-key \
|
|
openshell provider create \
|
|
--name openrouter \
|
|
--type openrouter \
|
|
--from-existing
|
|
```
|
|
|
|
Replace `your-key` with your OpenRouter API key, or drop that prefix if
|
|
`OPENROUTER_API_KEY` is already set in your shell. `--from-existing` tells
|
|
OpenShell to read the key from that variable.
|
|
|
|
## Start Pi in a Sandbox
|
|
|
|
Next, create a sandbox from the image, attach the provider, and start Pi:
|
|
|
|
```shell
|
|
openshell sandbox create \
|
|
--name pi \
|
|
--from pi-agent:local \
|
|
--provider openrouter \
|
|
-- pi
|
|
```
|
|
|
|
Everything after `--` runs inside the sandbox, so Pi and any commands it runs
|
|
stay contained.
|
|
|
|
Pi starts with its default OpenRouter model. To pick a different one, type
|
|
`/model` and choose any OpenRouter model from the list. OpenRouter usually has
|
|
some free models, marked with a `:free` suffix, which are handy for trying this
|
|
out without spending credits.
|
|
|
|
Then give Pi a try:
|
|
|
|
```text
|
|
Explain what files are available in this workspace.
|
|
```
|
|
|
|
The workspace starts empty, but we'll give Pi your own code in a later step.
|
|
|
|
## Inspect the Sandbox
|
|
|
|
While Pi is running, open another terminal and take a look at the sandbox's
|
|
status, access, providers, and logs:
|
|
|
|
```shell
|
|
openshell sandbox list
|
|
openshell policy get pi --full
|
|
openshell sandbox provider list pi
|
|
openshell logs pi --tail
|
|
```
|
|
|
|
`openshell logs` streams the sandbox's activity, including any connections it
|
|
blocks. When you're done, type `/quit` in Pi to exit.
|
|
|
|
## Work on a Local Project
|
|
|
|
To point Pi at your own code, run this from your project directory. `--upload`
|
|
copies the directory into the sandbox before Pi starts, skipping anything
|
|
`.gitignore` excludes.
|
|
|
|
```shell
|
|
openshell sandbox create \
|
|
--name pi-project \
|
|
--from pi-agent:local \
|
|
--provider openrouter \
|
|
--upload .:/workspace \
|
|
-- pi
|
|
```
|
|
|
|
Pi's changes stay inside the sandbox. To copy them back, run
|
|
`openshell sandbox download` from another terminal while Pi is still running.
|
|
Refer to [Transfer Files](/how-it-works/sandboxes/overview#transfer-files).
|
|
|
|
## Clean Up
|
|
|
|
When you're finished, delete both sandboxes:
|
|
|
|
```shell
|
|
openshell sandbox delete pi pi-project
|
|
```
|
|
|
|
</Steps>
|
|
|
|
## Troubleshooting
|
|
|
|
- If the gateway can't find `pi-agent:local`, make sure you built the image
|
|
with the same container engine your gateway uses, or pushed it to a registry
|
|
the gateway can reach.
|
|
- If Pi's requests to OpenRouter are denied, make sure the `binaries` path in
|
|
the profile matches where `node` is installed in your image. In the image
|
|
above, that's `/usr/local/bin/node`.
|
|
|
|
## Next Steps
|
|
|
|
- To give Pi more tools, add them to the image. To let Pi reach package
|
|
registries, source hosts, or other services, grant access with a
|
|
[sandbox policy](/how-it-works/policies/overview).
|
|
- To use a different model service, write a provider profile for it. The
|
|
[`providers/`](https://github.com/NVIDIA/OpenShell/tree/main/providers)
|
|
directory has examples, and [Profiles](/how-it-works/providers/profiles)
|
|
describes each field.
|
|
- To learn about images, resources, file transfer, and the sandbox lifecycle,
|
|
refer to [Sandboxes](/how-it-works/sandboxes/overview).
|