A TUI wrapper around GitHub Copilot CLI that lets you play terminal games while your AI codes.
Press Ctrl-G to toggle between Copilot and a game menu with 13 games. Switch back anytime — both your Copilot session and game progress are preserved. Enable Ctrl-S auto-switch mode to automatically toggle screens based on AI activity.
- Seamless screen switching — toggle between Copilot and games with
Ctrl-G, like a terminal multiplexer - Auto-switch mode — press
Ctrl-Sto automatically switch to games when AI is working, back to Copilot when it needs input - Game state preservation — pause mid-game, check Copilot, resume exactly where you left off
- Copilot status tracking — status bar shows whether AI is working, waiting for input, or idle (via Copilot Hooks)
- 13 turn-based games — 10 WASM games compiled from nbsdgames, plus 3 built-in JS games (2048, Cookie Clicker, Tic-Tac-Toe)
- Custom games support — add your own games as single-file Node.js scripts in
~/.copilot-fun/games/ - Cross-platform — no tmux, no native binaries, just Node.js
- Node.js 18+ (tested with v23.4.0)
- GitHub Copilot CLI installed:
npm install -g @github/copilot-cli
- Platform note: Works best on Linux or WSL. macOS should work but is untested. Windows has limited support (no auto-switch, manual closing required). See Compatibility & Known Issues for details.
Run directly without installation:
npx copilot-funPass Copilot CLI arguments:
npx copilot-fun --model claude-sonnet-4.5Install globally for easier access:
npm install -g copilot-fun
copilot-fun# Clone the repository
git clone https://github.com/sirluky/copilot-fun.git
cd copilot-fun
npm install
# Link globally
npm link
# Run
copilot-fun| Key | Action |
|---|---|
| Ctrl-G | Toggle between Copilot and Game Menu |
| Ctrl-S | Toggle auto-switch mode (auto-switch between Copilot and games based on AI activity) |
| Key | Action |
|---|---|
| ↑↓ / W/S / J/K | Navigate game list |
| Enter | Launch game (or resume paused game) |
| N | Start new game (replaces any paused game) |
| Q | Return to Copilot |
| Key | Action |
|---|---|
| Arrow keys / WASD / HJKL | Move cursor |
| Enter | Confirm / act |
| Ctrl-G | Pause game, return to menu |
| Q | Quit game |
See GAMES.md for per-game controls and rules.
All games are turn-based — perfect for playing while waiting for Copilot responses.
| Game | Description | Similar to |
|---|---|---|
| Fifteen Puzzle | Slide tiles into order | 15-Puzzle |
| Mines | Classic minesweeper | Minesweeper |
| Sudoku | Number placement puzzle | Sudoku |
| Reversi | Disc-flipping strategy | Othello |
| Checkers | Diagonal capture game | Draughts |
| SOS | Letter placement strategy | Tic-Tac-Toe (ext.) |
| Battleship | Naval combat guessing | Battleship |
| Memoblocks | Memory matching cards | Concentration |
| Rabbit Hole | Maze navigation | Maze Runner |
| Revenge | Block-pushing puzzles | Sokoban |
| 2048 | Slide tiles to create 2048 | 2048 (Gabriele Cirulli) |
| Cookie Clicker | Click cookies, buy upgrades | Cookie Clicker |
| Tic-Tac-Toe | Classic 3x3 game | Tic-Tac-Toe |
You can add your own games as single-file Node.js scripts. Create a ~/.copilot-fun/games/ directory and add .js files with metadata headers.
Custom games will automatically appear in the game menu.
-
Create the games directory:
mkdir -p ~/.copilot-fun/games -
Add a game file (e.g.,
~/.copilot-fun/games/my-game.js) with metadata:// @game.id my-game // @game.name My Game // @game.desc A short description // @game.controls Arrow keys to move // @game.goal Win the game // Your game code here...
-
Requirements:
- Must be a single
.jsfile (Node.js). - Use
process.env.LINESandprocess.env.COLSfor terminal size. - Use raw ANSI escape codes for rendering.
- Do not handle
qorESC(the wrapper intercepts these).
- Must be a single
See the Custom Games section in GAMES.md for a full template and detailed guide.
┌─────────────────────────────────────────┐
│ Your Terminal │
│ ┌───────────────────────────────────┐ │
│ │ index.js (wrapper) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌───────────┐ │ │
│ │ │ Copilot PTY │ │ Game PTY │ │ │
│ │ │ + VTerminal │ │ + VTerm │ │ │
│ │ └─────────────┘ └───────────┘ │ │
│ │ │ │
│ │ [Status Bar: AI working/idle] │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
- Copilot CLI runs inside a pseudo-terminal (
node-pty) - @xterm/headless virtual terminals track screen state for both Copilot and games (like tmux does internally)
- Ctrl-G switches which screen is rendered — the inactive process keeps running and its VTerminal keeps recording output
- Ctrl-S enables auto-switch mode — automatically switches to games when AI is working autonomously, back to Copilot when it needs input
- Copilot Hooks write status to a file, polled every second by the wrapper to update the status bar and drive auto-switch
- WASM games run in their own PTY via Node.js — compiled from C with a custom ncurses shim
- JS games run as Node.js child processes with raw terminal I/O
Pre-compiled .js + .wasm files are included in wasm/. If you want to recompile:
First clone the original C source code for the games:
git clone https://github.com/abakh/nbsdgames.git nbsdgamesdocker build -t copilot-fun-build .
docker run --rm -v $(pwd)/wasm:/build/wasm copilot-fun-build# Install Emscripten SDK
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk && ./emsdk install latest && ./emsdk activate latest
source emsdk_env.sh
cd ..
# Build all games
./build-wasm.shsource /path/to/emsdk/emsdk_env.sh
emcc -O2 -I wasm -I nbsdgames \
-DNO_MOUSE -DNO_VLA -D__unix__ \
-s ASYNCIFY=1 -s 'ASYNCIFY_IMPORTS=["em_getch"]' \
-s ENVIRONMENT=node -s EXIT_RUNTIME=1 \
-s FORCE_FILESYSTEM=1 -s NODERAWFS=1 \
--js-library wasm/term_input.js \
-lm -o wasm/mines.js nbsdgames/mines.cASYNCIFYis required —getch()in C blocks, but JS stdin is async. Asyncify bridges the gap.FORCE_FILESYSTEM=1 NODERAWFS=1— without these, Emscripten'sprintCharonly flushes on newline, breaking ANSI escape code output.wasm/curses.h— a ~370-line ncurses shim mapping all curses calls to ANSI escape codes.wasm/term_input.js— Emscripten JS library providingem_getch()with raw terminal input, CR→LF translation, and arrow key parsing.trsris excluded — has a source bug (variables declared inside#ifndef NO_VLAbut used outside it).
copilot-fun/
├── index.js # Main TUI wrapper (~918 lines)
├── package.json # node-pty + @xterm/headless deps
├── Dockerfile # Docker-based WASM compilation
├── build-wasm.sh # Build script for all games
├── wasm/
│ ├── curses.h # ncurses → ANSI shim for Emscripten
│ ├── term_input.js # Emscripten JS library for terminal input
│ ├── mines.js # Compiled game (JS loader)
│ ├── mines.wasm # Compiled game (WASM binary)
│ └── ... # Other compiled games
├── games/ # Built-in JS games
│ ├── 2048.js # 2048 game implementation
│ ├── 2048.json # 2048 game metadata
│ ├── cookie-clicker.js
│ ├── cookie-clicker.json
│ ├── tictactoe.js
│ ├── tictactoe.json
│ └── README.md # Guide for adding JS games
├── .github/
│ ├── hooks/ # Copilot CLI hooks
│ │ └── copilot-fun.json # Hook configuration
│ └── prompts/ # Agent prompts
│ └── copilot-fun-add-game.md # Custom game creation guide
├── nbsdgames/ # Original C source (git submodule / clone)
├── GAMES.md # Per-game controls and rules
├── LICENSE # MIT + CC0 (for nbsdgames)
└── POST.md # dev.to blog post
The wrapper creates a ~/.copilot-fun/ directory for runtime data:
~/.copilot-fun/
├── games/ # Custom user games (single .js files)
├── status # Copilot status file (idle/working/waiting)
└── hooks-debug.log # Hook debugging output
| Environment Variable | Default | Description |
|---|---|---|
COPILOT_BIN |
copilot |
Path to Copilot CLI binary |
| Platform | Status | Notes |
|---|---|---|
| Linux | ✅ Fully supported | Best experience, auto-switch works perfectly |
| WSL (Windows Subsystem for Linux) | ✅ Fully supported | Works as well as native Linux |
| macOS | Should work, but untested — feedback welcome | |
| Windows (native) | Works but with caveats (see below) |
- No auto-switch mode — Copilot Hooks don't work natively on Windows, so status tracking (and Ctrl-S auto-switching) is unavailable
- Manual screen switching only — Use Ctrl-G to toggle between Copilot and games
- Window closing issues — The terminal may hang on exit; you may need to kill the window manually
Use WSL 2 (Windows Subsystem for Linux) — provides full Linux compatibility and fixes all the above issues.
- GitHub Copilot CLI — the AI being wrapped
- node-pty — pseudo-terminal for spawning Copilot & games
- @xterm/headless — virtual terminal for screen state tracking
- Emscripten — C-to-WASM compiler
- nbsdgames — original C terminal games (CC0)
Built entirely using Copilot CLI & Me — an AI building its own entertainment system.
MIT — see LICENSE. Games from nbsdgames are CC0 public domain.
