Skip to main content

Operational UUID (OUID) Standard

The Operational UUID (OUID) is DTC's universal entity identifier. Every managed entity in DTC's ecosystem carries one: organizations, locations, devices, users, workload instances. It is the canonical identity that bridges all DTC-managed systems — NinjaOne, Backblaze B2, TrueNAS, Veeam, MSP360, the client portal, HaloPSA integrations, and any internally developed application.

The OUID is what makes cross-system lookups possible without hardcoded names, fragile string matching, or manual mapping tables. A provisioning script reads a device's OUID, queries NinjaOne for context, and computes everything else at runtime. An internal app that needs to find a location's cloud storage composes the location OUID into a bucket name. The OUID is the glue.


Format

All OUIDs are UUIDv7 (RFC 9562).

Property Value
Version UUIDv7
Format Lowercase, dashed: 018f6b1d-7c4a-7def-8a1b-3c4d5e6f7a8b
Length 36 characters (with dashes), 32 hex characters (flat)
Timestamp Embedded in the first 48 bits (Unix ms) — creation time is extractable
Random bits 62 bits of CSPRNG randomness
Collision risk Effectively zero — two UUIDs generated in different milliseconds can never collide; within the same millisecond, collision requires ~2 billion UUIDs

Why UUIDv7 over UUIDv4

  • Time-ordered. Newer entities sort after older ones. Better for database indexes, log correlation, and human readability.
  • Embedded timestamp. You can extract when the entity was provisioned directly from the OUID without querying another system.
  • Same compatibility. UUIDv7 is the same length and format as v4. Every system that accepts a UUID accepts a v7. Bucket names, ZFS properties, NinjaOne custom fields, registry keys — all work identically.

Legacy note: Some existing entities may carry UUIDv4 OUIDs from before this standard. They remain valid and do not need to be regenerated. All new OUIDs must be v7.


Generating UUIDv7

Windows (PowerShell)

.NET 9+ (pwsh 7.x on .NET 9 runtime):

[System.Guid]::CreateVersion7().ToString().ToLower()

Check your runtime version:

[System.Environment]::Version.ToString()
# Need 9.x for CreateVersion7()

Any Windows with Node.js installed:

npx uuid v7

Any Windows with Python 3.14+:

python -c "import uuid; print(uuid.uuid7())"

Python 3.13 and earlier:

pip install uuid6
python -c "import uuid6; print(uuid6.uuid7())"

macOS

npx uuid v7

Or with Python 3.14+:

python3 -c "import uuid; print(uuid.uuid7())"

Linux (TrueNAS, Proxmox, Ubuntu, etc.)

npx uuid v7

Or with Python 3.14+:

python3 -c "import uuid; print(uuid.uuid7())"

Python 3.13 and earlier:

pip3 install uuid6
python3 -c "import uuid6; print(uuid6.uuid7())"

Note: uuidgen on Linux and macOS does not support UUIDv7 yet. Do not use uuidgen for OUID generation.


What Carries an OUID

Entity Where the OUID lives Authoritative source
Organization (client) NinjaOne org custom field Org UUID NinjaOne
Location (physical site) NinjaOne location custom field Location UUID NinjaOne
Device NinjaOne device custom field Device GUID + on-device storage (see below) NinjaOne
Workload type Controlled vocabulary token (not a UUID): veeam, truenas, msp360, etc. This page
Workload instance HaloPSA workload-instance custom field (planned); 1Password as interim HaloPSA
User Future — not yet implemented TBD
AI identity The Hive shelf (id 3277) in this KB — each identity's books This KB

Workload type vs. workload instance: the workload type is a short controlled-vocabulary token that names a class of backup or storage workload (e.g., veeam is the type representing Veeam Backup & Replication). The workload instance is a specific deployment of that type and carries a real UUIDv7 OUID. For example, "DTC's MSP360 production deployment" is one workload instance with its own OUID; a hypothetical second deployment would be a separate instance with a separate OUID. Workload types live in the controlled vocabulary on this page and on the per-mode bucket architecture pages. Workload instances are tracked in HaloPSA (or 1Password until the HaloPSA schema lands).

Device OUID storage

The device's OUID (historically called "Device GUID") is the one OUID that gets stored on the device itself. This is because devices need to self-identify during provisioning and backup operations without network access to NinjaOne.

Platform Storage mechanism
TrueNAS (CORE or SCALE) ZFS user property com.dtctoday:device-guid on the root pool
Proxmox / Linux with ZFS ZFS user property com.dtctoday:device-guid on the root pool
Linux without ZFS /etc/dtctoday/device-guid
Windows (Veeam, BDR, etc.) NinjaOne device custom field + registry key HKLM\SOFTWARE\DTC\DeviceGuid
Any device Additionally mirrored in NinjaOne device custom field

Only the device OUID is stored on the device. Org and location OUIDs are ambient context looked up at runtime from NinjaOne. This is because devices move between orgs and locations over their lifecycle — the device OUID is the one thing that never changes.


How OUIDs Compose

OUIDs are building blocks. They compose into derived identifiers for specific purposes:

Cloud backup bucket names — Mode A (per-location, per-workload)

{workload}-{location-ouid-flat}
Component Derivation
workload Controlled vocabulary token (veeam, truenas, pbs, etc.)
location-ouid-flat Location OUID with dashes removed (32 hex chars)

The org OUID is not part of the bucket name: a location belongs to exactly one client, so the location OUID implies the org, and per-org rollups are recovered by joining location → org in NinjaOne. This keeps the storage boundary on the layer that actually moves — locations get bought and sold, and a transferred location keeps its OUID, so its bucket and data stay put. The folder inside the bucket is the device OUID in dashed form (see "Folder paths inside buckets" below).

See Cloud Backup Architecture Standards for the full bucket naming scheme, baseline settings, and credential model.

Cloud bucket names — Mode B (workload-instance)

{workload}-{workload-instance-ouid-flat}
Component Derivation
workload Controlled vocabulary token (msp360, etc.)
workload-instance-ouid-flat Workload instance OUID with dashes removed (32 hex chars)

Used for backup workloads that handle multi-tenancy at the application layer (MSP360) and for DTC-built multi-tenant services. See Workload-Instance Bucket Architecture for the full naming scheme, the 100-client cap, and the credential model.

Folder paths inside buckets

/{device-ouid-dashed}/{optional-sub-path}/             (Mode A)
/{workload-token}-{workload-instance-ouid-dashed}/...  (Mode B)

The OUID at the top folder is in its native dashed form. Literal string match across NinjaOne, HaloPSA, ZFS properties, B2 paths, and log lines.


Principles

  1. OUIDs are assigned once and never change. An entity's OUID is permanent. If an org rebrands, the OUID stays. If a device moves locations, its OUID stays. If a workload instance is renamed in HaloPSA, the OUID stays. Stability is the point.

  2. Authoritative platform per entity class. Org, location, and device OUIDs live in NinjaOne. Workload-instance OUIDs live in HaloPSA. Each entity class has exactly one authoritative source; everything else is derived at runtime.

  3. Context is looked up, not stored. A device knows its own OUID. It does not know its org's OUID or location's OUID. Provisioning scripts query NinjaOne to resolve context. This prevents stale metadata when entities move. The same pattern applies to workload instances — application code queries HaloPSA for instance context rather than persisting it.

  4. OUIDs bridge systems, not names. Human-readable names change. OUIDs don't. When DTC builds internal applications that need to reference an entity across systems, the OUID is the join key — never the display name, never a NinjaOne numeric ID, never a HaloPSA record number.


Collision Safety

UUIDs are designed to be globally unique without coordination. There is no central registry — any system can generate one independently and it will not collide with any other UUID ever generated.

For UUIDv7 specifically:

  • 48-bit millisecond timestamp partitions the UUID space by time. Two UUIDs generated in different milliseconds cannot collide regardless of the random portion.
  • 62 bits of randomness within each millisecond. Birthday-paradox collision requires generating ~2 billion UUIDs in the same millisecond on the same system.
  • In practice: DTC provisions entities at human scale (dozens per day, not billions per millisecond). The collision probability is not meaningfully different from zero.

UUIDv4 (122 random bits) has even more random space but lacks the time-ordering benefits. Existing v4 OUIDs remain valid and collision-safe.


AI Identities

AI identities (general-tier and team-member-tier) follow the same OUID model as every other entity at DTC. Each identity gets a UUIDv7 OUID that is its source of truth and permanent identifier.

AI Identities use a simplified single-field form of this standard: ouid is the UUIDv7 itself — there is no separate id field. Display names live in BookStack page titles, page slugs, and agent file name: keys. Other entity types (organizations, locations, devices, workload instances) continue using the two-field form.

Field Example (Apis)
ouid 019dc66e4dd87ea080ebf5d5e2985d91
Display name apis (in page title, slug, and agent name: key)
Tier general or team-member
Owner The human user who owns this identity

Identity Tiers

  • General-tier — top-level AI identity for the context. Apis is DTC's general. Runs primary work (engineering, infrastructure, client documentation, team operations).
  • Team-member-tier — owned by an individual team member (Mike, Steve, Monica, etc.). Scoped to that person's work. Each gets their own {Name}'s Identity, {Name}'s Collage, {Name}'s Journal books on The Hive shelf.

The Hive

DTC's Hive shelf (id 3277) hosts every AI identity's books. The AI Identity Directory on The Hive shelf holds the current roster.

Sub-agents

Each identity's sub-agents (code-writer, researcher, documenter, etc.) are separate entities — each agent file gets its own ouid and master_ouid. Sub-agents live in ~/.claude-dtc/agents/ for DTC-context work.

Compliance

This identity model directly implements 5.9 AI Usage Policy §4.5 — AI must not impersonate team members when a human is not in the loop. Every conversation surfaces the AI's identity so the human user always knows who they're talking to.