8000 docs: landing page and docs site on GitHub Pages by adeelahmad · Pull Request #16 · adeelahmad/Tether · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
8000 Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Docs site

on:
push:
branches: [main]
paths:
- docs/**
- website/**
- mkdocs.yml
- README.md
- SECURITY.md
- CONTRIBUTING.md
- CHANGELOG.md
- .github/workflows/pages.yml
pull_request:
paths:
- docs/**
- website/**
- mkdocs.yml
- SECURITY.md
- CONTRIBUTING.md
- CHANGELOG.md
- .github/workflows/pages.yml
workflow_dispatch:

permissions:
contents: read

concurrency:
group: pages-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.13"
cache: pip
cache-dependency-path: website/requirements.txt
- run: pip install -r website/requirements.txt
- run: mkdocs build --strict
- uses: actions/upload-pages-artifact@v4
with:
path: site

deploy:
name: Deploy
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ Thumbs.db
# Go workspaces
go.work
go.work.sum
/site/
__pycache__/
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
listen on this machine's tailnet address, and optionally publish over HTTPS
with `tailscale serve` (tailnet) or `tailscale funnel` (internet), removed
again on shutdown. Uses the installed tailscale CLI; needs a token.

- Docs site and landing page at <https://adeelahmad.github.io/Tether/>, built
from `docs/` with MkDocs Material and deployed to GitHub Pages on every push
to `main` (`make docs`, `make docs-serve`).
- Per-token and per-session domain policies (`docs/POLICIES.md`): a
`--policy-file` defines named tokens, each with allow/deny rules, an
`admin` flag and a `scripts` permission; `--deny-domains` adds a global
Expand Down
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ GO ?= go
GOLANGCI ?= golangci-lint

.DEFAULT_GOAL := build
.PHONY: help build run test test-integration lint fmt vet tidy cover clean cross vuln check
.PHONY: help build run test test-integration lint fmt vet tidy cover clean cross vuln check docs docs-serve

help: ## Show this help
@awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z_-]+:.*##/ {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
Expand Down Expand Up @@ -68,5 +68,11 @@ cross: ## Static release builds for all platforms into ./dist
-o $(DIST)/$(BINARY)_$${os}_$${arch}$$ext $(CMD) || exit 1; \
done

docs: ## Build the docs site into ./site (pip install -r website/requirements.txt)
mkdocs build --strict

docs-serve: ## Preview the docs site at http://127.0.0.1:8000
mkdocs serve

clean: ## Remove build output
rm -rf bin $(DIST) coverage.out
rm -rf bin $(DIST) coverage.out site
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ One self-contained binary. Speaks MCP, plain HTTP proxy and WebDriver. Drives Ch
[![CI](https://github.com/adeelahmad/tether/actions/workflows/ci.yml/badge.svg)](https://github.com/adeelahmad/tether/actions/workflows/ci.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/adeelahmad/tether)](https://goreportcard.com/report/github.com/adeelahmad/tether)
[![Latest release](https://img.shields.io/github/v/release/adeelahmad/tether?sort=semver)](https://github.com/adeelahmad/tether/releases)
[![Docs](https://img.shields.io/badge/docs-adeelahmad.github.io%2FTether-blue)](https://adeelahmad.github.io/Tether/)
[![License: GPL v3](https://img.shields.io/github/license/adeelahmad/tether)](LICENSE)

<img src="docs/demo.gif" alt="Tether driving a real Chrome tab: curl through the proxy returns a logged-in page" width="760"/>
Expand Down
86 changes: 86 additions & 0 deletions docs/assets/extra.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* Landing page hero (website/overrides/home.html). */
.tx-hero {
background: linear-gradient(135deg, var(--md-primary-fg-color) 0%, #1a237e 60%, #00695c 100%);
color: var(--md-primary-bg-color);
}

.tx-hero__inner {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 2.4rem;
padding: 3.2rem 0.8rem 3.6rem;
}

.tx-hero__copy {
flex: 1 1 22rem;
min-width: 0;
}

.tx-hero__demo {
flex: 1 1 22rem;
min-width: 0;
}

.tx-hero__demo img {
display: block;
width: 100%;
border-radius: 0.4rem;
box-shadow: 0 1rem 2.5rem rgba(0, 0, 0, 0.35);
}

.tx-hero .md-typeset h1 {
color: inherit;
font-weight: 700;
font-size: 2.2rem;
line-height: 1.2;
margin: 0 0 1rem;
}

.tx-hero__eyebrow {
margin: 0 0 0.6rem;
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
opacity: 0.8;
}

.tx-hero__lead {
font-size: 0.95rem;
opacity: 0.92;
}

.md-typeset .tx-hero__actions .md-button {
margin: 0.4rem 0.6rem 0.4rem 0;
color: var(--md-primary-bg-color);
border-color: var(--md-primary-bg-color);
}

.md-typeset .tx-hero__actions .md-button--primary {
background-color: var(--md-accent-fg-color);
border-color: var(--md-accent-fg-color);
color: #fff;
}

.md-typeset .tx-hero__install {
margin-top: 1.2rem;
}

.md-typeset .tx-hero__install code {
background: rgba(0, 0, 0, 0.3);
color: #e0f2f1;
font-size: 0.7rem;
white-space: pre-wrap;
word-break: break-all;
}

@media screen and (max-width: 44.9375em) {
.tx-hero .md-typeset h1 {
font-size: 1.6rem;
}

.tx-hero__inner {
padding: 2rem 0.8rem 2.4rem;
}
}
6 changes: 6 additions & 0 deletions docs/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!-- include: CHANGELOG.md -->
This page is published from [CHANGELOG.md](../CHANGELOG.md) on the docs site.
51 changes: 51 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Configuration

Every flag has a `TETHER_*` environment variable; flags win.

| Flag | Default | |
|---|---|---|
| `--addr` | `127.0.0.1:8787` | Listen address |
| `--token` / `--token-file` | — | Bearer token (≥16 chars); required off-loopback |
| `--insecure-allow-public` | `false` | Allow off-loopback with no token (don't) |
| `--chrome` | `auto` | `auto`, a port, `host:port`, `http://…`, `ws://…`, or a `DevToolsActivePort` path |
| `--launch` / `--headless` | `false` | Launch a dedicated Chrome (persistent profile under `--data-dir`) |
| `--chrome-bin`, `--chrome-args`, `--profile-dir` | auto | With `--launch` |
| `--idle-timeout` | `15m` | Close tabs Tether opened after inactivity (`0` = never) |
| `--timeout` | `60s` | Default per-request timeout |
| `--console-buffer` | `1000` | Console/log entries kept per tab (`0` = no capture) |
| `--allow-domains` | all | Comma-separated navigation allowlist (applies to every face) |
| `--deny-domains` | none | Comma-separated denylist; deny beats allow |
| `--policy-file` | — | JSON file with per-token rules and tokens, see [Policies](POLICIES.md) |
| `--data-dir` | user config dir | Local CA and launched profile |
| `--no-mitm` | `false` | Refuse HTTPS `CONNECT` instead of intercepting |
| `--mcp` | `true` | Serve the MCP face at `/mcp` |
| `--no-remote` | `false` | Don't serve the remote-browser UI at `/remote/` |
| `--remote-quality` | `70` | JPEG quality of the remote UI video (1–100) |
| `--log-level`, `--log-format` | `info`, `text` | `json` for machines; secrets are always redacted |

## From another machine (Tailscale)

```sh
export TETHER_TOKEN="$(openssl rand -hex 32)"
tether serve --launch --addr "$(tailscale ip -4):8787"
# elsewhere on the tailnet:
curl -x "http://tether:$TETHER_TOKEN@my-laptop:8787" --cacert tether-ca.pem https://github.com/
# or watch and drive it from your phone: http://my-laptop:8787/remote/
```

Tether refuses to listen beyond loopback without a token. Read
[Security](security.md) before exposing it anywhere.

## One token per agent

Give every agent its own token with its own domain rules. Each token only
sees the tabs it opened, and the rules are enforced inside the browser, so
redirects, link clicks and page script can't wander off the allowlist either.

```sh
tether serve --policy-file examples/policy.json # tokens + rules, see Policies
curl -s -H "Authorization: Bearer $TETHER_RESEARCH_TOKEN" http://127.0.0.1:8787/tether/v1/whoami
# lock a single tab tighter still
curl -s -H "Authorization: Bearer $TETHER_RESEARCH_TOKEN" -X POST http://127.0.0.1:8787/tether/v1/tabs \
-d '{"url":"https://en.wikipedia.org/","policy":{"allow":["en.wikipedia.org"]}}'
```
2 changes: 2 additions & 0 deletions docs/contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!-- include: CONTRIBUTING.md -->
This page is published from [CONTRIBUTING.md](../CONTRIBUTING.md) on the docs site.
94 changes: 94 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Getting started

Tether is one binary. Install it, point it at a Chrome, and every client that
speaks HTTP proxy, WebDriver or MCP can use that browser, logged-in sessions
and all.

## 1. Install

=== "Go"

```sh
go install github.com/adeelahmad/tether/cmd/tether@latest
```

=== "Homebrew"

```sh
brew install --cask adeelahmad/tap/tether
```

=== "Docker"

Headless Chromium ships inside the image.

```sh
docker run --rm -p 8787:8787 \
-e TETHER_TOKEN=$(openssl rand -hex 32) \
-v tether:/data ghcr.io/adeelahmad/tether
```

=== "Binary"

Download an archive for your platform from
[Releases](https://github.com/adeelahmad/Tether/releases) and put
`tether` on your `PATH`.

## 2. Start

```sh
tether serve --launch
```

This opens a dedicated Chrome window with a persistent profile. Log in to a
site (say, GitHub) once; the profile remembers it.

!!! tip "Prefer your everyday Chrome?"
Skip `--launch`. On Chrome 144+, open `chrome://inspect/#remote-debugging`,
allow remote debugging, and run `tether serve`: it finds the browser
automatically. On any Chrome you can also start it with
`--remote-debugging-port=9222 --user-data-dir=<dir>` (Chrome requires a
non-default profile directory for the debugging port).

## 3. Prove it

In another terminal, fetch a logged-in page through the proxy:

```sh
curl -s http://127.0.0.1:8787/tether/v1/ca.pem -o tether-ca.pem
curl -s -x http://127.0.0.1:8787 --cacert tether-ca.pem https://github.com/settings/profile \
| grep -o '<title>[^<]*</title>'
```

You get your profile settings page, the one that redirects to a login screen
for everyone else.

## Next steps

<div class="grid cards" markdown>

- :material-web: **[HTTP proxy](proxy.md)**

Headers, modes, the control API and console logs.

- :material-robot-outline: **[MCP for agents](MCP.md)**

Connect Claude, Cursor or your own agent.

- :material-language-python: **[WebDriver](WEBDRIVER.md)**

Point Selenium at Tether and run your scripts.

- :material-monitor-eye: **[Remote UI](REMOTE.md)**

Watch and drive any tab from your phone.

- :material-shield-lock-outline: **[Policies](POLICIES.md)**

One token per agent, each with its own domain rules.

- :material-tune: **[Configuration](configuration.md)**

Every flag, environment variable and exposure option.

</div>
Loading
Loading
0