Developer Lawrence Gripper releases free, open-source project enabling interactive terminals in failed GitHub Actions workflows using peer-to-peer WebRTC connections.
Solving the Debugging Bottleneck
Developers frequently encounter a frustrating loop when GitHub Actions workflows fail unexpectedly: push speculative code changes, wait for the CI run, then repeat when failures persist. Lawrence Gripper's new project (actions-term) eliminates this guesswork by providing direct terminal access to failed Actions runners. The open-source tool establishes a peer-to-peer connection between the GitHub Actions virtual machine and a developer's browser using WebRTC, bypassing costly data relay services.
Technical Architecture
At its core, the solution leverages WebRTC's UDP hole-punching capability to create direct connections between the Actions runner and end-user browsers. This eliminates the need for expensive traffic relay servers—the signaling service only handles initial introductions between peers:
Identity Verification:
- Browser users authenticate via GitHub OAuth
- Actions runners generate cryptographically signed OIDC tokens using GitHub's identity service
- The signaling server validates both ends using JWKS (code reference)
Signaling Mechanism:
- Server-sent events (SSE) coordinate connection details
- Session mapping ensures users only access their own workflows
Terminal Handling:
- Actions runners spawn PTY shells that stream data through WebRTC data channels
- Browser terminals render output using Ghostty's xterm.js implementation
- Dynamic terminal resizing compensates for rendering discrepancies
Zero-Trust Security Enhancement
To mitigate risks from potential signaling server compromises, Gripper implemented a secondary verification layer:
- Actions runners generate one-time password (OTP) secrets
- Browser users must input valid OTPs before terminal access is granted
- Validation occurs directly between peers, never touching the signaling server
"This approach ensures that even if the signaling service is compromised, attackers can't execute commands without intercepting the dynamically generated OTP," Gripper explains.
Memory consumption for Railway-hosted signaling service peaks around 20MB
Cost-Efficient Hosting
Deployed on Railway's usage-based infrastructure, the signaling service leverages:
- Pay-per-use billing (currently negligible cost)
- Automatic sleep mode during inactivity
- Sub-second cold starts (demo)
"Traditional cloud providers would require reserving entire VMs for this workload," notes Gripper. "Railway's granular resource accounting makes it economically viable to offer this freely."
The project remains experimental—networks blocking UDP hole punching won't establish connections, and there's no TURN relay fallback. Developers can self-host the open-source stack or experiment with the public instance.

Comments
Please log in or register to join the discussion