mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
feat(gtm): round 3 — never default a stranger into a dead cloud
Reviewer round 3 (9/7/9/8/7/9) caught the sharpest truth bug yet: the
README quickstart's bare 'bdrive login' defaults to beardrive.ai, which
is waitlist-only and not accepting logins — a launch-day visitor's
first command would fail silently. Fixes:
- quickstart step 1 now routes to self-hosting ('bdrive login
https://your-hub', ~10-minute guide linked) with Cloud honestly
framed as waitlist; website closer promises 'Self-host in one
binary' instead of 'under a minute, done'
- handoff gains a P0 gate: verify the FULL first run (login → init →
edit → log) against a working hub before any launch; bare 'bdrive
login' must not be advertised until Cloud accepts logins
- handoff: seed 3-5 good-first-issues (CONTRIBUTING promises them);
replace the mailto waitlist with a real form before Product Hunt
- README trimmed 583→524 lines: the Authentication and Choosing-a-
database operator reference moved verbatim into docs/self-hosting.md
with a compact pointer left behind
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P5cxPQdSGJnjXCYY9GeWXt
This commit is contained in:
co-authored by
Claude Fable 5
parent
71e8a49666
commit
3422d3509f
@@ -82,9 +82,11 @@ go install github.com/runbear-io/beardrive/cmd/bdrive@latest
|
||||
## Quick start
|
||||
|
||||
```sh
|
||||
# 1. Sign this device in (once). Default server: beardrive.ai;
|
||||
# self-hosters pass their own URL.
|
||||
bdrive login
|
||||
# 1. Sign this device in against your hub (once per device).
|
||||
# Self-host a hub in ~10 minutes (docs/self-hosting.md), then:
|
||||
bdrive login https://your-hub
|
||||
# (BearDrive Cloud — zero-setup, bare `bdrive login` — is coming;
|
||||
# join the waitlist at beardrive.ai. Self-host to try it today.)
|
||||
|
||||
# 2. Start syncing a project — interactive: create or connect a project,
|
||||
# sync the whole folder or just ./shared. Re-run any time to resume.
|
||||
@@ -360,77 +362,18 @@ distinct-reader counts, and last-read times — never who read what;
|
||||
`?by=device` adds the agent-only per-device folder breakdown (device
|
||||
identity is already public via history; human emails never appear).
|
||||
|
||||
### Authentication
|
||||
### Authentication & database
|
||||
|
||||
Hubs always require sign-in — every change is attributed to a real account.
|
||||
The whole API — web UI, uploads, project creation, device sync — needs a
|
||||
session; only `/api/config` and the auth pages stay open (the plain-folder
|
||||
viewer, `bdrive web ./folder`, remains auth-free). Accounts are
|
||||
email + password + name, kept in a file-backed registry (`auth.json`:
|
||||
bcrypt password hashes and SHA-256 token digests, atomically rewritten —
|
||||
no plaintext credentials ever touch disk).
|
||||
Hubs always require sign-in — every change is attributed to a real
|
||||
account. **Signup is invite-only by default** (the safe posture for a
|
||||
public URL); self-service signup opens only with a gate (admin approval,
|
||||
or allowed domains + email verification). Hub metadata (accounts,
|
||||
projects, orgs, shares) lives in a file-backed store by default, or
|
||||
SQLite/Postgres (incl. Supabase) via the `database` config block.
|
||||
|
||||
**Signup is invite-only by default** — the safe posture for a hub on a
|
||||
public URL. New people get in only through an expiring invite link an owner
|
||||
mints; the link lets them create an account (bypassing the gates below) and
|
||||
join, in one step. To allow self-service signup instead, set
|
||||
`"allow_signup": true` **with a gate** — the server refuses to start an open
|
||||
hub that has none, so a fake email can never just walk in. Three postures:
|
||||
Full reference — the three signup postures, SMTP, admins, CLI device
|
||||
sign-in, and database selection: **[docs/self-hosting.md](docs/self-hosting.md)**.
|
||||
|
||||
- **Invite-only** (default): `allow_signup` unset/false. Only invite links create accounts.
|
||||
- **Approval-gated**: `allow_signup: true` + `require_approval: true` — anyone can sign up, but a hub admin approves each new account before it works (no SMTP needed).
|
||||
- **Domain-restricted + verified**: `allow_signup: true` + `allowed_domains: ["you.com"]` + `require_verification: true` (needs `smtp`) — only your company's addresses may sign up, each confirming an emailed link. Verification without SMTP is refused (the link would otherwise only reach the server log).
|
||||
|
||||
Admins tune verification/approval live from the web UI (**Admin → Signup &
|
||||
access**); `allowed_domains`, the admin list, and `allow_signup` are
|
||||
server-config-owned so a browser session can never widen who gets in.
|
||||
|
||||
`bdrive login <url>` on a client device opens the server's sign-in page in
|
||||
a browser (sign up right there if needed); when the user signs in, the
|
||||
page bounces a one-time code to the CLI's loopback listener and the
|
||||
terminal finishes on its own, storing a long-lived per-device token
|
||||
(revocable server-side). On headless/SSH machines, `bdrive login --device`
|
||||
prints a short code to approve from any signed-in browser instead. Every
|
||||
sync and every `bdrive init` then authenticates with that token.
|
||||
|
||||
"Forgot password" emails a one-hour reset link via the `auth.smtp` block —
|
||||
plain SMTP, so any provider works. With no SMTP configured, the link is
|
||||
printed to the server log so an admin can hand it over; reset is never
|
||||
fully broken.
|
||||
|
||||
Two notes: put a hub behind TLS (reverse proxy
|
||||
or tailscale) — `bdrive login` warns when signing in over plain http to a
|
||||
non-localhost address. Internally all of this sits behind an
|
||||
`AuthProvider` interface; the open-source server ships the built-in
|
||||
email/password provider, and alternative identity backends can be swapped
|
||||
in without touching the CLI or the API.
|
||||
|
||||
### Choosing a database
|
||||
|
||||
A hub keeps a little **metadata** — accounts, projects, orgs, invites,
|
||||
shares, devices — separate from your files. (File content and the sync
|
||||
journals always live in the object store; the database never holds them.)
|
||||
You choose where that metadata lives with the `database` block:
|
||||
|
||||
```jsonc
|
||||
"database": { "driver": "file" } // default — JSON under BDRIVE_HOME
|
||||
"database": { "driver": "sqlite", "dsn": "/var/lib/bdrive/hub.db" }
|
||||
"database": { "driver": "postgres", "dsn": "postgres://…@…pooler.supabase.com:6543/postgres" }
|
||||
```
|
||||
|
||||
- **file** (default): zero dependencies, human-readable JSON, perfect for a
|
||||
laptop or a small self-hosted hub.
|
||||
- **sqlite**: one embedded database file — a real DB locally with no server
|
||||
to run.
|
||||
- **postgres**: a managed Postgres such as **Supabase** for production —
|
||||
just point `dsn` at its connection string (use the transaction pooler for
|
||||
many connections). Since Supabase *is* Postgres, this stays fully
|
||||
open-source with no managed-only lock-in.
|
||||
|
||||
`file` and `sqlite` are single-writer (run one hub instance); Postgres is
|
||||
transactional and can back more than one instance. Switching backends
|
||||
doesn't migrate existing data — pick one when you set the hub up. Both SQL
|
||||
drivers are pure Go, so the binary stays a CGO-free static build.
|
||||
|
||||
### Uploads
|
||||
|
||||
|
||||
+22
-9
@@ -25,10 +25,21 @@ Draft copy is ready to paste; adjust voice as you like.
|
||||
bdrive version`, and `go install
|
||||
github.com/runbear-io/beardrive/cmd/bdrive@latest`. If the tap is
|
||||
stale, cut a fresh `goreleaser release` first.
|
||||
6. **Verify the full first run, not just the binary**: on a clean
|
||||
machine, `bdrive login <a working hub> && bdrive init && edit a file
|
||||
&& bdrive log` must succeed end to end. Until BearDrive Cloud is
|
||||
live, every try-path (README, website, launch posts) must route
|
||||
people to self-hosting — bare `bdrive login` defaults to
|
||||
beardrive.ai and MUST NOT be advertised until that hub actually
|
||||
accepts logins. Gate any launch on this check.
|
||||
7. **Seed 3–5 `good first issue` / `help wanted` issues** from
|
||||
ROADMAP.md (more agent platforms in `bdrive hooks install`; per-path
|
||||
access scopes design discussion; demo assets; docs gaps) —
|
||||
CONTRIBUTING.md promises curated starter issues; make it true.
|
||||
|
||||
## P1 — demo assets (an hour)
|
||||
|
||||
6. **Record a 45–60s demo GIF/video** for the README hero and any
|
||||
8. **Record a 45–60s demo GIF/video** for the README hero and any
|
||||
launch post. Script (uses two terminals + a browser):
|
||||
- T1: `bdrive init --name demo --yes` in a folder with a few notes →
|
||||
show `bdrive status` (daemon running).
|
||||
@@ -40,29 +51,31 @@ Draft copy is ready to paste; adjust voice as you like.
|
||||
- T1: `bdrive share wiki/findings.md` → open the public URL.
|
||||
Tools: `vhs` (charmbracelet) or QuickTime + gifski. Put the result at
|
||||
`docs/assets/demo.gif` and add it above the fold in README.
|
||||
7. **Verify beardrive.ai serves the updated landing page** (the repo's
|
||||
9. **Verify beardrive.ai serves the updated landing page** (the repo's
|
||||
`website/` — including the new `assets/insights.png`) after the next
|
||||
deploy.
|
||||
|
||||
## P2 — when you're ready to be seen (launch window)
|
||||
|
||||
8. **Show HN post** — full drafts in [launch-plan.md](launch-plan.md):
|
||||
10. **Show HN post** — full drafts in [launch-plan.md](launch-plan.md):
|
||||
title, body, and the first-comment founder note. Post from your
|
||||
account; be present for the first 3 hours to answer everything.
|
||||
9. **Product Hunt** — drafts in launch-plan.md. Schedule after HN, not
|
||||
the same day.
|
||||
10. **Claude Code plugin discoverability** — submit/announce the
|
||||
11. **Product Hunt** — drafts in launch-plan.md. Schedule after HN, not
|
||||
the same day. Before PH: replace the mailto waitlist on the site
|
||||
with a real form (any hosted waitlist works) — email-composer
|
||||
friction kills launch-day conversion.
|
||||
12. **Claude Code plugin discoverability** — submit/announce the
|
||||
marketplace entry wherever Anthropic surfaces community plugins
|
||||
(Discord, awesome-lists PRs from your account).
|
||||
|
||||
## P3 — measurement plumbing (see metrics.md)
|
||||
|
||||
11. **Turn on GitHub traffic watching**: stars/clones/views are under
|
||||
13. **Turn on GitHub traffic watching**: stars/clones/views are under
|
||||
Insights → Traffic; consider a weekly note of the numbers in
|
||||
Discussions → Announcements.
|
||||
12. **Homebrew install counts**: `brew info --analytics
|
||||
14. **Homebrew install counts**: `brew info --analytics
|
||||
runbear-io/tap/beardrive` (public analytics take ~30 days to
|
||||
appear).
|
||||
13. **Decide on hub-side opt-in telemetry** (proposal in metrics.md —
|
||||
15. **Decide on hub-side opt-in telemetry** (proposal in metrics.md —
|
||||
requires your explicit approval before any implementation; nothing
|
||||
is wired today).
|
||||
|
||||
@@ -67,6 +67,7 @@ fabricated proof) — record such rejections under Won't-fix with reasons.
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 1 (baseline) | 6 | 4 | 8 | 3 | 3 | 2 | 3 blockers, 3 majors (all fixed this round; screenshots captured from the live demo hub — real UI, not fabricated) |
|
||||
| 2 | 8 | 7 | 9 | 8 | 8 | 8 | 1 major (residual dead-deployment-mode copy ×3 on the site — fixed) + 4 minors fixed; share.png re-captured with real rendered content |
|
||||
| 3 | 9 | 7 | 9 | 8 | 7 | 9 | 1 major (quickstart defaulted into the not-yet-live beardrive.ai — quickstart/closer rewritten to self-host-first, first-run gate added to handoff) + README trimmed 583→524, starter-issues & waitlist handoffs added |
|
||||
|
||||
## Won't-fix / disputed
|
||||
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ CLAUDE.md's invariants. Answer every comment for the first 3 hours.
|
||||
|
||||
**Prep checklist:** install path verified from a clean machine
|
||||
(`brew install runbear-io/tap/beardrive && bdrive version` — a 404 tap on
|
||||
launch day is fatal), demo GIF live in README (handoff #6), Discussions
|
||||
launch day is fatal), full first-run verified against a working hub (handoff #6), demo GIF live in README (handoff #8), Discussions
|
||||
enabled, `docs/self-hosting.md` linked from README, hub demo instance
|
||||
warm (expect self-host attempts within minutes).
|
||||
|
||||
|
||||
+2
-2
@@ -17,8 +17,8 @@ within a week. Everything else is upstream of it.
|
||||
|
||||
| # | Metric | Source | Stage |
|
||||
|---|---|---|---|
|
||||
| 1 | README/landing views → GitHub stars | GitHub Insights → Traffic (handoff #11) | attention |
|
||||
| 2 | Installs: brew + `go install` | brew analytics (handoff #12); go proxy stats are noisy — treat as directional | acquisition |
|
||||
| 1 | README/landing views → GitHub stars | GitHub Insights → Traffic (handoff #13) | attention |
|
||||
| 2 | Installs: brew + `go install` | brew analytics (handoff #14); go proxy stats are noisy — treat as directional | acquisition |
|
||||
| 3 | Activation: `bdrive init` → first successful sync | today: anecdotal/self-reported; future: opt-in telemetry (below) | activation |
|
||||
| 4 | Team formation: project gains a 2nd member (invite redeemed) | hub data (self-hosted: invisible to us; beardrive.ai once live) | expansion |
|
||||
| 5 | Wedge proof: first agent read-telemetry event in a project | hub read ledger (same visibility caveat) | wedge |
|
||||
|
||||
+74
-2
@@ -41,8 +41,8 @@ hub over HTTPS.
|
||||
}
|
||||
```
|
||||
|
||||
Full knob reference (allowed domains, email verification via SMTP,
|
||||
admin approval, Postgres/Supabase, share-link rate limits): the
|
||||
Full knob reference for auth and databases: the sections below;
|
||||
share-link rate limits and upload TTLs: the
|
||||
[README's web-server section](../README.md#web-server).
|
||||
|
||||
## 4. Run it
|
||||
@@ -70,6 +70,78 @@ as bearer tokens. For containers, the repo ships a `Dockerfile`
|
||||
copy-paste setup for Claude Code/Cowork, Hermes, and Codex; or run
|
||||
`bdrive hooks install` in the folder.
|
||||
|
||||
## Authentication reference
|
||||
|
||||
Hubs always require sign-in — every change is attributed to a real account.
|
||||
The whole API — web UI, uploads, project creation, device sync — needs a
|
||||
session; only `/api/config` and the auth pages stay open (the plain-folder
|
||||
viewer, `bdrive web ./folder`, remains auth-free). Accounts are
|
||||
email + password + name, kept in a file-backed registry (`auth.json`:
|
||||
bcrypt password hashes and SHA-256 token digests, atomically rewritten —
|
||||
no plaintext credentials ever touch disk).
|
||||
|
||||
**Signup is invite-only by default** — the safe posture for a hub on a
|
||||
public URL. New people get in only through an expiring invite link an owner
|
||||
mints; the link lets them create an account (bypassing the gates below) and
|
||||
join, in one step. To allow self-service signup instead, set
|
||||
`"allow_signup": true` **with a gate** — the server refuses to start an open
|
||||
hub that has none, so a fake email can never just walk in. Three postures:
|
||||
|
||||
- **Invite-only** (default): `allow_signup` unset/false. Only invite links create accounts.
|
||||
- **Approval-gated**: `allow_signup: true` + `require_approval: true` — anyone can sign up, but a hub admin approves each new account before it works (no SMTP needed).
|
||||
- **Domain-restricted + verified**: `allow_signup: true` + `allowed_domains: ["you.com"]` + `require_verification: true` (needs `smtp`) — only your company's addresses may sign up, each confirming an emailed link. Verification without SMTP is refused (the link would otherwise only reach the server log).
|
||||
|
||||
Admins tune verification/approval live from the web UI (**Admin → Signup &
|
||||
access**); `allowed_domains`, the admin list, and `allow_signup` are
|
||||
server-config-owned so a browser session can never widen who gets in.
|
||||
|
||||
`bdrive login <url>` on a client device opens the server's sign-in page in
|
||||
a browser (sign up right there if needed); when the user signs in, the
|
||||
page bounces a one-time code to the CLI's loopback listener and the
|
||||
terminal finishes on its own, storing a long-lived per-device token
|
||||
(revocable server-side). On headless/SSH machines, `bdrive login --device`
|
||||
prints a short code to approve from any signed-in browser instead. Every
|
||||
sync and every `bdrive init` then authenticates with that token.
|
||||
|
||||
"Forgot password" emails a one-hour reset link via the `auth.smtp` block —
|
||||
plain SMTP, so any provider works. With no SMTP configured, the link is
|
||||
printed to the server log so an admin can hand it over; reset is never
|
||||
fully broken.
|
||||
|
||||
Two notes: put a hub behind TLS (reverse proxy
|
||||
or tailscale) — `bdrive login` warns when signing in over plain http to a
|
||||
non-localhost address. Internally all of this sits behind an
|
||||
`AuthProvider` interface; the open-source server ships the built-in
|
||||
email/password provider, and alternative identity backends can be swapped
|
||||
in without touching the CLI or the API.
|
||||
|
||||
## Choosing a database
|
||||
|
||||
A hub keeps a little **metadata** — accounts, projects, orgs, invites,
|
||||
shares, devices — separate from your files. (File content and the sync
|
||||
journals always live in the object store; the database never holds them.)
|
||||
You choose where that metadata lives with the `database` block:
|
||||
|
||||
```jsonc
|
||||
"database": { "driver": "file" } // default — JSON under BDRIVE_HOME
|
||||
"database": { "driver": "sqlite", "dsn": "/var/lib/bdrive/hub.db" }
|
||||
"database": { "driver": "postgres", "dsn": "postgres://…@…pooler.supabase.com:6543/postgres" }
|
||||
```
|
||||
|
||||
- **file** (default): zero dependencies, human-readable JSON, perfect for a
|
||||
laptop or a small self-hosted hub.
|
||||
- **sqlite**: one embedded database file — a real DB locally with no server
|
||||
to run.
|
||||
- **postgres**: a managed Postgres such as **Supabase** for production —
|
||||
just point `dsn` at its connection string (use the transaction pooler for
|
||||
many connections). Since Supabase *is* Postgres, this stays fully
|
||||
open-source with no managed-only lock-in.
|
||||
|
||||
`file` and `sqlite` are single-writer (run one hub instance); Postgres is
|
||||
transactional and can back more than one instance. Switching backends
|
||||
doesn't migrate existing data — pick one when you set the hub up. Both SQL
|
||||
drivers are pure Go, so the binary stays a CGO-free static build.
|
||||
|
||||
## Upgrading
|
||||
|
||||
`brew upgrade beardrive` (clients and hub are the same binary — keep
|
||||
|
||||
+2
-2
@@ -494,8 +494,8 @@ every tool works content-addressed blobs append-only, no locks, offl
|
||||
|
||||
<section class="closer">
|
||||
<div class="wrap">
|
||||
<h2>Share files. Share context.<br><span class="green">Set up in under a minute.</span></h2>
|
||||
<p>brew install, bdrive init, done. Files travel to people as URLs; context travels to every agent on the team.</p>
|
||||
<h2>Share files. Share context.<br><span class="green">Self-host in one binary.</span></h2>
|
||||
<p>brew install, run one hub, bdrive init. Files travel to people as URLs; context travels to every agent on the team. Cloud — zero-setup — is on the waitlist.</p>
|
||||
<div class="cta-row">
|
||||
<a class="btn" href="https://github.com/runbear-io/beardrive">Start on GitHub</a>
|
||||
<button class="install" id="install2" title="Copy">
|
||||
|
||||
Reference in New Issue
Block a user