Skip to content
/ bits Public

Latest commit

 

History

494 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

#+title:   Bits
#+startup: content

[[https://code.invetica.team/jcf/bits/actions][https://code.invetica.team/jcf/bits/badges/workflows/ci.yml/badge.svg]]

Platforms control your audience. Payment processors control your revenue. Bits
gives you both back.

*What you get:*

- Subscriptions, one-time purchases, digital downloads
- Video hosting and delivery
- Your data, your domain, your rules
- Permissive content policies for persecuted creators

*Why it works:*

- Self-host on a $5/month VPS or use managed hosting
- Single binary deployment - no complex setup
- Built with care to minimize resource usage and maximize reliability
- Source-available - audit the code, modify what you need, contribute back

*The model:* Like WordPress.org - free to self-host, managed option available.
You're never locked in.

*Current state:* Active development. Your funding accelerates delivery.

* CLI
#+begin_src sh :results output verbatim
just cli --no-color --help 2>&1
#+end_src

#+results:
: Usage: bits <command> [options]
:
: Commands:
:   seed   Apply database seeds
:   serve  Start the HTTP server
:   warmup Load classes for AppCDS generation
:
: Run 'bits <command> --help' for command-specific help.

* Development
#+begin_src sh :eval never
just setup  # First time: generates certs, builds container images
just dev    # Starts all services via Docker Compose
#+end_src

All infrastructure runs in Docker containers (built with Nix). The =just dev=
command starts PostgreSQL, Datomic transactor, Jaeger, Traefik, the Clojure
nREPL, and Tailwind CSS watcher.

** HTTPS and =*.localhost= URLs
Subdomains of =localhost= automatically resolve to =127.0.0.1= per RFC 6761 —
no custom DNS resolver needed. Traefik terminates TLS with mkcert certificates.

*** Test
The marketing site and "catch-all" homepage where we have no realm aren't a
priority so will return non-200 status codes.

#+begin_src sh :results output verbatim :shebang "#!/usr/bin/env zsh"
urls=(
  # These will work, provided you've applied the seeds in `bits.dev.realm`.
  https://bits.page.localhost
  https://charlie.bits.page.localhost
  https://jcf.bits.page.localhost
)

for url in $urls; do
  http_code="$(curl --silent --output /dev/null --write-out "%{http_code}" "$url")"
  if [ "$http_code" -eq 200 ]; then
    echo "✅ $url"
  else
    echo "❌ $url ($http_code)"
  fi
done
#+end_src

#+results:
: ✅ https://bits.page.localhost
: ✅ https://charlie.bits.page.localhost
: ✅ https://jcf.bits.page.localhost

And with a non-existent tenant, we expect a 404 response:

#+begin_src sh :results output verbatim
url="https://foo.bits.page.localhost"
http_code="$(curl --silent --output /dev/null --write-out "%{http_code}" "$url")"

if [ "$http_code" -eq 404 ]; then
  echo "✅ $url"
else
  echo "❌ $url ($http_code)"
fi
#+end_src

#+results:
: ✅ https://foo.bits.page.localhost

** Decision records
#+begin_src sh :results output raw :exports output :exports results
fd --type file '\.org$' decisions | while read -r file; do
  title=$(awk -F':[[:space:]]*' 'NR==1 { print $2 }' "$file")
  echo "- [[file:$file][$title]]"
done
#+end_src

#+results:
- [[file:decisions/20251009133634-get-the-message-out.org][Get the message out]]
- [[file:decisions/20251009144920-python-style-environment-variables.org][Python-style environment variables]]
- [[file:decisions/20251118100535-mission-over-saas-startup-playbook.org][Mission over SaaS startup playbook]]
- [[file:decisions/20251119230950-ci-can-wait.org][CI can wait]]
- [[file:decisions/20251129175326-clojure-over-rust.org][Clojure over Rust]]
- [[file:decisions/20260212183128-vanilla-js-over-clojurescript-for-bits-js.org][Vanilla JS over ClojureScript for bits.js]]
- [[file:decisions/20260214190732-datahike-vs-datomic-for-distributed-coordination-appendix-crypto-shredding.org][Crypto-Shredding for GDPR Compliance]]
- [[file:decisions/20260214190732-datahike-vs-datomic-for-distributed-coordination.org][Datahike vs Datomic for distributed coordination]]
- [[file:decisions/20260220174238-body-style-indentation-for-ui-component-functions.org][Body-style indentation for UI component functions]]

** Dev tasks
#+begin_src sh :results output verbatim :exports results
just --list
#+end_src

** SLOC
#+begin_src sh :results output verbatim :exports results
tokei
echo
echo "$(git describe --always --dirty --abbrev=7) @ $(date +"%Y/%m/%d %H:%M")"
#+end_src

#+results:
#+begin_example
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Language              Files        Lines         Code     Comments       Blanks
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Astro                    10          165          139            0           26
 Clojure                  66         6751         5330          505          916
 CSS                       2           84           69            4           11
 Dockerfile                1           82           58            7           17
 Edn                       2          136          121            1           14
 HCL                      12          386          320           13           53
 JavaScript                5          305          250           20           35
 JSON                      4           59           59            0            0
 Just                      1          292          181           61           50
 MDX                       1           56            0           39           17
 Nix                      11         1131          861          122          148
 Org                      15         2335         2039            5          291
 SQL                       4           43           37            0            6
 SVG                       2           12           12            0            0
 TOML                      1           43           38            0            5
 TypeScript                3           36           30            1            5
 XML                       1           18           14            1            3
 YAML                      3         5073         3988            0         1085
─────────────────────────────────────────────────────────────────────────────────
 HTML                      1           76           72            0            4
 |- CSS                    1          171          151            0           20
 (Total)                              247          223            0           24
─────────────────────────────────────────────────────────────────────────────────
 Markdown                  1          404            0          266          138
 |- Clojure                1          238          152           50           36
 |- Org                    1           19           12            0            7
 |- Rust                   1           68           49           10            9
 |- YAML                   1            1            1            0            0
 (Total)                              730          214          326          190
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Total                   146        17984        13983         1105         2896
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

83a623b @ 2026/02/26 23:46
#+end_example

* License
Bits is source-available under the Business Source License 1.1 (BUSL-1.1) and
converts to the GNU Affero General Public License v3.0 or later four years
after each version's first public distribution. A commercial license is
available for organisations that cannot comply with BUSL.

See [[file:LICENSING.org][LICENSING.org]] for terms, rationale, and how to obtain a commercial
license.

* TODOs
#+begin_src sh :results output verbatim :exports results
rg --glob '!README.org' 'TODO|FIXME' </dev/null | sort
#+end_src

#+results:
#+begin_example
src/bits/app.clj:;; TODO Use Malli (or clojure.spec) to coerce and parse/validate configuration.
src/bits/asset.clj:;; TODO Make content-type explicit or more intelligent.
src/bits/brotli.clj:                          ;; TODO: Default buffer size for brotli library, needs to be tuned.
src/bits/middleware.clj:            ;; TODO Rename :sid to :session/id
src/bits/module/creator.clj:        ;; TODO: Real data from database
src/bits/module/creator.clj:     ;; TODO Extract platform/realm domain
src/bits/morph.clj:;; FIXME Relocate `morphable`.
src/bits/schema.clj:   ;; FIXME Avoid stringly typed entities - use `:db/ident`.
src/bits/ui.clj:  ;; TODO: I18n - error presentation
test/bits/session_test.clj:                                           ;; FIXME Remove `:sid` from `data`.
#+end_example

About

Open creator monetisation platform. Find your audience and make money doing what you love.

Resources

Stars

1 star

Watchers

0 watching

Forks

Sponsor this project

Packages

Used by

Contributors

Languages