Using the Overwatch service

The Overwatch service provides JSON-based remote introspection of a running Kanzi application. It exposes the scene graph, node properties, resources, textures, render passes, screen capture, performance metrics, data sources, logs, and trace capture through a set of overwatch.* commands.

You can use these commands from the local console, the remote TCP console, or the serial console. They are also the foundation for the Monitor Web UI, which provides a browser-based interface for visual debugging.

Platform support

The Overwatch service builds from sources on all known Kanzi target platforms.

How the Overwatch service works

The Overwatch service registers overwatch.* commands with the Command Processor service. Each command queries the Kanzi Engine and returns a single-line JSON response through the standard console protocol.

Property modification (overwatch.setprop), data modification (overwatch.setdata) and message dispatch (overwatch.dispatchmessage) are enabled by default. To disable them and operate in read-only mode, set OverwatchPropertyChangeEnabled = 0 in the configuration file.

Screenshot capture uses a two-phase protocol: the first call schedules a capture for the next RenderStage callback (because commands run before rendering, leaving framebuffer 0 empty at command time). The client polls until the image is ready.

Setting up the Overwatch service

  1. The Overwatch service is enabled by default. To disable it, set ServiceOverwatchEnabled = 0 in kanzimonitor.cfg.

  2. Property editing is enabled by default. To disable it, set OverwatchPropertyChangeEnabled = 0 in kanzimonitor.cfg.

  3. Start the application and connect using the remote console, local console, or Monitor Web UI.

  4. Send overwatch.* commands and receive JSON responses.

Querying service status

overwatch              Show Overwatch service status
overwatch.status       Get Overwatch service status as JSON (includes
                       buildConfig, remote console connection counts and
                       resourceMemoryStrategy).

Working with the node tree and properties

overwatch.nodes [maxDepth]                   Get node tree as JSON, each node with its
                                             handle. Optional depth limit.
overwatch.props <node_path> [precedence=local|all]
                                             Get a node's locally-set property values as JSON.
overwatch.setprop <path> <property> <value>  Set a property value on a node. For a
                                             Resource property the value is null, a
                                             resource URL, or a ResourceID.

The node path uses / separators matching the Kanzi node hierarchy (for example, Viewport 2D/Scene/Text Block 3D). The commands read a path that contains spaces in two different ways:

  • overwatch.props takes the rest of the line as the path, after an optional trailing precedence=. Quotes are optional and are stripped if present.

  • overwatch.setprop reads its arguments as tokens, so a path that contains spaces must be quoted, with double or single quotes. Unquoted, the path ends at the first space. The same applies to the property and the value, and to the data-object path of overwatch.setdata.

Quoting a path always works, so a client that quotes every node path is correct for every command:

overwatch.props /Screen/RootNode/Viewport 2D/Scene/Text Block 3D
overwatch.props "/Screen/RootNode/Viewport 2D/Scene/Text Block 3D"
overwatch.setprop "/Screen/RootNode/Viewport 2D/Scene/Text Block 3D" TextConcept.Text hello

debug.breakprop takes its path like overwatch.props; see Using the Debug service.

Addressing a node

A command that takes a node – overwatch.props, overwatch.setprop, overwatch.dispatchmessage, debug.breakprop and the nodetree.* commands – takes it in one of two forms:

  • A path, such as /Screen/RootNode/Button. A segment can be a Kanzi alias, #name, which resolves as Kanzi resolves it from the node’s resource dictionary. See Aliases in a path.

  • A handle, such as @48213977. overwatch.nodes gives every node it lists a handle, and the replies of these commands carry the handle of the node they reached.

A path names the first node it finds. Siblings can have the same name: content made in Kanzi Studio has unique names, but content created at runtime often has not – map labels, list items, instantiated prefabs. A later sibling with a taken name, and everything under it, cannot be reached by its path, only by its handle. overwatch.nodes marks such a node "pathAmbiguous": true, and so do the replies of the commands above, so a client that addresses a node by its handle learns that its path would not reach it. A detached node is reached by no path at all, and is not marked. The first of the same-named siblings is reached by its path and is not marked.

overwatch.nodes
... {"name":"Label","path":"/Screen/Map/prefab/Label","handle":"@48213990",...},
    {"name":"Label","path":"/Screen/Map/prefab/Label","handle":"@48213991","pathAmbiguous":true,...} ...
overwatch.setprop @48213991 TextConcept.Text "the second label"
overwatch.props @48213991

A handle names the node itself, for one run of the application:

  • It stays with the node when the node is moved or renamed. overwatch.props and the nodetree.* replies report the node’s current path. overwatch.setprop, overwatch.dispatchmessage and debug.breakprop echo their argument in path as it was given, so given a handle they echo the handle, and so do the breakpoint listing and log; read the node with overwatch.props for its path.

  • It names the node object, not what the node shows. An application that reuses node objects for other content, as a list that recycles its items does, keeps the handle on the object.

  • It never keeps a node alive. A handle whose node has been destroyed is refused with "error": "Node not found" and "reason": "The node of this handle no longer exists"; one that never named a node, such as a resource handle, or that named a node Monitor no longer keeps track of, with "No node has this handle". Monitor remembers the 8,192 most recently noticed destructions; a handle whose node was destroyed before those answers as unknown. An argument that starts with @ and is not a handle, such as @0, is refused with "Not a node handle". Node and resource handles come from one counter, so a handle never names both.

  • A node created after the last listing has a handle once a listing or a command reaches it. Each run numbers handles from a different, random point, so a handle kept from an earlier run is almost always refused: list again after a restart.

The NodeTree commands report the same handle for a node they create, detach or move, so a node keeps one handle whichever service reports it. A detached node, which has no path, is read and written through its handle with overwatch.props and overwatch.setprop too.

Aliases in a path

Kanzi Monitor hands everything after the root of a path to Kanzi’s own node lookup, so a segment #name is a Kanzi alias: Kanzi looks name up in the resource dictionary of the node the path has reached, then in each of its ancestors’ dictionaries, and continues from the node the alias points to. Every command that takes a node path accepts one, the nodetree.* commands included:

  • /Screen/#Button – an alias anywhere below the root, here in the dictionary of Screen.

  • /Screen/#Button/Text Block 2D – an alias followed by child segments.

  • /Screen/RootNode/Panel/#Button – an alias that Panel does not define is looked up in RootNode’s dictionary, then Screen’s.

A path still starts at a root: a bare #Button, with no root before it, is not supported and answers Node not found, as an alias no dictionary on the way defines does. The reply’s path is the node’s canonical path, without the alias:

overwatch.props "/Screen/#Button"
→ {"path":"/Screen/RootNode/Button 2D","handle":"@48213977",...}

overwatch.setprop requires OverwatchPropertyChangeEnabled = 1.

Resource-typed properties

A property that references a resource — Model3D.Mesh, CompositionTargetRenderPass.CompositionTarget0 and the like — reports the resource it points at in a resource block:

overwatch.props "/Screen/RootNode/Viewport 2D/Scene/Sphere"
→ {"name":"Model3D.Mesh","type":"Resource","precedence":"local","value":"<Resource>",
   "resource":{"name":"PrimitiveMeshInternal","type":"Kanzi.Mesh",
               "url":"kzb://kanziperformancetools/…/Sphere/PrimitiveMeshInternal"}}

Read the resource block, not value — value stays the placeholder "<Resource>" so that nothing keying off it breaks. The block’s url and handle both round-trip through overwatch.setprop, and unlike an index both survive load and purge churn: the URL across runs, the handle for one run, and the handle also for a resource that has no URL.

overwatch.setprop accepts four things for such a property:

Value

Effect

null

Clears the reference. The resource becomes reclaimable by overwatch.purge unless something else holds it, or unless it is keep-alive.

a handle, @ and digits, such as @48213977

That resource itself, as a resource listing or resource.create reports its handle. A resource created without a URL can be used this way too. See Using the Resource service.

a URL (anything containing ://)

Acquired from the ResourceManager.

anything else

Looked up as a ResourceID in the resource dictionary of the node or its nearest ancestor that has one, which is how project content addresses resources. Only a node has a dictionary, so overwatch.setrenderpassprop needs a URL.

null is read as a literal only for Resource properties. For a string property it is the five-character value, so setting Node.Name to null renames the node.

Warning

A clear may not repaint immediately. On a node with Node2D.ForceComposition set — an Image2D in the example project, for instance — clearing a Resource property leaves the node rendering its previous content, and it keeps doing so however many frames pass. The write itself has landed: overwatch.props reports the property as null, and overwatch.purge can reclaim the resource. Only the picture is stale, because the node is not marked for re-composition.

Any layout change repaints it, so setting Node.Width to its own value is enough to confirm. Setting the property to a resource does not have the problem; only clearing does. This is Kanzi behavior rather than something Kanzi Monitor does — the same clear repaints correctly when the node is not composited. See Known issues.

Any URL scheme the engine understands works, not only kzb://. That includes file://, which loads an image straight off disk, with a relative path resolved against Kanzi’s base resource directory — by default the process working directory, or the APK assets on Android; see Where relative resource paths point to move it:

overwatch.setprop "/Screen/RootNode/Image (Composition)" Image2D.Image file://./my_texture.png
→ {"success":true,"type":"Resource","typeSource":"registry",
   "resource":{"name":"./my_texture.png","type":"Kanzi.Texture","handle":"@48214189","url":"file://./my_texture.png"},
   "previousResource":{"name":"Default Texture","type":"Kanzi.Texture","handle":"@48214035",
                       "url":"kzb://kanziperformancetools/Textures/Default Texture"}}

Both carry the resource’s handle, the one the resource listings report, so the resource a property holds can be read, written or previewed by it, even when it has no URL, as most resources created at runtime have none.

The engine creates the texture from the file on demand, so a running application picks up an image that was not in the kzb and did not exist when it started — no re-export, no rebuild, no restart. That makes it a quick way to try artwork against a live layout, or to substitute a known test image while chasing a rendering problem.

Which schemes work is decided by the application: ResourceManager::registerProtocolHandler() is public API, so an application can add its own. A scheme with no handler is named as the problem, rather than being reported as something wrong with the path:

overwatch.setprop "…/Image (Composition)" Image2D.Image http://example.com/x.png
→ {"error":"Failed to set property",
   "reason":"No protocol handler registered for 'http'. This application cannot load that URL scheme", …}

That is a different failure from a registered scheme whose resource is missing, which says the protocol is registered but nothing resolves at that URL.

Note

The protocol is never used to refuse a URL, only to explain one that failed. A URL does not have to have a loadable scheme to be valid: ResourceManager::registerResource() accepts an arbitrary string, so a resource can be registered under a scheme that has no handler, or under no scheme at all. Kanzi itself does this — kanzi/core.ui/graphics2d/default_geometry is a live resource with no protocol. Every URL is therefore tried first, and the scheme is only inspected to describe what went wrong.

Clearing is reversible. Note the URL, clear the property, purge, and set the same URL back:

overwatch.setprop "…/Sphere" Model3D.Mesh null
overwatch.purge
overwatch.setprop "…/Sphere" Model3D.Mesh kzb://kanziperformancetools/…/PrimitiveMeshInternal

That is the point of the URL round trip: it lets you release a single reference, watch what a purge reclaims, and put it back — rather than testing resource lifetime by demolishing part of the scene graph. If the resource was purged in between, acquiring it reloads it from the kzb, so you get an equivalent resource at the same URL rather than the same object.

Note

A wrong-type write is accepted. The runtime property system records only that a property is Resource-typed, never which resource class it expects, so pointing Model3D.Mesh at a brush succeeds and can break rendering. Nothing can check it — the expected class exists only in the Kanzi Studio editor metadata, which Kanzi compiles into MSVC builds alone.

What Kanzi Monitor does instead is make it visible: a successful write reports resource (what it landed on) beside previousResource (what it replaced), so a change of class reads straight off the response.

The one exception is PrefabViewConcept.Prefab, which only takes a prefab template. A Prefab View uses whatever it is given as a prefab template without checking, so any other resource crashes the application. Kanzi Monitor refuses the write instead:

overwatch.setprop "…/Prefab View 2D" PrefabViewConcept.Prefab kzb://textperf1/Textures/DefaultBackground
→ {"error":"Failed to set property",
   "reason":"PrefabViewConcept.Prefab takes a prefab template, and that resource is a Kanzi.Texture", …}

Swapping the content of a Prefab View. Setting PrefabViewConcept.Prefab to the URL of a prefab replaces what the Prefab View shows. The view removes the node it instantiated before and instantiates the new prefab in its place, so you can switch between scenes from the console without a state manager or a controller property in the project:

overwatch.setprop "/Screen/RootNode/Prefab View 2D" PrefabViewConcept.Prefab "kzb://textperf1/Prefabs/RootNode (10x10 Grid)"
  • Each swap creates a new instance, so any state inside the previous one is lost. Setting the prefab the view already shows does nothing; to get a fresh instance, set null first (which leaves the view empty), then the URL.

  • The instantiation happens synchronously, during the setprop. A prefab that is not loaded yet is loaded in the same frame, so acquire it first with overwatch.acquireresource when frame timing matters.

  • A state manager that drives the property wins. If the project switches the Prefab View through a state manager, its value overrides the one setprop writes, although the write reports success and overwatch.props shows local precedence. To take control from the console, clear the node’s Node.StateManager first. The view keeps its current instance until a setprop changes the prefab; until then overwatch.props can report a prefab that is not the one on screen.

Setting a property value

overwatch.setprop takes the property’s data type from the engine-wide property type registry, the same registry overwatch.propertytypes lists, and parses the value according to that type. Pass the qualified name — TextConcept.HorizontalPadding, not HorizontalPadding — because that is what the registry is keyed by. An unqualified name that matches one or more qualified types is reported with those names as candidates.

Data type

Value format

Example

int

a whole number

overwatch.setprop <path> TextConcept.TextHorizontalAlignment 2

float

a number, with or without a decimal point

overwatch.setprop <path> FontStyleConcept.Size 72

bool

true, false, 1 or 0

overwatch.setprop <path> Node.Visible false

string

text, quoted with " or ' if it contains spaces. One more pair of matching quotes around the text is removed too, as in every release so far: '"x"' and "'x'" both set x. Quotes inside the text are kept. Any other text, a line break or a value wrapped in quotes included, is written as a string literal, $"...": see Setting any text: the string literal

overwatch.setprop <path> TextConcept.Text "Hello world"

ColorRGBA

r,g,b or r,g,b,a, each 0–1

overwatch.setprop <path> TextConcept.FontColor 1,0,0,1

Vector2 / Vector3 / Vector4

x,y / x,y,z / x,y,z,w

overwatch.setprop <path> TextConcept.HorizontalPadding 4,0

SRT2D

sx,sy,rotation,tx,ty, rotation in degrees

overwatch.setprop <path> Node2D.RenderTransformation 1,1,45,0,0

SRT3D

sx,sy,sz,rx,ry,rz,tx,ty,tz, rotations in degrees

overwatch.setprop <path> Node3D.RenderTransformation 1,1,1,0,0,45,0,0,0

pointer, Matrix3x3, Matrix4x4 and range properties cannot be set with this command; it reports the type it resolved and which types are supported.

Resource properties can be set, and take one of four values: null to clear the reference, a resource handle such as @48213977, a resource URL (anything containing ://), or a ResourceID looked up in the resource dictionary of the object or its nearest ancestor that has one. See Resource-typed properties.

The response names the resolved type and where that type came from:

{"success":true,"path":"…","property":"TextConcept.HorizontalPadding","type":"Vector2","typeSource":"registry","value":"4,0","requested":"4,0"}

typeSource

What it means

registry

The property type is registered in the process and its declared type was used. The normal case.

storage

The name is not in the registry, but this node has a property storage entry for it — an unregistered property type.

inferred

Nothing knows the name, so the type was guessed from the shape of the value. A guess, and usually a sign of a misspelled or unqualified name.

A value that does not parse is rejected and the error names the expected format for the resolved type. Nothing is written in that case, which matters for bool: a misspelled true is an error rather than a silent false.

Setting any text: the string literal

A console command is one line, and a quoted value ends at its next quote, so a plain or quoted value cannot hold a line break, a tab or both quote characters. A string literal can hold any text: a $ directly followed by a JSON string in double quotes.

overwatch.setprop <path> TextConcept.Text $"Line one\nline two"
overwatch.setprop <path> TextConcept.Text $"Both \"quotes\" and 'these'"
overwatch.setprop <path> TextConcept.Text $"\ud83d\ude00 is the same as the raw character"

Inside the quotes the JSON escapes apply: a backslash followed by ", \, /, b, f, n, r or t, or by u and four hex digits. A character above U+FFFF is written as a pair of \u escapes, a UTF-16 surrogate pair, or as raw UTF-8. Raw UTF-8 is taken as it is, except a control character, U+0000 to U+001F, which JSON requires to be escaped: a raw tab inside a literal is refused, and \t is what sets one. U+0000 is refused even as \u0000: Kanzi passes text on as C strings in places, which end at it. Because the literal is a JSON string, a client writes any text as $ followed by json.dumps(text) in Python or JSON.stringify(text) in JavaScript, with no rules of Kanzi Monitor’s own. The MCP server and the Web UI write a literal for every value that needs one, and write other values as before.

  • The literal is exact. No quotes are removed from it, so $"'x'" sets 'x', and $"" sets an empty string. It is the only way to clear a string with a property setter, which reads "" as a missing value; the MCP server and the Web UI send $"" for empty text.

  • It works wherever a command reads a value or an argument: overwatch.setprop, overwatch.setresourceprop, overwatch.setrenderpassprop, overwatch.setdata, the arguments of overwatch.dispatchmessage, nodetree.addcomponent and nodetree.setcomponentprop, the arguments of resource.create, and a node path, in overwatch.props too. A command that reads positional arguments reads a literal in any of them, so a file path or a filter that starts with $" is decoded too, and so does a command that takes the rest of the line as one argument when that argument is one literal: the URL of overwatch.acquireresource and overwatch.unregisterresource, the directory of overwatch.resourcedirectory and the filter of overwatch.allresources. In a lookup, such as a filter or a message type name, the literal is exact too: no quotes are removed from what it decodes to.

  • Plain and quoted values are read as before. A backslash in them is an ordinary character, so a Windows path keeps its meaning. Only $" starts a literal; a $ anywhere else is an ordinary character. A setter’s value, the last argument, is quoted only when one pair of quotes encloses all of it, and is otherwise the rest of the line as typed, so 'tis the season keeps its apostrophe. A string written quoted loses one more pair of matching quotes around it, as it always has, which is why the MCP server and the Web UI send text enclosed in quotes as a literal.

  • A malformed literal is refused, and nothing is written. The error names the cause: no closing quote, an escape that is not one of JSON’s, a surrogate that is not half of a pair, a raw control character or U+0000, or text directly after the closing quote. A positional argument ends at a space, and so does a quoted one: text straight after its closing quote is refused, so a path whose quote is never closed cannot end at a later argument’s quote; in a list of name=value pairs, any whitespace separates the next pair. In a property setter, nothing may follow the literal. A malformed node path or property name is refused the same way, as Malformed argument, rather than looked up as written.

Text must be valid UTF-8. Kanzi does not check the text it is given: a sequence that is not UTF-8 renders as nothing or as a replacement glyph, without an error. So every string value is checked, quoted or not, the text arguments of resource.create included, and a value that is not valid UTF-8 is refused with the offset of its first bad byte.

What a Text Block does with the characters is the engine’s behavior. On Kanzi 4.1.1, only a line feed (\n) breaks a line. A carriage return is not drawn, and a tab and the other control characters take no width. A character that no font of the family has renders as the missing-glyph box: add a font that has it as a fallback, see Fonts.

Understanding what overwatch.props reports

overwatch.props reports the properties a project set on a node — through Kanzi Studio, through a binding, or through overwatch.setprop. Each entry carries a precedence field naming the level that supplies its value, and by default every entry reads "precedence":"local".

Kanzi resolves a property value from several input sources, in a fixed order of precedence — a modified value, then the local value, then a named or typed style, then an inherited value, then the class default value. See Property precedence in the Kanzi documentation. precedence names which of those levels the reported value came from.

This is narrower than what the node holds. Kanzi has no way to enumerate “the properties this node can have”; the only thing it enumerates is the node’s property storage, and storage answers a different question — what the node has machinery for. Kanzi creates storage whenever anything needs it: a local value, a style, a modifier, a notification handler, or a property flag. Storage is therefore a superset of the set values, and it can outlive the value that caused it.

Kanzi Monitor enumerates storage because nothing else enumerates, then classifies each entry and reports only the local ones. What it leaves out is not dropped silently — the response ends with a storage object counting every entry by precedence:

"storage":{"entries":16,"local":10,"style":0,"modified":0,"classDefault":3,"none":3}

The counts always sum to entries, so you can see at a glance how much of a node’s storage is not a set value.

precedence

What it means

local

A value the project set: setProperty, a value loaded from a kzb, or a binding, which writes at local precedence. The only precedence reported by default.

style

A named or typed style supplies the value. A value source above class precedence that is not the local value.

modified

A modifier supplies the value, over a style, the class default or no value source: an animation, a value accumulator, an interpolator, a modifier binding, or a state manager state. A modifier acting on a local value is reported as local.

classDefault

The class default value is the only input. The project did not set this property, and no modifier acts on it.

none

Storage exists but nothing supplies a value. A notification handler, modifier storage, or a property flag needed the storage.

Pass precedence=all to see every storage entry, each labelled:

overwatch.props "/Screen/RootNode/Viewport 2D/Scene/Text Block 3D" precedence=all

Note

A none entry reports "value":null. That means no readable value exists, not that the property is set to null. TextConcept.FontColor on a stock TextBlock3D is one: it appears in storage because something registered interest in it, and it has never been set.

Note

An inherited value is reported on the ancestor that sets it, as a local value — not on the descendant that displays it. Kanzi resolves an inheritable property by walking up the ancestors when the value is read, so the descendant gets no value input of its own, and overwatch.props on the descendant reports the property as none or classDefault, or omits it entirely. A list box item whose text is bound through an inherited DataContext.DataContext shows exactly this: the bound text reads correctly, while the node’s own DataContext.DataContext reports "precedence":"none". That is not a missing data context — it is one that lives on an ancestor. To find where an inherited value comes from, query the ancestors.

Note

binding and precedence answer different questions and are reported separately. A bound property usually reads as local, because a binding writes at local precedence — but a resource binding can leave the value coming from the class default, in which case the entry carries a binding field and a precedence of classDefault. Do not read one as implying the other.

A property missing from the default listing is at its class default, or has no value at all. It is not evidence that the node cannot have that property — for that question, use overwatch.propertytypes, which lists the property types registered in the process.

Inspecting what the engine loaded

The commands above answer questions about instances — this node, that render pass. These answer questions about the vocabulary the process has: which kzb files are loaded, and what property types, message types and classes the engine knows.

overwatch.kzbfiles [files] [urls] [types]          Get loaded kzb files as JSON.
overwatch.kzbentry <hostName> <index> <path> [maxBytes]
                                                   Get raw bytes of a kzb entry as hex.
overwatch.propertytypes [filter] [limit] [offset]  Get registered property types as JSON.
overwatch.messagetypes [filter] [limit] [args]     Get registered message types as JSON.
overwatch.messagetype <name>                       Look up one message type by exact name.
overwatch.metaclasses [filter] [limit] [offset] [props] [messages]
                                                   Get registered metaclasses as JSON.
overwatch.metaclasses <class> effective            Get the types one class declares, resolved
                                                   across its base chain and its mixins.

The listings share a paging and filtering convention. filter is a case-insensitive substring of the name, and * means “everything” so that a limit can be passed positionally without narrowing the result. limit of 0 returns every match. Each response reports total, matched, returned and offset, and sets truncated and hasMore when matches exist beyond the window returned — a count is never presented as complete when it is a page.

Which surface answers which question

Command

Answers

overwatch.props

What did the project set on this node. See Understanding what overwatch.props reports.

overwatch.propertytypes

What property types exist in this process, with their data types. Process-wide, not per node.

overwatch.metaclasses

What classes the object factory can create by name, and which property and message types each class declares.

There is deliberately no “what properties can this node accept” listing. overwatch.props reports what a node has, and overwatch.propertytypes reports what exists — neither is a per-node schema.

kzb files

overwatch.kzbfiles lists the kzb files the resource manager has loaded, and the kzb format version this build parses:

{"count":3,"kzbFormatVersion":"46.0","kzbFiles":[
  {"hostName":"kanziperformancetools","index":0,"projectName":"kanziperformancetools","colorWorkflow":"Standard"}, … ]}

The optional flags are opt-in payloads, because they can be large: files adds each kzb’s entries with byte sizes, urls adds resource URLs, and types adds the property types, classes and message types the kzb declares. hostName and index together address one kzb — index is the position within a host name’s group, so it is usually 0.

Note

Under Kanzi Studio Preview, overwatch.kzbfiles does not list the project being authored, only the asset packages the preview loads, such as kzuiassets and runtimeassets. Kanzi Studio sends the project to the preview as patches, and Kanzi adds the kzb of each patch to the resource manager only while it applies that patch, and removes it afterwards. The resources a patch registers stay registered under the project’s kzb://<project>/… URLs, so overwatch.allresources still lists them, and a loaded one is still reachable by URL and by handle, for example with overwatch.resourceinfo. Acquiring a project URL that is not loaded fails, because the kzb it would load from is gone: overwatch.acquireresource, and an acquire after overwatch.unregisterresource, answer that Kanzi has no binary directory for the project. The next patch from Kanzi Studio loads it again. What reads the kzb itself does not cover the project there: the files, urls and types payloads, and the KZB Files view on the Web UI Engine tab. An exported kzb that an application loads is listed as usual.

overwatch.kzbentry reads the raw bytes of one entry, for when a listing is not enough:

overwatch.kzbentry kanziperformancetools 0 /$message_types 16
→ {"hostName":"kanziperformancetools","index":0,"path":"/$message_types","sizeBytes":12,
   "returnedBytes":12,"truncated":false,"leadingUint32LE":1,
   "hex":"01 00 00 00 08 00 00 00 03 00 00 00","ascii":"............"}

Note

The internal layout of $-prefixed kzb entries is private to Kanzi and can change between releases. Read them for diagnosis, not as a format to build on.

Property types, message types and metaclasses

overwatch.propertytypes lists the engine-wide property type registry with a data-type histogram over every match, which is what tells you the real type of a property before setting it:

overwatch.propertytypes ClearColor 6
→ {"total":911,"matched":5,"returned":5,"dataTypeCounts":{"ColorRGBA":5},"propertyTypes":[
   {"name":"ClearRenderPass.ClearColor0","unqualifiedName":"ClearColor0","dataType":"ColorRGBA",
    "inherited":false,"changeFlags":0}, … ]}

overwatch.metaclasses lists the classes the object factory can create by name. Pass props or messages to include what each class declares — this is the owning-class attribution the flat property type registry cannot give:

overwatch.metaclasses ClearRenderPass 2 0 props
→ {"total":465,"matched":1,"abstractCount":0,"sealedCount":1,"metaclasses":[
   {"name":"Kanzi.ClearRenderPass","base":"Kanzi.RenderPass","abstract":false,"sealed":true,
    "propertyTypeCount":6,"messageTypeCount":0,"propertyTypes":[
     {"name":"ClearRenderPass.ClearColor0","dataType":"ColorRGBA"}, … ]}]}

Reading the type graph: base classes and mixins

A class relates to the rest of the graph along two edges, and you need both:

base

The class it derives from, or null if it is a root. Follow it to walk up the hierarchy.

mixins

The concepts mixed into the class, present only when there are any. A concept is not an ancestor, so it never appears on the base chain — but it declares property and message types on the class’s behalf, so leaving it out gives a wrong answer to “what does this class declare”. Even with the mixins, the listing is what classes declare, not everything that affects a node: attached properties such as Grid Layout > Column and Row are declared by the layout and set on its children, and a node can inherit values from its ancestors.

Kanzi.TextBlock3D shows why both matter. It declares 2 property types itself; its base chain adds 39 through Kanzi.Node3D and Kanzi.Node; and its three mixins — Kanzi.TextConcept, Kanzi.TextBlockConcept and Kanzi.FontStyleConcept — add 24 more. Follow only the base chain and you see 41 of 65:

overwatch.metaclasses Kanzi.TextBlock3D 0 0
→ {"metaclasses":[{"name":"Kanzi.TextBlock3D","base":"Kanzi.Node3D","baseSkipped":1,
   "abstract":false,"sealed":true,"propertyTypeCount":2,"messageTypeCount":0,
   "mixins":["Kanzi.TextConcept","Kanzi.TextBlockConcept","Kanzi.FontStyleConcept"]}]}

Note

overwatch.metaclasses reports the object factory registry — the types creatable by name — not every metaclass that exists. A class that is only ever instantiated programmatically is absent by design, so a type appearing in overwatch.allresources but not here is not a defect.

Unnamed concept classes, and baseSkipped

A class implemented through a concept derives from a template instantiation, and the engine registers that instantiation’s metaclass without a name. Those metaclasses are left out of the listing: they all share the empty name, so none of them can be filtered for or referred to, and they declare nothing. unnamedOmitted reports how many were left out.

Because they are skipped, base names the nearest named ancestor rather than the immediate one, and baseSkipped counts the links crossed to reach it — 1 for Kanzi.TextBlock3D above, 2 for Kanzi.Button2D. skippedUnnamedBases reports how many classes in the listing that applies to. Whatever those skipped links carried appears in mixins, so nothing is lost by the skip.

Two guarantees follow, and they are what makes the listing walkable: every ``base`` and every mixin names a class the listing also describes, and every walk up the chain reaches a root rather than stopping at a name that identifies nothing.

What a class declares, in one call

Walking those two edges yourself is possible and not advisable. Add effective and the runtime does it:

overwatch.metaclasses Kanzi.TextBlock3D effective
→ {"class":"Kanzi.TextBlock3D","visitedCount":8,"propertyTypeCount":65,"messageTypeCount":0,
   "duplicatePropertyTypes":0,"duplicateMessageTypes":0,
   "visited":[{"name":"Kanzi.TextBlock3D","via":"self"},
              {"name":"Kanzi.TextConcept","via":"mixin","of":"Kanzi.TextBlock3D"},
              {"name":"Kanzi.TextBlockConcept","via":"mixin","of":"Kanzi.TextBlock3D"},
              {"name":"Kanzi.FontStyleConcept","via":"mixin","of":"Kanzi.TextBlock3D"},
              {"name":"Kanzi.Node3D","via":"base","of":"Kanzi.TextBlock3D"}, … ],
   "propertyTypes":[{"name":"TextConcept.Overflow","dataType":"string",
                     "declaredBy":"Kanzi.TextConcept"}, … ]}

The plain listing answers a narrower question — what one class declares by itself — and for Kanzi.TextBlock3D that is 2 of the 65.

Note

The union is what the class and its concepts declare. It is not everything that affects a node of that class. Some properties a node carries or responds to are declared by other classes: attached properties such as Grid Layout > Column and Row, which are declared by the layout and set on its children, and values a node inherits from its ancestors. Use overwatch.props <path> precedence=all for what a particular node actually holds.

visited reports the walk that produced the union, each entry saying how it was reached (self, base or mixin, with of naming where a mixin came from), so you can check the result instead of trusting it. Every declaredBy is one of those classes. duplicatePropertyTypes and duplicateMessageTypes count names declared by more than one class on the walk; they are 0 on a well-formed graph. Each class is visited once, however many routes reach it, so a mixin reachable twice is not a duplicate.

Both property and message types are always included, so props and messages add nothing here, and limit and offset do not apply — the query is one class, not a page of a listing.

effective needs the exact class name rather than the substring the listing filter takes, because a schema is about one class and Kanzi.Node matches nine of them. A name that does not resolve comes back with the substring matches as candidates:

overwatch.metaclasses TextBlock effective
→ {"error":"Class not found","class":"TextBlock","hint":"Use the exact class name.",
   "candidates":["Kanzi.TextBlock2D","Kanzi.TextBlock3D","Kanzi.TextBlockConcept"]}

overwatch.messagetypes unions two sources, because neither is complete on its own — the message types metaclasses declare, and the ones each kzb declares. The response says how many came from where, and every row carries its source:

overwatch.messagetypes Button 3
→ {"total":206,"matched":10,"returned":3,"truncated":true,"metaclassesScanned":465,
   "kzbDeclaredCount":1,"routingCounts":{"TunnelingBubbling":10},"messageTypes":[
   {"name":"Message.Button.Click","routing":"TunnelingBubbling","source":"metaclass",
    "argumentsClass":"Kanzi.ButtonConcept.ClickedMessageArguments","argumentCount":0}, … ]}

Pass args to include each message type’s flattened argument list.

overwatch.messagetype looks one up by exact name. The registry can only be queried by name, which is why the listing above has to union two walks instead of iterating it:

overwatch.messagetype Message.Button.Click
→ {"name":"Message.Button.Click","found":true,"registeredName":"Message.Button.Click",
   "routing":"TunnelingBubbling","argumentsClass":"Kanzi.ButtonConcept.ClickedMessageArguments",
   "listedByMessageTypes":true}

listedByMessageTypes tells you whether overwatch.messagetypes also reaches it, which is what distinguishes a type that is merely unlisted from one that is genuinely unregistered.

Dispatching a message

overwatch.dispatchmessage makes the application react as if its own logic had sent a message: fire a click at a button, ask a state manager for a state, run whatever a project trigger listens for. Nothing about input is simulated, and the project is not rebuilt.

overwatch.dispatchmessage <node-path> <MessageType> [argument=value ...]

The message is dispatched from the node, with Kanzi’s own dispatch, and travels by its routing. A tunneling message passes every ancestor on its way down to the node, a bubbling one passes them on its way up, and most Kanzi messages do both. So handlers on every ancestor can run, not only handlers on the node; handlers below it are not reached. The reply reports the routing and says in reach what it covers.

  • Message type. The exact, case-sensitive name that overwatch.messagetypes lists, such as Message.Button.Click. A type declared in the project, such as a MyClickMessage the project defines, is found the same way.

  • Arguments. name=value pairs, separated by spaces. The name is the argument’s qualified name, or its unqualified name when that matches only one argument; overwatch.messagetypes <filter> 0 args lists both. The value is parsed by the argument’s data type, with the formats overwatch.setprop takes (see Setting a property value): int, float, bool, string, Color, Vector2, Vector3, Vector4, SRT2D and SRT3D. Quote a value that contains spaces, with " or ', and write any other text as a string literal, $"..." (see Setting any text: the string literal). An empty value, Theme= or Theme="", is an empty string. Each argument can be given once, whichever name is used for it. A Resource, pointer, matrix or range argument cannot be set from the console.

  • Arguments you leave out are not an error, because the application could dispatch the message the same way. A handler reads such an argument as its type’s default. The reply lists every one of them in defaulted, so a value that nobody supplied is never silent.

Everything is checked before anything is dispatched: the arguments parse, the node exists, the message type is registered, every argument is one the type declares, and every value fits its type. A refusal names its stage (arguments, node or messageType) and what failed, and nothing runs. A handler that throws while the message travels is reported in the dispatch stage with "dispatched": true: the message went out, and handlers that ran before it may have changed the application.

overwatch.dispatchmessage /Screen Message.Screen.ActivateTheme Theme=kzb://kanziperformancetools/Themes/MonitorThemes/Dark
→ {"success":true,"path":"/Screen","handle":"@48213977","messageType":"Message.Screen.ActivateTheme",
   "routing":"TunnelingBubbling","reach":"From the root of the node tree down to this node, …",
   "arguments":[{"name":"MessageArgument.Screen.ActivateThemeMessageArguments.Theme",
                 "dataType":"string","value":"kzb://kanziperformancetools/Themes/MonitorThemes/Dark"}],
   "defaulted":[],"handled":true}

handled is the flag a handler sets when it marks the message handled, as a project trigger with Set Handled does. Many handlers never set it, so false does not mean that nothing ran. Nor does true mean that the message had an effect. ActivateTheme is reported handled for a theme that does not exist, and for a bare theme name such as Theme=Dark, which is not a theme URL. Neither changes anything, so read the themed property back with overwatch.props to see whether the theme changed. The example project has a theme group, MonitorThemes, with the themes Light and Dark, and a localization table with fi-FI: overwatch.setprop /Screen Node.Locale fi-FI switches the locale, and $"" clears it.

A dispatch runs application logic — state changes, navigation, animations, anything subscribed to the message — which is more than overwatch.setprop does to one value. It is behind the same switch, OverwatchPropertyChangeEnabled, and every dispatch is written to the application log (Monitor: dispatching message …), so a state change you cannot otherwise explain can be traced to it.

overwatch.dispatchmessage can be a breakpoint command: it runs after the property write that triggered the breakpoint has returned, not under it. See When a breakpoint’s command runs.

Also in the Web UI, as Dispatch message on the Nodes tab, and through the MCP dispatch_message tool.

Querying resources and memory

overwatch.resources                    Get the resources that have a URL as JSON, with
                                       keepAlive. The count and memory totals cover
                                       all resources.
overwatch.allresources [name_filter]   Get every resource the ResourceManager holds,
                                       with or without a URL, as JSON. Optional name
                                       filter.
overwatch.resourceinfo <resource>      Get detailed resource info as JSON. For textures,
                                       textureInfo includes type, faceCount, sliceCount,
                                       and isCubemap.
overwatch.purge                        Purge unused resources from the ResourceManager.
overwatch.setmemorystrategy <strategy> Set the ResourceManager default memory strategy
                                       for resources acquired from now on. The strategy
                                       is ``KeepInMemory`` or ``OptimizeMemory``.
overwatch.acquireresource <url>        Force a resource into existence by URL.
overwatch.unregisterresource <url>     Remove a URL association so the next acquire
                                       recreates the resource.
overwatch.resourcedirectory [path]     Get or set the directory relative resource paths
                                       resolve against. 'default' restores the engine
                                       default.

Which list to use. The two listings answer different questions:

Command

What it lists

Use it for

overwatch.resources

The resources that have a URL: what the application loaded from a kzb or a file, what overwatch.acquireresource forced into existence, and what resource.create created with a URL.

Project content, and how much of it is loaded.

overwatch.allresources

Every resource the ResourceManager holds, including those created at runtime without a URL, such as a GPU buffer the engine allocates or a resource created with resource.create … -.

Memory accounting, and finding a large runtime allocation that no URL leads to.

Read the two replies differently:

  • In overwatch.resources, count, totalRamBytes and totalVramBytes come from the ResourceManager and cover every resource it holds, with or without a URL. The resources array lists only the resources with a URL. So count is usually larger than the number of entries, and the totals larger than the sum of the entries’ cpuBytes and gpuBytes. The difference is the resources without a URL, which only overwatch.allresources lists.

  • In overwatch.allresources, count, totalCpuBytes and totalGpuBytes cover the entries listed, and totalUnfiltered is the number of resources the manager holds. Without a filter, the two replies agree on the count and the totals. With a filter, the reply lists the resources whose name contains the filter text, matched case-sensitively. A resource without a URL has an empty url. registered is true when the manager maps the resource’s url to that resource, and false when the resource has no URL, or still exists after overwatch.unregisterresource removed the mapping (see Forcing a resource into existence, and letting go of one).

  • index and handle name the same resource in both replies, so the index values in overwatch.resources skip the resources without a URL.

  • A resource keeps its URL after overwatch.unregisterresource, so overwatch.resources lists it for as long as it exists. Only registered in overwatch.allresources tells it apart.

For example, in a Kanzi Studio Preview of a project with a particle system, overwatch.resources reported a count of 267 and 17.6 MB of GPU memory, but listed about 150 entries holding about 6.2 MB of it. Part of the difference was a Kanzi.GPUBuffer named ParticleDataBuffer, 1.12 MB of GPU memory that the particle system holds without a URL. Only overwatch.allresources lists it, with an empty url, and its handle reaches it in overwatch.resourceinfo.

Addressing a resource. Every command that takes a <resource> takes one of three forms, told apart by the first character:

Form

What it names

@48213989, a handle

The resource itself, for the rest of the run. Every resource listing reports one as handle, assigned the first time the resource is listed, and it never changes or names anything else. Use it.

kzb://..., a URL

The resource definition. Stable across runs, but most resources have none: in the example application, 53 of 372.

136, an index (deprecated)

A position in the resource manager’s list. It changes between launches, because resources register in the order they finish loading, and when resources unload, because Kanzi moves the last resource into each freed slot. A stale index reaches another resource and the command reports success.

A handle whose resource has since been destroyed or purged is refused with "error": "Resource no longer loaded"; one that was never a resource’s, such as a NodeTree node’s handle, with "No resource has this handle". A handle lasts one run of the application: after a restart, list the resources again, or use the URL. Each run numbers its handles from a different, random point, so a handle kept from an earlier run is almost always refused with "No resource has this handle" rather than reaching whatever has that number now; this is a safeguard, not a guarantee. A key that starts with / is a node path and is refused as "Not a resource key". A refusal for the wrong kind of resource, such as "Resource is not a texture", names the resource by handle as well as index. Node and resource handles come from one counter, so a handle never names both. In overwatch.framebuffers, handle is the texture’s console handle and fboHandle is the graphics API’s framebuffer object.

A reply to a command whose resource was named by index carries deprecation, saying so, as well as "resolvedBy": "index" where the reply reports how the key resolved. The member is added to overwatch.resourceinfo, texturepreview, renderpasspreview, renderpassprops and setrenderpassprop, refusals included, such as "Resource is not a texture", and is absent when the key was a handle or a URL.

overwatch.resourceprops and overwatch.setresourceprop take a handle or a URL only. An index is refused with "error": "Index not accepted" and a hint to the handle, so these commands never take the form that can reach another resource (KZMON-945).

overwatch.resourceinfo, texturepreview, renderpasspreview, renderpassprops and resourceprops refuse an argument they do not take with "error": "Unexpected argument", naming it in argument and giving the command’s usage, instead of answering for the arguments before it. A maxDim must be a whole number of 0 or more, and texturepreview takes one.

overwatch.allresources Default
→ {"resources":[{"index":97,"handle":"@48214075","name":"Default Texture","type":"Kanzi.Texture", … }, …]}
overwatch.purge                          # resources move to other indices…
overwatch.texturepreview "@48214075" 128       # …but @48214075 is still the same texture

Each resource entry carries keepAlive, the resource’s runtime keep-alive flag. When it is true, the Kanzi Engine ResourceManager pins the resource and overwatch.purge cannot reclaim it. This is the usual explanation for a resource that survives a purge, so the field turns “purge freed nothing” into a question you can answer without a debugger.

Two limits are worth knowing:

  • The field reports the flag the engine resolved at runtime, not the Keep Alive Behavior authored in Kanzi Studio. Comparing the two is how you find a mismatch, but you have to read the project to do it.

  • A resource can survive a purge with keepAlive set to false, simply because something still references it. The field explains pinning, not reference counts.

The memory strategy behind a purge

overwatch.purge is only half the picture. What happens to a resource the moment nothing references it is decided by the ResourceManager memory strategy, and overwatch.status reports it as resourceMemoryStrategy:

Strategy

What happens when a resource becomes unreferenced

KeepInMemory

The Kanzi Engine ResourceManager keeps the resource in memory until you purge.

OptimizeMemory

The Kanzi Engine ResourceManager deletes the resource and frees its CPU and GPU memory straight away.

Read the strategy before you read a purge result, because the same result means opposite things under the two. Under OptimizeMemory, “purge reclaimed nothing” is the expected outcome and tells you nothing is wrong. Under KeepInMemory, the same output means something is still referencing those resources.

That reading holds while the strategy has not been changed. resourceMemoryStrategy is the default for resources acquired from now on, and each resource keeps the strategy it was acquired with, so after a switch a purge covers resources acquired under both. A purge under a reported OptimizeMemory can still reclaim resources cached under KeepInMemory before the switch, and after switching to KeepInMemory, resources acquired earlier under OptimizeMemory are still freed as soon as nothing references them.

To change the strategy at runtime:

overwatch.setmemorystrategy optimizememory

The strategy name is matched without regard to case. Anything else is rejected, so a typo cannot quietly select a strategy you did not ask for.

The change applies to resources acquired from that point on. It does not go back over what is already loaded, so memory does not drop when you run it — switch to OptimizeMemory and then run overwatch.purge if you want both halves.

resourceMemoryStrategy is one value for the whole resource manager, and it is not the same thing as the per-resource keepAlive flag above. A resource can be cached by the manager under KeepInMemory and still report keepAlive: false: keep-alive survives a purge, whereas a cached resource is exactly what a purge reclaims.

Forcing a resource into existence, and letting go of one

overwatch.acquireresource loads a resource by URL whether or not anything asked for it:

overwatch.acquireresource file://./my_texture.png
→ {"success":true,"url":"file://./my_texture.png","alreadyRegistered":false,
   "resource":{"name":"./my_texture.png","type":"Kanzi.Texture","handle":"@48214310",
               "url":"file://./my_texture.png"},
   "retained":true,"memoryStrategy":"KeepInMemory"}

Read retained. Kanzi Monitor does not keep the reference it acquires — holding resources would distort the memory picture it exists to report — so what happens next is the ResourceManager’s decision, and the response reports what it observed rather than predicting it, beside the current default memoryStrategy:

  • retained: true — the resource still exists after Kanzi Monitor let go of it. Either the manager is caching it, and it stays until overwatch.purge, or something else holds it, such as a node that already used it — likely when alreadyRegistered is true. The response cannot tell the two apart.

  • retained: false — nothing references it and the manager is not caching it, so it was destroyed as the command returned and will not appear in overwatch.allresources. That is the OptimizeMemory regime, not a failure.

The resource block carries the resource’s handle, so the next command can address exactly the resource that was acquired (see Addressing a resource). When retained is false, the handle already answers "Resource no longer loaded".

overwatch.unregisterresource is the counterpart, and it is not a delete:

overwatch.unregisterresource file://./my_texture.png
→ {"success":true,"url":"file://./my_texture.png","wasRegistered":true,
   "resource":{…},"resourceStillPresent":true,
   "note":"The URL association is removed, not the resource. …"}

It removes the mapping from the URL to the resource. The resource itself survives for as long as anything references it — resourceStillPresent says whether it did. The resource block carries its handle, which still reaches it after the URL has moved on: once the URL is acquired again, the URL reaches the new resource and the handle the old one. What changes is that the next acquire of that URL builds the resource again. In overwatch.allresources such a resource is still listed with its url, which is the resource’s own, and with "registered": false: the manager no longer maps the URL to it. The Web UI’s kzb URL listing counts only registered resources as loaded, so the row of an unregistered URL offers acquire.

Reloading an asset you edited on disk

That is what makes the command worth having. A resource loaded from a file:// URL is cached, so setting the same URL again returns the old content — and overwatch.purge cannot help, because a resource a property still references is not reclaimable. Unregister breaks the cache:

overwatch.setprop "…/Image (Composition)" Image2D.Image file://./my_texture.png
… edit my_texture.png on disk …
overwatch.unregisterresource file://./my_texture.png
overwatch.setprop "…/Image (Composition)" Image2D.Image file://./my_texture.png

The last step reads the file again and the new image appears. No re-export, no rebuild, no restart. Leave out the unregister and you see the old image, which is the cache doing its job.

Both commands require OverwatchPropertyChangeEnabled = 1.

Where relative resource paths point

overwatch.resourcedirectory reads and sets Kanzi’s base resource directory — a working directory of the engine’s own, scoped to resource and kzb loading:

overwatch.resourcedirectory
→ {"directory":null,"isDefault":true, …}

overwatch.resourcedirectory /data/data/<package>/files/assets
→ {"success":true,"directory":"/data/data/<package>/files/assets","isDefault":false,
   "previousDirectory":null, …}

overwatch.resourcedirectory default
→ {"success":true,"directory":null,"isDefault":true,
   "previousDirectory":"/data/data/<package>/files/assets", …}

It decides what a relative resource path means, a relative file:// URL included. It does not affect ordinary file I/O — fopen() still resolves against the process working directory — and it does not affect absolute URLs.

directory: null with isDefault: true means nothing has been set and the engine default applies: the APK assets on Android, the process working directory elsewhere.

default, unquoted, puts the engine default back, so a directory you set is never a one-way change. A directory that is really named default is still reachable as ./default. On Android this returns relative paths to the APK assets: with a 64×64 kzmon853.png packed into the APK and a 16×16 file of the same name in the application’s data directory, the same file://./kzmon853.png resolved to the APK asset, then to the data-directory file once the directory was set, and to the APK asset again after default.

Android is the reason this exists. Kanzi reads resources from inside the APK by default, so a kzb pushed to the device is unreachable. Point the base directory at a filesystem path and the application loads from there instead, with no rebuild and no re-signing:

adb root
adb shell mkdir -p /data/data/<package>/files/assets
adb push myproject.kzb /data/data/<package>/files/assets/
adb shell chown -R <uid>:<uid> /data/data/<package>/files
overwatch.resourcedirectory /data/data/<package>/files/assets

adb shell stat -c %u /data/data/<package> gives the application’s <uid>. adb root needs an emulator or userdebug image; on a debuggable build adb shell run-as <package> reaches the same directory instead.

Pick a directory the application itself can read. Android sandboxes application storage, so a directory that adb push created is owned by the shell user and is unreadable to the application until you chown it — the symptom is that the URL still does not resolve after you set the directory. The application’s own data directory, chowned as above, works; an application with no storage permission cannot read /sdcard or /data/local/tmp at all.

The setting applies to paths resolved from now on. Anything already loaded keeps what it loaded — to make a URL read again from the new directory, overwatch.unregisterresource it first. Setting the directory needs OverwatchPropertyChangeEnabled = 1; reading it does not.

Note

The change is visible in what a relative URL resolves to, not in the URL itself. On Android, file://./kztest/claude_says_hi.png did not resolve at all while the directory was unset — Kanzi looked for it in the APK assets — and loaded a 1024×1024 texture from the device filesystem once the directory pointed at the folder holding it. Same URL, and the only thing that changed was the directory.

When a path does not resolve, Kanzi logs where it looked: W/KanziResourceFile: APKOpenFile failed: '<the resolved path>' in logcat. That line tells you what the base directory turned a relative path into.

Previewing textures and graphics

overwatch.texturepreview <resource> [maxDim] [gpu] [face=<n>]
                                                   Get texture preview as base64 RGBA.
overwatch.framebuffers                             Get all FBO-backed render-target textures
                                                   as JSON.
overwatch.screenshot [maxDim] [outputIndex]        Capture default framebuffer (FBO 0)
                                                   as base64 RGBA.

overwatch.texturepreview returns a downscaled RGBA image of the given texture (see Addressing a resource). The optional maxDim parameter limits the longest dimension (default: 256). The optional gpu flag forces GPU readback for textures that only exist on the GPU. The optional face=<n> argument selects a single cubemap face, where n is 0–5 in the order +X, -X, +Y, -Y, +Z, -Z (default: 0). The response includes face and faceCount fields.

All image commands (overwatch.texturepreview, overwatch.screenshot, overwatch.renderpasspreview, and the capture.* commands of Using the Capture service) return raw RGBA data.

The pixel rows of a surface capture run bottom-up, on every backend, and the commands say so rather than leaving you to assume it. Kanzi normalises the readback: OpenGL reports the FlipSurface feature as false and a GL surface is already bottom-up in memory, while Vulkan reports it true because it renders to an onscreen surface with a negative viewport height, which leaves that surface top-down — and the engine’s conditional vertical flip turns it back into bottom-up. The flag describes how the surface is stored; the flip cancels it.

overwatch.screenshot, capture.frame, capture.status and capture.manifest therefore carry a rowOrder field, today always "bottom-up". Flip a bottom-up image before display; show a top-down one as it is. Honour the field rather than the convention. The value is a constant in this release – a backend that stored its rows the other way round would need Kanzi Monitor to report it – so what this buys you is that such a change lands in Kanzi Monitor alone and not in your client.

Treat any other value, or a missing field from an older Kanzi Monitor, as no answer and fall back to flipping, which is what every client did before the field existed.

overwatch.texturepreview and overwatch.renderpasspreview carry no rowOrder: they read a texture, or a framebuffer that is not a surface, so the engine applies no surface compensation to them. Treat them as bottom-up, which is what the Kanzi Monitor Web UI’s Flip vertical checkbox does by default.

overwatch.screenshot uses a two-phase capture protocol. The first call schedules the capture for the next render frame and returns {"status":"pending"}. The client polls with the same command until the image is ready, at which point it returns the base64-encoded RGBA data.

The capture is taken inside the render stage, so an application that is not rendering cannot produce one. Each pending response therefore reports waitedMs, framesRendered and deadlineMs, and after the deadline the request is abandoned and answered with an error instead of staying pending indefinitely. framesRendered is always 0 in a pending answer, and that is not a bug: the capture happens inside the render stage with no early return, so if a frame had rendered the request would already be complete rather than pending. The number that moves is mainLoopFrames, the scheduler frames since the request — it climbs even when nothing is drawing. So mainLoopFrames climbing with framesRendered at 0 means the main loop is alive but not rendering (minimised, idle-suspended, or a host whose view trees render into surfaces owned by other processes), while both at 0 means the loop itself is not turning. A request that cannot be served at all, because the graphics output does not exist, is refused immediately rather than accepted and timed out.

A successful capture reports what it captured, so a surface that has nothing to do with the application is visible as such: viewRoots lists each view root with its laid-out size, uniformColor says whether every pixel is identical, and a warning is added when the captured surface matches no view root’s size. That combination — a uniform image at a size no view root has — is what a capture of the wrong framebuffer looks like. A uniform image on its own is not conclusive, since a deliberately black screen is uniform too.

Inspecting render passes

overwatch.renderpasses                             Get render pass tree as JSON.
overwatch.renderpasspreview <resource> [maxDim]    Get CompositionTarget preview as base64 RGBA.
overwatch.renderpassprops <resource> [precedence=local|all]
                                                   Get a render pass's property values as JSON.
overwatch.setrenderpassprop <resource> <property> <value>
                                                   Set a property value on a render pass.

Reading and setting render pass properties

A render pass is a property object, like a node. overwatch.renderpassprops reports its properties in exactly the shape Understanding what overwatch.props reports describes for nodes — only locally-set values by default, each with its precedence, and the rest counted under storage — and overwatch.setrenderpassprop writes one, taking the data type from the property type registry and accepting the value formats listed in Setting a property value.

Both address a pass by the index that overwatch.renderpasses reports, the same index overwatch.renderpasspreview and overwatch.resourceinfo use. overwatch.setrenderpassprop requires OverwatchPropertyChangeEnabled = 1.

To list the property types a pass type declares, use overwatch.metaclasses <type> effective, which resolves the property types across the pass’s base chain and its mixed-in concepts in one call. See What a class declares, in one call.

The properties worth changing interactively:

Property

Type

What it does

RenderPass.Enabled

bool

Turns the pass off. The fastest way to see what a pass contributes — pair it with overwatch.renderpasspreview on the composition target above it.

RenderPass.UpdateRate / UpdateOffset

int

How often the pass runs, and its phase.

RenderPass.InputViewportArea

Vector4

x,y,width,height.

ClearRenderPass.ClearColor0–3

ColorRGBA

r,g,b,a, each 0–1.

ClearRenderPass.ClearDepth / ClearStencil

float / int

Clear values.

ComputeRenderPass.InvokeCountX/Y/Z

int

Compute dispatch size.

For example, to see what a draw pass contributes to a composition target:

overwatch.setrenderpassprop 104 RenderPass.Enabled false
overwatch.renderpasspreview 101

Note

The listing reports what a pass has set, exactly as it does for a node, so a property nothing has assigned does not appear — including RenderPass.Enabled on a pass nobody has toggled. Set it once with overwatch.setrenderpassprop, which resolves the property by name and does not need an existing value, and it appears in the listing from then on.

Note

Resource-typed properties — composition targets, textures, materials, and the OutputBuffer of a CreateGPUBufferRenderPass — can be set here, but take only three of the four values a node accepts: null to clear the reference, a resource handle, or a resource URL. See Resource-typed properties.

A ResourceID is not accepted. An ID resolves through the resource dictionary of a node or its nearest ancestor that has one, and a render pass is not a node, so the name is looked up only in the resource manager. Unless something is registered under exactly that name, the write fails with a reason saying nothing is registered under it and it carries no protocol. Pass a URL instead.

Like the node setter’s, the render pass response reports the resource the write stored as resource and the one it replaced as previousResource, beside the resolved type and whether the write succeeded.

A render pass is a resource, and overwatch.renderpassprops and overwatch.setrenderpassprop are the resource commands of the next section applied to one: they take the same keys and their replies identify the pass the same way, with resolvedBy, handle, index, name, kind, metaclass and url.

Reading and setting properties on any resource

overwatch.resourceprops <resource> [precedence=local|all]
                                                   Get any resource's property values as JSON.
overwatch.setresourceprop <resource> <property> <value>
                                                   Set a property value on any resource.

Every resource is a property object, so brushes, materials, data objects and the rest can be read and set the way render passes are. A resource is shared: a write changes it for every node, material and pass that uses it, not only where you found it. The listing and the value formats are those of overwatch.renderpassprops and overwatch.setrenderpassprop, and the same limit applies to Resource-typed values: a URL or null, not a ResourceID, because a resource is not a node.

Addressing. A resource is addressed by its handle or its URL, as in Addressing a resource, and the response says which one resolved and what it reached. An index is refused, unlike in the older resource commands:

overwatch.setresourceprop "@48214114" ColorBrush.Color "0,1,0,1"
→ {"resolvedBy":"handle","handle":"@48214114","index":136,"name":"TextBlockColorFontBrush","kind":"resource",
   "metaclass":"Kanzi.ColorBrush","url":"","property":"ColorBrush.Color","type":"ColorRGBA","typeSource":"registry",
   "value":"0,1,0,1","requested":"0,1,0,1","success":true}
  • The handle is the one every resource listing reports, and the only key that reaches every resource and cannot reach another one. metaclass is the class; a listing also gives it as type, while in a setresourceprop reply type is the property’s data type.

  • A URL is matched against the loaded resources, as the listings show it; looking one up never loads it. After overwatch.unregisterresource a resource that something still uses keeps its URL and is still found by it; when two loaded resources have the URL, because it was acquired again, the one registered under it is the answer. Use overwatch.acquireresource to load one first.

  • An index is refused with "error": "Index not accepted". A stale index reaches another resource – for setresourceprop, a write to the wrong resource that reports success. index in a reply says where the resource is listed now; it is not a key to keep.

The same reply for every kind of object. overwatch.setprop, overwatch.setresourceprop and overwatch.setrenderpassprop write through one setter, so they accept the same values and report the same way. A write to a Resource-typed property reports the resource it stored as resource and the one it replaced as previousResource, on a resource as on a node. Every property listing and every setprop, setresourceprop and setrenderpassprop reply says what it reached with kind (node or resource) and metaclass, the object’s class.

What a listing tells you. declaredPropertyTypes counts the property types the resource’s class declares, across its bases and mixed-in concepts, taken from the live resource rather than from the class registry, which does not hold every type that exists. When it is 0 and the listing is empty, a note says the class has no properties to report, which is not an error. A resource can hold properties its class does not declare, so a listing with entries carries no note even when the count is 0: a request that fails always carries error. Two kinds of resource deserve a word:

  • A material’s locally-set properties are its shader’s uniforms, such as Diffuse and BlendMode. Its class declares none of them, so a material’s listing is not a subset of what overwatch.metaclasses Kanzi.Material effective reports. The same holds for the uniform-style properties a blit render pass sets. The listing reports what is set; the class reports what it declares.

  • A data object’s value is not a property. Kanzi.DataObjectString and its kind are reachable, but list nothing; read and set their values through overwatch.datasources and overwatch.setdata.

  • A data source, by contrast, is configured through its properties, and setting one is how to reconfigure it while the application runs. The example application’s data source declares CustomPerformanceTools.ExampleDataSource.VehicleModel and feeds it into vehicle/model, which its screen shows:

    overwatch.setresourceprop "kzb://kanziperformancetools/Data Sources/Example Data source" CustomPerformanceTools.ExampleDataSource.VehicleModel "Monitor Car"
    

    The text bound to vehicle/model changes from “Kanzi Car” to “Monitor Car”. What a property of your own data source does is up to the data source: it has to react to the change, as the example does in onPropertyChanged().

A texture has no properties. Its dimensions, format and mipmaps are reported by overwatch.resourceinfo.

Monitoring performance

overwatch.perf                                                   Get performance metrics as JSON.
overwatch.watchers                                               Get performance watchers and
                                                                 available metrics as JSON.
overwatch.addwatcher <metric> <below|above> <threshold> <cmd>    Add a performance watcher.
overwatch.removewatcher <id>                                     Remove a performance watcher
                                                                 by ID.
overwatch.resetwatcher <id>                                      Reset a triggered watcher back
                                                                 to active.
overwatch.clearwatchers                                          Remove all performance watchers.

overwatch.perf returns per-frame rendering statistics using Kanzi 4.0 metric names (drawCount, drawnElements, imageCount, framebufferCount, renderPipelineCount, constantDataCount, renderPassCount, renderPipelineBindCount, computeDispatchCount). For backward compatibility, the old metric names (batchCount, triangleCount, textureSwitches, framebufferSwitches, shaderSwitches, uniformsSent) are also included with the same values.

The response also includes a gpuObjects array with all 16 GPU object types (current, maximum, lifetime, increase, decrease counts) and a stagingBuffers array with per-buffer memory usage.

Note

Rendering statistics and GPU object counts require the Kanzi graphics statistics layer. In Debug builds this is enabled by default; in Release and Profiling builds, set GraphicsStatisticEnabled = true in application.cfg or configuration.graphicsStatisticsEnabled = true in onConfigure(). See Built-in metrics for details.

Performance watchers integrate with the Performance service. See Using performance watchers.

Capturing traces and logs

overwatch.trace                    Capture a Monitor profiling trace and write to
                                   file(s). The format(s) depend on which writers
                                   are active — chrometrace produces .json, perfetto
                                   produces .perfetto-trace.
overwatch.fetchtrace               Fetch the most recently captured chrometrace
                                   (.json) trace as a JSON string. Returns an error
                                   pointing at fetchperfettotrace if only the
                                   perfetto writer is active.
overwatch.fetchperfettotrace       Fetch the most recently captured .perfetto-trace
                                   (native Perfetto protobuf). The binary is
                                   base64-encoded inside a JSON envelope so it can
                                   be transported over the line-delimited protocol.
overwatch.kztrace                  Capture a kzTrace snapshot (engine-native tracing).
overwatch.fetchkztrace             Fetch the most recently captured kzTrace as JSON.
overwatch.kztracecategories        List the kzTrace categories as JSON (read-only).
overwatch.writers                  List registered trace writers as JSON.
overwatch.activatewriter <name>    Activate a trace writer by name.
overwatch.deactivatewriter <name>  Deactivate a trace writer by name.
overwatch.profilingcategories      List profiling categories and their state as JSON.
overwatch.profilingcategories <name> on|off      Enable or disable one category.
overwatch.profilingcategories filter "<filter>"  Apply a category filter.
overwatch.logs           Get recent log entries as JSON with timestamp, level,
                         category, and message.
overwatch.logconfig                        Query log buffer configuration as JSON.
overwatch.logconfig maxentries <count>     Set the log buffer size at runtime.
overwatch.gputimestamps                    Query the GPU timestamp dump as JSON.
overwatch.gputimestamps on [interval]      Dump GPU timings every N frames.
overwatch.gputimestamps off                Stop dumping GPU timings.

How many clients are connected

overwatch.status reports the remote console’s occupancy:

{"remoteConsoleConnections": 2, "remoteConsoleMaxConnections": 4, …}

The remote console serves several clients at once and refuses one that arrives when every slot is taken (see Using the Command Processor service), so these two numbers say whether a tool that cannot connect is being refused or is failing for some other reason.

Reading this over TCP counts the reader, because asking the question occupies a slot. A connection whose client has already gone is counted until the acceptor notices, within a half-second.

Both are null when the remote console is not running — over the serial console, or with RemoteConsoleEnabled = 0. Zero would be misleading, because there is no capacity at all rather than capacity that happens to be free.

Kanzi Monitor supports two trace sources:

  • Monitor profiling trace (overwatch.trace / overwatch.fetchtrace) – Collects profiling data through the Monitor Trace service. The output format is determined by which writers are active in ActiveWriters (see Configuring Kanzi Monitor): chrometrace produces Chrome Trace Format JSON (.json), perfetto produces native Perfetto protobuf (.perfetto-trace), or both can be active simultaneously. In all build configurations the trace includes default registry profilers, named interval profilers, and custom collection tasks such as PerformanceInfo counters. In Profiling builds the trace additionally includes Kanzi Engine engine-internal instrumentation: main loop and startup timing, domain node/layout/render operations, and resource loading. Requires ServiceTraceEnabled = 1. See Using the Profiling Trace service for details.

  • kzTrace (overwatch.kztrace / overwatch.fetchkztrace) – Captures a snapshot from the Kanzi Engine tracing subsystem (kzTrace scope macros). Always produces Chrome Trace Format JSON. Covers engine-internal instrumentation such as frame stages, rendering, resource loading, and node operations. Available only in Debug and Profiling builds (KANZI_TRACING_BUILD). In Release builds, overwatch.kztrace returns an error with a hint about the required build configuration. On Android Kanzi Monitor takes over the engine’s trace output directory: when it resolves the host application’s internal files directory it calls kzTraceSetOutputDirectory() with it, at plugin initialization and again on every overwatch.kztrace. This is deliberate – the Kanzi Engine default destination is /sdcard/Download/, which an application without a storage permission cannot write, and logTraceToFile() reports no failure, so the trace would go missing silently. It does mean that a path your application set with kzTraceSetOutputDirectory() is replaced for as long as Kanzi Monitor is loaded.

If that resolution fails, overwatch.kztrace retries it, and what happens then depends on whether Kanzi Monitor ever took the setting over:

  • It had. The engine is aimed at a Kanzi Monitor directory that is now unusable, so the command returns an error and writes nothing. The response’s reason says which failure it was – the Android files directory could not be determined, or it was determined and is not a writable directory.

  • It never had. Kanzi Monitor has overridden nothing, so the destination is the engine’s default or whatever your application set, and that is not Kanzi Monitor’s to refuse. The trace is written and the response carries "verified": false with "destination": "engine": Kanzi Monitor cannot confirm the write or fetch the file, because it does not know where the file went. See the Tracing API reference and Tracing application configuration in the Kanzi Engine documentation.

Both outputs are compatible with Perfetto UI: drag a .json or .perfetto-trace file into the page to view it.

overwatch.fetchtrace reads the last trace file written by the Trace service and returns its full contents as a JSON string. This can be a large response (several MB). It only returns .json (chrometrace) output — when only the perfetto writer is active it returns an error pointing at overwatch.fetchperfettotrace. That command reads the most recent .perfetto-trace file (binary protobuf), base64-encodes the bytes, and emits a JSON envelope of the form {"file":"<name>.perfetto-trace","size":<bytes>,"data":"<base64>"}; the Web UI and MCP server decode the base64 on receipt. overwatch.fetchkztrace works the same way as fetchtrace for kzTrace files.

The trace writers are themselves inspectable and controllable at runtime through three additional commands — overwatch.writers (lists all registered writers with name, description, active state and availability as JSON), overwatch.activatewriter <name>, and overwatch.deactivatewriter <name>. See Using the Profiling Trace service for the registry model and built-in writer reference. Which profiling categories are recorded is controlled the same way, with overwatch.profilingcategories; see Choosing which profiling categories are recorded. overwatch.kztracecategories lists the kzTrace categories; see Listing the kzTrace categories.

GPU timestamp dump

overwatch.gputimestamps turns on the engine’s GPU timing dump, which reports how long the GPU spent on each frame and on each render pass within it. Use it to find which render pass is expensive on a device you cannot attach a GPU profiler to.

This works in every engine build, including Release.

The output arrives through the normal log, so read it back with overwatch.logs, in the Web UI Logs tab, or over MCP:

Frame duration 491250 start 0 end 491250
RP 1 duration 219062 start 162604 end 381666
RP 2 duration 44635 start 15677 end 60312

Durations are in nanoseconds. Lines appear only for frames the application actually renders. Kanzi renders a frame only when something in the node tree changes, so a static scene produces no dump at all – interact with the application, or run an animation, while the dump is on.

The dump is bounded by a frame interval rather than a frame count, because it produces a handful of lines per frame rather than hundreds – the useful control is how often rather than how many. It still shares the one log buffer, so raise the interval rather than leaving it at 1, and switch the dump off when you are finished.

Warning

On every |k| 4.1.x, the timings can be wrong, and nothing available to you says when. When affected, passes report start 0 and the durations are meaningless: exactly 0, tens of hours (around 1e14 ns, an absolute clock reading), or close to 1.8e19 ns (end before start, wrapped around). The Frame line is affected as well, not only the render passes.

The cause is a defect in the Kanzi OpenGL backend (RENDERING-3141): the GL query pool shared a single query object across all of its slots, so per-slot result reads raced. No |k| 4.1.x release contains a fix, so it is present with every Kanzi version this Kanzi Monitor line supports.

Some GPUs show it and others do not – NVIDIA and AMD drivers happened to tolerate the race, Intel did not. That is why neither the graphics backend nor the GPU vendor tells you whether the numbers are usable, and why the engine’s TimestampQuery capability flag is no help either: it reports supported on the affected path.

Check the durations yourself before using them. overwatch.gputimestamps reports "valuesValidated": false – it does not judge the values for you. Read the dump lines back and look at them: a working configuration produces durations in the microsecond-to-millisecond range, with a non-zero start on the render passes. Anything else – 0, hours, or 1.8e19 – is the defect, and the exact figure varies from run to run, so do not look for a particular number.

Note

The passes are unnamed. They arrive as RP 1 … RP n in submission order, with no mapping back to the render pass tree, so you have to count against overwatch.renderpasses to identify one.

overwatch.status reports whether the dump is currently on through gpuTimestampsEnabled. There is no availability flag beside it, because no engine build support is required.

Working with data sources

overwatch.datasources                              Get all DataSources and their DataObject
                                                   trees as JSON.
overwatch.setdata <datasource> <path> <value>      Set a DataObject value.

overwatch.datasources serializes DataObjectList nodes with a type of list, an itemCount field, and an items array containing each list item’s data.

Use the #index path syntax to address items inside a DataObjectList. For example, to set the name of the first contact in a list:

overwatch.setdata MyDataSource Root/contacts/#0/name "Alice"

overwatch.setdata requires OverwatchPropertyChangeEnabled = 1.

Inspecting fonts and glyph caches

overwatch.fonts                                       Get all active FontRuntimes as JSON with
                                                      font identity, style definition, glyph cache
                                                      state, font metrics, and node usage.
overwatch.glyphcachepreview <index> [maxDim]          Get glyph cache texture preview as base64
                                                      RGBA. The index refers to a font entry from
                                                      overwatch.fonts.
overwatch.setglyphcachesize <width> <height>          Set glyph cache texture size for newly
                                                      created caches. Existing caches retain their
                                                      current size. Requires OverwatchPropertyChangeEnabled.

Font inspection requires a registered node tree. When the node tree is not available, overwatch.fonts returns "nodeTreeAvailable":false with an empty font list, and overwatch.glyphcachepreview returns an error message.

The overwatch.fonts response includes a uniqueCacheCount field and a deduplicated totalGpuMemory total. When the glyph cache size has been overridden, a configuredGlyphCacheSize object is included.

Each font’s glyphCache object carries generation, the glyph cache’s generation as Kanzi counts it; overwatch.glyphcachepreview reports it too, and the fontinfo console command shows it as gen. Kanzi increments it each time a glyph does not fit in a full cache and Kanzi tries to recycle the slot of an older glyph for it: once per glyph, so a jump of a few hundred is a few hundred glyphs, not a few hundred refills. It counts the attempt: when no slot is old enough to recycle, the generation still grows and the glyph is not rendered. A glyph cache belongs to one font file at one size, and every text in that font and size shares it, so the count covers all of that text, not one Text Block. A generation that grows while the text on screen does not change means that text holds more distinct glyphs than the cache can: the screen still looks right, but the glyphs are rendered into the cache again frame after frame. overwatch.setglyphcachesize lets you find the size at which it stops growing. Kanzi also logs a warning the first time a cache fills, once per cache: Glyph cache full for font '<name>' (size <n>), recycling glyphs for more space for a scalable font, and Glyph cache full for non-scalable font '<name>', recycling glyphs for more space for a bitmap font. A generation that stays the same does not prove that the glyphs fit: a glyph that Kanzi fetches without recycling fails on a full cache and leaves the generation as it is. Measured on Kanzi 4.1.1, a Text Block of 240 distinct CJK characters at size 24, redrawn every frame: with the default 512×512 cache the generation stayed the same and rendering took 0.11 ms per frame, and with a 256×256 cache it grew by about 140 per frame and rendering took 2.83 ms.

Overriding the glyph cache size with overwatch.setglyphcachesize lets you pressure-test glyph cache behavior — for example, forcing cache eviction or measuring the GPU memory impact of a larger atlas — without recompiling the application.

Querying graphics information

overwatch.graphics     Get graphics and GPU information as JSON (backend,
                       device, API version, driver version, features).

Understanding the JSON response format

All overwatch.* commands return a single line of compact JSON. The console protocol uses empty lines as message delimiters, so responses do not contain newlines.

Example request and response over the remote console:

overwatch.perf
{"fps":60.0,"appFps":60.0,"frameTime":16.6,"animTime":0.5,"batches":42,"triangles":15234,...}

Floating-point values that are not finite are reported as null. JSON has no literal for inf, -inf, or NaN, and a property can legitimately hold one — GridListBoxConcept.CalculatedOffset is infinite for a list item that has not been scrolled yet — so writing the value verbatim would make the whole response unparseable. This applies to every property type that carries floats: scalars, ColorRGBA, Vector2/3/4, Matrix3x3/4x4, and SRT2D/3D.

Available commands

Command

Description

overwatch

Shows Overwatch service status.

overwatch.status

Gets Overwatch service status as JSON, including how many remote console clients are connected. See How many clients are connected.

overwatch.nodes

Gets node tree as JSON. Usage: overwatch.nodes [maxDepth]

overwatch.props

Gets a node’s locally-set property values as JSON, each with its precedence, plus a count of the storage entries left out. Usage: overwatch.props <node_path> [precedence=local|all]. See Understanding what overwatch.props reports.

overwatch.setprop

Sets a property value, taking the data type from the property type registry. A Resource property takes null, a resource handle, a resource URL, or a ResourceID. Usage: overwatch.setprop <path> <property> <value>. See Setting a property value and Resource-typed properties.

overwatch.kzbfiles

Gets the loaded kzb files as JSON, with the kzb format version. Usage: overwatch.kzbfiles [files] [urls] [types]. See Inspecting what the engine loaded.

overwatch.kzbentry

Gets the raw bytes of one kzb entry as hex. Usage: overwatch.kzbentry <hostName> <index> <path> [maxBytes]

overwatch.propertytypes

Gets the engine-wide property type registry as JSON, with a data-type histogram. Usage: overwatch.propertytypes [filter] [limit] [offset]

overwatch.messagetypes

Gets the registered message types as JSON, unioning metaclass-declared and kzb-declared types and naming each row’s source. Usage: overwatch.messagetypes [filter] [limit] [args]

overwatch.messagetype

Looks up one message type by exact name. Usage: overwatch.messagetype <name>

overwatch.dispatchmessage

Dispatches a message from a node, with arguments by name, and reports its routing, the declared arguments left at their default, and the handled flag. Requires OverwatchPropertyChangeEnabled = 1. Usage: overwatch.dispatchmessage <node-path> <MessageType> [argument=value ...]. See Dispatching a message.

overwatch.metaclasses

Gets the classes the object factory can create by name, each with its base class and mixin concepts, optionally with the property and message types each declares. Usage: overwatch.metaclasses [filter] [limit] [offset] [props] [messages]. See Reading the type graph: base classes and mixins.

overwatch.metaclasses <class> effective

Gets the property and message types one class declares, resolved across its base chain and its mixed-in concepts, with each entry attributed to the class that declares it. Usage: overwatch.metaclasses <class> effective. See What a class declares, in one call.

overwatch.resources

Gets the resources that have a URL as JSON, each with keepAlive. count, totalRamBytes and totalVramBytes cover every resource in the ResourceManager, so they can exceed the entries listed; overwatch.allresources lists the rest. See Which resource list to use.

overwatch.allresources

Gets every resource the ResourceManager holds as JSON, including those without a URL, whose url is empty. Each has keepAlive and registered, which is false when the resource has no URL, or when the manager no longer maps the resource’s url to it, after overwatch.unregisterresource. Usage: overwatch.allresources [name_filter]. See Which resource list to use.

overwatch.resourceinfo

Gets resource info as JSON, including keepAlive. Usage: overwatch.resourceinfo <resource>. For textures, the textureInfo block includes type, faceCount, sliceCount, and isCubemap.

overwatch.texturepreview

Gets texture preview as base64 RGBA. Usage: overwatch.texturepreview <resource> [maxDim] [gpu] [face=<n>]. face=<n> (0–5) selects a cubemap face.

overwatch.framebuffers

Gets FBO-backed textures as JSON.

overwatch.screenshot

Captures screen as base64 RGBA. Usage: overwatch.screenshot [maxDim] [outputIndex]

overwatch.renderpasses

Gets render pass tree as JSON.

overwatch.renderpasspreview

Gets render pass preview as base64 RGBA. Usage: overwatch.renderpasspreview <resource> [maxDim]

overwatch.renderpassprops

Gets a render pass’s locally-set property values as JSON, each with its precedence, plus a count of the storage entries left out. Usage: overwatch.renderpassprops <resource> [precedence=local|all]

overwatch.setrenderpassprop

Sets a property value on a render pass, taking the data type from the property type registry. Usage: overwatch.setrenderpassprop <resource> <property> <value>

overwatch.resourceprops

Gets any resource’s locally-set property values as JSON, addressed by handle or URL, with the identity the key resolved to and the number of property types its class declares. Usage: overwatch.resourceprops <resource> [precedence=local|all]

overwatch.setresourceprop

Sets a property value on any resource, addressed by handle or URL. Usage: overwatch.setresourceprop <resource> <property> <value>

overwatch.perf

Gets performance metrics as JSON.

overwatch.watchers

Gets watchers and metrics as JSON.

overwatch.addwatcher

Adds a performance watcher. Usage: overwatch.addwatcher <metric> <below|above> <threshold> <command> [args]

overwatch.removewatcher

Removes a watcher. Usage: overwatch.removewatcher <id>

overwatch.resetwatcher

Resets a triggered watcher. Usage: overwatch.resetwatcher <id>

overwatch.clearwatchers

Removes all watchers.

overwatch.trace

Captures a Monitor profiling trace and writes a file per active writer (.json for chrometrace, .perfetto-trace for perfetto). overwatch.trace clear empties the trace storage instead; see Clearing the trace storage.

overwatch.fetchtrace

Fetches the last Monitor profiling .json (chrometrace) trace as a JSON string. Returns an error pointing at fetchperfettotrace if only the perfetto writer ran.

overwatch.fetchperfettotrace

Fetches the last Monitor profiling .perfetto-trace file as {file, size, data} JSON envelope with the binary base64-encoded.

overwatch.kztrace

Captures a kzTrace snapshot (engine-native tracing, requires Debug or Profiling build).

overwatch.fetchkztrace

Fetches the last kzTrace as JSON.

overwatch.kztracecategories

Lists the kzTrace categories the loaded code registers as JSON, one entry per name with name, description and ids. Read-only: Kanzi 4.1 cannot switch a kzTrace category at runtime. In a Release build the reply is {"available":false,...}. See Listing the kzTrace categories.

overwatch.writers

Lists registered trace writers as JSON with name, description, active state and available. A writer the Trace service blocked, such as a file writer on an Android host with no files directory, has "available": false and an unavailableReason.

overwatch.activatewriter

Activates a trace writer by name. Usage: overwatch.activatewriter <name>. A name no writer has answers Unknown writer; a writer the Trace service blocked answers Writer unavailable with the reason.

overwatch.deactivatewriter

Deactivates a trace writer by name. Usage: overwatch.deactivatewriter <name>

overwatch.profilingcategories

Lists profiling categories (not kzTrace categories) as JSON with name, enabled, known and fromProfiler, plus the startup filter and how the list was built. Gets or sets one category, or applies a filter with the syntax of ProfilingCategoryFilter. reset returns every category to its code default, then applies the startup filter. Usage: overwatch.profilingcategories [<name> [on|off] | filter "<filter>" | reset]. See Choosing which profiling categories are recorded.

overwatch.logs

Gets recent log entries as JSON.

overwatch.logconfig

Gets or sets log buffer configuration. Usage: overwatch.logconfig [maxentries <count>]

overwatch.graphics

Gets graphics information as JSON.

overwatch.datasources

Gets DataSource trees as JSON.

overwatch.setdata

Sets a DataObject value. Usage: overwatch.setdata <datasource> <path> <value>

overwatch.fonts

Gets active FontRuntimes as JSON with style, glyph cache, metrics, and node info.

overwatch.glyphcachepreview

Gets glyph cache texture preview as base64 RGBA. Usage: overwatch.glyphcachepreview <index> [maxDim]

overwatch.setglyphcachesize

Sets glyph cache texture size for new caches. Usage: overwatch.setglyphcachesize <width> <height>

overwatch.purge

Purges unused resources.

overwatch.setmemorystrategy

Sets the ResourceManager default memory strategy for resources acquired from now on. Usage: overwatch.setmemorystrategy <keepinmemory|optimizememory>. See The memory strategy behind a purge.

overwatch.acquireresource

Forces a resource into existence by URL, and reports whether it still exists afterwards. Usage: overwatch.acquireresource <url>. See Forcing a resource into existence, and letting go of one.

overwatch.unregisterresource

Removes a URL association so the next acquire recreates the resource. Not a delete. Usage: overwatch.unregisterresource <url>. See Forcing a resource into existence, and letting go of one.

overwatch.resourcedirectory

Gets or sets Kanzi’s base resource directory, which decides what a relative resource path means. Usage: overwatch.resourcedirectory [path | default]; default restores the engine default. See Where relative resource paths point.

See also

Using the Monitor Web UI

Using the Command Processor service

Using the Capture service

Using the Debug service

Configuring Kanzi Monitor