Tap.Workspace
0.5.0-beta.6
See the version list below for details.
dotnet add package Tap.Workspace --version 0.5.0-beta.6
NuGet\Install-Package Tap.Workspace -Version 0.5.0-beta.6
<PackageReference Include="Tap.Workspace" Version="0.5.0-beta.6" />
<PackageVersion Include="Tap.Workspace" Version="0.5.0-beta.6" />
<PackageReference Include="Tap.Workspace" />
paket add Tap.Workspace --version 0.5.0-beta.6
#r "nuget: Tap.Workspace, 0.5.0-beta.6"
#:package Tap.Workspace@0.5.0-beta.6
#addin nuget:?package=Tap.Workspace&version=0.5.0-beta.6&prerelease
#tool nuget:?package=Tap.Workspace&version=0.5.0-beta.6&prerelease
<div align="center"> <p> <img src="assets/tap-logo.svg" alt="Tap" width="150"> </p>
<picture> <source srcset="assets/tap-hero-dark.png" media="(prefers-color-scheme: dark)"> <img src="assets/tap-hero.png" alt="Tap tunnel and HTTP inspector illustration" width="620"> </picture>
<p><strong>Two local-first tools for HTTP: one to watch traffic arrive, one to send it.</strong></p>
<p> <a href="https://philbir.github.io/tap/"><strong>Landing page and docs</strong></a> </p>
<p> <a href="https://philbir.github.io/tap/"><img alt="Docs" src="https://img.shields.io/badge/docs-GitHub%20Pages-14945f"></a> <img alt=".NET" src="https://img.shields.io/badge/.NET-10-512bd4?logo=dotnet"> <img alt="Aspire" src="https://img.shields.io/badge/Aspire-ready-7b2ff7"> <img alt="Cloudflare Tunnel" src="https://img.shields.io/badge/Cloudflare-Tunnel-f38020?logo=cloudflare"> <img alt="Tailscale Funnel" src="https://img.shields.io/badge/Tailscale-Funnel-5e64f4?logo=tailscale"> <img alt="UI" src="https://img.shields.io/badge/UI-React%2019-14945f?logo=react"> </p> </div>
The big picture
Local HTTP development has two halves. Sometimes the internet needs to reach your laptop โ a webhook, an OAuth callback, a mobile build, a partner poking at your machine for ten minutes โ and you need to see exactly what arrived. Other times you are the client, and you need to compose a request, authenticate properly, send it, and keep it somewhere your team can find it next month.
Tap is two products, one for each half:
| ๐ | Tap Tunnel + Inspector | Give localhost a real public URL through Cloudflare Tunnel or Tailscale, and capture every request, response, SSE event, and WebSocket frame that flows through it. Runs as the tap CLI or as .NET Aspire resources. |
| ๐งช | Tap Studio | An HTTP workbench: compose requests, run real authentication flows, execute, and keep the whole workspace in your git repo as Markdown. Ships as a desktop app, with an AI assistant built in. |
They share a philosophy more than they share code:
- Local-first. Everything runs on your machine. No account, no cloud workspace, no telemetry. Quick tunnels cost nothing; stable hostnames just need a domain you already own.
- Plain text, in your repo. Studio's workspace is Markdown with YAML frontmatter โ no proprietary export, no sync service, ordinary git diffs.
- Secrets stay out of files. The Inspector never persists credentials; Studio resolves secret references at execute time and keeps tokens in your OS state folder, never in the workspace.
- Explicit boundaries. Tunnels are private by default where the provider allows it, and public exposure is something you opt into with your eyes open.
inbound Internet โโถ Cloudflare Tunnel / Tailscale โโถ Tap capture proxy โโถ your service
โ
โผ
Inspector UI
requests ยท SSE ยท WS ยท replay
outbound request.req.md + auth profile + environment โโถ Tap Studio โโถ any API
โโโโโโโโโ Markdown, in your repo โโโโโโโโโโ executor
Use either on its own. Used together, Studio composes the call and the Inspector shows you what your service actually received.
๐ Tap Tunnel + Inspector
For the moment when localhost needs to behave like a real internet endpoint, but you still want full visibility into every request. Mobile app hooks, webhook deliveries, third-party OAuth redirects, partner integrations, and "can you hit my laptop for a minute?" demos all need the same two things: a tunnel that is quick to bring up, and a request log that tells you what actually happened.
๐ Full reference: docs/inspector.md
Public tunnels are scanned within minutes. As soon as a public hostname's TLS certificate
hits a CT log โ immediately, when Cloudflare Tunnel or Tailscale Funnel comes up โ
opportunistic scanners start probing for admin endpoints and known-CVE banners. Always pair
public tunnels with Tap's auth options (header / CIDR / country / OIDC) or edge controls like
Cloudflare Access and WAF rules. For Tailscale, prefer WithTailscaleServe(...)
(tailnet-only) over WithTailscaleFunnel(...) (public) unless you actually need internet
exposure.
What it does
| Tunnels without ceremony | Free TryCloudflare URLs, dashboard connector tokens, API-managed Cloudflare tunnels + DNS, or Tailscale Serve/Funnel when your tailnet is the right boundary. |
| Captures every hop | Method, host, path, headers, status, timing, request and response bodies, and image previews โ recorded before forwarding to your upstream. |
| Live streaming protocols | text/event-stream responses and WebSocket connections proxy through the same port and render as live, direction-tagged timelines in dedicated SSE and WS tabs. |
| Replay and QR | Replay any captured request; scan the public URL straight onto a phone from the QR tab. |
| Aspire-native | Model inspectors and tunnels in your AppHost. Allocated ports and generated hostnames resolve at startup and show up in the dashboard. |
| Auth on the public path | Header, CIDR, country, and OIDC checks gate the proxy branch before traffic reaches your upstream. The UI port stays local. |
Install
All three routes install the same tap CLI.
dotnet tool install -g Tap # .NET 10 SDK on PATH
curl -fsSL https://raw.githubusercontent.com/philbir/tap/main/install.sh | sh # Linux/macOS, self-contained
irm https://raw.githubusercontent.com/philbir/tap/main/install.ps1 | iex # Windows
Make sure ~/.dotnet/tools (Linux/macOS) or %USERPROFILE%\.dotnet\tools (Windows) is on your
PATH. Pin a version with TAP_VERSION=0.1.0 (or $env:TAP_VERSION on Windows). Archives are
also on the Releases page as
tap-<version>-<rid>.tar.gz with a SHA256SUMS alongside.
Cloudflare features need cloudflared
on PATH โ brew install cloudflared, winget install Cloudflare.cloudflared, or
tap install-cloudflared. Tailscale host modes need the
tailscale CLI; Docker mode doesn't.
Quick start โ CLI
tap run http://localhost:3000
Proxy on http://localhost:4444, Inspector UI on http://localhost:4445.
# throwaway public URL, no account needed
tap run http://localhost:3000 --quick
# your own hostname, via a tunnel you created in the Cloudflare dashboard
tap run http://localhost:3000 --token "$CLOUDFLARE_TUNNEL_TOKEN" --hostname api-local.example.com
# tailnet-only (the safe default)
tap run http://localhost:3000 --tailscale
# public Tailscale Funnel โ pair it with auth
tap run http://localhost:3000 --tailscale --tailscale-public --auth-header "X-Tap-Key=$TAP_KEY"
Every flag, every environment variable, and the tap.config file format:
docs/inspector.md.
Quick start โ Aspire
using Aspire.Hosting;
var builder = DistributedApplication.CreateBuilder(args);
var api = builder.AddProject<Projects.Sample_Api>("api");
var tap = builder.AddTap<Projects.Tap_Server>();
api.WithTap(tap);
builder.Build().Run();
Inspector UI on http://localhost:5198; traffic through http://localhost:5199 is recorded
before it reaches api. Add .WithQuickTunnel(), .WithTunnel(...), .WithTailscaleServe(...),
or .WithTailscaleFunnel(...) to put a tunnel in front โ the
Aspire recipes cover each mode.
Packages
| Package | Purpose |
|---|---|
Tap.Hosting |
Aspire AppHost extensions: AddTap, AddTapContainer, WithTap, WithTunnel, WithQuickTunnel, WithTailscaleServe (tailnet-only, default), WithTailscaleFunnel (public, opt-in), WithExistingTunnel, WithApiManagedTunnel, WithDynamicHostname, WithSystemDaemon / WithEphemeralDaemon / WithFunnelPort. |
Tap.Server |
ASP.NET Core capture server: YARP reverse proxy, capture middleware, WebSocket-terminating proxy, SSE event parser, REST API, /api/stream push channel, and the bundled React Inspector UI. |
Tap.Cli |
Local command host that reuses the same server code. |
Both entry points run the same Tap.Server host: the CLI builds TapInspectorOptions from
flags, environment variables, and tap.config; Aspire writes the same options as project
environment variables.
๐งช Tap Studio
The other direction: you are the client. Studio is a full HTTP request workbench โ compose, authenticate, execute, document โ with a workspace that lives in your repository as plain Markdown.
๐ Full reference: docs/studio.md ยท ๐ On-disk format: docs/workspace-format.md
What it does
| Full request composition | Method, URL, query params, headers, and bodies as None / Form / Multipart / Raw / Binary / GraphQL โ with JSON/XML formatting, multi-file uploads, and a GraphQL editor backed by the live schema. |
| Real responses | Status, duration, size, syntax-highlighted body with image and binary previews, plus Headers, the exact Request that went on the wire, the auth/variable Flow, and which Secrets were resolved. |
| Streaming | SSE responses stream in live; requests marked protocol: websocket open a real socket and append frames as they arrive. |
| Many authentication flows | OAuth 2.0 / OIDC (authorization code + PKCE, client credentials, ROPC, device code), Microsoft Entra, Azure CLI (direct + on-behalf-of), GitHub (PAT / gh CLI / GitHub App / OAuth App), AWS SigV4, signed JWT, bearer, basic, API key, and custom headers. |
| AI assistance | Hand the request to GitHub Copilot CLI or Claude Code โ running locally, with your existing CLI login โ and get a proposed edit you review before saving. |
| Git-native workspace | Requests, collections, auth profiles, and environments are Markdown files. Built-in branch, diff, stage, and commit. |
| Variables and secrets | A six-level cascade (workspace โ collection โ stage โ environment โ request โ per-run) over pluggable providers: process env with allowlists, an encrypted workspace file, Azure Key Vault, and machine-local system variables. |
Authentication, properly
Creating an auth profile starts from a template catalog; the wizard then asks only for the fields that flow actually needs, and shows you what it will write before it writes it.
Tokens never touch the workspace โ they live in ~/.tap/auth-tokens.json, keyed by workspace
and profile, and refresh automatically. The redirect URI is owned by the runtime and shown
read-only so you know exactly what to register with your identity provider; the desktop app
uses the stable tap-studio://callback deep link instead of an ephemeral loopback port. You
can also pick which browser and profile handles an interactive sign-in, so a work tenant
doesn't land in your personal session.
Details and the full grant matrix: docs/studio.md.
AI assistance
Studio spawns an AI coding CLI you already have installed โ no bundled SDK, no extra credentials. The assistant is handed the request you're editing plus the collection's base URL, default auth, and shared headers, the available auth profiles, the environment names, and the variable catalog, so it edits your workspace instead of inventing endpoints and tokens.
It never writes files. It proposes a structured request that the UI applies to the editor as an
unsaved change, together with Markdown documentation for the request โ you review the diff and
decide whether to keep it. Secrets are always referenced as {{variables}}, never inlined.
The workspace is your repo
.tap/
โโโ tap.md โ workspace: name, providers, default env
โโโ auth/corp-entra.auth.md โ auth profile shared by every collection
โโโ environments/local.env.md โ named variable set
โโโ collections/billing/
โโโ _collection.md โ baseUrl, stages, default auth/headers
โโโ billing-oauth.auth.md โ auth profile scoped to this collection
โโโ create-customer.req.md โ one request, as a fenced http block
Because a request is a couple of lines of Markdown, review, blame, cherry-pick, and revert all work the way they do for code. Studio is the only thing that writes the YAML โ editors PUT a typed spec and the server re-emits the file โ so what lands in your diff is predictable.
Install and run
Studio ships as a native desktop app (Tauri 2 wrapping the self-contained Tap.Studio
sidecar). Grab the .dmg, .msi/.exe, or .deb from
Releases; it self-updates from there.
From source, the whole dev loop is one command:
cd samples
aspire run
That brings up demo-api (an upstream exercising every verb, content type, SSE, WebSockets,
GraphQL, and a real OAuth2/OIDC server), studio-api, and the Vite UI on port 5297. Point it
at your own repo with STUDIO_WORKSPACE=/path/to/your/repo aspire run, and add
RunDesktop=true to open the native window too.
Development
dotnet restore Tap.slnx
dotnet build Tap.slnx
dotnet run --project samples/Sample.AppHost # tunnels + inspector scenarios
cd samples && aspire run # Tap Studio
The SDK is pinned in global.json to .NET 10 and TreatWarningsAsErrors is on globally, so
warnings break the build. There is no test project yet.
Two independent UIs, both yarn 4 (Berry):
cd src/ui-inspector && yarn && yarn dev # Inspector โ port 5197
cd src/ui-studio && yarn && yarn dev # Studio โ port 5297
cd docs-site && yarn && yarn build # landing page + docs
src/ui-inspector is built into src/backend/Tap.Server/wwwroot/ on every server build, and
src/ui-studio into Tap.Studio's wwwroot. Skip those with -p:SkipTapUiBuild=true and
-p:SkipStudioUiBuild=true when iterating on C# only. The generated wwwroot directories are
gitignored โ never hand-edit them.
Layout
assets/ Logo, hero art, and documentation screenshots
docs/ Reference documentation
docs-site/ Vite landing page + docs, published to GitHub Pages
src/backend/Tap.Core/ Shared auth and Cloudflare/cloudflared primitives
src/backend/Tap.Hosting/ Aspire integration and lifecycle hooks
src/backend/Tap.Server/ Capture server, YARP proxy, SSE/WS API, bundled Inspector UI
src/backend/Tap.Cli/ CLI host for the inspector server
src/backend/Tap.Studio/ Studio backend (REST + SSE, auth runner, AI, git)
src/backend/Tap.Workspace/ Workspace parsing, variable providers, and rendering
src/ui-inspector/ Vite + React Inspector UI
src/ui-studio/ Vite + React Studio UI
src/desktop/ Tauri desktop shell for Studio
samples/ Sample AppHosts, the demo API, and a sample workspace
Documentation
| Document | Contents |
|---|---|
| docs/inspector.md | Tunnel modes, full CLI reference, Cloudflare and Tailscale setup, proxy auth, Aspire recipes, configuration. |
| docs/studio.md | Workspace model, request composer, authentication flows, variables and secrets, AI assistant, git, desktop app. |
| docs/workspace-format.md | The authoritative on-disk format spec for Studio workspaces. |
| docs/ARCHITECTURE.md | Deep technical background on the capture path and tunnel providers. |
| src/desktop/README.md | Desktop shell internals, build, signing, and release pipeline. |
| docs/release-notes/ | Per-release notes. |
License
TBD.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Markdig (>= 1.3.2)
- YamlDotNet (>= 18.1.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Tap.Workspace:
| Package | Downloads |
|---|---|
|
Tap.Execution
Executes Tap workspace requests, flows, and test sets: HTTP transport, assertion evaluation, value extraction, and the sequential run engine. The engine behind both Tap Studio and the `tap-studio` CLI, so a verdict from CI and a verdict from the UI are the same computation. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.7.0-p.2 | 51 | 8/17/2026 |
| 0.7.0-p.1 | 62 | 8/16/2026 |
| 0.6.1 | 58 | 8/15/2026 |
| 0.6.0 | 61 | 8/15/2026 |
| 0.6.0-beta.1 | 51 | 8/14/2026 |
| 0.5.0-beta.6 | 52 | 8/9/2026 |
| 0.5.0-beta.5 | 53 | 8/8/2026 |
| 0.5.0-beta.4 | 55 | 8/8/2026 |
| 0.5.0-beta.3 | 52 | 8/8/2026 |
| 0.5.0-beta.2 | 52 | 8/7/2026 |
| 0.5.0-beta.1 | 66 | 7/11/2026 |