Pre-launch.NetCraftGames is not accepting customers yet. Launch happens only after its public checks pass.See launch statusJoin the waitlist

AI prompt

Express or Fastify server for NetCraftGames

A copy-paste prompt that makes your AI get an Express or Fastify game server with WebSocket ready for NetCraftGames, on the root path, as one Linux program. Copy it, paste it into your AI coding assistant, and read what it changes.

By Charging Bull SoftwareLast updated:

When to use this prompt

Your Node.js server uses Express or Fastify next to the WebSocket server, for example to serve pages or an API.

If you are not sure this is the right prompt, answer the five questions on the check first: it names the one prompt that fits.

The prompt

Status: Manifest checked by our validator. Not yet tried against a real AI.

Node.js with Express or Fastify and WebSocketClick inside the box to select it all, then copy.
You are preparing an existing multiplayer game so a hosting service (NetCraftGames) can run its dedicated server on a Linux machine.
Rules for you:
- Make ONLY the changes listed below. Do not redesign game logic. Do not add multiplayer to a game that has none. If something below cannot be done without a redesign, stop and tell me instead of improvising.
- Never put a password, key or token in code or in any file. Read secrets from environment variables.
- Run every proof step at the end and show me the real output. If a proof step fails, fix it or tell me exactly why you cannot.
- If a step needs a tool you do not have, say so and stop at that step. Do not invent a substitute and do not pretend the step passed.

Facts about the host (exact):
- Linux x86-64, glibc 2.39 or older for every compiled program in the upload.
- The server starts as an unprivileged user in /game. Writable places: /game/saves and a 256 MB /tmp. Nothing is installed, downloaded or compiled on the host. The start command is a fixed list of arguments, not a shell string.
- The host (Ubuntu 24.04 LTS) provides these programs: sh, bash, dash, python3, node, node24 (Python 3.12, Node.js 24.21.0). There is no Java, .NET, Deno or Bun on the host unless you ship it inside the upload.
- Nothing is installed or downloaded on the host: packages travel inside the upload, built for Linux x64 on the owner's own computer.
- A game server cannot look up other websites by name (DNS is closed to it on purpose), so do not make the server depend on calling an outside address by name.
- The host does not set a PORT variable. The port your server uses by default must be the port written in the manifest.
- The host stops the server with SIGTERM and waits up to the number of seconds in the manifest (between 1 and 300).
- The upload is one .tar.gz of at most 512 MiB with at most 10,000 files, no symlinks and no setuid files.
- The host checks your server from outside with a 3 second timeout per request.

TASK: Make this Express or Fastify game server ready for NetCraftGames.
1. Express: build the HTTP server yourself and attach the WebSocket server to it:
     const server = http.createServer(app);
     const wss = new WebSocketServer({ server });
     server.listen(Number(process.env.PORT ?? 8080), '0.0.0.0');
   Fastify: fastify.listen({ host: '0.0.0.0', port: Number(process.env.PORT ?? 8080) }) with the WebSocket route (@fastify/websocket) at "/" or at one fixed path.
2. Serve R2 and R3 below as ordinary routes (app.get or fastify.get), and keep every other route as it is.
3. Add the loopback player-count listener (R4) and the shutdown handler (R5). On shutdown close the HTTP server and the WebSocket server.
4. Accept WebSocket connections at the root path "/" (simplest). If the code must keep another fixed path such as "/ws", that is fine: declare it as "wsPath" in the manifest (the second ncg.json below) and the gateway connects to exactly that path. Do not use a path that changes for each room or each player: the gateway cannot follow it. Players never connect to the path themselves; they use the gateway address from the connection config.
5. Packaging: our servers provide Node.js 24.21.0 and install nothing, so the upload carries your code and its packages, built for Linux x64 on the owner's computer, not by you and not on the host.
   - Prefer pure JavaScript packages (ws needs no add-on: leave out the optional bufferutil and utf-8-validate). Stop and ask before adding a package that has a native add-on (a .node file).
   - package.json: "engines": { "node": ">=24" }, a "start" script that runs your entry file (for example "node server.js"), and only the packages the game needs under "dependencies".
   - Make sure package-lock.json exists (the owner runs npm install once to create it). Do not edit anything inside node_modules.
   - If the project is TypeScript, compile it to JavaScript first and tell the owner to pass the built file with --entry <file>.
   - Do NOT write a start script and do NOT pack anything yourself. The owner runs  ncg pack . --node --install  which builds .ncg/build (your code under app/, the production packages for Linux x64 and a start script named server that runs node with --max-old-space-size=2048), then  ncg check .ncg/build  and fixes everything it lists.

Server requirements (all exact):
R1  Listen on 0.0.0.0 (never 127.0.0.1 only, never a random port). Read the port from the PORT environment variable and default to 8080.
R2  Health probe: an HTTP GET /health on TCP port 8080 answers HTTP 200 with the body exactly "ok" within 3 seconds. It must not touch a database or game state. Return 503 if the server loop is stalled or shutting down.
R3  Join probe: an HTTP GET /join-probe on the same port answers 200 with a body that contains "joinable" while a new player could be admitted, otherwise 503 with the body "full" or "stopping". It needs no login and exposes nothing private.
R4  Player count: a second HTTP listener bound to 127.0.0.1 only, port 9090. GET /players answers 200 with JSON {"players": N}, where N is the number of connected players, a whole number from 0 to 10,000, in a body under 4 KB. Do not count a health probe, a join probe or a player who is only in a reconnect grace window.
R5  Shutdown: on SIGTERM (and SIGINT) stop admitting players, tell connected clients, write the save atomically (write a temporary file in the same folder, flush it, then rename it) under /game/saves, close sockets and exit with code 0 within the grace seconds.
R6  Saves and every other file the server writes live under /game/saves only. Read the folder from an environment variable SAVE_DIR and default to /game/saves (use ./saves when running on your own computer).
R7  Log events (join, leave, error), not every tick. The host drops log lines above its rate limit.

6. Write ncg.json with exactly this content:

----- ncg.json (start) -----
{
  "ncg": 1,
  "game": {
    "name": "My Game"
  },
  "version": "0.1.0",
  "build": {
    "dir": ".ncg/build"
  },
  "manifest": {
    "engine": "browser-wss",
    "transport": "wss",
    "platforms": [
      "web"
    ],
    "mode": "dedicated",
    "networkingImplemented": true,
    "os": "linux",
    "arch": "x64",
    "command": [
      "/game/server"
    ],
    "ports": [
      {
        "port": 8080,
        "protocol": "tcp"
      }
    ],
    "profile": "standard",
    "savePath": "/game/saves",
    "health": {
      "type": "http",
      "port": 8080,
      "path": "/health",
      "expected": "ok"
    },
    "playerProbe": {
      "type": "http",
      "port": 9090,
      "path": "/players"
    },
    "joinProbe": {
      "type": "http",
      "port": 8080,
      "path": "/join-probe",
      "expected": "joinable"
    },
    "shutdown": {
      "signal": "SIGTERM",
      "graceSeconds": 30
    },
    "idleSupported": true
  }
}
----- ncg.json (end) -----

If the WebSocket route keeps a path (for example '/ws'), write this ncg.json instead; it differs only in "wsPath":

----- ncg.json (start) -----
{
  "ncg": 1,
  "game": {
    "name": "My Game"
  },
  "version": "0.1.0",
  "build": {
    "dir": ".ncg/build"
  },
  "manifest": {
    "engine": "browser-wss",
    "transport": "wss",
    "platforms": [
      "web"
    ],
    "mode": "dedicated",
    "networkingImplemented": true,
    "os": "linux",
    "arch": "x64",
    "command": [
      "/game/server"
    ],
    "ports": [
      {
        "port": 8080,
        "protocol": "tcp"
      }
    ],
    "profile": "standard",
    "savePath": "/game/saves",
    "health": {
      "type": "http",
      "port": 8080,
      "path": "/health",
      "expected": "ok"
    },
    "playerProbe": {
      "type": "http",
      "port": 9090,
      "path": "/players"
    },
    "joinProbe": {
      "type": "http",
      "port": 8080,
      "path": "/join-probe",
      "expected": "joinable"
    },
    "shutdown": {
      "signal": "SIGTERM",
      "graceSeconds": 30
    },
    "idleSupported": true,
    "wsPath": "/ws"
  }
}
----- ncg.json (end) -----

About ncg.json (the project file the ncg tool reads; it is never packed into the upload):
- Write it in the project root with exactly the content shown. Change only: "game.name" (the real name of the game, 1 to 100 characters), "manifest.platforms" (the platforms the game's players really use) and, if your server uses another port, the port numbers in "manifest.ports", "manifest.health" and "manifest.joinProbe".
- "build.dir" is ".ncg/build": the folder that "ncg pack . --node --install" (or "--python --install") builds for you from this project: your code under app/, the packages for Linux x64, and a start script named "server" that the manifest starts as "/game/server". Do not write that script yourself.
- Run "ncg pack" again after every change: it rebuilds .ncg/build from scratch and never changes your own files.

Proof (run these and show me the real output):
P1  Start the finished server the way the host will: the exact command from ncg.json, in a Linux shell (WSL or an ubuntu:24.04 container if you are on Windows or Mac), with no environment variables set except PATH, LANG and HOME.
P2  curl -s -w " %{http_code}" http://127.0.0.1:8080/health  must print ok and 200.
P3  curl -s http://127.0.0.1:9090/players  must print {"players":0}. Connect one real client: it must become {"players":1}.
P4  Send SIGTERM (kill -TERM <pid>). The process must exit with code 0 inside the grace seconds and the save file must exist and parse.
P5  If the ncg tool is installed, run "ncg check" in the project folder and fix everything it lists. If it is not installed, say so; do not write a substitute.

After your AI finishes

  1. Read what it changed. It was told to change only what the prompt lists and to stop and ask when something needs a redesign.
  2. Run the game with two real players. A prompt cannot prove your game plays well.
  3. Come back to the check and answer again, or run the local check the prompt ends with when you have the ncg tool.