diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index 58f98f426fa8eec4b22870a7927f082ee2ba420a..52ef30ba8bad4b3422f15c51ac52ef31f1c3f094 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -81,9 +81,11 @@ ul.nav.nav-projects-tabs {
 
 .public-projects {
   li {
-    margin-top: 8px;
-    margin-bottom: 5px;
-    border-bottom: 1px solid #eee;
+    .project-title {
+      font-size: 14px;
+      line-height: 2;
+      font-weight: normal;
+    }
 
     .description {
       margin-left: 15px;
@@ -92,6 +94,14 @@ ul.nav.nav-projects-tabs {
   }
 }
 
+.public-clone {
+  background: #333;
+  color: #f5f5f5;
+  padding: 5px 10px;
+  margin: 1px;
+  font-weight: normal;
+}
+
 .new-tag-btn {
   position: relative;
   top: -5px;
diff --git a/app/controllers/public/projects_controller.rb b/app/controllers/public/projects_controller.rb
index 6c0b397b4c37273a31b73f53965a4ccb18f22ae9..85216cd32714d38689a1f1b66fc38b0cf7dcc628 100644
--- a/app/controllers/public/projects_controller.rb
+++ b/app/controllers/public/projects_controller.rb
@@ -10,4 +10,15 @@ class Public::ProjectsController < ApplicationController
     @projects = @projects.search(params[:search]) if params[:search].present?
     @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
   end
+
+  def show
+    @project = Project.public_only.find_with_namespace(params[:id])
+    render_404 and return unless @project
+
+    @repository = @project.repository
+    @recent_tags = @repository.tags.first(10)
+
+    @commit = @repository.commit(params[:ref])
+    @tree = Tree.new(@repository, @commit.id)
+  end
 end
diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml
index b9395873c337472c3b896973bd0583996ba0314b..df2350b1535a24b97a549dd2a5d72e649b17bef7 100644
--- a/app/views/layouts/errors.html.haml
+++ b/app/views/layouts/errors.html.haml
@@ -2,7 +2,7 @@
 %html{ lang: "en"}
   = render "layouts/head", title: "Error"
   %body{class: "#{app_theme} application"}
-    = render "layouts/head_panel", title: ""
+    = render "layouts/head_panel", title: "" if current_user
     = render "layouts/flash"
     .container
       .content
diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml
index e330da9bd73d470c0826a2d2cfd822da6d4bcd0d..4a06d63fafd17547b065106ca468f96e98e00f3b 100644
--- a/app/views/layouts/public.html.haml
+++ b/app/views/layouts/public.html.haml
@@ -10,10 +10,16 @@
           .container
             %div.app_logo
               %span.separator
-              = link_to root_path, class: "home" do
+              = link_to public_root_path, class: "home" do
                 %h1 GITLAB
               %span.separator
             %h1.project_name Public Projects
+            %ul.nav
+              %li
+                %a
+                  %div.hide.turbolink-spinner
+                    %i.icon-refresh.icon-spin
+                    Loading...
 
     .container.navless-container
       .content
diff --git a/app/views/public/projects/_tree.html.haml b/app/views/public/projects/_tree.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..bd09c236a0b2fd7ad5cd23e9d3940c3f7268fe97
--- /dev/null
+++ b/app/views/public/projects/_tree.html.haml
@@ -0,0 +1,5 @@
+- if tree.readme
+  = render "projects/tree/readme", readme: tree.readme
+- else
+  .alert
+    %h3.nothing_here_message This project does not have README file
diff --git a/app/views/public/projects/index.html.haml b/app/views/public/projects/index.html.haml
index 4bc67d8c6ae84f9798c9bb28cb8afd31863fed9a..e933268973a5a254bb628e1691bdeaf0fda16580 100644
--- a/app/views/public/projects/index.html.haml
+++ b/app/views/public/projects/index.html.haml
@@ -11,22 +11,20 @@
             = search_field_tag :search, params[:search], placeholder: "gitlab-ci", class: "span3 search-text-input", id: "projects_search"
             = submit_tag 'Search', class: "btn btn-primary wide"
 
-%hr
-
 .public-projects
-  %ul.unstyled
+  %ul.bordered-list
     - @projects.each do |project|
-      %li.clearfix
-        %div
-          %i.icon-share
-          - if current_user
-            = link_to_project project
-          - else
+      %li
+        .project-title
+          %i.icon-share.cgray
+          = link_to public_project_path(project) do
             = project.name_with_namespace
           .pull-right
-            %pre.dark.tiny git clone #{project.http_url_to_repo}
-        %div.description
-          = project.description
+            %pre.public-clone git clone #{project.http_url_to_repo}
+
+        - if project.description.present?
+          %div.description
+            = project.description
     - unless @projects.present?
       %h3.nothing_here_message No public projects
 
diff --git a/app/views/public/projects/show.html.haml b/app/views/public/projects/show.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..c4d8a4f5a5fce0f582348c585185ab1c5ef52e79
--- /dev/null
+++ b/app/views/public/projects/show.html.haml
@@ -0,0 +1,46 @@
+%h3.page-title
+  = @project.name_with_namespace
+  .pull-right
+    %pre.public-clone git clone #{@project.http_url_to_repo}
+  .pull-right
+    - if current_user
+      = link_to 'Browse project', @project, class: 'btn btn-create append-right-10'
+
+
+%div
+  = link_to public_root_path do
+    &larr; To projects list
+  .pull-right
+    %span.light= @project.description
+
+%br
+.row
+  .span9
+    = render 'tree', tree: @tree
+  .span3
+    %h5 Repository:
+    %div
+      %p
+        %span.light Bare size is
+        #{@project.repository.size} MB
+
+      %p
+        = pluralize(@repository.round_commit_count, 'commit')
+      %p
+        = pluralize(@repository.branch_names.count, 'branch')
+      %p
+        = pluralize(@repository.tag_names.count, 'tag')
+
+    - if @recent_tags.present?
+      %hr
+      %h5 Most Recent Tags:
+      %ul.unstyled
+        - @recent_tags.each do |tag|
+          %li
+            %p
+              %i.icon-tag
+              %strong= tag.name
+              %small.light.pull-right
+                %i.icon-calendar
+                  = time_ago_in_words(tag.commit.committed_date)
+                ago
diff --git a/config/routes.rb b/config/routes.rb
index 2d9875eb496941207cffa3114caa707acc8edf94..d303a57d3047a418abb4ac1307a5f74d04122430 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -55,6 +55,8 @@ Gitlab::Application.routes.draw do
   #
   namespace :public do
     resources :projects, only: [:index]
+    resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, only: [:show]
+
     root to: "projects#index"
   end
 
diff --git a/features/public/public_projects.feature b/features/public/public_projects.feature
new file mode 100644
index 0000000000000000000000000000000000000000..c4f1b6203e7ca62d475e7b4e935f007a21480e72
--- /dev/null
+++ b/features/public/public_projects.feature
@@ -0,0 +1,14 @@
+Feature: Public Projects Feature
+  Background:
+    Given public project "Community"
+    And private project "Enterprise"
+
+  Scenario: I visit public area
+    When I visit the public projects area
+    Then I should see project "Community"
+    And I should not see project "Enterprise"
+
+  Scenario: I visit public project page
+    When I visit public page for "Community" project
+    Then I should see public project details
+    And I should see project readme
diff --git a/features/steps/public/projects_feature.rb b/features/steps/public/projects_feature.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8d612498fb9a3a5f832be0bde0601fd3297e3e50
--- /dev/null
+++ b/features/steps/public/projects_feature.rb
@@ -0,0 +1,35 @@
+class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps
+  include SharedPaths
+
+  step 'I should see project "Community"' do
+    page.should have_content "Community"
+  end
+
+  step 'I should not see project "Enterprise"' do
+    page.should_not have_content "Enterprise"
+  end
+
+  step 'I should see public project details' do
+    page.should have_content '32 branches'
+    page.should have_content '16 tags'
+  end
+
+  step 'I should see project readme' do
+    page.should have_content 'README.md'
+  end
+
+  step 'public project "Community"' do
+    create :project_with_code, name: 'Community', public: true
+  end
+
+  step 'private project "Enterprise"' do
+    create :project, name: 'Enterprise'
+  end
+
+  private
+
+  def project
+    @project ||= Project.find_by_name("Community")
+  end
+end
+
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index 67e14121c6d420b062abb2ca396b27364add8d90..eb91ed2373735b6445a4d44b829ed17fbbebce19 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -275,6 +275,10 @@ module SharedPaths
     visit public_root_path
   end
 
+  step 'I visit public page for "Community" project' do
+    visit public_project_path(Project.find_by_name("Community"))
+  end
+
   # ----------------------------------------
   # Snippets
   # ----------------------------------------