diff --git a/CHANGELOG.md b/CHANGELOG.md
index e8de85e..9753d4d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes are recorded here. This project follows Semantic Versioning.
## [Unreleased]
+## [0.1.2] - 2026-09-17
+
+### Added
+
+- Add `LexKey.AsMemory()` for allocation-free integration with memory-oriented storage APIs.
+
## [0.1.1] - 2026-09-17
### Fixed
diff --git a/Directory.Build.props b/Directory.Build.props
index 043d738..345872f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -13,7 +13,7 @@
true
true
1.0.0.0
- 0.1.1
+ 0.1.2
$(PackageVersion)
$(PackageVersion)
true
diff --git a/README.md b/README.md
index 73a8ffe..14cd91c 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ UUIDs, time values, composites, and storage ranges.
The package is published to Cntryl's GitHub Packages feed:
```xml
-
+
```
The package namespace is `Cntryl.Keys` so the primary type remains the unambiguous
@@ -45,6 +45,8 @@ The composite convenience API uses typed, stack-friendly descriptors and allocat
the immutable result for strings, numbers, UUIDs, existing keys, and custom encoders.
The reusable encoder can write without managed allocations after its buffer reaches capacity;
materializing a `LexKey` or array intentionally creates an owned copy.
+Use `AsMemory()` to pass an encoded key to memory-oriented storage APIs such as Fitz without
+copying; use `ToArray()` only when the caller needs mutable ownership.
## Range helpers
diff --git a/smoke/LexKey.PackageConsumer/LexKey.PackageConsumer.csproj b/smoke/LexKey.PackageConsumer/LexKey.PackageConsumer.csproj
index 87ddefc..88687ed 100644
--- a/smoke/LexKey.PackageConsumer/LexKey.PackageConsumer.csproj
+++ b/smoke/LexKey.PackageConsumer/LexKey.PackageConsumer.csproj
@@ -5,7 +5,7 @@
enable
enable
true
- 0.1.1
+ 0.1.2
$(MSBuildThisFileDirectory)../../artifacts/consumer-package-cache
false
true
diff --git a/smoke/LexKey.PackageConsumer/Program.cs b/smoke/LexKey.PackageConsumer/Program.cs
index 5bac1d3..2517084 100644
--- a/smoke/LexKey.PackageConsumer/Program.cs
+++ b/smoke/LexKey.PackageConsumer/Program.cs
@@ -3,6 +3,8 @@
var key = LexKey.EncodeComposite("tenant", 42L, true);
if (key.ToHexString() != "74656e616e7400800000000000002a0001")
throw new InvalidOperationException("Packed composite encoding did not match the contract.");
+if (!key.AsMemory().Span.SequenceEqual(key.AsSpan()))
+ throw new InvalidOperationException("The allocation-free memory view did not match the encoded key.");
var uuid = LexKey.EncodeGuid(Guid.Parse("550e8400-e29b-41d4-a716-446655440000"));
if (uuid.ToHexString() != "550e8400e29b41d4a716446655440000")
diff --git a/src/LexKey/LexKey.cs b/src/LexKey/LexKey.cs
index a0a057a..69ed10f 100644
--- a/src/LexKey/LexKey.cs
+++ b/src/LexKey/LexKey.cs
@@ -33,6 +33,9 @@ public sealed class LexKey : IComparable, IEquatable, ILexKeyEnc
/// Returns a read-only view of the encoded bytes.
public ReadOnlySpan AsSpan() => _bytes;
+ /// Returns an allocation-free read-only memory view of the encoded bytes.
+ public ReadOnlyMemory AsMemory() => _bytes;
+
/// Returns an owned copy of the encoded bytes.
public byte[] ToArray() => _bytes.ToArray();
diff --git a/src/LexKey/PublicAPI.Unshipped.txt b/src/LexKey/PublicAPI.Unshipped.txt
index 2946079..99a4305 100644
--- a/src/LexKey/PublicAPI.Unshipped.txt
+++ b/src/LexKey/PublicAPI.Unshipped.txt
@@ -1,4 +1,5 @@
#nullable enable
+Cntryl.Keys.LexKey.AsMemory() -> System.ReadOnlyMemory
Cntryl.Keys.Encoder
Cntryl.Keys.Encoder.AsSpan() -> System.ReadOnlySpan
Cntryl.Keys.Encoder.Clear() -> void
diff --git a/test/LexKey.Tests/RangeAndValueTests.cs b/test/LexKey.Tests/RangeAndValueTests.cs
index 6a23977..cdcb177 100644
--- a/test/LexKey.Tests/RangeAndValueTests.cs
+++ b/test/LexKey.Tests/RangeAndValueTests.cs
@@ -75,6 +75,21 @@ public void ShouldCloneInputsAndOutputsGivenImmutableKey()
Assert.Equal(new byte[] { 1, 2, 3 }, key.ToArray());
}
+ [Fact]
+ public void ShouldExposeReadOnlyMemoryWithoutCopyGivenImmutableKey()
+ {
+ // Arrange
+ var key = LexKey.FromBytes([1, 2, 3]);
+
+ // Act
+ var first = key.AsMemory();
+ var second = key.AsMemory();
+
+ // Assert
+ Assert.True(first.Equals(second));
+ Assert.Equal(new byte[] { 1, 2, 3 }, first.ToArray());
+ }
+
[Fact]
public void ShouldCloneCallerOwnedBytesGivenCompositePart()
{