diff --git a/.bin/browser b/.bin/browser
new file mode 100755
index 0000000..21fc5b1
--- /dev/null
+++ b/.bin/browser
@@ -0,0 +1,24 @@
+#!/bin/sh -e
+#
+# Usage: browser
+# pipe html to a browser
+# e.g.
+# $ echo '
hi mom!
' | browser
+# $ ron -5 man/rip.5.ron | browser
+
+if [ -t 0 ]; then
+ if [ -n "$1" ]; then
+ open $1
+ else
+ cat <hi mom!' | browser
+$ ron -5 man/rip.5.ron | browser
+usage
+fi
+else
+ f="/tmp/browser.$RANDOM.html"
+ cat /dev/stdin > $f
+ xdg-open $f
+fi
diff --git a/.bin/horoscope.sh b/.bin/horoscope.sh
new file mode 100644
index 0000000..e423dee
--- /dev/null
+++ b/.bin/horoscope.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+set -efu
+
+# Berlin: -d lodeg=13 -d lomin=22 -d losec=41 -d lodir=E -d ladeg=52 -d lamin=27 -d lasec=42 -d ladir=N -d usecoords=1 \
+# Kassel: -d lodeg=9 -d lomin=32 -d losec=5 -d lodir=E -d ladeg=51 -d lamin=18 -d lasec=17 -d ladir=N -d usecoords=1 \
+
+
+[ $# -eq 1 ] || {
+ echo >&2 Usage: "$0" TIMESTAMP
+ exit 1
+}
+
+export TZ=UTC
+
+chart_path="$(mktemp /tmp/chart_XXX.pdf)"
+
+timestamp="$1"
+
+year="$(date -d "@$timestamp" +%Y)"
+month="$(date -d "@$timestamp" +%m)"
+day="$(date -d "@$timestamp" +%d)"
+hour="$(date -d "@$timestamp" +%H)"
+minute="$(date -d "@$timestamp" +%M)"
+
+curl -sSL 'https://edifyingfellowship.org/astro/' \
+ -d lodeg=9 -d lomin=32 -d losec=5 -d lodir=E -d ladeg=51 -d lamin=18 -d lasec=17 -d ladir=N -d usecoords=1 \
+ -d ybyr="$year" -d ybmo="$month" -d ybdy="$day" -d ybhr="$hour" -d ybmi="$minute" -d ybsc=0 -d ybtz="$TZ" \
+ -d currenttime=0 \
+ -d title="$timestamp" \
+ -d options[]=VancouverWheel -d options[]=Arrow -d options[]=XBold -d options[]=HouseLabels -d options[]=Placidus \
+ -d options[]=Sun -d options[]=Moon -d options[]=Mercury -d options[]=Venus -d options[]=Mars -d options[]=Jupiter -d options[]=Saturn -d options[]=Uranus -d options[]=Neptune -d options[]=Pluto -d options[]=Ascendant -d options[]=MC -d options[]=Lilith -d options[]=MeanNode -d options[]=TrueNode \
+ -d aspectpct=100 -d format=PDF -d Submit= -o "$chart_path"
+
+zathura "$chart_path"
diff --git a/.bin/mail-current-part b/.bin/mail-current-part
new file mode 100755
index 0000000..cc0f000
--- /dev/null
+++ b/.bin/mail-current-part
@@ -0,0 +1,3 @@
+#! /bin/sh
+set -efu
+exec curl -fSs --unix-socket /tmp/much.api.sock http://localhost/current/part
diff --git a/.bin/mail-current-query b/.bin/mail-current-query
new file mode 100755
index 0000000..81f28ba
--- /dev/null
+++ b/.bin/mail-current-query
@@ -0,0 +1,3 @@
+#! /bin/sh
+set -efu
+exec curl -fSs --unix-socket /tmp/much.api.sock http://localhost/current/query
diff --git a/.bin/mail-current-query-find-part-by-name b/.bin/mail-current-query-find-part-by-name
new file mode 100755
index 0000000..2f49b90
--- /dev/null
+++ b/.bin/mail-current-query-find-part-by-name
@@ -0,0 +1,27 @@
+#! /bin/sh
+# usage: mail-current-query-find-part-by-name NAME
+set -efu
+
+name=$1
+
+query=$(mail-current-query)
+result=$(notmuch show --entire-thread=false --format=json "$query")
+
+part_id=$(printf %s "$result" | jq --arg name "$name" '
+ [
+ recurse |
+ select(type == "object") |
+ { id, name: .filename } |
+ select(.id != null and .name != null)
+ ] |
+ map(select(.name == $name))[0].id
+')
+
+if test "$part_id" = null; then
+ printf 'error: could not find part with name %s\n' \
+ "$name" \
+ >&2
+ exit 1
+fi
+
+exec notmuch show --part="$part_id" "$query"
diff --git a/.bin/mail-current-query-find-part-by-type b/.bin/mail-current-query-find-part-by-type
new file mode 100755
index 0000000..6d741bc
--- /dev/null
+++ b/.bin/mail-current-query-find-part-by-type
@@ -0,0 +1,39 @@
+#! /bin/sh
+# usage: mail-current-query-find-part-by-type TYPE
+set -efu
+
+type=$1
+
+query=$(mail-current-query)
+result=$(notmuch show --entire-thread=false --format=json "$query")
+
+part_id=$(printf %s "$result" | jq --arg type "$type" '
+ #flatten|map(select(.!=null))[0].body[0] |
+ #
+ #if .["content-type"] == $type then
+ # .id
+ #elif .["content-type"] | test("^multipart/") then
+ # .content|map(select(.["content-type"]==$type))[0].id
+ #else
+ # null
+ #end
+
+ [
+ recurse |
+ select(type == "object") |
+ { id, type: .["content-type"] } |
+ select(.id != null and .type != null)
+ ] |
+ map(select(.type == $type))[0].id
+')
+
+if test "$part_id" = null; then
+ printf 'error: could not find part with type %s\n' \
+ "$type" \
+ >&2
+ exit 1
+fi
+
+exec notmuch show --part="$part_id" "$query"
+
+
diff --git a/.bin/mail-reply b/.bin/mail-reply
new file mode 100755
index 0000000..2e3d2b7
--- /dev/null
+++ b/.bin/mail-reply
@@ -0,0 +1,47 @@
+#! /bin/sh
+set -efu
+
+reply_to=$(mail-current-query)
+
+if ! test "$(notmuch search --output=messages "$reply_to" | wc -l)" = 1; then
+ echo "current query doesn't point to exactly one message. abort." >&2
+ exit 1
+fi
+
+# TODO update headers
+
+notmuch reply "$reply_to" |
+sed '
+ /^Non-text part: /d
+ /^Attachment: /d
+' |
+jq -Rrs '
+ # TODO dedup with mail-send
+ split("\n") |
+ index("") as $i |
+ .[:$i] as $head |
+ .[$i:] as $body |
+
+ {
+ "MIME-Version": "1.0",
+ "Content-Type": "text/plain; charset=UTF-8; format=flowed",
+ "Content-Transfer-Encoding": "8bit"
+ } as $extra_head |
+
+ ($extra_head | keys | join("|")) as $extra_head_regex |
+ ($extra_head | to_entries | map("\(.key): \(.value)")) as $extra_head_lines |
+
+ # TODO each of these could be followed by multiple lines starting with spaces
+ ($head | map(select(test("^(\($extra_head_regex)):";"i") | not))) as $head |
+
+ ($head + $extra_head_lines) as $head |
+
+ ($head + $body) | join("\n")
+'
+
+
+# TODO fix From:
+# TODO tune quote
+
+# TODO write draft
+# TODO send mail
diff --git a/.bin/playlist_entries.sh b/.bin/playlist_entries.sh
new file mode 100755
index 0000000..0032806
--- /dev/null
+++ b/.bin/playlist_entries.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+youtube-dl -ij "$*" | jq -sr '.[] | .webpage_url'
diff --git a/.bin/readme b/.bin/readme
new file mode 100755
index 0000000..6698bf0
--- /dev/null
+++ b/.bin/readme
@@ -0,0 +1,4 @@
+#!/bin/sh
+curl -sSL "https://raw.githubusercontent.com/$*/master/README.md" \
+ | pandoc -f gfm -t man -s \
+ | man -l -
diff --git a/.bin/rfc.sh b/.bin/rfc.sh
new file mode 100644
index 0000000..3c21f3e
--- /dev/null
+++ b/.bin/rfc.sh
@@ -0,0 +1 @@
+curl -sSL "https://tools.ietf.org/rfc/rfc$*.txt" | less