Files
matrix-bridge/scripts/capture-note.sh
T
Keysat 0786286cde Capture: parse leading type keyword; record master-deploy + Element lessons
capture-note.sh reads an optional leading bug:/feature:/chore:/idea: keyword
as the inbox type (default idea, always P2). AGENTS.md: capture mode marked
live; two durable lessons — the Update button deploys origin/master so commits
must land there, and Element intercepts /capture (the thread is the trigger).
2026-06-16 16:10:07 -05:00

65 lines
2.6 KiB
Bash
Executable File

#!/bin/zsh -l
# capture-note.sh — matrix-bridge capture wrapper.
#
# Invoked over SSH by the bot: capture-note.sh <project> <text...>
# Appends ONE line to the cross-project inbox (standards/INBOX.md) in the exact format the
# /capture skill uses, commits it, and best-effort pushes — so /triage (run later inside the
# target repo) drains it like any other captured item.
#
# Deterministic on purpose: no LLM, no token, nothing leaves the Mac except the git push to
# Gitea. The "smarts" (priority, repo-routing, phrasing) stay at /triage, where the human is —
# routing message text through a frontier model would break the sovereignty boundary (D13/D8).
# Type comes from an optional leading keyword the user types ("bug: ...", "feature: ...");
# anything without one defaults to a raw [idea]. Priority is always P2; /triage sets the real one.
#
# Why a login shell (-l): git config / PATH live in ~/.zprofile, which a non-login SSH shell
# skips — the same seam as launch-claude.sh / ask-claude.sh.
set -e
setopt extended_glob # for whitespace-run trimming below
standards="$HOME/Projects/standards"
inbox="$standards/INBOX.md"
project="$1"
shift || true
note="$*"
if [[ -z "$project" || -z "$note" ]]; then
print -u2 "usage: capture-note.sh <project> <text>"
exit 2
fi
if [[ ! -f "$inbox" ]]; then
print -u2 "capture-note: inbox not found: $inbox"
exit 1
fi
# Optional leading type keyword ("bug: ...", "feature: ...", etc.) → that type; default idea.
# Only fires when the text before the first colon is exactly one known keyword, so a note that
# merely contains a colon ("ratio is 3:1") is left untouched. Types: standards/guides/capture.md.
type="idea"
if [[ "$note" == *:* ]]; then
cand="${(L)note%%:*}" # lowercase the text before the first colon
cand="${cand##[[:space:]]#}" # trim surrounding whitespace
cand="${cand%%[[:space:]]#}"
case "$cand" in
bug|feature|idea|chore|skill|agent|project)
type="$cand"
note="${note#*:}" # drop "keyword:"
note="${note##[[:space:]]#}" # trim leading whitespace
;;
esac
fi
line="- [ ] ($project) [$type][P2] $note — via matrix, $(date +%F)"
print -r -- "$line" >> "$inbox"
git -C "$standards" add INBOX.md
git -C "$standards" commit -q -m "Capture: ${note[1,60]} (via matrix)" -- INBOX.md
# Push is best-effort — a captured line committed locally is not lost if Gitea is unreachable.
git -C "$standards" push -q 2>/dev/null || print -u2 "capture-note: push skipped/failed (committed locally)"
# Echo the exact line so the bot can post it back into the thread as confirmation.
print -r -- "$line"