mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-30 07:33:59 +08:00
236 lines
7.1 KiB
Plaintext
236 lines
7.1 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, skipping anything `.gitignore` excludes.
|
|
You cannot combine `--upload` with a trailing command, so start Pi from the
|
|
shell that opens.
|
|
|
|
```shell
|
|
openshell sandbox create \
|
|
--name pi-project \
|
|
--from pi-agent:local \
|
|
--provider openrouter \
|
|
--upload .:/workspace
|
|
```
|
|
|
|
In the sandbox shell, run `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).
|