yudai/gotty
Share your terminal as a web application
Stale — last commit 2y ago
worst of 4 axeslast commit was 2y ago; no tests detected
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓14 active contributors
- ✓MIT licensed
- ✓CI configured
Show 3 more →Show less
- ⚠Stale — last commit 2y ago
- ⚠Single-maintainer risk — top contributor 84% of recent commits
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Mixed → Healthy if: 1 commit in the last 365 days
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/yudai/gotty)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/yudai/gotty on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: yudai/gotty
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/yudai/gotty shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Stale — last commit 2y ago
- 14 active contributors
- MIT licensed
- CI configured
- ⚠ Stale — last commit 2y ago
- ⚠ Single-maintainer risk — top contributor 84% of recent commits
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live yudai/gotty
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/yudai/gotty.
What it runs against: a local clone of yudai/gotty — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in yudai/gotty | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 676 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of yudai/gotty. If you don't
# have one yet, run these first:
#
# git clone https://github.com/yudai/gotty.git
# cd gotty
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of yudai/gotty and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "yudai/gotty(\\.git)?\\b" \\
&& ok "origin remote is yudai/gotty" \\
|| miss "origin remote is not yudai/gotty (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "main.go" \\
&& ok "main.go" \\
|| miss "missing critical file: main.go"
test -f "server/server.go" \\
&& ok "server/server.go" \\
|| miss "missing critical file: server/server.go"
test -f "backend/localcommand/local_command.go" \\
&& ok "backend/localcommand/local_command.go" \\
|| miss "missing critical file: backend/localcommand/local_command.go"
test -f "js/src/webtty.ts" \\
&& ok "js/src/webtty.ts" \\
|| miss "missing critical file: js/src/webtty.ts"
test -f "server/handlers.go" \\
&& ok "server/handlers.go" \\
|| miss "missing critical file: server/handlers.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 676 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~646d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/yudai/gotty"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
GoTTY is a Go-based CLI tool that wraps any terminal command and exposes it as a real-time web application via WebSocket. Users run gotty top or gotty bash and get an interactive terminal in their browser at localhost:8080, using xterm.js on the frontend to render TTY output and hterm for additional terminal emulation features. Standard CLI tool structure: main.go is the entry point, backend/localcommand/ handles spawning and managing the subprocess and PTY, server/ serves HTTP/WebSocket endpoints, js/src/ contains the TypeScript frontend (main.ts orchestrates hterm/xterm rendering, websocket.ts handles the WebSocket protocol), and resources/ holds static HTML/CSS.
👥Who it's for
System administrators and DevOps engineers who need to share live terminal sessions with team members remotely without SSH access, and developers who want to turn command-line tools (monitoring dashboards, databases CLIs, build processes) into shareable web interfaces without additional code.
🌱Maturity & risk
Moderately mature but aging: the project has a stable release pattern and MIT license, but the last visible commit activity appears dated relative to modern Go/TypeScript standards (Godeps dependency management is legacy). Wercker CI is configured but the TypeScript tooling (webpack 2, TypeScript 2.3) is 5+ years old. No comprehensive test suite is visible in the file structure.
Single maintainer (yudai) with outdated dependency tooling (Godeps instead of Go modules, webpack 2 instead of modern bundlers). The xterm.js dependency is pinned to v2.7.0 (released ~2017), and libapps is forked from a third party (github:yudai/libapps#release-hterm-1.70), raising security patch concerns. No visible GitHub Actions or modern CI. Breaking changes in Go or JavaScript ecosystems are unlikely to be addressed quickly.
Active areas of work
No active development is visible; the repository appears dormant. The file structure shows it's frozen at a functional state with TypeScript/webpack 2 and Go 1.9+ requirement, but no recent pull requests or issue milestones are evident from the provided data.
🚀Get running
git clone https://github.com/yudai/gotty.git
cd gotty
make build
# or with go get: go get github.com/yudai/gotty
./gotty top # Replace 'top' with any command
Daily commands:
# Development:
make dev # Assumes Makefile has dev target
# or manually:
go run main.go -p 8080 -- bash
# Production binary (after build):
./gotty --address 0.0.0.0 --port 8080 --permit-write -- top
🗺️Map of the codebase
main.go— Entry point for the GoTTY application; defines CLI flags and orchestrates server startupserver/server.go— Core HTTP server and WebSocket handler; manages client connections and session lifecyclebackend/localcommand/local_command.go— Implements terminal command execution and PTY management; bridges local shell to web interfacejs/src/webtty.ts— Client-side WebSocket protocol handler; manages bidirectional terminal communicationserver/handlers.go— HTTP request handlers for authentication, WebSocket upgrade, and asset servingjs/src/main.ts— Frontend initialization; wires xterm display to WebSocket terminal backendvendor/github.com/gorilla/websocket— WebSocket dependency for real-time bidirectional communication between browser and server
🧩Components & responsibilities
- main.go (Go codegangsta/cli) — Parse CLI flags, instantiate server options, start HTTP listener
- Failure mode: Application refuses to start; reports flag parsing or port binding errors
- server/server.go (Go net/http, Gorilla WebSocket) — Register HTTP routes, accept connections, dispatch to handlers
- Failure mode: Port already in use, or handler panic crashes entire server
- backend/localcommand/local_command.go (Go os/exec, syscall (PTY ioctls)) — Allocate PTY, spawn shell process, manage Read/Write I/O streams
- Failure mode: PTY allocation fails (no ptmx), shell crash closes connection, OOM from large output
- js/src/webtty.ts (TypeScript, Binary protocol (custom wire format)) — Encode/decode terminal messages (input, output, resize), manage protocol state
- Failure mode: Malformed message causes parsing error, connection drops silently
- js/src/xterm.ts (x) — Render terminal output, capture user input, handle ANSI escape sequences
🛠️How to make changes
Add a new authentication method
- Define auth logic in server/handlers.go as a new middleware or handler function (
server/handlers.go) - Add auth options to server/options.go for configuration (
server/options.go) - Call auth middleware from server/server.go in the router setup (
server/server.go)
Support a new terminal backend (e.g., SSH, container exec)
- Create backend/mybackend/my_backend.go implementing the backend interface (
backend/localcommand/local_command.go) - Add factory logic in backend/mybackend/factory.go with options handling (
backend/localcommand/factory.go) - Wire backend selection in main.go via CLI flags and server.go (
main.go)
Add a new UI feature (keybinding, resize handler, theme)
- Implement feature logic in js/src/main.ts or create a new module in js/src/ (
js/src/main.ts) - If it requires server communication, extend js/src/webtty.ts protocol (
js/src/webtty.ts) - Add styling in resources/index.css or resources/xterm_customize.css (
resources/index.css) - Run npm install && npm run build in js/ to bundle changes (
js/webpack.config.js)
🔧Why these technologies
- Go + net/http — Cross-platform compilation, minimal dependencies, built-in HTTP server suitable for distributing as single binary
- WebSocket (gorilla/websocket) — Enables low-latency bidirectional communication; essential for real-time terminal keystroke and output streaming
- xterm.js (frontend) — Mature, battle-tested terminal emulator; handles ANSI escapes, mouse events, and wide character support
- TypeScript + Webpack — Type safety for complex WebSocket protocol; bundling ensures assets embed cleanly into Go binary
- PTY (Unix pseudo-terminal) — Allows arbitrary CLI tools to believe they're connected to a real terminal, preserving colors, pagination, interactivity
⚖️Trade-offs already made
-
Single server instance (no clustering)
- Why: Simplicity; avoids distributed session management complexity
- Consequence: Horizontal scaling requires sticky sessions or external load balancer state
-
Embedded static assets (no separate CDN)
- Why: Minimal deployment friction; single binary includes UI
- Consequence: Browser caches entire ~100KB bundle per version; no incremental updates
-
No built-in user/tenant isolation in core
- Why: Flexibility for different deployment models (single user, reverse proxy auth, etc.)
- Consequence: Production use requires external auth (reverse proxy, OAuth middleware)
-
Command spawned as direct child (not containerized)
- Why: Works with any CLI tool out-of-the-box
- Consequence: Limited resource isolation; runaway processes consume server CPU/RAM
🚫Non-goals (don't propose these)
- Does not provide built-in authentication or user management beyond basic header parsing
- Does not handle persistence, logging, or session replay (stateless per client)
- Does not cluster or distribute across multiple machines in core
- Does not provide true multi-user collaboration (each connection is independent)
- Does not isolate or sandbox shell processes; assumes trusted commands
🪤Traps & gotchas
PTY allocation: The backend/localcommand/ relies on syscall-level PTY setup (Unix-only; Windows is unsupported despite Go's cross-platform pretense). Subprocess zombie processes: If the server crashes mid-request, child processes may not be reaped. WebSocket framing: The init_message.go format is non-standard; check the schema if adding new clients. TypeScript compilation: The js/ build requires Node.js and webpack 2; modern npm may fail due to old peer dependencies—use npm ci or pin Node version. Credential format: --credential user:pass is plaintext in the CLI command; no documented secure alternative (env var GOTTY_CREDENTIAL is plaintext too). TLS default paths: Certs default to ~/.gotty.crt and ~/.gotty.key; must be pre-generated (no auto-generation).
🏗️Architecture
💡Concepts to learn
- Pseudoterminal (PTY) — GoTTY's entire value proposition depends on allocating a PTY to the subprocess and bridging it bidirectionally over WebSocket; understanding POSIX PTY semantics (master/slave, signal handling, window resizing) is essential to debug terminal-related bugs
- WebSocket Protocol — GoTTY uses WebSocket for real-time, bidirectional TTY I/O; understanding frame types, message serialization in
init_message.go, and reconnection semantics is critical for debugging frontend-backend communication - Terminal Emulation (xterm/hterm) — The frontend uses two terminal emulators (xterm.js and hterm); knowing the difference (VT100/VT102 escape sequence support, performance trade-offs) helps choose the right one and debug rendering issues
- HTTP Upgrade and Connection Hijacking — GoTTY upgrades HTTP connections to WebSocket in
server/handlers.go; understanding the Upgrade header, 101 Switching Protocols response, and socket-level I/O is needed to extend or debug the server - Process Signal Handling — GoTTY must forward signals (SIGTERM, SIGWINCH for window resize) from the WebSocket client to the subprocess; Go's signal.Notify and syscall patterns are non-obvious and critical to graceful shutdown and responsive resizing
- TypeScript Webpack Bundling — The
js/source is compiled and bundled intojs/dist/gotty-bundle.js; understanding webpack 2 loaders (ts-loader), entry points, and the dev/prod split is required to modify or upgrade the frontend build - HTTP Basic Authentication — GoTTY supports optional HTTP Basic Auth via the
--credentialflag; understanding the Base64-encoded Authorization header and stateless auth validation in the server is needed to extend or audit security
🔗Related repos
ttyd/ttyd— Direct competitor: C-based terminal-over-HTTP tool with similar feature set (TTY sharing, auth, TLS) but lighter footprint and more active maintenancejerch/xterm-pty— Companion project: xterm.js with Node.js PTY integration; useful for understanding modern terminal emulation beyond GoTTY's aging xterm v2.7.0yudai/windy— Related by author: a different approach to terminal sharing using libapps/hterm, may inform architectural decisionslibapps/libapps— Upstream dependency: hterm source repository (GoTTY forks release-hterm-1.70); needed to understand terminal emulation layer and potential security patchesxtermjs/xterm.js— Upstream dependency (v2.7.0): the frontend terminal renderer; major version upgrades would require significant testing
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add unit tests for backend/localcommand package
The backend/localcommand directory contains critical logic for spawning and managing local commands (factory.go, local_command.go, options.go) but has no corresponding test files. This is a core component that deserves test coverage to catch regressions in command execution, option parsing, and error handling across different platforms.
- [ ] Create backend/localcommand/local_command_test.go with tests for command spawning and I/O handling
- [ ] Create backend/localcommand/factory_test.go with tests for command factory creation logic
- [ ] Create backend/localcommand/options_test.go with tests for option parsing and validation
- [ ] Run tests with 'go test ./backend/localcommand' to verify coverage
- [ ] Consider platform-specific tests (Windows vs Unix) given the nature of local command execution
Add TypeScript tests for js/src modules (especially webtty.ts and websocket.ts)
The frontend TypeScript code in js/src/ handles critical WebSocket communication and terminal emulation logic (webtty.ts, websocket.ts, main.ts) but has no test suite configured. The package.json already has webpack and ts-loader configured but no test runner. Adding Jest or Mocha tests would catch bugs in terminal state management and WebSocket message handling.
- [ ] Install test dependencies (jest, ts-jest, or mocha + typescript) in js/package.json
- [ ] Create js/src/webtty.test.ts with tests for terminal state, resize handling, and data transmission
- [ ] Create js/src/websocket.test.ts with tests for connection handling, message framing, and error recovery
- [ ] Create jest.config.js or mocha configuration for TypeScript compilation
- [ ] Add test script to js/package.json and document in CONTRIBUTING.md
Add GitHub Actions CI workflow for multi-platform Go builds and tests
The repo currently uses Wercker for CI (referenced in README), but Wercker is deprecated. The Makefile and Go code suggest the project supports multiple platforms. Adding a GitHub Actions workflow would provide native, maintainable CI that tests Go compilation on Linux, macOS, and Windows, runs the existing test suite, and validates the JavaScript build.
- [ ] Create .github/workflows/go-build-test.yml with matrix strategy for ubuntu-latest, macos-latest, windows-latest
- [ ] Include steps to run 'go test ./...' for all packages including backend/localcommand
- [ ] Include steps to build JavaScript: 'cd js && npm install && npm run build' (or equivalent from Makefile)
- [ ] Include step to build the final binary using Make or 'go build'
- [ ] Update README.md to replace Wercker badge with GitHub Actions badge
🌿Good first issues
- Add comprehensive unit tests for
backend/localcommand/local_command.go(PTY lifecycle, signal handling). Currently no test files visible in the file list, making this area error-prone. - Modernize TypeScript tooling: upgrade webpack from v2 to v4+, TypeScript from v2.3 to v4+, and xterm.js from v2.7.0 to v4+. Includes updating
js/webpack.config.js,js/tsconfig.json, andjs/package.jsonwith new compiler options. - Add documentation for the WebSocket message protocol in
docs/(specify the JSON schema forinit_message.gopayloads, input/output frame format, error responses). Currently only code serves as documentation, making client implementations difficult.
⭐Top contributors
Click to expand
Top contributors
- @yudai — 84 commits
- @jizhilong — 3 commits
- @moul — 2 commits
- @DenKoren — 1 commits
- @tsl0922 — 1 commits
📝Recent commits
Click to expand
Recent commits
a080c85— Release v2.0.0-alpha.3 (yudai)8df0bf4— Merge pull request #179 from badoo/hterm_deactivate_fix_pull (yudai)b4728f6— set deactivated terminal handlers to empty functions instead of null (DenKoren)9ac120a— Support local webpack (yudai)0bb62e0— Mention minimum go compiler version (yudai)513b3a5— Do not compile asset by default (yudai)79e1328— Update README.md (yudai)2c50c43— Release v2.0.0-alpha.2 (yudai)6ab3093— Pickup random port when port option is 0 (yudai)b2c2db0— Move responsibility to decode output encoding to terminal implementation (yudai)
🔒Security observations
- High · Outdated TypeScript Dependencies —
js/package.json - devDependencies.typescript. The package.json specifies TypeScript 2.3.2 (released in 2017), which is severely outdated and contains multiple known security vulnerabilities and bugs. This version is no longer supported and lacks security patches. Fix: Update to the latest stable TypeScript version (4.x or 5.x). Run 'npm update typescript' and test thoroughly. - High · Outdated Webpack and Build Tools —
js/package.json - devDependencies (webpack, ts-loader, uglifyjs-webpack-plugin). Webpack 2.5.1 (2017), ts-loader 2.0.3 (2017), and uglifyjs-webpack-plugin 1.0.0-beta.2 are all severely outdated. These contain known vulnerabilities and lack modern security features. The beta version of uglifyjs indicates incomplete/untested code. Fix: Update to Webpack 5.x+, ts-loader 9.x+, and use TerserPlugin instead of uglifyjs. Review and update all build tooling. - High · Outdated XTerm Dependency —
js/package.json - dependencies.xterm. XTerm 2.7.0 is outdated (released 2017) and likely contains known vulnerabilities. Modern versions include critical security fixes for terminal emulation and input handling. Fix: Update to the latest stable version of xterm (4.x or 5.x). Review changelog for security fixes between current and target version. - Medium · Potential Terminal Injection via WebSocket —
server/ws_wrapper.go, js/src/websocket.ts, server/handlers.go. The application shares terminals via WebSocket. File 'server/ws_wrapper.go' and WebSocket handling in TypeScript files suggest bidirectional command/input transmission. Without proper input validation/sanitization, this could allow command injection attacks. Fix: Implement strict input validation and sanitization for all WebSocket messages. Validate that terminal input doesn't contain shell metacharacters or escape sequences that could alter command execution. Use parameterized execution where possible. - Medium · Missing Authentication/Authorization Framework —
server/, main.go. No visible authentication mechanism in the file structure. The README mentions sharing terminals as web applications, but there's no evidence of user authentication, authorization, or access control in server/handlers.go or server/options.go. Fix: Implement authentication (e.g., JWT, OAuth2) and authorization mechanisms. Require credentials before granting terminal access. Support role-based access control. - Medium · Potential XSS via Terminal Output Rendering —
js/src/xterm.ts, js/src/hterm.ts, resources/index.html. XTerm and hterm render terminal output as HTML. If malicious terminal output contains HTML/JavaScript, it could execute in the browser context, especially if rendered with insufficient sanitization in the web frontend. Fix: Ensure XTerm and hterm are configured to safely escape HTML content. Validate that terminal output is treated as plain text. Implement Content Security Policy (CSP) headers to restrict script execution. - Medium · Missing Security Headers —
server/middleware.go, server/handlers.go. No visible implementation of security headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options) in the server code. This leaves the web interface vulnerable to clickjacking, MIME-type sniffing, and other browser-based attacks. Fix: Implement security middleware that adds: Content-Security-Policy, Strict-Transport-Security, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, X-XSS-Protection headers. - Medium · Potential Arbitrary Command Execution —
backend/localcommand/local_command.go, backend/localcommand/factory.go. The backend spawns local commands via 'backend/localcommand/local_command.go'. Without strict restrictions on what commands can be executed, users could execute arbitrary system commands with the privileges of the GoTTY process. Fix: Implement a whitelist of allowed commands. Validate command arguments
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.