Sign-in is now OpenID Connect against Authentik (authorization code flow with PKCE, state and nonce). The password, API tokens and the add command are gone; each person who signs in gets a private notebook in a folder named from a hash of who they are. An optional allowed list is checked on every request. Notes become pages with titles, a tree of subpages, [[links]] with backlinks that follow renames, a Ctrl+K finder, slash commands, list continuation, and Write and Read modes. Autosave keeps the text through a dropped connection or an expired session. Export opens as an Obsidian vault. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
189 lines
9.0 KiB
Markdown
189 lines
9.0 KiB
Markdown
# Basking
|
|
|
|
A private notebook in the spirit of Obsidian and Notion, for people who would rather run their own.
|
|
Pages that nest inside each other, `[[links]]` between them with backlinks, a journal page for each
|
|
day, tags, and quick search, all kept as plain markdown files. One small binary, no database, no
|
|
dependencies. You sign in with **Authentik** and nothing else: there are no passwords in Basking.
|
|
|
|
Named for the basking shark, which swims along with its mouth open and takes in whatever drifts by.
|
|
|
|
## What it does
|
|
|
|
- **Pages in a tree.** Give a page a title and it appears in the sidebar. Add a subpage with the `+`
|
|
next to it, or move a page with Move. Delete moves a page to the trash with an Undo, and any
|
|
subpages move up a level so nothing is lost with it.
|
|
- **Link pages with `[[`.** Type `[[` and pick a page, or type a new title to create it. A dashed link
|
|
is a page that does not exist yet; click it and it is made. Each page lists what links to it.
|
|
Rename a page and every `[[link]]` to it is updated.
|
|
- **Type `/` for commands**: headings, to-do lists, quotes, code blocks, dividers, today's date, the
|
|
time. Lists continue when you press Enter and indent with Tab. Ctrl+B and Ctrl+I work as you expect.
|
|
- **Write or Read.** Write shows the markdown; Read shows the page as it will look, with tasks you can
|
|
tick and links you can follow. Click a page in Read to start writing (Ctrl+E switches).
|
|
- **Quick find with Ctrl+K** searches titles and text as you type, and makes a new page if there is no
|
|
match.
|
|
- **A journal.** Today opens the page for the day, with an Insert time button. Days link to each
|
|
other: `[[2026-10-31]]` goes to that day.
|
|
- **Quick notes.** The box on Home takes a thought in two keystrokes (`n`, then Ctrl+Enter). They stay
|
|
out of the sidebar until you give them a title.
|
|
- **Tags by typing.** Write `#errands` or `#projects/basking` anywhere. Numbers such as `#12` and
|
|
anything in code are left alone.
|
|
- **Autosave that does not lose things.** Changes save as you type. If the connection drops, Basking
|
|
keeps your text and retries. If your Authentik session ends mid-sentence, it keeps the text, offers
|
|
to sign in again in another tab, and saves when you are back. If a page changed on another device,
|
|
it asks which version to keep instead of overwriting.
|
|
- **Take it with you.** Download everything as a zip that opens as a vault in Obsidian: file names are
|
|
titles, so the links keep working, and journal days sit in a Journal folder.
|
|
|
|
## Signing in with Authentik
|
|
|
|
Basking never sees a password. Who may open it is decided in Authentik, and each person gets a
|
|
notebook that only they can read.
|
|
|
|
1. In Authentik, go to **Applications → Providers → Create** and choose **OAuth2/OpenID Provider**.
|
|
Set the client type to **Confidential**, add the redirect URI (strict)
|
|
`https://notes.example.com/auth/callback` (use the address you will open Basking at), and keep the
|
|
default scopes (openid, profile, email).
|
|
2. **Applications → Create**: name it Basking and pick that provider. To limit who can open it, bind a
|
|
user or group to the application.
|
|
3. Copy the provider's **Client ID** and **Client Secret**, and note its **OpenID Configuration
|
|
Issuer**, which looks like `https://auth.example.com/application/o/basking/`.
|
|
4. Give Basking those four things (see below), then run `basking check`. It tells you whether
|
|
Authentik answers and what redirect URI to allow.
|
|
|
|
Basking asks for the `openid profile email` scopes and uses the authorization code flow with PKCE, a
|
|
`state` and a `nonce`. Whoever Authentik lets into the application can sign in; to be stricter, list
|
|
people under `allowed` (emails or usernames), and Basking turns anyone else away even if Authentik
|
|
lets them through.
|
|
|
|
## Installing on Linux (systemd)
|
|
|
|
```sh
|
|
curl -fsSL https://git.veillax.com/Veillax/basking/raw/branch/main/deploy/install.sh | sudo sh
|
|
```
|
|
|
|
This downloads the latest release (checking its SHA-256), installs `/usr/local/bin/basking`, creates a
|
|
`basking` user, `/etc/basking/` (settings) and `/var/lib/basking/` (your notes), and writes the
|
|
systemd service and `/etc/basking/basking.env`. Then:
|
|
|
|
```sh
|
|
sudoedit /etc/basking/basking.env # fill in the four Authentik lines at the top
|
|
sudo systemctl start basking
|
|
journalctl -u basking -f # it says at once if a setting is missing or wrong
|
|
```
|
|
|
|
Basking listens on `127.0.0.1:8490`. Put an HTTPS reverse proxy (or
|
|
[Hammerhead](https://git.veillax.com/Veillax/hammerhead)) in front of it and open the address you gave
|
|
as `BASKING_PUBLIC_URL`. Authentik will only send people back to an address you allowed, and cookies
|
|
are marked Secure when that address is https.
|
|
|
|
Run the installer again to upgrade; your settings and notes are kept and a running service is
|
|
restarted. Options: `--start`, `--version v0.1.0`, `--listen 127.0.0.1:8490`, `--source` (build with Go
|
|
instead) and `--uninstall` (add `--purge` to delete settings and notes). Read it first if you like:
|
|
[`deploy/install.sh`](deploy/install.sh).
|
|
|
|
## Running it by hand or in Docker
|
|
|
|
```sh
|
|
export BASKING_PUBLIC_URL=https://notes.example.com
|
|
export BASKING_OIDC_ISSUER=https://auth.example.com/application/o/basking/
|
|
export BASKING_OIDC_CLIENT_ID=...
|
|
export BASKING_OIDC_CLIENT_SECRET=...
|
|
./basking check # optional: test the settings
|
|
./basking serve
|
|
```
|
|
|
|
Docker: see [`Dockerfile`](Dockerfile) and [`deploy/docker-compose.yml`](deploy/docker-compose.yml).
|
|
|
|
### Commands
|
|
|
|
```
|
|
basking serve [-config basking.json] [-listen addr] [-data dir]
|
|
basking check [-config basking.json] test the Authentik settings without starting
|
|
basking version
|
|
```
|
|
|
|
## Settings
|
|
|
|
Everything can be set with environment variables, which win over the settings file and are never
|
|
written to it:
|
|
|
|
| Setting | Variable | |
|
|
| --- | --- | --- |
|
|
| `public_url` | `BASKING_PUBLIC_URL` | where you open Basking, no path |
|
|
| `oidc.issuer` | `BASKING_OIDC_ISSUER` | the provider's issuer |
|
|
| `oidc.client_id` | `BASKING_OIDC_CLIENT_ID` | |
|
|
| `oidc.client_secret` | `BASKING_OIDC_CLIENT_SECRET` | |
|
|
| `allowed` | `BASKING_ALLOWED` | optional; emails, usernames or Authentik ids, comma separated |
|
|
| `listen` | `BASKING_LISTEN` | default `127.0.0.1:8490` |
|
|
| `data_dir` | `BASKING_DATA` | default `data` |
|
|
|
|
`basking.json` also holds a `secret` that signs session cookies. It is made on first run and written
|
|
with mode `0600`. Changing it signs everyone out.
|
|
|
|
## Where your notes are
|
|
|
|
```
|
|
data/users/<hash of who you are>/
|
|
owner.txt your name and email, so the folder can be matched to a person
|
|
notes/20261031-143205-a1b2c3.md one file per page
|
|
notes/daily-2026-10-31.md the journal page for a day
|
|
trash/ deleted pages, until the trash is emptied
|
|
```
|
|
|
|
A page file looks like this, so you can edit it with anything:
|
|
|
|
```
|
|
---
|
|
title: "Trip to Lisbon"
|
|
parent: 20261030-091200-ffee11
|
|
created: 2026-10-31T14:32:05.123Z
|
|
updated: 2026-10-31T14:35:00.456Z
|
|
pinned: true
|
|
---
|
|
|
|
Flights and hotels, see [[Packing list]] #travel
|
|
```
|
|
|
|
A plain `.md` file dropped into `notes/` is picked up too, with its file time as its date (name it with
|
|
lower-case letters, numbers and dashes). Restart Basking to see files added by hand.
|
|
|
|
## Security notes
|
|
|
|
- Sign-in is Authentik only: the authorization code flow with PKCE, `state` and `nonce`, over https. The
|
|
ID token comes straight from Authentik's token endpoint, and its issuer, audience, expiry and nonce
|
|
are checked. Authentik and Basking must be reachable over https unless both are on the same machine.
|
|
- Sessions are `HttpOnly`, `SameSite=Lax` cookies that last 14 days, signed with the secret in the
|
|
settings file. Nothing is kept on the server, so a restart does not sign anyone out. The `allowed`
|
|
list is checked on every request.
|
|
- Each person's folder is named from a hash of who they are, never from anything they typed. One
|
|
person's requests can only ever reach their own folder.
|
|
- Every change from the browser needs a header a page on another site can't send. The page has a strict
|
|
Content-Security-Policy, and pages are never rendered as HTML.
|
|
- Pages are **not encrypted** on disk. Anyone who can read the server's disk can read them.
|
|
|
|
## Honest limits
|
|
|
|
- No sharing or real-time collaboration: each notebook has one reader.
|
|
- No attachments or images, and no offline mode; it needs the server to be reachable.
|
|
- No scripts or tokens for posting notes from elsewhere: Authentik is the only way in.
|
|
- Searching holds every page in memory, which is comfortable for tens of thousands of pages and not
|
|
built for millions.
|
|
- Pages are only reloaded from disk when Basking starts.
|
|
- Write mode is plain markdown, not a block editor. Read mode shows how it looks.
|
|
|
|
## Design
|
|
|
|
The interface follows the Lightwell design language, the same one Hammerhead and Megalodon use. See
|
|
[docs/design.md](docs/design.md). `node scripts/lint-design.mjs` checks the rules a machine can check.
|
|
|
|
## Development
|
|
|
|
```sh
|
|
go test ./...
|
|
go run ./cmd/basking serve # with the BASKING_* variables set
|
|
```
|
|
|
|
Releases are built by the Gitea workflow when a `v*` tag is pushed.
|
|
|
|
Licensed under the AGPL-3.0 (see [LICENSE](LICENSE)).
|