select plan, count(*) from signups group by plan;
plan | count ------+------- free | 1204 pro | 187
import pandas as pd
df = pd.read_csv("signups.csv")
print(df["source"].mode()[0])newsletter
p99 alarm at 09:12. Working it from this note — playbook in . #api
kubectl top pods -n api --sort-by=cpu | head -4
One replica is hot: x2vn at 912m CPU, its siblings near 140m.
from statistics import quantiles
q = quantiles([float(x) for x in open("p99_samples.txt")], n=100)
print(f"p50 {q[49]:.0f} ms · p99 {q[98]:.0f} ms")Confirmed: p99 at 2.1 s against the 120 ms baseline. Restarted x2vn at 09:31; recovering.
Write an incident update from this note for #api-oncall
Ledge is a Markdown notebook for developers and DevOps. Write a note, press ⌘↩ on a code block, and its output streams in beneath it. In your shell, in your project, on your machine, or on a server.
curl -fsSL https://ledge.sh/server.sh | shShell blocks run in a persistent shell that belongs to the note. A cd, an exported variable, or an activated virtualenv carries into the next run.
sudo password or a [y/N] in the output panel.cwd: and env: in the frontmatter set where the note's shells start and what they carry.norun on a fence takes the Run button away. Use it for a command you are quoting, not running.Totals drift by a cent on partial refunds. Repro first. #billing
cd services/billing && source .venv/bin/activate
pytest -q --tb=no tests/test_refunds.py
Point Ledge at a machine over ssh and the notes live there. The server holds the files and runs the shells. The app on your Mac is the window onto it.
ledge backup puts an encrypted copy of the notes in an S3-compatible bucket every hour.curl -fsSL https://ledge.sh/server.sh | shCut 2.4.2 from the server, not the laptop. The build takes a minute.
make release
Ledge runs on iPhone and iPad as a window onto the same server. The phone holds no notes. It reads, edits, and runs what is on the server.
^C, ^D, Escape, and the arrow keys sit above the keyboard, so you can interrupt a command, quit a pager, or move around in htop.ledge pair prints on the server. The phone signs in with a key made in the Secure Enclave that never leaves it, and that key can speak to Ledge and nothing else.Two episodes transcoding. Check before starting a third.
htop
Add a host: line to the frontmatter and every run in the note happens over ssh on that host. The note itself stays where it is.
confirm and Ledge shows the code, names the machine, and asks before running it.ssh. Keys, agents, ~/.ssh/config, and 2FA work as they do in a terminal.cwd and env travel with the run. Profiles and secrets never do.python, node, and other interpreted blocks run on the host too, with a per-machine interpreter override in Settings.Stale session keys after the 2.4.1 deploy. Flush staging, verify, then prod.
redis-cli -n 2 flushdb
⌘D splits the view left and right, ⇧⌘D top and bottom, and either side can split again. Each pane has its own tabs.
Some trials end a day early.
go test ./...
A profile is a named file of environment variables kept outside your notes folder. A note that names it gets the variables in its shells. The note carries only the name.
profile: deploy in the frontmatter reads ~/.config/ledge/profiles/deploy.env, a plain dotenv file readable only by you.env: line overrides a value for one note.envFile: .env loads the project's own dotenv for everything that is not a secret.Backup restore drill. The AWS keys come from the deploy profile.
aws s3 ls s3://ledge-api-backups/nightly/ | tail -2
Ledge ships an MCP server. claude mcp add ledge -- ledge mcp connects Claude Code, and any MCP agent can read, search, create, and edit your notes through it.
prompt code block is a runnable block. ⌘↩ pipes it to the agent and the reply streams in beneath it.Tag after the migration bake. Checklist in . #release
git log --oneline v2.4.1..HEAD | head -3
9f31c22 storage: chunked uploads for assets over 50 MB 41b0a07 api: rate limit per token, not per IP c2ade19 fix: retry idempotent writes on 5xx
Locking encrypts a note's body on disk behind a passphrase. Agents never see it, sync services carry ciphertext, and reading it requires an unlock.
This note is locked. Its body stays sealed on disk, away from agents and search, until you unlock.
Unlock Notes…Notes are plain files in ordinary folders, so syncing them is syncing a folder: iCloud Drive, Dropbox, git, Syncthing, or whatever you already use. There is no database on the side.
This workspace is a repo. One run commits and pushes every note in it.
git add -A && git commit -m "notes $(date +%F)" || true git pull --rebase && git push
Six kinds of notes, each with the manual page that covers it.
select plan, count(*) from signups group by plan;
plan | count ------+------- free | 1204 pro | 187
import pandas as pd
df = pd.read_csv("signups.csv")
print(df["source"].mode()[0])newsletter
docker compose up -d db make migrate
✔ Container api-db-1 Started migrated to 0043_signup_source
INFO keyspace
# Keyspace db0:keys=4812339,expires=0,avg_ttl=0
%w[a b c].each_with_index do |s, i|
puts "#{i}: #{s}"
end0: a 1: b 2: c
zpool list -o name,cap,health
NAME CAP HEALTH tank 81% ONLINE
List the open tasks in [[2026-07-30]]
- Send the lease renewal back - Finish the chapter 4 notes
Everything else you expect from a notes app is here.
Python, Node, Ruby, and PHP run out of the box. A redis block feeds redis-cli, pointed at staging or prod by the note's REDIS_URL. TypeScript uses the Bun runtime bundled with the app, so ts blocks run with nothing installed. Adding an interpreter is one line in Settings.
⌘J opens today's note, stamped from your daily template. Templates are ordinary notes with {{date}} and {{yesterday}} tokens, and one carrying a prompt block gives every morning a one-keystroke briefing.
Attach a project folder and its Markdown files become notes where they are, running their blocks in the project. ⌘1 to ⌘9 switch workspaces, and each keeps its own pane layout. Removing an attached folder from Ledge touches no files.
Syntax hides away from the caret: **bold** shows bold, links show their label, tables and images render in place, and a checkbox is clickable. Move the caret in and the exact characters come back. One setting shows every character all the time.
Copy part of a web page, a Slack thread, or a Google Doc, and ⌘V pastes it as Markdown: headings, lists, checkboxes, links, and tables included. ⇧⌘V pastes the plain text. An image on the pasteboard lands in the workspace as a file, rendering in place; pasted into a locked note, it is encrypted from the first byte.
⌘P opens a note by title; type # for full-text search. Wikilinks address titles, so a retitle never leaves a stale link. Backlinks and outline each get a panel.
Tag a note with inline #hashtags or a frontmatter tags: line, and ⌥⌘T lists every tag with its count. Press f on a note's row, or click its star, and it sits in a Favorites section at the top of the sidebar, however deep in a folder it lives. Both are frontmatter, so they travel with the file.
⌫ moves a note to the workspace trash and shows an Undo strip. The Trash section in the sidebar holds it for 30 days, where r restores it and permanent deletion asks first.
Lists, reads, searches, creates, and appends from any terminal, and the app follows along live. Results go to stdout, everything conversational to stderr, so pipes stay clean, and --json switches any verb to machine-readable output.
Free and open source under Apache-2.0. No account required, and no database on the side. Your notes are Markdown files on your Mac or on a server you run, and they stay yours.
curl -fsSL https://ledge.sh/server.sh | sh