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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 44 additions & 9 deletions DEPLOY.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,54 @@
# Deploy
# Deploy the hosted Wingthing coordinator

## Fly.io Setup (one-time)
Wingthing is a typed agent manager for durable agent runs and terminals. This Fly
deployment hosts `wingthing.ai`: identity, the authorized wing directory, key
exchange, connection coordination, the web portal, and the optional encrypted
relay. It does not run users' agents.

## Deployment boundary

| Decision | Hosted deployment |
| --- | --- |
| **Execution wing** | A user's laptop, VM, or self-hosted machine selected by `wing_id`; the Fly login and edge processes are coordinators, not execution wings. |
| **Workspace** | An existing path on that selected wing. The hosted service does not create, clone, upload, or synchronize workspaces. |
| **Display** | Direct MCP gives a parent agent semantic runs and persistent PTYs. The hosted browser terminal and control relay require relay entitlement; self-hosted and SSH displays remain separate compatible paths. |
| **Provider credentials** | The execution owner's provider-agent home on the selected wing. Provider tokens and SSH keys do not belong in Fly secrets, MCP arguments, or prompts. |
| **Durable memory** | Gateway account, organization, auth, entitlement, and routing records persist on the login volume. Run/task records, eggs, Wingthing prompt memory, provider history, and project files remain wing-local. Edge processes are stateless. |

## One-time Fly setup

From a checkout whose `fly.toml` still targets the intended app and region:

```bash
flyctl apps create wingthing
flyctl volumes create wt_data --region ewr --size 1
flyctl secrets set WT_JWT_KEY=$(wt keygen)
fly apps create wingthing
fly volumes create wt_data --region ewr --size 1
fly secrets set WT_JWT_KEY=$(wt keygen)
```

## Deploy
Configure the OAuth, email, and optional billing secrets required by this hosted
installation. If the login, app, and WebSocket endpoints use separate hosts, set
`WT_APP_HOST` and `WT_WS_HOST` consistently and provision DNS/TLS for each one.
The checked-in production base URL is `https://wingthing.ai`; the application and
wing endpoints are `app.wingthing.ai` and `ws.wingthing.ai`.

## Promote and deploy

The public documentation and installer are a versioned contract. Publish and
verify the matching GitHub release before deploying its site:

```bash
flyctl deploy
git tag vX.Y.Z
git push origin vX.Y.Z
gh release view vX.Y.Z
curl -fsSL https://wingthing.ai/install.sh | sh
make deploy
```

## DNS
`make deploy` runs the documentation/web build, Go tests, binary build, release
command-surface check, and N-1/current compatibility gate before `fly deploy`. It
does not create a GitHub release. Use a full clone with tags so the compatibility
gate can find its published baseline.

Point `wt.ai` to fly: `flyctl certs create wt.ai`
Do not replace this sequence with a bare `fly deploy`. For split login/edge
rollouts, relay policy, DNS, scaling, rollback constraints, and verification, use
the [Fly operations guide](docs/fly-ops.md).
23 changes: 19 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

[![ci](https://github.com/ehrlich-b/wingthing/actions/workflows/ci.yml/badge.svg)](https://github.com/ehrlich-b/wingthing/actions/workflows/ci.yml)

Wingthing is an agent manager for agents. Give Codex, Claude, or another parent
agent one typed control plane for starting and supervising durable agents across
all your machines. A person can inspect or take over the same sessions from a
terminal or browser.
Wingthing is a typed agent manager for durable agent runs and terminals. Give
Codex, Claude, or another parent agent one control plane for starting and
supervising work across all your machines. A person can inspect or take over the
same terminal sessions from a terminal or browser.

The agents run where the code and hardware already live. Wingthing keeps their
terminals alive, records semantic runs as durable tasks, applies sandbox policy,
Expand Down Expand Up @@ -133,6 +133,20 @@ person: CLI or browser ----------------/ (inspect or take over)
| **Egg** | The per-session execution boundary: process, PTY, sandbox policy, and local control socket. |
| **Roost** | The self-hosted bundle started by `wt roost start`: a portal/gateway and an embedded wing in one process. Other wings may register with its gateway. |

### Place every run explicitly

| Question | Wingthing's contract |
| --- | --- |
| **Execution** | Select the wing that will run the process. Direct remote calls require its `wing_id`; Wingthing never substitutes another wing. |
| **Workspace** | Pass a `cwd` that already exists on that wing. Wingthing does not clone, create, or synchronize repositories. |
| **Display** | Use `agent_run` for semantic status and a final result without a live browser view. Use `agent_start` when the task needs a PTY that a person can attach to from the CLI, SSH, or an entitled/self-hosted browser. |
| **Credentials** | The provider CLI reads credentials from the execution owner's agent home on that wing. Shared hosts separate those homes by owner. Do not put provider tokens or SSH keys in prompts or MCP arguments. |
| **Durable memory** | Wingthing stores task, result, message, and thread records in `~/.wingthing/wt.db`, session state under `~/.wingthing/eggs`, and optional prompt memory under `~/.wingthing/memory`. Provider-native history stays in the provider home. These are wing-local unless the operator arranges replication. |

`WINGTHING_DIR` changes the `~/.wingthing` state root. A terminal survives client
detachment, but not an unplanned host restart. A run's record and result persist;
an active headless run still depends on the supervising Wingthing process.

`wingthing.ai` is the hosted identity, directory, key-exchange, and connection
coordination service—roughly the control plane in a tailnet. It does not run the
agents. New free accounts use direct remote MCP; Pro adds the encrypted hosted
Expand Down Expand Up @@ -329,6 +343,7 @@ Update an installed binary with `wt update`.

## Documentation

- [Agent-facing Wingthing skill](SKILL.md)
- [Choose a usage pattern](https://wingthing.ai/patterns)
- [Web documentation](https://wingthing.ai/docs)
- [Historical LLM-first architecture review](docs/llm-first-review.md)
Expand Down
45 changes: 45 additions & 0 deletions SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
name: wingthing
description: Use Wingthing's typed control plane to start and supervise coding agents in durable runs or terminals on local and remote wings.
---

# Use Wingthing

## Place the work first

Before launching, identify:

- the execution wing;
- an existing `cwd` on that wing;
- whether the human display is a terminal, browser terminal, or no live display;
- which Wingthing owner and provider-agent home supply credentials; and
- which wing holds the task record, provider history, and optional Wingthing memory.

Wingthing routes control. It does not create or synchronize workspaces, credentials,
or memory across wings.

## Run safely

1. Call `wingthing_capabilities` before relying on an operation or agent.
2. On `wt mcp connect`, call `wing_list` and pass the chosen `wing_id` to every
wing-owned operation. Never rely on a current or default remote wing.
3. Call `sandbox_explain` for the selected agent and `cwd` before starting work.
4. Use `agent_run` when the caller needs semantic status and a final result. Keep
its `run_id`, wait with `agent_wait`, and read completion with `agent_result`.
5. Use `agent_start` only when an interactive PTY and later human attachment are
part of the task. Keep its session ID; do not infer semantic completion from
terminal text.
6. Stop or steer only the exact run or session ID returned by the selected wing.

## Boundaries

- Put no provider tokens, SSH keys, or other secrets in prompts or MCP arguments.
Authenticate the provider CLI in the execution owner's agent home.
- A terminal survives client detachment. A run's record and result persist, but
active headless execution still requires its supervising Wingthing process.
- Headless runs do not currently have a browser view. Start a terminal when human
takeover is required.
- Direct remote MCP rejects locked wings and never silently switches to the hosted
relay. Use an unlocked authorized wing, SSH, or a self-hosted roost as appropriate.
- Treat `~/.wingthing/wt.db`, `~/.wingthing/memory/`, provider history, and the
workspace as wing-local state unless the operator has arranged replication.
24 changes: 23 additions & 1 deletion docs/fly-ops.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Fly Operations Guide

Wingthing is a typed agent manager for durable agent runs and terminals. The Fly
fleet hosts its public coordinator: identity, the authorized wing directory, key
exchange, WebRTC signaling, the portal, and the optional encrypted relay. Agents
still execute on a user's selected wing; neither Fly process group is a general
agent host.

## Placement and durable state

| Decision | Public Fly deployment |
| --- | --- |
| **Execution wing** | The access-filtered wing explicitly selected by `wing_id`. Login and edge machines coordinate connections but do not substitute themselves as execution targets. |
| **Workspace** | An existing `cwd` on the selected wing. No Fly service clones or synchronizes user repositories or untracked files. |
| **Display** | `agent_run` returns semantic state over direct MCP without a browser view. `agent_start` creates a persistent PTY; hosted browser/control relay is entitlement-gated, while CLI, SSH, and self-hosted displays remain compatible. |
| **Provider credentials** | The execution owner's agent home on the selected wing. Fly secrets are only service credentials such as JWT, OAuth, billing, or internal-node keys—not Claude, Codex, SSH, or other user provider credentials. |
| **Durable memory** | The login volume stores gateway account, organization, auth, entitlement, and routing records. Each wing remains authoritative for its task database, eggs, optional Wingthing memory, provider history, and workspaces. Edge machines are stateless. |

The public `direct-free` relay policy changes transport entitlement, not ownership
or organization authorization. Existing personal and organization directories,
roles, configured path scopes, grants, and bounds continue to apply at the wing.

## Architecture

Two process groups, one image:
Expand Down Expand Up @@ -86,7 +106,9 @@ On `direct-free`, the historical billing-free personal and organization upgrade
endpoints are disabled, and the account UI does not offer plan mutation. Existing
Pro/team entitlements and cancellation paths remain valid; new relay entitlements
must be provisioned by the deployment's billing or operator workflow. Legacy and
self-hosted gateways retain their previous self-service behavior.
self-hosted gateways retain their previous self-service behavior. This does not
remove organization membership or wing sharing; it only prevents those endpoints
from granting new hosted-relay entitlement.

The public deployment also sets an explicit temporary migration boundary in
`fly.toml`. Accounts created on or before that instant retain relay parity while
Expand Down
11 changes: 10 additions & 1 deletion internal/relay/templates/docs.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
</nav>
<div class="docs-body">
<h1>documentation</h1>
<p class="lead">wingthing is an agent manager for agents: one typed control plane for durable work across every machine, with human takeover when useful.</p>
<p class="lead">Wingthing is a typed agent manager for durable agent runs and terminals across local and remote wings, with human takeover when useful.</p>

<div class="docs-section" id="quickstart">
<h2>quickstart</h2>
Expand Down Expand Up @@ -121,6 +121,15 @@ <h2>overview</h2>
<div class="docs-section" id="agent-control">
<h2>agent control</h2>
<p>The MCP server lets a parent LLM discover and operate Wingthing without scraping terminal output. Use <code>wt mcp stdio</code> for the same host and <code>wt mcp connect</code> for an explicitly selected remote wing. Use <code>agent_run</code> for semantic task state. Use <code>agent_start</code> when a person should be able to attach to the persistent terminal.</p>
<table class="vocab-table">
<tr><th>placement</th><th>current contract</th></tr>
<tr><td>execution wing</td><td>Local stdio executes on its host. Direct remote calls require the selected <code>wing_id</code>. A roost HTTP MCP endpoint controls that roost's built-in wing; Wingthing never silently substitutes a different target.</td></tr>
<tr><td>workspace</td><td>Pass an existing <code>cwd</code> on the execution wing. Wingthing does not create, clone, upload, or synchronize the repository or its untracked files.</td></tr>
<tr><td>display</td><td><code>agent_run</code> has semantic status and a final result but no live browser view. <code>agent_start</code> creates a PTY a person can attach to through the CLI, SSH, or an entitled/self-hosted browser.</td></tr>
<tr><td>credentials</td><td>The provider CLI uses the execution owner's agent home on that wing. Shared hosts keep those homes separate. Provider tokens and SSH keys do not belong in prompts or MCP arguments.</td></tr>
<tr><td>durable memory</td><td>Tasks, results, messages, and threads stay in that wing's <code>~/.wingthing/wt.db</code>; terminal state stays under <code>~/.wingthing/eggs</code>, optional prompt memory under <code>~/.wingthing/memory</code>, and provider history in the provider home. <code>WINGTHING_DIR</code> changes the Wingthing state root. None of this is replicated between wings automatically.</td></tr>
</table>
<p>A terminal survives client detachment. A run's record and result persist, but an active headless run still depends on its supervising Wingthing process. Keep the returned run or session ID together with its owning wing for every later operation.</p>
<div class="docs-code">
<span class="prompt">$ </span><span class="cmd">codex mcp add wingthing -- wt mcp stdio --client codex</span><br>
<span class="prompt">$ </span><span class="cmd">claude mcp add --scope user wingthing -- wt mcp stdio --client claude</span>
Expand Down
6 changes: 3 additions & 3 deletions internal/relay/templates/home.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{define "title"}}wt - one place for you and your agents{{end}}
{{define "title"}}wingthing - typed agent manager{{end}}
{{define "head"}}
<style>
.hero{padding:40px 0 24px;text-align:center}
Expand Down Expand Up @@ -98,8 +98,8 @@
})();
</script>
<div class="hero">
<h1>all your agents, one place</h1>
<p class="tagline">Wingthing is an agent manager for agents. Give Codex, Claude, or another parent agent one typed control plane for starting and supervising durable agents across all your machines. Take over from a terminal or browser when a person belongs in the loop.</p>
<h1>durable agent runs and terminals</h1>
<p class="tagline">Wingthing is a typed agent manager for Codex, Claude, and other agents. Start and supervise work on the wing where the code and credentials already live, then take over a persistent terminal when a person belongs in the loop.</p>
{{if .User}}<div class="prompt-flow">
<a href="{{.AppURL}}" class="prompt-line" id="prompt-app"><span class="prompt-dim">press</span> <span class="prompt-key">.</span> <span class="prompt-dim">to</span> <span class="prompt-key">open app</span></a>
</div>
Expand Down
18 changes: 14 additions & 4 deletions internal/relay/templates/install.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
{{define "content"}}
<div class="inst-hero">
<h1>install wt</h1>
<p>One command installs the Wingthing runtime. macOS and Linux, x64 and arm64.</p>
<p>Install Wingthing, the typed agent manager for durable agent runs and terminals. macOS and Linux, x64 and arm64.</p>
</div>

<div class="inst-platforms">
Expand All @@ -50,16 +50,26 @@ <h2>quick install</h2>

<div class="inst-section">
<h2>get started</h2>
<p>Every launch uses an existing workspace and provider login on its execution wing. Wingthing keeps task and terminal state on that wing; it does not copy the workspace, credentials, or durable memory elsewhere.</p>
<ol class="inst-steps">
<li>
<h3>start locally</h3>
<p>No account or daemon is required. Detach with <code>Ctrl+B</code>, then <code>Q</code>.</p>
<h3>start an agent terminal locally</h3>
<p>Authenticate the provider CLI first and use an existing project directory. No Wingthing account or daemon is required. Detach with <code>Ctrl+B</code>, then <code>Q</code>.</p>
<div class="inst-code">
<span class="prompt">$ </span><span class="cmd">wt terminal --name work</span><br>
<span class="prompt">$ </span><span class="cmd">cd /path/to/existing/project</span><br>
<span class="prompt">$ </span><span class="cmd">wt egg claude --name work</span><br>
<span class="prompt">$ </span><span class="cmd">wt attach work</span>
</div>
</li>
<li>
<h3>give a parent agent typed local control</h3>
<p>Register local MCP, restart the parent client, and ask it to call <code>wingthing_capabilities</code>. Use <code>agent_run</code> for a semantic result or <code>agent_start</code> for an attachable PTY.</p>
<div class="inst-code">
<span class="prompt">$ </span><span class="cmd">codex mcp add wingthing -- wt mcp stdio --client codex</span><br>
<span class="comment"># or: claude mcp add --scope user wingthing -- wt mcp stdio --client claude</span>
</div>
</li>
<li>
<h3>optionally run your own browser portal</h3>
<p>No Wingthing account is required. This creates and trusts a localhost-only certificate for your current user; Linux needs <code>certutil</code> from <code>libnss3-tools</code> or <code>nss-tools</code> for that trust step.</p>
<div class="inst-code">
Expand Down
6 changes: 3 additions & 3 deletions internal/relay/templates/patterns.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
{{end}}
{{define "content"}}
<main class="patterns">
<h1>choose what you want to do</h1>
<p class="lead">Each setup below works today. Pick one to see what must be installed, where the agents run, and how to connect.</p>
<h1>choose a durable agent workflow</h1>
<p class="lead">Wingthing is a typed agent manager for durable agent runs and terminals. Each setup below works today; pick one to see exactly what must be installed, where execution and state live, and how the driver connects.</p>

<div class="plain-language"><strong>A wing is simply a computer running Wingthing.</strong> Your code, agent credentials, and processes stay on that computer. Wingthing keeps the work alive and lets an authorized person or parent agent reconnect.</div>
<div class="plain-language"><strong>A wing is the computer that runs the work.</strong> Before launch, choose the execution wing, an existing workspace on it, a headless or terminal display, the owner whose provider home supplies credentials, and the wing that keeps durable state. Wingthing routes control; it does not copy workspaces, credentials, provider history, or Wingthing memory between wings.</div>

<div class="pattern-list">
<section class="pattern">
Expand Down
15 changes: 13 additions & 2 deletions patterns/local-sandbox/INSTRUCTIONS.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
# Run a durable, sandboxed agent on this computer
# Run a durable, sandboxed agent terminal on this computer

Use this setup when you want to run Claude, Codex, or another agent in a local
project. No Wingthing account or server is required.

Wingthing applies the project's sandbox policy and keeps the terminal alive if you
close the window or lose the connection.

## Placement and durable state

| Decision | This setup |
| --- | --- |
| **Execution wing** | This computer. The local CLI starts the egg directly; a wing daemon, portal, and hosted account are optional. |
| **Workspace** | An existing project directory on this computer. Run the command from that directory; Wingthing does not create, clone, or synchronize it. |
| **Display** | A persistent terminal opened by `wt egg` and resumed with `wt attach`. If this computer is also connected to a relay-entitled hosted portal or a self-hosted roost, the same terminal can appear there. |
| **Provider credentials** | The selected agent CLI uses the current OS user's provider login on this computer. Authenticate that CLI here; do not pass provider tokens on the command line or in a prompt. |
| **Durable memory** | Egg and terminal state stay under this computer's `~/.wingthing/eggs` (or `WINGTHING_DIR`). Provider-native history stays in its local agent home, and optional Wingthing prompt memory stays under `~/.wingthing/memory`. None of it is copied elsewhere automatically. |

## Set it up

Install Wingthing once:
Expand All @@ -14,7 +24,8 @@ Install Wingthing once:
curl -fsSL https://wingthing.ai/install.sh | sh
```

Open the project directory and inspect the sandbox before starting an agent:
Authenticate the provider CLI if needed, then open the existing project directory
and inspect the sandbox before starting an agent:

```sh
cd /path/to/project
Expand Down
Loading
Loading