Tailscale preview command plugin for Takopi
Project description
takopi-preview
preview command plugin for takopi. exposes existing local ports via
tailscale serve, and tracks preview sessions by project/worktree context.
published as the takopi-preview package. the command id is preview.
features
/previewcommands to start, list, stop, and clean up previews- per-project overrides for ports
- session registry with ttl expiration
- allowlist support for sensitive commands (like
killall)
requirements
- python 3.14+
- takopi >= 0.20
- provider tooling:
- tailscale installed and authenticated on the host (
tailscale up)
- tailscale installed and authenticated on the host (
- the service you want to share binds to 127.0.0.1 (tunnels proxy locally)
- security groups should not expose the local service port publicly
install
install into the same environment as takopi.
uv tool install -U takopi
uv tool install -U takopi --with takopi-transport-slack --with takopi-preview
or, with a virtualenv:
pip install takopi-transport-slack takopi-preview
setup
- install tailscale and authenticate (
tailscale up). - enable magicdns so
DEVICE.TAILNET.ts.netresolves. (https://tailscale.com) - run takopi with your transport (slack or telegram) as usual.
configuration
add to ~/.takopi/takopi.toml:
[plugins]
enabled = ["takopi-transport-slack", "takopi-preview"]
[plugins.preview]
provider = "tailscale"
default_port = 3000
ttl_minutes = 120
path_prefix = "/preview"
tailscale_https_port = 443
allowed_user_ids = [123456789]
local_host = "127.0.0.1"
tailscale_bin = "tailscale"
# per-project overrides (Takopi project tables are strict, so use plugins.preview.projects)
[plugins.preview.projects.myapp]
port = 5173
notes:
provider = "tailscale"uses tailnet-only urls fromtailscale serve.- preview only configures tailscale serve; start your dev server separately.
- takopi-preview is a command backend plugin that registers
/previewand managestailscale serveentries based on takopi context/worktrees. ttl_minutes = 0disables expiration.- empty
allowed_user_idsmeans no allowlist enforcement.
commands
/preview start [port]: start a preview for the current context/preview list: show active previews (url, port, uptime, context)/preview stop [id|port]: stop a preview (defaults to current context)/preview killall: stop all previews (restricted by allowlist)/preview help: usage help
workflow
- choose a context:
/myapp @feat/loginor reply in an existing thread. previews only run in worktrees, so include a branch to create/use one. - start your dev server in that worktree (ex:
pnpm dev -- --port 5173). - run
/preview start(or/preview start 5173). - open the returned url, for example:
https://DEVICE.TAILNET.ts.net/preview/5173
- stop when done:
/preview stopor/preview stop 5173.
common setups
vite / web apps
Allow tailnet hosts and bind to localhost:
server: {
host: "127.0.0.1",
port: 5173,
allowedHosts: [".ts.net"],
},
Start the dev server, then run /preview start 5173.
react native (metro)
Metro expects requests at the root path, so use path_prefix = "/" and a
dedicated HTTPS port for the Metro port (example: 8081).
metro.config.js example:
const config = getDefaultConfig(__dirname);
const metroPort = Number(process.env.METRO_PORT || 8081);
config.server = {
...config.server,
port: metroPort,
};
module.exports = config;
Start Metro bound to localhost:
METRO_PORT=8081 bun start:dev -- --host localhost --port 8081
Expose it over tailnet:
/preview start 8081
On devices, set the dev server host/port to HOST.TAILNET.ts.net:8081 in the
React Native dev menu.
If your dev client cannot use HTTPS, skip takopi-preview and connect directly
to the tailnet IP by running Metro with --host 0.0.0.0.
state and ttl
- tailscale: sessions are derived from
tailscale serve status; no preview state file is written. - tailscale: if the requested port is already served, takopi will attempt to disable the existing serve entry before starting a new preview.
- tailscale: set
path_prefix = "/"to serve from the tailnet root. This avoids subpath issues with apps that assume/, but only one preview can be served at a time with the built-in config. Usepath_prefix = "/preview"if you need multiple concurrent previews. - tailscale: the default HTTPS port is
443, so previews map tohttps://host.ts.net/preview/<port>(orhttps://host.ts.net/whenpath_prefix = "/"). Settailscale_https_port = 0to use the preview port (forhttps://host.ts.net:3000/). When using per-port HTTPS, start the dev server on127.0.0.1(no--host 0.0.0.0) so tailscale can bind the public port without conflicts.
ttl_minutes controls automatic expiration for previews started by this takopi
process; expired sessions are cleaned up on the next command invocation.
worktrees that are pruned or deleted are also cleaned up on the next command.
takopi shutdown stops all previews.
errors
- missing tailscale: follow the install docs and run
tailscale up. - serve disabled: enable serve for your tailnet (Tailscale admin UI) if you see the "Serve is not enabled" error.
- preview already active: if a port is already served, takopi will stop the existing serve entry before re-enabling it.
- service not reachable: ensure your dev server is running and bound to
local_host(default127.0.0.1). - not in a worktree: include a branch (ex:
/myapp @feat/foo) to create/use a worktree.
spec alignment
this implementation follows the webapp preview workflow spec:
- command surface: start/list/stop/killall/help
- config in
[plugins.preview]with per-project overrides - tailscale serve for tailnet-only preview urls
- tailscale serve registry
- ttl-based expiration (
ttl_minutes) - allowlist enforcement via
allowed_user_ids
license
mit
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file takopi_preview-0.1.16.tar.gz.
File metadata
- Download URL: takopi_preview-0.1.16.tar.gz
- Upload date:
- Size: 11.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b5120e0199bf76b439376bf2ebaeaf68a5451468bba259eeaf0bf610632d8d7
|
|
| MD5 |
0bd0d1fb7a56a3d85cd552ce476d3ada
|
|
| BLAKE2b-256 |
eb5a6c6db1dd38b90a3ff2c9250cb2f7be1f2450bab2d59817a12b4a38dd7e15
|
Provenance
The following attestation bundles were made for takopi_preview-0.1.16.tar.gz:
Publisher:
workflow.yml on richardliang/takopi-preview
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
takopi_preview-0.1.16.tar.gz -
Subject digest:
0b5120e0199bf76b439376bf2ebaeaf68a5451468bba259eeaf0bf610632d8d7 - Sigstore transparency entry: 844236245
- Sigstore integration time:
-
Permalink:
richardliang/takopi-preview@ce88c65eaecb245e5ee5e57e3193b1bae77c0bcf -
Branch / Tag:
refs/tags/v0.1.16 - Owner: https://github.com/richardliang
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@ce88c65eaecb245e5ee5e57e3193b1bae77c0bcf -
Trigger Event:
push
-
Statement type:
File details
Details for the file takopi_preview-0.1.16-py3-none-any.whl.
File metadata
- Download URL: takopi_preview-0.1.16-py3-none-any.whl
- Upload date:
- Size: 12.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77fe0a13cd295c9bf7585d997e98f0752d4f2bb24014af33f761c94594af74f5
|
|
| MD5 |
a8c3eea8c03cd048fe7a77c7351e7565
|
|
| BLAKE2b-256 |
1d311ee2d4026a7d62d393e8f9b0acfeebd8fbc200ba9903daccdeb5585da520
|
Provenance
The following attestation bundles were made for takopi_preview-0.1.16-py3-none-any.whl:
Publisher:
workflow.yml on richardliang/takopi-preview
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
takopi_preview-0.1.16-py3-none-any.whl -
Subject digest:
77fe0a13cd295c9bf7585d997e98f0752d4f2bb24014af33f761c94594af74f5 - Sigstore transparency entry: 844236249
- Sigstore integration time:
-
Permalink:
richardliang/takopi-preview@ce88c65eaecb245e5ee5e57e3193b1bae77c0bcf -
Branch / Tag:
refs/tags/v0.1.16 - Owner: https://github.com/richardliang
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@ce88c65eaecb245e5ee5e57e3193b1bae77c0bcf -
Trigger Event:
push
-
Statement type: