What's broken
Codex-generated image outputs are visible in the iOS app when the phone is on the same Wi-Fi/LAN as the desktop daemon, but they are not visible when the phone is on cellular/5G and connects through Paseo relay.
I asked Codex to generate an image:
Codex completed the turn and the assistant said that the image was generated, but when the iOS app was on cellular/5G, the app only showed text. No image preview/rendered image appeared.
Expected:
- The generated image should be visible in the iOS app both on LAN and over cellular/relay.
- If the image is stored on the desktop/daemon side, Paseo should expose it through a mobile/relay-safe image or attachment path.
Actual:
- The image is visible when the iOS app is on the same Wi-Fi/LAN as the desktop daemon.
- The image is not visible when the iOS app is on cellular/5G.
- The image generation itself succeeds locally.
- The generated PNG exists under ~/.codex/generated_images/....
- Electron logs repeatedly show:
[attachments] Failed to resolve preview URL [object Object]
This suggests that the current image preview path works with LAN/direct daemon access but is not fully relay-safe.
Steps to reproduce
-
Open the Paseo desktop app and have the daemon running with relay enabled.
-
Open the Paseo iOS app while the phone is on the same Wi-Fi/LAN as the desktop daemon.
-
Start a Codex session.
-
Ask Codex to generate an image, for example:
Generate a rabbit image
-
Confirm that the image is visible on the iOS app while on the same LAN.
-
Switch the phone to cellular/5G, not the same Wi-Fi/LAN.
-
Open the same conversation/session in the iOS app through Paseo relay.
Result:
- The assistant says the image was generated.
- The image is visible on LAN.
- The image is not visible over cellular/relay.
Locally, the generated image file exists, for example:
~/.codex/generated_images/019ef6ed-370b-7480-b41a-a625069f189b/ig_06fdd1d3f938738f016a3b1e1342d88193b14c31224b54b58f.png
Where did this happen
iOS app
Paseo version
0.1.98
OS version
Desktop daemon: macOS;Mobile client: iOS app over Wi-Fi/LAN and cellular/5G
Agent provider
Codex
Provider configuration
paseo --version
0.1.98
Sanitized ~/.paseo/config.json:
{
"version": 1,
"daemon": {
"listen": "0.0.0.0:6767",
"mcp": {
"injectIntoAgents": false
},
"autoArchiveAfterMerge": false,
"enableTerminalAgentHooks": false,
"appendSystemPrompt": "",
"terminalProfiles": [
{
"id": "codex",
"name": "Codex",
"command": "omx",
"args": ["--madmax"],
"icon": "codex"
}
],
"cors": {
"allowedOrigins": ["https://app.paseo.sh"]
},
"relay": {
"enabled": true,
"endpoint": "xxxxx.net:443",
"publicEndpoint": "xxxxx.net:443",
"useTls": true,
"publicUseTls": true
},
"auth": {
"password": "<redacted>"
}
},
"app": {
"baseUrl": "https://app.paseo.sh"
}
}
Logs
From macOS Electron log:
~/Library/Logs/Paseo/main.log
[2026-06-23 16:31:09.424] [error] [attachments] Failed to resolve preview URL [object Object]
[2026-06-23 19:36:05.671] [error] [attachments] Failed to resolve preview URL [object Object]
[2026-06-23 19:36:05.674] [error] [attachments] Failed to resolve preview URL [object Object]
Daemon log did not show relevant attachment/image errors during my check
Screenshots or video
Attached screenshot shows:
- iOS app on 5G
- prompt asking Codex to generate a rabbit image
- assistant says the image was generated
- no image is rendered
- Stream end encountered is visible in the conversation
Extra technical context
I looked at the current source code:
- packages/server/src/server/agent/providers/codex-app-server-agent.ts
- packages/server/src/server/agent/providers/provider-image-output.ts
- packages/app/src/components/message.tsx
- packages/app/src/utils/assistant-image-source.ts
- packages/app/src/attachments/service.ts
Relevant observations:
-
Codex image output can be mapped into assistant markdown.
-
codex-app-server-agent.ts reads image result fields such as path, savedPath, saved_path, url, data, and mimeType.
-
If Codex returns base64/data image output, Paseo materializes it into a temp directory named paseo-attachments.
-
renderProviderImageOutputAsAssistantMarkdown() eventually returns markdown like:

-
On the app side, AssistantMarkdownImage resolves non-HTTP/data/blob image sources as file paths and then tries to read them through the daemon/file RPC path.
-
The generated images I observed were stored outside the workspace, for example under:
~/.codex/generated_images/...
and Codex data-image materialization can also use:
os.tmpdir()/paseo-attachments/...
These local paths may work while the iOS app can directly reach the desktop daemon on the same LAN, but they do not appear to be reliably resolvable over relay/cellular.
Suggested fix
Short-term fix:
When Codex image output contains a local path / savedPath, the provider should avoid emitting assistant markdown that directly references the local filesystem path.
A small compatibility fix may be to read the local image file in the Codex provider and materialize it as a data:image/...;base64,... URI before calling renderProviderImageOutputAsAssistantMarkdown().
The existing iOS/app renderer already supports data: image sources and persists them through the platform attachment store via persistAttachmentFromDataUrl().
Long-term fix:
A more robust solution would be to represent provider-generated images as relay-safe managed attachments or structured image timeline items instead of local-path markdown images. That would avoid embedding large
base64 payloads in timeline markdown and would better support caching, garbage collection, relay access, and cross-platform rendering.
In short:
- Short-term: local Codex image path -> data URL before rendering markdown.
- Long-term: provider image output -> managed attachment / relay-safe image reference.
What's broken
Codex-generated image outputs are visible in the iOS app when the phone is on the same Wi-Fi/LAN as the desktop daemon, but they are not visible when the phone is on cellular/5G and connects through Paseo relay.
I asked Codex to generate an image:
Codex completed the turn and the assistant said that the image was generated, but when the iOS app was on cellular/5G, the app only showed text. No image preview/rendered image appeared.
Expected:
Actual:
[attachments] Failed to resolve preview URL [object Object]
This suggests that the current image preview path works with LAN/direct daemon access but is not fully relay-safe.
Steps to reproduce
Open the Paseo desktop app and have the daemon running with relay enabled.
Open the Paseo iOS app while the phone is on the same Wi-Fi/LAN as the desktop daemon.
Start a Codex session.
Ask Codex to generate an image, for example:
Generate a rabbit image
Confirm that the image is visible on the iOS app while on the same LAN.
Switch the phone to cellular/5G, not the same Wi-Fi/LAN.
Open the same conversation/session in the iOS app through Paseo relay.
Result:
Locally, the generated image file exists, for example:
~/.codex/generated_images/019ef6ed-370b-7480-b41a-a625069f189b/ig_06fdd1d3f938738f016a3b1e1342d88193b14c31224b54b58f.png
Where did this happen
iOS app
Paseo version
0.1.98
OS version
Desktop daemon: macOS;Mobile client: iOS app over Wi-Fi/LAN and cellular/5G
Agent provider
Codex
Provider configuration
paseo --version
0.1.98
Sanitized ~/.paseo/config.json:
{ "version": 1, "daemon": { "listen": "0.0.0.0:6767", "mcp": { "injectIntoAgents": false }, "autoArchiveAfterMerge": false, "enableTerminalAgentHooks": false, "appendSystemPrompt": "", "terminalProfiles": [ { "id": "codex", "name": "Codex", "command": "omx", "args": ["--madmax"], "icon": "codex" } ], "cors": { "allowedOrigins": ["https://app.paseo.sh"] }, "relay": { "enabled": true, "endpoint": "xxxxx.net:443", "publicEndpoint": "xxxxx.net:443", "useTls": true, "publicUseTls": true }, "auth": { "password": "<redacted>" } }, "app": { "baseUrl": "https://app.paseo.sh" } }Logs
Screenshots or video
Attached screenshot shows:
Extra technical context
I looked at the current source code:
Relevant observations:
Codex image output can be mapped into assistant markdown.
codex-app-server-agent.ts reads image result fields such as path, savedPath, saved_path, url, data, and mimeType.
If Codex returns base64/data image output, Paseo materializes it into a temp directory named paseo-attachments.
renderProviderImageOutputAsAssistantMarkdown() eventually returns markdown like:

On the app side, AssistantMarkdownImage resolves non-HTTP/data/blob image sources as file paths and then tries to read them through the daemon/file RPC path.
The generated images I observed were stored outside the workspace, for example under:
~/.codex/generated_images/...
and Codex data-image materialization can also use:
os.tmpdir()/paseo-attachments/...
These local paths may work while the iOS app can directly reach the desktop daemon on the same LAN, but they do not appear to be reliably resolvable over relay/cellular.
Suggested fix
Short-term fix:
When Codex image output contains a local path / savedPath, the provider should avoid emitting assistant markdown that directly references the local filesystem path.
A small compatibility fix may be to read the local image file in the Codex provider and materialize it as a data:image/...;base64,... URI before calling renderProviderImageOutputAsAssistantMarkdown().
The existing iOS/app renderer already supports data: image sources and persists them through the platform attachment store via persistAttachmentFromDataUrl().
Long-term fix:
A more robust solution would be to represent provider-generated images as relay-safe managed attachments or structured image timeline items instead of local-path markdown images. That would avoid embedding large
base64 payloads in timeline markdown and would better support caching, garbage collection, relay access, and cross-platform rendering.
In short: