Files
claude-co-engineer/README.md
T
faabandClaude Opus 5.5 c5b2f6d603 Harden /ask helper, UDP replies and run_lua in multiplayer
- Pass the /ask question to claude on stdin so it can't be parsed as a CLI option.
- Block run_lua in multiplayer unless an admin enables the new
  "Allow Lua queries in multiplayer" map setting.
- Ignore UDP packets that don't come from the game's port, in both the
  MCP server and the ask helper.
- Build the screenshot path from our own name instead of the game's reply,
  and restrict screenshot names in the mod.
- Validate ask packets, cap question length and limit concurrent claude runs.
- Replace hard-coded home paths in the README and systemd unit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:40:39 +01:00

172 lines
8.7 KiB
Markdown

# Claude Co-Engineer
Ask Claude questions about your live Factorio game — "what should I do next?", "why is my
science slow?", "where's the nearest iron?" — from Claude Desktop or Claude Code, using your
subscription instead of API tokens. Works in singleplayer; no RCON needed.
It's read-only by design: Claude looks, explains and suggests; you play.
```
Claude Desktop / Claude Code ──stdio(MCP)──▶ server/ (Python) ──UDP localhost──▶ mod/ (in-game Lua)
```
The mod uses Factorio 2.x's Lua UDP API (`helpers.recv_udp` / `send_udp`), which is enabled
per game instance with `--enable-lua-udp <port>`.
## Setup
**1. Install the mod** (symlinked, so edits apply on the next save load):
```bash
ln -s "$PWD/mod/claude-co-engineer" ~/.factorio/mods/claude-co-engineer
```
Then enable "Claude Co-Engineer" in the in-game Mods menu.
**2. Launch Factorio with UDP enabled.** In Steam: Factorio → Properties → Launch Options, add:
```
--enable-lua-udp 34200
```
The game only listens on 127.0.0.1.
**3. Register the MCP server.** Requires [uv](https://docs.astral.sh/uv/).
Claude Code (run from this repo's root):
```bash
claude mcp add factorio --scope user -e FACTORIO_UDP_PORT=34200 -- uv run --directory "$PWD/server" claude-co-engineer-mcp
```
Claude Desktop — add to `claude_desktop_config.json` (Settings → Developer → Edit Config), with
`/path/to/claude-co-engineer` replaced by where you cloned this repo, then restart it:
```json
{
"mcpServers": {
"factorio": {
"command": "uv",
"args": ["run", "--directory", "/path/to/claude-co-engineer/server", "claude-co-engineer-mcp"],
"env": { "FACTORIO_UDP_PORT": "34200" }
}
}
}
```
Local (stdio) MCP servers only work in the desktop app and Claude Code, not claude.ai in a browser
or the mobile apps.
## Tools
| Tool | Answers |
|---|---|
| `get_overview` | Where am I, what am I hovering, what's researching, what's broken — start here |
| `get_player` | Inventory, cursor, hand-crafting queue, hovered/opened entity |
| `inspect_entity` | Everything about the hovered entity (or one at x,y): status, recipe, contents, fuel, power |
| `find_problems` | Machines not working, grouped by status (no_ingredients, full_output, low_power, …) with nearest examples |
| `find_entities` | What's around a point; ore patches with total amounts |
| `get_production` | Produced/consumed/net per minute per item and fluid |
| `get_power` | kW consumption and production per electric network |
| `trace_belt` | Follows a belt (the hovered one by default) through undergrounds, side-loads and splitters: fill and motion per section (backed up vs full and flowing), what inserters and drills put on or take off, and where it ends |
| `get_trends` | How production, consumption and power changed over the last 10 min / hour / 10 hours; finds the biggest movers by itself |
| `get_research` | Current/queued research, what's researchable now, the path to any technology |
| `get_recipe` | How to make something, in which machines, whether it's unlocked, what uses it |
| `calculate_ratios` | Machines, drills, belts and power for a target rate (or machine count), using your unlocked recipes and machines, research productivity, and what you've already built |
| `screenshot` | An image of part of the map (Alt mode on, always daylight) for layout questions |
| `highlight` / `clear_highlights` | Outline places in your game, with labels, guide lines from you, and clickable map links in chat |
| `run_lua` | Read-only Lua query for anything else |
"This" usually works: hover over a machine and ask "why isn't this working?".
When Claude points you at something, it outlines it in your world and posts a `[gps]` link in chat
(click it to open the map there). Highlights are visible only to you, expire after a minute by
default, and are purely visual.
`run_lua` is instructed to only read, but Lua can't be sandboxed read-only. To guarantee nothing in
your world changes, turn off **Allow Lua queries** in Settings → Mod settings → Map. Every query is
logged to `factorio-current.log`.
In multiplayer, `run_lua` is off unless an admin also turns on **Allow Lua queries in multiplayer**:
the Lua runs for everyone, and text other players put in the world (station names, labels) ends up
in what Claude reads, so it could be talked into changing things.
## Asking from inside the game
Type `/ask <question>` in the game chat (e.g. `/ask why is my green science slow?`). The answer
appears in chat a few seconds to a minute later, with clickable map links and item icons, and
the places it mentions get highlighted. Follow-up questions continue the same conversation;
`/ask-new` starts a fresh one.
```
/ask ──UDP──▶ claude-co-engineer-ask ──▶ claude -p (+ this MCP server) ──▶ answer ──UDP──▶ chat
```
This needs:
- the `claude` CLI logged in with your subscription (`claude auth login`, once);
- the helper running. Either start it by hand from this repo's root:
```bash
uv run --directory server claude-co-engineer-ask
```
or install it as a systemd user service that starts at login (from this repo's root; this fills in
its path):
```bash
uv sync --directory server && mkdir -p ~/.config/systemd/user && sed "s|/path/to/claude-co-engineer|$PWD|" server/claude-co-engineer-ask.service > ~/.config/systemd/user/claude-co-engineer-ask.service && systemctl --user daemon-reload && systemctl --user enable --now claude-co-engineer-ask
```
Its log shows each question and answer: `journalctl --user -u claude-co-engineer-ask -f`.
Pick the model under Settings → Mod settings → Per player → **/ask model**: Haiku, Sonnet
(default), Opus or Fable. Bigger models give more thorough answers but are slower and use more of
your plan's usage. It's per player, so in multiplayer everyone picks their own.
The dropdown entries are aliases, which the `claude` CLI resolves to the newest model of that name,
so a new Sonnet or Opus is used automatically. To force any other model, uncomment
`FACTORIO_ASK_MODEL_OVERRIDE` in `~/.config/systemd/user/claude-co-engineer-ask.service` (an alias or a full model ID)
and run `systemctl --user daemon-reload && systemctl --user restart claude-co-engineer-ask`. It wins
over the in-game setting for everyone.
Claude only gets the Factorio tools in these sessions: no shell, files or web. If the helper isn't
running, the game tells you after 3 seconds. The helper's port is a map setting (Ask helper port, default 34201).
Helper environment variables: `FACTORIO_ASK_PORT`, `FACTORIO_ASK_MODEL` (model when the game doesn't
send one, default `sonnet`), `FACTORIO_ASK_MODEL_OVERRIDE` (always use this model),
`FACTORIO_ASK_TIMEOUT` (300 s), `FACTORIO_ASK_MAX_CONCURRENT` (Claude runs at once across all players,
default 2), `FACTORIO_ASK_CLAUDE` (path to the CLI). The helper only accepts packets from the game's UDP port.
## Ratio calculator
Ask things like "how many assemblers for 1 green science per second?" or "what does 10 red
science assemblers need?". `calculate_ratios` works from your game, not a generic table:
- **Recipe:** the unlocked one for each item (never recycling). Mineable items count as mined, so
Space Age asteroid ore doesn't sneak in.
- **Machine:** the type you already use for that recipe, otherwise the fastest one you've unlocked.
- **Productivity:** research and machine bonuses are included. Modules and beacons aren't (yet).
- **Output:** per step, how many machines you need, how many you've already built on that recipe,
and how much you currently make. Ore becomes mining drill and belt counts.
Tell it what you already supply ("plates come from my main bus") to stop the breakdown there, or
override the recipe or machine for any item. Byproducts are listed but not subtracted from demand.
## Configuration
Environment variables for the server: `FACTORIO_UDP_PORT` (default 34200), `FACTORIO_UDP_HOST`
(127.0.0.1), `FACTORIO_TIMEOUT` seconds (5), `FACTORIO_SCRIPT_OUTPUT` (`~/.factorio/script-output`).
Screenshots are rendered off-screen with `game.take_screenshot` (your camera doesn't move), written
to `script-output/claude-co-engineer/`, and deleted once sent to Claude.
## Troubleshooting
- **"No reply from Factorio"**: the game must be running a save, launched with `--enable-lua-udp`
on the same port, with the mod enabled — and not paused. Singleplayer pauses while the Esc menu is open.
- **Headless servers** pause with no players connected unless `auto_pause` is false in
server settings. With nobody connected, queries use the `player` force and the first surface.
- **Screenshots** need a game client that renders; a headless server can't take them.
- Changes to `control.lua` take effect after reloading the save; changes to `settings.lua` need a
full game restart.