# DSH Red Alert [简体中文](README.md) | [English](README.en.md) An AI battlefield sandbox powered by a real Red Alert 2 engine. DeepSeek builds, scouts, commands armies, fights, loses, reviews the evidence, and carries bounded lessons into the next match under fog of war. This is not screenshot interpretation, a Canvas tactical map, or a headless simulation hidden in the background. Native DSH Chat stays in the center, where the model's decisions, tool calls, and battle reports remain visible. A real Red Alert 2-compatible web client runs on the right in the same browser instance, on the same battlefield, and under the same AI seat. The user can enter a directive in Chat at any time and steer the next command cycle. If you want to see an agent do more than answer questions and instead act continuously under real rules, fog of war, and meaningful defeat, this is one of the most direct and playable AI battlefield sandboxes for DSH. ![DeepSeek commands a real Red Alert 2 battlefield beside DSH Chat](https://raw.githubusercontent.com/vibeinging/dsh-red-alert/main/docs/readme-media/real-ai-battlefield.webp) The image shows the complete DSH page: sessions on the left, model decisions in the center, and the real game on the right. It comes from a live match using locally imported RA2 resources supplied by the user. The repository contains no game assets. ## Why it is fun - Watch the command logic: every tactical assessment, production plan, batch order, and tool receipt stays in Chat. - Intervene at any time: directives such as "hold the first wave," "keep two harvesters," or "stop expanding and build three tanks" enter the next command context. - Wins and losses are real: economy, power, build queues, pathfinding, combat, fog of war, and the result screen all come from the live client. - Command more than one unit at a time: a single tool call can issue a batch of unit orders and return a fresh battlefield summary, reducing redundant observation turns. - Let the model perform the micro: the plugin never selects a target, retreats a unit, or launches an attack in the background. The model splits exact units from its fair Chat-visible snapshot and can combine focus fire, kiting, scouting, and movement in one batch. - Turn defeats into rules: a natural match ending creates a structured episode; the model accepts or rejects candidate lessons and retrieves a short strategy matched to the next map, faction, and opponent. - Stay fair without becoming slow: the model sees its own forces, currently visible enemies, and frozen last-seen records, never hidden enemy state, while checking queues and coordinating parallel work more consistently than manual play. ![The model keeps deciding in Chat while the battlefield executes its commands](https://raw.githubusercontent.com/vibeinging/dsh-red-alert/main/docs/readme-media/live-command.webp) ## Start in one minute You need Node.js 22.19 or later, pnpm, and Git. This plugin supports only the current `@deepseek-ai/dsh@0.1.1-rc.2` release, not older DSH versions. The NPM consumer path is fully verified with pnpm 8.15.3; source development remains pinned to pnpm 11.7.0 through `packageManager`. On the first compatible-client preparation, setup uses an exact Bun version through `pnpm dlx`; no global Bun installation is required. ```sh mkdir dsh-red-alert-play cd dsh-red-alert-play pnpm init pnpm add @vibeinging/dsh-red-alert@0.1.3 @deepseek-ai/dsh@0.1.1-rc.2 pnpm exec dsh-red-alert-setup --profile web --download-resources pnpm exec dsh-red-alert ``` `dsh-red-alert-setup` checks the environment, prepares the locked compatible client, mounts the published plugin into the DSH Web Profile, and verifies the final configuration. `--download-resources` explicitly authorizes setup to fetch the archive from the fixed address documented below. Setup verifies its exact size and SHA-256, then stores it under `$DSH_HOME/red-alert/renderer-v5/dist`. On first launch, the compatible client starts muted, imports that verified local archive automatically, and lets a waiting create-match continue. There is no audio-permission dialog, file-picker hunt, return-to-Chat handoff, or second create request. Initial import, extraction, and client startup may take several minutes, so create-match has its own 10-minute timeout while normal tactical commands retain the 120-second timeout. Do not submit another create request while it is pending. Later launches need only `pnpm exec dsh-red-alert`. The launcher always enforces `--no-open`: it prints the DSH address but never creates a browser tab. Open that address manually or reuse the same DSH tab. The public NPM package and GitHub repository contain no game art, sound, or map assets. Setup downloads nothing unless `--download-resources` is explicitly present. You remain responsible for confirming that you have the right to obtain and use the third-party archive. ## DSH is already running. How do I play? DSH loads Profile plugins and the Red Alert renderer environment when the process starts, so they cannot be injected into a process that is already running. Your Profile, sessions, settings, and `$DSH_HOME/.env` remain unchanged. Handle the current process once according to its state: | Current state | What to do | | --- | --- | | `dsh-red-alert-setup` has never run | Stop the current DSH process, run setup in the directory where this package is installed, then use the Red Alert launcher | | Setup is complete, but DSH was started with `dsh web` or `dsh --profile web` | Stop it once, then start it with `pnpm exec dsh-red-alert` | | DSH is already running through `pnpm exec dsh-red-alert` | No restart is needed; open the printed DSH address and create a new Chat | The common path is: ```sh # Press Ctrl+C in the original terminal to stop the current DSH process first cd dsh-red-alert-play pnpm add @vibeinging/dsh-red-alert@0.1.3 @deepseek-ai/dsh@0.1.1-rc.2 pnpm exec dsh-red-alert-setup --profile web --download-resources pnpm exec dsh-red-alert ``` If an older launch says that `RA_ASSETS_DIR` is required, do not create or populate that internal variable. It is a 0.1.1 error shown when the Red Alert launch environment is absent, not evidence that the user's game archive is missing. Run the upgrade and setup commands above. Version 0.1.2 and later directly tell the user to stop DSH, run setup, and restart through the Red Alert launcher. If you normally use a Profile other than `web`, replace `web` in the setup command with its real name. Later launches still use `pnpm exec dsh-red-alert`; the launcher reads the saved Profile, renderer, and port automatically. You do not need to copy an API key or create a second DSH installation. When the page opens, enter this in Chat: ```text Create a Soviet match against a normal AI at speed 2. Read the Soviet structure and opening manual first, play to completion, and review the evidence after the match. ``` If setup completed with `--download-resources` and the integrity check passed, the first create command imports the archive automatically and continues. The user no longer locates a popup, selects a file, reports completion in Chat, or asks the model to retry. Initial loading can take several minutes; do not submit another create request until the live battlefield or an explicit error appears. The center shows model decisions and tool receipts while the right side runs the same live match. Directives such as "hold the line," "add two harvesters," or "focus the attack" can steer any later command cycle. During a live match, drag the battlefield with the left mouse button, click or drag the minimap to relocate the camera, and use the arrow keys or wheel for navigation. In the embedded DSH viewer these inputs change only the spectator camera. They cannot select units, build, produce, or issue combat orders; actual game commands still come from auditable model tool calls in Chat. If the right panel shows a `live Connection` error while a match is being created or is active, do not run the launcher repeatedly or open more pages. Wait until the terminal prints the same DSH address, refresh only that DSH tab, then click `Retry local renderer connection` once. If the panel says that the previous match has ended, do not reconnect that terminal renderer. Enter "review and continue with another match" in the same Chat. The model reuses the reviewed strategy, creates a new `matchId`, and the panel switches to a fresh real game. Start a new Chat only when the first create still ends with `browser command receipt timed out` after the full 10-minute wait. ### Install from source ```sh git clone https://github.com/vibeinging/dsh-red-alert.git cd dsh-red-alert pnpm run setup -- --profile web --download-resources pnpm run dsh ``` Source mode additionally installs dependencies and builds the plugin. NPM mode uses the published Host, browser, and type artifacts directly and never tries to rebuild inside `node_modules`. ### Resource download and local fallback Automatic preparation uses the public candidate [`https://download.ra2web.com/full-pack.7z`](https://download.ra2web.com/full-pack.7z): - Exact size: `140316786` bytes - Exact SHA-256: `3119b300794839ab597df556df8718c0a0a28fe89648ddced1c3790d801cb646` - Local destination: `$DSH_HOME/red-alert/renderer-v5/dist/dsh-red-alert-resource.7z` RA2WEB operates this address as a convenience source. Its availability does not grant rights from EA or any other rights holder to copy or distribute the assets. Setup prints the same source, size, digest, and rights notice before fetching. A download occurs only when the command explicitly includes `--download-resources`. The NPM package, GitHub repository, and compatible-client source do not contain the archive. If you do not want to use this address, omit `--download-resources`. The battlefield keeps a visible local-archive fallback. Select an archive that you have the right to use. The verified minimum archive contains only: - `RA2.MIX` - `LANGUAGE.MIX` - `MULTI.MIX` Music, Taunts, movies, executables, and DLLs are not required. The browser persists the imported result in the stable renderer origin for later launches. An automatically downloaded source archive stays under the local `$DSH_HOME`; a manually selected archive is not copied into the NPM package, GitHub repository, or a DSH source checkout. When the verified archive exists, the compatible client auto-accepts only the renderer's fixed same-origin path. A third-party URL, another port, a query string, or a fragment cannot trigger automatic import. If the local archive is absent or the first import fails, the automatic path runs only once and then falls back to the visible local-file UI. The stable local port saved by setup keeps the same browser resource space on later launches. If another program owns that port, rerun setup or pass `--renderer-port `. After updating a source checkout, run the same setup command to verify the build and mount again: ```sh git pull --ff-only pnpm run setup -- --profile web --download-resources ``` ## Command it like this Use natural language in DSH Chat, for example: ```text Create a Soviet match against a normal AI at speed 2. Read the Soviet structure and opening manual first, play to completion, and review the result. Hold the first wave, keep two harvesters, then transition into three Rhino Tanks. When enemies enter vision, focus the highest threat. Do not chase into fog of war. Perform every tactical cycle yourself: use exact unit ids from the latest snapshot and batch damaged-unit retreat, current-visible focus fire, and the main advance without starting any background rule commander. After a defeat, summarize the match, adopt only rules with clear evidence, and carry them into the next game. ``` The model loads lobby or learning tools when they become relevant, then adds observation, production, construction, and combat tools as the match advances. Unloaded tool schemas do not enter the model context. ## Post-match learning with evidence ![The real result screen appears beside the model review and adopted rules](https://raw.githubusercontent.com/vibeinging/dsh-red-alert/main/docs/readme-media/post-match-learning.webp) Automatic learning does not train or modify model weights, and it does not store free-form prompts. The plugin derives a closed set of candidate rules only from fair battlefield data and accepted command results, records their evidence, and lets the model adopt or reject them. Later matches retrieve only a small set of rules matched to the current map and faction, preventing an unlimited history from filling the context window. A three-match series at speed 2 proves that lessons persist and can be retrieved by the next match. The first two matches ended in defeat; the third remained alive at tick 24090 with a more complete defense and armored production chain. This proves the learning path works, not that the current strategy has reached a stable win rate. See the [automatic improvement and match series report](docs/reports/2026-08-23_auto-learning-speed2-and-command-cycle.md) for the complete evidence. ## A built-in battlefield manual instead of guessed ids The `strategy/learning` group now includes `red_alert_field_manual`. Before a match, the model can load only one needed topic: structures, infantry, vehicles and aircraft, openings, or combat. Results can be filtered to Soviet, Allied, or shared knowledge. Structure and unit ids, costs, and prerequisites come from Red Alert 2 `rules.ini`; opening and combat rules come from public strategy material and this plugin's fair match reviews. The manual explicitly separates the `NAWEAP/GAWEAP` land war factories from the `NAYARD/GAYARD` shipyards. It also covers basic unit roles, the first three-tank group, early anti-infantry defense, combined-arms screens, current-vision scouting, and the limits of last-seen intelligence. Every returned page is written to the session log. The manual contains public static knowledge only and never adds hidden enemy positions, economy, or units. ## A real battlefield without cheating Chat, tools, the bridge, the engine, and the renderer remain bound to the same `sessionId`, `matchId`, AI seat, and tick. Enemy information reaches the model in only three forms: - `visibleEnemies`: enemies inside current real vision. - `lastSeenEnemies`: the final legal observation before an enemy leaves vision; position, health, and `observedAtTick` remain frozen while hidden. - `visibleNeutralObjects`: neutral objects inside current real vision. The model cannot access hidden enemy start positions, enemy economy, full-map objects, debug state, an observer view, Canvas pixels, or unfiltered engine objects. The renderer and model bridge use the same current-LOS rule. Construction placement searches only for legal foundations inside current vision. ## Game capabilities loaded by phase All 85 public engine declarations are classified in `METHOD_POLICY`. Twenty-two precise manifest entries cover allowed engine capabilities and plugin-owned learning operations; unsafe methods remain unavailable. A new session initially registers only two bootstrap tools: | Group | Main capabilities | | --- | --- | | `bootstrap/capability` | Discover capabilities and load precise tool groups | | `strategy/learning` | Load manual pages on demand, retrieve short strategies, review matches, and adopt candidate rules | | `lobby/setup` | Select maps, configure players, create matches, and start games | | `observation` | Fair observation, state, maps, resources, and rules | | `units/combat` | Movement, attacks, deployment, and batch unit commands | | `production/economy` | Catalogs, queues, production, pause, and cancellation | | `construction` | Building catalogs, legal placement, repair, and selling | | `diplomacy/comms` | Diplomacy and communication | | `superweapon` | Superweapons | | `lifecycle/replay` | Stop and end a match | Every precise renderer tool returns a `commandView` containing the current tick, economy, power, owned units, visible enemies, and frozen last-seen records. The model can continue from the same receipt instead of reading the full state again before every action. `red_alert_unit_order` is an executor, not an AI. The real model chooses every target, group, retreat, and direction. The plugin only validates current owned ids, current-visible attack targets, and same-match identity, then executes the supplied `orders[]` in order. One call can contain several independent actions, so the model can retreat damaged armor, focus another group, and advance the main force in the same tactical cycle. `red_alert_start.gameSpeed` accepts values from 0 through 6. The default is speed 2, the original 15 ticks per second. Speed applies equally to both sides and the renderer and does not change model permissions. Profiles can override it with `defaultGameSpeed`. ## What the installer does and does not do ```text pnpm exec dsh-red-alert-setup --profile web --download-resources -> check pnpm and dsh 0.1.1-rc.2 -> verify the base DSH Web Profile without loading user plugins -> use the artifacts already included in the NPM package -> on first preparation, check Git and use exact Bun through pnpm dlx -> prepare the locked GPLv3-compatible client and adapter, then reuse it -> when the explicit flag is present, download and verify the declared archive -> give the verified local archive to the same-origin client for automatic first import -> mount the external plugin with the official dsh plugin command -> verify the mount through the final Profile configuration -> save launch state under $DSH_HOME/red-alert/install.json ``` The installer stops at the real failure point. If the active command is not `dsh 0.1.1-rc.2`, it exits before changing the Profile. If a Web Profile does not exist yet, the latest DSH release creates its default `web` Profile during the first check. Setup does not require global Bun: only the first renderer build downloads and runs the locked `pnpm dlx bun@1.3.14` tool, while a prepared renderer no longer checks Git or Bun. Resource preparation first checks the declared response length, enforces the byte limit while streaming, and calculates SHA-256. Any mismatch deletes the unfinished `.part` file and stops setup before the compatible client can receive the content. To use a custom renderer directory: ```sh pnpm exec dsh-red-alert-setup --profile web --renderer-dir /absolute/new/red-alert-renderer ``` To select the stable renderer port explicitly: ```sh pnpm exec dsh-red-alert-setup --profile web --renderer-port 4317 ``` To print the exact command plan without changing files or Profile state: ```sh pnpm exec dsh-red-alert-setup --profile web --dry-run ``` See the [renderer adapter documentation](renderer-adapter/README.md) for the locked source, commit, patch contents, and GPLv3 boundary. ### Manual mount For complete manual control: ```sh pnpm install --frozen-lockfile pnpm run build pnpm prepare:renderer -- /absolute/new/red-alert-renderer RA_RENDERER_DIST_DIR=/absolute/new/red-alert-renderer/dist \ dsh plugin --profile web add -w file:/absolute/path/to/dsh-red-alert --save-exact --ignore-scripts RA_RENDERER_DIST_DIR=/absolute/new/red-alert-renderer/dist \ dsh --profile web --dump-config ``` Uninstalling removes only the external plugin and does not touch DSH source: ```sh dsh plugin --profile web remove -w @vibeinging/dsh-red-alert ``` ## Acceptance result ```text RA_READY = min(PROFILE, FOG, VISUAL, TOOL_COVERAGE, LAZY_LOAD, SAME_MATCH, DSH_CONTRACT, REGRESSION) = 1 ``` | Metric | Result | Evidence summary | | --- | --- | --- | | `PROFILE` | 1 | The external bundle mounts through a real DSH Profile with zero DSH checkout writes | | `FOG` | 1 | Offline audits show no leak; current LOS, last-seen freezing, and fail-closed boundaries pass in a real browser | | `VISUAL` | 1 | The DSH right panel shows the real map, HUD, minimap, fog, units, and buildings beside Chat | | `TOOL_COVERAGE` | 1 | All 85 public declarations are classified; allowed methods have precise wrappers and unsafe methods stay unavailable | | `LAZY_LOAD` | 1 | A session starts with bootstrap only and publishes group schemas after durable selection | | `SAME_MATCH` | 1 | Chat commands, bridge, engine, and iframe remain bound to the same match | | `DSH_CONTRACT` | 1 | Official SDK, Profile, client handoff, transport, and projection paths pass | | `REGRESSION` | 1 | Plugin checks, adapter tests, builds, package checks, and fair-observation audits pass | Detailed evidence is available in the [final acceptance report](docs/reports/2026-08-22_dsh-real-client-final-acceptance.md), [wide-panel defense rematch report](docs/reports/2026-08-23_dsh-wide-panel-defense-rematch.md), and [automatic improvement report](docs/reports/2026-08-23_auto-learning-speed2-and-command-cycle.md). These reports are currently written in Chinese. ## Verification ```sh pnpm run check pnpm run setup -- --profile web --dry-run ``` `pnpm run check` covers repository rules, method policy, the renderer adapter, lint, Host and client type checking, builds, plugin tests, game-host tests, fair-observation audits, and publint. ## Project boundaries - This is an independent external plugin built specifically for DeepSeek Harness. It mounts through the official NPM SDK, `cordis.patch.yml`, and Profile mechanisms without modifying DSH source. - Pending commands do not promise cross-process exactly-once behavior after a browser or Host crash. Recovery fails closed instead of guessing whether a command ran. - Without movie assets, the compatible client can report non-blocking video decoding warnings. Minimum resource import and real matches continue to work. - Open-source compatible client code does not place EA art, sound, or map assets in the public domain. Users must confirm their resource source and usage rights. - Plugin source and the NPM package use `GPL-3.0-only`; the compatible renderer adapter follows the same upstream GPLv3 license. The license grants no rights to EA game assets. - The NPM package and GitHub repository distribute no game assets. Only an explicit `--download-resources` setup run retrieves the fixed-digest archive from the third-party address documented in this README and keeps it on the local machine. Users must verify the source and usage rights of their resources.