Open Plannotator review and annotation sessions from another device through Tailscale Serve without binding the server beyond localhost.
Use --tailscale to open a Plannotator session from another device on your tailnet. Plannotator keeps its server on 127.0.0.1 and publishes an HTTPS proxy through Tailscale Serve.The session is available only through your tailnet. Plannotator uses Serve, never Tailscale Funnel.
Permit the review device to reach the agent host through your Tailscale access rules.
Enable HTTPS certificates for the tailnet. On first use, Tailscale can open an administrator consent flow.
The review device needs Tailscale and a browser. It does not need the Plannotator CLI.Run tailscale status on the agent host. Before you start Plannotator, resolve any login or daemon error.
Start a remote review
Run Plannotator on the agent host:
plannotator review --tailscale
The same flag works with document annotation and the last-message picker:
Plannotator prints the HTTPS session URL to standard error. An interactive terminal also displays a QR code.Verify that Tailscale is connected on the review device. Scan the QR code or open the printed URL.
--tailscale works in the compiled Plannotator CLI. The Pi extension does not accept this flag.
How the connection works
Plannotator performs these steps for each --tailscale session:
It starts the review server on 127.0.0.1.
It reads the current Tailscale Serve configuration.
It refuses to replace an existing Serve mapping on the selected port.
It runs the following command with the session port:
Tailscale terminates HTTPS and proxies requests to the loopback server.
Plannotator prints the Serve URL and displays a QR code in an interactive terminal.
Plannotator removes its Serve mapping at normal session exit.
Mappings on other ports remain unchanged. A pre-existing mapping on the selected port stops startup instead of being replaced.--tailscale forces local mode for that session. It overrides PLANNOTATOR_REMOTE, SSH detection, and PLANNOTATOR_URL_HOST.
Understand the security boundary
Tailscale Serve makes the session reachable through the tailnet, not the public internet. Tailscale access rules still govern which devices can reach the host.Plannotator does not add a login screen or per-request authentication. Every permitted tailnet peer can use the session UI and its local API.The embedded agent terminal is disabled for --tailscale sessions. Enable it only for a tailnet where every permitted peer is trusted:
This variable exposes command execution through the session UI. Its terminal token is not an authentication boundary.
Advertise a Tailscale host in remote mode
PLANNOTATOR_URL_HOST=auto solves a different problem. It produces a reachable URL for Plannotator remote mode without starting Tailscale Serve.When another system already provides private routing or port forwarding, use this configuration:
Plannotator first reads the machine’s Tailscale MagicDNS name. A fallback requires exactly one Tailscale IPv4 address in 100.64.0.0/10.Detection runs once per process. Detection failure prints a warning and falls back to localhost.This value changes only the advertised URL. Remote mode still binds to 0.0.0.0, and you remain responsible for network access.To make the value persistent, save it in ~/.plannotator/config.json:
{ "urlHost": "auto"}
PLANNOTATOR_URL_HOST takes precedence over urlHost in the configuration file. An empty environment value suppresses the saved value.
Remove a stale Serve mapping
Plannotator removes its mapping after normal exit, SIGINT, SIGTERM, or SIGHUP. Failed cleanup retries once and prints the manual command.SIGKILL or a host restart can leave the background mapping active. Inspect the current configuration:
tailscale serve status
Remove the mapping for the affected port:
tailscale serve --https=<port> off
Do not remove mappings for unrelated ports.
Troubleshoot startup and access
The Tailscale CLI is unavailable or logged out
Run:
tailscale status
Install Tailscale or restore the daemon and sign in. Then run the Plannotator command again.
Tailscale requests HTTPS approval
Complete the administrator consent flow that Tailscale displays. Then run the Plannotator command again.See Set up HTTPS certificates for the tailnet requirement.
The selected port already has a Serve mapping
Inspect the Serve configuration:
tailscale serve status
Remove a stale mapping with the exact command above. Keep an intentional mapping and select another Plannotator port:
Verify that both devices are connected to Tailscale. Verify that access rules permit the review device to reach the host.Then inspect the active mapping:
tailscale serve status
Tailscale documents Serve status and removal commands in its Serve CLI reference.
The QR code is absent
When standard error is an interactive terminal, Plannotator displays the QR code. Use the printed HTTPS URL in other environments.
A gated annotation cannot start
A Tailscale publishing failure returns exit code 1 for a normal command. A strict annotation gate returns exit code 2.Strict gates use --require-approval or --result-file. A startup failure does not create a result file.
Integration limits
Only review, annotate, annotate-last, and its last alias accept --tailscale. Other subcommands reject the flag.Agent hooks do not add --tailscale automatically. When you need tailnet access, start a file gate directly:
See Remote access for trusted private networks, SSH tunnels, and development-container forwarding.Last verified on August 12, 2026, against Plannotator v0.27.0 and product commits 5f33b72 and ed6f44b. Maintained by the Plannotator project.
Last modified on August 13, 2026
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Plannotator","description":"Plannotator product and open-source documentation, planning templates, framework profiles, comparisons, and guides to AI-assisted development.","colors":{"primary":"#6D5BD0","light":"#8A7BE0","dark":"#8A7BE0"},"logo":{"light":"https://mintcdn.com/plannotator/vqDpSTQONLoR6rqS/images/totman_transparent.webp?fit=max\u0026auto=format\u0026n=vqDpSTQONLoR6rqS\u0026q=85\u0026s=979a51a8f7a0fc863c02150b818d7df0","dark":"https://mintcdn.com/plannotator/vqDpSTQONLoR6rqS/images/totman_transparent.webp?fit=max\u0026auto=format\u0026n=vqDpSTQONLoR6rqS\u0026q=85\u0026s=979a51a8f7a0fc863c02150b818d7df0"},"favicon":"https://mintcdn.com/plannotator/R7DK-7odgGi8zHBh/favicon.png?fit=max\u0026auto=format\u0026n=R7DK-7odgGi8zHBh\u0026q=85\u0026s=3ab0d16d5c5acbc3b715b15b24274415","navbar":{"links":[{"href":"https://help.plannotator.ai/workspaces/","label":"Workspaces Help"},{"href":"https://github.com/backnotprop/plannotator","label":"GitHub"},{"href":"https://plannotator.ai","label":"Plannotator.ai"}],"primary":{"type":"button","label":"Open source","href":"/open-source/"}},"footer":{"socials":{}},"search":{"prompt":"Search Plannotator docs and guides…"},"seo":{"metatags":{"canonical":"https://docs.plannotator.ai","og:image":"https://plannotator.ai/assets/plannotator-generic-og-v1.jpg","twitter:image":"https://plannotator.ai/assets/plannotator-generic-og-v1.jpg","twitter:card":"summary_large_image"}},"errors":{"404":{"redirect":false,"title":"Page not found","description":"Use the product switcher, navigation, or search to find a page."}},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","cursor","vscode"],"display":"header"},"metadata":{"timestamp":true},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"plannotator","hasAudioNarration":false,"actualSubdomain":"plannotator","customDomains":["docs.plannotator.ai"],"gitSource":{"type":"github","owner":"plannotator","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":false,"mountPath":"","label":""},"entitlements":{"AI_CHAT":{"status":"ENABLED"}},"buildId":"6aebe80b859848b3a5e3dcb5","clientVersion":"0.0.4128","searchFilterCounts":[{"language":"default","tag":"Open Source","count":53},{"language":"default","tag":"Learn","count":31},{"language":"default","tag":"Planning Library","count":24},{"language":"default","tag":"Code review","count":12},{"language":"default","tag":"Start","count":12},{"language":"default","tag":"Agents","count":10},{"language":"default","tag":"Reference","count":10},{"language":"default","tag":"Templates","count":10},{"language":"default","tag":"Frameworks","count":9},{"language":"default","tag":"AI development workflows","count":9}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":true,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-rbac-roles","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"open-source/tailscale","slug":"/open-source/tailscale","pageMetadata":{"title":"Review Plannotator Sessions over Tailscale","sidebarTitle":"Tailscale remote reviews","description":"Open Plannotator review and annotation sessions from another device through Tailscale Serve without binding the server beyond localhost.","keywords":["Plannotator Tailscale","Tailscale remote review","Tailscale Serve","Plannotator iPad review","Plannotator remote session"],"og:type":"article","href":"/open-source/tailscale"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Open Plannotator review and annotation sessions from another device through Tailscale Serve without binding the server beyond localhost.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Note}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Note)_missingMdxReference(`Note`,true);return _jsxs(_Fragment,{children:[_jsxs(_components.p,{children:[`Use `,_jsx(_components.code,{children:`--tailscale`}),` to open a Plannotator session from another device on your tailnet. Plannotator keeps its server on `,_jsx(_components.code,{children:`127.0.0.1`}),` and publishes an HTTPS proxy through `,_jsx(_components.a,{href:`https://tailscale.com/docs/features/tailscale-serve`,children:`Tailscale Serve`}),`.`]}),`\n`,_jsx(_components.p,{children:`The session is available only through your tailnet. Plannotator uses Serve, never Tailscale Funnel.`}),`\n`,_jsx(Heading,{level:`2`,id:`prerequisites`,children:`Prerequisites`}),`\n`,_jsx(_components.p,{children:`Before you start, verify this configuration:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/open-source/start/installation`,children:`Install or update Plannotator`}),` on the machine that runs your agent.`]}),`\n`,_jsxs(_components.li,{children:[`Run `,_jsx(_components.code,{children:`plannotator --version`}),` and verify `,_jsx(_components.code,{children:`v0.27.0`}),` or later.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`https://tailscale.com/download`,children:`Install Tailscale`}),` on the agent host and review device.`]}),`\n`,_jsx(_components.li,{children:`Connect both devices to the same tailnet.`}),`\n`,_jsx(_components.li,{children:`Permit the review device to reach the agent host through your Tailscale access rules.`}),`\n`,_jsx(_components.li,{children:`Enable HTTPS certificates for the tailnet. On first use, Tailscale can open an administrator consent flow.`}),`\n`]}),`\n`,_jsx(_components.p,{children:`The review device needs Tailscale and a browser. It does not need the Plannotator CLI.`}),`\n`,_jsxs(_components.p,{children:[`Run `,_jsx(_components.code,{children:`tailscale status`}),` on the agent host. Before you start Plannotator, resolve any login or daemon error.`]}),`\n`,_jsx(Heading,{level:`2`,id:`start-a-remote-review`,children:`Start a remote review`}),`\n`,_jsx(_components.p,{children:`Run Plannotator on the agent host:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`plannotator`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` review`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --tailscale`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The same flag works with document annotation and the last-message picker:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`plannotator`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` annotate`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` path/to/spec.md`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --tailscale`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`plannotator`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` annotate-last`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --tailscale`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Plannotator prints the HTTPS session URL to standard error. An interactive terminal also displays a QR code.`}),`\n`,_jsx(_components.p,{children:`Verify that Tailscale is connected on the review device. Scan the QR code or open the printed URL.`}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.code,{children:`--tailscale`}),` works in the compiled Plannotator CLI. The Pi extension does not accept this flag.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`how-the-connection-works`,children:`How the connection works`}),`\n`,_jsxs(_components.p,{children:[`Plannotator performs these steps for each `,_jsx(_components.code,{children:`--tailscale`}),` session:`]}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[`It starts the review server on `,_jsx(_components.code,{children:`127.0.0.1`}),`.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`It reads the current Tailscale Serve configuration.`}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`It refuses to replace an existing Serve mapping on the selected port.`}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`It runs the following command with the session port:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`tailscale`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` serve`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --bg`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --https=`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`port`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` http://127.0.0.1:`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`por`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`t`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`})]}),`\n`]})})}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`Tailscale terminates HTTPS and proxies requests to the loopback server.`}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`Plannotator prints the Serve URL and displays a QR code in an interactive terminal.`}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsx(_components.p,{children:`Plannotator removes its Serve mapping at normal session exit.`}),`\n`]}),`\n`]}),`\n`,_jsx(_components.p,{children:`Mappings on other ports remain unchanged. A pre-existing mapping on the selected port stops startup instead of being replaced.`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`--tailscale`}),` forces local mode for that session. It overrides `,_jsx(_components.code,{children:`PLANNOTATOR_REMOTE`}),`, SSH detection, and `,_jsx(_components.code,{children:`PLANNOTATOR_URL_HOST`}),`.`]}),`\n`,_jsx(Heading,{level:`2`,id:`understand-the-security-boundary`,children:`Understand the security boundary`}),`\n`,_jsx(_components.p,{children:`Tailscale Serve makes the session reachable through the tailnet, not the public internet. Tailscale access rules still govern which devices can reach the host.`}),`\n`,_jsx(_components.p,{children:`Plannotator does not add a login screen or per-request authentication. Every permitted tailnet peer can use the session UI and its local API.`}),`\n`,_jsxs(_components.p,{children:[`The embedded agent terminal is disabled for `,_jsx(_components.code,{children:`--tailscale`}),` sessions. Enable it only for a tailnet where every permitted peer is trusted:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`PLANNOTATOR_AGENT_TERMINAL_REMOTE`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`1`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:` plannotator`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` annotate`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` path/to/spec.md`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --tailscale`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`This variable exposes command execution through the session UI. Its terminal token is not an authentication boundary.`}),`\n`,_jsx(Heading,{level:`2`,id:`advertise-a-tailscale-host-in-remote-mode`,children:`Advertise a Tailscale host in remote mode`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`PLANNOTATOR_URL_HOST=auto`}),` solves a different problem. It produces a reachable URL for Plannotator remote mode without starting Tailscale Serve.`]}),`\n`,_jsx(_components.p,{children:`When another system already provides private routing or port forwarding, use this configuration:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`export`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` PLANNOTATOR_REMOTE`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`1`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`export`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` PLANNOTATOR_URL_HOST`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`auto`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`plannotator`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` review`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Plannotator first reads the machine’s Tailscale MagicDNS name. A fallback requires exactly one Tailscale IPv4 address in `,_jsx(_components.code,{children:`100.64.0.0/10`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`Detection runs once per process. Detection failure prints a warning and falls back to `,_jsx(_components.code,{children:`localhost`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`This value changes only the advertised URL. Remote mode still binds to `,_jsx(_components.code,{children:`0.0.0.0`}),`, and you remain responsible for network access.`]}),`\n`,_jsxs(_components.p,{children:[`To make the value persistent, save it in `,_jsx(_components.code,{children:`~/.plannotator/config.json`}),`:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`3`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"urlHost\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"auto\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`PLANNOTATOR_URL_HOST`}),` takes precedence over `,_jsx(_components.code,{children:`urlHost`}),` in the configuration file. An empty environment value suppresses the saved value.`]}),`\n`,_jsx(Heading,{level:`2`,id:`remove-a-stale-serve-mapping`,children:`Remove a stale Serve mapping`}),`\n`,_jsxs(_components.p,{children:[`Plannotator removes its mapping after normal exit, `,_jsx(_components.code,{children:`SIGINT`}),`, `,_jsx(_components.code,{children:`SIGTERM`}),`, or `,_jsx(_components.code,{children:`SIGHUP`}),`. Failed cleanup retries once and prints the manual command.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`SIGKILL`}),` or a host restart can leave the background mapping active. Inspect the current configuration:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`tailscale`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` serve`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` status`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Remove the mapping for the affected port:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`tailscale`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` serve`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --https=`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`port`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` off`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Do not remove mappings for unrelated ports.`}),`\n`,_jsx(Heading,{level:`2`,id:`troubleshoot-startup-and-access`,children:`Troubleshoot startup and access`}),`\n`,_jsx(Heading,{level:`3`,id:`the-tailscale-cli-is-unavailable-or-logged-out`,children:`The Tailscale CLI is unavailable or logged out`}),`\n`,_jsx(_components.p,{children:`Run:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`tailscale`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` status`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Install Tailscale or restore the daemon and sign in. Then run the Plannotator command again.`}),`\n`,_jsx(Heading,{level:`3`,id:`tailscale-requests-https-approval`,children:`Tailscale requests HTTPS approval`}),`\n`,_jsx(_components.p,{children:`Complete the administrator consent flow that Tailscale displays. Then run the Plannotator command again.`}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://tailscale.com/docs/how-to/set-up-https-certificates`,children:`Set up HTTPS certificates`}),` for the tailnet requirement.`]}),`\n`,_jsx(Heading,{level:`3`,id:`the-selected-port-already-has-a-serve-mapping`,children:`The selected port already has a Serve mapping`}),`\n`,_jsx(_components.p,{children:`Inspect the Serve configuration:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`tailscale`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` serve`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` status`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Remove a stale mapping with the exact command above. Keep an intentional mapping and select another Plannotator port:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`PLANNOTATOR_PORT`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`19433`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:` plannotator`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` review`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --tailscale`})]}),`\n`]})})}),`\n`,_jsx(Heading,{level:`3`,id:`the-url-does-not-open-on-the-review-device`,children:`The URL does not open on the review device`}),`\n`,_jsx(_components.p,{children:`Verify that both devices are connected to Tailscale. Verify that access rules permit the review device to reach the host.`}),`\n`,_jsx(_components.p,{children:`Then inspect the active mapping:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`tailscale`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` serve`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` status`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Tailscale documents Serve status and removal commands in its `,_jsx(_components.a,{href:`https://tailscale.com/docs/reference/tailscale-cli/serve`,children:`Serve CLI reference`}),`.`]}),`\n`,_jsx(Heading,{level:`3`,id:`the-qr-code-is-absent`,children:`The QR code is absent`}),`\n`,_jsx(_components.p,{children:`When standard error is an interactive terminal, Plannotator displays the QR code. Use the printed HTTPS URL in other environments.`}),`\n`,_jsx(Heading,{level:`3`,id:`a-gated-annotation-cannot-start`,children:`A gated annotation cannot start`}),`\n`,_jsxs(_components.p,{children:[`A Tailscale publishing failure returns exit code `,_jsx(_components.code,{children:`1`}),` for a normal command. A strict annotation gate returns exit code `,_jsx(_components.code,{children:`2`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`Strict gates use `,_jsx(_components.code,{children:`--require-approval`}),` or `,_jsx(_components.code,{children:`--result-file`}),`. A startup failure does not create a result file.`]}),`\n`,_jsx(Heading,{level:`2`,id:`integration-limits`,children:`Integration limits`}),`\n`,_jsxs(_components.p,{children:[`Only `,_jsx(_components.code,{children:`review`}),`, `,_jsx(_components.code,{children:`annotate`}),`, `,_jsx(_components.code,{children:`annotate-last`}),`, and its `,_jsx(_components.code,{children:`last`}),` alias accept `,_jsx(_components.code,{children:`--tailscale`}),`. Other subcommands reject the flag.`]}),`\n`,_jsxs(_components.p,{children:[`Agent hooks do not add `,_jsx(_components.code,{children:`--tailscale`}),` automatically. When you need tailnet access, start a file gate directly:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`plannotator`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` annotate`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` path/to/plan.md`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --tailscale`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --gate`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`/open-source/remote-access`,children:`Remote access`}),` for trusted private networks, SSH tunnels, and development-container forwarding.`]}),`\n`,_jsxs(_components.p,{children:[`Last verified on August 12, 2026, against Plannotator `,_jsx(_components.code,{children:`v0.27.0`}),` and product commits `,_jsx(_components.code,{children:`5f33b72`}),` and `,_jsx(_components.code,{children:`ed6f44b`}),`. Maintained by the Plannotator project.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Review Plannotator Sessions over Tailscale","sidebarTitle":"Tailscale remote reviews","description":"Open Plannotator review and annotation sessions from another device through Tailscale Serve without binding the server beyond localhost.","keywords":["Plannotator Tailscale","Tailscale remote review","Tailscale Serve","Plannotator iPad review","Plannotator remote session"],"og:type":"article","href":"/open-source/tailscale"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Prerequisites","slug":"prerequisites","depth":2,"children":[]},{"title":"Start a remote review","slug":"start-a-remote-review","depth":2,"children":[]},{"title":"How the connection works","slug":"how-the-connection-works","depth":2,"children":[]},{"title":"Understand the security boundary","slug":"understand-the-security-boundary","depth":2,"children":[]},{"title":"Advertise a Tailscale host in remote mode","slug":"advertise-a-tailscale-host-in-remote-mode","depth":2,"children":[]},{"title":"Remove a stale Serve mapping","slug":"remove-a-stale-serve-mapping","depth":2,"children":[]},{"title":"Troubleshoot startup and access","slug":"troubleshoot-startup-and-access","depth":2,"children":[{"title":"The Tailscale CLI is unavailable or logged out","slug":"the-tailscale-cli-is-unavailable-or-logged-out","depth":3,"children":[]},{"title":"Tailscale requests HTTPS approval","slug":"tailscale-requests-https-approval","depth":3,"children":[]},{"title":"The selected port already has a Serve mapping","slug":"the-selected-port-already-has-a-serve-mapping","depth":3,"children":[]},{"title":"The URL does not open on the review device","slug":"the-url-does-not-open-on-the-review-device","depth":3,"children":[]},{"title":"The QR code is absent","slug":"the-qr-code-is-absent","depth":3,"children":[]},{"title":"A gated annotation cannot start","slug":"a-gated-annotation-cannot-start","depth":3,"children":[]}]},{"title":"Integration limits","slug":"integration-limits","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"plannotator","siteName":"Plannotator","title":"Review Plannotator Sessions over Tailscale - Plannotator","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-08-13T05:04:23.536Z","gitLastModified":"2026-08-13T03:38:36.000Z","originalFileLocation":"open-source/tailscale.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Open Plannotator review and annotation sessions from another device through Tailscale Serve without binding the server beyond localhost.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Plannotator\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/plannotator/hZJJbeM0ENum3mVc/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/plannotator/hZJJbeM0ENum3mVc/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/plannotator/hZJJbeM0ENum3mVc/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/plannotator/hZJJbeM0ENum3mVc/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/plannotator/hZJJbeM0ENum3mVc/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/plannotator/hZJJbeM0ENum3mVc/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/plannotator/hZJJbeM0ENum3mVc/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/plannotator/hZJJbeM0ENum3mVc/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/plannotator/hZJJbeM0ENum3mVc/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Review Plannotator Sessions over Tailscale - Plannotator\">\u003cmeta data-mint-head property=\"og:description\" content=\"Open Plannotator review and annotation sessions from another device through Tailscale Serve without binding the server beyond localhost.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Plannotator\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.plannotator.ai/open-source/tailscale\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://plannotator.ai/assets/plannotator-generic-og-v1.jpg\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Review Plannotator Sessions over Tailscale - Plannotator\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Open Plannotator review and annotation sessions from another device through Tailscale Serve without binding the server beyond localhost.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://plannotator.ai/assets/plannotator-generic-og-v1.jpg\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/plannotator/hZJJbeM0ENum3mVc/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Plannotator\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#6D5BD0\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.plannotator.ai/open-source/tailscale\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/open-source/tailscale.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.plannotator.ai/#organization\",\"name\":\"Plannotator\",\"url\":\"https://docs.plannotator.ai\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/plannotator/vqDpSTQONLoR6rqS/images/totman_transparent.webp?fit=max\u0026auto=format\u0026n=vqDpSTQONLoR6rqS\u0026q=85\u0026s=979a51a8f7a0fc863c02150b818d7df0\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.plannotator.ai#website\",\"name\":\"Plannotator\",\"url\":\"https://docs.plannotator.ai\",\"publisher\":{\"@id\":\"https://docs.plannotator.ai/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.plannotator.ai/open-source/tailscale#webpage\",\"url\":\"https://docs.plannotator.ai/open-source/tailscale\",\"name\":\"Review Plannotator Sessions over Tailscale\",\"description\":\"Open Plannotator review and annotation sessions from another device through Tailscale Serve without binding the server beyond localhost.\",\"dateModified\":\"2026-08-13T03:38:36.000Z\",\"isPartOf\":{\"@id\":\"https://docs.plannotator.ai#website\"},\"breadcrumb\":{\"@id\":\"https://docs.plannotator.ai/open-source/tailscale#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.plannotator.ai/open-source/tailscale#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Start\",\"item\":\"https://docs.plannotator.ai/open-source\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Review Plannotator Sessions over Tailscale\",\"item\":\"https://docs.plannotator.ai/open-source/tailscale\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.plannotator.ai/open-source/tailscale#article\",\"headline\":\"Review Plannotator Sessions over Tailscale\",\"name\":\"Review Plannotator Sessions over Tailscale\",\"description\":\"Open Plannotator review and annotation sessions from another device through Tailscale Serve without binding the server beyond localhost.\",\"url\":\"https://docs.plannotator.ai/open-source/tailscale\",\"mainEntityOfPage\":{\"@id\":\"https://docs.plannotator.ai/open-source/tailscale#webpage\"},\"image\":\"https://plannotator.ai/assets/plannotator-generic-og-v1.jpg\",\"dateModified\":\"2026-08-13T03:38:36.000Z\",\"keywords\":\"Plannotator Tailscale, Tailscale remote review, Tailscale Serve, Plannotator iPad review, Plannotator remote session\",\"publisher\":{\"@id\":\"https://docs.plannotator.ai/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.plannotator.ai#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Plannotator\",\"publisher\":{\"@type\":\"Organization\",\"name\":\"Plannotator\"},\"provider\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","agentPointerHref":"/open-source/tailscale.md","siteName":"Plannotator","nav":{"global":null,"products":[{"product":"Plannotator","icon":"house","pages":[{"title":"Plannotator","href":""}]},{"product":"Open Source","icon":"code-branch","groups":[{"group":"Start","pages":[{"title":"Plannotator OSS Documentation","sidebarTitle":"Overview","href":"/open-source"},{"title":"Install Plannotator","sidebarTitle":"Installation","href":"/open-source/start/installation"},{"title":"Plannotator Open Source Security","sidebarTitle":"Security","href":"/open-source/security"},{"title":"Self-Host Plannotator's Deprecated Share Services","sidebarTitle":"Self-hosting","href":"/open-source/self-hosting"},{"title":"Set Up the Plannotator Inbox for Your Coding Agents","sidebarTitle":"Inbox","description":"Start the Plannotator Inbox, connect Claude Code, Codex, Pi, OpenCode, or another MCP client, and answer agent questions without holding a session open.","href":"/open-source/inbox"},{"title":"Review Plannotator Sessions over Tailscale","sidebarTitle":"Tailscale remote reviews","href":"/open-source/tailscale"},{"title":"Open Plannotator on Another Device","sidebarTitle":"Remote access","description":"Open a Plannotator session from a phone, tablet, local browser, or another computer through Tailscale, a trusted private network, SSH, or a development-container port forward.","href":"/open-source/remote-access"},{"title":"Install and Manage Plannotator Skills","sidebarTitle":"Skills","href":"/open-source/start/skills"},{"title":"Annotate Your First Plan","sidebarTitle":"Quickstart: Planning","href":"/open-source/start/quickstart"},{"title":"Review Your First Code Change","sidebarTitle":"Quickstart: Code Review","href":"/open-source/start/code-review-quickstart"},{"title":"Open Plannotator","sidebarTitle":"Open Plannotator","href":"/open-source/start/open-plannotator"},{"title":"Turn Plannotator Feedback into Agent Skills","sidebarTitle":"Compound value","href":"/open-source/start/compound-value"}]},{"group":"Plans and documents","pages":[{"title":"Review an AI Coding Plan with Plannotator","sidebarTitle":"Plan review","href":"/open-source/workflows/plan-review"},{"title":"Open and Annotate Markdown, Documents, URLs, and Folders","sidebarTitle":"Documents","href":"/open-source/workflows/documents"},{"title":"Annotate a Folder with Plannotator","sidebarTitle":"Folders","href":"/open-source/workflows/folders"},{"title":"Annotate HTML in Plannotator","sidebarTitle":"HTML","href":"/open-source/workflows/html"},{"title":"Add Annotations and Send Feedback","sidebarTitle":"Annotations and feedback","href":"/open-source/workflows/annotations-and-feedback"},{"title":"Answer Your Agent's Questions Asynchronously","sidebarTitle":"Questions","href":"/open-source/workflows/questions"},{"title":"Use Local Version History and Plan Diffs","sidebarTitle":"Version history","href":"/open-source/workflows/version-history"},{"title":"Share a Plannotator Session","sidebarTitle":"Sharing","href":"/open-source/workflows/sharing"}]},{"group":"Code review","pages":[{"title":"Code Review with Plannotator","sidebarTitle":"Code review overview","href":"/code-review/index"},{"title":"Review local code changes","sidebarTitle":"Local changes","href":"/open-source/workflows/local-changes"},{"title":"Review GitButler Workspaces, Stacks, and Branches","sidebarTitle":"GitButler","href":"/open-source/workflows/gitbutler"},{"title":"Review pull requests and merge requests","sidebarTitle":"Pull requests and merge requests","href":"/open-source/workflows/pull-requests"},{"title":"Ask AI during a review","sidebarTitle":"Ask AI","href":"/open-source/workflows/ask-ai"},{"title":"Ask This Session: Ask AI Answered by Your Agent","sidebarTitle":"Ask this session","href":"/open-source/workflows/ask-this-session"},{"title":"Run Agent Reviews, Code Tours, and Guided Reviews","sidebarTitle":"Agent and guided reviews","href":"/open-source/workflows/agent-reviews"}]},{"group":"Reference","pages":[{"title":"Automate and Customize Plannotator","sidebarTitle":"Reference overview","href":"/open-source/reference/index"},{"title":"Plannotator CLI reference","sidebarTitle":"CLI","href":"/open-source/reference/cli"},{"title":"Configure Plannotator","sidebarTitle":"Configuration","href":"/open-source/reference/configuration"},{"title":"Plannotator environment variables","sidebarTitle":"Environment variables","href":"/open-source/reference/environment-variables"},{"title":"Plannotator OSS Privacy and Data Flow","sidebarTitle":"Privacy and data flow","href":"/open-source/reference/privacy-and-data-flow"},{"title":"Customize Feedback","sidebarTitle":"Custom feedback","href":"/open-source/reference/custom-feedback"},{"title":"Plannotator keyboard shortcuts","sidebarTitle":"Keyboard shortcuts","href":"/open-source/reference/keyboard-shortcuts"},{"title":"Use Plannotator Approval Gates and Automation Hooks","sidebarTitle":"Gates and hooks","href":"/open-source/reference/hooks"},{"title":"Plannotator Local Server and API","sidebarTitle":"Local server and API","href":"/open-source/reference/local-api"},{"title":"Add external annotations to Plannotator","sidebarTitle":"External annotations","href":"/open-source/reference/external-annotations"}]},{"group":"Agents","pages":[{"title":"Choose Your Agent","sidebarTitle":"Agents","href":"/open-source/agents/index"},{"title":"Use Plannotator with Claude Code","sidebarTitle":"Claude Code","href":"/open-source/agents/claude-code"},{"title":"Use Plannotator with Codex","sidebarTitle":"Codex","href":"/open-source/agents/codex"},{"title":"Use Plannotator with OpenCode","sidebarTitle":"OpenCode","href":"/open-source/agents/opencode"},{"title":"Use Plannotator with Copilot CLI","sidebarTitle":"Copilot CLI","href":"/open-source/agents/copilot-cli"},{"title":"Use Plannotator with Gemini CLI","sidebarTitle":"Gemini CLI","href":"/open-source/agents/gemini-cli"},{"title":"Use Plannotator with Pi","sidebarTitle":"Pi","href":"/open-source/agents/pi"},{"title":"Use Plannotator with Amp","sidebarTitle":"Amp","href":"/open-source/agents/amp"},{"title":"Use Plannotator with Droid","sidebarTitle":"Droid","href":"/open-source/agents/droid"},{"title":"Use Plannotator with Kiro CLI","sidebarTitle":"Kiro CLI","href":"/open-source/agents/kiro-cli"}]},{"group":"Editors and notes","pages":[{"title":"Open Plannotator in VS Code","sidebarTitle":"VS Code","href":"/open-source/agents/vscode"},{"title":"Open review files in Zed","sidebarTitle":"Zed","href":"/open-source/agents/zed"},{"title":"Save Plannotator Plans to Obsidian or Bear","sidebarTitle":"Obsidian and Bear","href":"/open-source/agents/notes"},{"title":"Save Plannotator Plans to Octarine","sidebarTitle":"Octarine","href":"/open-source/agents/octarine"}]},{"group":"Troubleshooting","pages":[{"title":"Troubleshoot Plannotator","sidebarTitle":"Troubleshooting","href":"/open-source/troubleshooting"}]},{"group":"Related project","pages":[{"title":"Artifact Server: A Local Workspace for AI Agent Artifacts","sidebarTitle":"Artifact Server","href":"/open-source/artifact-server"}]}]},{"product":"Planning Library","icon":"books","pages":[{"title":"Planning Library","href":"/templates"}]},{"product":"Learn","icon":"graduation-cap","pages":[{"title":"Learn","href":"/learn"}]}]},"basePath":"","title":"Review Plannotator Sessions over Tailscale - Plannotator","buildId":"dpl_5tKr6cUUeuVJdEZ9JAEY3h4soMJ8","deploymentId":"dpl_5tKr6cUUeuVJdEZ9JAEY3h4soMJ8","dynamics":[],"chunks":[]}