Files
council/scripts/audiopen-ingest.sh
jpmschweitzerandClaude Opus 4.7 2c8df9425b add AudioPen ingest pipeline and sync architecture setup docs
Voice-note capture as the primary mobile input channel. AudioPen
polishes on their cloud, POSTs to a self-hosted receiver on the
desktop (exposed via Tailscale Funnel so no router ports open and
nothing behind Authentik). The receiver writes to inbox/raw/; a bash
normaliser wraps each drop in frontmatter and moves it to inbox/;
/triage-inbox routes them from there.

scripts/audiopen-ingest.sh — 80-line bash normaliser. Idempotent;
safe to re-run. Extracts title, slugifies, computes capture timestamp
from mtime, rewrites with fleeting-note frontmatter.

scripts/audiopen-webhook/main.py — stdlib-only Python HTTP server.
Zero pip deps; binds to 127.0.0.1 by default. Accepts flexible
payload shapes (title/name + body/output/summary/polished/
orig_transcript) so AudioPen version drift is logged rather than
silently dropped.

scripts/audiopen-webhook/*.example — systemd user-unit templates for
the receiver and the path/service pair that fires the ingest wrapper
on inbox/raw/ changes.

scripts/pyproject.toml + README.md — Python venv convention. Zero
deps today; venv location reserved at scripts/.venv/ (gitignored),
manifest at scripts/pyproject.toml, bootstrap documented for both
plain pip and uv. Optional-dependencies groups let individual tools
pull what they need without bloating the whole env.

docs/setup/audiopen.md — full setup guide: generating the shared
secret, installing the systemd units, pairing with Tailscale Funnel,
configuring AudioPen's webhook, and the IMAP-fallback path for
setups that can't run a public-reachable receiver.

docs/setup/sync.md — companion guide: Gitea SSH remote (works even
with Authentik gating HTTPS), obsidian-git plugin configuration,
Syncthing desktop↔phone pairing with the critical .stignore patterns,
and the three phone-role tiers so the user can pick Tier 1 / 2 / 3
at their own pace.

.gitignore gains **/.venv/, **/venv/, **/__pycache__/, and *.pyc so
nobody accidentally commits a materialised environment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:17:48 +02:00

79 lines
2.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# audiopen-ingest.sh
#
# Normalises raw AudioPen drops in inbox/raw/ into proper fleeting notes in inbox/.
# Adds frontmatter, renames to timestamp-slug format, moves to inbox/.
# Idempotent: safe to re-run. Destructive on inbox/raw/ (files are moved, not copied).
#
# Environment:
# COUNCIL_REPO — vault root. Default: /var/mnt/data/projects/council
#
# Exit status:
# 0 = success (even if zero files were processed)
# 1 = unexpected error
set -euo pipefail
REPO="${COUNCIL_REPO:-/var/mnt/data/projects/council}"
RAW="$REPO/inbox/raw"
OUT="$REPO/inbox"
if [ ! -d "$RAW" ]; then
echo "audiopen-ingest: raw dir $RAW does not exist; nothing to do." >&2
exit 0
fi
mkdir -p "$OUT"
shopt -s nullglob
count=0
for f in "$RAW"/*.md; do
# mtime as ISO-8601 (date -r works on GNU coreutils; Bazzite ships it)
captured=$(date -r "$f" -Iseconds)
ts=$(date -r "$f" +%Y-%m-%d-%H%M)
# Title: first `# ` line, else filename (without extension)
title=$(grep -m1 '^# ' "$f" 2>/dev/null | sed 's/^# *//' || true)
if [ -z "$title" ]; then
title=$(basename "$f" .md)
fi
# Slugify: lowercase, non-alnum → dash, collapse dashes, trim, cap at 60
slug=$(printf '%s' "$title" | tr '[:upper:]' '[:lower:]' \
| sed 's/[^a-z0-9]/-/g' \
| sed 's/--*/-/g' \
| sed 's/^-*//;s/-*$//' \
| cut -c1-60)
[ -z "$slug" ] && slug="untitled"
out="$OUT/${ts}_${slug}.md"
# If target exists (same timestamp + slug), append a numeric suffix
i=2
while [ -e "$out" ]; do
out="$OUT/${ts}_${slug}_${i}.md"
i=$((i+1))
done
# Body: strip the first `# title` line so we regenerate it in the normalised form
content=$(awk 'BEGIN{stripped=0} /^# / && !stripped { stripped=1; next } { print }' "$f")
{
echo "---"
echo "type: fleeting"
echo "source: audiopen"
echo "captured: $captured"
echo "slug: $slug"
echo "---"
echo
echo "# $title"
echo
printf '%s\n' "$content"
} > "$out"
rm "$f"
echo "ingested: $(basename "$f")$(basename "$out")"
count=$((count+1))
done
echo "audiopen-ingest: $count file(s) normalised."