Skip to main content
Glama
4i7

Veyrqel

by 4i7

Veyrqel

Persistent Windows and WSL2 terminal control for ChatGPT through MCP.

TypeScript Node.js Cloudflare Workers MCP Windows 11 WSL2 Kali

Veyrqel keeps PowerShell 7 and WSL2 Kali PTYs on the operator's Windows machine while ChatGPT controls them through an authenticated Cloudflare-hosted MCP relay. Sessions are persistent across tool calls, so working directories, shell state, environment variables, interactive programs and follow-up input can remain alive while the model reasons over incremental output.

Veyrqel does not provide a shared relay endpoint. Each operator deploys their own Cloudflare Worker and pairs only their own device.

What it does

  • Persistent windows-pwsh and wsl-kali terminal sessions.

  • Interactive raw PTY input and incremental reads instead of one-shot command execution.

  • ChatGPT-facing MCP tools for device status, operation submission and result retrieval.

  • GitHub OAuth owner binding for the MCP client.

  • Separate device credential for the Windows-side outbound WebSocket.

  • Durable operation admission and replayable receipts to avoid accidental duplicate execution.

  • Per-process epochs so requests from a previous device process are rejected after restart.

  • Local hidden secret input for password-backed sudo without placing passwords in model tool arguments.

  • Explicit shell environment allowlisting on the remote device path.

There is no WSL-side agent, inbound listener, privileged broker or command-name denylist. OS authorization remains authoritative.

Architecture

ChatGPT
   |
   | MCP + OAuth
   v
https://<your-worker-origin>/mcp
   |
   v
Cloudflare Worker
   |-- GitHub OAuth + owner binding
   |-- OAUTH_KV
   `-- Durable Object: Broker
            |
            | authenticated outbound WebSocket
            v
       Windows Veyrqel device
            |
            |-- operation journal
            |-- SessionManager
            `-- node-pty / ConPTY
                   |-- PowerShell 7
                   `-- WSL2 Kali / bash

The Windows device owns all real PTYs. Cloudflare brokers authenticated control traffic and durable operation state; terminal execution remains local to the paired Windows machine.

Current remote tools

The remote MCP surface intentionally exposes three tools:

Tool

Purpose

device_status

Report whether the paired device is online and return its current process epoch.

terminal_submit

Admit one terminal lifecycle/input/read operation under a fresh UUID.

terminal_result

Retrieve the receipt for that exact operation without rerunning it.

terminal_submit supports open, list, input, read, close and forget.

Submission is not command completion. After sending shell input, read the same session until the expected output or prompt is observed.

Start the paired Windows device

On the paired Windows machine, use a visible, non-Administrator PowerShell 7 window with Node.js 22 or newer. The operator configuration and profiles remain under %LOCALAPPDATA%\Veyrqel.

$launcher = Invoke-RestMethod 'https://raw.githubusercontent.com/4i7/Veyrqel/main/scripts/start-device.ps1'
& ([scriptblock]::Create($launcher))

The launcher downloads the latest GitHub-built Windows release, checks its published SHA-256 digest and commit metadata, runs the device from a temporary directory, and removes that runtime after the process exits. Keep the window open for terminal access and local hidden password input. A local Git checkout, npm ci, TypeScript build, and Wrangler are not needed for normal device startup.

If device_status reports online: false, check whether this visible device window is still running. Start it with the command above if it has stopped, then call device_status again. An offline result does not authorize resending an uncertain terminal operation.

Developer setup from a checkout

Requirements:

  • Windows 11

  • PowerShell 7

  • Node.js 22+

  • WSL2 with an already provisioned Kali Linux user

Create the operator-owned local profile file:

npm.cmd ci
Copy-Item profiles.example.json profiles.local.json
# Edit local paths and the explicit non-root Kali username.
npm.cmd test
npm.cmd run smoke

profiles.local.json is ignored by Git. No machine setup, distro provisioning, sudoers changes or account privilege changes are performed by Veyrqel.

npm ci applies the version-checked ConPTY lifecycle patch. Installing with --ignore-scripts does not produce the qualified runtime.

Typical ChatGPT flow

1. device_status
2. open wsl-kali or windows-pwsh
3. input command text + carriage return
4. terminal_result for the submitted operation
5. read the session output
6. reason over the output
7. send follow-up input to the same session
8. close and forget the test session when finished

This persistent loop is suitable for interactive shell work where state must survive between reasoning steps, including controlled lab environments such as local development, debugging and authorized training systems.

Local password input

Do not send passwords through model tool calls.

When a trusted program in a managed PTY is waiting for a password, use the visible device console locally:

sessions
secret <sessionId>

If exactly one ready session matches a profile, the profile shortcut is available:

secret wsl-kali
secret windows-pwsh

The value is entered locally with hidden input and bypasses MCP arguments and operation journals. Exact matching terminal echoes are redacted before entering the remote output ring. See Cloudflare setup: local password input for the full security boundary.

Local stdio MCP

After npm.cmd ci and npm.cmd run build, a local MCP client can run:

node <absolute-path>/dist/src/mcp/stdio.js <absolute-path>/profiles.local.json

or from this checkout:

npm.cmd run mcp

The local stdio MCP exposes terminal_open, terminal_list, terminal_input, terminal_read, terminal_close and terminal_forget.

Library API

import { ProfileRegistry, SessionManager } from './dist/src/main.js';

const manager = new SessionManager(new ProfileRegistry(operatorProfiles));
try {
  const session = await manager.open('windows-pwsh');
  manager.write(session.sessionId, "Write-Output 'hello'\r");
  console.log(manager.read(session.sessionId));
  manager.close(session.sessionId);
  manager.forget(session.sessionId);
} finally {
  manager.shutdown();
}

Applications must read asynchronously and provide their own shutdown handling. READY is a session state, not a command-completion fence.

Cloudflare relay

Operator origin:

https://<your-worker-origin>

Important routes:

/mcp       ChatGPT MCP endpoint
/device    authenticated Windows-device WebSocket
/authorize OAuth authorization
/token     OAuth token exchange
/register  dynamic MCP client registration
/callback  GitHub OAuth callback
/health    public service health

Local Cloudflare qualification commands:

npm.cmd run cloud:check
npm.cmd run cloud:test
npm.cmd run cloud:live

cloud:test runs the real Worker/DO/OAuth/MCP implementation with mocked GitHub and terminal peers. cloud:live connects the local relay implementation to configured real Windows and WSL PTYs while GitHub authentication remains mocked. Neither command deploys.

Reliability model

Every device process has an epoch. Every submitted terminal operation has a caller-generated UUID.

  • Durable admission is recorded before dispatch.

  • The relay never automatically retries execution.

  • Reusing the same operation ID with the same payload returns the existing admission.

  • Reusing it with a different payload returns a conflict.

  • A device restart changes epoch and retires prior operation state.

  • UNKNOWN_OUTCOME requires reconciliation; it is not permission to resend an effect under a new ID.

See Cloudflare setup for capacity limits and protocol details.

Qualification status

The implementation has passed bounded local and integration checks for:

  • real ChatGPT -> public MCP -> Windows device control;

  • persistent PowerShell and WSL2 Kali sessions;

  • GitHub OAuth owner binding;

  • password-authenticated Kali sudo through local hidden input;

  • operation receipt replay and duplicate-operation suppression;

  • controlled production WebSocket interruption and reconnect with session/receipt preservation;

  • Windows/WSL foreground descendant cleanup and repeated exit/close races.

Each operator must qualify their own Cloudflare/OAuth/device pairing. Automatic Windows logon startup and exhaustive recovery from arbitrary Cloudflare outages, OS sleep, network failures, detached-process schedules and PID reuse remain outside the qualified boundary.

Documentation

Related MCP Connectors