Index: trunk/lib/Bookmarks/Controller.pm
===================================================================
--- trunk/lib/Bookmarks/Controller.pm	(revision 106)
+++ trunk/lib/Bookmarks/Controller.pm	(revision 107)
@@ -222,3 +222,46 @@
 }
 
+sub tag_tree {
+    my $self = shift;
+    my $tags = shift || [];
+
+    my $list = Bookmarks::List->new({
+        bookmarks => $self->bookmarks,
+        search    => $self->bookmarks->search({
+            tags   => $tags,
+        }),
+    });
+
+    my @tags = map {
+        {
+            path => join('/', @$tags[0 .. $_ - 1]),
+            tag  => $tags->[$_ - 1],
+        }
+    } 1 .. scalar(@{ $tags });
+
+    require Template;
+    require File::Basename;
+    my @cotags = $self->bookmarks->get_cotags({ search => $list->search });
+
+    #TODO: get the actual request URI and makre sure it ends with a /
+    my $base_url = join '/', ($self->base_uri . 'tags'), @$tags;
+    $base_url .= '/';
+    my $template = Template->new({ INCLUDE_PATH => File::Basename::dirname($INC{'Bookmarks/Controller.pm'}) });
+
+    $template->process(
+        'tagtree.html',
+        {
+            base_url => $self->base_uri,
+            request_url => $base_url,
+            tags      => \@tags,
+            cotags    => \@cotags,
+            bookmarks => $list->results,
+        },
+        \my $output,
+    );
+
+
+    return [200, ['Content-Type' => 'text/html; charset=UTF-8'], [$output]];
+}
+
 1;
Index: trunk/lib/BookmarksApp.pm
===================================================================
--- trunk/lib/BookmarksApp.pm	(revision 106)
+++ trunk/lib/BookmarksApp.pm	(revision 107)
@@ -82,4 +82,18 @@
         };
 
+        resource '/tags' => sub {
+            GET {
+                my ($env, $params) = @_;
+                return $self->_controller->tag_tree;
+            };
+        };
+        resource '/tags/*' => sub {
+            GET {
+                my ($env, $params) = @_;
+                my $tag_path = (@{ $params->{splat} })[0];
+                return $self->_controller->tag_tree([ split m{/}, $tag_path ]);
+            };
+        };
+
         resource '/{id}' => sub {
             GET {
@@ -99,4 +113,5 @@
             };
         };
+
     };
 
