libs/pi-extension/README.md
This is a Pi extension that runs every Pi tool call inside a Daytona sandbox. The agent runs on your machine, while bash, file I/O, and search execute in a remote sandbox that is created when you launch Pi with --daytona, kept with your session (and reattached when you resume it), and deleted when you delete that session.
--repo you pass) into the sandbox automaticallyFirst, install Pi:
npm install -g @earendil-works/pi-coding-agent
See pi.dev for other install options.
Then add the Daytona extension to Pi:
pi install npm:@daytona/pi
[!NOTE] To update the extension later, run
pi update—pi installwon't refresh an existing install.
This extension requires a Daytona account and Daytona API key to create sandboxes.
Set your Daytona API key as an environment variable (e.g. in your shell profile):
export DAYTONA_API_KEY="your-api-key"
The extension also reads these optional variables:
DAYTONA_API_URL — defaults to https://app.daytona.io/api.DAYTONA_TARGET — e.g. us.If no key is set and a UI is available, Pi prompts you for one once per session.
Run Pi from inside a git repository:
cd my-project
pi --daytona
The extension clones the repo you're in into the sandbox and syncs your work to a GitHub branch (see GitHub branch sync).
Or point at a different repository:
pi --daytona --repo github.com/acme/api --branch dev
Or run outside a git repo to get a blank workspace.
| Flag | Description |
|---|---|
--daytona | Run tools inside a Daytona sandbox |
--repo <url> | Git repo to clone into the sandbox (defaults to the repo you're in) |
--branch <name> | Branch to clone (defaults to your current branch) |
--snapshot <name> | Choose a Daytona snapshot / base image |
--public | Create a public sandbox so preview URLs need no token |
While Pi is running with --daytona, you can manage the active sandbox:
/sandbox — show the active sandbox's status: state, working directory, branch, sync status, and its GitHub branch link/github — open this session's branch on GitHub/compare — open this session's branch compare view on GitHub/merge — merge this session's branch into its base on GitHub/pr — open a GitHub pull request for this session's branchThe agent runs on your machine. Pi's tool layer is pluggable, so this extension substitutes Daytona-backed implementations of bash, read, write, edit, and ls, plus dedicated in-sandbox tools for find and grep. A footer badge is the always-visible signal that work is remote.
autoStopInterval, overridable with --idle-stop <minutes>). Its filesystem is preserved; resuming transparently restarts it.--blank / no session) can't be resumed, so their sandbox is deleted on exit.If you're in a github.com repo and logged in via the GitHub CLI (gh auth login), each session gets its own branch and the agent's commits are pushed there automatically. The repo comes from --repo, or — when you omit it — is detected from the git project you launched Pi in (its origin and current branch).
pi/<short-session-id> on GitHub (off your current branch, or --branch) and clones it into the sandbox over HTTPS./merge merges the branch into its base, and /pr opens a pull request.All network git operations (clone/push) run inside the sandbox through Daytona; the host only uses gh to mint a token and call the GitHub API. A temporary git identity is configured in the sandbox so commits work out of the box.
[!NOTE] When you're not in a github.com repo (or
ghisn't authenticated), push is disabled. The sandbox still gets a local git repo so the agent can commit, but nothing is pushed.
| Tool | What it does |
|---|---|
bash (+ user !) | Run a command in the sandbox; backgrounded processes (&) don't hang the agent |
read | Read a file from the sandbox |
write | Write a file to the sandbox |
edit | Edit a file (download → modify → upload; preserves Pi's exact-match semantics) |
ls | List a sandbox directory |
find | Find files by glob inside the sandbox (gitignore-aware, supports path globs) |
grep | Search file contents inside the sandbox |
preview_url(port) | Get a public preview URL for a port — the agent calls this after starting a server |
This extension is part of the Daytona monorepo.
First, clone the Daytona monorepo:
git clone https://github.com/daytonaio/daytona
cd daytona
Install dependencies:
yarn install
To modify the extension, edit the source files in libs/pi-extension.
[!NOTE] Because Pi loads extensions as TypeScript via jiti, there is no build step — Pi runs the source directly.
Install the extension's own dependencies once (needed for running it and for the tests):
cd libs/pi-extension && npm install
This is needed even after yarn install at the repo root, which doesn't make @daytona/sdk resolvable at runtime.
Remove any previously installed copy (loading two copies makes every tool and flag conflict):
pi list # shows installed packages and their exact source
pi uninstall <source> # e.g. npm:@daytona/pi — use the source shown by `pi list`
Install the local directory:
pi install ./libs/pi-extension # add --local to scope it to the current project instead of globally
Run Pi:
DAYTONA_API_KEY=dtn_... pi --daytona
Edits to the source take effect on the next run — no reinstall needed.
Alternatively, load the source for a single run without installing:
DAYTONA_API_KEY=dtn_... pi -e ./libs/pi-extension/index.ts --daytona
npx nx run pi-extension:type-check # type-check (from the repo root; needs the monorepo installed)
cd libs/pi-extension
npm run smoke # offline: load the extension and check it registers (no API key/network)
npm run test:live # end-to-end against real Daytona (needs DAYTONA_API_KEY)
Publish the TypeScript source to npm:
npx nx run pi-extension:publish
This will publish to npm with public access and use the version number from package.json.
libs/pi-extension/
├── index.ts # Extension entry point: flags, lifecycle, commands
├── src/ # Daytona-backed tool implementations
│ ├── tools.ts # Tool registration (sandbox-backed tools + preview_url)
│ ├── auth.ts # Daytona API key resolution
│ ├── sandbox.ts # Sandbox resilience layer (auto-restart, exec)
│ ├── ops.ts # Daytona-backed bash/read/write/edit/ls operations
│ ├── find-tool.ts # In-sandbox find (ripgrep/find)
│ ├── grep-tool.ts # In-sandbox grep (ripgrep/grep)
│ ├── github.ts # Host gh control-plane (token + GitHub API)
│ ├── sync.ts # Sandbox-side git push (Daytona git API)
│ └── util.ts # Small shared helpers
├── scripts/ # Offline smoke + live integration tests
├── package.json # Package metadata (includes the "pi" extensions field)
├── project.json # Nx project configuration
├── tsconfig.json # TypeScript config
└── README.md
Apache-2.0