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:
uuidgenon Linux and macOS does not support UUIDv7 yet. Do not useuuidgenfor 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
-
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.
-
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.
-
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.
-
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:
ouidis the UUIDv7 itself — there is no separateidfield. Display names live in BookStack page titles, page slugs, and agent filename: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 Journalbooks 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.
Related
- Cloud Backup Architecture Standards — Mode A bucket naming, baseline settings, credential model (all built on org/location/device OUIDs)
- Workload-Instance Bucket Architecture — Mode B bucket naming, 100-client cap, credential model (built on workload-instance OUIDs)
- TrueNAS Cloud Sync Provisioning SOP — step-by-step provisioning using OUIDs
- Device Naming Convention — display names (complementary to OUIDs, not a replacement)
- Client Credential Administration Standard — credential scoping uses OUIDs for bucket isolation
- Entity Identity — OUID Standard (DevOps book) — application-level OUID pattern for DTC-built software (database schema, API resolution, external identifier mapping)
- Entity Identity — OUID Standard (BR KB) — the broader cross-context standard covering the conceptual model (id + ouid) across both personal and DTC applications