Agent Controller has two deliberately different remote-access models:
- Managed cloud (the production design): controllers and browsers connect to the stable Agent Controller HTTPS/WSS origin. A connector running beside T3 Code initiates an authenticated outbound connection to that cloud service and proxies T3 commands and events.
- Self-hosted/advanced: an operator exposes a locally running gateway or T3 server through Tailscale Serve, Funnel, or another independently secured network path.
Do not combine the two into one setup contract. Managed cloud does not require the cloud service to join a user's Tailnet, reach a LAN address, or accept a standing T3 token. Direct Tailscale/Funnel gateway access remains useful for development and self-hosting, but it is not the production cloud topology.
The intended path is:
controller or browser ── HTTPS/WSS ── Agent Controller cloud
│
└── authenticated WSS ── connector CLI ── local/Tailnet T3
The local connector:
- redeems a short-lived, single-use code created by the signed-in user;
- receives a revocable environment-scoped credential, separate from platform, device, factory, and T3 credentials;
- discovers or safely launches T3 on the user's machine;
- stores the T3 access material locally rather than sending it to the cloud;
- maintains heartbeat, reconnect, replay, backpressure, and truthful offline/reconnecting state;
- proxies commands, events, terminal results, approvals, questions, cancellation, and thread subscriptions over the outbound channel.
The repository contains the connector package and its bin entry. The eventual install-free command
has this shape:
npx @agent-controller/connector connect \
--server 'https://controller.example.com' \
--code 'one-time-code'The package has not been published, and the managed cloud has not been deployed from this checkout. Until publication, developers can run the package from a repository checkout; that is local evidence, not proof of the install-free production journey.
When DEPLOYMENT_MODE=cloud, connector enrollment is the supported T3 path. Direct environment URL
and token creation are disabled, and onboarding intentionally hides gateway Serve/Funnel controls.
Readiness is proof-gated: a socket acknowledgement alone does not count as a working environment.
The flow must observe the selected environment, project, provider and model, then a completed command
with a newer T3 reply before presenting the journey as ready. That contract is locally tested; a
deployed first-reply journey remains unproven.
Tailscale may run on the same user machine as T3 and the connector. It can provide a private route from the connector to a T3 process elsewhere in that user's Tailnet, but it is not required when T3 is reachable over loopback.
Production rules:
- ESP32 controllers do not run Tailscale.
- The Agent Controller cloud account does not join the user's Tailnet.
- No inbound port or public T3 endpoint is required for the common path.
- Tailscale access does not replace Agent Controller authentication or connector authorization.
- Cached environment state must be shown as stale/offline until the connector proves liveness.
The packaged connector reports this optional layer through status and doctor. It performs only a
bounded tailscale status --json read and emits a privacy-minimal projection; raw peer, user,
Tailnet, hostname, and address data never enters its report. Missing or disconnected Tailscale adds
static, operator-directed guidance but does not make connector health fail by itself. The actual T3
reachability check remains authoritative.
The connector does not install Tailscale, run tailscale up, authenticate the machine, or inspect or
change Serve/Funnel configuration. Those are explicit operator actions. This keeps the managed cloud
path outbound-only and prevents a diagnostic or enrollment command from changing an independently
managed network boundary.
The commands in this section apply to a gateway that the operator runs locally. They are not needed for the managed-cloud service.
Tailscale Serve gives a self-hosted gateway a stable MagicDNS HTTPS URL and limits access to devices and users permitted by the Tailnet policy.
Prerequisites:
- Install Tailscale on the gateway host.
- Sign in and confirm
tailscale statusreports the device as connected. - Install Tailscale on each remote phone or computer that should open the private URL.
- Keep Agent Controller authentication enabled. Tailnet access is an additional boundary, not a replacement for Clerk.
Run:
npm run setup:tunnel -- --mode serve --write-envThe command checks Tailscale, proxies HTTPS to http://127.0.0.1:3996, prints the MagicDNS URL,
updates PUBLIC_BASE_URL, and appends the origin to CLERK_AUTHORIZED_PARTIES. Restart the gateway
after .env changes:
npm startDisable the persistent mapping with:
npm run setup:tunnel -- --mode serve-offFunnel publishes the self-hosted gateway to the public internet. Use it only when the client cannot join the Tailnet and public reachability is intentionally required:
npm run setup:tunnel -- --mode funnel --write-envThe setup command refuses Funnel when Agent Controller uses development authentication. The
--allow-public override is for operators who have independently installed another production
authentication layer; it is not a safe bypass for an unprotected gateway.
Before using Funnel, verify Clerk at the public origin, retain rate limits, keep all credentials out of URLs and screenshots, and revoke unrecognized sessions. Disable the mapping with:
npm run setup:tunnel -- --mode funnel-offThe repository retains a direct environment transport for development and self-hosting. A running T3 server can configure Tailscale Serve and mint a one-time pairing credential with:
npx t3 pair --tailscaleA repository-managed local environment can use:
npm run setup:t3 -- --project '/path/to/project' --tunnel tailscaleThis path requires the self-hosted gateway to reach the T3 Serve URL. If they run on different machines, both machines need an allowed Tailnet path. It also means the gateway participates in the T3 trust boundary, so protect T3 credentials and keep authentication enabled.
Do not use this direct URL/token flow as a workaround in cloud mode. The public cloud service must not make arbitrary requests into LAN, Tailnet, or user-supplied origins; the connector is the application bridge and SSRF boundary.
ESP32 controllers do not normally run Tailscale. For a self-hosted gateway reached over local Wi-Fi, listen on the LAN interface:
HOST=0.0.0.0Point the device at the gateway host's LAN URL, for example http://192.168.1.162:3996. Use HTTPS
with verified trust anchors for any production credential path; plain HTTP is a local-bench path.
If no LAN devices need the gateway, binding to 127.0.0.1 reduces direct LAN exposure.
- Confirm the connector is using the exact cloud origin and an unexpired one-time code.
- Check that local T3 is running or that the connector can launch it.
- Distinguish
offline,reconnecting,accepted,completed, approval, and user-input states; an accepted dispatch is not a completed agent turn. - Re-enroll after credential revocation or rotation. The old socket should be closed and must not resume with the replaced credential.
- A local contract test does not prove hosted Service Binding, WAN, sleep/wake, or live-T3 behavior.
Run agent-controller-connect doctor --json for the redacted cloud, T3, service, credential-storage,
and optional Tailscale projection. If its tailscale.guidance array contains an action and this T3
path actually uses the Tailnet, complete that action yourself and rerun doctor. Do not configure
Serve for the managed-cloud connector; its cloud channel is outbound.
Install Tailscale, launch the app, sign in, and run tailscale status. On macOS, the setup command
checks both PATH and the standard Tailscale application CLI location.
- Restart Agent Controller after
--write-envchanges.env. - Confirm
PUBLIC_BASE_URLis the printed HTTPS origin. - Confirm
CLERK_AUTHORIZED_PARTIESincludes that origin. - Add the origin in Clerk if the frontend reports an origin or redirect restriction.
Confirm the phone is signed in to Tailscale, both devices appear in tailscale status, Tailnet ACLs
allow the path, and tailscale serve status reports the proxy.
The first Funnel setup can require administrator consent, MagicDNS, HTTPS certificates, and the Funnel node attribute. Follow the URL printed by the Tailscale CLI and retry after approval.