# reg

_Peios / Using Peios / Administration_

> The reg command reads and writes the live registry — values, keys, layers, links, security descriptors, watches, and atomic batches.

`reg` is the command-line interface to the **live** registry — the running [LCS](/peios/using-peios/registry-administration/lcs-and-sources.md) store, reached through the registry system calls. Where [`regman`](/peios/using-peios/registry-administration/regman.md) 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`](/peios/using-peios/registry-administration/regman.md) 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`](/peios/using-peios/registry-administration/regman.md) |

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](/peios/using-peios/registry-security/access-control.md) 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 `.reg` convention: `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](/peios/using-peios/registry-layers/layers.md) 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](#value-literals-and-types) 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](/peios/using-peios/registry-layers/deleting-keys-and-values.md) 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](/peios/using-peios/registry-layers/layers.md) 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](/peios/using-peios/registry-advanced/private-hives-and-layers.md).

---

## Security descriptors

### `reg sd <key>`

Show or set a key's [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md) as SDDL, using the same codec as the [`sd`](/peios/security-fundamentals/security-descriptors/overview.md) 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](/peios/using-peios/registry-security/access-control.md).

---

## 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](/peios/using-peios/registry-advanced/registry-links.md).

---

## 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](/peios/using-peios/registry-concepts/watches.md) 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](/peios/using-peios/registry-advanced/transactions.md) — 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](/peios/using-peios/registry-administration/backup-and-restore.md) 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`](/peios/using-peios/registry-administration/regman.md) — the registry *manual*: what a key or value *means*, as opposed to what it is set to. Consult it before you `reg set`.
- [Keys, values, and types](/peios/using-peios/registry-concepts/keys-values-and-types.md) — the data model `reg` addresses.
- [Layers](/peios/using-peios/registry-layers/layers.md) — what "effective" resolves against, and what `--layer`, `mask`, and `hide` operate on.
- [Access control on keys](/peios/using-peios/registry-security/access-control.md) — the check every `reg` operation goes through.

Related content:

- [The registry](/peios/using-peios/registry-concepts/overview.md)
- [The registry manual (regman)](/peios/using-peios/registry-administration/regman.md)
- [Keys, values, and types](/peios/using-peios/registry-concepts/keys-values-and-types.md)
- [Layers](/peios/using-peios/registry-layers/layers.md)
- [Access control on keys](/peios/using-peios/registry-security/access-control.md)
- [Watching for changes](/peios/using-peios/registry-concepts/watches.md)
- [Backup and restore](/peios/using-peios/registry-administration/backup-and-restore.md)
- [Registry links](/peios/using-peios/registry-advanced/registry-links.md)
- [Private hives and layers](/peios/using-peios/registry-advanced/private-hives-and-layers.md)
- [Transactions](/peios/using-peios/registry-advanced/transactions.md)
