> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arupa.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# KV storage

> Use the Kernel's shared in-memory key-value store from a plugin.

The Kernel provides a shared key-value store to all running plugins. A plugin
can use it for small pieces of state that must be read or updated through the
Kernel, such as cached values, plugin state, or data shared with another
plugin.

KV values are raw bytes. The Kernel does not assign a data format to them, so
you can encode a value as JSON, text, a binary structure, or any other format
your plugin understands.

## Storage model

The store has a two-level layout:

```text theme={null}
namespace → key → byte value
```

For example:

```text theme={null}
namespace: preferences
key:       theme
value:     dark
```

The KV store belongs to the Kernel, not to an individual plugin instance. All
plugins connected to the same Kernel use the same store. A plugin namespace is
an organizational convention; it is not a permission boundary. In the current
implementation, a plugin can read and write another plugin's namespace unless
that namespace is read-only.

Use a namespace owned by your plugin by convention, usually derived from the
plugin name. If multiple plugins intentionally share a namespace, document the
key names and value format they agree to use.

## Operations

The operations are defined by the Protobuf host contract. See
[Protobuf](../proto) for the shared transport definition.

### Read a value

The read request contains:

| Field       | Type     | Meaning                       |
| ----------- | -------- | ----------------------------- |
| `namespace` | `string` | Namespace containing the key. |
| `key`       | `string` | Key to read.                  |

The response contains a `found` boolean and a `value` byte sequence. A missing
key is not an error: `found` is `false` and no value is returned.

Reading a value does not create its namespace or key.

### Write a value

The write request contains the same `namespace` and `key` fields plus:

| Field   | Type    | Meaning             |
| ------- | ------- | ------------------- |
| `value` | `bytes` | Raw value to store. |

Writing an existing key replaces its value. The operation returns an error
string when the write is rejected, for example when the namespace is
read-only.

### Delete a value

The delete request contains `namespace` and `key`. Deleting an existing key
removes its value. Deleting a key that does not exist succeeds without changing
the store.

The operation returns an error string when deletion is rejected, including an
attempt to delete from a read-only namespace.

### List keys

The list request contains a `namespace` field:

* When `namespace` is non-empty, the response contains the keys currently
  present in that namespace.
* When `namespace` is empty, the response contains the names of all namespaces
  currently present in the store.

The returned names are sorted by the Kernel. Listing does not return values.

## Lifecycle and persistence

The Kernel creates the KV store when it creates the plugin manager. The store is
in memory:

* stopping or restarting a plugin does not clear its KV values;
* loading a new version of the same plugin does not clear its KV values; and
* restarting the Kernel creates a new empty store and clears all values.

KV is therefore not a durable database. Persist data elsewhere when it must
survive a Kernel restart, and treat KV as runtime state or a shared cache.

## Concurrency and value ownership

The Kernel synchronizes individual KV operations. Reads, writes, deletes, and
lists are safe when multiple plugin calls happen concurrently.

There is no transaction or compare-and-swap operation. A sequence such as
“read, modify, write” is not atomic with respect to another plugin. If several
plugins update the same key, coordinate ownership or design the value so that
lost updates do not corrupt the application state.

The Kernel copies byte values when storing and reading them. Mutating a byte
buffer after a write does not change the stored value, and mutating a returned
buffer does not change the value in the store.

## The `sys` namespace

`sys` is a Kernel-managed, read-only namespace. Plugins can read and list it,
but writes and deletes through the plugin host boundary return an error.

The Kernel uses this namespace for host-managed state, including plugin
registry information. Do not write to `sys`, and do not depend on undocumented
system keys unless the Kernel documentation explicitly defines them.

## Backend behavior

WASM and gRPC plugins use the same KV contract:

* a WASM plugin reaches the store through the generated host bindings; and
* a gRPC plugin reaches the store through the Kernel's host callback channel.

The storage semantics are the same for both backends. The backend changes how
the request crosses the plugin boundary, not how the Kernel stores or returns
the value.

## Recommended usage

Use a predictable namespace and key scheme:

```text theme={null}
namespace: my-plugin
keys:
  config/theme
  cache/user/<id>
  state/last-sync
```

Keep values small enough for the calling path and define their encoding before
other components consume them. Check the `found` result before decoding a
value, handle write and delete errors, and avoid treating a successful write
as durable persistence.
