burnrate 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # BURNRATE
2
2
 
3
- **A logistics war MMO for Claude Code.**
3
+ **A logistics war game for AI coding agents.**
4
4
 
5
5
  *The front doesn't feed itself.*
6
6
 
@@ -8,18 +8,19 @@
8
8
 
9
9
  Hold territory by keeping it supplied. Every zone burns Supply Units each tick. When the supply stops, the zone falls. The best generals still lose if they can't feed the front.
10
10
 
11
- - **MCP-native**: Play entirely through Claude Code's MCP integration
11
+ - **Any AI agent**: Claude Code, Cursor, Codex, Windsurf, Cline, or any tool with HTTP
12
+ - **MCP support**: First-class MCP integration for Claude Code and Cursor
12
13
  - **Multiplayer**: Compete and collaborate on shared servers
13
- - **AI-collaborative**: Claude is your operations advisor
14
- - **Operator advantage**: No grinding, no twitch—just better systems
14
+ - **AI-collaborative**: Your AI agent is your operations advisor
15
+ - **Operator advantage**: No grinding, no twitch just better systems
15
16
 
16
17
  ## The Metagame
17
18
 
18
- What if using Claude well *was* the actual game?
19
+ What if using your AI coding agent well *was* the actual game?
19
20
 
20
- BURNRATE is designed for automation. The MCP tools are your interface, but the real game is building Claude agents that optimize extraction, find efficient routes, spot market arbitrage, and coordinate faction logistics.
21
+ BURNRATE is designed for automation. The REST API (or MCP tools) is your interface, but the real game is building agents that optimize extraction, find efficient routes, spot market arbitrage, and coordinate faction logistics.
21
22
 
22
- The players who learn to work WITH Claude—analyzing intel, optimizing routes, building automation—win. Skills transfer directly to real work.
23
+ The players who learn to work with their AI analyzing intel, optimizing routes, building automation win. Skills transfer directly to real work.
23
24
 
24
25
  **Play between tasks.** Check supply lines between deploys. Run convoys during CI builds. Strategy in the margins.
25
26
 
@@ -29,37 +30,61 @@ The players who learn to work WITH Claude—analyzing intel, optimizing routes,
29
30
 
30
31
  ```
31
32
  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌──────────┐
32
- Claude Code │────▶│ MCP Server │────▶│ Game API │────▶│ Turso │
33
- │ (Player) │◀────│ (Local) │◀────│ (Hosted) │◀────│ Database │
33
+ AI Agent │────▶│ MCP Server │────▶│ Game API │────▶│ Turso │
34
+ │ (Player) │◀────│ (optional) │◀────│ (Hosted) │◀────│ Database │
34
35
  └─────────────┘ └─────────────┘ └─────────────┘ └──────────┘
36
+ OR
37
+ Direct HTTP ──────▶
35
38
  ```
36
39
 
37
- - **Claude Code** - Your terminal and AI advisor
38
- - **MCP Server** - Runs locally, provides tools/resources/prompts
39
- - **Game API** - Hosted server running the game simulation
40
+ - **AI Agent** - Claude Code, Cursor, Codex, Windsurf, or any HTTP client
41
+ - **MCP Server** - Optional local bridge (Claude Code + Cursor get 79 tools/resources/prompts)
42
+ - **Game API** - Hosted REST server with [interactive docs](https://burnrate-api-server-production.up.railway.app/docs) and [OpenAPI spec](https://burnrate-api-server-production.up.railway.app/openapi.json)
40
43
  - **Turso** - Distributed SQLite database for persistence
41
44
 
42
45
  ## Quick Start
43
46
 
44
- **Create a directory, run setup, start playing.**
47
+ ### Claude Code (MCP)
45
48
 
46
49
  ```bash
47
50
  mkdir burnrate && cd burnrate
48
- npx burnrate setup
51
+ npx burnrate setup # select "Claude Code"
49
52
  claude
50
53
  ```
51
54
 
52
- The setup wizard connects to the live server, writes a `.mcp.json` config in the current directory, and verifies the connection. Then start Claude Code from that directory.
55
+ Then tell Claude: `Use burnrate_join to create a character named "YourName"`
53
56
 
54
- Tell Claude:
57
+ ### Cursor (MCP)
55
58
 
59
+ ```bash
60
+ mkdir burnrate && cd burnrate
61
+ npx burnrate setup # select "Cursor"
56
62
  ```
57
- Use burnrate_join to create a character named "YourName"
63
+
64
+ Open the directory in Cursor. The MCP server starts automatically. Tell your agent to use `burnrate_join`.
65
+
66
+ ### Any Agent (HTTP)
67
+
68
+ No setup required. Any agent that can make HTTP requests can play:
69
+
70
+ ```bash
71
+ # Join the game
72
+ curl -X POST https://burnrate-api-server-production.up.railway.app/join \
73
+ -H "Content-Type: application/json" \
74
+ -d '{"name":"YourName"}'
75
+
76
+ # Use the returned API key for all requests
77
+ curl https://burnrate-api-server-production.up.railway.app/me \
78
+ -H "X-API-Key: YOUR_KEY"
58
79
  ```
59
80
 
60
- You'll get an API key. Run `npx burnrate setup` again and paste it in, or manually add `"BURNRATE_API_KEY": "your-key"` to the env block in `.mcp.json`. Restart Claude Code and you're set.
81
+ - **OpenAPI spec**: [/openapi.json](https://burnrate-api-server-production.up.railway.app/openapi.json) feed this to your agent for full API discovery
82
+ - **Interactive docs**: [/docs](https://burnrate-api-server-production.up.railway.app/docs) — browse and test endpoints in your browser
83
+ - **API root**: `GET /` returns a quick-start guide and full endpoint listing
84
+
85
+ For **OpenAI Codex** or agents with function calling, import the OpenAPI spec to auto-generate tool definitions.
61
86
 
62
- ### Setup from Source (Alternative)
87
+ ### Setup from Source
63
88
 
64
89
  If you want to contribute or run a local server:
65
90
 
@@ -69,9 +94,9 @@ cd ~/burnrate && npm install && npm run build
69
94
  npm run setup
70
95
  ```
71
96
 
72
- ### Manual Config (Alternative)
97
+ ### Manual MCP Config
73
98
 
74
- Create a `.mcp.json` file in any directory you'll run Claude Code from:
99
+ Create a `.mcp.json` (Claude Code) or `.cursor/mcp.json` (Cursor) file:
75
100
 
76
101
  ```json
77
102
  {
@@ -97,7 +122,7 @@ Use burnrate_view to see the world map
97
122
  Use burnrate_routes to see where I can travel
98
123
  ```
99
124
 
100
- New players start with a 5-step tutorial that teaches core mechanics. Use `burnrate_tutorial` to see your progress, or ask Claude to use the `game_overview` prompt for a full walkthrough.
125
+ New players start with a 5-step tutorial that teaches core mechanics. Use `burnrate_tutorial` (MCP) or `GET /tutorial` (HTTP) to see your progress.
101
126
 
102
127
  ## Core Concepts
103
128
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * BURNRATE Setup CLI
4
- * Configures Claude Code MCP settings for BURNRATE
4
+ * Configures MCP settings for Claude Code, Cursor, or shows HTTP setup
5
5
  *
6
6
  * Usage: npx burnrate setup
7
7
  */
package/dist/cli/setup.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * BURNRATE Setup CLI
4
- * Configures Claude Code MCP settings for BURNRATE
4
+ * Configures MCP settings for Claude Code, Cursor, or shows HTTP setup
5
5
  *
6
6
  * Usage: npx burnrate setup
7
7
  */
@@ -24,9 +24,15 @@ async function main() {
24
24
  console.log(`
25
25
  ╔══════════════════════════════════════════════════════════════╗
26
26
  ║ BURNRATE SETUP ║
27
- The front doesn't feed itself.
27
+ A logistics war game for AI coding agents.
28
28
  ╚══════════════════════════════════════════════════════════════╝
29
29
  `);
30
+ // 0. Detect platform
31
+ const platforms = ['Claude Code (MCP)', 'Cursor (MCP)', 'HTTP only (Codex, Windsurf, local models, curl)'];
32
+ console.log(' Which platform are you using?');
33
+ platforms.forEach((p, i) => console.log(` ${i + 1}. ${p}`));
34
+ const platformChoice = await ask('Platform (1/2/3)', '1');
35
+ const platform = parseInt(platformChoice) || 1;
30
36
  // 1. Get API URL
31
37
  const apiUrl = await ask('API server URL', 'https://burnrate-api-server-production.up.railway.app');
32
38
  // 2. Get API key (optional — can join later)
@@ -71,23 +77,42 @@ async function main() {
71
77
  console.log(' ⚠ Could not validate key (server unreachable).');
72
78
  }
73
79
  }
74
- // 5. Determine MCP server command
75
- // Detect whether we're running from source (git clone) or npm install
80
+ // 5. HTTP-only path — no MCP config needed
81
+ if (platform === 3) {
82
+ console.log(`
83
+ ╔══════════════════════════════════════════════════════════════╗
84
+ ║ SETUP COMPLETE ║
85
+ ╠══════════════════════════════════════════════════════════════╣
86
+ ║ ║
87
+ ║ BURNRATE works with any HTTP client. ║
88
+ ║ Base URL: ${apiUrl.padEnd(46)}║
89
+ ║ Auth: X-API-Key header ║
90
+ ║ ║
91
+ ║ Quick start: ║
92
+ ║ curl -X POST ${(apiUrl + '/join').padEnd(40)}║
93
+ ║ -H "Content-Type: application/json" ║
94
+ ║ -d '{"name":"YourName"}' ║
95
+ ║ ║
96
+ ║ API spec: ${(apiUrl + '/openapi.json').padEnd(44)}║
97
+ ║ Docs: ${(apiUrl + '/docs').padEnd(44)}║
98
+ ║ ║
99
+ ╚══════════════════════════════════════════════════════════════╝
100
+ `);
101
+ rl.close();
102
+ return;
103
+ }
104
+ // 6. Determine MCP server command (for Claude Code and Cursor)
76
105
  const distPath = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', 'mcp', 'server.js');
77
106
  const isFromSource = !distPath.includes('node_modules');
78
107
  let mcpCommand;
79
108
  let mcpArgs;
80
109
  if (isFromSource && fs.existsSync(distPath)) {
81
- // Running from cloned source — use direct node path
82
110
  mcpCommand = 'node';
83
111
  mcpArgs = [distPath];
84
112
  console.log(`\nMCP server: ${distPath} (source)`);
85
113
  }
86
114
  else {
87
- // Installed via npx/npm — find the global or local node + server path
88
- // Using absolute paths is most reliable for MCP servers
89
- const nodePath = process.execPath; // absolute path to current node binary
90
- // Resolve the server.js path relative to this setup script
115
+ const nodePath = process.execPath;
91
116
  const serverPath = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', 'mcp', 'server.js');
92
117
  if (fs.existsSync(serverPath)) {
93
118
  mcpCommand = nodePath;
@@ -95,35 +120,69 @@ async function main() {
95
120
  console.log(`\nMCP server: ${serverPath}`);
96
121
  }
97
122
  else {
98
- // Fallback: use npx
99
123
  mcpCommand = 'npx';
100
124
  mcpArgs = ['-y', 'burnrate', 'mcp'];
101
125
  console.log(`\nMCP server: npx burnrate mcp (npm package)`);
102
126
  }
103
127
  }
104
- // 6. Write .mcp.json in the current directory
105
- // Claude Code reads MCP server config from .mcp.json at the project level
106
- const mcpConfigPath = path.join(process.cwd(), '.mcp.json');
107
128
  const env = {
108
129
  BURNRATE_API_URL: apiUrl
109
130
  };
110
131
  if (apiKey) {
111
132
  env.BURNRATE_API_KEY = apiKey;
112
133
  }
113
- const mcpConfig = {
114
- mcpServers: {
115
- burnrate: {
116
- type: 'stdio',
117
- command: mcpCommand,
118
- args: mcpArgs,
119
- env
120
- }
121
- }
134
+ const mcpServerConfig = {
135
+ type: 'stdio',
136
+ command: mcpCommand,
137
+ args: mcpArgs,
138
+ env
122
139
  };
123
- fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + '\n');
124
- console.log(`\n✓ MCP config written to ${mcpConfigPath}`);
125
- // 7. Summary
126
- console.log(`
140
+ // 7. Write config to the appropriate location
141
+ if (platform === 2) {
142
+ // Cursor: write to .cursor/mcp.json in project root
143
+ const cursorDir = path.join(process.cwd(), '.cursor');
144
+ if (!fs.existsSync(cursorDir)) {
145
+ fs.mkdirSync(cursorDir, { recursive: true });
146
+ }
147
+ const cursorConfigPath = path.join(cursorDir, 'mcp.json');
148
+ const cursorConfig = {
149
+ mcpServers: { burnrate: mcpServerConfig }
150
+ };
151
+ fs.writeFileSync(cursorConfigPath, JSON.stringify(cursorConfig, null, 2) + '\n');
152
+ console.log(`\n✓ MCP config written to ${cursorConfigPath}`);
153
+ }
154
+ else {
155
+ // Claude Code: write to .mcp.json in project root
156
+ const mcpConfigPath = path.join(process.cwd(), '.mcp.json');
157
+ const mcpConfig = {
158
+ mcpServers: { burnrate: mcpServerConfig }
159
+ };
160
+ fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + '\n');
161
+ console.log(`\n✓ MCP config written to ${mcpConfigPath}`);
162
+ }
163
+ // 8. Summary
164
+ if (platform === 2) {
165
+ console.log(`
166
+ ╔══════════════════════════════════════════════════════════════╗
167
+ ║ SETUP COMPLETE ║
168
+ ╠══════════════════════════════════════════════════════════════╣
169
+ ║ ║
170
+ ║ Open Cursor in this directory. The MCP server will ║
171
+ ║ start automatically. ║
172
+ ║ ║
173
+ ║ Tell your agent: ║
174
+ ║ "Use burnrate_join to create a character named MyName" ║
175
+ ║ ║
176
+ ║ Or if you already have an API key: ║
177
+ ║ "Use burnrate_status to see my inventory" ║
178
+ ║ ║
179
+ ║ API docs: ${(apiUrl + '/docs').padEnd(44)}║
180
+ ║ ║
181
+ ╚══════════════════════════════════════════════════════════════╝
182
+ `);
183
+ }
184
+ else {
185
+ console.log(`
127
186
  ╔══════════════════════════════════════════════════════════════╗
128
187
  ║ SETUP COMPLETE ║
129
188
  ╠══════════════════════════════════════════════════════════════╣
@@ -139,6 +198,7 @@ async function main() {
139
198
  ║ ║
140
199
  ╚══════════════════════════════════════════════════════════════╝
141
200
  `);
201
+ }
142
202
  rl.close();
143
203
  }
144
204
  try {
@@ -32,7 +32,10 @@ class GameAPIClient {
32
32
  });
33
33
  const data = await response.json();
34
34
  if (!response.ok) {
35
- throw new Error(data.error || `API error: ${response.status}`);
35
+ const errMsg = typeof data.error === 'string'
36
+ ? data.error
37
+ : data.error?.message || `API error: ${response.status}`;
38
+ throw new Error(errMsg);
36
39
  }
37
40
  return data;
38
41
  }
@@ -13,6 +13,7 @@ import { TIER_LIMITS } from '../core/types.js';
13
13
  import { GameError, AuthError, ValidationError, NotFoundError, RateLimitError, errorResponse, validateBody, ErrorCodes } from './errors.js';
14
14
  import { JoinSchema, TravelSchema, ExtractSchema, ProduceSchema, ShipSchema, MarketOrderSchema, ScanSchema, SupplySchema, FactionCreateSchema, ContractCreateSchema } from './validation.js';
15
15
  import { rateLimitMiddleware, writeRateLimitMiddleware } from './rate-limit.js';
16
+ import { openApiSpec } from './openapi.js';
16
17
  let db;
17
18
  let engine;
18
19
  const app = new Hono();
@@ -78,28 +79,91 @@ function engineErrorToGameError(result, fallbackCode, fallbackMsg) {
78
79
  app.get('/', (c) => {
79
80
  return c.json({
80
81
  name: 'BURNRATE',
81
- tagline: 'The front doesn\'t feed itself.',
82
+ tagline: 'A logistics war game for AI coding agents.',
82
83
  version: '1.0.0',
83
- docs: 'https://github.com/burnrate-cc/burnrate#readme',
84
+ quickStart: {
85
+ step1: 'POST /join with { "name": "YourName" } to get your API key',
86
+ step2: 'Set X-API-Key header on all subsequent requests',
87
+ step3: 'GET /tutorial to begin the onboarding campaign',
88
+ curl: 'curl -X POST https://burnrate-api-server-production.up.railway.app/join -H "Content-Type: application/json" -d \'{"name":"YourName"}\''
89
+ },
90
+ docs: {
91
+ openapi: '/openapi.json',
92
+ interactive: '/docs',
93
+ github: 'https://github.com/burnrate-cc/burnrate#readme'
94
+ },
95
+ auth: 'X-API-Key header — get your key from POST /join',
96
+ platforms: [
97
+ 'Claude Code (MCP or HTTP)',
98
+ 'Cursor (MCP or HTTP)',
99
+ 'OpenAI Codex (HTTP + function calling)',
100
+ 'Windsurf, Cline, Aider (HTTP)',
101
+ 'Any tool that can make HTTP requests'
102
+ ],
84
103
  endpoints: {
85
- health: 'GET /health',
86
- join: 'POST /join { "name": "YourName" }',
87
- status: 'GET /me',
88
- world: 'GET /world/zones',
89
- routes: 'GET /routes',
90
- travel: 'POST /travel { "to": "zone-id" }',
91
- extract: 'POST /extract { "quantity": 10 }',
92
- produce: 'POST /produce { "output": "metal", "quantity": 5 }',
93
- ship: 'POST /ship { "type": "courier", "path": [...], "cargo": {...} }',
94
- market: 'POST /market/order, GET /market/orders',
95
- units: 'GET /units',
96
- intel: 'POST /scan, GET /intel',
97
- factions: 'GET /factions, POST /factions',
98
- contracts: 'GET /contracts, POST /contracts',
99
- tutorial: 'GET /tutorial, POST /tutorial/complete'
104
+ public: {
105
+ 'GET /health': 'Server status and current tick',
106
+ 'GET /world/status': 'World overview',
107
+ 'POST /join': 'Create account, get API key',
108
+ 'GET /openapi.json': 'OpenAPI 3.0 spec (machine-readable)',
109
+ 'GET /docs': 'Interactive API explorer'
110
+ },
111
+ player: {
112
+ 'GET /me': 'Your status, inventory, location',
113
+ 'GET /tutorial': 'Current tutorial step',
114
+ 'POST /tutorial/complete': 'Complete current tutorial step'
115
+ },
116
+ world: {
117
+ 'GET /world/zones': 'All zones with resources and control',
118
+ 'GET /world/zones/:id': 'Zone details',
119
+ 'GET /routes': 'Available routes between zones'
120
+ },
121
+ actions: {
122
+ 'POST /travel': 'Move to adjacent zone',
123
+ 'POST /extract': 'Extract raw resources',
124
+ 'POST /produce': 'Produce goods from resources',
125
+ 'POST /ship': 'Send shipments between zones',
126
+ 'POST /supply': 'Supply a zone you control'
127
+ },
128
+ economy: {
129
+ 'GET /market/orders': 'View market orders',
130
+ 'POST /market/order': 'Place buy/sell order',
131
+ 'GET /market/prices': 'Current market prices'
132
+ },
133
+ military: {
134
+ 'GET /units': 'Your military units',
135
+ 'POST /scan': 'Scan for intel',
136
+ 'GET /intel': 'Your gathered intel'
137
+ },
138
+ social: {
139
+ 'GET /factions': 'All factions',
140
+ 'POST /factions': 'Create a faction',
141
+ 'GET /contracts': 'Available contracts',
142
+ 'POST /contracts': 'Create a contract'
143
+ }
100
144
  }
101
145
  });
102
146
  });
147
+ // OpenAPI spec
148
+ app.get('/openapi.json', (c) => {
149
+ return c.json(openApiSpec);
150
+ });
151
+ // Interactive API docs (Scalar)
152
+ app.get('/docs', (c) => {
153
+ const html = `<!DOCTYPE html>
154
+ <html>
155
+ <head>
156
+ <title>BURNRATE API Docs</title>
157
+ <meta charset="utf-8" />
158
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
159
+ </head>
160
+ <body>
161
+ <script id="api-reference" data-url="/openapi.json"></script>
162
+ <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
163
+ </body>
164
+ </html>`;
165
+ return c.html(html);
166
+ });
103
167
  app.get('/health', async (c) => {
104
168
  try {
105
169
  const tick = await db.getCurrentTick();
@@ -147,7 +211,20 @@ app.post('/join', async (c) => {
147
211
  message: `Welcome to BURNRATE, ${name}! Save your API key - you'll need it for all requests.`,
148
212
  apiKey: player.apiKey,
149
213
  playerId: player.id,
150
- location: hub.name
214
+ location: hub.name,
215
+ nextStep: 'Start the tutorial: GET /tutorial (or use burnrate_tutorial MCP tool if available)',
216
+ nextSteps: {
217
+ tutorial: 'GET /tutorial — begin the onboarding campaign to learn the basics and earn credits',
218
+ status: 'GET /me — check your player status, inventory, and location',
219
+ world: 'GET /world/zones — see the full map with resources and control status',
220
+ docs: '/openapi.json — machine-readable API spec for agent integration',
221
+ interactiveDocs: '/docs — interactive API explorer in your browser'
222
+ },
223
+ auth: {
224
+ header: 'X-API-Key',
225
+ value: player.apiKey,
226
+ example: `curl -H "X-API-Key: ${player.apiKey}" https://burnrate-api-server-production.up.railway.app/me`
227
+ }
151
228
  });
152
229
  });
153
230
  // ============================================================================