diff --git a/cabal.project b/cabal.project
index b216db5dffaa26749cae2f6bce4530a0d9e41498..78fa3af55a5c1c65dc617f30e2ced0b5e78c37f6 100644
--- a/cabal.project
+++ b/cabal.project
@@ -1,4 +1,8 @@
 packages: .
+          -- These aren't released on hackage yet so we have to grab them
+          -- straight from the vcs host.  Probably should do some releases
+          -- soon.
+          https://whetstone.private.storage/privatestorage/tahoe-chk/-/archive/0.1.0.1/tahoe-chk-0.1.0.1.tar.gz
 
 tests: True
 
diff --git a/src/Tahoe/Directory/Internal/Capability.hs b/src/Tahoe/Directory/Internal/Capability.hs
new file mode 100644
index 0000000000000000000000000000000000000000..e1637b44bbcd22dcf47fde1614f678e6782f9b3a
--- /dev/null
+++ b/src/Tahoe/Directory/Internal/Capability.hs
@@ -0,0 +1,126 @@
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FunctionalDependencies #-}
+
+module Tahoe.Directory.Internal.Capability where
+
+import Control.Monad.IO.Class (MonadIO)
+import Crypto.Cipher.AES128 (AESKey128)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as LB
+import qualified Data.Text as T
+import Data.Void (Void)
+import qualified Tahoe.CHK as CHK
+import qualified Tahoe.CHK.Capability as CHK
+import qualified Tahoe.CHK.Encrypt as CHK
+import qualified Tahoe.CHK.Share as CHK
+import qualified Tahoe.CHK.Types as CHK
+import qualified Text.Megaparsec
+
+{- | Something which contains confidential information and can be rendered as
+ text such that the text also includes confidential information.  It is
+ expected (but not required) that such types will also have a Show instance
+ which obscures the confidential information.
+-}
+class ConfidentialShowable s where
+    -- | Show the value, including any confidential information.
+    confidentiallyShow :: s -> T.Text
+
+{- | From "capability-based security", a communicable, unforgeable token of
+ authority.
+
+ In our case, a short cryptographically derived string which may allow us to
+ interact with some plaintext previously stored.
+
+ It is expected that an instances of Show and ConfidentialShowable will also
+ be provided for any type c.
+-}
+class Capability c where
+    -- | Interpret a textual representation of the capability into a
+    -- structured representation of the same, if possible.
+    parse :: Text.Megaparsec.Parsec Void T.Text c
+
+{- | A capability which can have some of its authority removed to produce a
+ new, weaker capability.
+-}
+class Diminishable stronger weaker | stronger -> weaker where
+    -- | Perform the diminution.
+    diminish :: stronger -> weaker
+
+{- | A capability which allows "shares" of data to be located and their
+ integrity verified but does not allow the data to be read or re-written.
+-}
+class (MonadIO m, Capability v) => VerifyCapability m v where
+    -- | Perform the verification.  True if the data passes all verification
+    -- checks, False otherwise.  XXX Replace Bool with a more expressive type
+    -- so we can learn the details of the failure.
+    verify :: v -> m Bool
+
+{- | A capability which allows "shares" of data to be read but does not allow
+ data to be re-written.  Typically, a ReadCapability can also be diminished to
+ a VerifyCapability.
+
+ The typeclass includes encryption and encoding methods because even though
+ the capability does not allow *re-writing* it must still support writing
+ shares the first time.
+
+ Each instance must use its own secret key type so that the key type can
+ uniquely determine the type of capability in use.
+-}
+class (MonadIO m, Capability read) => ReadCapability m params key share read | read -> m params key share, key -> m params share read where
+    -- | Encrypt plaintext to ciphertext.
+    encrypt :: LB.ByteString -> (LB.ByteString, key)
+
+    -- | Recover plaintext by decrypting ciphertext.
+    decrypt :: key -> LB.ByteString -> LB.ByteString
+
+    -- | Encode some ciphertext into "shares", creating a ReadCapability at
+    -- the same time.
+    encode ::
+        -- | The encoding parameters for this operation.
+        params ->
+        -- | The ciphertext and the secret key which can decrypt it.
+        (LB.ByteString, key) ->
+        -- | The read capability and the encoded shares.
+        m ([share], read)
+
+    -- | If possible, decode the shares to the original ciphertext.
+    decodeMaybe ::
+        read ->
+        -- | The shares to decode.
+        [(Int, share)] ->
+        m (Maybe LB.ByteString)
+
+-- | A capability which allows "shares" of data to re-written.
+class (MonadIO m, Capability write) => WriteCapability m params write | write -> m params where
+    -- | Write new shares which completely replace the old data with the new data.
+    rewrite :: params -> write -> LB.ByteString -> m [LB.ByteString]
+
+data Reader = forall m params key share read. (ReadCapability m params key share read, Show read, ConfidentialShowable read) => Reader read
+
+instance Eq Reader
+instance Show Reader
+instance ConfidentialShowable Reader where
+    confidentiallyShow (Reader r) = confidentiallyShow r
+
+instance ConfidentialShowable CHK.Verifier where
+    confidentiallyShow = CHK.dangerRealShow . CHK.CHKVerifier
+
+instance Capability CHK.Verifier where
+    parse = CHK.pVerifier
+
+instance MonadIO m => VerifyCapability m CHK.Verifier where
+    verify = error "chk verification is unimplemented"
+
+instance ConfidentialShowable CHK.Reader where
+    confidentiallyShow = CHK.dangerRealShow . CHK.CHKReader
+
+instance Capability CHK.Reader where
+    parse = CHK.pReader
+
+instance ReadCapability IO CHK.Parameters AESKey128 CHK.Share CHK.Reader where
+    encrypt = error "tahoe-chk library doesn't have quite the right shape to make this easy yet"
+    decrypt = CHK.decrypt
+
+    encode params (ciphertext, key) = CHK.encode key params ciphertext
+    decodeMaybe = CHK.decode
diff --git a/src/Tahoe/Directory/Internal/Parsing.hs b/src/Tahoe/Directory/Internal/Parsing.hs
index 889c22e7c893b6331686ba1f5471bd783c21d7ed..299e12cb80def7e6f2a5bf4447426699d45cd7cb 100644
--- a/src/Tahoe/Directory/Internal/Parsing.hs
+++ b/src/Tahoe/Directory/Internal/Parsing.hs
@@ -1,5 +1,4 @@
 {-# LANGUAGE ExistentialQuantification #-}
-{-# LANGUAGE FunctionalDependencies #-}
 
 -- | Parsing and serialization for directories and their entries.
 module Tahoe.Directory.Internal.Parsing where
@@ -10,8 +9,10 @@ import qualified Data.ByteString.Char8 as C8
 import qualified Data.Text as T
 import Data.Text.Encoding (decodeUtf8', encodeUtf8)
 import Data.Void (Void)
+import qualified Tahoe.CHK.Capability as CHK
+import Tahoe.Directory.Internal.Capability (Capability (parse), ConfidentialShowable (confidentiallyShow), Reader (..))
 import Tahoe.Directory.Internal.Types (Directory (..), Entry (..))
-import Text.Megaparsec (MonadParsec (eof, label, takeP), ParseErrorBundle, Parsec, many, parse)
+import Text.Megaparsec (MonadParsec (eof, label, takeP), ParseErrorBundle, Parsec, failure, many, parse)
 import Text.Megaparsec.Byte (string)
 import Text.Megaparsec.Byte.Lexer (decimal)
 
@@ -57,10 +58,19 @@ pEntry =
         pNetstring $ \_ ->
             Entry
                 <$> label "name" (pNetstring pUTF8)
-                <*> label "ro_uri" (pNetstring (takeP Nothing))
+                <*> label "ro_uri" (pNetstring parseCap)
                 <*> label "rw_uri" (pNetstring (takeP Nothing))
                 <*> label "metadata" (pNetstring (takeP Nothing))
 
+parseCap :: Int -> Parser Reader
+parseCap n = do
+    bs <- takeP Nothing n
+    case decodeUtf8' bs of
+        Left _ -> Text.Megaparsec.failure Nothing mempty
+        Right txt -> case Text.Megaparsec.parse (Tahoe.Directory.Internal.Capability.parse :: Parsec Void T.Text CHK.Reader) "" txt of
+            Left err -> failure Nothing mempty
+            Right cap -> pure $ Tahoe.Directory.Internal.Capability.Reader cap
+
 pUTF8 :: Int -> Parser T.Text
 pUTF8 n = do
     bs <- takeP Nothing n
@@ -77,7 +87,7 @@ serializeEntry Entry{..} =
     -- constructor?
     netstring . B.concat $
         [ netstring . encodeUtf8 $ entryName
-        , netstring entryReader
+        , netstring . encodeUtf8 . confidentiallyShow $ entryReader
         , netstring entryEncryptedWriter
         , netstring entryMetadata
         ]
@@ -91,11 +101,3 @@ netstring xs =
         , xs
         , ","
         ]
-
-class ReadCapability c s m | c -> s where
-    read :: c -> [s] -> m B.ByteString
-
-data CapabilityParser = forall c. CapabilityParser (Parser c)
-
-parserWithCapabilities :: ReadCapability c s m => [Parser c] -> Parser (Directory c s (m a))
-parserWithCapabilities parsers = undefined
diff --git a/src/Tahoe/Directory/Internal/Types.hs b/src/Tahoe/Directory/Internal/Types.hs
index ff4b7c619d657f647b4d1382b431738baf4eca20..0b8bfbd440ce408ee239d5774170d9c22519de4b 100644
--- a/src/Tahoe/Directory/Internal/Types.hs
+++ b/src/Tahoe/Directory/Internal/Types.hs
@@ -3,18 +3,20 @@ module Tahoe.Directory.Internal.Types where
 import qualified Data.ByteString as B
 import qualified Data.Text as T
 
+import Tahoe.Directory.Internal.Capability (Reader)
+
 -- | A collection of references to other objects.
-newtype Directory c s m = Directory
-    { directoryChildren :: [Entry c s m]
+newtype Directory = Directory
+    { directoryChildren :: [Entry]
     }
     deriving (Eq, Show)
 
 -- | A reference to an object of any kind.
-data Entry c s m = Entry
+data Entry = Entry
     { -- | The name of this entry in its containing directory.  XXX What if UTF-8 decoding fails?
       entryName :: T.Text
     , -- | A capability for reading the contents of this entry. XXX Structured cap instead
-      entryReader :: c
+      entryReader :: Reader
     , -- | An encrypted capability for performing writes to this entry. XXX
       -- Document the encryption scheme.
       entryEncryptedWriter :: B.ByteString
diff --git a/tahoe-directory.cabal b/tahoe-directory.cabal
index fad8cfd975977dd00e4c5ef0a71bec7e1a352f60..83caa7514aab4711cbb3bbb8d127a7f7d1030cd0 100644
--- a/tahoe-directory.cabal
+++ b/tahoe-directory.cabal
@@ -90,13 +90,16 @@ library
   hs-source-dirs:  src
   exposed-modules:
     Tahoe.Directory
+    Tahoe.Directory.Internal.Capability
     Tahoe.Directory.Internal.Parsing
     Tahoe.Directory.Internal.Types
 
   build-depends:
-    , base        >=4 && <5.0
+    , base           >=4 && <5.0
     , bytestring
+    , cipher-aes128
     , megaparsec
+    , tahoe-chk
     , text
 
 test-suite tahoe-directory-test