diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -609,6 +609,7 @@
     'DivinerFileAtomizer' => 'applications/diviner/atomizer/DivinerFileAtomizer.php',
     'DivinerFindController' => 'applications/diviner/controller/DivinerFindController.php',
     'DivinerGenerateWorkflow' => 'applications/diviner/workflow/DivinerGenerateWorkflow.php',
+    'DivinerLanguageConstant' => 'applications/diviner/constants/DivinerLanguageConstant.php',
     'DivinerLiveAtom' => 'applications/diviner/storage/DivinerLiveAtom.php',
     'DivinerLiveBook' => 'applications/diviner/storage/DivinerLiveBook.php',
     'DivinerLivePublisher' => 'applications/diviner/publisher/DivinerLivePublisher.php',
diff --git a/src/applications/diviner/application/PhabricatorApplicationDiviner.php b/src/applications/diviner/application/PhabricatorApplicationDiviner.php
--- a/src/applications/diviner/application/PhabricatorApplicationDiviner.php
+++ b/src/applications/diviner/application/PhabricatorApplicationDiviner.php
@@ -29,7 +29,7 @@
       '/book/'.
         '(?P<book>[^/]+)/'.
         '(?P<type>[^/]+)/'.
-        '(?:(?P<context>[^/]+)/)?'.
+        '(?P<context>[^/]+)/'.
         '(?P<name>[^/]+)/'.
         '(?:(?P<index>\d+)/)?' => 'DivinerAtomController',
     );
diff --git a/src/applications/diviner/atom/DivinerAtom.php b/src/applications/diviner/atom/DivinerAtom.php
--- a/src/applications/diviner/atom/DivinerAtom.php
+++ b/src/applications/diviner/atom/DivinerAtom.php
@@ -9,6 +9,8 @@
   const TYPE_FUNCTION  = 'function';
   const TYPE_INTERFACE = 'interface';
 
+  const CONTEXT_SEPARATOR = ':';
+
   private $type;
   private $name;
   private $file;
@@ -57,6 +59,20 @@
   }
 
   public function setContext($context) {
+    $language = $this->getLanguage();
+    if (!$language) {
+      throw new Exception("Call setLanguage() before setContext()");
+    }
+    // Normalize the context based on the atom's language
+    $separator = id(new DivinerLanguageConstant())
+      ->getContextSeparatorForLanguage($language);
+    $context = trim($context, $separator);
+    $context = str_replace($separator, DivinerAtom::CONTEXT_SEPARATOR,
+      $context);
+    if (!strlen($context)) {
+      $context = null;
+    }
+
     $this->context = $context;
     return $this;
   }
@@ -294,7 +310,6 @@
     return implode('/', $parts);
   }
 
-
   public function toDictionary() {
     // NOTE: If you change this format, bump the format version in
     // getAtomSerializationVersion().
@@ -345,8 +360,8 @@
       ->setLine(idx($dictionary, 'line'))
       ->setHash(idx($dictionary, 'hash'))
       ->setLength(idx($dictionary, 'length'))
-      ->setContext(idx($dictionary, 'context'))
       ->setLanguage(idx($dictionary, 'language'))
+      ->setContext(idx($dictionary, 'context'))
       ->setParentHash(idx($dictionary, 'parentHash'))
       ->setDocblockRaw(idx($dictionary, 'docblockRaw'))
       ->setProperties(idx($dictionary, 'properties'));
diff --git a/src/applications/diviner/constants/DivinerLanguageConstant.php b/src/applications/diviner/constants/DivinerLanguageConstant.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diviner/constants/DivinerLanguageConstant.php
@@ -0,0 +1,20 @@
+<?php
+
+class DivinerLanguageConstant {
+
+  public function getContextSeparatorForLanguage($language) {
+    switch ($language) {
+      case 'php':
+        $separator = '\\';
+        break;
+      case 'human':
+        $separator = '';
+        break;
+      default:
+        $separator = '.';
+        break;
+    }
+    return $separator;
+  }
+
+}
diff --git a/src/applications/diviner/controller/DivinerAtomController.php b/src/applications/diviner/controller/DivinerAtomController.php
--- a/src/applications/diviner/controller/DivinerAtomController.php
+++ b/src/applications/diviner/controller/DivinerAtomController.php
@@ -16,7 +16,7 @@
     $this->bookName = $data['book'];
     $this->atomType = $data['type'];
     $this->atomName = $data['name'];
-    $this->atomContext = nonempty(idx($data, 'context'), null);
+    $this->atomContext = $data['context'];
     $this->atomIndex = nonempty(idx($data, 'index'), null);
   }
 
@@ -293,7 +293,7 @@
   private function renderAtomTag(DivinerLiveSymbol $symbol) {
     return id(new PHUITagView())
       ->setType(PHUITagView::TYPE_OBJECT)
-      ->setName($symbol->getName())
+      ->setName($symbol->getTitle())
       ->setHref($symbol->getURI());
   }
 
@@ -513,6 +513,17 @@
         break;
     }
 
+    switch ($symbol->getType()) {
+      case DivinerAtom::TYPE_CLASS:
+      case DivinerAtom::TYPE_INTERFACE:
+      case DivinerAtom::TYPE_FUNCTION:
+        $name = $symbol->getTitle();
+        break;
+      default:
+        $name = $symbol->getName();
+        break;
+    }
+
     $out[] = phutil_tag(
       $anchor ? 'a' : 'span',
       array(
@@ -520,7 +531,7 @@
         'href' => $anchor ? '#'.$anchor : null,
         'name' => $is_link ? null : $anchor,
       ),
-      $symbol->getName());
+      $name);
 
     $out = phutil_implode_html(' ', $out);
 
diff --git a/src/applications/diviner/controller/DivinerBookController.php b/src/applications/diviner/controller/DivinerBookController.php
--- a/src/applications/diviner/controller/DivinerBookController.php
+++ b/src/applications/diviner/controller/DivinerBookController.php
@@ -43,6 +43,7 @@
     $properties = $this->buildPropertyList($book);
 
     $atoms = id(new DivinerAtomQuery())
+      ->needAtoms(true)
       ->setViewer($viewer)
       ->withBookPHIDs(array($book->getPHID()))
       ->execute();
diff --git a/src/applications/diviner/query/DivinerAtomQuery.php b/src/applications/diviner/query/DivinerAtomQuery.php
--- a/src/applications/diviner/query/DivinerAtomQuery.php
+++ b/src/applications/diviner/query/DivinerAtomQuery.php
@@ -46,6 +46,9 @@
   }
 
   public function withContexts(array $contexts) {
+    if ($contexts == array(DivinerAtom::CONTEXT_SEPARATOR)) {
+      $contexts = array();
+    }
     $this->contexts = $contexts;
     return $this;
   }
diff --git a/src/applications/diviner/storage/DivinerLiveSymbol.php b/src/applications/diviner/storage/DivinerLiveSymbol.php
--- a/src/applications/diviner/storage/DivinerLiveSymbol.php
+++ b/src/applications/diviner/storage/DivinerLiveSymbol.php
@@ -63,6 +63,9 @@
     if ($this->getContext()) {
       $parts[] = $this->getContext();
     }
+    else {
+      $parts[] = DivinerAtom::CONTEXT_SEPARATOR;
+    }
 
     $parts[] = $this->getName();
 
@@ -103,12 +106,31 @@
     return parent::save();
   }
 
+  public function getLanguage() {
+    // TODO: add this as a column?
+    try {
+      return $this->getAtom()->getLanguage();
+    }
+    catch (PhabricatorDataNotAttachedException $e) {
+      return '';
+    }
+  }
+
   public function getTitle() {
     $title = parent::getTitle();
     if (!strlen($title)) {
       $title = $this->getName();
     }
-    return $title;
+    $separator = id(new DivinerLanguageConstant())
+      ->getContextSeparatorForLanguage($this->getLanguage());
+    $context = str_replace(DivinerAtom::CONTEXT_SEPARATOR, $separator,
+      $this->getContext());
+
+    if (strlen($context)) {
+      $context .= $separator;
+    }
+
+    return $context.$title;
   }
 
   public function setTitle($value) {