Pages open in Live mode, where every line is rendered except the one being edited, with Edit (plain markdown) and View (fully rendered) beside it. Arrow keys, Backspace and Delete move between lines, code blocks are edited as a whole, and edits are spliced back into the one text the rest of the editor already saves. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
192 lines
9.3 KiB
Markdown
192 lines
9.3 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.
|
|
- **Live, Edit or View.** Live is the default: every line shows rendered except the one you are on,
|
|
which shows its markdown, as in Obsidian's live preview. Edit shows the whole page as plain
|
|
markdown, and View shows the whole page rendered, with tasks you can tick and links you can follow.
|
|
Click a page in View to start writing. Ctrl+E switches between editing and View.
|
|
- **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.
|
|
- Live preview works a line at a time (a code block counts as one), so a table or a quote spread over
|
|
several lines shows rendered line by line. View shows the whole page as one.
|
|
|
|
## 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)).
|