@luan.sh/pi-view-image
Codex-compatible native image attachment tool for Pi
Package details
Install @luan.sh/pi-view-image from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@luan.sh/pi-view-image- Package
@luan.sh/pi-view-image- Version
0.3.8- Published
- Sep 12, 2026
- Downloads
- not available
- Author
- cfcluan
- License
- MIT
- Types
- extension
- Size
- 25.8 MB
- Dependencies
- 2 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./src/extension.ts",
"./node_modules/@luan.sh/pi-libtui/src/extension.ts"
],
"image": "https://pi.luan.sh/media/previews/pi-view-image-3b76f3119bb5.png",
"video": "https://pi.luan.sh/media/previews/pi-view-image-62df21208d2a.mp4"
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@luan.sh/pi-view-image
@luan.sh/pi-view-image adds a Codex-compatible view_image tool to Pi. A
native Rust binary reads and validates a local PNG, JPEG, GIF, or WebP file and
returns it as a Pi image content block, so any vision-capable model can look at
a file that is already on disk. The same package makes pasted image paths in the
Pi editor attach as images and labels image attachments in the Codex format
before they reach the provider.
Preview

Install
pi install npm:@luan.sh/pi-view-image
Requires a Rust toolchain (https://rustup.rs). The view-image binary builds
itself on first use under Pi's agent directory (native/view-image/<version>/).
Set PI_VIEW_IMAGE_BIN to use a prebuilt binary; it must point to an
executable file. Pi shows an info notification while the first build runs.
Code Mode support is bundled. If @luan.sh/pi-code-mode is also installed
(pi install npm:@luan.sh/pi-code-mode), view_image is callable from inside
Code Mode scripts as described below; without it the tool is still available as
a normal Pi tool.
The view_image tool
Parameters:
| Name | Type | Notes |
|---|---|---|
path |
string, required | Absolute path or a path relative to the Pi session's working directory. A leading @ is stripped. file_path and image_path are accepted as aliases. |
detail |
"high" or "original", optional |
Defaults to high. |
Example call:
{ "path": "screenshots/current.png", "detail": "original" }
Behaviour:
highresizes images larger than 2000 pixels on either axis (Anthropic's limit for requests carrying more than 20 images). Resized images and GIF input are re-encoded as PNG; PNG, JPEG, and WebP files that are not resized keep their original bytes and MIME type.originalkeeps the source dimensions and bytes.- The
detailparameter is only exposed to models that support it. For theopenai-codexprovider it requires the model'scompat.supportsImageDetailOriginalflag; every other provider with image input gets it. When a model does not support it, a requestedoriginalsilently falls back tohigh. - Any Pi model that declares
imagein itsinputcapabilities can use the tool. Other models get the errorview_image is not allowed because the current model does not support image inputsbefore the file is read. - The tool result contains one image content block. Its
detailsrecord the input, the resolved path, MIME type, width, height, byte size, and duration in milliseconds. - Errors from the binary (missing file, unsupported format, decode failure) are surfaced as the tool error message, truncated to 8192 characters.
Inside Code Mode
The tool is also registered through @luan.sh/pi-code-mode/sdk. In a Code Mode
script, view_image returns { image_url, detail }, where image_url is a
base64 data: URL. Forward it with image(result) so the model sees the image:
const result = await tools.view_image({ path: "screenshots/current.png" });
image(result);
Pasting image paths into the editor
In the TUI, when a paste contains a single path to an existing PNG, JPEG, GIF,
or WebP file (checked by file signature, not just extension), the path is
replaced inline with an [Image #N] pill. Accepted forms: absolute paths,
paths relative to the working directory, ~/ paths, file:// URLs, quoted
paths, and shell-escaped paths. This covers Pi's clipboard image paste (Pi
writes the bitmap to a temporary file and inserts its path) and terminals that
paste a file path on Command-V. Ordinary text and non-image paths are left
alone.
When the prompt is submitted, each pending pill is loaded through the native
binary at high detail, attached as an image, and its text becomes a
<file name="..."></file> tag. If a file cannot be loaded, the pill reverts to
the plain path and Pi shows a warning Could not attach <path>: <message>.
Pending pills are cleared on session start and shutdown.
Codex-style image labels
Before each request is sent to the provider, user messages whose first text
block contains <file name="..."> tags with image extensions (bmp, gif,
jpg, jpeg, png, webp) and a matching number of image blocks are
rewritten. Each image tag becomes:
<image name=[Image #N] path="...">
<the image block, detail high>
</image>
followed by the rest of the user's text. Tags are only rewritten when the count
of image tags equals the count of image blocks; otherwise the message is left
unchanged. This applies to Pi's own @image attachments and to pastes handled
by this package, and is provider-neutral.
The same hook then clamps every image block in the outgoing context, in user
and tool-result messages alike, to 2000 pixels on either axis using Pi's
resizeImage. Anthropic rejects larger images once a request carries more
than 20 of them, and attach-time resizing cannot fix images already in the
session history. Each distinct image is decoded once per session.
Shrinking an image that Anthropic has already seen changes the request prefix,
so the next response reports dropped thinking blocks once; pi-thinking-binding
then strips those blocks for the rest of the session.
Configuration
The package has no settings. The only configuration is the
PI_VIEW_IMAGE_BIN environment variable described under Install. It
registers no keybindings; pasting uses the editor's normal paste path.
Layout
| Responsibility | File |
|---|---|
| Pi registration and lifecycle | src/extension.ts |
| Tool schema, aliases, model capability checks | src/tools/view-image/definition.ts |
| Tool result and details shape | src/tools/view-image/result.ts |
| Tool call and result rendering | src/tools/view-image/presentation.ts |
| Native binary discovery and build | src/native/binary.ts |
| Running the binary and parsing its JSON | src/native/view-image.ts |
Codex-style <image> labeling in the context hook |
src/native-attachments.ts |
| Pasted image path detection and pending attachment tokens | src/core/attachments.ts |
| Turning pending tokens into attached images on submit | src/runtime/attachments.ts |
| Editor paste handler and pill rendering | src/runtime/editor-attachments.ts |
| Code Mode adapter | src/code-mode-adapter.ts |
| Icon and pill appearance | src/core/appearance.ts |
Develop
Source: https://github.com/luan/agents, directory
harnesses/pi/agent/packages/pi-view-image. Run bun run typecheck and
bun test test in that directory.