Administration
Single-page view · as markdown
How the registry boots and configures itself
Peios / Using Peios / Administration
The registry holds the configuration for everything on the system. Which raises an awkward question: what configures the registry? The honest answer is that it mostly configures itself — and doing that means breaking a circular dependency, because the registry's own settings live in the registry, and the store those settings live in is itself a service that has to start up. This page is how that knot is untied, and it doubles as the purest example of the reject-or-keep discipline.
Bootstrap, in one sentence #
The registry subsystem is fully operational on compiled-in defaults from the instant the kernel loads, and hot-swaps to registry-backed configuration once its store comes up — it never enters a "waiting for configuration" state.
The circular dependencies #
Three loops have to be broken at boot:
- The registry reads its own operational parameters (timeouts, size limits, and so on) from a key under the
Machine\hive — but that hive is held by a store that has not started yet. - Other early services want to read their configuration from the registry before that same store is up.
- On a brand-new install there is no data at all: the store's database is empty.
A configuration store that refused to function until it was configured would deadlock on the first of these. The registry is designed so that never happens.
Compiled-in defaults #
Every operational parameter the registry uses has a compiled-in default that produces correct behaviour. From the moment the kernel module loads, the registry runs on those defaults — it is immediately operational and never blocks waiting for configuration. The base layer likewise exists unconditionally, hardcoded, needing no persisted state. So before any store has registered, the machinery is already alive; it simply has no hives to serve yet.
Hot-swap, not restart #
When the store registers and the configuration keys become readable, the registry reads, validates, and swaps its parameters in place — no restart, no re-initialisation. Operations already in flight finish on the values they started with; new operations pick up the new values. The transition from "compiled-in defaults" to "registry-backed configuration" is seamless and is the only configuration transition there is.
flowchart LR
A["Kernel loads — registry live on compiled-in defaults"] --> B["Store registers its hives"]
B --> C["Read Machine\System\Registry\* parameters"]
C --> D["Validate and hot-swap into effect"]
It applies reject-or-keep to itself #
This is the cleanest demonstration of the idea from Configuration, not storage: the registry treats its own configuration as untrusted bytes it must validate. A parameter value that is valid is hot-swapped into effect. One that is invalid — out of range, wrong type — is ignored: the registry keeps the value it was already using and emits an audit event naming the key, the rejected value, and the value still in force. It never clamps the bad value to something legal. The subsystem that owns the entire registry does not trust even its own settings until it has checked them — and when stored and in-force disagree, the audit log is the truth.
First boot, with no data #
A fresh install has an empty store, and the sequence is built to cope:
- The store —
registryd, the base registry source peinit starts at early boot (see LCS and sources) — starts, finds its database empty, and creates the hive root keys with their default security descriptors — but no configuration beneath them. - The registry looks for its parameter keys, finds nothing, and keeps its compiled-in defaults. It is fully operational regardless.
- The init system (not the registry's concern) restores a seed — a backup of the system's initial configuration — that populates
Machine\with the system's real configuration. - That write trips the registry's watch on its own configuration area; it re-reads, validates, and hot-swaps to the seeded values. Normal operation continues.
At no point is there a stall. Empty store, missing keys, seed arriving later — each is handled by "use the defaults until something better shows up", driven by the same watch mechanism every other reactive consumer uses.
The self-watch #
The registry notices changes to its own configuration the same way any service notices changes — by watching the subtree — except the watcher is internal to the kernel rather than a userspace handle. It is the reaction loop turned on the registry itself: a change to a parameter key fires the watch, the registry re-reads and re-validates, and applies or rejects. There is no polling and no special-case configuration path; self-configuration is just the registry being one more consumer of the registry.
Where to go next #
If you want the store itself — what it is, how the kernel and the userspace store divide the work, and the trust boundary between them — read LCS and sources.
If you want the validation discipline this page leans on, read Configuration, not storage.
If you want the change-notification mechanism behind the self-watch, read Watching for changes.
Backup and restore
Peios / Using Peios / Administration
Beyond reading and writing individual values, the registry can move whole subtrees at once: export a key and everything beneath it to a stream, and restore such a stream back into the tree. This is the bulk-data path, and it is the mechanism behind things you have already met — first-boot seeding — as well as the disaster-recovery and migration any real deployment needs.
Backup and restore, in one sentence #
Backup streams a point-in-time copy of a subtree out; restore replaces a subtree wholesale from such a stream — both are privileged, whole-subtree operations, not value-by-value edits.
Backup is a point-in-time snapshot #
A backup captures a key and its entire subtree as it stands at one instant — a consistent snapshot, unaffected by writes happening concurrently. The result is a self-contained stream you can send to a file, a pipe, or across a network.
It is full-fidelity with respect to layers: a backup records every layer's writes, not merely the effective values. Restore it and the layered structure comes back intact — the base values, the role layers, the policy overlays, all of them, resolving the way they did before. A backup is not a flattened picture of "what the values currently are"; it is the whole stack.
The stream is also self-verifying: it carries an integrity check, so a truncated or corrupted backup is caught when you try to restore it, rather than restored as garbage.
Restore is replace, not merge #
This is the rule to internalise. Restoring into a key replaces that key's contents and entire subtree: the existing descendants are removed and the backup's contents take their place. It is not a merge and it does not add to what is there — whatever was under the target key before is gone, supplanted by the stream.
The target key itself survives as the anchor — it keeps its identity and its place in the tree — and everything beneath it is rebuilt from the backup. The whole operation is atomic: it either completes and swaps the new subtree in, or fails and leaves the original untouched. There is no half-restored state to clean up.
Both bypass per-key permissions — by design #
Backup and restore do not consult the security descriptor on each key the way an ordinary open does. They are gated by privilege instead — a backup privilege to read the whole subtree, a restore privilege to write it. This is the same model as file backup: a backup operator reads files they were never granted access to, because reading-for-backup is the privilege, not per-file permission.
(Both operations are audited every time they run, regardless of a key's own audit settings — see the auditing topic.)
What it is for #
- First-boot seeding. A fresh machine's registry is empty; its initial configuration is delivered by restoring a seed. Same mechanism, described in bootstrap.
- Disaster recovery. Snapshot a subtree — or a whole hive — and restore it after a failure or a bad change.
- Migration. Move configuration between machines by backing up on one and restoring on another; the stream is portable.
Where to go next #
For where restore comes from at first boot, read How the registry boots and configures itself.
For who actually performs these operations — the kernel coordinating the store — read LCS and sources.
For the privilege model they lean on, read Access control on keys.
LCS and sources
Peios / Using Peios / Administration
Every page until now has treated the registry as a single thing, and that was the right altitude to learn the model. This page pulls it apart, because at the implementation level "the registry" is two cooperating components — and the division between them is clean, deliberate, and worth knowing once the concepts are solid.
The split, in one sentence #
The registry is a kernel subsystem (LCS) that is the sole authority for the data model, access control, layer resolution, and change notification — plus one or more userspace sources that do nothing but persist and return data; the base source, registryd, is loregd by default and backs the Machine and Users hives.
Who does what #
The dividing line is sharp, and it is the principle the whole design rests on: the kernel decides meaning; sources only store.
| The kernel subsystem (LCS) owns | A source owns |
|---|---|
| The data model — keys, values, types | Persisting entries to disk and returning them |
| Path resolution and routing | Nothing about who is asking |
| Access control — running AccessCheck | No security decisions at all |
| Layer resolution — choosing the effective value | No idea which write is effective |
| Watch dispatch and transaction coordination | Executing storage operations it is told to |
A source never sees a caller's identity, never evaluates a security descriptor, and never resolves a contest between layers. It stores writes tagged with layer names and hands all of them back when asked; the kernel does the deciding. That is why earlier pages could say "the registry checks", "the registry resolves" — it is always the kernel doing it, never the store.
flowchart LR
P["Any process"] -->|registry system calls| L["LCS (kernel): access control, layer resolution, watches"]
L -->|private protocol| S["Source — e.g. loregd (userspace): storage only"]
S --> DB["On-disk database"]
Userspace never talks to a source directly. Every registry operation goes through the kernel; the source talks only to the kernel, over a private protocol on a dedicated device. This is what lets the registry carry the same identity model, access control, and auditing as everything else — the kernel is unavoidably in the path.
Why split it this way #
Storage is a separable concern. Putting it in userspace means the backing store can be replaced, or different stores can back different hives, without changing the kernel — and the store can be developed, tested, and hardened as an ordinary (if privileged) service. The kernel keeps the parts that must be trusted and uniform — the data model and the security model — and delegates the part that is "just a database".
Hives are how the work is parcelled out: each hive is backed by exactly one source, and a source may back several hives. In practice the base source registers Machine and Users; other sources could register additional hives.
The base source: registryd #
The standard hives have to exist before anything can read configuration, so one source is always started at boot. registryd is that base source — the registry store peinit starts in early boot, and the first thing to register hives with LCS so the rest of startup has configuration to read. Its interface is deliberately minimal: one HiveName=path argument per hive, naming the hive and the on-disk database that backs it.
registryd Machine=/var/state/registry/machine.regdb Users=/var/state/registry/users.regdb
That is the whole of its configuration — registryd is the configuration store, so it takes what it needs from its arguments rather than from a config file of its own.
registryd is a role, not a fixed program. loregd — the Local Registry Daemon, which backs each hive with a SQLite database — is the default implementation, and the one running on a stock system. But the name is a swappable slot: another source can ship a registryd claim, and installing it puts that source in loregd's place with no change to anything that depends on the registry. Whatever holds the role starts the same way and answers to the same name. (Writing an alternative source is a developer task — the Peios SDK covers the protocol one speaks to the kernel.)
The trust boundary #
It is worth being blunt about the security boundary, the same way the rest of these docs are. A source is part of the trusted computing base. The kernel runs AccessCheck, but it runs it against the security descriptor the source hands back — so a compromised source can return a permissive SD for a key and cause access that should have been denied, or fabricate the precedence of a layer and tilt every contest in the system. The kernel validates that a source's responses are structurally well-formed and rejects malformed data, but it cannot detect a well-formed lie.
This is not a gap so much as a fact about where the boundary is: trusting the store to tell the truth about what it stores is inherent in having a userspace store at all. The mitigations are operational — a source runs with tightly scoped privileges, is protected by the security descriptors on its own service definition, and is managed as a critical service (with process-integrity protection where available). The honest summary is: the store is small, privileged, and trusted, and protecting it is part of protecting the system.
Two operations the kernel coordinates #
Two registry capabilities are the kernel orchestrating a source rather than features of the data model: atomic transactions, and backup and restore. In both, the source does the storage work — committing a batch atomically, or reading out and replacing a subtree — while the kernel coordinates it and enforces the rules around it. Each has its own page; the point here is only that the same division of labour holds: the kernel decides, the source stores.
When a source goes away #
Because the store is a separate process, it can crash or restart. When a source goes down its hives become unavailable: open key handles stay valid (they hold identity and a granted mask, neither of which needs the store), but operations that need to reach the store return an error until it is back. Watches stay armed across the outage, and when the source re-registers, watchers receive an overflow so they re-read and resynchronise. The registry treats a store restart as a disruption to recover from, not a reason to lose state.
Where to go next #
You have now seen the whole model — data, meaning, layers, security, change notification, and the parts underneath.
For the tool you will reach for most when configuring a system — looking up what any key or value means — read The registry manual (regman).
Three advanced topics remain:
For grouping several writes into one all-or-nothing change — how a role installs without ever being half-applied — read Transactions.
For complete per-caller isolation — hives and layers visible only to one sandboxed process — read Private hives and layers.
For keys that point at other keys — the one place the registry follows a value — read Registry links.
The registry manual (regman)
Peios / Using Peios / Administration
Configuration, not storage established that the registry holds values but not their meaning: it keeps a type tag and some bytes, and never knows that BufferCapacity must be a power of two or what it is for. That knowledge has to live somewhere a person can look it up. It lives in regman, the registry's manual.
regman is the man of the registry. Give it a path and it tells you what a key or value actually is. It is the everyday tool for configuring a Peios system — before you touch a knob, regman is how you find out what it does and what changing it will cost.
regman, in one sentence #
regman <path> [value] documents what a registry key or value means — its type, default, valid values, when a change takes effect, and a prose description — drawn from shipped documentation, never from the live registry.
That last clause is the one to hold onto; there is a section on it below.
Looking up a value #
Give regman a key path and a value name and it prints a knob-card — an identity line, an aligned block of facts, and a description:
$ regman Machine\System\KMES BufferCapacity
Machine\System\KMES BufferCapacity documented by kmes
Type REG_QWORD
Default 4194304 (4 MB)
Valid 65536–268435456 bytes (64 KB–256 MB), power of two
Applies live — ring-buffer swap
Per-CPU ring buffer capacity, in bytes. Must be a power of two; values
that are not are treated as invalid and ignored.
Every registry value is a knob, and every knob has the same few facts worth knowing, so the card is uniform rather than free-form:
| Field | Tells you |
|---|---|
| Type | The value's registry type (REG_QWORD, REG_SZ, …). |
| Default | The value used when nothing is set. |
| Valid | The range, set, or constraint a sensible value must satisfy. |
| Applies | When a change takes effect — live, on restart, or on reboot. |
The Applies field is the one operators reach for most: it is the difference between "edit it and you're done" and "edit it and schedule a reboot". Only the fields that make sense for a given item are shown, and a knob that is being retired carries a prominent deprecation notice at the top of its card.
Looking up a key #
Give regman just a key — no value — and it does double duty as an index: the key's own description, then a list of every value documented under it, one summary line each.
$ regman Machine\System\KMES
Machine\System\KMES documented by kmes
The KMES event subsystem reads its tuning parameters from the values
under this key...
Values
BufferCapacity Per-CPU ring buffer capacity in bytes.
MaxEventSize Max total size of a userspace-emitted event.
MaxNestingDepth Max nesting depth for userspace event payloads.
MaxEmitRatePerProcess Max events per second a single process may emit.
So you can start at a subtree, see what is configurable there, and drill into any single value.
Searching, when you do not know the path #
If you don't know where a setting lives, regman -k searches names and summaries — the registry's apropos:
$ regman -k buffer
Machine\System\KMES BufferCapacity Per-CPU ring buffer capacity in bytes.
regman documents intent, not current state #
This is the boundary that matters most. regman tells you what a setting should be — what it means and which values are legal — not what it is currently set to on this machine. It reads shipped documentation, never the live registry; it does not talk to LCS at all. Ask regman about BufferCapacity and you learn it must be a power of two and defaults to 4 MB; you do not learn that this particular box has it set to 8 MB right now. Reading the current value is a separate, live query against the registry — that is reg's job. regman tells you a knob should be a power of two; reg get tells you what it is set to, and reg set changes it. Reach for regman to decide what to write, and reg to write it.
Put regman next to the other two things from Configuration, not storage and a clean division of labour appears:
| To learn… | Look at… |
|---|---|
| What a setting means, and what is valid | regman — the manual |
| What the value is set to | reg — a live query against the store |
| What the subsystem is actually running on | the event log |
regman is the one you consult first, and the only one that works before you have changed anything — because documentation ships with the software, not with the machine's state. It is the natural complement to reject-or-keep: regman tells you the valid range up front, so you set a good value the first time instead of writing one the owning subsystem will quietly refuse.
Where the documentation comes from #
regman has no built-in database of every setting. Each package ships its own documentation as files dropped into a well-known directory (/usr/share/regman/), one fragment per package documenting that package's whole configuration surface. Install a package and its registry documentation appears; remove the package and it goes away. The package that owns a set of keys is the package that documents them — the only arrangement that stays correct as the system changes.
A consequence worth knowing: regman can only describe settings that some installed package has documented. An undocumented key is invisible to it — regman is exactly as complete as the packages on the machine make it. If two packages happen to document the same item, regman shows both and flags the overlap rather than silently picking a winner.
(For the people who write that documentation, regman fmt and regman lint prepare and check fragments, and regman index keeps lookups fast on large corpora — the lookup is always correct without an index, which is purely an accelerator. These are packaging concerns rather than everyday operator ones.)
Where to go next #
For the idea regman exists to serve — why the registry holds values without holding their meaning, and what reject-or-keep means — read Configuration, not storage.
For the other half of the picture — reading what a value is actually set to, which is a live query against the store rather than a documentation lookup — read LCS and sources.
reg
Peios / Using Peios / Administration
reg is the command-line interface to the live registry — the running LCS store, reached through the registry system calls. Where regman reads shipped documentation and tells you what a key means, reg talks to the kernel and reads or writes what a key is. It is the everyday tool for scripting configuration: querying effective values, writing to layers, masking and hiding, managing security descriptors, watching for change, and taking backups.
reg <command> [options] <key> [value] [data]
reg is the read/write half of the registry toolset and regman is the lookup half. The division is exact:
| To… | Use… |
|---|---|
| Read or change what a value is set to, on this machine, right now | reg |
| Look up what a value means — its type, default, valid range, when it applies | regman |
Consult regman first to learn the legal range for a knob, then use reg set to write a value inside it. reg never checks a value's meaning and regman never touches the live store; they are complementary.
How reg treats access and privilege #
Every reg operation goes through the kernel's access check against the single key it opens — the same access-control path as any other protected object, with no traversal check on the parent keys. reg performs no identity or membership checks of its own: it does not refuse a privileged operation up front. It attempts the operation and reports faithfully whatever the kernel returns. An operation that needs a privilege you lack (creating a link, a positive-precedence layer, a backup or restore, reading a SACL) simply fails with access denied (exit 3) rather than being blocked by the tool. A single reg command may legitimately span privilege tiers.
Addressing model #
Almost every subcommand shares one addressing scheme: a key path positional, and an optional value name positional. Understanding the split is most of understanding reg.
Key paths #
The key is a positional path argument. Both / and \ are accepted as separators — neither character is legal inside an LCS key component, so there is no ambiguity, and you may use whichever your shell quotes most comfortably:
reg get Machine/System/KMES
reg get 'Machine\System\KMES' # identical
A leading separator is optional and ignored (/Machine/X is the same as Machine/X). Paths are compared case-insensitively. The first component is the hive:
| Path | Meaning |
|---|---|
Machine\… | The machine hive — system-wide configuration. |
Users\<SID>\… | A specific principal's hive. |
CurrentUser\… | A kernel alias, rewritten to the caller's own Users\<SID>\ at the syscall boundary. |
On output, reg displays paths with a backslash by default. --sep=/ (or REG_SEP=/) switches display to forward slash for that invocation; this affects display only, never how a path is parsed.
The value-name positional #
The value name is a separate positional argument — it is never folded into the key path. This is deliberate: an LCS value name may itself contain / or \ (which a key component may not), so keeping them apart removes all ambiguity.
reg get Machine/System/KMES BufferCapacity
# └──── key path ─────┘ └── value ──┘
The presence or absence of the value argument selects what the command targets:
- No value argument ⇒ the command targets the key itself — its metadata, its values as a set, its security descriptor, its children.
- A value argument ⇒ the command targets that one named value.
- The default value (the empty-name value) is addressed by the literal token
@in the value-name position, mirroring.regconvention:reg get Machine\App @.
This split applies uniformly to get, set, del, mask, and unmask.
Value literals and types #
On set (and in a batch), the value's data is a single token whose registry type is either forced by a type: prefix or inferred from its shape. The registry value types and their literal syntax:
| Prefix | Registry type | Data syntax |
|---|---|---|
sz: | REG_SZ | UTF-8 string (rest of token, verbatim). |
expand: | REG_EXPAND_SZ | UTF-8 string, %VAR% left unexpanded on disk. |
dword: | REG_DWORD | 42 or 0x2A; must fit u32. |
dword-be: | REG_DWORD_BIG_ENDIAN | 42 or 0x2A; must fit u32. |
qword: | REG_QWORD | 42 or 0x2A; must fit u64. |
multi: | REG_MULTI_SZ | Comma-separated; \, escapes a literal comma. |
hex: / bin: | REG_BINARY | Hex bytes; :, -, and space separators are ignored. |
link: | REG_LINK | An absolute key path (a symlink target). |
none: | REG_NONE | No data (token must be empty after the prefix). |
When the substring before the first : is not a recognised keyword (for example http://host), the token is not treated as typed and inference applies:
| Token shape | Inferred type |
|---|---|
all decimal digits, fits u32 | REG_DWORD |
all decimal digits, fits u64 but not u32 | REG_QWORD |
0x… hex, ≤ 8 significant hex digits | REG_DWORD |
0x… hex, ≤ 16 significant hex digits | REG_QWORD |
| anything else (including empty) | REG_SZ |
Inference is intentionally broad, so any all-digit token becomes a number — a PIN, a zip code, or 007 becomes a REG_DWORD and loses its textual form. To force a string, prefix it with sz: (sz:007 stores the string 007; sz:dword:42 stores the literal string dword:42). Because the coercion is a known trap, reg set always echoes the resolved type on success, so a surprising conversion is never silent even under --quiet.
Global options #
Every subcommand accepts the following. Each behavioural toggle also has an environment-variable equivalent, so it can be set per-invocation (the flag) or once per shell or script (the variable). The flag wins over the variable, which wins over the built-in default.
| Option | Env var | Effect |
|---|---|---|
--json | REG_JSON=1 | Emit structured JSON instead of human text. watch emits JSON-lines. |
-v, --verbose | REG_VERBOSE=1 | More detailed output. |
-q, --quiet | — | Suppress non-essential output. (A surprising type coercion is still reported.) |
--sep=CHAR | REG_SEP | Path display separator: \ (default) or /. |
--help | — | Print help for the command and exit 0. |
--version | — | Print the version and exit 0. |
Mutating subcommands additionally accept:
| Option | Env var | Effect |
|---|---|---|
--layer NAME | REG_LAYER | Target layer for the write (default: the base layer). |
-y, --yes | REG_ASSUME_YES=1 | Skip the confirmation prompt on a destructive command. |
Destructive commands (del -r, restore, layer del) prompt for confirmation when standard input is a terminal, and auto-proceed when it is not — so interactive use is guarded while scripts are never blocked. Set -y/--yes or REG_ASSUME_YES=1 to skip the prompt explicitly.
Reading #
reg get <key> [value] #
Read the effective (resolved) value. With a value, prints that value's data; with no value, lists the key's effective values (the default @ value first, then named values sorted case-insensitively) — a shorthand for ls --values-only.
| Option | Effect |
|---|---|
-L, --layers | Annotate the value with the layer it resolved from and its sequence number. |
--raw | Write the value's raw bytes to standard output verbatim — for piping REG_BINARY data. |
--no-follow | Operate on a symlink key itself rather than following it to its target. |
The single-value default form prints data bare (no quotes; one element per line for REG_MULTI_SZ) so it pipes cleanly. -L shows the winning layer's provenance:
$ reg get Machine\System\KMES BufferCapacity
4194304
$ reg get Machine\App Theme -L
Theme = REG_SZ "dark" (layer: policy, seq 7)
Only the winning value is shown; the full shadowed stack beneath it is not yet exposed by any client ABI (the -L flag will render the whole stack unchanged once that primitive lands). See Layers for what "effective" resolves against.
reg ls <key> #
One-level listing of a key's immediate subkeys and values.
| Option | Effect |
|---|---|
-l, --long | Long form: for subkeys, child and value counts; for values, type and byte size. |
--keys-only | List subkeys only. |
--values-only | List values only. |
$ reg ls Machine\System\KMES -l
BufferCapacity = REG_QWORD 4194304 (8 bytes)
MaxEventSize = REG_DWORD 65536 (4 bytes)
reg tree <key> #
Recursively list the subkey tree rooted at key.
| Option | Effect |
|---|---|
--depth N | Limit recursion to N levels. |
--values | Include each node's values, not just its keys. |
$ reg tree Machine\System --depth 2
reg info <key> #
Print a key's metadata: leaf name, subkey and value counts, last-write time, hive generation, security-descriptor size, and the volatile and symlink flags.
| Option | Effect |
|---|---|
--no-follow | Inspect a symlink key itself rather than its target. |
$ reg info Machine\System\KMES
path Machine\System\KMES
name KMES
subkeys 0
values 4
last_write_ns 1717243800000000000
hive_generation 42
sd_size 164
volatile false
symlink false
Writing #
reg set <key> <value> <data> #
Create or update a value. The value name (or @) and the data token are both required. Writes are tagged with --layer (default: base). See value literals for the data syntax.
| Option | Effect |
|---|---|
--layer NAME | Write into layer NAME instead of the base layer. |
-p, --parents | Create any missing ancestor keys. |
--expected-seq N | Compare-and-swap guard: apply only if the value's current sequence is N; a mismatch exits 6 without writing. |
$ reg set Machine\App Build 4096
set Machine\App Build = REG_DWORD 4096 (layer: base)
$ reg set Machine\App Servers multi:alpha,beta --layer policy
--expected-seq supports lock-free read-modify-write: read the value with -L to learn its sequence, then write back with --expected-seq set to that number; if another writer changed it in between, your write fails cleanly instead of clobbering theirs.
reg new <key> #
Create a key with no values. Reports whether the key was created or already existed.
| Option | Effect |
|---|---|
--layer NAME | Create the key in layer NAME. |
-p, --parents | Create any missing ancestor keys. |
--volatile | Create a volatile (RAM-only) key that does not survive a reboot. |
$ reg new Machine\App\Cache --volatile
created Machine\App\Cache (layer: base)
reg del <key> [value] #
Delete a value, or a key. (Alias: delete.)
With a value, deletes this layer's entry for that value only — lower-layer entries resurface, because a per-layer delete is not a tombstone (use mask for that). With no value, deletes the key, which must be empty unless -r is given.
| Option | Effect |
|---|---|
--layer NAME | Delete from layer NAME. |
-r, --recursive | Delete the key and all its descendants (walks and removes children). |
-y, --yes | Skip the confirmation prompt (recursive deletes prompt on a terminal). |
$ reg del Machine\App Legacy
deleted value Legacy from Machine\App
$ reg del Machine\App\Temp -r
Recursively delete key Machine\App\Temp and all its contents? [y/N] y
deleted Machine\App\Temp (3 keys)
See Deleting keys and values for how a per-layer delete differs from a tombstone.
Masking and hiding #
These commands expose LCS's tombstone and hide primitives, which mask lower-precedence state rather than removing a layer's own entry — the distinction that makes layers revertible. The layer is chosen with --layer (default: base).
reg mask <key> [value] / reg unmask <key> [value] #
mask sets a tombstone: a per-value marker in the target layer that hides that value from all layers below it. unmask clears it.
| Option | Effect |
|---|---|
--layer NAME | The layer that carries the tombstone. |
--all | Blanket tombstone: mask all lower-layer values on the key (no value argument). |
A value is required unless --all is given.
$ reg mask Machine\App ApiKey --layer policy
set tombstone on Machine\App ApiKey (layer: policy)
$ reg mask Machine\App --all --layer policy
set blanket tombstone on Machine\App (layer: policy)
reg hide <key> / reg unhide <key> #
hide installs a HIDDEN path entry in the target layer, masking the key's existence in that layer and below. unhide removes that layer's path entry, letting the key reappear.
| Option | Effect |
|---|---|
--layer NAME | The layer that hides (or unhides) the key. |
$ reg hide Machine\App\Debug --layer policy
hid Machine\App\Debug (layer: policy)
Layers #
reg layer ls #
List layers with name, precedence, enabled state, and (informational) owner SID, ordered by descending precedence.
| Option | Effect |
|---|---|
-l, --long | Long form. |
$ reg layer ls
policy prec=100 enabled owner=S-1-5-32-544
base prec=0 enabled
reg layer new <name> #
Create a layer by writing its metadata key under Machine\System\Registry\Layers\.
| Option | Effect |
|---|---|
--precedence N | Precedence (higher wins). A precedence above 0 requires SeTcbPrivilege; the tool attempts it and reports any denial. |
--owner SID | Record an informational owner SID. |
--disabled | Create the layer disabled. |
$ reg layer new policy --precedence 100 --owner S-1-5-32-544
created layer policy (precedence 100, enabled)
reg layer set <name> #
Modify an existing layer's metadata.
| Option | Effect |
|---|---|
--precedence N | Change the precedence. |
--enable / --disable | Enable or disable the layer. |
--owner SID | Change the informational owner SID. |
reg layer del <name> #
Delete a layer — removes its metadata key; LCS tears down the layer's entries. Prompts for confirmation on a terminal.
$ reg layer del policy
Delete layer policy and all its entries? [y/N] y
deleted layer policy
Managing per-process private layer views is out of scope for reg; see private hives and layers.
Security descriptors #
reg sd <key> #
Show or set a key's security descriptor as SDDL, using the same codec as the sd tool, so its output is consistent. With no scope flags, the default is owner + group + DACL (a SACL requires the privileged ACCESS_SYSTEM_SECURITY right).
| Option | Effect |
|---|---|
--set SDDL | Apply the given SDDL. Without it, sd prints the current descriptor. |
--owner | Scope to the owner. |
--group | Scope to the group. |
--dacl | Scope to the DACL. |
--sacl | Scope to the SACL (needs ACCESS_SYSTEM_SECURITY). |
$ reg sd Machine\App
O:BAG:BAD:(A;;KA;;;BA)(A;;KR;;;WD)
$ reg sd Machine\App --set 'O:BAG:BAD:(A;;KA;;;BA)' --owner --dacl
set security descriptor on Machine\App
A security-descriptor change takes effect on future opens only (existing handles keep the access mask they were granted). Security changes are not layered and are not undone by layer removal — they mutate the key object directly. See Access control on keys.
Symlinks #
reg link <key> <target> #
Create a symlink key pointing at the absolute target key path. This creates a key with the immutable symlink flag and a default REG_LINK value holding the target. Requires KEY_CREATE_LINK and SeTcbPrivilege/Administrator; the tool attempts it and reports any denial.
| Option | Effect |
|---|---|
--layer NAME | Create the link key in layer NAME. |
$ reg link Machine\App\CurrentConfig Machine\App\Config\v3
linked Machine\App\CurrentConfig -> Machine\App\Config\v3 (layer: base)
get and info follow symlinks to their target by default; pass --no-follow to inspect the link key itself. See Advanced: registry links.
Watching #
reg watch <key> #
Arm a change watch and stream one event per change until interrupted (or until --count events). Each event faithfully means "something under the filter changed — re-read"; reg does not decode the change records' contents. With --json, emits one JSON object per line.
| Option | Effect |
|---|---|
--subtree | Watch descendant keys too, not just this key. |
--filter LIST | Comma-separated subset of value, subkey, sd (default: all). |
--count N | Exit after N events. |
$ reg watch Machine\System\KMES --subtree --filter value
changed: Machine\System\KMES
changed: Machine\System\KMES
See Watching for changes for why a service watches instead of polling.
Batch, export, backup, and restore #
Two paths move a subtree around: export/apply are the portable, reviewable path (a diffable text or JSON document); backup/restore are the exact, privileged path (an opaque kernel snapshot).
reg apply <file> #
Apply a batch of operations to one hive in a single transaction — all-or-nothing. All operations must target one hive (a cross-hive batch fails with exit 4). - reads standard input.
| Option | Effect |
|---|---|
--dir DIR | Apply every batch file in DIR (sorted), each as its own transaction. A missing or empty directory applies nothing and succeeds. |
--once-delete | Delete each batch file after it applies successfully (a drain). |
-y, --yes | Skip confirmation. |
The batch format is JSON (canonical and exact) or a line-oriented text format; apply auto-detects (a leading { or [ means JSON). Text-format input is not yet implemented — supply JSON, or generate one with reg export --json. Text export works for review.
$ reg export --json Machine\App - | reg apply -
applied 4 keys
reg export <key> [file] #
Dump a subtree to the batch format. Omit file (or pass -) to write to standard output. Human-readable text by default; --json emits the canonical exact form.
| Option | Effect |
|---|---|
--layer NAME | Export one layer's view (default: the effective state). |
$ reg export Machine\App app-config.reg
reg backup <key> <file> #
Write an opaque, exact, binary kernel snapshot of a key and its subtree to file. Requires SeBackupPrivilege.
$ reg backup Machine\System\KMES kmes.snap
backed up Machine\System\KMES -> kmes.snap
reg restore <key> <file> #
Replace a key and its entire subtree from a snapshot, in one transaction. Requires SeRestorePrivilege. Prompts for confirmation on a terminal.
$ reg restore Machine\System\KMES kmes.snap
Replace key Machine\System\KMES and its entire subtree from kmes.snap? [y/N] y
restored Machine\System\KMES from kmes.snap
See Backup and restore for when to reach for each path.
Output formats #
Default output is terse, human-readable, and grep-friendly. --json switches every command to structured output — a single self-contained JSON document, except watch, which emits JSON-lines (one object per event). In any value listing, the default (@) value is emitted first, then named values sorted case-insensitively.
Type formatting on read:
| Registry type | Human form | JSON form |
|---|---|---|
REG_SZ / REG_EXPAND_SZ | the string | {"type":"sz","data":"…"} |
REG_DWORD / REG_QWORD | decimal | {"type":"dword","data":42} |
REG_MULTI_SZ | one element per line | {"type":"multi","data":["a","b"]} |
REG_BINARY | hex | {"type":"binary","data":"deadbeef"} |
REG_LINK | the target path | {"type":"link","data":"…"} |
Exit status #
| Code | Meaning | Typical cause |
|---|---|---|
0 | Success. | — |
1 | Usage error. | Bad arguments; a required option missing. |
2 | Key or value not found. | ENOENT. |
3 | Access denied. | EACCES, EPERM — the kernel refused the operation. |
4 | Invalid specification. | Bad path, type, or literal; a cross-hive batch; a name too long (EINVAL, EXDEV, ENAMETOOLONG). |
5 | Syscall or source failure. | EIO, ETIMEDOUT, ENOSPC, ENOMEM. |
6 | Compare-and-swap conflict. | EAGAIN — an --expected-seq guard did not match; the value changed under you. |
A denial (3) reports the operation, the target, and, where relevant, the access that was required — in the style of the sd and token tools.
See also #
regman— the registry manual: what a key or value means, as opposed to what it is set to. Consult it before youreg set.- Keys, values, and types — the data model
regaddresses. - Layers — what "effective" resolves against, and what
--layer,mask, andhideoperate on. - Access control on keys — the check every
regoperation goes through.