1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>PyGitWeb</title>
<meta name="description" content="Self-host git repositories with boards, tasks, Smart HTTP, and metadata stored in your repo. A Python forge built with FastAPI and Tabler.">
<script>
document.documentElement.setAttribute(
"data-bs-theme",
window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
);
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function (e) {
document.documentElement.setAttribute("data-bs-theme", e.matches ? "dark" : "light");
});
</script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="tabler.min.css">
<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="landing.css">
<link rel="icon" href="logo.svg" type="image/svg+xml">
<style>
:root {
--tblr-font-sans-serif: "Fira Sans", system-ui, sans-serif;
--tblr-font-monospace: "Fira Code", ui-monospace, monospace;
--tblr-primary: var(--pgw-theme-slate, #66717e);
--tblr-primary-fg: #fff;
--tblr-link-color: var(--pgw-link);
--tblr-link-hover-color: var(--pgw-link-hover);
--tblr-body-bg: var(--pgw-bg);
--tblr-body-color: var(--pgw-text);
--tblr-bg-surface: var(--pgw-bg-raised);
--tblr-bg-surface-secondary: var(--pgw-bg-muted);
--tblr-border-color: var(--pgw-border);
--tblr-secondary: var(--pgw-text-muted);
}
</style>
</head>
<body class="landing">
<a class="skip-link" href="#main">Skip to content</a>
<header class="navbar navbar-expand-md sticky-top landing-nav">
<div class="container-xl">
<a class="navbar-brand navbar-brand-autodark d-flex align-items-center" href="/">
<img src="logo.svg" width="32" height="32" alt="" class="navbar-brand-image">
<span class="ms-2">PyGitWeb</span>
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#landing-nav" aria-controls="landing-nav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="landing-nav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="#features">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#apart">Why</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#start">Get started</a>
</li>
</ul>
<div class="nav-item ms-md-3 mt-2 mt-md-0">
<a class="btn btn-primary" href="https://app.pygitweb.com">Open the demo</a>
</div>
</div>
</div>
</header>
<header class="hero" aria-labelledby="site-title">
<div class="hero__wash" aria-hidden="true"></div>
<div class="container-xl hero__inner">
<img src="logo.svg" alt="" width="128" height="128" class="hero__logo">
<p class="hero__version text-secondary">v0.3.1</p>
<h1 id="site-title" class="hero__title">PyGitWeb</h1>
<p class="hero__tagline">Self-hosted project hosting with git as the database</p>
<p class="hero__lede text-secondary">
A FastAPI-based forge for small teams: repositories, sprint boards, tasks, Smart HTTP, and OAuth -
with merge requests and metadata living in your object store.
</p>
<div class="hero__actions btn-list">
<a class="btn btn-primary btn-lg" href="https://app.pygitweb.com">See it in action</a>
<a class="btn btn-outline-secondary btn-lg" href="#start">Install with uv</a>
</div>
</div>
</header>
<main id="main">
<section id="what" class="section section--muted">
<div class="container-xl">
<div class="row justify-content-center">
<div class="col-lg-8 text-center">
<h2 class="section__heading">What is PyGitWeb?</h2>
<p class="text-secondary mb-0">
Everything you need to self-host a code forge for individuals and small or medium-sized teams with OAuth2 or local-auth flows.
The UI follows <a href="https://docs.tabler.io/ui">Tabler</a>, the same kit used in the app itself.
</p>
</div>
</div>
</div>
</section>
<section id="features" class="section">
<div class="container-xl">
<div class="text-center mb-5">
<h2 class="section__heading">Built for modern workflows</h2>
<p class="text-secondary mb-0">Current through 0.3.x - boards, Smart HTTP, plugins, and a terminal companion.</p>
</div>
<div class="row g-4">
<div class="col-md-6 col-lg-4">
<div class="feature">
<span class="feature__icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 4m0 1a1 1 0 0 1 1 -1h14a1 1 0 0 1 1 1v14a1 1 0 0 1 -1 1h-14a1 1 0 0 1 -1 -1z" /><path d="M9 8v7" /><path d="M15 8v4" /></svg>
</span>
<h3 class="feature__title">Sprint boards & tasks</h3>
<p class="feature__desc text-secondary mb-0">Kanban boards with Fibonacci story points, board switching, archive and delete, plus task search by tag or commit.</p>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="feature">
<span class="feature__icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M7 8l-4 4l4 4" /><path d="M17 8l4 4l-4 4" /><path d="M14 4l-4 16" /></svg>
</span>
<h3 class="feature__title">Smart HTTP</h3>
<p class="feature__desc text-secondary mb-0">Clone and push over HTTP with scoped keys. Ref push rules cover branches, tags, and notes.</p>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="feature">
<span class="feature__icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 3l8 4.5l0 9l-8 4.5l-8 -4.5l0 -9l8 -4.5" /><path d="M12 12l8 -4.5" /><path d="M12 12l0 9" /><path d="M12 12l-8 -4.5" /></svg>
</span>
<h3 class="feature__title">Metadata in git</h3>
<p class="feature__desc text-secondary mb-0">Settings, merge requests, comments, and tasks live in the repository object database. Discover work with a fetch - no separate DB service.</p>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="feature">
<span class="feature__icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M12 10m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" /><path d="M6.168 18.849a4 4 0 0 1 3.832 -2.849h4a4 4 0 0 1 3.834 2.855" /></svg>
</span>
<h3 class="feature__title">OAuth & permissions</h3>
<p class="feature__desc text-secondary mb-0">Sign in with an identity provider or local accounts. Project read gates visibility; write grants cover branches and arbitrary refs.</p>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="feature">
<span class="feature__icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 20h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4" /><path d="M13.5 6.5l4 4" /></svg>
</span>
<h3 class="feature__title">Plugins & blogs</h3>
<p class="feature__desc text-secondary mb-0">Enable or disable plugins from settings with protocol checks. Render a project's markdown blog with archive, search, and assets.</p>
</div>
</div>
<div class="col-md-6 col-lg-4">
<div class="feature">
<span class="feature__icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 7l5 5l-5 5" /><path d="M12 19l7 0" /></svg>
</span>
<h3 class="feature__title">pgt terminal UI</h3>
<p class="feature__desc text-secondary mb-0">Browse repos, stage and commit, switch worktrees, run project actions, and manage tasks from the CLI - no web server required.</p>
</div>
</div>
</div>
</div>
</section>
<section id="apart" class="section section--muted">
<div class="container-xl">
<div class="row justify-content-center">
<div class="col-lg-8">
<h2 class="section__heading text-center">What sets it apart?</h2>
<blockquote class="pullquote">
<p>All project metadata is stored in-situ; discovering new merge requests and tasks is just a git fetch.</p>
</blockquote>
<p class="text-secondary mb-0 text-center">
PyGit2 powers the shared tooling package, so you can script workflows without bringing up the web server.
An ABC-based plugin model lets you extend the stack when you need to.
</p>
</div>
</div>
</div>
</section>
<section id="start" class="section">
<div class="container-xl">
<div class="row justify-content-center">
<div class="col-lg-8">
<h2 class="section__heading text-center">Get started</h2>
<p class="text-secondary text-center">
Run with uv in bash or PowerShell. By default you get local auth and an <code>admin</code> account with a random password.
</p>
<pre class="install-snippet"><code>uv run --with pygitweb uvicorn pygitweb.main:app</code></pre>
<p class="text-secondary text-center small mb-3">
PGW uses Pydantic for configs: set <code>PYGITWEB_AUTH=0</code> if all connections are trusted.
</p>
<div class="text-center">
<a class="btn btn-primary" href="https://app.pygitweb.com">Try the hosted demo</a>
</div>
</div>
</div>
</div>
</section>
<section id="audience" class="section section--muted">
<div class="container-xl">
<div class="row justify-content-center">
<div class="col-lg-8 text-center">
<h2 class="section__heading">Design Philosophy</h2>
<p class="text-secondary mb-0">
PyGitWeb is built for personal projects and small teams that want a place to host repos and organize tasks.
Designed for light, efficient workflows - so you can stay focused on the work in the repo.
</p>
</div>
</div>
</div>
</section>
</main>
<footer class="footer footer-transparent landing-footer">
<div class="container-xl">
<div class="row text-center align-items-center flex-row-reverse">
<div class="col-lg-auto ms-lg-auto">
<ul class="list-inline list-inline-dots mb-0">
<li class="list-inline-item">
<a href="https://app.pygitweb.com" class="link-secondary">Demo</a>
</li>
<li class="list-inline-item">
<a href="https://docs.tabler.io/ui" class="link-secondary">Tabler UI</a>
</li>
</ul>
</div>
<div class="col-12 col-lg-auto mt-3 mt-lg-0">
<p class="mb-0 text-secondary">
PyGitWeb <code>© 2026 Will Bowers & Contributors</code>
</p>
</div>
</div>
</div>
</footer>
<script defer src="tabler.min.js"></script>
</body>
</html>