hoi4-agent-tools 0.1.7 → 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.
Files changed (99) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +31 -25
  3. package/SECURITY.md +4 -2
  4. package/dist/bin/setup.js +11 -4
  5. package/dist/bin/setup.js.map +1 -1
  6. package/dist/hoi4_agent_tools/core/configuration.d.ts +1 -0
  7. package/dist/hoi4_agent_tools/core/configuration.d.ts.map +1 -1
  8. package/dist/hoi4_agent_tools/core/configuration.js +3 -3
  9. package/dist/hoi4_agent_tools/core/configuration.js.map +1 -1
  10. package/dist/hoi4_agent_tools/core/engine.d.ts +1 -0
  11. package/dist/hoi4_agent_tools/core/engine.d.ts.map +1 -1
  12. package/dist/hoi4_agent_tools/core/engine.js +1 -0
  13. package/dist/hoi4_agent_tools/core/engine.js.map +1 -1
  14. package/dist/hoi4_agent_tools/core/transactions.d.ts +2 -0
  15. package/dist/hoi4_agent_tools/core/transactions.d.ts.map +1 -1
  16. package/dist/hoi4_agent_tools/core/transactions.js +49 -6
  17. package/dist/hoi4_agent_tools/core/transactions.js.map +1 -1
  18. package/dist/hoi4_agent_tools/core/workspace.js +1 -1
  19. package/dist/hoi4_agent_tools/core/workspace.js.map +1 -1
  20. package/dist/hoi4_agent_tools/focus/service.d.ts.map +1 -1
  21. package/dist/hoi4_agent_tools/focus/service.js +4 -18
  22. package/dist/hoi4_agent_tools/focus/service.js.map +1 -1
  23. package/dist/hoi4_agent_tools/gui/studio.d.ts.map +1 -1
  24. package/dist/hoi4_agent_tools/gui/studio.js +3 -2
  25. package/dist/hoi4_agent_tools/gui/studio.js.map +1 -1
  26. package/dist/hoi4_agent_tools/map/service.d.ts.map +1 -1
  27. package/dist/hoi4_agent_tools/map/service.js +11 -5
  28. package/dist/hoi4_agent_tools/map/service.js.map +1 -1
  29. package/dist/hoi4_agent_tools/mcp/prompts/register.d.ts +2 -1
  30. package/dist/hoi4_agent_tools/mcp/prompts/register.d.ts.map +1 -1
  31. package/dist/hoi4_agent_tools/mcp/prompts/register.js +35 -13
  32. package/dist/hoi4_agent_tools/mcp/prompts/register.js.map +1 -1
  33. package/dist/hoi4_agent_tools/mcp/registry/metadata.d.ts +1 -1
  34. package/dist/hoi4_agent_tools/mcp/security/auth.d.ts.map +1 -1
  35. package/dist/hoi4_agent_tools/mcp/security/auth.js +1 -4
  36. package/dist/hoi4_agent_tools/mcp/security/auth.js.map +1 -1
  37. package/dist/hoi4_agent_tools/mcp/server/base-tools.d.ts +12 -0
  38. package/dist/hoi4_agent_tools/mcp/server/base-tools.d.ts.map +1 -1
  39. package/dist/hoi4_agent_tools/mcp/server/base-tools.js +239 -220
  40. package/dist/hoi4_agent_tools/mcp/server/base-tools.js.map +1 -1
  41. package/dist/hoi4_agent_tools/mcp/server/create.d.ts.map +1 -1
  42. package/dist/hoi4_agent_tools/mcp/server/create.js +8 -2
  43. package/dist/hoi4_agent_tools/mcp/server/create.js.map +1 -1
  44. package/dist/hoi4_agent_tools/mcp/server/output-schemas.d.ts +5 -0
  45. package/dist/hoi4_agent_tools/mcp/server/output-schemas.d.ts.map +1 -1
  46. package/dist/hoi4_agent_tools/mcp/server/output-schemas.js +1 -0
  47. package/dist/hoi4_agent_tools/mcp/server/output-schemas.js.map +1 -1
  48. package/dist/hoi4_agent_tools/mcp/server/result.js +1 -1
  49. package/dist/hoi4_agent_tools/mcp/server/result.js.map +1 -1
  50. package/dist/hoi4_agent_tools/mcp/server/transaction-execution.d.ts +31 -0
  51. package/dist/hoi4_agent_tools/mcp/server/transaction-execution.d.ts.map +1 -0
  52. package/dist/hoi4_agent_tools/mcp/server/transaction-execution.js +127 -0
  53. package/dist/hoi4_agent_tools/mcp/server/transaction-execution.js.map +1 -0
  54. package/dist/hoi4_agent_tools/mcp/tools/focus.d.ts.map +1 -1
  55. package/dist/hoi4_agent_tools/mcp/tools/focus.js +69 -23
  56. package/dist/hoi4_agent_tools/mcp/tools/focus.js.map +1 -1
  57. package/dist/hoi4_agent_tools/mcp/tools/gui.d.ts +6 -0
  58. package/dist/hoi4_agent_tools/mcp/tools/gui.d.ts.map +1 -1
  59. package/dist/hoi4_agent_tools/mcp/tools/gui.js +40 -12
  60. package/dist/hoi4_agent_tools/mcp/tools/gui.js.map +1 -1
  61. package/dist/hoi4_agent_tools/mcp/tools/map.d.ts.map +1 -1
  62. package/dist/hoi4_agent_tools/mcp/tools/map.js +39 -12
  63. package/dist/hoi4_agent_tools/mcp/tools/map.js.map +1 -1
  64. package/dist/hoi4_agent_tools/mcp/transports/http.d.ts.map +1 -1
  65. package/dist/hoi4_agent_tools/mcp/transports/http.js +3 -0
  66. package/dist/hoi4_agent_tools/mcp/transports/http.js.map +1 -1
  67. package/dist/hoi4_agent_tools/version.d.ts +1 -1
  68. package/dist/hoi4_agent_tools/version.js +1 -1
  69. package/docs/README.md +2 -2
  70. package/docs/adr/0012-autonomous-rewrites.md +55 -0
  71. package/docs/adr/README.md +1 -0
  72. package/docs/agent-integration.md +33 -23
  73. package/docs/architecture.md +20 -4
  74. package/docs/artifacts.md +8 -5
  75. package/docs/completion-report.md +85 -125
  76. package/docs/configuration.md +24 -8
  77. package/docs/focus-workflow.md +16 -14
  78. package/docs/gui-workflow.md +7 -3
  79. package/docs/limitations.md +3 -2
  80. package/docs/map-workflow.md +15 -9
  81. package/docs/performance.md +1 -1
  82. package/docs/release.md +11 -9
  83. package/docs/research/mcp-2026-07-10.md +9 -3
  84. package/docs/security.md +12 -6
  85. package/docs/self-hosting.md +8 -6
  86. package/docs/transactions.md +45 -33
  87. package/docs/troubleshooting.md +12 -4
  88. package/package.json +2 -2
  89. package/schemas/configuration.schema.json +3 -2
  90. package/schemas/continuous-focus-palette.schema.json +1 -1
  91. package/schemas/focus-plan.schema.json +1 -1
  92. package/schemas/focus-planning-sidecar.schema.json +1 -1
  93. package/schemas/gui-animation-source.schema.json +1 -1
  94. package/schemas/gui-helper.schema.json +1 -1
  95. package/schemas/gui-scenario.schema.json +1 -1
  96. package/schemas/map-operation.schema.json +1 -1
  97. package/schemas/operation-result.schema.json +1 -1
  98. package/schemas/transaction-manifest.schema.json +1 -1
  99. package/server.json +3 -3
@@ -7,6 +7,14 @@ path is equally valid when the client registration sets `HOI4_AGENT_CONFIG`. Unk
7
7
  rejected.
8
8
  The read-only setup discovery command also checks `HOI4_GAME_ROOT` and the path-delimited `HOI4_MOD_ROOTS`; it reports candidates without registering or modifying them.
9
9
 
10
+ Setup stays read-only unless a write flag is explicit. The recommended write configuration is generated with:
11
+
12
+ ```bash
13
+ hoi4-agent-tools-setup --init-config /absolute/path/config.json --workspace /absolute/path/mod --autonomous-writes --server-state /separate/operator/state
14
+ ```
15
+
16
+ That writes `"writePolicy": "autonomous"` and `"writeEnabled": true` for the supplied mod. Use `--reviewed-writes` only for the legacy separate review/apply tool sequence; `--enable-writes` remains a compatibility alias for reviewed mode. Autonomous and reviewed flags are mutually exclusive, and both require `--server-state`.
17
+
10
18
  The stdio executable accepts newline-delimited JSON-RPC frames up to a fixed 16,777,216-byte
11
19
  ceiling, excluding the line-feed delimiter. This transport safety limit is deliberately not a
12
20
  configuration field; malformed UTF-8 and oversized terminated or unterminated frames close the
@@ -16,7 +24,7 @@ separately configured `http.maxBodyBytes`.
16
24
  ```json
17
25
  {
18
26
  "version": 1,
19
- "writePolicy": "read-only",
27
+ "writePolicy": "autonomous",
20
28
  "serverStateRoot": "/var/lib/hoi4-agent-tools-state",
21
29
  "transactionTtlSeconds": 3600,
22
30
  "transactionMaxJournalBytes": 536870912,
@@ -47,7 +55,7 @@ separately configured `http.maxBodyBytes`.
47
55
  "replacePaths": ["common/national_focus"],
48
56
  "artifactRoot": "/srv/hoi4/workspaces/example/.hoi4-agent/artifacts",
49
57
  "cacheRoot": "/srv/hoi4/workspaces/example/.hoi4-agent/cache",
50
- "writeEnabled": false
58
+ "writeEnabled": true
51
59
  }
52
60
  ]
53
61
  }
@@ -60,8 +68,8 @@ All byte values are exact bytes. Defaults are applied when a field is omitted.
60
68
  | Field | Default | Validation and behavior |
61
69
  | ---------------------------- | ----------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
62
70
  | `version` | required | Must equal the current configuration version, `1`. |
63
- | `writePolicy` | `"read-only"` | `"read-only"` or `"transactions"`. |
64
- | `serverStateRoot` | omitted | Required for `"transactions"`; absolute canonical operator state used for the private journal key and replay-protection heads. |
71
+ | `writePolicy` | `"read-only"` | `"read-only"`, recommended `"autonomous"`, or compatibility `"transactions"`. |
72
+ | `serverStateRoot` | omitted | Required for either write policy; absolute canonical operator state used for the private journal key and replay-protection heads. |
65
73
  | `transactionTtlSeconds` | `3600` | 60 through 86,400 seconds. |
66
74
  | `transactionMaxJournalBytes` | `536870912` | At least 1 MiB; aggregate transaction-journal retention ceiling and per-plan work ceiling. |
67
75
  | `transactionMaxJournals` | `128` | 1 through 10,000 journals per workspace cache. |
@@ -82,7 +90,7 @@ The configuration also rejects unsafe combined budgets: `scanMaxBytes` multiplie
82
90
  `maxConcurrentRequests` must be at most 16 MiB. HTTP concurrency has a fixed maximum of two so two
83
91
  simultaneous offline renders cannot exceed the supported process-safety model.
84
92
 
85
- `serverStateRoot` is mandatory whenever `writePolicy` is `"transactions"`. It must be absolute,
93
+ `serverStateRoot` is mandatory whenever `writePolicy` is not `"read-only"`. It must be absolute,
86
94
  resolve to a canonical directory through components that contain no symbolic links or junctions,
87
95
  and it must not overlap any configured or runtime source, fixture, artifact, cache, registration,
88
96
  writable-registration, or storage root. The server stores the native canonical spelling, including
@@ -112,7 +120,7 @@ protocol when those primitives are unavailable.
112
120
  | `artifactRoot` | mod default; otherwise required | A mod defaults to `<root>/.hoi4-agent/artifacts`. A game/dependency primary workspace must name an operator-owned path under `storageRoots`. |
113
121
  | `cacheRoot` | mod default; otherwise required | A mod defaults to `<root>/.hoi4-agent/cache`. A game/dependency primary workspace must name an operator-owned path under `storageRoots`. |
114
122
  | `fixtureRoot` | omitted | Optional read-only fixture source. |
115
- | `writeEnabled` | `false` | Effective only for `kind: "mod"` when global `writePolicy` is `"transactions"`. |
123
+ | `writeEnabled` | `false` | Effective only for `kind: "mod"` when global `writePolicy` is `"autonomous"` or `"transactions"`. |
116
124
 
117
125
  `registrationRoots`, `writableRegistrationRoots`, and `storageRoots` grant different capabilities:
118
126
 
@@ -170,11 +178,19 @@ path samples, so a workspace with many `replace_path` entries cannot inflate a t
170
178
 
171
179
  ## Read and write policy
172
180
 
173
- `writePolicy` defaults to `read-only`. Source apply/rollback requires `transactions` globally and `writeEnabled: true` on that mod workspace. A dependency or game registration remains read-only even if misconfigured.
181
+ `writePolicy` defaults to `read-only`. In this mode the server exposes analysis and evidence tools but no source-mutation path.
182
+
183
+ `autonomous` is the recommended write policy. With `writeEnabled: true` on a mod workspace, it exposes `hoi4.focus_rewrite`, `hoi4.gui_rewrite`, and `hoi4.map_rewrite`. Each tool plans, validates, journals, applies, rebuilds the index, and post-validates inside one call. If application or post-validation fails, exact original bytes are restored automatically. The transaction status/diff/apply/rollback tools are not registered in autonomous mode.
184
+
185
+ `transactions` is an optional compatibility policy for clients that still need a distinct reviewed plan and apply boundary. It exposes the `*_plan_changes`/`map_plan` tools plus `hoi4.transaction_status`, `hoi4.transaction_diff`, `hoi4.transaction_apply`, and `hoi4.transaction_rollback`. It uses the same journal, hash checks, post-validation, and automatic failure recovery as autonomous mode.
186
+
187
+ Both write policies require `serverStateRoot` and `writeEnabled: true` on the target mod. A dependency or game registration remains read-only even if misconfigured. Changing the global policy changes the MCP tool surface; restart the server and reinitialize the MCP session after changing it.
188
+
189
+ The autonomous rewrite tools advertise `destructiveHint: true`. MCP does not require per-call prompts from that annotation, and server configuration cannot override a client's host approval or filesystem policy. A client may still prompt for or refuse a rewrite.
174
190
 
175
191
  `registrationRoots` controls runtime `hoi4.project_register`. A requested root must canonicalize beneath one of these roots, and a runtime mod additionally requires `writableRegistrationRoots`. HTTP principals also need `allowRegistration`. Granting `allowRegistration` permits that principal to register unclaimed sources beneath the configured capability roots, so use narrow roots or static reviewed workspaces for multi-user deployments. Runtime registration does not edit a client configuration or persist raw paths. It atomically records a hash-only owner/workspace claim in the canonical artifact root; later registrations of that physical store must match it. Reassigning a claimed store is therefore an explicit operator operation: stop the server, review/archive the claim and existing evidence, and choose whether to preserve or separately migrate data. The server never deletes or silently rebinds it.
176
192
 
177
- Transaction mode does not accept pre-upgrade unauthenticated journal manifests. Preserve their
193
+ Write modes do not accept pre-upgrade unauthenticated journal manifests. Preserve their
178
194
  cache directories for operator review, then explicitly archive or remove them together with the
179
195
  corresponding protected state decision; the server never guesses a migration or treats a public
180
196
  integrity hash as authorization.
@@ -29,8 +29,10 @@ National focuses and continuous focuses use their actual HOI4 source models. Nat
29
29
  3. `hoi4.focus_lint` separates syntax, reference, layout, and design diagnostics. Omit `mode` for national-tree compatibility, or pass `mode: "continuous"` with an optional `paletteId` to lint a palette directly.
30
30
  4. `hoi4.focus_layout` calculates stable integer coordinates. Pinned positions and existing coordinates anchor incremental changes.
31
31
  5. `hoi4.focus_render` returns deterministic HTML, SVG, PNG, JSON, and generated-source-map resources. National mode also returns the graph layout and hash-bound planning sidecar; a uniform `reviewScale` from `0.25` through `1.0` keeps unusually wide or deep trees within bounded raster limits without changing logical geometry or source coordinates. Continuous mode accepts palette columns and renders the actual continuous-focus source model.
32
- 6. `hoi4.focus_plan_changes` accepts either a national plan (the backward-compatible default) or `mode: "continuous"` with a continuous-palette plan. Both make source-preserving range edits where possible and produce before/proposed/bitmap-diff review artifacts before creating the dry-run transaction. National plans may set `horizontalSpacing`, `verticalSpacing`, `padding`, and a uniform `reviewScale` for both review renders; those pixel-space settings do not alter focus coordinates or compiled HOI4 source. National plans also maintain the adjacent planning sidecar. To create a first tree or palette in a new mod source file, the coding agent must set `createIfMissing: true`; without that explicit flag, missing sources and IDs refuse. Creation never appends a different target to an existing source file, because doing so could repurpose unrelated source or its adjacent planning sidecar. It uses a transparent source-linked before render, never copies a read-only game/dependency file into a shadowing mod path, and rolls back newly created source and sidecar files atomically.
33
- 7. Review drift, diagnostics, source maps, diff artifacts, and plan hash before apply.
32
+ 6. In autonomous mode, `hoi4.focus_rewrite` accepts either a national plan (the default when `mode` is omitted) or `mode: "continuous"` with a continuous-palette plan. It makes source-preserving range edits where possible, produces before/proposed/bitmap-diff evidence, journals exact recovery bytes, applies, rebuilds the index, and post-validates in one call. National plans may set `horizontalSpacing`, `verticalSpacing`, `padding`, and a uniform `reviewScale` for both review renders; those pixel-space settings do not alter focus coordinates or compiled HOI4 source. National plans also maintain the adjacent planning sidecar. To create a first tree or palette in a new mod source file, set `createIfMissing: true`; without it, missing sources and IDs refuse. Creation never appends a different target to an existing source file, never copies a read-only game/dependency file into a shadowing mod path, and restores newly created source and sidecar files automatically if the rewrite fails.
33
+ 7. Check `execution`, drift, diagnostics, validation, changed files, source maps, and diff artifacts. `execution: "planned"` means validation blocked the proposal without changing source; `execution: "applied"` means post-write validation succeeded.
34
+
35
+ With the optional `"transactions"` compatibility policy, use `hoi4.focus_plan_changes`, page through `hoi4.transaction_diff`, and call `hoi4.transaction_apply` with the exact plan hash instead. The same core validation and recovery engine is used.
34
36
 
35
37
  ## Repairing an existing large tree
36
38
 
@@ -48,17 +50,17 @@ full cleanup, the coding agent must make the movement policy explicit:
48
50
  4. Keep only deliberate trunk or convergence anchors fixed/pinned. Change every movable focus to
49
51
  `{ "mode": "auto", "pinned": false }`; `preferredX` and `preferredY` may retain the authored
50
52
  route intent without making those coordinates mandatory.
51
- 5. Submit the complete plan to `hoi4.focus_plan_changes`. The dry run performs layout, compilation,
52
- lint, source-preserving range edits, deterministic before/proposed rendering, and bitmap diffing.
53
+ 5. Submit the complete plan to `hoi4.focus_rewrite`. The call performs layout, compilation,
54
+ lint, source-preserving range edits, deterministic before/proposed rendering, bitmap diffing,
55
+ journaling, application, index rebuild, and post-write validation.
53
56
  For an unusually wide or deep tree, set a uniform national `reviewScale` between `0.25` and
54
57
  `1.0`; `0.4` is appropriate for a very large comparison. It scales nodes, text, connectors, and
55
58
  the viewport together, avoiding artificial overlap. The same scale governs both sides of the
56
59
  comparison and affects only artifact pixels, never source-grid coordinates. Explicit spacing and
57
60
  padding remain available when the artifact's logical presentation itself needs adjustment.
58
- 6. Read every `hoi4.transaction_diff` page and all linked review resources. Apply the exact
59
- hash-bound transaction only under the coding-agent host's configured write policy.
60
- 7. Rescan, lint, and render the applied tree. A rejected result can be restored exactly with
61
- `hoi4.transaction_rollback` and the same transaction ID and plan hash.
61
+ 6. Inspect the returned validation and evidence links. Rescan, lint, and render when additional
62
+ final evidence is useful. A blocked proposal changes nothing; failure after replacement begins
63
+ restores every affected file automatically.
62
64
 
63
65
  This workflow is suitable for hundreds of focuses. The solver keeps parents above children,
64
66
  rejects visible overlap and duplicate coordinates, separates bounded lanes, validates relative
@@ -75,7 +77,7 @@ localisation/icon/AI/link metadata. Unsupported Clausewitz blocks belong in `raw
75
77
  round-trip instead of being approximated.
76
78
 
77
79
  This minimal national plan is schema-valid. It intentionally omits an icon and reward; a production
78
- tree should add complete presentation and gameplay data before apply:
80
+ tree should add complete presentation and gameplay data before rewriting:
79
81
 
80
82
  ```json
81
83
  {
@@ -142,10 +144,10 @@ tree should add complete presentation and gameplay data before apply:
142
144
  Within each focus, one `prerequisites.groups` entry represents one Clausewitz `prerequisite` block
143
145
  whose listed focuses are OR alternatives. Multiple group entries are AND requirements. For a new
144
146
  target, use `sourcePath: "plan:<tree-id>"` and 64 zeroes for both initial hashes, then call
145
- `hoi4.focus_plan_changes` with `createIfMissing: true`. Use that convention only for a missing
147
+ `hoi4.focus_rewrite` with `createIfMissing: true`. Use that convention only for a missing
146
148
  target. Existing sources normally use imported, hash-bound provenance; resolving intentional
147
149
  plan/source drift additionally requires explicit `authority: "plan"`. The server refuses to append
148
- a different tree to an occupied source file and still requires the normal dry-run/apply boundary.
150
+ a different tree to an occupied source file and still requires complete pre-write and post-write validation.
149
151
 
150
152
  ## Prerequisite and route semantics
151
153
 
@@ -179,7 +181,7 @@ Weak dangling branches, terminal payoff, missing AI, and repeated generic reward
179
181
 
180
182
  The plan records imported source and semantic hashes. If both saved plan and hand-edited script diverge, regeneration is blocked until the coding agent explicitly identifies the authoritative source. Raw fields remain attached to source ranges either way. An explicitly created target reports `target_missing` drift with `requiresAuthority: false`; that status means there is no prior target to reconcile, not that an existing source was overwritten.
181
183
 
182
- Every compiled or proposed focus block receives a source-map entry containing the focus ID, generated location, planning-node location when available, and imported source location when available. National render artifacts use `<tree>.focus.source-map.json`; continuous renders use `<palette>.continuous.source-map.json`. Dry-run transactions retain the corresponding proposed source map and all review artifacts after apply and rollback.
184
+ Every compiled or proposed focus block receives a source-map entry containing the focus ID, generated location, planning-node location when available, and imported source location when available. National render artifacts use `<tree>.focus.source-map.json`; continuous renders use `<palette>.continuous.source-map.json`. Rewrite journals retain the corresponding proposed source map and all review artifacts after success or automatic restoration.
183
185
 
184
186
  ## Artifacts
185
187
 
@@ -187,9 +189,9 @@ Each rendered node includes its ID, resolved title/working label, resolved icon
187
189
 
188
190
  National-tree renders store `<tree>.focus.html`, `.svg`, `.png`, `.json`, `.source-map.json`, and `.plan.json`. Continuous-palette renders use the same core artifact store and produce `<palette>.continuous.html`, `.svg`, `.png`, `.json`, and `.source-map.json`. The JSON embeds the same complete generated-source map that is also stored separately, and all formats carry content hashes plus source/render provenance.
189
191
 
190
- A national focus transaction also stores `<tree>.focus.proposed-validation.json`. It contains every
192
+ A national focus rewrite also stores `<tree>.focus.proposed-validation.json`. It contains every
191
193
  diagnostic and validation check from re-importing, laying out, and linting the compiled proposal.
192
194
  When that complete set is larger than the fixed transaction-manifest allowance, the manifest keeps
193
195
  a blocker-first bounded summary and an explicit resource diagnostic; it never drops findings from
194
- the validation decision. The generic apply boundary uses the same pattern for oversized post-write
196
+ the validation decision. The rewrite boundary uses the same pattern for oversized post-write
195
197
  diagnostics.
@@ -63,11 +63,15 @@ BMFont text inputs stop at 2,097,152 bytes, 50,000 records, 32 fields per record
63
63
 
64
64
  ## Source-preserving plans
65
65
 
66
- Existing `.gui` files accept only hash-bound patches at parser-proven ranges. A patch may replace one known scalar assignment or scalar value, delete one known scalar assignment, or insert complete parsed entries immediately before a block close. Whole-file ranges, block rewrites, unknown-field rewrites, malformed insertions, stale text, and ambiguous ranges are refused. New files may be supplied in full only when no mod, dependency, or game source already owns the path. Every proposal is reparsed and rendered before it can become a transaction.
66
+ Existing `.gui` files accept only hash-bound patches at parser-proven ranges. A patch may replace one known scalar assignment or scalar value, delete one known scalar assignment, or insert complete parsed entries immediately before a block close. Whole-file ranges, block rewrites, unknown-field rewrites, malformed insertions, stale text, and ambiguous ranges are refused. New files may be supplied in full only when no mod, dependency, or game source already owns the path. Every proposal is reparsed and rendered before it can be journaled or applied.
67
+
68
+ With `writePolicy: "autonomous"`, call `hoi4.gui_rewrite` in `source`, `patches`, or `helpers` mode. The one call validates the proposal, persists exact recovery bytes, applies under the workspace lock, rebuilds the index, and post-validates. A successful result reports `execution: "applied"`; a blocked proposal reports `execution: "blocked"` and changes no source; a valid no-change request reports `execution: "unchanged"`. Any application or post-validation failure restores the original bytes automatically. No transaction diff/apply/rollback tools are exposed in autonomous mode.
69
+
70
+ The optional `"transactions"` compatibility policy exposes `hoi4.gui_plan_changes` and the separate transaction review/apply tools instead. Both policies use the same source-preserving compiler, validation, journal, and recovery implementation.
67
71
 
68
72
  ## Declarative helper compilation
69
73
 
70
- `hoi4.gui_plan_changes` in `helpers` mode compiles a strict, build-time helper document into explicit `.gui` source and then plans the write through the normal transaction path. The generated mod has no runtime dependency on `hoi4-agent-tools` or its server.
74
+ `hoi4.gui_rewrite` in `helpers` mode compiles a strict, build-time helper document into explicit `.gui` source and runs it through the normal autonomous rewrite path. In compatibility mode, use `hoi4.gui_plan_changes` with the same input. The generated mod has no runtime dependency on `hoi4-agent-tools` or its server.
71
75
 
72
76
  A document has one `root` and may declare reusable `templates`. A template instance uses `kind: "template"` plus `templateId`; its instance ID becomes the deterministic prefix for every expanded ID and name. For example, instance `left_status` of a template whose root is named `status_card` produces `left_status__status_card`. Instance fields may override the template root, but templates do not provide parameters, slots, or appended children. Missing references, duplicate template IDs, duplicate node IDs, reference cycles, duplicate compiled GUI names, and source or expanded budget overflow refuse compilation. Expanded identifiers stop at 1,024 UTF-8 bytes; conservative source-construction work stops at 16 MiB, and final source stops at the 8 MiB Clausewitz parser ceiling before a transaction is planned.
73
77
 
@@ -95,7 +99,7 @@ The structured helpers compile as follows:
95
99
 
96
100
  Structured leaf output is type-aware. `iconType` accepts sprite/frame fields, `instantTextBoxType` accepts text/font plus `maxWidth` and `maxHeight`, and `buttonType` accepts sprite/frame plus `buttonText` and `buttonFont`. Leaf elements never receive a fabricated `size` block and cannot contain child GUI elements. Hardcoded or legacy forms such as `checkboxType`, `guiButtonType`, and `textBoxType` are refused by the structured helper; use `raw` only when an exact engine precedent justifies them.
97
101
 
98
- Selecting a custom UI `state` requires a matching `stateVariants` entry. Its frame, sprite, text, font, and allowlisted scalar attributes replace the base values in the emitted source; no preview-state comment or inferred frame is written. The engine-managed `normal`, `hover`, `pressed`, and `disabled` states may be named on `buttonType` without a custom variant, but the compiler does not fabricate their frame mapping. Attribute keys must be both safe identifiers and documented scalar fields for the selected container, icon, text, or button type; structured fields, misspellings, and type-incompatible fields cannot be smuggled through `attributes`. `raw` remains the explicit escape hatch for complete advanced Clausewitz GUI source and is counted in transaction evidence.
102
+ Selecting a custom UI `state` requires a matching `stateVariants` entry. Its frame, sprite, text, font, and allowlisted scalar attributes replace the base values in the emitted source; no preview-state comment or inferred frame is written. The engine-managed `normal`, `hover`, `pressed`, and `disabled` states may be named on `buttonType` without a custom variant, but the compiler does not fabricate their frame mapping. Attribute keys must be both safe identifiers and documented scalar fields for the selected container, icon, text, or button type; structured fields, misspellings, and type-incompatible fields cannot be smuggled through `attributes`. `raw` remains the explicit escape hatch for complete advanced Clausewitz GUI source and is counted in rewrite evidence.
99
103
 
100
104
  ## Validation
101
105
 
@@ -15,6 +15,7 @@ These are precise safety boundaries, not silent fallbacks.
15
15
  - Declarative GUI helper documents admit at most 1,024 one-root templates and 64 state variants per node; both source and expanded trees remain subject to the 128-level and 10,000-node ceilings. Grid columns stop at 10,000, expanded identifiers at 1,024 UTF-8 bytes, conservative source-construction work at 16 MiB, and final generated source at 8 MiB. Templates have root overrides but no parameters, slots, or appended children. Scroll-list helpers emit deterministic grid and entry-container handoff names but do not create `dynamic_lists` scripted-GUI bindings or verify an external scrollbar definition's axis. Meter helpers choose one static icon frame from a validated range and do not provide runtime progress behavior. Advanced, hardcoded, legacy, or non-allowlisted scalar GUI fields require the counted raw escape hatch.
16
16
  - Focus design diagnostics such as weak branches, payoff quality, avoidable crossings, or generic rewards are deterministic heuristics and do not rewrite gameplay.
17
17
  - Plan/script drift requires an explicit authoritative-source choice.
18
+ - Autonomous mode deliberately exposes only `hoi4.focus_rewrite`, `hoi4.gui_rewrite`, and `hoi4.map_rewrite`; it does not expose transaction diff, status, apply, or explicit rollback tools. Failed application and post-validation restore automatically. An intentional later reversal requires Git or another explicit domain rewrite. The tools advertise `destructiveHint: true`, but MCP does not mandate per-tool confirmation and the server cannot override its host's approval policy.
18
19
  - Map geometry requires an exact polygon with explicit `fillRule: "even-odd"`, a canonical hash-bound raster-mask manifest, or absolute pixel selection. Polygon vertices are integer raster-boundary coordinates: `0` through raster width/height are valid, greater coordinates are refused before work allocation, and polygons are never clipped. Inclusion is determined at pixel centers. Descriptive geography alone cannot apply.
19
20
  - Province hole detection is a deterministic four-connected digital-topology review. It warns on enclosed components but does not declare every enclave invalid; provinces touching the horizontally wrapping map seam are excluded from the planar hole calculation.
20
21
  - Map text tables are limited to 16,777,216 bytes and 500,000 records so the bounded parser admits the current vanilla unit-position table. Province rasters are limited to the documented 13,238,272-pixel engine area, exact raster masks to 20,000,000 cells, and polygon rasterization to 50,000,000 cell-point comparisons. Every exact selection/recolor operation is additionally limited to 1,000,000 pixels, including explicit pixels, selected mask cells, rasterized polygons, normal-adjacency transfers, whole-province color updates, and merges. Known counts are refused before dangerous decoding/scanning/materialization with `MAP_SELECTED_PIXEL_BUDGET_BLOCKED`. Selected pixels use four-byte numeric offsets, so the primary operation-owned offset buffer remains below 4 MiB (4,000,000 bytes); coordinate-string keys and per-pixel coordinate/color object arrays are not materialized. Map diagnostics are capped at 2,000; overflow retains 1,999 findings and replaces the last slot with a blocking `MAP_DIAGNOSTICS_TRUNCATED`. Undefined bitmap colors retain at most 256 individual samples and add a blocker when more distinct colors exist.
@@ -24,8 +25,8 @@ These are precise safety boundaries, not silent fallbacks.
24
25
  - State `capital` is derived from exact victory points for inspection; Agent Nudger does not write a generic state `capital` assignment.
25
26
  - Map ID allocation obeys scanned format/contiguity evidence from every root's own `default.map`-selected definition database; it refuses an allocation when the current source family cannot safely represent a gap or append. A present selector with any syntax or parser-limit diagnostic blocks the whole map model, including when it belongs to a lower game/dependency root, because falling back could hide an ID or color collision.
26
27
  - Province merge/removal supports arbitrary compatible source IDs and compacts every connected province reference; it refuses renumbering only when the active definition table is already gapped or ambiguous by ID/color, or when source and target type/state/region membership is incompatible.
27
- - Recoverable logical multi-file atomicity cannot prevent an unrelated process from briefly reading a replacement sequence. Success follows the server's post-write validation and final hash check, and persisted before-bytes support rollback. This is not a race-proof filesystem transaction: hostile concurrent symlink, junction, mount, directory, or file replacement by another operating-system principal is outside the application security boundary.
28
- - Artifact retention defaults to 536,870,912 bytes, 5,000 manifests, and 134,217,728 bytes per content object; each provenance manifest is separately capped at 1 MiB before parsing. Broad project, focus, GUI, and map manifests retain a bounded source-hash sample plus a digest commitment to the complete inventory, while exact structured artifact content retains the complete hashes. Opt-in oversized logical evidence is preserved as bounded binary chunks plus a one-read JSON index, not as a larger content object: every chunk/index manifest counts against the same quotas, an index above 1 MiB is refused, and one logical preparation batch has a fixed 536,870,912-byte in-memory ceiling (or the lower configured aggregate ceiling). The whole logical batch is admitted before copying or hashing; preflight and hashing yield to cancellation. Transaction journals default to 536,870,912 bytes and 128 entries, with a fixed 16 MiB ceiling per authenticated manifest; only expired authenticated planned/rolled-back journals, authenticated safe cache-without-head remnants, head-without-cache remnants, or old manifest-less directories are pruned, while other terminal/interrupted or unauthenticated states remain fail-closed and count against quota. See [artifacts](artifacts.md) and [transactions](transactions.md).
28
+ - Recoverable logical multi-file atomicity cannot prevent an unrelated process from briefly reading a replacement sequence. Success follows the server's post-write validation and final hash check, and persisted before-bytes support automatic failure restoration (plus explicit rollback in reviewed compatibility mode). This is not a race-proof filesystem transaction: hostile concurrent symlink, junction, mount, directory, or file replacement by another operating-system principal is outside the application security boundary. Git supplies project history but is not required for the internal recovery guarantee.
29
+ - Artifact retention defaults to 536,870,912 bytes, 5,000 manifests, and 134,217,728 bytes per content object; each provenance manifest is separately capped at 1 MiB before parsing. Broad project, focus, GUI, and map manifests retain a bounded source-hash sample plus a digest commitment to the complete inventory, while exact structured artifact content retains the complete hashes. Opt-in oversized logical evidence is preserved as bounded binary chunks plus a one-read JSON index, not as a larger content object: every chunk/index manifest counts against the same quotas, an index above 1 MiB is refused, and one logical preparation batch has a fixed 536,870,912-byte in-memory ceiling (or the lower configured aggregate ceiling). The whole logical batch is admitted before copying or hashing; preflight and hashing yield to cancellation. Internal rewrite/transaction journals default to 536,870,912 bytes and 128 entries, with a fixed 16 MiB ceiling per authenticated manifest; only expired authenticated planned/rolled-back journals, authenticated safe cache-without-head remnants, head-without-cache remnants, or old manifest-less directories are pruned, while other terminal/interrupted or unauthenticated states remain fail-closed and count against quota. See [artifacts](artifacts.md) and [autonomous rewrites and transactions](transactions.md).
29
30
  - Installed-game and external-workspace font files are read locally and are never published as raw MCP resources or redistributed by this package. Their glyph outlines or bounded BMFont atlas crops may appear inside an authorized generated review artifact. Portable fixtures and tool-owned artifact labels use the pinned Roboto package under OFL-1.1; unavailable workspace glyph data is visibly classified as an approximation rather than delegated to a host font.
30
31
  - Local external integration depends on environment-provided paths and is not a substitute for portable CI.
31
32
  - The server never launches, automates, controls, or captures Hearts of Iron IV. Offline previews are not game screenshots and do not prove in-engine rendering or gameplay behavior.
@@ -1,6 +1,6 @@
1
1
  # Agent Nudger map workflow
2
2
 
3
- Agent Nudger is a headless declarative map transaction service for coding agents. HTML/PNG/JSON maps are inspection evidence, not a manual editor.
3
+ Agent Nudger is a headless declarative map rewrite service for coding agents. HTML/PNG/JSON maps are inspection evidence, not a manual editor.
4
4
 
5
5
  ## Indexed sources
6
6
 
@@ -8,14 +8,14 @@ The shared scan connects province bitmap and definitions, states, strategic regi
8
8
 
9
9
  ## Geometry input
10
10
 
11
- Province geometry apply requires one exact representation:
11
+ Province geometry rewrite requires one exact representation:
12
12
 
13
13
  - selected existing province IDs;
14
14
  - polygon with integer raster-boundary coordinates and explicit `fillRule: "even-odd"`;
15
15
  - raster mask manifest with dimensions, origin, exact selected-pixel count, SHA-256, and canonical Base64 data;
16
16
  - explicit absolute pixel region (`kind: pixels`).
17
17
 
18
- Natural-language descriptions can guide a coding agent, but are not accepted as apply geometry.
18
+ Natural-language descriptions can guide a coding agent, but are not accepted as rewrite geometry.
19
19
 
20
20
  Polygon vertices describe raster cell boundaries, not pixel indices. For a raster of `width` by `height`, every vertex must use an integer `x` from `0` through `width` and an integer `y` from `0` through `height`; the right and bottom boundary values `width` and `height` are valid. A greater coordinate is rejected with `MAP_GEOMETRY_OUT_OF_BOUNDS` before bounding-box or raster-work allocation, and polygon geometry is never silently clipped. Rasterization samples each candidate pixel at its center, `(x + 0.5, y + 0.5)`, using the required even-odd fill rule. Every selected center must still belong to the declared source province.
21
21
 
@@ -33,7 +33,7 @@ Split/merge/move operations do not guess manpower, resources, buildings, victory
33
33
  - exact manifest values;
34
34
  - block until resolved.
35
35
 
36
- Proportional rounding is deterministic and checked for conservation. The transaction remains blocked while any required policy is unresolved.
36
+ Proportional rounding is deterministic and checked for conservation. The rewrite remains blocked while any required policy is unresolved.
37
37
 
38
38
  State move, split, and merge manifests also declare `ports`, `supplyNodes`, `railways`, and `positions` as `follow-province`. Those records are keyed by a selected province or its state association, so their source bytes remain unchanged except for the already modelled state-ID field on applicable position rows. The explicit literals make that behavior reviewable and prevent a partial distribution object from silently choosing it.
39
39
 
@@ -45,11 +45,11 @@ New states require an explicit name localisation key and a strict `localisation`
45
45
 
46
46
  `merge_provinces` and `remove_province` accept arbitrary compatible source IDs; removed IDs do not need to be the highest rows in `definition.csv`. Surviving definitions are compacted deterministically to contiguous IDs from zero in old-ID order. Removed source IDs map to the target's compacted ID, including when the target itself moves downward.
47
47
 
48
- The same total old-to-new map is applied atomically to state membership, victory points, province buildings, strategic regions, special-adjacency endpoints and through-provinces, supply nodes, railways, unit positions, and building-position sea references. Source pixels are repainted with the target color; other province colors and pixels remain unchanged. Reference collisions created by the merge are resolved by the declared sum/deduplicate policy. Definition row order, comments and extra fields, text-file comments, line endings, and source encoding are retained by targeted rewrites, and rollback restores every affected file byte-for-byte.
48
+ The same total old-to-new map is applied as one recoverable operation to state membership, victory points, province buildings, strategic regions, special-adjacency endpoints and through-provinces, supply nodes, railways, unit positions, and building-position sea references. Source pixels are repainted with the target color; other province colors and pixels remain unchanged. Reference collisions created by the merge are resolved by the declared sum/deduplicate policy. Definition row order, comments and extra fields, text-file comments, line endings, and source encoding are retained by targeted rewrites. A failed application or post-validation restores every affected file byte-for-byte.
49
49
 
50
50
  Compaction requires an active definition table that is already contiguous from zero and unambiguous by ID and color. The merge also requires every source and target to share province type plus exact state and strategic-region membership; these are refusal cases rather than guessed redistribution.
51
51
 
52
- Province split/create manifests explicitly retain existing victory points, province buildings, ports, supply nodes, railways, special adjacencies, positions, and entity locators on the source province while the selected pixels and new ID join the declared state and strategic region. To move connected data to the new province, place the corresponding exact remove/add or update operations after the split in the same ordered transaction. Omitting any retention field blocks the split before geometry changes are proposed.
52
+ Province split/create manifests explicitly retain existing victory points, province buildings, ports, supply nodes, railways, special adjacencies, positions, and entity locators on the source province while the selected pixels and new ID join the declared state and strategic region. To move connected data to the new province, place the corresponding exact remove/add or update operations after the split in the same ordered rewrite. Omitting any retention field blocks the split before geometry changes are proposed.
53
53
 
54
54
  ## Province type migration
55
55
 
@@ -66,7 +66,7 @@ The policy explicitly covers:
66
66
  - building and unit positions (`retain-if-valid` or `remove`) and entity locators (`retain-at-coordinate`, because type migration does not alter geometry);
67
67
  - special adjacency endpoint/through references (`retain-if-valid` or `remove-referencing`).
68
68
 
69
- Land-to-water requires removal from the exact indexed state and cannot leave that state without land. Water-to-land requires an explicit existing target state in the same strategic region. Sea targets require `ocean` terrain and continent `0`; lake targets require `lakes` and continent `0`; land targets require a non-water terrain and nonzero continent. Coastal fields and neighboring coastal changes remain exact manifest inputs and are verified by final map validation. Dependency removals and the definition edit share one hash-bound transaction, so apply and rollback cover every affected state, definition, network, position, and adjacency file together.
69
+ Land-to-water requires removal from the exact indexed state and cannot leave that state without land. Water-to-land requires an explicit existing target state in the same strategic region. Sea targets require `ocean` terrain and continent `0`; lake targets require `lakes` and continent `0`; land targets require a non-water terrain and nonzero continent. Coastal fields and neighboring coastal changes remain exact manifest inputs and are verified by final map validation. Dependency removals and the definition edit share one hash-bound journal, so success or automatic failure restoration covers every affected state, definition, network, position, and adjacency file together.
70
70
 
71
71
  When a dependency should move rather than disappear, place the corresponding exact `update_state`, position, supply, railway, or adjacency operation after the type migration in the same ordered manifest. The migration policy removes or retains the old record explicitly; the later operation supplies the new target explicitly.
72
72
 
@@ -74,16 +74,22 @@ When a dependency should move rather than disappear, place the corresponding exa
74
74
 
75
75
  Special adjacency rows remain declarative `add_adjacency` and `remove_adjacency` operations against the active `default.map` adjacency CSV. Normal topological adjacency is derived only from four-neighbor province bitmap geometry (including horizontal map wrap) and uses separate `add_normal_adjacency` and `remove_normal_adjacency` operations.
76
76
 
77
- Every normal-adjacency operation carries unique exact pixel transfers with a coordinate, the province currently owning that pixel, and the destination province. Both requested endpoints and all transfer provinces must exist, every source must match the active raster, and every transfer must involve at least one requested endpoint. Agent Nudger repaints only those 24-bit pixels, rebuilds topology, and blocks/rolls back the operation unless the requested pair is present after an add or absent after a remove. Related coastal-definition changes remain explicit ordered operations in the same transaction.
77
+ Every normal-adjacency operation carries unique exact pixel transfers with a coordinate, the province currently owning that pixel, and the destination province. Both requested endpoints and all transfer provinces must exist, every source must match the active raster, and every transfer must involve at least one requested endpoint. Agent Nudger repaints only those 24-bit pixels, rebuilds topology, and restores the operation unless the requested pair is present after an add or absent after a remove. Related coastal-definition changes remain explicit ordered operations in the same rewrite.
78
78
 
79
79
  ## Allocation
80
80
 
81
81
  ID/color allocation scans current game, dependencies, and mod sources first, including the definition table selected by each root's own `default.map` even when its filename differs from the active table. It records per-file/root maxima, used ranges, active definition contiguity, collisions, reserved values, selected value/color, and source revision. Explicit values are checked against the same evidence. A lower-root ID/color collision is returned as a named dependency conflict on the manifest operation that requested it. The allocator never assumes the numerically next value is safe.
82
82
 
83
+ ## Autonomous rewrite
84
+
85
+ With `writePolicy: "autonomous"`, submit the complete ordered operation manifest once to `hoi4.map_rewrite`. The tool scans dependencies, resolves exact geometry and policies, renders baseline/proposed/diff evidence, validates, journals exact before-bytes, applies all affected text and binary files under the workspace lock, rescans, and post-validates. `execution: "applied"` means the final hashes and validation passed. A blocked proposal reports `execution: "blocked"` and changes nothing; a valid no-change request reports `execution: "unchanged"`; a failure after replacement begins restores every affected file automatically.
86
+
87
+ No transaction tools are registered in autonomous mode. The optional `"transactions"` compatibility policy exposes `hoi4.map_plan` followed by the separate diff/apply/status/rollback tools, using the same internal journal and recovery engine.
88
+
83
89
  ## Artifacts and validation
84
90
 
85
91
  Map base layers cover province, state, strategic region, terrain, continent, owner, controller, cores, claims, and coast. Overlays cover coastlines, ports, victory points, resources, state buildings, province buildings, supply nodes, railways, special adjacencies, building positions, unit positions, and weather positions. Resource/building data is present in canonical JSON as exact sorted state/province maps as well as deterministic PNG markers; HTML embeds the same JSON and PNG with pan/zoom controls. Render loops honor cancellation signals.
86
92
 
87
- Every map preflight stores three content-addressed PNG/JSON/HTML triplets: baseline (`map-before.*`), proposed (`map-proposed.*`), and changed-pixel/semantic diff (`map-diff.*`). Their links and content hashes are included in the transaction plan hash. Semantic diff JSON includes definitions, state/region membership, full state values (manpower, category, resources, owner/controller, cores/claims, VPs, state/province buildings, and derived capital), ports, building/unit/weather positions, entity locators, supply, railways, exact special-adjacency records, and exact bitmap-derived normal-adjacency pairs.
93
+ Every map preflight stores three content-addressed PNG/JSON/HTML triplets: baseline (`map-before.*`), proposed (`map-proposed.*`), and changed-pixel/semantic diff (`map-diff.*`). Their links and content hashes are included in the internal plan hash. Semantic diff JSON includes definitions, state/region membership, full state values (manpower, category, resources, owner/controller, cores/claims, VPs, state/province buildings, and derived capital), ports, building/unit/weather positions, entity locators, supply, railways, exact special-adjacency records, and exact bitmap-derived normal-adjacency pairs.
88
94
 
89
95
  Validation detects duplicate IDs/colors, bitmap-definition mismatches, invalid references, unassigned/multi-state land, invalid derived capitals/VPs/ports/regions/adjacency/supply/rail/placements, removed references, coast inconsistencies, duplicate state IDs, missing localisation, ownership/control conflicts, lost payload, changes outside declared bounds, and dependency conflicts. Geometry review includes disconnected components, one-pixel corridors, and enclosed province holes. Hole detection uses one bounded digital-topology pass and reports `MAP_PROVINCE_HOLE_REVIEW` as a warning because intentional enclaves can be valid; provinces crossing the horizontally wrapping seam are excluded from planar hole classification. Baseline comparisons diagnose dimensions, file/DIB header, row orientation, pixel offset, bit depth, and palette changes separately. Sea and legitimate lake/island cases are not misclassified as missing state membership.
@@ -75,7 +75,7 @@ The benchmark changes only the copied fixture's modification time and confirms t
75
75
  - metadata-only rescan/cache hit: 5.431 ms;
76
76
  - same-size, same-mtime content change/rescan: 20.300 ms.
77
77
 
78
- The deterministic unit test in `tests/unit/core-cache.test.ts` continuously checks this correctness property without asserting timing. Explicit transaction apply/rollback paths also invalidate the workspace cache; the content-derived revision remains the safety backstop for external edits.
78
+ The deterministic unit test in `tests/unit/core-cache.test.ts` continuously checks this correctness property without asserting timing. Autonomous rewrites and reviewed transaction apply/rollback paths all invalidate the workspace cache; the content-derived revision remains the safety backstop for external edits.
79
79
 
80
80
  The Scripted GUI Studio and Agent Nudger benchmark paths currently rebuild their domain scans/indexes on each call. Their warm figures therefore reflect runtime/JIT and operating-system cache effects rather than a domain-level memoization claim. Stored artifacts are content-addressed, but artifact storage is not treated as a parsed-source cache.
81
81
 
package/docs/release.md CHANGED
@@ -59,7 +59,7 @@ stable package is published, the normal strict stable-version monotonic and exac
59
59
  ## Immutable fix-forward history
60
60
 
61
61
  Stable tags and public package versions are never moved, deleted, or overwritten after a failed
62
- release attempt. The retained history before the `0.1.7` candidate is:
62
+ release attempt. The retained history is:
63
63
 
64
64
  - `v0.1.0` stopped during prepublication validation, before any public writer ran;
65
65
  - `v0.1.1` stopped before npm accepted bytes because npm interpreted a slash-containing relative
@@ -86,14 +86,16 @@ release attempt. The retained history before the `0.1.7` candidate is:
86
86
  the pinned official schema defines false as that field's default and every public object passed
87
87
  its preceding publication gate. All public objects remain unchanged as audit evidence.
88
88
  - `v0.1.6` completed the ordered workflow and independent verification across npm, GHCR, the
89
- immutable GitHub Release, and the official MCP Registry. Its exact public evidence is retained in
90
- [the 0.1.6 completion report](completion-report.md).
91
-
92
- `0.1.7` is the next strictly monotonic candidate. It adds agent-first discovery/setup guidance and
93
- corrects shared event indexing and partial-inventory focus diagnostics. The normal stable-version
94
- gate treats the public `0.1.6` package as immutable history and permits only a strictly newer
95
- version. Rerunning or fixing a release never authorizes rewriting a tag, package version, image
96
- tag, release asset, or Registry version.
89
+ immutable GitHub Release, and the official MCP Registry.
90
+ - `v0.1.7` completed the same ordered workflow with agent-first persistent setup guidance, large
91
+ focus-tree review scaling, symbolic focus-cost preservation, and complete resource-backed focus
92
+ validation. Its exact public evidence is retained in
93
+ [the 0.1.7 completion report](completion-report.md).
94
+
95
+ `0.2.0` is the current strictly monotonic release candidate. The normal stable-version gate treats
96
+ public `0.1.7` as immutable history; only a strictly newer version may be published. Rerunning or fixing a
97
+ release never authorizes rewriting a tag, package version, image tag, release asset, or Registry
98
+ version.
97
99
 
98
100
  ## Required pre-tag immutability check
99
101
 
@@ -1,6 +1,6 @@
1
1
  # MCP protocol, SDK, security, and Registry review
2
2
 
3
- Verified 2026-07-10 against official sources.
3
+ Verified again on 2026-07-12 against official sources.
4
4
 
5
5
  ## Selected production baseline
6
6
 
@@ -17,10 +17,16 @@ The breaking `2026-07-28` protocol and SDK v2 split packages were release candid
17
17
  - Stdio uses newline-delimited UTF-8 JSON-RPC, protocol-only stdout, and stderr logging.
18
18
  - Streamable HTTP uses one `/mcp` POST/GET endpoint plus DELETE for session termination. It is stateful to support progress, cancellation, server notifications, SSE resumption, and secure random sessions.
19
19
  - Sessions are bound to authenticated principals and expire; they are never authentication credentials.
20
- - Tools use strict schemas and explicit read-only/destructive/idempotent/open-world annotations. Hints do not replace enforcement.
20
+ - Tools use strict schemas and explicit read-only/destructive/idempotent/open-world annotations. Hints do not replace enforcement and do not require a client to show a confirmation prompt for each call.
21
21
  - Long work observes `AbortSignal` and sends monotonic progress only when the client supplies a progress token.
22
22
  - Large results are content-addressed resources. Binary reads are bounded/chunkable because resource links defer retrieval but are not a byte-stream transport.
23
- - Prompts describe safe workflows but grant no permission.
23
+ - Prompts describe domain workflows but grant no permission.
24
+
25
+ ### Write-policy conclusion
26
+
27
+ MCP separates server-advertised tool metadata from client-host policy. A server can truthfully mark a source-changing tool with `readOnlyHint: false` and `destructiveHint: true`, but it cannot require, suppress, or bypass a host confirmation dialog. The host decides how to present or constrain the call; the server independently enforces its configured workspace, authentication, scope, validation, journaling, and recovery boundaries.
28
+
29
+ For this server, `writePolicy: "autonomous"` therefore exposes one-call `hoi4.focus_rewrite`, `hoi4.gui_rewrite`, and `hoi4.map_rewrite` tools with destructive annotations. The tools internally plan, validate, journal, apply, and post-validate, restoring original bytes on failure. Transaction tools are not registered in that mode. `writePolicy: "transactions"` remains an optional compatibility surface for the older client-driven review/apply sequence, while `read-only` remains the default.
24
30
 
25
31
  ## Remote security requirements applied
26
32
 
package/docs/security.md CHANGED
@@ -4,13 +4,13 @@
4
4
 
5
5
  - external mod source and binary map data;
6
6
  - installed game and dependency references;
7
- - transaction approval intent and rollback blobs;
7
+ - configured write authority, authenticated journals, and exact recovery blobs;
8
8
  - generated artifacts that may reveal source details;
9
9
  - HTTP credentials and principal/workspace grants.
10
10
 
11
11
  ## Trust boundaries
12
12
 
13
- MCP input, file paths, manifest content, client annotations, session IDs, Origin/Host headers, and remote access tokens are untrusted. Tool annotations are descriptive hints. Prompts are guidance. Server-side policy is authoritative.
13
+ MCP input, file paths, manifest content, client annotations, session IDs, Origin/Host headers, and remote access tokens are untrusted. Tool annotations are descriptive hints. Prompts are guidance. MCP does not require a confirmation prompt for every destructive tool call. Server-side configuration is authoritative for server access, while the MCP host independently controls its own approval and filesystem policy; neither can override the other.
14
14
 
15
15
  ## Filesystem controls
16
16
 
@@ -19,7 +19,7 @@ MCP input, file paths, manifest content, client annotations, session IDs, Origin
19
19
  - Traversal, absolute paths, UNC/device paths, NULs, alternate data streams, ambiguous trailing characters, and device names are rejected.
20
20
  - Existing symlinks and junctions are resolved; an escape outside the root is rejected.
21
21
  - Artifact shards, transaction journals, blobs, and lock descendants are re-canonicalized before access. A symlink or junction observed in artifact/journal enumeration is rejected.
22
- - Transaction mode requires an absolute `serverStateRoot` whose existing components are non-linked
22
+ - Each write-enabled policy requires an absolute `serverStateRoot` whose existing components are non-linked
23
23
  and whose canonical target does not overlap any source, registration capability,
24
24
  generated-storage root, or runtime-nominated root. Harmless native path-spelling aliases are
25
25
  normalized only after the link check. Its random journal key and protected revision heads are
@@ -40,7 +40,13 @@ concurrent mutation.
40
40
 
41
41
  ## Write controls
42
42
 
43
- Read-only is the default. A write requires global and workspace enablement, a validated dry run, a persisted transaction, exact plan hash, separate apply call, unexpired principal/workspace binding, unchanged source hashes, and a workspace lock. There is no command execution field. Stale apply and rollback operations fail closed.
43
+ Read-only is the default. The recommended `"autonomous"` policy exposes only `hoi4.focus_rewrite`, `hoi4.gui_rewrite`, and `hoi4.map_rewrite` for source mutation. Each call computes the complete affected-file set, validates proposed bytes, persists an authenticated journal and exact before-bytes, rechecks the unexpired principal/workspace binding and source hashes under a workspace lock, applies, rebuilds the index, and post-validates. Invalid proposals do not apply; an application, final-hash, or post-validation failure restores original bytes automatically.
44
+
45
+ The optional `"transactions"` compatibility policy exposes the older plan/diff/apply/status/rollback tool sequence. It uses the same core journal and failure-recovery path. Autonomous mode intentionally does not register the transaction tools, so it has no client-callable bypass around the one-call rewrite contract.
46
+
47
+ The autonomous rewrite tools advertise `destructiveHint: true` because a successful call changes mod source. That hint is truthful risk metadata, not a server request to suppress or force a dialog. A client host may prompt for or block the call; the server cannot override it. There is no command-execution field in either mode, and stale or cross-workspace writes fail closed.
48
+
49
+ Git remains the project-history and intentional-revert layer. It is not required for operational recovery: the journal and exact before-bytes prevent a failed multi-file rewrite from remaining partially applied.
44
50
 
45
51
  Runtime registration definitions and raw paths are not persisted. The canonical artifact root does
46
52
  retain an atomically created ownership claim containing only domain-separated SHA-256 workspace and
@@ -63,7 +69,7 @@ valid manifest. A cache-first crash may reconcile only an authenticated exact ne
63
69
  missing head, revision gap, altered expiry/state/failure/rollback field, or recomputed public hash
64
70
  fails closed. No HMAC key is derived from public workspace data.
65
71
 
66
- Read-only transaction operations never repair protected state. Cache-first successor promotion is
72
+ Read-only journal/resource operations never repair protected state. Cache-first successor promotion is
67
73
  confined to startup recovery and authorized write paths. Artifact manifests are capped at 1 MiB and
68
74
  transaction manifests at 16 MiB before parsing; transaction resource ranges use a bounded verified
69
75
  byte cache instead of repeatedly rebuilding the authenticated object.
@@ -129,7 +135,7 @@ root ACL for the dedicated server account; the server still rejects a linked/non
129
135
  inherits that operator ACL. A hostile operating-system principal that can read the key or replace
130
136
  state-root entries remains outside the documented filesystem trust boundary.
131
137
 
132
- Raw installed-game or dependency sprite, font, and bitmap files are never registered as downloadable resources. Structured JSON evidence strips embedded raster and glyph payloads, retaining only source-linked hashes, paths, frame and dimension metadata. Composite SVG/PNG reviews may contain processed frames or glyphs required to inspect the requested render, but remain generated, authorization-checked workspace evidence rather than raw asset-file resources. Transaction evidence may contain authorized mod-source before/proposed text and diffs; every artifact remains bound to the workspace principal.
138
+ Raw installed-game or dependency sprite, font, and bitmap files are never registered as downloadable resources. Structured JSON evidence strips embedded raster and glyph payloads, retaining only source-linked hashes, paths, frame and dimension metadata. Composite SVG/PNG reviews may contain processed frames or glyphs required to inspect the requested render, but remain generated, authorization-checked workspace evidence rather than raw asset-file resources. Rewrite and reviewed-transaction evidence may contain authorized mod-source before/proposed text and diffs; every artifact remains bound to the workspace principal.
133
139
 
134
140
  The runtime sends no telemetry or analytics. Its only outbound network request is OAuth JWT-key retrieval from the administrator-configured JWKS endpoint; stdio and static-token loopback deployments require no runtime network access.
135
141
 
@@ -51,7 +51,9 @@ Public mode—either a non-loopback listener or a non-loopback `publicUrl` in fr
51
51
  }
52
52
  ```
53
53
 
54
- The server is an OAuth resource server, not an authorization server. Protected Resource Metadata is served at the standard well-known paths and its endpoint-specific URL is included in 401 and insufficient-scope 403 challenges. Baseline access uses the configured `requiredScopes`; transaction planning, registration, apply, and rollback additionally require `hoi4:write`. Each MCP session is bound to the exact bearer credential that initialized it, not only to mutable subject/client claims. A refreshed or step-up token must initialize a new MCP session; the previous session remains bound to its original credential and expires no later than that credential's `exp`. The server retains only a SHA-256 credential identifier, never the raw token. Static-token sessions keep the configured sliding inactivity lifetime. Terminate TLS at a trusted reverse proxy, preserve Authorization/Origin/Host headers, and do not make a session ID a bearer credential.
54
+ The server is an OAuth resource server, not an authorization server. Protected Resource Metadata is served at the standard well-known paths and its endpoint-specific URL is included in 401 and insufficient-scope 403 challenges. Baseline access uses the configured `requiredScopes`; runtime registration and every source-mutation tool additionally require `hoi4:write`. In autonomous mode that means `hoi4.focus_rewrite`, `hoi4.gui_rewrite`, and `hoi4.map_rewrite`; in compatibility mode it includes planning, apply, and rollback. Each MCP session is bound to the exact bearer credential that initialized it, not only to mutable subject/client claims. A refreshed or step-up token must initialize a new MCP session; the previous session remains bound to its original credential and expires no later than that credential's `exp`. The server retains only a SHA-256 credential identifier, never the raw token. Static-token sessions keep the configured sliding inactivity lifetime. Terminate TLS at a trusted reverse proxy, preserve Authorization/Origin/Host headers, and do not make a session ID a bearer credential.
55
+
56
+ `hoi4:write` authorizes the server-side capability; it does not dictate the MCP host's user-interaction policy. Autonomous rewrite tools advertise `destructiveHint: true`, but MCP does not require a prompt for every such call. The server cannot override a host that prompts for or blocks it.
55
57
 
56
58
  ### Reverse-proxy boundary
57
59
 
@@ -110,7 +112,7 @@ releases the ordinary request-concurrency slot. Each session retains at most 1,0
110
112
  `sessionTtlSeconds`. Old per-session history is evicted first. A new event that cannot fit the
111
113
  shared budget is not retained for replay and does not evict another session's history.
112
114
 
113
- Principal grants isolate tool, resource, session, and transaction access within one deployment. Run separate least-privilege server instances or containers for mutually distrustful teams or operating-system trust domains; do not treat application-level grants as an OS sandbox.
115
+ Principal grants isolate tool, resource, session, and journal access within one deployment. Run separate least-privilege server instances or containers for mutually distrustful teams or operating-system trust domains; do not treat application-level grants as an OS sandbox.
114
116
 
115
117
  Runtime registration has two operator capabilities. `registrationRoots` permits read-only source
116
118
  selection. A caller-declared mod root additionally must be under the default-empty
@@ -121,14 +123,14 @@ these capability roots to that principal; prefer static registrations or separat
121
123
  mutually distrustful users.
122
124
 
123
125
  Runtime artifact storage must support same-volume hard links so the server can create persistent
124
- owner claims without replacement races. Transaction deployments additionally require an isolated,
126
+ owner claims without replacement races. Every write-enabled deployment additionally requires an isolated,
125
127
  persistent `serverStateRoot` on a filesystem with hard-link and atomic-replacement support. Do not
126
128
  place it beneath any source, capability, artifact, cache, fixture, or `storageRoots` directory.
127
129
 
128
130
  ## Container
129
131
 
130
132
  ```bash
131
- docker build -t hoi4-agent-tools:0.1.7 .
133
+ docker build -t hoi4-agent-tools:0.2.0 .
132
134
  docker run --read-only --rm -p 127.0.0.1:3210:3210 \
133
135
  -e HOI4_AGENT_CONFIG=/config/config.json \
134
136
  -v /srv/hoi4/config:/config:ro \
@@ -136,7 +138,7 @@ docker run --read-only --rm -p 127.0.0.1:3210:3210 \
136
138
  -v /srv/hoi4/workspaces:/srv/hoi4/workspaces \
137
139
  -v /var/lib/hoi4-agent-tools:/var/lib/hoi4-agent-tools \
138
140
  -v /var/lib/hoi4-agent-tools-state:/var/lib/hoi4-agent-tools-state \
139
- hoi4-agent-tools:0.1.7
141
+ hoi4-agent-tools:0.2.0
140
142
  ```
141
143
 
142
144
  Port publishing reaches the container through a non-loopback interface. The mounted configuration
@@ -146,7 +148,7 @@ Terminate TLS at the configured reverse proxy. Mapping the host port only to `12
146
148
  exposure but does not turn the container-side listener into loopback, so it does not permit static
147
149
  bearer tokens.
148
150
 
149
- When writes are enabled, set `serverStateRoot` to `/var/lib/hoi4-agent-tools-state` in this example.
151
+ When writes are enabled in either autonomous or reviewed mode, set `serverStateRoot` to `/var/lib/hoi4-agent-tools-state` in this example.
150
152
  Keep that mount persistent across restarts and protect it for the dedicated server account. It is a
151
153
  separate mount because a state root may not overlap `/var/lib/hoi4-agent-tools` when that path is a
152
154
  configured generated-storage capability.