Tunneling, File Viewer & Developer Tools in OpenACP
AI coding agents do not just generate code -- they build and run applications, serve local development servers, and produce files you need to review. OpenACP includes a suite of developer tools that bridge the gap between your local development environment and your messaging app: tunnel providers to expose local ports, a Monaco-powered file viewer for syntax-highlighted code review, usage tracking for API cost management, and diagnostic commands that help you troubleshoot quickly. This guide covers each tool in depth.
Tunnel Providers: Expose Local Ports to the World
When your AI agent spins up a local development server -- say, a React app on port 3000 or a FastAPI service on port 8000 -- you usually need to be at your computer to see it in a browser. But if you are controlling the agent from Telegram on your phone, how do you preview the running application?
OpenACP solves this with built-in tunnel providers that create secure public URLs pointing to your local ports. When the agent starts a dev server, OpenACP can automatically create a tunnel and send you the public URL in your chat. You tap the link on your phone and see your app running live.
OpenACP supports four tunnel providers, each with different characteristics:
Cloudflare Tunnel (cloudflared)
Cloudflare Tunnel is the recommended default. It is free for development use, requires no account for quick tunnels, provides fast global edge connectivity, and automatically handles HTTPS.
# Install cloudflared
brew install cloudflared # macOS
sudo apt install cloudflared # Ubuntu/Debian
# OpenACP configuration
{
"tunnel": {
"provider": "cloudflare"
}
}
When the agent starts a server on a local port, OpenACP runs cloudflared tunnel --url http://localhost:PORT in the background and captures the generated URL. The URL is sent to your chat as a clickable link.
// How OpenACP creates a Cloudflare tunnel
async function createCloudflareTunnel(port: number): Promise<string> {
const proc = spawn('cloudflared', ['tunnel', '--url', `http://localhost:${port}`]);
return new Promise((resolve) => {
proc.stderr.on('data', (data: Buffer) => {
const output = data.toString();
// Cloudflare outputs the URL to stderr
const match = output.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/);
if (match) {
resolve(match[0]);
}
});
});
}
Cloudflare tunnels generate random subdomains like https://orange-butterfly-3f42.trycloudflare.com. These URLs are temporary and expire when the tunnel process exits.
ngrok
ngrok is a popular alternative that offers more features like custom domains, request inspection, and replay. It requires a free account and auth token.
# Install ngrok
brew install ngrok # macOS
# Authenticate (one-time)
ngrok config add-authtoken YOUR_AUTH_TOKEN
# OpenACP configuration
{
"tunnel": {
"provider": "ngrok",
"authToken": "your_ngrok_auth_token"
}
}
ngrok provides a local dashboard at http://127.0.0.1:4040 where you can inspect all HTTP requests passing through the tunnel. This is incredibly useful for debugging webhook integrations or API calls.
bore
bore is a lightweight, open-source alternative written in Rust. It is the simplest option -- a single binary with no authentication required. It is ideal for quick, ephemeral tunnels when you do not want to set up accounts or install heavy dependencies.
# Install bore
cargo install bore-cli
# OpenACP configuration
{
"tunnel": {
"provider": "bore"
}
}
bore generates URLs in the format bore.pub:PORT. It does not provide HTTPS by default, so it is best suited for development and testing rather than production previews.
Tailscale Funnel
If you are already using Tailscale for your network, Tailscale Funnel provides tunnel functionality that integrates with your existing Tailscale setup. It uses your Tailscale domain and provides HTTPS automatically.
# Tailscale must be installed and authenticated
# Enable funnel for a port
tailscale funnel 3000
# OpenACP configuration
{
"tunnel": {
"provider": "tailscale"
}
}
Tailscale Funnel is unique because the URL is stable -- it uses your machine's Tailscale hostname, so the same URL works across sessions. This is useful for ongoing development where you want a consistent preview URL.
Choosing a Tunnel Provider
| Provider | HTTPS | Account Required | Custom Domain | Best For |
|---|---|---|---|---|
| Cloudflare | Yes | No (quick tunnels) | With account | General use (recommended) |
| ngrok | Yes | Yes (free tier) | Yes (paid) | Request inspection, debugging |
| bore | No | No | No | Minimal, lightweight, quick |
| Tailscale | Yes | Yes (Tailscale) | Yes (stable) | Tailscale users, stable URLs |
Built-in File Viewer with Monaco Editor
When your AI agent creates or modifies a file, you often want to review the changes before proceeding. Reading raw code in a Telegram message is not a great experience -- no syntax highlighting, no line numbers, no ability to scroll through large files. OpenACP addresses this with a built-in file viewer powered by Monaco Editor (the same editor engine that powers VS Code).
When the agent produces a file or you request to view a specific file, OpenACP serves a local web page with the file rendered in Monaco Editor. You receive a link in your chat that opens a full-featured code viewer with:
- Syntax highlighting for 50+ languages (JavaScript, TypeScript, Python, Rust, Go, Java, etc.)
- Line numbers and minimap navigation
- Search and replace (Ctrl/Cmd+F)
- Code folding for collapsible sections
- Multiple themes including dark and light modes
- Read-only mode by default (preventing accidental edits)
// The file viewer is served by OpenACP's built-in Hono web server
import { Hono } from 'hono';
import { serveStatic } from 'hono/serve-static';
const app = new Hono();
// Serve Monaco Editor assets
app.use('/monaco/*', serveStatic({ root: './node_modules/monaco-editor/min' }));
// Serve file viewer page
app.get('/view/:sessionId/:filePath', async (c) => {
const { sessionId, filePath } = c.req.param();
const session = sessions.get(sessionId);
if (!session) return c.text('Session not found', 404);
const content = await fs.readFile(filePath, 'utf-8');
const language = detectLanguage(filePath);
return c.html(renderMonacoViewer({
content,
language,
filePath,
readOnly: true
}));
});
Accessing the File Viewer
There are two ways to use the file viewer:
Automatic: When the agent creates or modifies a file, OpenACP can automatically generate a viewer link and include it in the response message. You click the link to see the file with full syntax highlighting.
On-demand: Send a message like "show me the file src/utils/parser.ts" and the agent will respond with a viewer link for that specific file.
When tunneling is configured, the file viewer URL is accessible from your phone. Without tunneling, it is only accessible on your local network (typically http://localhost:21420/view/...).
Diff View
The file viewer also supports a diff mode that shows the before and after of a file modification side by side. This uses Monaco's built-in diff editor, providing the same diff experience you would see in VS Code:
// Diff viewer endpoint
app.get('/diff/:sessionId/:filePath', async (c) => {
const { sessionId, filePath } = c.req.param();
const session = sessions.get(sessionId);
const original = session.getOriginalContent(filePath);
const modified = await fs.readFile(filePath, 'utf-8');
return c.html(renderMonacoDiffViewer({
original,
modified,
language: detectLanguage(filePath),
filePath
}));
});
Additions appear highlighted in green, deletions in red, and unchanged lines in the default color. This makes it easy to review exactly what the agent changed, even for large files.
Usage Tracking and Budget Limits
AI coding agents consume API tokens, and those tokens cost money. Without visibility into usage, costs can spiral unexpectedly, especially in team environments where multiple developers are running sessions simultaneously. OpenACP provides built-in usage tracking that monitors API consumption and enforces budget limits.
How Usage Tracking Works
OpenACP intercepts the token usage metadata from agent responses (most AI providers include token counts in their API responses) and aggregates it per session, per user, and per time period:
// Usage tracking data structure
interface UsageRecord {
sessionId: string;
userId: string;
platform: 'telegram' | 'discord' | 'slack';
agent: string;
inputTokens: number;
outputTokens: number;
estimatedCost: number;
timestamp: Date;
}
// Usage is tracked per session and aggregated
class UsageTracker {
private records: UsageRecord[] = [];
async trackUsage(session: Session, tokens: TokenUsage) {
const cost = this.estimateCost(session.agent, tokens);
this.records.push({
sessionId: session.id,
userId: session.userId,
platform: session.platform,
agent: session.agentType,
inputTokens: tokens.input,
outputTokens: tokens.output,
estimatedCost: cost,
timestamp: new Date()
});
// Check budget limits
await this.checkBudgetLimits(session.userId);
}
async getDailyUsage(userId: string): Promise<UsageSummary> {
const today = new Date();
today.setHours(0, 0, 0, 0);
const todayRecords = this.records.filter(r =>
r.userId === userId && r.timestamp >= today
);
return {
totalInputTokens: sum(todayRecords, 'inputTokens'),
totalOutputTokens: sum(todayRecords, 'outputTokens'),
totalCost: sum(todayRecords, 'estimatedCost'),
sessionCount: new Set(todayRecords.map(r => r.sessionId)).size
};
}
}
Setting Budget Limits
You can configure daily and monthly budget limits to prevent unexpected costs:
{
"usage": {
"tracking": true,
"budgets": {
"daily": 10.00,
"monthly": 200.00,
"perSession": 5.00
},
"currency": "USD"
}
}
When a budget limit is approaching (80% consumed), OpenACP sends a warning message. When the limit is reached, new sessions are paused or throttled depending on your configuration.
Viewing Usage Reports
You can request usage reports directly in your chat:
/usage today-- Shows today's token consumption and estimated cost/usage week-- Weekly summary with daily breakdown/usage month-- Monthly summary with trends
Usage data is also available through the REST API (covered in the daemon mode guide) for integration with external monitoring dashboards.
Doctor Diagnostics
We touched on openacp doctor in the security guide, but it deserves a deeper look as a developer tool. The doctor command performs a comprehensive check of your OpenACP installation and configuration:
$ openacp doctor
OpenACP Doctor v1.4.2
=====================
System Checks
[PASS] Node.js v22.5.0 (>= 20.0.0 required)
[PASS] npm v10.8.0
[PASS] OS: darwin arm64
Configuration
[PASS] Config file: ~/.openacp/config.json
[PASS] Config valid (Zod schema check)
[PASS] File permissions: 600
Platform Connectivity
[PASS] Telegram Bot API: connected (bot: @MyOpenACPBot)
[PASS] Discord Gateway: connected (bot: OpenACP#1234)
[SKIP] Slack: not configured
Agent Availability
[PASS] claude: found at /usr/local/bin/claude
[PASS] gemini: found at /usr/local/bin/gemini
[WARN] codex: not found in PATH
Tunnel Providers
[PASS] cloudflared: v2024.8.2
[SKIP] ngrok: not installed
[SKIP] bore: not installed
[PASS] tailscale: v1.68.1
Voice
[PASS] Groq API: connected
[PASS] Edge TTS: available
Security
[PASS] Allowed user IDs configured
[WARN] Auto-approve is ENABLED
[PASS] Max sessions: 10
[PASS] Session timeout: 60 min
Network
[PASS] Port 21420: available
[PASS] Outbound HTTPS: working
Summary: 18 passed, 2 warnings, 0 errors, 2 skipped
The doctor command is invaluable for troubleshooting. If something is not working, openacp doctor will usually point you to the exact issue -- a missing binary, an invalid token, a port conflict, or a misconfigured permission.
Running Doctor in CI/CD
You can also use the doctor command in your deployment pipeline to verify that the environment is correctly set up before starting OpenACP:
# In your deployment script
openacp doctor --json | jq '.errors'
if [ $? -ne 0 ]; then
echo "OpenACP doctor found errors, aborting deployment"
exit 1
fi
openacp --daemon start
The --json flag outputs structured JSON that can be parsed by scripts and monitoring tools.
CLI Commands Reference
OpenACP provides a comprehensive set of CLI commands for managing your installation. Here is the complete reference:
Core Commands
# Start OpenACP (interactive mode)
openacp
# Start with a specific config file
openacp --config /path/to/config.json
# Start with a specific working directory
openacp --cwd /path/to/project
# Start with a specific agent
openacp --agent claude
openacp --agent gemini
openacp --agent codex
Daemon Commands
# Start as background daemon
openacp --daemon start
# Stop the daemon
openacp --daemon stop
# Check daemon status
openacp --daemon status
# View daemon logs
openacp --daemon logs
openacp --daemon logs --follow # tail -f style
Diagnostic Commands
# Run diagnostics
openacp doctor
# JSON output for scripting
openacp doctor --json
# Version information
openacp --version
# Help
openacp --help
Session Commands (via chat)
These commands are sent as messages in your chat, not from the terminal:
/handoff -- Generate a session handoff token
/resume XXX -- Resume a session from a handoff token
/usage -- Show usage statistics
/cancel -- Cancel the current agent operation
/clear -- Clear the session and start fresh
Integrating with Your Development Workflow
OpenACP's developer tools are designed to integrate seamlessly with existing workflows rather than replacing them. Here are some integration patterns:
Preview Deployments
When your agent builds a feature, use tunneling to create a preview URL. Share that URL in your team's Slack channel for quick feedback:
You: "Build the new user profile page and start the dev server"
Agent: "Done! I've created the UserProfile component with avatar,
bio, and settings sections. Dev server running on port 3000.
Preview: https://autumn-leaf-4c21.trycloudflare.com"
Code Review from Mobile
Use the Monaco file viewer to review code changes on your phone. The viewer is fully responsive and works well on mobile screens, with horizontal scrolling for wide code and pinch-to-zoom for readability.
Cost Management for Teams
Set per-user daily budgets to prevent any single developer from consuming the team's entire API budget. Use the REST API's usage endpoints to build a dashboard showing team-wide consumption.
Automated Health Checks
Run openacp doctor --json on a cron schedule and alert (via Slack webhook, PagerDuty, etc.) if any checks fail. This catches issues like expired tokens, unavailable agents, or port conflicts before they affect developers.
# crontab entry: run doctor every hour
0 * * * * openacp doctor --json | jq 'select(.errors | length > 0)' \
&& curl -X POST -H 'Content-type: application/json' \
--data '{"text":"OpenACP doctor found errors!"}' \
https://hooks.slack.com/services/YOUR/WEBHOOK/URL
Performance Considerations
Some things to keep in mind about resource usage with these developer tools:
- Tunnels: Each tunnel provider runs as a separate process. Cloudflared and ngrok use roughly 20-50MB of RAM each. Tunnels are created per-port, so a session with multiple servers creates multiple tunnel processes.
- File viewer: Monaco Editor assets are served from a local Hono server and cached by the browser. The initial load is about 2MB, but subsequent views are instant.
- Usage tracking: Usage data is stored in memory by default and resets when OpenACP restarts. For persistent usage tracking, configure a storage backend or use the REST API to export data periodically.
- Doctor: The diagnostic checks make network requests to platform APIs (to verify tokens and connectivity). Run it sparingly in automated environments to avoid rate limiting.
Wrapping Up
OpenACP's developer tools transform the messaging-based coding experience from a simple chat interface into a full-featured development environment. Tunnel providers let you preview running applications from anywhere. The Monaco file viewer gives you proper code review capabilities on any device. Usage tracking keeps costs visible and controlled. And the doctor command ensures your setup stays healthy over time.
These tools are not just convenience features -- they address real pain points that arise when you move your AI coding workflow away from the desktop. By solving these problems at the platform level, OpenACP lets you focus on the actual coding work rather than fighting with the tooling.
Developer Tools at Your Fingertips
Install OpenACP and get tunneling, file viewing, and usage tracking out of the box.
npm install -g @openacp/cli && openacp