diff --git a/stdlib-candidate/std-rfc/kv/mod.nu b/stdlib-candidate/std-rfc/kv/mod.nu
new file mode 100644
index 00000000..084d6169
--- /dev/null
+++ b/stdlib-candidate/std-rfc/kv/mod.nu
@@ -0,0 +1,210 @@
+# kv module
+#
+# use std-rfc/kv *
+#
+# Easily store and retrieve key-value pairs
+# in a pipeline.
+#
+# A common request is to be able to assign a
+# pipeline result to a variable. While it's
+# not currently possible to use a "let" statement
+# within a pipeline, this module provides an
+# alternative. Think of each key as a variable
+# that can be set and retrieved.
+
+# Stores the pipeline value for later use
+#
+# If the key already exists, it is updated
+# to the new value provided.
+#
+# Usage:
+# | kv set
+#
+# Example:
+# ls ~ | kv set "home snapshot"
+# kv set foo 5
+export def "kv set" [
+ key: string
+ value_or_closure?: any
+ --return (-r): string # Whether and what to return to the pipeline output
+ --universal (-u)
+] {
+ # Pipeline input is preferred, but prioritize
+ # parameter if present. This allows $in to be
+ # used in the parameter if needed.
+ let input = $in
+
+ # If passed a closure, execute it
+ let arg_type = ($value_or_closure | describe)
+ let value = match $arg_type {
+ closure => { $input | do $value_or_closure }
+ _ => ($value_or_closure | default $input)
+ }
+
+ # Store values as nuons for type-integrity
+ let kv_pair = {
+ session: '' # Placeholder
+ key: $key
+ value: ($value | to nuon)
+ }
+
+ let db_open = (db_setup --universal=$universal)
+ try {
+ # Delete the existing key if it does exist
+ do $db_open | query db $"DELETE FROM std_kv_store WHERE key = '($key)'"
+ }
+
+ match $universal {
+ true => { $kv_pair | into sqlite (universal_db_path) -t std_kv_store }
+ false => { $kv_pair | stor insert -t std_kv_store }
+ }
+
+ # The value that should be returned from `kv set`
+ # By default, this is the input to `kv set`, even if
+ # overridden by a positional parameter.
+ # This can also be:
+ # input: (Default) The pipeline input to `kv set`, even if
+ # overridden by a positional parameter. `null` if no
+ # pipeline input was used.
+ # ---
+ # value: If a positional parameter was used for the value, then
+ # return it, otherwise return the input (whatever was set).
+ # If the positional was a closure, return the result of the
+ # closure on the pipeline input.
+ # ---
+ # all: The entire contents of the existing kv table are returned
+ match ($return | default 'input') {
+ 'all' => (kv list --universal=$universal)
+ 'a' => (kv list --universal=$universal)
+ 'value' => $value
+ 'v' => $value
+ 'input' => $input
+ 'in' => $input
+ 'i' => $input
+ _ => {
+ error make {
+ msg: "Invalid --return option"
+ label: {
+ text: "Must be 'all'/'a', 'value'/'v', or 'input'/'in'/'i'"
+ span: (metadata $return).span
+ }
+ }
+ }
+ }
+}
+
+# Retrieves a stored value by key
+#
+# Counterpart of "kv set". Returns null
+# if the key is not found.
+#
+# Usage:
+# kv get |
+export def "kv get" [
+ key: string # Key of the kv-pair to retrieve
+ --universal (-u)
+] {
+ let db_open = (db_setup --universal=$universal)
+ do $db_open
+ # Hack to turn a SQLiteDatabase into a table
+ | $in.std_kv_store | wrap temp | get temp
+ | where key == $key
+ # Should only be one occurence of each key in the stor
+ | get -i value.0
+ | match $in {
+ # Key not found
+ null => null
+ # Key found
+ _ => { from nuon }
+ }
+}
+
+# List the currently stored key-value pairs
+#
+# Returns results as the Nushell value rather
+# than the stored nuon.
+export def "kv list" [
+ --universal (-u)
+] {
+ let db_open = (db_setup --universal=$universal)
+
+ do $db_open | $in.std_kv_store? | each {|kv_pair|
+ {
+ key: $kv_pair.key
+ value: ($kv_pair.value | from nuon )
+ }
+ }
+}
+
+# Returns and removes a key-value pair
+export def --env "kv drop" [
+ key: string # Key of the kv-pair to drop
+ --universal (-u)
+] {
+ let db_open = (db_setup --universal=$universal)
+
+ let value = (kv get --universal=$universal $key)
+
+ try {
+ do $db_open
+ # Hack to turn a SQLiteDatabase into a table
+ | query db $"DELETE FROM std_kv_store WHERE key = '($key)'"
+ }
+
+ if $universal and ($env.NU_KV_UNIVERSALS? | default false) {
+ hide-env $key
+ }
+
+ $value
+}
+
+def universal_db_path [] {
+ $env.NU_UNIVERSAL_KV_PATH?
+ | default (
+ $nu.data-dir | path join "std_kv_variables.sqlite3"
+ )
+}
+
+def db_setup [
+ --universal
+] : nothing -> closure {
+ try {
+ match $universal {
+ true => {
+ # Ensure universal sqlite db and table exists
+ let uuid = (random uuid)
+ let dummy_record = {
+ session: ''
+ key: $uuid
+ value: ''
+ }
+ $dummy_record | into sqlite (universal_db_path) -t std_kv_store
+ open (universal_db_path) | query db $"DELETE FROM std_kv_store WHERE key = '($uuid)'"
+ }
+ false => {
+ # Create the stor table if it doesn't exist
+ stor create -t std_kv_store -c {session: str, key: str, value: str} | ignore
+ }
+ }
+ }
+
+ # Return the correct closure for opening on-disk vs. in-memory
+ match $universal {
+ true => {|| {|| open (universal_db_path)}}
+ false => {|| {|| stor open}}
+ }
+}
+
+# This hook can be added to $env.config.hooks.pre_execution to enable
+# "universal variables" similar to the Fish shell. Adding, changing, or
+# removing a universal variable will immediately update the corresponding
+# environment variable in all running Nushell sessions.
+export def "kv universal-variable-hook" [] {
+{||
+ kv list --universal
+ | transpose -dr
+ | load-env
+
+ $env.NU_KV_UNIVERSALS = true
+}
+}
diff --git a/stdlib-candidate/tests/kv.nu b/stdlib-candidate/tests/kv.nu
new file mode 100644
index 00000000..c5a459aa
--- /dev/null
+++ b/stdlib-candidate/tests/kv.nu
@@ -0,0 +1,240 @@
+use std/assert
+use ../std-rfc/kv *
+
+# Important to use random keys and clean-up
+# since the user running these tests may have
+# either an existing local stor or universal db.
+
+#[test]
+def simple-local-set [] {
+ let key = (random uuid)
+
+ kv set $key 42
+ let actual = (kv get $key)
+ let expected = 42
+ assert equal $actual $expected
+
+ kv drop $key | ignore
+}
+
+#[test]
+def local-pipeline_set_returns_value [] {
+ let key = (random uuid)
+ let actual = (42 | kv set $key)
+ let expected = 42
+ assert equal $actual $expected
+
+ let actual = (kv get $key)
+ let expected = 42
+ assert equal $actual $expected
+
+ kv drop $key | ignore
+}
+
+#[test]
+def local-multiple_assignment [] {
+ let key1 = (random uuid)
+ let key2 = (random uuid)
+ let key3 = (random uuid)
+
+ "test value" | kv set $key1 | kv set $key2 | kv set $key3
+ let expected = "test value"
+ assert equal (kv get $key1) $expected
+ assert equal (kv get $key2) $expected
+ assert equal (kv get $key3) $expected
+ assert equal (kv get $key3) (kv get $key1)
+
+ kv drop $key1
+ kv drop $key2
+ kv drop $key3
+}
+
+#[test]
+def local-transpose_to_record [] {
+ let key1 = (random uuid)
+ let key2 = (random uuid)
+ let key3 = (random uuid)
+
+ "test value" | kv set $key1 | kv set $key2 | kv set $key3
+
+ let record = (kv list | transpose -dr)
+ let actual = ($record | select $key1)
+ let expected = { $key1: "test value" }
+
+ assert equal $actual $expected
+
+ kv drop $key1
+ kv drop $key2
+ kv drop $key3
+}
+
+#[test]
+def local-using_closure [] {
+ let name_key = (random uuid)
+ let size_key = (random uuid)
+
+ ls
+ | kv set $name_key { get name }
+ | kv set $size_key { get size }
+
+ let expected = "list"
+ let actual = (kv get $name_key | describe)
+ assert equal $actual $expected
+
+ let expected = "list"
+ let actual = (kv get $size_key | describe)
+ assert equal $actual $expected
+
+ kv drop $name_key
+ kv drop $size_key
+}
+
+#[test]
+def local-return-entire-list [] {
+ let key1 = (random uuid)
+ let key2 = (random uuid)
+
+ let expected = 'value1'
+ $expected | kv set $key1
+
+ let actual = (
+ 'value2'
+ | kv set --return all $key2 # Set $key2, but return the entire kv store
+ | transpose -dr # Convert to record for easier retrieval
+ | get $key1 # Attempt to retrieve key1 (set previously)
+ )
+
+ assert equal $actual $expected
+ kv drop $key1
+ kv drop $key2
+}
+
+#[test]
+def local-return_value_only [] {
+ let key = (random uuid)
+
+ let expected = 'VALUE'
+ let actual = ('value' | kv set -r v $key {str upcase})
+
+ assert equal $actual $expected
+
+ kv drop $key
+
+}
+
+#[test]
+def universal-simple_set [] {
+ let key = (random uuid)
+
+ kv set -u $key 42
+ let actual = (kv get -u $key)
+ let expected = 42
+ assert equal $actual $expected
+
+ kv drop -u $key | ignore
+}
+
+#[test]
+def universal-pipeline_set_returns_value [] {
+ let key = (random uuid)
+ let actual = (42 | kv set -u $key)
+ let expected = 42
+ assert equal $actual $expected
+
+ let actual = (kv get -u $key)
+ let expected = 42
+ assert equal $actual $expected
+
+ kv drop -u $key | ignore
+}
+
+#[test]
+def universal-multiple_assignment [] {
+ let key1 = (random uuid)
+ let key2 = (random uuid)
+ let key3 = (random uuid)
+
+ "test value" | kv set -u $key1 | kv set -u $key2 | kv set -u $key3
+ let expected = "test value"
+ assert equal (kv get -u $key1) $expected
+ assert equal (kv get -u $key2) $expected
+ assert equal (kv get -u $key3) $expected
+ assert equal (kv get $key3) (kv get $key1)
+
+ kv drop -u $key1
+ kv drop -u $key2
+ kv drop -u $key3
+}
+
+#[test]
+def universal-transpose_to_record [] {
+ let key1 = (random uuid)
+ let key2 = (random uuid)
+ let key3 = (random uuid)
+
+ "test value" | kv set -u $key1 | kv set -u $key2 | kv set -u $key3
+
+ let record = (kv list -u | transpose -dr)
+ let actual = ($record | select $key1)
+ let expected = { $key1: "test value" }
+
+ assert equal $actual $expected
+
+ kv drop -u $key1
+ kv drop -u $key2
+ kv drop -u $key3
+}
+
+#[test]
+def universal-using_closure [] {
+ let name_key = (random uuid)
+ let size_key = (random uuid)
+
+ ls
+ | kv set -u $name_key { get name }
+ | kv set -u $size_key { get size }
+
+ let expected = "list"
+ let actual = (kv get -u $name_key | describe)
+ assert equal $actual $expected
+
+ let expected = "list"
+ let actual = (kv get -u $size_key | describe)
+ assert equal $actual $expected
+
+ kv drop -u $name_key
+ kv drop -u $size_key
+}
+
+#[test]
+def universal-return-entire-list [] {
+ let key1 = (random uuid)
+ let key2 = (random uuid)
+
+ let expected = 'value1'
+ $expected | kv set -u $key1
+
+ let actual = (
+ 'value2'
+ | kv set -u --return all $key2 # Set $key2, but return the entire kv store
+ | transpose -dr # Convert to record for easier retrieval
+ | get $key1 # Attempt to retrieve key1 (set previously)
+ )
+
+ assert equal $actual $expected
+ kv drop --universal $key1
+ kv drop --universal $key2
+}
+
+#[test]
+def universal-return_value_only [] {
+ let key = (random uuid)
+
+ let expected = 'VALUE'
+ let actual = ('value' | kv set --universal -r v $key {str upcase})
+
+ assert equal $actual $expected
+
+ kv drop --universal $key
+}
+