235 lines
11 KiB
Markdown
235 lines
11 KiB
Markdown
# Brokkr Provider Contract
|
|
|
|
Provider id: `brokkr.creative_tool_broker`
|
|
|
|
CultMesh base URI: `cultmesh://brokkr`
|
|
|
|
Eve is deprecated, and Thing 2 is its successor (`thing2:ruling:eve-dashboards-quarantined`, 2026-10-22). Brokkr advertises no operator-dashboard surface; it publishes typed CultMesh state meanwhile.
|
|
|
|
## Tool Kinds
|
|
|
|
- `unity-editor`
|
|
- `blender-editor`
|
|
|
|
## Capability Families
|
|
|
|
- `cultcache.mirror.publish`
|
|
- `cultcache.intent.watch`
|
|
- `host.status.read`
|
|
- `scene.tree.read`
|
|
- `component.state.read`
|
|
- `selection.read`
|
|
- `asset.catalog.read`
|
|
- `asset.scriptable_object.create`
|
|
- `asset.prefab.instantiate`
|
|
- `asset.prefab.variant.create`
|
|
- `gameobject.create`
|
|
- `component.attach`
|
|
- `component.property.write`
|
|
- `editor.assets.refresh`
|
|
- `editor.lifecycle.write`
|
|
- `editor.view.capture`
|
|
- `command.receipt.publish`
|
|
|
|
## Mirror Documents
|
|
|
|
- `brokkr.unity.host_snapshot.v0` at `unity/host/current`
|
|
- `brokkr.unity.command_intent.v0` at `unity/commands/{commandId}`
|
|
- `brokkr.unity.command_receipt.v0` at `unity/receipts/{commandId}`
|
|
- `brokkr.unity.snapshot_receipt.v0` at `unity/receipts/snapshots/{observedAt}`
|
|
- `brokkr.unity.quest_route.v0` at `unity/quest-routes/{routeId}`
|
|
- `brokkr.unity.warped_video_frame.v0` at `unity/quest/video/{frameId}`
|
|
- `brokkr.blender.host_snapshot.v0` at `blender/host/current`
|
|
- `brokkr.blender.command_intent.v0` at `blender/commands/{commandId}`
|
|
- `brokkr.blender.command_receipt.v0` at `blender/receipts/{commandId}`
|
|
- `brokkr.sync.session.v0` at `sync/sessions/{sessionId}`
|
|
- `brokkr.sync.object_binding.v0` at `sync/bindings/objects/{bindingId}`
|
|
- `brokkr.sync.var.v0` at `sync/vars/{syncVarId}`
|
|
- `brokkr.sync.timeline_binding.v0` at `sync/bindings/timelines/{bindingId}`
|
|
- `brokkr.sync.receipt.v0` at `sync/receipts/{receiptId}`
|
|
|
|
## Sync Organ
|
|
|
|
Brokkr owns sync correspondence and policy documents. Editor hosts still own
|
|
scene mutation. A sync record can request or describe a lane, but it is not real
|
|
editor state until Unity or Blender publishes accepted command receipts and a
|
|
fresh host snapshot.
|
|
|
|
Primary sync documents:
|
|
|
|
- `brokkr.sync.session.v0`: shared sync session and mode.
|
|
- `brokkr.sync.object_binding.v0`: Unity GameObject to Blender object/collection
|
|
correspondence.
|
|
- `brokkr.sync.var.v0`: per-lane sync options such as transform, parent,
|
|
material, component property, custom property, timeline frame, camera lens,
|
|
or Cinemachine virtual camera.
|
|
Editor surfaces may also publish ad hoc sync vars with an explicit kind,
|
|
paths, authority, enabled flag, and interpolation. The daemon executes
|
|
implemented kinds and preserves unsupported kinds as typed sync policy for
|
|
external consumers.
|
|
- `brokkr.sync.timeline_binding.v0`: Blender scene/action timeline to Unity
|
|
Timeline/Cinemachine correspondence.
|
|
- `brokkr.sync.receipt.v0`: daemon sync pass receipts.
|
|
|
|
Operational commands:
|
|
|
|
- `dotnet run --project brokkr-command/Brokkr.Command.csproj -- --unity-cache .brokkr/unity-editor.ccmp --action readHost`
|
|
- `dotnet run --project brokkr-command/Brokkr.Command.csproj -- --unity-cache .brokkr/unity-editor.ccmp --action createGameObject --name Marker --local-position 0,1,0`
|
|
- `brokkr-daemon sync-once --unity-cache .brokkr/unity-editor.ccmp --blender-cache .brokkr/blender-editor.ccmp`
|
|
- `brokkr-daemon sync-loop --unity-cache .brokkr/unity-editor.ccmp --blender-cache .brokkr/blender-editor.ccmp --interval-ms 500`
|
|
|
|
`brokkr-command` is a caller. Each invocation writes one intent through the
|
|
directory store (every intent field has a `--kebab-case` option; `--view` and
|
|
`--output` fill the capture fields), waits for the receipt, and exits 0 for
|
|
`accepted`, 1 for any other status, and 2 for a usage error or a timeout. It
|
|
never writes receipts, host snapshots or the agent-commands flag.
|
|
|
|
`sync-loop` owns scheduling only. It repeatedly invokes the same sync decision
|
|
primitive as `sync-once`, writes command intents and sync receipts through the
|
|
mirrors, and prints per-pass telemetry to stdout.
|
|
|
|
Each daemon pass writes the same `brokkr.sync.receipt.v0` document into both
|
|
editor mirror stores at `sync/receipts/{receiptId}`. Unity and Blender editor
|
|
panels may display the latest receipt, but the daemon remains the owner of pass
|
|
status.
|
|
|
|
Implemented sync lanes:
|
|
|
|
- Missing counterpart materialization for enabled object bindings. When an
|
|
authority side has an object and the target side does not, Brokkr emits
|
|
`createObject` or `createGameObject` and waits for the next host snapshot
|
|
before applying per-lane mutations.
|
|
- Unity GameObject transform to Blender object transform.
|
|
- Unity GameObject active state to Blender object visibility.
|
|
- Unity GameObject parent id to Blender object parent through `setObjectParent`.
|
|
- Unity Renderer material name to Blender object material assignment through
|
|
`assignMaterial`.
|
|
- Blender object visibility to Unity GameObject active state through
|
|
`setGameObjectActive`.
|
|
- Blender object parent name to Unity GameObject parent through
|
|
`setGameObjectParent`. The Blender parent must have an object binding so
|
|
Brokkr can resolve the Unity parent object id.
|
|
- Unity serialized component property to Blender object custom property through
|
|
`setObjectCustomProperty`. The syncvar kind may be `component-property` or
|
|
`custom-property`; authority and paths determine direction. It uses
|
|
`unityPropertyPath =
|
|
Component.Type::propertyPath` and `blenderPropertyPath = customProperties.name`.
|
|
- Blender object transform to Unity GameObject transform.
|
|
- Blender object material name to Unity Renderer material assignment through
|
|
`assignMaterial`.
|
|
- Blender scene frame to Unity timeline time through `setComponentProperty`.
|
|
- Blender scene camera transform/FOV to a Unity Cinemachine virtual camera
|
|
GameObject/component. The FOV write uses `componentType =
|
|
Cinemachine.CinemachineVirtualCamera` and property path `m_Lens.FieldOfView`.
|
|
- Blender object custom property to Unity serialized property through
|
|
`setComponentProperty`. The syncvar kind may be `custom-property` or
|
|
`component-property`; authority and paths determine direction. It uses
|
|
`blenderPropertyPath =
|
|
customProperties.name` and `unityPropertyPath = Component.Type::propertyPath`
|
|
when a Unity component should receive the value.
|
|
|
|
## Unity Command Actions
|
|
|
|
All Unity writes use `brokkr.unity.command_intent.v0` and receive
|
|
`brokkr.unity.command_receipt.v0`.
|
|
|
|
- `createGameObject`
|
|
- `attachComponent`
|
|
- `setGameObjectTransform`
|
|
- `setGameObjectActive`
|
|
- `setGameObjectParent`
|
|
- `setComponentProperty`
|
|
- `instantiatePrefab`
|
|
- `createPrefabVariant`
|
|
- `assignMaterial`
|
|
- `createScriptableObject`
|
|
- `refreshAssets`
|
|
- `setEditorPlayState`
|
|
- `setEditorPaused`
|
|
- `captureEditorView`
|
|
- `saveScene`
|
|
|
|
Unity owns the mutation. Brokkr advertises the command surface; Verse clients
|
|
write typed command intents; Unity executes recognized intents and publishes
|
|
receipts. `setComponentProperty` writes the target object by default; when
|
|
`componentType` is present, Unity resolves that component on the target
|
|
GameObject and writes the serialized property there.
|
|
`setGameObjectActive` uses `targetObjectId` and boolean `value`.
|
|
`setGameObjectParent` uses `targetObjectId` and `parentObjectId`; an empty
|
|
`parentObjectId` reparents the GameObject to the scene root.
|
|
`instantiatePrefab` uses `assetPath` as the source prefab, `name` as the
|
|
optional instance name, and `parentObjectId` as the optional parent.
|
|
`createPrefabVariant` uses `assetPath` as the source prefab and `value` as the
|
|
destination prefab path.
|
|
`createScriptableObject` uses `componentType` as the ScriptableObject type and
|
|
`assetPath` as the destination asset path.
|
|
`refreshAssets` forces an AssetDatabase refresh. `setEditorPlayState` and
|
|
`setEditorPaused` take boolean `value`; the editor service restarts from
|
|
`[InitializeOnLoad]` after the resulting domain reload and keeps draining.
|
|
`captureEditorView` renders `viewKind` (`scene` or `game`) to a PNG at `width`
|
|
by `height` (0 means the camera size, at most 8192). `outputPath` is a plain
|
|
relative path ending in `.png`, resolved under `<project>/.brokkr/captures/`;
|
|
anything else is denied. `saveScene` saves the open scenes.
|
|
|
|
### Admission
|
|
|
|
Before any intent runs, `BrokkrCommandPolicy` checks it against the project's
|
|
allowed-action list (window field "Allowed Actions", per project). By default
|
|
scene mutation and editor lifecycle actions are allowed; the asset-writing
|
|
actions `createScriptableObject` and `createPrefabVariant`, and `saveScene`,
|
|
are not, and an action the list does not name is denied. A denied intent gets a
|
|
receipt with `status: denied` and the reason in `message`, so a refusal is as
|
|
visible as an acceptance. `requestedBy` on the intent names the caller and is
|
|
echoed on the receipt; admission never reads it. The window's buttons write
|
|
intents like any other caller, so the operator and an agent pass the same gate.
|
|
|
|
## Unity Command Transport
|
|
|
|
Commands reach the editor through the project's directory store at
|
|
`<project>/.brokkr/unity-editor.ccmp` (`.records/` beside it). There is no
|
|
network listener: admission starts at filesystem permissions, and the editor sees
|
|
a written intent on its next pull, about once a second.
|
|
|
|
The editor executes intents only while the operator has enabled agent commands
|
|
for that project (window toggle "Agent Commands"). The flag is off by default
|
|
and installing the package never turns it on. The host snapshot carries it as
|
|
`agentCommandsEnabled`, so a caller can see why nothing executes.
|
|
|
|
A command id is single-use. Every writer mints a fresh `commandId` for each
|
|
act, and a receipt at `unity/receipts/{commandId}` answers exactly that id.
|
|
Once an id has a receipt, the editor never executes it again, whatever is
|
|
later written under it: reusing an answered id is a caller defect, and its
|
|
receipt is the answer that stands. A writer that repeats an intent mints a new
|
|
id for each repetition.
|
|
|
|
## Blender Command Actions
|
|
|
|
All Blender writes use `brokkr.blender.command_intent.v0` and receive
|
|
`brokkr.blender.command_receipt.v0`.
|
|
|
|
- `createObject`
|
|
- `deleteObject`
|
|
- `setObjectTransform`
|
|
- `setObjectVisibility`
|
|
- `setObjectParent`
|
|
- `setObjectCustomProperty`
|
|
- `selectObject`
|
|
- `assignMaterial`
|
|
- `importGltf`
|
|
- `setCamera`
|
|
- `setLight`
|
|
- `setWorld`
|
|
- `renderStill`
|
|
- `createNodeGroup`, `addNode`, `removeNode`, `linkSockets`, `unlinkSockets`, `addModifier`,
|
|
`removeModifier`, `setModifierInput` (Geometry Nodes graphs; fields in
|
|
`surfaces/blender/docs/node-actions.md`)
|
|
|
|
Blender owns the mutation. Brokkr advertises the command surface; Verse clients
|
|
write typed command intents; Blender executes recognized intents and publishes
|
|
receipts.
|
|
`setObjectParent` uses `targetObjectName` and optional `parentObjectName`; an
|
|
empty parent reparents the object to the Blender scene root.
|
|
|
|
## Operator Views
|
|
|
|
Eve is deprecated, and Thing 2 is its successor (`thing2:ruling:eve-dashboards-quarantined`, 2026-10-22). Brokkr advertises no operator-dashboard surface; it publishes typed CultMesh state meanwhile. The scene graph, component state, asset library, command affordances and command receipts are mirrored documents; a future Thing 2 view over them does not own editor truth.
|