Documentation

Connect AI agents to your customers' data, safely

Agent Bridge gives an AI vendor's agent time-boxed, customer-approved, audited access to systems inside the customer's network, through one outbound-only connector. No VPN, no inbound firewall rule, and Postgres stays read-only. tunr can also host the agent, deploy small apps, and open tunnels to a local port.

FeatureStatus
Agent Bridge: connector, grants, read-only Postgres, end-to-end TLS, dashboard, MCP toolsPreview
Hosted agents (tunr agent deploy, cron/webhook triggers)Early access
Bridge: MySQL / MSSQL, HTTP resources, approver-signed grantsPlanned
HTTP / WebSocket tunnelsStable
Raw TCP, UDP and TLS tunnels (over WebSocket)Experimental
Access control, demo tools, inspector & replayStable
MCP server (tunnel tools)Stable
Python & Node.js SDKsStable
Cloud deploy, tunr apps, app logs, MCP cloud toolsPreview v0.6.1+
Scale-to-zero (sleep / wake)Preview
Multiple relay regionsPlanned

Preview means it works end to end, but the edges are still sharp and details may change. Agent Bridge guides on GitHub: customer quick start, vendor quick start, security overview. The CLI is a single static Go binary with no runtime dependencies; the source is on GitHub.

Agent Bridge Preview #

Two sides use the bridge. The customer keeps data inside its network and runs one connector. The vendor sells an AI agent that needs to read some of that data.

 vendor's agent ──► tunr access ──(TLS 1.3, pinned)──► connector ──► customer's database
 (anywhere)        127.0.0.1:port   relay forwards     (customer network,  (read-only role)
                                    ciphertext          outbound only)
PieceWhat it is
Connectortunr connect, running as a service on a machine inside the customer's network. It only dials out and serves named resources; their addresses never leave that machine.
ResourceA named target such as acme/erp-db: postgres (read-only) or tcp (read-write, two approvers).
AgentA vendor's agent identity, separate from any person. Its token lasts at most 24 h.
GrantAgent × resource × mode × duration, requested with a reason and approved by the customer. It expires on its own; the customer sets the longest allowed window (default 8 h, 1–24 h).
Dashboardapp.tunr.sh/bridge: approvals, sites, vendors, activity, agents, members and settings. A self-hosted relay serves the same screens itself at /portal/.

Customer quick start #

Plan on 10–15 minutes.

  1. Organization. Sign in to the dashboard with your work e-mail and create an organization of type Customer. Its slug (e.g. acme) is the first half of every resource address. Add colleagues under Members and give the people who decide on access the approver role.
  2. Site. Sites → Add a site. A site is one network location. The dashboard shows the setup command once, with your token and the relay's key filled in. Run it on a Linux server inside that network. The connector only makes outbound HTTPS connections; open no firewall ports.
  3. Resources. Name what agents may reach, create a read-only database role for your DBA to apply, and start the service.
  4. Vendors. Vendors → Allow a vendor with their org slug. They can see your resource names and ask; nothing is granted yet. Give them the connector's TLS fingerprint through a channel you trust.
  5. Approve, watch, cut. Requests appear under Approvals with the agent, resource, mode, duration and reason. Activity shows every session and query summary; export the audit log as CSV.
sudo tunr connect --relay https://bridge.tunr.sh --site istanbul-office \
  --token tunr_site_… --relay-key ed25519:… --secret-store file --setup-only

sudo tunr connect resource add erp-db --kind postgres --target 10.0.0.5:5432 --database logo
sudo tunr connect pg-role --database logo --tables invoices,stock --resource erp-db > pg-role.sql
psql -h 10.0.0.5 -U postgres -f pg-role.sql    # your DBA runs this once

sudo tunr connect install                      # systemd service, hardened
sudo tunr connect status                       # shows the site's TLS fingerprint
CommandWhat it does
tunr connect resource add|remove|listManage the resources this site exposes (--kind postgres|tcp, --target host:port, --database).
tunr connect pg-rolePrint SQL for a SELECT-only login role (--tables, --schemas, --role) and store its credential for --resource.
tunr connect install|uninstallInstall the connector as a service (tunr-connector.service on Linux).
tunr connect statusConnection state and the site's TLS fingerprint (--json).
tunr connect kill · resumeStop every stream locally, even without the relay; undo it.
tunr connect --health-addr 127.0.0.1:9095GET /healthz for monitoring: 200 when connected, 503 when not.
tunr grants list|approve|deny|revoke --org acmeDecide on requests from the terminal instead of the dashboard.

Revoking a grant closes that agent's open connections immediately. Sites → Cut all access revokes every approved grant on the site. To keep full query text in the audit log, turn it on under Settings; it is off by default. Settings also takes webhook URLs for grant events (grant.requested, grant.approved, grant.denied, grant.revoked, grant.expired), signed in X-Tunr-Signature with HMAC-SHA256.

Vendor quick start #

In the dashboard, create an organization of type Vendor (e.g. finbot) and tell your customer that slug. Create an agent identity per agent or product feature; customers see its name. Issue its token in the dashboard or from the CLI:

tunr login
tunr agent create invoice-reconciler --org finbot
export TUNR_AGENT_TOKEN=$(tunr agent token invoice-reconciler --org finbot --ttl 24h)
export TUNR_RELAY_URL=https://bridge.tunr.sh

tunr catalog                                   # resources you may request
tunr access request acme/erp-db --ttl 2h --reason "Reconcile October invoices" --wait 15m
tunr access acme/erp-db --port 15432
#  postgresql://agent:<local secret>@127.0.0.1:15432/db?sslmode=disable
psql "postgresql://agent:…@127.0.0.1:15432/db?sslmode=disable" -c "select count(*) from invoices"
  • Write the reason for the customer's approver: what you will read and why. Databases are read-only; raw TCP resources need --mode rw, which the customer must approve with two people.
  • The stream is end-to-end TLS 1.3 to the customer's connector, pinned to its certificate. tunr access logs the fingerprint it pinned; compare it with the one the customer gave you. If the customer's connector is too old to support it, tunr access warns that the stream is not end-to-end encrypted; add --require-e2e to refuse such streams instead.
  • Writes fail with SQLSTATE 42501. Grants can limit rows per query, bytes and queries per second; respect them with LIMIT and WHERE.
  • Access stops when the grant expires or is revoked. Treat a closed connection as "ask again", not as an error to retry blindly. tunr access list and tunr access status <grant> show where you stand.

Agents over MCP #

Point your MCP client at tunr mcp with TUNR_AGENT_TOKEN in its environment. The bridge tools use the agent token, not your tunr login.

{"mcpServers": {"tunr": {"command": "tunr", "args": ["mcp"],
  "env": {"TUNR_AGENT_TOKEN": "…", "TUNR_RELAY_URL": "https://bridge.tunr.sh"}}}}
ToolArgumentsWhat it does
tunr_list_resources—Customer resources this agent can request.
tunr_request_accessresource*, reason*, ttl, modeAsk the customer. Returns pending until a person approves.
tunr_access_statusgrant_id*Check a grant.
tunr_open_accessresource*Open a local port and return the DSN.
tunr_close_accessresource*Close the local port when done.

Hosted agents Early access #

tunr can run the agent itself: private, woken by cron or signed webhooks, with its identity issued automatically. Hosted agents aren't generally available yet; ask for early access.

tunr agent deploy invoice-reconciler --org finbot --volume 256 ./agent
tunr agent trigger add invoice-reconciler --org finbot --cron "0 7 * * *"        # UTC
tunr agent trigger add invoice-reconciler --org finbot --webhook new-invoice --path /hooks/invoice
tunr agent trigger list invoice-reconciler --org finbot
  • The agent listens on $PORT and receives POST on its trigger path (default /run), signed in X-Tunr-Trigger-Signature with TUNR_TRIGGER_SECRET: t=<unix>,v1=<hex HMAC-SHA256(secret, "<unix>.<body>")>. Keep the request open while it works; the app is not paused mid-request.
  • Identity is automatic: the bundled CLI at /opt/tunr/bin/tunr (and tunr mcp) exchanges TUNR_AGENT_BOOTSTRAP for hourly agent tokens.
  • It isn't reachable from the internet except through signed webhooks. /data persists across restarts.

Security model #

GuaranteeHow
Default denyThe relay requires an approved, unexpired grant, an active agent and token, an active vendor link and an online connector before opening anything.
Databases are read-onlyA SELECT-only login role; every session starts with default_transaction_read_only=on and a 30 s statement timeout; a statement classifier (an allow-list over a real SQL tokenizer) refuses writes, DDL, COPY, function-call messages, row locks, SET of unsafe parameters and side-effect functions. Refusals return SQLSTATE 42501.
The connector checks every streamEach stream carries a short-lived (≤15 min), single-use, Ed25519-signed grant token bound to the site, the resource and that stream. The connector verifies it against the relay key pinned at install.
No database password for agentsThe connector logs in with the read-only role from its own secret store. The agent's DSN holds a random per-process secret that only unlocks its own local port.
No inbound portsThe connector dials out; the relay cannot dial in.
Short-lived credentialsGrant tokens ≤15 min; agent tokens ≤24 h (hosted agents: 1 h, renewed); site tokens can be rotated from the dashboard.
Everything is recordedGrant requests, approvals, denials, revocations, expiries, every stream (with byte counts) and a summary of every query (command, tables, rows, duration, blocked), exportable as CSV or JSON. Query text is stored only if the customer turns it on.
Instant cut-offRevoke closes a grant's open connections on both sides (about 4 ms in end-to-end tests); "Cut all access" revokes every grant on a site; tunr connect kill works without the relay.
Tenant isolationEvery relay database query is filtered by organization; another org's objects look missing.
Relay can't read the streamEnd-to-end TLS 1.3 between tunr access and the connector, pinned to the connector's certificate.

What it does not protect against. An actively compromised relay: the relay signs grant tokens and tells the vendor which certificate to expect, so an attacker controlling it could mint grants or substitute a certificate. Verify the connector fingerprint out of band (dashboard → Sites, or tunr connect status); approver-signed grants are planned; self-hosting the relay removes the third party. A compromised connector machine, which holds the database credential. What a vendor does with data it was allowed to read: that's a contract matter, and the audit log is the evidence. Query text in transit: the connector sends each query summary, including the statement text, to the relay, which stores the text only if the customer enabled it.

Connector secrets live in the OS keychain, or on a headless server in 0600 files in a 0700 directory (--secret-store file); the connector refuses to read them if other users can. They are not encrypted at rest. The Linux service runs with ProtectSystem=strict, NoNewPrivileges and private /tmp and devices. Report vulnerabilities privately to [email protected].

Install #

macOS and Linux

curl -fsSL https://tunr.sh/install.sh | sh

The script detects your OS and architecture, downloads the latest release from GitHub, verifies its SHA-256 checksum and installs tunr to /usr/local/bin (it asks for sudo only if that directory isn't writable). Set TUNR_INSTALL_DIR to install somewhere else.

Homebrew

brew install tunr-dev/tap/tunr

Go

go install github.com/tunr-dev/tunr/cmd/tunr@latest

Windows

Download the windows_amd64.zip archive from the releases page and put tunr.exe on your PATH, or run the install script from Git Bash.

Verify

tunr version
tunr doctor      # checks network, relay, login and config

Keep it current with tunr update. tunr uninstall stops the daemon and removes the binary, config and stored credentials.

Quickstart #

Share something that's already running — no account needed:

npm run dev                 # your app on :3000
tunr share --port 3000
#  ✓ https://a1b2c3.tunr.sh → localhost:3000

The URL lives as long as the command does. Press Ctrl+C to close it.

Host it so it outlives your laptop — needs an account:

tunr login
tunr deploy --name my-app
#  🚀 Live: https://my-app.tunr.sh

Log in #

tunr login     # opens your browser; the token comes back to the CLI
tunr logout    # removes the stored token

The token is stored in your operating system's keychain (macOS Keychain, Windows Credential Manager, Secret Service on Linux) — never in a dotfile. Anonymous tunnels work without logging in. You need an account for cloud apps, and a Pro plan for a custom subdomain or custom domain on a tunnel.

Deploy an app Preview v0.6.1+ #

tunr deploy packs a directory, builds it on tunr's infrastructure and runs it in its own sandbox. You get https://<name>.tunr.sh.

tunr deploy                                   # current directory, name = folder name
tunr deploy ./api --name sprint-api           # another directory, explicit name
tunr deploy --port 3000 --env DATABASE_URL=postgres://… --env NODE_ENV=production
FlagDefaultDescription
[dir]current directoryProject to deploy.
--namedirectory nameApp name — also the subdomain.
--port8080Port your app listens on inside the container. It also receives it as $PORT.
--env KEY=VALUE—Environment variable. Repeat the flag for more than one.

What gets uploaded

Everything in the directory except:

  • .env and .env.* files — pass secrets with --env instead
  • .git, node_modules, .next, dist, __pycache__, .venv, venv, .DS_Store
  • *.sqlite files

The compressed upload is limited to 50 MB. .gitignore is not consulted, so move large datasets or media out of the project directory before deploying.

How builds work #

tunr picks the first strategy that applies:

  1. Your Dockerfile — if the project has one, it's used as is.
  2. A slim generated image for Node.js (package.json) and Python (requirements.txt or pyproject.toml). Node apps whose start command is a single node file.js run on a distroless base; others on Alpine. Python runs on a slim base. Images are typically 120–250 MB.
  3. Nixpacks auto-detection for everything else (Go, Ruby, Rust, PHP, Java, …). This works for almost any stack but produces larger images.

Every app runs in its own gVisor sandbox with CPU, memory and disk limits.

Manage apps v0.6.1+ #

tunr apps                          # name, URL and status of every app
tunr apps logs my-app              # last 200 lines of build + runtime logs
tunr apps logs my-app -f           # follow new lines as they arrive
tunr apps logs my-app --tail 0     # everything
tunr apps delete my-app            # remove the app and free the subdomain

To ship a new version, run tunr deploy again with the same --name. You can also see your apps in the dashboard.

Sleep & wake Preview #

Apps scale to zero, so a dozen rarely used internal tools cost about what one does.

StateWhenWhat it means for you
RunningReceiving trafficNormal latency.
PausedAfter ~45 s without requestsThe next request wakes it; typical wake time is ~150 ms.
StoppedAfter ~20 min without requestsThe next request starts the container again — expect a cold start.
  • Health checks don't keep apps awake. Requests from uptime monitors, crawlers and common health endpoints are answered without waking a sleeping app, so a monitored app can still sleep.
  • Open connections do. An app with an open WebSocket or Server-Sent Events stream is never paused while that connection is open.
  • Don't rely on in-memory state or background timers surviving idle periods. Keep state in a database.

HTTP tunnels #

tunr share exposes a local port over HTTPS. WebSockets (including dev-server hot reload) work out of the box.

tunr share --port 3000
tunr share -p 3000 --subdomain myapp               # https://myapp.tunr.sh (Pro)
tunr share -p 3000 --domain preview.example.com    # custom domains — coming soon
tunr share -p 3000 --json --no-open                # machine-readable, don't open a browser

A tunnel is a preview of something on your machine: it goes away when you stop the command or close the laptop. For something that should stay up, deploy it.

Background mode #

tunr start --port 3000     # run as a daemon; survives closing the terminal
tunr status                # list active tunnels (alias: tunr list)
tunr stop                  # stop the daemon
tunr down                  # stop all daemon tunnels

To start a tunnel at boot, install it as a system service (systemd on Linux, launchd on macOS):

tunr service install --port 3000
tunr service status
tunr service uninstall

Multiple tunnels from .tunr.json #

.tunr.json
{
  "tunnels": {
    "frontend": { "port": 3000, "subdomain": "app" },
    "api":      { "port": 8080, "subdomain": "api", "password": "secret" },
    "db":       { "port": 5432, "protocol": "tcp" }
  }
}
tunr up                         # start every tunnel in .tunr.json
tunr up --config ./infra/tunr.json

Each entry accepts port (required), protocol (http, tcp, udp, tls), subdomain, domain, password, demo, freeze and region. tunr config init writes a starter file and tunr config show prints the current one.

TCP, UDP & TLS (experimental) #

tunr tcp --port 5432
tunr udp --port 53
tunr tls --port 8443      # a local TLS port over the same raw transport

The relay exposes a raw tunnel only as a WebSocket stream at wss://<subdomain>.tunr.sh/tunnel/tcp (binary frames carry the bytes). There's no raw TCP/UDP port on the relay yet, so native clients like psql or ssh can't connect directly — you need a client that speaks that WebSocket.

tunr tls is not SNI passthrough and not end-to-end encrypted: the relay terminates TLS for *.tunr.sh and sees the bytes. (Agent Bridge streams are different: they are end-to-end TLS to the customer's connector.) --allow-ip isn't enforced on raw tunnels, so it returns an error. All three accept --json.

Access control #

FlagEffect
--password passHTTP Basic Auth. user:pass sets both; a bare password uses the username admin.
--auth-token TOKENRequire Authorization: Bearer TOKEN — for APIs and webhooks.
--allow-ip CIDR,…Only these addresses may connect, e.g. 203.0.113.0/24,10.0.0.1.
--ttl 30mClose the tunnel automatically after this long (--expire is an alias).

Demo tools #

Flags for showing unfinished work to a client or teammate:

FlagEffect
--demoRead-only mode. POST, PUT, PATCH and DELETE never reach your server; they get a fake JSON success (201 for POST, 200 otherwise) with X-Tunr-Demo-Mode: blocked-mutation, so the UI still looks like it works.
--freezeRemembers the last good responses. If your dev server crashes or returns an error, visitors get the cached copy (marked X-Tunr-Freeze-Cache: HIT) instead of an error page.
--inject-widgetAdds a small feedback button to HTML pages. Messages and JavaScript errors from visitors show up in your terminal.
--auto-login "session=…"Adds this cookie to every request, so viewers skip your login screen.
--qrPrints a QR code of the URL — handy for testing on a phone.
tunr share -p 3000 --demo --freeze --inject-widget --password client:preview

Headers, CORS & routing #

FlagEffect
--header-add "K: v"Add a request header before it reaches your server.
--header-replace "K: v"Overwrite a header, e.g. "Host: myapp.local".
--header-remove KStrip a header.
--x-forwarded-forPass the visitor's IP in X-Forwarded-For.
--original-urlPass the public URL in X-Original-URL.
--cors-origin URL,…Answer CORS preflight requests for these origins.
--route /api=8080Send a path prefix to a different local port. Repeat for more routes.
--proxy URLReach the relay through an HTTP or SOCKS5 proxy (corporate networks).
--regionPreferred relay region. tunr currently runs a single relay in the EU, so this is a hint that takes effect once more regions launch.

Inspector & replay #

Every tunnel records its recent requests locally — they never leave your machine.

tunr open                     # web inspector at http://localhost:19842
tunr logs -f                  # stream requests in the terminal (--json for scripts)
tunr logs --flush             # clear the captured history
tunr replay abc12345          # re-send a captured request to localhost
tunr replay abc12345 --curl   # or print it as a curl command

Replay is the fast way to debug a webhook: trigger it once, then replay it as many times as you need while you fix the handler.

MCP server #

tunr mcp runs a Model Context Protocol server over stdio, so your coding agent can deploy apps, open tunnels and inspect traffic itself.

Claude Code
claude mcp add tunr -- tunr mcp
Claude Desktop · Cursor (.cursor/mcp.json) · Windsurf
{
  "mcpServers": {
    "tunr": { "command": "tunr", "args": ["mcp"] }
  }
}

Then just ask: "deploy this to tunr" or "share port 3000 so I can test on my phone". The cloud tools use the account from tunr login.

Tools #

ToolArgumentsWhat it does
tunr_deploydir, name, port, envBuild and host a directory; returns the live URL.
tunr_list_apps—List deployed apps with URL and status.
tunr_app_logsname*, tail (≤ 1000)Read build and runtime logs — for debugging a failed deploy.
tunr_delete_appname*Delete an app and free its subdomain.
tunr_shareport*, subdomainOpen a temporary tunnel to a running local port.
tunr_status—List active tunnels.
tunr_inspectlimit, methodList captured HTTP requests.
tunr_replayrequest_id*, portReplay a captured request against your local server.
tunr_stoptunnel_id*Close a tunnel.
Agent Bridge adds tunr_list_resources, tunr_request_access, tunr_access_status, tunr_open_access and tunr_close_access (preview) — see Agents over MCP.

* required. tunr_deploy and tunr_share are deliberately separate: deploy means "host this, it should outlive my laptop"; share means "expose what's running right now".

Python SDK #

The SDKs drive the tunr binary, so install the CLI first.

pip install tunr
from tunr import TunrClient, TunnelOptions

client = TunrClient()

tunnel = client.share(port=3000)
print(tunnel.public_url)

secured = client.share(port=8080, opts=TunnelOptions(
    subdomain="myapp", password="demo123", allow_ips=["10.0.0.0/8"], ttl="2h",
))

db = client.tcp(port=5432)     # also: client.udp(), client.tls()

reqs = client.get_requests(tunnel.subdomain)
client.replay_request(tunnel.subdomain, reqs[0]["id"], port=3000)

tunnel.close()

Node.js SDK #

npm install @tunr/cli
import { TunrClient } from '@tunr/cli'

const client = new TunrClient()

const tunnel = await client.share(3000)
console.log(tunnel.publicUrl)

const secured = await client.share(8080, {
  subdomain: 'myapp', password: 'demo123', allowIps: ['10.0.0.0/8'], ttl: '2h',
})

tunnel.on('error', (err) => console.error(err))
await tunnel.close()

CLI commands #

Run tunr <command> --help for every flag.

CommandDescription
connect PreviewRun the Agent Bridge connector (customer side). Subcommands: resource, pg-role, install, uninstall, status, kill, resume. Details.
access CUSTOMER/RESOURCE PreviewOpen a local port to a resource you have a grant for. Subcommands: request, list, status.
catalog PreviewList customer resources your agent can request.
agent PreviewVendor agent identities: create, list, token; hosted agents: deploy, trigger add|list|remove.
grants PreviewCustomer side: list, approve, deny, revoke.
deploy [dir]Build and deploy a project to the tunr cloud.
appsList cloud apps. Subcommands: logs <name>, delete <name>.
shareExpose a local port over HTTPS.
tcp · udp · tlsForward a raw TCP, UDP or TLS port over WebSocket (experimental).
start · stopRun a tunnel as a background daemon / stop it.
statusShow active tunnels and daemon status (alias list).
up · downStart every tunnel in .tunr.json / stop all daemon tunnels.
openOpen the local HTTP inspector.
logsStream captured tunnel requests.
replay <id>Re-send a captured request, or export it as curl.
mcpStart the MCP server (stdio).
login · logoutAuthenticate with tunr.sh / remove stored credentials.
config init · config showCreate / print .tunr.json.
serviceinstall, status, uninstall a boot-time service.
doctorDiagnose installation and connectivity.
updateUpdate to the latest release (alias upgrade).
uninstallRemove tunr, its config and credentials.
versionPrint the version.

Global flags: --relay <url> (use a self-hosted relay) and -v, --verbose (debug logging).

Environment variables #

VariablePurpose
TUNR_RELAY_URLRelay to connect to. Same as --relay; default https://relay.tunr.sh.
TUNR_AGENT_TOKENAgent Bridge: the agent token used by tunr access, tunr catalog and the bridge MCP tools.
TUNR_APP_URLDashboard / login URL; default https://app.tunr.sh.
TUNR_INSTALL_DIRWhere install.sh puts the binary; default /usr/local/bin.
TUNR_WS_EXTRA_ALLOWED_ORIGIN_SUFFIXESExtra WebSocket origins your dev server should accept, comma-separated (e.g. .mycompany.test).

Self-hosting #

The relay, control plane and cloud runner are in the same repository under relay/. Run your own and point the CLI at it:

tunr share --port 3000 --relay https://relay.example.com
# or, for every command:
export TUNR_RELAY_URL=https://relay.example.com

Setup, requirements and capacity planning: SELF_HOSTING.md and SCALING.md.

Licensing. The CLI and SDKs (cmd/, internal/, sdk/) are Apache-2.0. The relay and runner (relay/) are PolyForm Shield 1.0.0: you can run, modify and self-host them, including inside your company, but not to offer a service that competes with tunr.

Troubleshooting #

SymptomFix
unknown command "deploy"Your CLI predates v0.6.1. Run tunr update.
not logged inRun tunr login. Cloud commands need an account.
Custom subdomain requires Pro subscriptionDrop --subdomain for a random URL, or upgrade in the dashboard.
upload is … (>50MB)Move large files (datasets, media, build output) out of the project directory.
Deploy succeeds but the URL errorsMake sure the app listens on 0.0.0.0 and on --port / $PORT. Check tunr apps logs <name>.
Hot reload doesn't connect through a tunnelAdd your dev domain to TUNR_WS_EXTRA_ALLOWED_ORIGIN_SUFFIXES or allow the tunnel origin in your dev server config.
Anything elseRun tunr doctor, then retry with -v for debug logs.

Help & support #

Want to contribute? Start with CONTRIBUTING.md.

Found a mistake? Report it on GitHub © tunr.sh · Privacy · Terms