diff --git a/bench/Ob.hs b/bench/Ob.hs
new file mode 100644
--- /dev/null
+++ b/bench/Ob.hs
@@ -0,0 +1,89 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Control.DeepSeq
+import Criterion.Main
+import qualified Urbit.Ob as Ob
+
+instance NFData Ob.Patp
+
+patpGroup :: Benchmark
+patpGroup = bgroup "patp" [
+    bench "~zod" $
+      nf Ob.patp 0x0000
+
+  , bench "~marzod" $
+      nf Ob.patp 0x0100
+
+  , bench "~dapnep-ronmyl" $
+      nf Ob.patp 0x00010000
+
+  , bench "~fipfes-fipfes-dostec-risfen" $
+      nf Ob.patp 0xFFFFFFFFFFFFFFFF
+
+  , bench "~fipfes-fipfes-fipfes-fipfes--fipfes-fipfes-fipfes-fipfes" $
+      nf Ob.patp 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+  ]
+
+fromPatpGroup :: Benchmark
+fromPatpGroup = bgroup "fromPatp" [
+   bench "~zod" $
+     whnf Ob.fromPatp (Ob.patp 0x0000)
+
+ , bench "~marzod" $
+     whnf Ob.fromPatp (Ob.patp 0x0100)
+
+ , bench "~dapnep-ronmyl" $
+     whnf Ob.fromPatp (Ob.patp 0x00010000)
+
+ , bench "~fipfes-fipfes-dostec-risfen" $
+     whnf Ob.fromPatp (Ob.patp 0xFFFFFFFFFFFFFFFF)
+
+ , bench "~fipfes-fipfes-fipfes-fipfes--fipfes-fipfes-fipfes-fipfes" $
+     whnf Ob.fromPatp (Ob.patp 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
+ ]
+
+renderGroup :: Benchmark
+renderGroup = bgroup "renderPatp" [
+   bench "~zod" $
+     nf Ob.renderPatp (Ob.patp 0x0000)
+
+ , bench "~marzod" $
+     nf Ob.renderPatp (Ob.patp 0x0100)
+
+ , bench "~dapnep-ronmyl" $
+     nf Ob.renderPatp (Ob.patp 0x00010000)
+
+ , bench "~fipfes-fipfes-dostec-risfen" $
+     nf Ob.renderPatp (Ob.patp 0xFFFFFFFFFFFFFFFF)
+
+ , bench "~fipfes-fipfes-fipfes-fipfes--fipfes-fipfes-fipfes-fipfes" $
+     nf Ob.renderPatp (Ob.patp 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
+ ]
+
+parseGroup :: Benchmark
+parseGroup = bgroup "parsePatp" [
+   bench "~zod" $
+     nf Ob.parsePatp "~zod"
+
+ , bench "~marzod" $
+     nf Ob.parsePatp "~marzod"
+
+ , bench "~dapnep-ronmyl" $
+     nf Ob.parsePatp "~dapnep-ronmyl"
+
+ , bench "~fipfes-fipfes-dostec-risfen" $
+     nf Ob.parsePatp "~fipfes-fipfes-dostec-risfen"
+
+ , bench "~fipfes-fipfes-fipfes-fipfes--fipfes-fipfes-fipfes-fipfes" $
+     nf Ob.parsePatp "~fipfes-fipfes-fipfes-fipfes--fipfes-fipfes-fipfes-fipfes"
+ ]
+
+main :: IO ()
+main = defaultMain [
+    patpGroup
+  , fromPatpGroup
+  , renderGroup
+  , parseGroup
+  ]
diff --git a/lib/Urbit/Ob.hs b/lib/Urbit/Ob.hs
--- a/lib/Urbit/Ob.hs
+++ b/lib/Urbit/Ob.hs
@@ -6,3 +6,4 @@
 import Urbit.Ob.Co as E
 import Urbit.Ob.Muk as E
 import Urbit.Ob.Ob as E
+import Urbit.Ob.Title as E
diff --git a/lib/Urbit/Ob/Co.hs b/lib/Urbit/Ob/Co.hs
--- a/lib/Urbit/Ob/Co.hs
+++ b/lib/Urbit/Ob/Co.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE OverloadedStrings #-}
 
 -- |
@@ -15,12 +16,19 @@
 
 module Urbit.Ob.Co (
     Patp
+  , Patq
 
   , patp
+  , patq
+
   , fromPatp
+  , fromPatq
 
-  , render
-  , parse
+  , renderPatp
+  , renderPatq
+
+  , parsePatp
+  , parsePatq
   ) where
 
 import qualified Data.ByteString as BS
@@ -30,6 +38,7 @@
 import qualified Data.Text as T
 import qualified Data.Vector as V
 import Data.Word (Word8)
+import GHC.Generics (Generic)
 import Numeric.Natural (Natural)
 import Prelude hiding (log)
 import qualified Urbit.Ob.Ob as Ob (fein, fynd)
@@ -44,15 +53,28 @@
 --
 --   (It's also used for naming comets, i.e. self-signed 128-bit Urbit ships.)
 --
-newtype Patp = Patp BS.ByteString
-  deriving Eq
+newtype Patp = Patp {
+    unPatp :: BS.ByteString
+  } deriving (Eq, Generic)
 
 instance Show Patp where
-  show = T.unpack . render
+  show = T.unpack . renderPatp
 
-unPatp :: Patp -> BS.ByteString
-unPatp (Patp p) = p
+-- | Hoon's \@q encoding.
+--
+--   Unlike \@p, the \@q encoding is a /non-obfuscated/ representation of an
+--   atom.
+--
+--   It's typically used for serializing arbitrary data in a memorable and
+--   pronounceable fashion.
+--
+newtype Patq = Patq {
+    unPatq :: BS.ByteString
+  } deriving (Eq, Generic)
 
+instance Show Patq where
+  show = T.unpack . renderPatq
+
 -- | Convert a 'Natural' to \@p.
 --
 --   >>> patp 0
@@ -67,6 +89,20 @@
 patp :: Natural -> Patp
 patp = Patp . BS.reverse . C.unroll . Ob.fein
 
+-- | Convert a 'Natural' to \@q.
+--
+--   >>> patq 0
+--   ~zod
+--   >>> patp 256
+--   ~marzod
+--   >>> patp 65536
+--   ~nec-dozzod
+--   >>> patp 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+--   ~fipfes-fipfes-fipfes-fipfes-fipfes-fipfes-fipfes-fipfes
+--
+patq :: Natural -> Patq
+patq = Patq . BS.reverse . C.unroll
+
 -- | Convert a \@p value to its corresponding 'Natural'.
 --
 --   >>> let zod = patp 0
@@ -76,17 +112,68 @@
 fromPatp :: Patp -> Natural
 fromPatp = Ob.fynd . C.roll . BS.reverse . unPatp
 
+-- | Convert a \@q value to its corresponding 'Natural'.
+--
+--   >>> let zod = patq 0
+--   >>> fromPatq zod
+--   0
+--
+fromPatq :: Patq -> Natural
+fromPatq = C.roll . BS.reverse . unPatq
+
 -- | Render a \@p value as 'T.Text'.
 --
---   >>> render (patp 0)
+--   >>> renderPatp (patp 0)
 --   "~zod"
---   >>> render (patp 15663360)
+--   >>> renderPatp (patp 15663360)
 --   "~nidsut-tomdun"
-render :: Patp -> T.Text
-render (Patp bs) = render' bs
+renderPatp :: Patp -> T.Text
+renderPatp (Patp bs) = render' Padding LongSpacing bs
 
-render' :: BS.ByteString -> T.Text
-render' bs =
+-- | Render a \@p value as 'T.Text'.
+--
+--   >>> renderPatq (patq 0)
+--   "~zod"
+--   >>> renderPatq (patq 15663360)
+--   "~mun-marzod"
+renderPatq :: Patq -> T.Text
+renderPatq (Patq bs) = render' NoPadding ShortSpacing bs
+
+-- | Parse a \@p value existing as 'T.Text'.
+--
+--   >>> parsePatp "~nidsut-tomdun"
+--   Right ~nidsut-tomdun
+--   > parsePatp "~fipfes-fipfes-fipfes-doznec"
+--   Right ~fipfes-fipfes-fipfes-doznec
+--
+parsePatp :: T.Text -> Either T.Text Patp
+parsePatp = fmap Patp . parse
+
+-- | Parse a \@q value existing as 'T.Text'.
+--
+--   >>> parsePatq "~nec-dozzod"
+--   Right ~nec-dozzod
+--   > parsePatq "~fipfes-fipfes-fipfes-doznec"
+--   Right ~fipfes-fipfes-fipfes-doznec
+--
+parsePatq :: T.Text -> Either T.Text Patq
+parsePatq = fmap Patq . parse
+
+-- Padding option for rendering.
+data Padding =
+    Padding
+  | NoPadding
+  deriving Eq
+
+-- Spacing option for rendering.
+data Spacing =
+    LongSpacing
+  | ShortSpacing
+  deriving Eq
+
+-- General-purpose renderer.
+render' :: Padding -> Spacing -> BS.ByteString -> T.Text
+render' padding spacing bs =
       T.cons '~'
     . snd
     . BS.foldr alg (0 :: Int, mempty)
@@ -95,27 +182,29 @@
     alg val (idx, acc) =
       let syl = if even idx then suffix val else prefix val
           glue
-            | idx `mod` 8 == 0 = if idx == 0 then mempty else "--"
+            | idx `mod` 8 == 0 = if idx == 0 then mempty else dash
             | even idx         = "-"
             | otherwise        = mempty
       in  (succ idx, syl <> glue <> acc)
 
-    padded =
+    padded
+      | padCondition = BS.cons 0 bs
+      | otherwise    = bs
+
+    dash = case spacing of
+      LongSpacing  -> "--"
+      ShortSpacing -> "-"
+
+    padCondition =
       let len = BS.length bs
-      in  if   (odd len && len > 2) || len == 0
-          then BS.cons 0 bs
-          else bs
+      in  case padding of
+            NoPadding -> len == 0
+            Padding   -> (odd len && len > 2) || len == 0
 
--- | Parse a \@p value existing as 'T.Text'.
---
---   >>> parse "~nidsut-tomdun"
---   Right ~nidsut-tomdun
---   > parse "~fipfes-fipfes-fipfes-doznec"
---   Right ~fipfes-fipfes-fipfes-doznec
---
-parse :: T.Text -> Either T.Text Patp
+-- General-purpose (non-strict) parser.
+parse :: T.Text -> Either T.Text BS.ByteString
 parse p =
-      fmap (Patp . snd)
+      fmap snd
     $ foldrM alg (0 :: Int, mempty) syls
   where
     alg syl (idx, acc) = do
diff --git a/lib/Urbit/Ob/Title.hs b/lib/Urbit/Ob/Title.hs
new file mode 100644
--- /dev/null
+++ b/lib/Urbit/Ob/Title.hs
@@ -0,0 +1,111 @@
+{-# LANGUAGE BangPatterns #-}
+
+-- |
+-- Module: Urbit.Ob.Title
+-- Copyright: (c) 2019 Jared Tobin
+-- License: MIT
+--
+-- Maintainer: Jared Tobin <jared@jtobin.io>
+-- Stability: unstable
+-- Portability: ghc
+--
+-- Functions for determining ship class and parentage.
+--
+-- Analogous to the +title arm of zuse.hoon.
+
+module Urbit.Ob.Title (
+    Class(..)
+  , clan
+  , sein
+  ) where
+
+import Urbit.Ob.Co (Patp)
+import qualified Urbit.Ob.Co as Co (patp, fromPatp)
+
+-- | Ship class.
+data Class =
+    -- | 8-bit atom
+    --
+    Galaxy
+    -- | 16-bit atom
+    --
+  | Star
+    -- | 32-bit atom
+    --
+  | Planet
+    -- | 64-bit atom
+    --
+  | Moon
+    -- | 128-bit atom
+    --
+  | Comet
+  deriving (Eq, Show)
+
+-- | Determine ship class.
+--
+--   >>> let fes = patp 255
+--   >>> let fipfes = patp 256
+--   >>> let dostec = patp 0xFFFFFFFF
+--   >>> let risfen = patp 0xFFFFFFFFFFFFFFFF
+--   >>> let fipfesfipfes = patp 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+--   >>> clan fes
+--   Galaxy
+--   >>> clan fipfes
+--   Star
+--   >>> clan dostec
+--   Planet
+--   >>> clan risfen
+--   Moon
+--   >>> clan fipfesfipfes
+--   Comet
+--
+clan :: Patp -> Class
+clan ship
+    | wid <= 1  = Galaxy
+    | wid == 2  = Star
+    | wid <= 4  = Planet
+    | wid <= 8  = Moon
+    | otherwise = Comet
+  where
+    wid = met 3 (Co.fromPatp ship)
+
+-- | Determine parent.
+--
+--   A ship's parent signs for it on the network.  'sein' establishes the
+--   so-called /autoboss/ of a ship (which can escape to another sponsor).
+--
+--   Note that galaxies sign for themselves, and stars sign for comets.
+--
+--   >>> sein fes
+--   ~fes
+--   >>> sein fipfes
+--   ~fes
+--   >>> sein dostec
+--   ~fipfes
+--   >>> sein risfen
+--   ~dostec-risfen
+--   >>> sein fipfesfipfes
+--   ~fipfes
+--
+sein :: Patp -> Patp
+sein ship = Co.patp $ case clan ship of
+    Galaxy -> nat
+    Star   -> end 3 1 nat
+    Planet -> end 4 1 nat
+    Moon   -> end 5 1 nat
+    Comet  -> end 4 1 nat
+  where
+    nat = Co.fromPatp ship
+
+met :: Integral a => a -> a -> a
+met = loop 0 where
+  loop !acc a !b
+    | b == 0    = acc
+    | otherwise = loop (succ acc) a (rsh a 1 b)
+
+rsh :: Integral a => a -> a -> a -> a
+rsh a b c = c `div` 2 ^ (2 ^ a * b)
+
+end :: Integral a => a -> a -> a -> a
+end a b c = c `mod` 2 ^ (2 ^ a * b)
+
diff --git a/test/Co/Tests/Property.hs b/test/Co/Tests/Property.hs
--- a/test/Co/Tests/Property.hs
+++ b/test/Co/Tests/Property.hs
@@ -4,7 +4,7 @@
   ) where
 
 import qualified Data.Text as T
-import Data.Word (Word32)
+import Data.Word (Word64)
 import Numeric.Natural (Natural)
 import Test.Hspec
 import Test.Hspec.Core.QuickCheck (modifyMaxSuccess)
@@ -12,14 +12,20 @@
 import qualified Urbit.Ob.Co as Co
 
 nats :: Gen Natural
-nats = fmap fromIntegral (arbitrary :: Gen Word32)
+nats = fmap fromIntegral (arbitrary :: Gen Word64)
 
 patps :: Gen Co.Patp
 patps = fmap Co.patp nats
 
+patqs :: Gen Co.Patq
+patqs = fmap Co.patq nats
+
 patpStrings :: Gen T.Text
-patpStrings = fmap Co.render patps
+patpStrings = fmap Co.renderPatp patps
 
+patqStrings :: Gen T.Text
+patqStrings = fmap Co.renderPatq patqs
+
 tests :: Spec
 tests = do
   describe "fromPatp" $
@@ -32,11 +38,29 @@
       it "inverts fromPatp" $
         forAll patps $ \x -> Co.patp (Co.fromPatp x) == x
 
-  describe "render" $
+  describe "renderPatp" $
     modifyMaxSuccess (const 1000) $
-      it "inverts parse" $
+      it "inverts parsePatp" $
         forAll patpStrings $ \x ->
-          case Co.parse x of
+          case Co.parsePatp x of
             Left _  -> False
-            Right p -> Co.render p == x
+            Right p -> Co.renderPatp p == x
+
+  describe "fromPatq" $
+    modifyMaxSuccess (const 1000) $
+      it "inverts patq" $
+        forAll nats $ \x -> Co.fromPatq (Co.patq x) == x
+
+  describe "patq" $
+    modifyMaxSuccess (const 1000) $
+      it "inverts fromPatq" $
+        forAll patqs $ \x -> Co.patq (Co.fromPatq x) == x
+
+  describe "renderPatq" $
+    modifyMaxSuccess (const 1000) $
+      it "inverts parsePatq" $
+        forAll patqStrings $ \x ->
+          case Co.parsePatq x of
+            Left _  -> False
+            Right p -> Co.renderPatq p == x
 
diff --git a/test/Co/Tests/Unit.hs b/test/Co/Tests/Unit.hs
--- a/test/Co/Tests/Unit.hs
+++ b/test/Co/Tests/Unit.hs
@@ -9,32 +9,61 @@
 import qualified Urbit.Ob.Co as Co
 
 tests :: Spec
-tests =
-  describe "render" $ do
+tests = do
+  describe "renderPatp" $ do
     it "matches 32-bit reference values" $ do
-      Co.render (Co.patp 0) `shouldBe` "~zod"
-      Co.render (Co.patp 255) `shouldBe` "~fes"
-      Co.render (Co.patp 256) `shouldBe` "~marzod"
-      Co.render (Co.patp 65535) `shouldBe` "~fipfes"
-      Co.render (Co.patp 65536) `shouldBe` "~dapnep-ronmyl"
-      Co.render (Co.patp 15663360) `shouldBe` "~nidsut-tomdun"
-      Co.render (Co.patp 0xFFFFFFFF) `shouldBe` "~dostec-risfen"
+      Co.renderPatp (Co.patp 0) `shouldBe` "~zod"
+      Co.renderPatp (Co.patp 255) `shouldBe` "~fes"
+      Co.renderPatp (Co.patp 256) `shouldBe` "~marzod"
+      Co.renderPatp (Co.patp 65535) `shouldBe` "~fipfes"
+      Co.renderPatp (Co.patp 65536) `shouldBe` "~dapnep-ronmyl"
+      Co.renderPatp (Co.patp 15663360) `shouldBe` "~nidsut-tomdun"
+      Co.renderPatp (Co.patp 0xFFFFFFFF) `shouldBe` "~dostec-risfen"
 
     it "matches 64-bit reference values" $ do
       let big_64_01 = 0x0000000100000000
-      Co.render (Co.patp big_64_01) `shouldBe` "~doznec-dozzod-dozzod"
+      Co.renderPatp (Co.patp big_64_01) `shouldBe` "~doznec-dozzod-dozzod"
 
       let big_64_02 = 0xFFFFFFFFFFFFFFFF
-      Co.render (Co.patp big_64_02) `shouldBe` "~fipfes-fipfes-dostec-risfen"
+      Co.renderPatp (Co.patp big_64_02) `shouldBe` "~fipfes-fipfes-dostec-risfen"
 
     it "matches 128-bit reference values" $ do
       let big_128_01  = 0x00000000000000010000000000000000
           patp_128_01 = "~doznec--dozzod-dozzod-dozzod-dozzod"
-      Co.render (Co.patp big_128_01) `shouldBe` patp_128_01
+      Co.renderPatp (Co.patp big_128_01) `shouldBe` patp_128_01
 
       let big_128_02  = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
           patp_128_02 =
             "~fipfes-fipfes-fipfes-fipfes--fipfes-fipfes-fipfes-fipfes"
 
-      Co.render (Co.patp big_128_02) `shouldBe` patp_128_02
+      Co.renderPatp (Co.patp big_128_02) `shouldBe` patp_128_02
+
+  describe "renderPatq" $ do
+    it "matches 32-bit reference values" $ do
+      Co.renderPatq (Co.patq 0) `shouldBe` "~zod"
+      Co.renderPatq (Co.patq 255) `shouldBe` "~fes"
+      Co.renderPatq (Co.patq 256) `shouldBe` "~marzod"
+      Co.renderPatq (Co.patq 65535) `shouldBe` "~fipfes"
+      Co.renderPatq (Co.patq 65536) `shouldBe` "~nec-dozzod"
+      Co.renderPatq (Co.patq 15663360) `shouldBe` "~mun-marzod"
+      Co.renderPatq (Co.patq 0xFFFFFFFF) `shouldBe` "~fipfes-fipfes"
+
+    it "matches 64-bit reference values" $ do
+      let big_64_01 = 0x0000000100000000
+      Co.renderPatq (Co.patq big_64_01) `shouldBe` "~nec-dozzod-dozzod"
+
+      let big_64_02 = 0xFFFFFFFFFFFFFFFF
+          patq_64_02 = "~fipfes-fipfes-fipfes-fipfes"
+      Co.renderPatq (Co.patq big_64_02) `shouldBe` patq_64_02
+
+    it "matches 128-bit reference values" $ do
+      let big_128_01  = 0x00000000000000010000000000000000
+          patq_128_01 = "~nec-dozzod-dozzod-dozzod-dozzod"
+      Co.renderPatq (Co.patq big_128_01) `shouldBe` patq_128_01
+
+      let big_128_02  = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          patq_128_02 =
+            "~fipfes-fipfes-fipfes-fipfes-fipfes-fipfes-fipfes-fipfes"
+
+      Co.renderPatq (Co.patq big_128_02) `shouldBe` patq_128_02
 
diff --git a/test/Ob.hs b/test/Ob.hs
--- a/test/Ob.hs
+++ b/test/Ob.hs
@@ -11,5 +11,5 @@
   hspec $ do
     context "small input space" S.tests
     context "medium input space" M.tests
-    context "propert tests" P.tests
+    context "property tests" P.tests
     context "unit tests" U.tests
diff --git a/test/Title.hs b/test/Title.hs
new file mode 100644
--- /dev/null
+++ b/test/Title.hs
@@ -0,0 +1,10 @@
+module Main where
+
+import qualified Title.Tests.Property as P
+import Test.Hspec
+
+main :: IO ()
+main =
+  hspec $
+    context "property tests" P.tests
+
diff --git a/test/Title/Tests/Property.hs b/test/Title/Tests/Property.hs
new file mode 100644
--- /dev/null
+++ b/test/Title/Tests/Property.hs
@@ -0,0 +1,45 @@
+
+module Title.Tests.Property (
+  tests
+  ) where
+
+import Data.Word (Word8, Word16, Word32, Word64)
+import Test.Hspec
+import Test.QuickCheck
+import Urbit.Ob.Co (Patp)
+import qualified Urbit.Ob.Co as Co
+import qualified Urbit.Ob.Title as Title
+
+galaxies :: Gen Patp
+galaxies = fmap (Co.patp . fromIntegral) (arbitrary :: Gen Word8)
+
+stars :: Gen Patp
+stars = do
+  star <- arbitrary `suchThat` (> (0xFF :: Word16))
+  return (Co.patp (fromIntegral star))
+
+planets :: Gen Patp
+planets = do
+  planet <- arbitrary `suchThat` (> (0xFFFF :: Word32))
+  return (Co.patp (fromIntegral planet))
+
+moons :: Gen Patp
+moons = do
+  moon <- arbitrary `suchThat` (> (0xFFFFFFFF :: Word64))
+  return (Co.patp (fromIntegral moon))
+
+tests :: Spec
+tests =
+  describe "clan" $ do
+    it "identifies galaxies correctly" $
+      forAll galaxies $ \x -> Title.clan x == Title.Galaxy
+
+    it "identifies stars correctly" $
+      forAll stars $ \x -> Title.clan x == Title.Star
+
+    it "identifies planets correctly" $
+      forAll planets $ \x -> Title.clan x == Title.Planet
+
+    it "identifies moons correctly" $
+      forAll moons $ \x -> Title.clan x == Title.Moon
+
diff --git a/urbit-hob.cabal b/urbit-hob.cabal
--- a/urbit-hob.cabal
+++ b/urbit-hob.cabal
@@ -1,5 +1,5 @@
 name:           urbit-hob
-version:        0.2.0
+version:        0.3.0
 synopsis:       Hoon-style atom manipulation and printing functions
 homepage:       https://github.com/urbit/urbit-hob
 bug-reports:    https://github.com/urbit/urbit-hob/issues
@@ -12,29 +12,43 @@
 build-type:     Simple
 cabal-version:  >= 1.10
 description:
-  Here you can primarily find functions for dealing with the \"patp\" phonetic
-  base used by Urbit.  The \@p encoding is used for naming ships; it uniquely
-  represents a 32-bit number in a memorable and pronounceable fashion.
+  Here you can primarily find functions for dealing with the \"patp\" and
+  \"patq\" /phonetic bases/ used by Urbit.  The \@p encoding is used for naming
+  ships, while the \@q encoding is used for arbitrary data; they each uniquely
+  represent an underlying natural number (or /atom/) in a memorable and
+  pronounceable fashion.
   .
-  The \@p encoding is an /obfuscated/ representation of an underlying 32-bit
-  number, in particular, hence the \"ob\" in the library's name.
+  The \@p encoding is an /obfuscated/ representation of an underlying atom, in
+  particular, hence the \"ob\" in the library's name.
   .
-  The @Urbit.Ob@ module exposes two functions, 'patp' and 'fromPatp', for
-  converting between representations.  You can also render a 'Patp' value via
-  the 'render' function, or parse one via 'parse'.
+  The @Urbit.Ob@ module exposes two families of functions, 'patp' and
+  'fromPatp', and then 'patq' and 'fromPatq', for converting between
+  representations.  You can also render a 'Patp' or 'Patq' value as 'Text' via
+  the 'renderPatp' and 'renderPatq' functions, or parse them from 'Text' via
+  'parsePatp' and 'parsePatq'.
   .
+  Since \@p values represent ships, some utilities for dealing with ships are
+  also exposed.  The 'clan' and 'sein' functions are useful for determining a
+  ship's class and (default) parent, respectively.
+  .
   Some quick examples:
   .
   >>> :set -XOverloadedStrings
   >>> import qualified Urbit.Ob as Ob
-  >>>
   >>> let nidsut = Ob.patp 15663360
-  >>> Ob.render nidsut
+  >>> let marzod = Ob.patq (Ob.fromPatp nidsut)
+  >>> Ob.renderPatp nidsut
   "~nidsut-tomdun"
+  >>> Ob.renderPatq marzod
+  "~mun-marzod"
   >>> Ob.fromPatp nidsut
   15663360
-  >>> Ob.parse "~nidsut-tomdun"
+  >>> Ob.parsePatp "~nidsut-tomdun"
   Right ~nidsut-tomdun
+  >>> Ob.clan nidsut
+  Planet
+  >>> Ob.sein nidsut
+  ~marzod
 
 source-repository head
   type: git
@@ -50,7 +64,7 @@
   hs-source-dirs:   lib
 
   if flag(release)
-    ghc-options:     -Wall
+    ghc-options:     -Wall -O2
   else
     ghc-options:     -Wall -Werror
 
@@ -59,6 +73,7 @@
     , Urbit.Ob.Co
     , Urbit.Ob.Muk
     , Urbit.Ob.Ob
+    , Urbit.Ob.Title
 
   other-modules:
       Data.Serialize.Extended
@@ -105,5 +120,33 @@
     , hspec-core
     , QuickCheck
     , text
+    , urbit-hob
+
+Test-suite title
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Title.hs
+  other-modules:
+    Title.Tests.Property
+  default-language:    Haskell2010
+  ghc-options:
+    -rtsopts
+  build-depends:
+      base
+    , hspec
+    , QuickCheck
+    , urbit-hob
+
+benchmark ob-bench
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      bench
+  main-is:             Ob.hs
+  default-language:    Haskell2010
+  ghc-options:
+    -rtsopts -O2
+  build-depends:
+      base
+    , criterion
+    , deepseq
     , urbit-hob
 
