Free, open tools for AI safety
Sandbox AI agents, watch what they do with a hidden Observer, and measure it with evals. Open source, local, with evidence anyone can check.
Free, versioned media storage that is just a GitHub repo you already own. Try the live demo without signing in.
Developer toolsTypeScript · CSSGitHub @satyamkushwaha11OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Turn any GitHub repository into a media bucket. Sign in with GitHub, pick or create a repo, drag files in, browse them in a gallery, and copy permanent links into your site.
1. Create a GitHub OAuth app at https://github.com/settings/developers → New OAuth App:
| Field | Value |
|---|---|
| Homepage URL | http://localhost:3000 |
| Authorization callback URL | http://localhost:3000/api/auth/callback/github |
2. Configure the environment:
cp .env.example .env.local
npx auth secret # writes AUTH_SECRET
Paste your client ID and secret into .env.local as AUTH_GITHUB_ID and
AUTH_GITHUB_SECRET.
3. Run it:
npm install
npm run dev
The sign-in button asks for public_repo only, so the consent screen is as
small as it can be. "Include private repos" asks for repo instead, and a
public-only session can upgrade later from the sidebar. The granted scopes come
back on GitHub's token response and are kept on the session as session.scope;
lib/scopes.ts is the single place that interprets them.
The landing page embeds a read-only copy of the gallery running on
public/demo/, a handful of sample files committed to this repo. Thumbnails are
served by the site itself; "copy link" hands out the real
raw.githubusercontent.com URL for each file. Uploads in the demo are simulated
in the browser and never leave it. Regenerate the sample media and its manifest
with:
NODE_PATH=./node_modules node scripts/gen-demo.cjs
The app stores nothing itself — every action is a GitHub API call made with your OAuth token.
| Action | GitHub API |
|---|---|
| Browse | GET /repos/{o}/{r}/contents/{path}?ref= |
| Upload | PUT /repos/{o}/{r}/contents/{path} (base64) |
| Delete file | DELETE /repos/{o}/{r}/contents/{path} |
| Delete folder | Git Data API — one commit for the whole tree |
| Move / rename | Git Data API — one commit, blob re-pathed |
| Download | Blobs API (private) or raw CDN (public) |
Uploads and deletes are ordinary commits, so the full history stays in the repo.
| URL | Shows |
|---|---|
/ | Landing page (signed-in users go to /vault) |
/vault | Repo picker |
/vault/owner/repo | Repo root on its default branch |
/vault/owner/repo/some/folder | A folder inside it |
…?branch=name | Any non-default branch |
So refresh, back/forward, bookmarks and shared links all land where you expect.
The one real branch in the design, handled in app/api/media/route.ts:
raw.githubusercontent.com. Fast, free,
no server in the path. These are the links worth embedding in a website.app/api/raw/route.ts with your token attached. Links
only resolve for a signed-in session, and every view costs an API call.Git can't represent an empty directory. Creating a folder commits a hidden
.gitkeep inside it, which the UI filters out of listings.
Surfaced in-app too — the ⓘ button in the toolbar shows live storage and API meters, and warns before you hit a wall.
| Limit | Value | Notes |
|---|---|---|
| File size | 95 MB | GitHub hard-caps blobs at 100 MB |
| Oversized images | auto-compressed | re-encoded to WebP/JPEG until they fit |
| Oversized video/GIF/zip | rejected | see below |
| Repo size | 1 GB soft / 5 GB hard | GitHub emails you past 1 GB |
| API requests | 5,000/hour | shared across your token; public views are free |
| Private-repo links | signed-in only | can't be embedded in a public site |
lib/upload-direct.ts), so Vercel's 4.5 MB function
cap never applies. The ceiling is GitHub's, wherever you deploy.app/api/raw/route.ts
implements real 206 Range responses over a cached blob, since GitHub's Blobs
API has no Range support of its own.This is the beginning of the README. Read the rest at the original. Read the full README ↗