An Agent Skills-compatible package for safe, comprehensive management of Tailscale Funnel through the local Tailscale CLI.
The skill covers the complete Funnel lifecycle while adding safeguards around operations where the native CLI can affect more configuration than its command name suggests.
- Inspect background public Funnel routes and private Serve handlers
- Expose HTTP/HTTPS backends, files, directories, static text, and Unix sockets
- Configure path-based HTTPS routing
- Manage raw TCP and TLS-terminated TCP forwarding
- Configure PROXY protocol v1/v2
- Disable one exact route without accidentally removing sibling paths
- Guard all-path removal and shared Serve/Funnel reset operations
- Detect when enabling Funnel would make existing private Serve handlers public
- Dry-run every mutation by default
- Parse and summarize native status JSON
- Python 3.10 or newer
- A local
tailscaleCLI with Funnel support - Tailscale 1.52 or newer recommended
- A connected tailnet with MagicDNS, HTTPS, and Funnel policy permissions configured
The wrapper uses only the Python standard library.
Using the Skills CLI:
npx skills add 1am2syman/tailscale-cli-skill --skill tailscale-funnelInstall globally:
npx skills add 1am2syman/tailscale-cli-skill --skill tailscale-funnel --globalFor Pi, you can also clone it directly into the global skill directory:
git clone https://github.com/1am2syman/tailscale-cli-skill.git \
~/.pi/agent/skills/tailscale-funnelcd skills/tailscale-funnel
python3 scripts/funnelctl.py check
python3 scripts/funnelctl.py inspectPlan a persistent HTTPS Funnel without changing anything:
python3 scripts/funnelctl.py on --bg --https 443 --set-path /api localhost:3000Execute after approving the exact public exposure:
python3 scripts/funnelctl.py on --execute --bg \
--https 443 --set-path /api localhost:3000Remove only /api:
python3 scripts/funnelctl.py off --execute \
--https 443 --set-path /apiRemove only the root route:
python3 scripts/funnelctl.py off --execute \
--https 443 --set-path /Funnel makes local resources reachable from the public internet.
on,off, andresetare dry-runs unless--executeis supplied.- HTTPS removal requires an exact
--set-path; root is represented by/. - Removing every HTTPS path requires
--all-paths --confirm-all-paths. - Enabling Funnel on a private Serve port is blocked unless the user explicitly supplies
--allow-publicize-private-port. - Native
tailscale funnel resetclears the shared ServeConfig, including private Serve routes. Execution therefore requires--confirm-serve-and-funnel. - Port
0is rejected because native Tailscale can interpret it as an unset mode and fall back to HTTPS/443. - Foreground Funnel sessions are not reported by native status output; the skill calls this out explicitly.
Read skills/tailscale-funnel/SKILL.md for the complete agent workflow and skills/tailscale-funnel/references/cli-reference.md for detailed CLI behavior.
Tests use synthetic configuration and harmless binaries; they do not modify live Tailscale configuration.
python3 skills/tailscale-funnel/scripts/test_funnelctl.py -vskills/tailscale-funnel/
├── SKILL.md Agent instructions and safety workflow
├── scripts/funnelctl.py Safe Funnel CLI wrapper
├── scripts/test_funnelctl.py Regression tests
└── references/cli-reference.md Detailed native CLI semantics
- Funnel and Serve share the same underlying configuration.
- The most recent Serve/Funnel command determines whether a listener port is private or public.
- Omitting
--set-pathfrom an HTTPSoffcommand selects all handlers on that port. tailscale funnel resetclears both Funnel and Serve configuration in Tailscale v1.98.8.- Native status reports background configuration, not foreground Funnel sessions.
Review every planned command before adding --execute.