AGENTS.md - git - Webernet Explorer _X
git 🏠 Home 👤 Sign up Self hosted git, retro shell
★ otgit, code hosting from the year 2000 ★
📄 octuna / AGENTS.md
263 lines · 10.1 KB · Raw
1# otgit agent rules
2 
3A self-hosted git host with a 1999 Microsoft-era UI. Octuna's CSS shell, otgit's brain.
4Read this file before every change. Follow it without exception.
5 
6## Mission
7 
8Portable, self-hosted, open source git host. Lightweight, low RAM, fast, secure.
9Retro skin, modern feature set covering the must-haves and nothing more.
10Useful enough to pick over a folder of zips. Never bloated.
11 
12## Chosen architecture: layered minimal
13 
14Decided by scored comparison. Raw node `http`, git binary subprocess for all repo
15ops, JSON state with atomic write, scrypt + HMAC session cookies. Logic is split
16into small reusable modules under `lib/` so values, security checks, and git ops
17live in exactly one place. Routes are thin and call into those modules.
18 
19## The five hard limits
20 
211. RAM: server target under 60 MB resident. Cap node heap at 64 MB. No in-memory
22 caches of file contents. Stream everything from disk.
232. Dependencies: at most two runtime npm deps. Default to one (`busboy`). Add a
24 second only if it removes more code than it adds. Never add a framework.
253. Source file size: no file over 400 lines. Plan a split before adding more.
264. CSS: total under 1000 lines across all files. Reuse classes.
275. No hardcoded tunables. Every magic number, path, limit, label, or feature
28 flag comes from `config.get(...)`. If a value would appear in two files, it
29 goes in config or in `lib/`.
30 
31If a change breaks any of these, stop and surface it before continuing.
32 
33## Reusability rule
34 
35If a piece of logic is used twice, it lives in `lib/` and both callers import it.
36If a value is referenced twice, it lives in `config.json` and both callers read
37it through `config.get()`. No exceptions for "it's just a small string". This is
38the rule that prevents drift.
39 
40## File layout
41 
42```
43F:\otgit\
44 server.js boot, register routes, listen
45 setup.js create admin user, generate secrets, write config
46 config.json runtime, generated
47 config.example.json shipped
48 package.json
49 AGENTS.md
50 README.md
51 lib\
52 router.js pattern match, :param compile, dispatch
53 respond.js json, html, text, redirect, security headers
54 auth.js scrypt, HMAC sessions, requireAuth, requireOwner
55 limit.js rate limit factory
56 store.js atomic JSON read, debounced write
57 config.js layered loader, get, set, requiresRestart list
58 git.js spawn wrappers: init, log, tree, blob, diff, etc
59 http-backend.js smart HTTP CGI bridge
60 render.js template fill, html escape, markdown, diff to html
61 validate.js names, paths, schemas, prefix safety
62 log.js small leveled logger
63 routes\
64 auth.js signup, login, logout, me, password
65 user.js user profile and repo list
66 repo.js repo home, tree, blob, history, single commit
67 repo-write.js create, rename, visibility, delete
68 smart-http.js git push and pull
69 admin.js admin settings UI and save
70 static.js cached static asset serve
71 public\
72 style.css shell, ported from Octuna
73 pages.css page specific styles, diff, tree, code
74 app.js shared client glue
75 logo.png from Octuna
76 views\
77 layout.html page chrome with content slot
78 home.html
79 auth.html
80 user.html
81 repo-home.html
82 repo-tree.html
83 repo-blob.html
84 repo-history.html
85 repo-commit.html
86 repo-settings.html
87 admin-settings.html
88 data\
89 users.json
90 repos.json
91 repos\<owner>\<name>.git\
92 scripts\
93 smoke.js end to end smoke test
94```
95 
96## Config schema
97 
98`config.json` is the single source of truth for tunables. Admin web UI writes
99it through `config.set(path, value)` which validates and atomically rewrites
100the file. Fields marked restart in `lib/config.js#REQUIRES_RESTART` show a
101warning in the admin UI.
102 
103```
104site
105 name string display name
106 publicUrl string external URL, controls cookieSecure when auto
107 bindHost string restart
108 port number restart
109 tagline string
110auth
111 sessionSecret base64 restart, generated by setup
112 sessionMaxAgeDays number
113 scryptN number restart effectively, only for new hashes
114 allowSignup bool
115repos
116 maxPerUser number
117 maxRepoSizeMB number
118 defaultVisibility public or private
119 allowPrivate bool
120 defaultBranch string
121limits
122 login { max, windowMin }
123 signup { max, windowMin }
124 write { max, windowMin }
125 push { max, windowMin }
126 uploadMaxMB number
127security
128 trustProxy bool
129 cookieSecure auto or true or false
130 csp string
131ui
132 addressBarMode real or fixed
133 addressBarFixed string
134 marqueeText string
135 footerText string
136 themeColor teal or navy or purple
137git
138 binPath string
139 httpBackendPath string
140admin
141 user string restart on change
142```
143 
144Setup writes `auth.sessionSecret`, `admin.user`, and the admin password hash.
145Every other field has a default in `lib/config.js`.
146 
147## Security rules
148 
149- Passwords: scrypt N=16384, r=8, p=1, 16 byte salt per user, 64 byte hash.
150- Sessions: HMAC SHA256 over `user.issued`, base64url. Verify with
151 `crypto.timingSafeEqual`. Cookie HttpOnly, SameSite=Strict, Secure when
152 publicUrl is https or `security.cookieSecure` is true.
153- Rate limits: every limit value comes from config. No literal numbers in route
154 files. Smart HTTP push gets its own bucket.
155- Path safety: validate owner and repo names against
156 `^[a-z0-9][a-z0-9_-]{0,38}$`. Always `path.resolve` and assert the resolved
157 path starts with the configured repos root.
158- `git http-backend` runs with `GIT_PROJECT_ROOT` pinned to the resolved repo
159 root. Never let request data choose the repo path.
160- Public repo reads anonymous. Private reads and any write require a session
161 whose user owns the repo. Push reuses the login credentials over basic auth.
162- CSP from config. No inline scripts except a single config blob, hashed in
163 CSP. No third party origins.
164- All HTML output escaped. Markdown renderer is a safe subset, no raw HTML.
165- Never `exec`. Always `spawn` with argv arrays.
166- Never log passwords, session tokens, or full cookies.
167- Setup forbids weak admin passwords (length under 10 or in a tiny common list).
168 
169## Performance rules
170 
171- Stream files. Never `readFileSync` a blob to send it.
172- Blob viewer caps render at `repos.maxRenderBlobMB` (default 1). Larger files
173 show metadata and a raw download link only.
174- Diff viewer caps rendered diff at 5000 lines. Larger diffs link to raw.
175- Cache static assets in memory once at boot. Nothing else cached in RAM.
176- Read repo metadata lazily from git. Do not maintain shadow indices.
177 
178## Code style
179 
180- No em dashes anywhere, in code or comments or text. Use commas, periods, or
181 parentheses. The character `—` is banned in this repo.
182- No cheesy AI prose. No "Let's", "I'll go ahead", "Certainly!", no emojis in
183 comments, no decorative banners. Plain, terse, technical.
184- Comments only when the why is non obvious. Never restate the code.
185- Identifiers say what they are. Functions short, under 40 lines. If a handler
186 grows, extract.
187- No abstractions for hypothetical future use. Three similar lines beats a
188 premature helper, but two distinct call sites for the same logic must share.
189- No try catch that swallows. Either handle or let it bubble.
190- No backwards compat shims for code we wrote ourselves yesterday.
191 
192## CSS rules
193 
194- Reuse Octuna's variables and components. Do not redefine the shell tokens.
195- Page specific styles in `pages.css`. `style.css` stays generic.
196- Plain hand written CSS. No framework, no preprocessor.
197- Audit total CSS line count at every change. Hard cap 1000.
198 
199## Self critique protocol
200 
201After every plan, every step, every commit, end with a Critique block:
202 
203```
204Critique:
205- Weakest part of this, specific.
206- Anything that violates the rules: RAM, deps, line count, CSS budget, em dash,
207 cheesy text, hardcoded value, security shortcut.
208- Anything skipped that the spec asked for.
209- Next risk.
210```
211 
212If the critique surfaces a rule violation, fix it before continuing. Do not
213mark a step complete with an open critique item unaddressed.
214 
215## v1 feature checklist
216 
217Must ship:
218- Signup, login, logout, change password
219- Create repo public or private, rename, toggle visibility, delete
220- Repo home: rendered README, file tree, branch dropdown, commit count
221- File tree browser
222- Blob viewer with line numbers and total line count
223- Commit history list and single commit diff view with red and green hunks
224- Push and pull over HTTPS smart protocol with basic auth
225- User profile page listing the user's visible repos
226- Admin settings page with full backend control over config.json
227- Per repo settings page
228- Issues
229- Releases and Source download .zip
230- Stars
231 
232Out of scope:
233- pull requests, stars, forks, webhooks, CI, wikis, gists,
234 organizations, SSH transport, federation.
235 
236If you find yourself building something not on the must ship list, stop.
237 
238## Testing
239 
240- `scripts/smoke.js` hits every route, asserts status codes, exercises a real
241 push and pull against a temp git client. Run after every change.
242- No mocks. Real server, real git, real disk.
243 
244## Build order (suggested, may revise per critique)
245 
2461. Skeleton: `lib/config.js`, `lib/store.js`, `lib/respond.js`, `lib/router.js`,
247 `lib/log.js`, `lib/validate.js`, `server.js` boot.
2482. Auth: `lib/auth.js`, `lib/limit.js`, `routes/auth.js`, `setup.js`, login UI.
2493. Repos read path: `lib/git.js`, `routes/repo.js`, `routes/user.js`, repo
250 views, blob viewer, history, diff.
2514. Repo write path: `routes/repo-write.js`, repo settings view.
2525. Smart HTTP: `lib/http-backend.js`, `routes/smart-http.js`, push and pull.
2536. Admin settings: `routes/admin.js`, admin view.
2547. Theme port: `style.css`, `pages.css`, layout chrome.
2558. Smoke test, RAM check, CSS line audit, doc the README.
256 
257After each step, run smoke and write the critique.
258 
259## When in doubt
260 
261Pick the option with less code, less RAM, less surface area. If two options tie,
262pick the one easier for a stranger to read in five years.
263 
Done 🔒 Internet