Skip to content

gabrielmaialva33/winx-code-agent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

518 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Winx fairy mascot

✨ Winx - MCP Server for Shell & Coding Agents ✨

πŸ¦€ Native Rust implementation inspired by WCGW, built for local code-agent workflows

Language License MCP stdio transport

A local MCP server you can hand to a coding agent and stop worrying about the shell.

Winx is the MCP server I wanted while running Claude, Codex, and friends against real repos: one process that handles the shell, file IO, and PTY-backed interactive sessions, written in Rust so it doesn't fight you on stdio.

It started as a Rust port of WCGW but isn't a Python wrapper. Everything runs on a real PTY (via portable-pty), cd actually sticks, Ctrl+C actually interrupts, and background shells survive long-running TUIs without leaking output buffers into your token budget.

What you get

  • A stateful bash session per thread with proper PTY semantics β€” foreground, background, status checks, text input, Enter/Ctrl-C/Ctrl-D, raw ASCII. Multiline scripts and top-level command shorthand both work; NUL bytes are rejected before they reach the shell.
  • Workspaces with three modes: wcgw (full access), architect (read-only), code_writer (allowlist of commands and write globs). The command allowlist is parsed with tree-sitter, so it checks every command on the line β€” pipelines, &&/||/;, command substitution, subshells β€” not just the first word, and can't be bypassed with ls && curl … | sh or ls $(rm …).
  • A resilient PTY: a shell that won't return to a prompt (even after Ctrl-C) is auto-reset at the same cwd/mode, child processes are reaped on drop, and prompt detection is robust to a custom PS1. Opt into zsh with WINX_SHELL=zsh.
  • File reads with WCGW-style line ranges (file.rs:10-40, file.rs:10-, file.rs:-40). Active files are tracked and prioritized in the repository context across calls.
  • File writes and SEARCH/REPLACE edits that survive ambiguous matches, indentation drift, and the usual unicode quote-mismatches from LLMs. Writes are blocked when the file hasn't been read or the cached content is stale.
  • ContextSave for handing a task summary plus its files to the next session β€” including workspace context, active files, git status/diff, and terminal sharing for proper resumption. Resuming reopens the saved project root and token-caps the restored memory so it never overflows the context window.
  • ReadImage so multimodal clients can pull screenshots, mockups, error PNGs, etc.
  • Clean, token-aware shell output: cursor/ANSI noise from interactive programs (REPLs, progress bars) is rendered away through a terminal emulator, and mechanical repetition is collapsed losslessly (line [winx: Γ—N]) so build/install logs don't blow your context budget. Toggle the collapsing with WINX_NO_COMPRESS.
  • Two transports: stdio for local clients, plus an optional token-gated Streamable HTTP server (winx serve --http) for remote MCP clients like ChatGPT β€” see Remote access.

MCP Tools

Tool What it does
Initialize Boots the workspace, picks the mode, hands you a thread_id. Call this first or everything else errors out. With no workspace path it spins up a scratch playground; resuming a task (task_id_to_resume) reopens its saved project root.
BashCommand Runs commands, polls long-running ones, sends Enter/Ctrl-C, drives TUIs. Supports is_background, status_check, send_text, send_specials, send_ascii, allow_multi for multi-statement scripts.
ReadFiles One or many files, with line numbers. Append :10-40 to a path for a range. When the token budget is hit it tells you the exact line + file:N-M syntax to resume from instead of silently dropping the tail.
FileWriteOrEdit Full overwrites or SEARCH/REPLACE blocks. Validates file read coverage and freshness before writing, then runs a tree-sitter syntax check (18+ languages) and points at the offending line with a snippet.
ContextSave Dumps task description + file globs into a single text file with workspace context, active files, and git status/diff for clean handoff and task resumption.
ReadImage Returns a native MCP image content block (not base64 as text), so multimodal models actually see the image.

Search/Replace editing

Standard block syntax:

<<<<<<< SEARCH
old content
=======
new content
>>>>>>> REPLACE

Things the matcher forgives so you don't have to babysit the model:

  • atomic: ambiguous or missing matches abort without touching the file
  • adjusts replacement indentation when the LLM gets the leading whitespace wrong
  • strips ReadFiles line numbers if they leak into a SEARCH block
  • normalizes the usual "smart quote" / em-dash / ellipsis substitutions
  • uses neighboring blocks to disambiguate when the same snippet appears twice
  • single-line substring edits work β€” you don't need the whole line in SEARCH
  • retries once with \" unescaped when the model over-escapes quotes in SEARCH
  • refuses edits that only matched after too much fuzzy fixup, and rejects blocks that match in too many places β€” so you re-read instead of corrupting the file

Install

cargo install winx-code-agent

Binary lands in ~/.cargo/bin β€” every config snippet below assumes that's on $PATH. If your MCP client launches with a sterile env, swap winx-code-agent for the absolute path (which winx-code-agent).

Needs Rust 1.75+, Linux/macOS/WSL2, and a real terminal (any modern one β€” Winx spawns its own PTY).

Claude Code (CLI)

One-liner via the CLI (stdio is the default transport):

claude mcp add winx -- winx-code-agent

Or drop a .mcp.json in your project root:

{
  "mcpServers": {
    "winx": {
      "command": "winx-code-agent",
      "env": { "RUST_LOG": "winx_code_agent=info" }
    }
  }
}
Claude Desktop

Add to your config file (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows):

{
  "mcpServers": {
    "winx": {
      "command": "winx-code-agent",
      "env": { "RUST_LOG": "winx_code_agent=info" }
    }
  }
}

Restart Claude Desktop after saving.

Codex (OpenAI CLI)

One-liner:

codex mcp add winx -- winx-code-agent

Or edit ~/.codex/config.toml:

[mcp_servers.winx]
command = "winx-code-agent"
env = { RUST_LOG = "winx_code_agent=info" }
Cursor

Add to ~/.cursor/mcp.json (or .cursor/mcp.json for project-local):

{
  "mcpServers": {
    "winx": {
      "command": "winx-code-agent",
      "env": { "RUST_LOG": "winx_code_agent=info" }
    }
  }
}
VS Code (Copilot Chat / MCP)

Add to .vscode/mcp.json:

{
  "servers": {
    "winx": {
      "type": "stdio",
      "command": "winx-code-agent"
    }
  }
}
Zed

Add to your Zed settings (~/.config/zed/settings.json):

{
  "context_servers": {
    "winx": {
      "source": "custom",
      "command": "winx-code-agent",
      "args": [],
      "env": { "RUST_LOG": "winx_code_agent=info" }
    }
  }
}
Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "winx": {
      "command": "winx-code-agent",
      "env": { "RUST_LOG": "winx_code_agent=info" }
    }
  }
}
OpenCode

Add to opencode.json:

{
  "mcp": {
    "winx": {
      "type": "local",
      "command": ["winx-code-agent"],
      "enabled": true,
      "environment": { "RUST_LOG": "winx_code_agent=info" }
    }
  }
}
Gemini CLI

Add to ~/.gemini/settings.json:

{
  "mcpServers": {
    "winx": {
      "command": "winx-code-agent",
      "args": [],
      "env": { "RUST_LOG": "winx_code_agent=info" }
    }
  }
}
agy (Google Antigravity CLI)

agy is Google's new Gemini-powered CLI (Go binary, usually at ~/.local/bin/agy). No mcp add subcommand yet β€” it reads MCP servers from JSON.

Edit ~/.gemini/config/mcp_config.json (also ~/.gemini/antigravity/mcp_config.json if you run the Antigravity IDE alongside):

{
  "mcpServers": {
    "winx": {
      "command": "winx-code-agent",
      "env": { "RUST_LOG": "winx_code_agent=info" }
    }
  }
}

If winx-code-agent is not on the agy process $PATH, swap command for the absolute path (~/.cargo/bin/winx-code-agent after cargo install winx-code-agent).

Continue.dev

Add to your ~/.continue/config.yaml:

mcpServers:
  - name: winx
    command: winx-code-agent
    env:
      RUST_LOG: winx_code_agent=info
Kiro

Add to ~/.kiro/settings/mcp.json:

{
  "mcpServers": {
    "winx": {
      "command": "winx-code-agent",
      "env": { "RUST_LOG": "winx_code_agent=info" }
    }
  }
}
Warp

Settings β†’ MCP Servers β†’ Add MCP Server:

{
  "winx": {
    "command": "winx-code-agent",
    "env": { "RUST_LOG": "winx_code_agent=info" }
  }
}
Roo Code

Add to your Roo Code MCP config:

{
  "mcpServers": {
    "winx": {
      "type": "stdio",
      "command": "winx-code-agent"
    }
  }
}
Other clients (generic stdio)

Any client that speaks stdio MCP works with this shape:

{
  "mcpServers": {
    "winx": {
      "command": "winx-code-agent",
      "args": [],
      "env": { "RUST_LOG": "winx_code_agent=info" }
    }
  }
}

If your client launches Winx with an empty $PATH, swap command for the absolute path ( ~/.cargo/bin/winx-code-agent).

Build from source

For unreleased changes or a custom build:

git clone https://github.com/gabrielmaialva33/winx-code-agent.git
cd winx-code-agent
cargo install --path .

Or run it without installing:

cargo run --release

Check it's wired up

List MCP tools in your client. You should see six entries: Initialize, BashCommand, ReadFiles, FileWriteOrEdit, ContextSave, ReadImage. The first call always has to be Initialize β€” Winx tracks workspace + mode per thread.

Remote access (ChatGPT & other remote MCP clients)

By default Winx speaks MCP over stdio β€” the local transport every desktop client (Claude Desktop, Cursor, VS Code) uses. For clients that live in the cloud and can't reach your machine over stdio β€” like ChatGPT's developer-mode custom connectors β€” Winx can also serve MCP over Streamable HTTP:

winx serve --http --bind 127.0.0.1:8000 --token "$(openssl rand -hex 24)"

The MCP protocol is served at /mcp. Every request must carry the token, either as Authorization: Bearer <token> or a ?token=<token> query parameter. Without a token the server refuses to start β€” serving a shell over the network without auth is remote code execution waiting to happen.

Flag Purpose
--http Serve over Streamable HTTP instead of stdio.
--bind Listen address. Defaults to 127.0.0.1:8000. Keep it on loopback.
--token Shared secret required on every request. Falls back to the WINX_HTTP_TOKEN env var.
--allowed-host Extra Host authority to accept (your tunnel hostname). Repeatable. Loopback is always allowed.

Remote clients run in the cloud, so the endpoint has to be reachable over HTTPS β€” put a tunnel in front of the loopback listener and allow its hostname through the built-in DNS-rebinding guard:

# 1. tunnel first, to learn the public hostname
cloudflared tunnel --url http://localhost:8000
#    -> https://<random>.trycloudflare.com

# 2. start Winx, allowing that host
winx serve --http --bind 127.0.0.1:8000 \
     --token "$(openssl rand -hex 24)" \
     --allowed-host <random>.trycloudflare.com

In ChatGPT (Settings β†’ Apps β†’ Advanced β†’ Developer mode), add a connector with:

  • URL: https://<random>.trycloudflare.com/mcp?token=<your-token>
  • Authentication: None (the secret rides in the URL)

Remote clients are effectively stateless β€” they don't reuse the MCP session between tool calls β€” so the HTTP transport shares one shell session across all requests: the shell Initialize creates stays alive for the lifetime of the server, and later BashCommand calls find it. Reuse the same thread_id across calls.

Warning

The HTTP transport puts arbitrary shell and file access on the network. Anyone with the token (and URL) gets a shell on your machine as your user β€” and not just inside the workspace, since BashCommand in wcgw mode isn't path-restricted. Bind to loopback, keep it behind an authenticated tunnel, prefer architect/code_writer mode or a container, and shut it down when you're done.

Environment variables

All optional β€” Winx works out of the box without any of these.

Variable Effect
RUST_LOG Log verbosity, e.g. winx_code_agent=info. At info you get the per-call audit trail (tool name, arg summary, duration, ok/error).
WINX_HTTP_TOKEN Shared secret for the HTTP transport, used if --token isn't passed (see Remote access).
WINX_NO_COMPRESS Set to 1 to disable output compression and see raw, uncollapsed shell output (the [winx: Γ—N] collapsing is on by default).
WINX_KEEP_TAIL_PIPE Set to 1 to keep a trailing | tail … instead of stripping it. Winx truncates output server-side, so by default it drops a redundant trailing tail (wcgw parity).
WINX_USE_SCREEN / WINX_ATTACH_TERMINAL Run the shell inside screen/tmux so you can attach to the live session. Set to screen, tmux, or any truthy value; Winx prints an attach hint on Initialize.
WINX_OPEN_CONTEXT Set to 1 to open the saved context file in your default app after ContextSave.
WINX_SHELL Set to zsh to run the session under zsh instead of bash (opt-in; bash stays the default). Falls back to bash if zsh isn't on PATH or the mode is restricted.
WINX_SERVER_INSTRUCTIONS Extra operator instructions appended to every Initialize response (e.g. house rules for the agent).

Hacking on it

cargo fmt --all
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features

CI runs the same three. If you touch src/state/pty.rs or anything in src/tools/bash_command.rs, the regression suite at tests/bash_pty_regression_test.rs is what protects against the usual TUI/PTY foot-guns β€” run it first.

A note on security

By default this is a local (stdio) MCP server. Anything connected to it can read files, edit files, and run shell commands inside the workspace β€” same blast radius as letting the model into your terminal. The optional HTTP transport (--http) extends that reach to the network; see Remote access for the extra precautions it demands.

If you want a tighter leash:

  • architect mode disables writes and most commands;
  • code_writer mode lets you allowlist commands and write globs.

SECURITY.md has the disclosure process and threat model.

License

MIT - Gabriel Maia (@gabrielmaialva33)

About

πŸ¦€ A high-performance code agent written in Rust, combining the best features of WCGW for maximum efficiency and semantic capabilities.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Contributors