29 KiB
History (2026-09-30). Superseded by
docs/brokkr-adoption-cut.md. The operator unparked agent access, and the adoption map re-derives these cuts against the Codex donor. Read that map; this one is kept only for its rejected paths.
Brokkr Agent Access: Cut Map
Parked (operator, 2026-09-18): "screw it, I'll do any editor shenanigans we need for now." Nothing here is started. The immediate consumer (rigging a scene in Aetheria,
F:\Projects\Aetheria\docs\shield-panel-cut.mdCut 4) is the operator's hands instead. Unpark this when editor work becomes repetitive enough to be worth six cuts in this repo, or when the CultMesh MCP bridge campaign (F:\Projects\CultLib\src\GameCult.Mesh\docs\mcp-bridge-campaign.md) takes it up. The probe results below keep their value either way: noservecommand, a vendored-assembly collision with CultLib, the file-poke path being dead, and no admission at all.
Status: cut map, nothing landed. Ends: an agent process on this box sends a typed
brokkr.unity.command_intent.v0 to a live Unity editor, the editor executes it,
and the agent reads back brokkr.unity.command_receipt.v0 plus a refreshed
brokkr.unity.host_snapshot.v0. Immediate consumer: rigging scenes in
F:\Projects\Aetheria (Unity 6000.3.24f1, built-in pipeline).
This is the thin slice under the named CultMesh MCP bridge campaign
(F:\Projects\CultLib\src\GameCult.Mesh\docs\mcp-bridge-campaign.md). It is built
so the bridge subsumes it: the seam is a typed operation invoke + receipt read
over an already-hosted CultNet endpoint, which is exactly what the campaign's
"operation binding descriptor" lowers. Nothing here becomes a second description
of what Brokkr offers.
Written by Imagination, 2026-09-18, against Brokkr 94b9334, CultLib fa327a0.
What probing established
Names in the repo do not match the machine. These are the measured facts.
The daemon builds and is green, and is not a daemon.
cargo build --workspace and cargo test --workspace pass (20 tests, 0.27s),
cargo fmt --check clean, against cultcache-rs pinned at CultLib
c2a9a6e5 (brokkr-daemon/Cargo.toml:10), which resolves and compiles.
brokkr-daemon/src/main.rs:127-141 dispatches exactly four subcommands:
provider|smoke, sync-contract, sync-once, sync-loop. There is no serve.
README.md:57 tells you to run cargo run -p brokkr-daemon -- serve under the
heading "Unity Smoke"; that command exits 2. The process needs no config, no
port, no CultMesh node, no credentials and no Odin, because it opens nothing but
two files. sync-loop is a polling scheduler over two .ccmp paths, not a
service. tools/check.ps1:112 and tools/vendor-cultmesh-unity.ps1:4 both point
at E:\Projects\..., a drive this box does not have.
The daemon's write path is the file, not the mesh.
MirrorStore::open (brokkr-daemon/src/main.rs:1400-1404) wraps
SingleFileMessagePackBackingStore on the Unity .ccmp directly and pushes
envelopes into it (:1421-1443). In cultcache-rs
(F:\Projects\CultLib\packages\cultcache-rs\src\lib.rs:652-700) that store is
whole-file read-modify-write under a sibling .lock held with fs2. So
cross-process writes to the file are safe at the file level.
But a file write does not wake the editor. The Unity mirror subscribes to
node.Database.Watch<BrokkrUnityCommand>()
(surfaces/unity/Packages/com.gamecult.brokkr/Editor/BrokkrCultMeshMirror.cs:44-52),
which observes in-process database mutations. Nothing in the package re-pulls the
backing store, and Unity's next FlushAsync(soft: true) (:68, :78, :89)
rewrites the whole file from memory. An external file poke is therefore both
invisible and liable to be clobbered. This is the single most load-bearing
finding: the .ccmp-poke option is not viable for live command delivery.
The live path already exists and is a network one.
CultMesh.StartNodeAsync forces StartServer = true
(F:\Projects\CultLib\src\GameCult.Mesh\CultMesh.cs:596-602) and
CultNetLocal.CreateHostAsync starts the host (GameCult.Networking\CultNetLocal.cs:146-163),
so the Unity editor is already hosting a CultNet server. A remote
CultNetDocumentPutRawMessage is applied into the hosted database by
CultNetDatabaseServer.HandlePutAsync
(GameCult.Networking\CultNetDatabaseServer.cs:236), which is exactly the
mutation the editor's Watch observes. The typed client side of that message
exists in C# (CultNetDocumentRegistry.CreateRawDocumentPutMessage
at GameCult.Networking\CultNetDocumentRegistry.cs:212;
CultNetDatabaseSubscriptionClient.cs:237). cultnet-rs has RUDP, framing,
schema discovery and snapshot query, but no evidenced typed document-put client —
treat a Rust caller as unproven work, not a swap.
The port is a constant. GameCult.Networking\Server.cs:26:
private const int ServerPort = 3075;. Not in CultNetHostOptions
(CultNetLocal.cs:13-44), not in CultMeshNodeOptions (CultMesh.cs:20-50).
One Unity editor per machine can host a Brokkr mirror. Security is
ServerSecurityOptions.Development() by default (CultNetLocal.cs:149).
Command delivery depends on an open window and an off-by-default toggle.
The mirror is owned by BrokkrWindow, an EditorWindow. OnEnable hooks
EditorApplication.update (BrokkrWindow.cs:102); OnDisable unhooks it and
disposes the mirror (:110-114). The drain is OnEditorUpdate
(:775-788), gated on autoPollCommands, which defaults to false
(BrokkrSettings.cs:23-27), throttled to one command per second, and it
dequeues exactly one command per tick (:382-393). So today: no window open, no
commands; window open but toggle off, no commands; window closed mid-run, mirror
gone. EditorApplication.update also does not tick dependably while the editor
is unfocused, which is the normal state when an agent is driving it.
There is no scene save. Every scene-mutating action ends at
EditorSceneManager.MarkSceneDirty (BrokkrUnityCommandExecutor.cs:45, 64, 92, 96, 141, 160, 175, 195, 263). Only the asset commands call
AssetDatabase.SaveAssets (:219, 240, 367). An agent's whole rig lives in the
editor's memory until a human presses Ctrl+S.
Addressing is sound. Object ids are
GlobalObjectId.GetGlobalObjectIdSlow(target).ToString()
(BrokkrUnitySnapshotBuilder.cs:183-186), carried in the host snapshot and
resolved back on execute. Read snapshot, get ids, issue commands: that loop is
already coherent.
The Unity package cannot go into Aetheria as-is. It vendors
GameCult.Caching.dll, GameCult.Caching.MessagePack.dll, GameCult.Mesh.dll,
GameCult.Networking.dll, GameCult.Logging.dll, MessagePack.dll, R3.dll
and 20 more into Plugins/CultMesh/. Aetheria already resolves
org.gamecult.cultlib at cultlib-unity-v1.0.60
(F:\Projects\Aetheria\Packages\manifest.json:57), whose
Runtime/Plugins/ ships the identical assembly names behind a
GameCult.CultLib asmdef with overrideReferences: true. Duplicate assembly
names are a Unity compile failure, not a warning. The vendored copies are also
stale: GameCult.Mesh.dll is 75,776 bytes in Brokkr against 675,840 bytes in
cultlib 1.0.60. package.json declares no dependencies at all and pins
"unity": "2022.3".
There is no admission. None. No allowlist, no policy, no caller identity, no
signature, no dry-run, anywhere in BrokkrUnityCommandExecutor.cs or
BrokkrCultMeshMirror.cs. Anything that can reach the endpoint gets
createScriptableObject, createPrefabVariant and arbitrary serialized property
writes on a live project. The receipt (BrokkrHostSnapshot.cs:215-226) carries
commandId, status, message, objectId, observedAt — the executor's own
account of what it did. It is evidence, not proof: no requester identity, no
before/after, nothing signed.
Ordered cuts
Cut 1. Cut the stale claims
- Repo/branch: Brokkr,
agent-accessfrom94b9334. No dependencies. - First: none.
- Deletes first:
README.md:49-64(theserveinvocation and thefile:E:/Projects/...manifest line).tools/check.ps1:112-118(theE:\Projects\CultLib-main-workBlender probe branch — it is dead on this box and silently skipped, which is worse than absent). - Keeps and moves: nothing.
- Adds: a README line naming the four real subcommands and saying plainly
that
brokkr-daemonis a CLI over.ccmpfiles, not a listening service. - Per-file changes:
README.md:49-64: replace the Unity Smoke section with the real install path from Cut 2 and the real agent path from Cut 5.tools/vendor-cultmesh-unity.ps1:4:$cultLibRootfromE:\Projects\CultLibto a-CultLibRootparameter defaulting toF:\Projects\CultLib.tools/check.ps1:112: same, parameterized; fail loudly when absent instead of skipping.
- Authority map: Owner: README and
tools/describe the daemon's real CLI surface. Inputs:main.rs:127-141. Outputs: operator-followable commands. Derived state: none. Forbidden writers: docs may not invent subcommands. Shared paths: n/a. Deletion line: everyE:\literal in the repo. - Verification:
- tests:
tools/check.ps1runs to completion on this box with no skipped branch. - negative:
rg -n 'E:\\\\Projects' F:\Projects\Brokkrreturns nothing. - negative:
rg -n 'brokkr-daemon -- serve'returns nothing.
- tests:
Cut 2. Make the Unity package installable beside CultLib
- Repo/branch: Brokkr, same branch. Depends on nothing; blocks Cut 5's verification.
- First: record Aetheria's resolved hashes from
F:\Projects\Aetheria\Packages\packages-lock.json:245-266so a regression is attributable. - Deletes first: the entire
surfaces/unity/Packages/com.gamecult.brokkr/Plugins/CultMesh/tree (27 DLLs plus.metafiles) andPlugins.meta,Plugins/CultMesh.meta. These are the collision and they are stale. - Keeps and moves:
tools/vendor-cultmesh-unity.ps1is retired with them; the package stops carrying its own copy of CultLib. - Adds: a
dependenciesblock inpackage.jsonnamingorg.gamecult.cultlibat the same git tag Aetheria pins, and"unity": "6000.3"only if 2022.3 support is actually abandoned (see Q7). - Per-file changes:
surfaces/unity/Packages/com.gamecult.brokkr/Editor/GameCult.Brokkr.Editor.asmdef:4-9: references["GameCult.Brokkr", "GameCult.Caching", "GameCult.Mesh", "GameCult.Networking", "R3"]become["GameCult.Brokkr", "GameCult.CultLib"].surfaces/unity/Packages/com.gamecult.brokkr/Runtime/GameCult.Brokkr.asmdef:4-7: references["GameCult.Caching", "MessagePack"]become["GameCult.CultLib"].surfaces/unity/Packages/com.gamecult.brokkr/package.json:5: add"dependencies": {"org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.60"}.tools/check.ps1:100-111: the required-DLL assertion inverts — assert the vendored tree is absent and the asmdefs referenceGameCult.CultLib.
- Authority map:
- Owner:
org.gamecult.cultlibowns the CultCache/CultNet/CultMesh assemblies in every Unity project.com.gamecult.brokkrowns only Brokkr's document types, editor service, executor and window. - Inputs: the host project's resolved CultLib package version.
- Outputs:
GameCult.BrokkrandGameCult.Brokkr.Editorassemblies. - Derived state: none.
- Forbidden writers: the Brokkr package may no longer ship any assembly whose name CultLib also ships.
- Shared paths: Aetheria and any future host project resolve one CultLib.
- Deletion line:
Plugins/CultMesh/and the vendoring script, before any asmdef edit.
- Owner:
- Verification:
- builds: add
"com.gamecult.brokkr": "file:F:/Projects/Brokkr/surfaces/unity/Packages/com.gamecult.brokkr"toF:\Projects\Aetheria\Packages\manifest.json, open Unity 6000.3.24f1, and confirm a clean compile with no duplicate-assembly error inEditor.log. This is also the first real test of whether the package's source compiles against cultlib 1.0.60's API at all — the vendored DLLs were an order of magnitude smaller, so drift is likely andStartNodeAsync,CultMeshNodeOptions.EnableDurableShardLogs,CultNetDatabaseOptions.RuntimeIdandnode.Database.Watch<T>()each need to still exist. - negative:
packages-lock.jsongainscom.gamecult.brokkrand nothing else; no new transitive package appears. - operator: Unity's Package Manager shows Brokkr with no errors and
GameCult > Brokkropens.
- builds: add
Cut 3. Move command drain off the window
- Repo/branch: Brokkr, same branch. Depends on Cut 2.
- First: none.
- Deletes first:
BrokkrWindow.cs:113-114(mirror disposal inOnDisable),:102/:110(theEditorApplication.updatehook/unhook),:775-788(OnEditorUpdate),:377-400region's ownership of dequeue-and-execute, and theprivate BrokkrCultMeshMirror mirrorfield at:18. - Keeps and moves:
PollAndExecuteCommand's body moves into the new service unchanged in behaviour except for the batch rule below. The window keeps its buttons, which now call the service. - Adds:
Editor/BrokkrEditorService.cs,[InitializeOnLoad], static, owning oneBrokkrCultMeshMirrorfor the editor's lifetime, hookingEditorApplication.updateonce, draining all queued commands per tick rather than one per second, and surviving domain reload by re-opening on the static constructor. Gate on anEditorPrefsenable flag (renamed fromAutoPollCommands, default still false) so an unattended project does not silently host a mutation endpoint. - Per-file changes:
BrokkrCultMeshMirror.cs:16: theQueue<BrokkrUnityCommand>stays, but the service owns dequeuing. No change to the watch.BrokkrWindow.cs:65-114:OnEnable/OnDisablestop touching the mirror; they read service state for display only.BrokkrSettings.cs:23-27:AutoPollCommandsbecomesAgentCommandsEnabled, same defaultfalse.
- Authority map:
- Owner:
BrokkrEditorServiceowns mirror lifecycle and command drain. - Inputs:
AgentCommandsEnabled,CultMeshCachePath, the watch queue. - Outputs: executed mutations,
brokkr.unity.command_receipt.v0, refreshedbrokkr.unity.host_snapshot.v0. - Derived state:
BrokkrWindow'slastReceipt,lastSnapshot,lastSyncReceiptare display-only. The window is no longer an owner. - Forbidden writers:
BrokkrWindow.OnDisablemay not dispose the mirror; nothing but the service may callTryDequeueCommand. - Shared paths: window-button commands, agent-sent commands and daemon
sync-oncecommands all land in the same queue and take the sameBrokkrUnityCommandExecutor.Executepath. - Deletion line: the window's mirror field and update hook, deleted before the service is wired.
- Owner:
- Verification:
- builds: Aetheria compiles.
- operator: enable the flag, close the Brokkr window, send a command, see it execute. That negative — the old path could not do this — is the point of the cut.
- negative:
rg -n 'EditorApplication.update' surfaces/unitymatches onlyBrokkrEditorService.cs.
Cut 4. Make the editor reachable and awake
- Repo/branch: Brokkr, same branch. Depends on Cut 3.
- First: measure it. With the service running, unfocus Unity, send a command from a second process, and time the receipt. If it lands in under a second the unfocused-tick worry is theoretical on Unity 6000.3 and this cut shrinks to endpoint publication alone. Do not build the compensator before the measurement.
- Deletes first: nothing.
- Adds:
Runtime/BrokkrEndpoint.cs:brokkr.unity.endpoint.v0— host, port,projectPath,unityVersion,startedAt,agentCommandsEnabled, process id. Published by the service on start into the mirror atunity/endpoint/current, and written as a plain sibling file<project>/.brokkr/endpoint.ccso an agent can find a live editor without already being connected to it. The file is a discovery pointer, not authority; the document in the mirror is the truth.- Only if the measurement demands it: a keep-awake that does not lie about
ownership.
EditorApplication.updatestays the single drain; the addition is a backgroundSystem.Threading.Timerthat callsEditorApplication.QueuePlayerLoopUpdate()/delayCallto force ticks whileagentCommandsEnabledis set. The timer schedules; it never executes a command off the main thread.
- Per-file changes:
BrokkrEditorService.cspublishes the endpoint on start and clears it onquitting. - Authority map: Owner: the service owns the endpoint document. Inputs:
node.Serverport,Application. Outputs:brokkr.unity.endpoint.v0. Derived state:.brokkr/endpoint.ccis a discovery cache; a stale one must be detectable (check pid, refuse on mismatch). Forbidden writers: the agent CLI may read it and must never write it. Deletion line: n/a. - Verification:
- operator: with Unity unfocused and a browser in front, an agent command executes within a stated bound; record the measured latency in the doc.
- negative: kill Unity, and the CLI reports "no live editor" from the pid check rather than hanging on a connect.
Cut 5. brokkr-ctl: the agent's hands
- Repo/branch: Brokkr, same branch. Depends on Cuts 2-4.
- First: none.
- Deletes first: nothing. This is net-new surface and must justify itself:
it buys the named capability (an agent process drives a live editor) that no
existing owner provides, because
brokkr-daemonwrites files the editor cannot see and the Unity window is not callable from outside Unity. - Adds:
tools/brokkr-ctl/— a .NET console project referencing CultLib'sGameCult.Mesh/GameCult.Networkingprojects and Brokkr's document types. Subcommands, all reading.brokkr/endpoint.ccfor the target:snapshot [--project PATH]— connect, readunity/host/current, print it.send --action <a> [--target-object-id ID] [--name N] [--component-type T] [--property-path P] [--value V] [--asset-path A] [--parent-object-id P] [--local-position x,y,z] [...]— build aBrokkrUnityCommand, put it atunity/commands/{guid}, then block on the matchingunity/receipts/{commandId}with a timeout, print the receipt, exit non-zero onstatus != accepted.send --file plan.cc— a batch of intents applied in order, stopping at the first failure, printing every receipt. This is what makes scene rigging usable instead of a hundred process launches.watch-receipts— tail receipts. The document types are shared with the Unity package rather than redeclared: theRuntime/.csfiles are compiled intobrokkr-ctlby<Compile Include>so there is exactly one definition ofbrokkr.unity.command_intent.v0.
- Authority map:
- Owner:
brokkr-ctlowns nothing. It is a caller. Unity owns the mutation; the receipt owns the outcome; the snapshot owns editor truth. - Inputs: CLI args,
.brokkr/endpoint.cc. - Outputs: one
brokkr.unity.command_intent.v0per invocation, to the live node over CultNet. - Derived state: printed text is telemetry. Exit code is derived from the
receipt
status, never from "the put succeeded". - Forbidden writers:
brokkr-ctlmust never open the.ccmpfile. That path is invisible to a running editor and clobbered by its next flush. It must never write receipts, snapshots or endpoint documents. - Shared paths:
brokkr-ctl, the Brokkr window's buttons andbrokkr-daemon sync-onceall produce the same intent document and go through the same executor. No second commit primitive. - Deletion line: if
brokkr-ctlgrows its own policy, its own receipt ledger, or its own idea of editor state, cut it back to a caller.
- Owner:
- Verification — this is the decisive one:
- Open
F:\Projects\Aetheriain Unity 6000.3.24f1 with the Brokkr package installed. Enable agent commands. Note.brokkr/endpoint.cc. - From a Claude Code session, run
brokkr-ctl send --action createGameObject --name BrokkrProofOfLife. Assert: exit 0, receiptstatus=accepted, receiptobjectIdis aGlobalObjectIdstring. brokkr-ctl send --action attachComponent --target-object-id <that id> --component-type UnityEngine.BoxCollider→ accepted.brokkr-ctl send --action setGameObjectTransform --target-object-id <that id> --local-position 1,2,3→ accepted.brokkr-ctl snapshot→ the returnedbrokkr.unity.host_snapshot.v0contains aBrokkrGameObjectSnapshotnamedBrokkrProofOfLifewithlocalPosition(1.0, 2.0, 3.0)and aBoxColliderincomponents.- The layer the operator sees: the operator looks at the Unity Hierarchy and the Inspector and confirms the object, the collider and the transform are there, and that the scene shows dirty. A receipt that says accepted while the Hierarchy is empty is the failure this step exists to catch — the executor writes its own receipt, so the receipt alone cannot prove the mutation.
- Undo (Ctrl+Z) removes it, proving the
Undo.RegisterCreatedObjectUndopath atBrokkrUnityCommandExecutor.cs:43is real and the operator retains a way out. - Negative: with agent commands disabled, step 2 times out and exits non-zero without mutating anything.
- Open
Cut 6. Admission and the save question
- Repo/branch: Brokkr, same branch. Depends on Cut 5.
- First: verify what
Serverbinds.Server.cs:26fixes the port at 3075 but the bind address was not established in this pass. If it binds0.0.0.0, every machine on the LAN can currently mutate an open Unity project, and this cut is urgent rather than tidy. - Deletes first: nothing, because there is nothing. Stated plainly: today admission is absent, not weak.
- Adds:
- Loopback-only binding for the Brokkr mirror node, or an explicit operator opt-in to bind wider.
- A
BrokkrCommandPolicyconsulted by the service beforeBrokkrUnityCommandExecutor.Execute: an action allowlist and an asset-path prefix allowlist, defaulting to scene mutation permitted and asset-creating actions (createScriptableObject,createPrefabVariant) denied. Denials produce astatus=deniedreceipt, so a refusal is as inspectable as an acceptance. requestedByon the intent anddeniedReasonon the receipt, so a receipt says who asked, not only what happened.- A
saveSceneaction, gated by the same policy and denied by default (Q4).
- Authority map: Owner:
BrokkrCommandPolicyowns admission. Inputs: the intent, EditorPrefs policy. Outputs: permit/deny. Derived state: the receipt'sstatus. Forbidden writers: the executor may not bypass the policy; the window's own buttons go through it too, so operator and agent share one admission path rather than two truths. Deletion line: n/a. - Verification:
- negative: a
createScriptableObjectintent under default policy yieldsstatus=deniedand creates no asset — verified byAssetDatabaseabsence, not by the receipt. - negative:
rg -n 'Execute\(' surfaces/unityshows the policy call on every path into the executor.
- negative: a
Subtraction ledger (estimate)
| Cut | Removed | Added | Deps/targets |
|---|---|---|---|
| 1 | ~30 lines docs/scripts, 1 dead branch | ~15 lines | — |
| 2 | 27 DLLs + 27 .meta (~6 MB), 1 script (~55 lines) |
~6 lines manifest | −0 packages in Brokkr, +1 UPM dep declared, +1 UPM dep in Aetheria |
| 3 | ~45 lines from BrokkrWindow.cs |
~90 lines (BrokkrEditorService.cs) |
— |
| 4 | — | ~70 lines + 1 document type | +1 schema |
| 5 | — | ~350 lines | +1 build target (tools/brokkr-ctl, .NET console), +2 project references to CultLib |
| 6 | — | ~120 lines | — |
Net: strongly negative in shipped bytes (the vendored DLL tree dwarfs everything
added), net +1 executable target and +2 schemas. The one new target is the whole
point of the campaign's gap and is the thing the MCP bridge later wraps rather
than replaces. Build budget: cargo build/test --workspace already runs in 24s
cold, and nothing here touches the Rust crate. The new .NET target builds
GameCult.Mesh + GameCult.Networking from CultLib source — check that cost on
first build; if it exceeds a few seconds, reference the packed assemblies
instead. Build host is this Windows box and the artifacts run on it, so no
cross-platform claim is being made.
Operator forks
Q1 — Where the agent-side tool lives, and in what language. Most blocking: everything after Cut 2 assumes an answer.
- A:
tools/brokkr-ctl, a .NET console in this repo, CultNet client over the Unity node's port. - B: Extend
brokkr-daemonin Rust with asend/snapshotsubcommand. - C: No tool; agents poke the
.ccmpfile.
Recommended: A. C is dead on the evidence — a file write is invisible to the
running editor's Watch and gets clobbered by its next flush. B needs a typed
document-put client in cultnet-rs that does not exist today; the RUDP and
schema primitives are there, so it is buildable, but it is a campaign-sized
detour to reach parity with a C# client that already works. A reuses
CultNetDocumentRegistry.CreateRawDocumentPutMessage and the same document
.cs files Unity compiles, so there is exactly one definition of the intent
schema. When the MCP bridge lands in Rust, brokkr-ctl is what it replaces, and
the intent/receipt contract it exercised is what the bridge lowers.
Q2 — Does the editor poll or subscribe?
- A: Subscribe. The mirror already does (
BrokkrCultMeshMirror.cs:44-52); the bug is that the drain of the subscription queue is window-owned and rate-limited to one command per second. - B: Add an explicit poll of the backing store.
Recommended: A. B would mean re-pulling the .ccmp in the editor and
creating a second delivery path with different semantics — two truths about how
a command arrives. Cut 3 fixes the real defect (ownership and batching) without
inventing a lane.
Q3 — Unfocused ticking.
- A: Measure first (Cut 4's "First"), and only add a keep-awake timer if the measurement shows a stall.
- B: Add the timer now.
- C: Require the editor focused; document it and move on.
Recommended: A. B is a compensator bought before the symptom is confirmed on Unity 6000.3. C is honest but makes the tool useless for the actual use — an agent drives Unity while the operator is elsewhere.
Q4 — Does scene save become a command?
- A: New
saveSceneaction, denied by default in policy, opt-in per project. - B: Save stays the operator's, always.
Recommended: A, shipped denied. B is safer today and is what Cut 5's verification assumes, but it means an agent rigging fifty objects leaves all of it in volatile editor memory, and one crash or one mis-clicked "Don't Save" takes the lot. A with a default denial keeps the operator's hand on the switch while making the capability exist and inspectable. If you would rather not have the action in the codebase at all, B is defensible; say so and Cut 6 drops it.
Q5 — MCP server now, or CLI the bridge wraps?
- A: CLI now; the campaign's generic CultMesh MCP bridge wraps or replaces it.
- B: A Brokkr-specific MCP server now.
Recommended: A. The campaign doc is explicit that Brokkr-specific tooling
treats the symptom and that the missing organ is general
(mcp-bridge-campaign.md, "Brokkr-specific tooling would treat the symptom").
A Brokkr MCP server is exactly the thing the campaign says not to build, and it
would have to be deleted. A CLI is a caller — the bridge invokes the same typed
operation over the same endpoint, and brokkr-ctl either becomes a thin shim or
goes away without anything else moving. It also answers the campaign's own open
question ("what a provider must publish before it is usable through the bridge,
and whether Brokkr already publishes it") with a worked example: Brokkr publishes
the commands and receipts but not the endpoint, which is Cut 4.
Q6 — The hard-coded port 3075 (Server.cs:26).
- A: Accept it; one Brokkr-hosting Unity editor per machine, and the endpoint document says which project owns it.
- B: Push a port option into
CultNetHostOptionsin CultLib.
Recommended: A for this slice, B as a CultLib follow-up. B is a change to
shared substrate every runtime depends on, and it does not belong inside an
unblock-the-work cut. A is honest as long as brokkr-ctl refuses clearly when
.brokkr/endpoint.cc names a different project than the one asked for — which
is worth stating as a requirement, because the silent failure (commands landing
in the wrong Unity project) is exactly the class of damage this whole effort
exists to stop.
Q7 — Does com.gamecult.brokkr stay self-contained?
- A: Depend on
org.gamecult.cultlib; drop the vendored DLLs (Cut 2 as written). - B: Keep vendoring, and make it installable only in projects without CultLib.
Recommended: A. B cannot serve the immediate consumer at all: Aetheria has
CultLib and the assembly names collide. A also ends the staleness — the vendored
GameCult.Mesh.dll is a tenth the size of the one Aetheria resolves, which means
the package has been compiling against a CultMesh from a different era. Expect
Cut 2 to surface real API drift; that is the cut doing its job, not a surprise.