Implement TUIcast: AI-Powered Terminal GIF Generation Service#1
Implement TUIcast: AI-Powered Terminal GIF Generation Service#1
Conversation
Co-authored-by: tig <585482+tig@users.noreply.github.com>
|
@copilot you should be able to build a POC that runs in a gh workflow runner that is automated and self contained. No azure service etc should be needed. The workflow should be able to install and configure everything in the runner needed. Build the first one that just verifies UICatalog can run and exit producing a gif. |
Co-authored-by: tig <585482+tig@users.noreply.github.com>
Done in e0a96e6. Here's what was added:
npm run record -- --binary /path/to/UICatalog \
--keystrokes "wait:3000,ArrowDown,ArrowDown,Ctrl+Q" \
--output recording.gifNo Azure or Claude API key required — provide keystrokes directly to skip the AI loop. The |
|
@copilot use dotnet 10. Verify the runner runs and works. |
|
2026-03-16T14:27:29.0809289Z ##[group]Run git clone --depth 1 --branch main |
Co-authored-by: tig <585482+tig@users.noreply.github.com>
Done in 72a14d2. Three fixes were required to get the CI green:
The workflow now runs end-to-end in ~90 seconds — builds UICatalog, records a session, renders a GIF, verifies the magic bytes, and uploads the artifact. All 12 steps ✅ Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot cherry pick spec.md from the claude/create-tuicast-blog-07Kds branch. Review it and compare it to what you've built so far. Since the POC basically works, we're on the right path. That spec was written by another ai agent and may have goodness in it or be totally duplicated. Either way ensure the final doc is clear, complete, and crisp. Ensure it captures any mistakes you made or things you discovered build what's here and the POC. |
…arnings Co-authored-by: tig <585482+tig@users.noreply.github.com>
Done in b17750a.
|
|
@copilot can we tighten the vertical cell spacing. See the gaps? |
Co-authored-by: tig <585482+tig@users.noreply.github.com>
Done in f8e78c8. The root cause was Changes:
The next CI run will produce a tighter GIF. If you want a touch of breathing room, |
|
@copilot can you make it easier to get the url to the generated gif out of the workflow? Having to dl the zip and extract it is a pita. |
Co-authored-by: tig <585482+tig@users.noreply.github.com>
Done in 2fb2ce0. The After the next CI run the Summary page will look like:
One click from the Summary tab — no navigating to the Artifacts section or unzipping manually. |
|
@copilot now, to prove ui flow, have the example use the mouse to show the UICatalog about box. |
Co-authored-by: tig <585482+tig@users.noreply.github.com>
Done in 1190cee. Three things changed:
The next CI run will produce a GIF that shows the mouse opening the About dialog. |
|
@copilot analyze the plan to deploy and host this on azure. What do you need to be able to deploy it (using the azure cli)? |
Here's what's needed for a full Azure deployment, based on the existing Bicep templates and Dockerfiles. Azure resources required
Secrets / credentials needed up-front
Deployment sequence (Azure CLI)# 1. One-time setup
az login
az group create -n tuicast-rg -l eastus
# 2. Provision shared infrastructure
az deployment group create -g tuicast-rg -f infra/service-bus.bicep
az deployment group create -g tuicast-rg -f infra/storage.bicep
# 3. Create ACR and push images
az acr create -g tuicast-rg -n tuicastacr --sku Basic --admin-enabled true
az acr build -r tuicastacr -t tuicast-api:latest -f Dockerfile.api .
az acr build -r tuicastacr -t tuicast-worker:latest -f Dockerfile.worker .
# 4. Deploy the API (e.g. as a Container App)
# A container-app.bicep is not yet in the repo — this is the main gap.
# 5. Per-job worker containers
# The API spawns these via container-instance.bicep at job-submission time.What's missing from the repo
Want me to add a |
|
@copilot There should be a script that does initial setup/config that can be run locally, using gh login. It should do initial deployment Then the push action should update the deployment as needed. |
|
@copilot There should be a script that does initial setup/config that can be run locally, using gh login. It should do initial deployment Then the push action should update the deployment as needed. |
- infra/acr.bicep: Azure Container Registry template - infra/container-app.bicep: Container Apps environment + API template - infra/main.bicep: orchestration module wiring all Bicep templates - infra/setup.sh: one-shot local deploy script (az login + gh secret set) - .github/workflows/deploy.yml: push-to-main CD workflow - Dockerfile.worker: .NET 8 → .NET 10 Co-authored-by: tig <585482+tig@users.noreply.github.com>
Done in 25a28c9. Here's what was added:
cd <repo-root>
ANTHROPIC_API_KEY=sk-ant-... ./infra/setup.shThe script:
New Bicep templates added to complete the infra:
|

TUIcast enables Terminal.Gui developers to generate animated GIF recordings of their TUI apps by describing what they want demonstrated in plain English — no manual scripting or recording tool setup required.
Core Pipeline
src/worker/pty-session.ts) — spawns the target app vianode-ptywith configurable terminal dimensionssrc/worker/recorder.ts) — captures raw PTY output as asciinema v2 cast format natively (no binary dependency)src/worker/claude-driver.ts) — observes terminal screen state after each action, decides next keystroke via Anthropic API, loops until goal reached or timeout; falls back to deterministic keystroke script when providedsrc/worker/gif-renderer.ts) — wrapsaggwith configurable font, theme, playback speed, and line height; font is optional, falling back to agg's built-in bitmap font when not specifiedsrc/worker/worker.ts) — orchestrates the above; supports inline (dev) and queue-based (prod) execution modesAPI & Frontend
POST /jobs,GET /jobs/:id,GET /jobs) withexpress-rate-limitapplied per-route (100 req/min general, 10 req/min job submission)public/index.html) for job submission, live status polling, and GIF preview/downloadInfrastructure
infra/acr.bicep) — storestuicast-apiandtuicast-workerimagesinfra/container-app.bicep) — hosts the long-running API service (1–3 replicas, auto-TLS ingress, rolling revision updates)infra/container-instance.bicep)infra/main.bicep— single orchestration template that provisions Service Bus, Storage, ACR, and the Container App in oneaz deployment group createcalldocker-compose.ymlwith Azurite emulator for local dev;USE_QUEUE=falseprocesses jobs inlineAzure Deployment
infra/setup.sh— one-shot local setup script; run once withANTHROPIC_API_KEY=... ./infra/setup.sh:az,gh,docker,jq)az loginandgh auth loginif not already authenticatedmain.bicep(~5 min)tuicast-apiandtuicast-workerimages to ACRtuicast-github-actionsservice principal with Contributor scopegh secret set— no manual copy-paste.github/workflows/deploy.yml— triggered on every push tomain; rebuilds both images tagged with the commit SHA, pushes to ACR, updates the Container App revision, and writes the live API URL to the job Summary tabStandalone Recorder CLI & POC Workflow
src/cli/record.ts— self-contained recorder CLI requiring no Azure or Anthropic credentials; accepts a binary path and a comma-separated keystroke/mouse script to drive the session deterministically; supportswait:<ms>, named keys (ArrowDown,Ctrl+Q, etc.), andclick:<col>:<row>mouse clicks (SGR encoding); validates the output GIF's magic bytes and exits non-zero on failure (CI-friendly).github/workflows/poc-uicatalog.yml— fully self-contained GitHub Actions workflow that installs .NET 10, clones Terminal.Gui (v2_developbranch, which targetsnet10.0), builds UICatalog, installs Node.js dependencies and theaggstatic binary, records a UICatalog session that uses the mouse to open Help → About, verifies the produced GIF, uploads it as a workflow artifact, and prints a direct one-click download link in the workflow run's Summary tab — no Azure services or API keys requiredKey Design Decisions
src/utils/keys.ts— used by the PTY session, Claude driver, and standalone CLI; now covers allCtrl+A…Ctrl+Zsequences (includingCtrl+Q = \x11which was previously missing)mouseClickSequence(col, row)insrc/utils/keys.tsgenerates an SGR left-button press+release pair (\x1b[<0;col;rowM/\x1b[<0;col;rowm); Terminal.Gui v2 enables SGR mouse reporting on start-up so no extra setup is needed; CLI exposes it asclick:<col>:<row>tokens (colon sub-separator avoids conflict with the comma list separator)dotnet publish), Docker image, or uploaded binary blob--line-heightdefaults to1.0(no extra inter-row gap) rather thanagg's built-in default of1.4— Terminal.Gui apps already include cell borders that provide visual row separation, so the extra padding is redundant and produces visible blank strips between rowsDockerfile.workerinstalls .NET 10 (corrected from .NET 8) to match thenet10.0target framework used by Terminal.Guiv2_developTechnical Specification (
spec.md)A consolidated technical specification has been added, merging an earlier AI-drafted spec with the ground truth of what was built. It documents:
— fixed; allCtrl+Q(\x11) is absent fromsrc/utils/keys.tsCtrl+A…Ctrl+Zcodes are now presentmainbranch;v2_developtargetsnet10.0, notnet8.0; UICatalog is atExamples/UICatalog/UICatalog.csprojnode-ptyrequirespython3 make g++in CI runners at install timeaggmust not receive--font-familyon headless runners without system fonts installedagg's default--line-heightof1.4produces visible inter-row gaps in Terminal.Gui recordings;1.0is the correct valueOriginal prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.