refactor: cherry-pick improvements from dev-agent's PR #700

Two wins from the dev-agent's implementation:

1. exec-briefing.sh: rewritten to just call exec-inject.sh with a
   briefing prompt (57 lines, down from 154). No more duplicated
   compass/character/context loading.

2. exec-inject.sh: response capture now uses agent_wait_for_claude_ready
   + pane line diff instead of custom EXEC-RESPONSE-START/END markers.
   Claude just responds naturally — no special output format needed.

Also: matrix listener uses nohup for robustness and validates TOML
path before passing to exec-inject.sh.
This commit is contained in:
disinto-exec 2026-03-25 16:15:10 +00:00
parent 8375611244
commit c3acce7f8f
5 changed files with 111 additions and 230 deletions

View file

@ -2,15 +2,10 @@
# =============================================================================
# exec-briefing.sh — Daily morning briefing via the executive assistant
#
# Cron wrapper: spawns a one-shot Claude session that gathers factory state
# and posts a morning briefing to Matrix. Unlike the interactive session,
# this runs, posts, and exits.
# Cron entry: 0 7 * * * /path/to/disinto/exec/exec-briefing.sh [project.toml]
#
# Usage:
# exec-briefing.sh [projects/disinto.toml]
#
# Cron:
# 0 7 * * * /path/to/disinto/exec/exec-briefing.sh
# Sends a briefing prompt to exec-inject.sh, which handles session management,
# response capture, and Matrix posting. No duplication of compass/context logic.
# =============================================================================
set -euo pipefail
@ -20,134 +15,43 @@ FACTORY_ROOT="$(dirname "$SCRIPT_DIR")"
export PROJECT_TOML="${1:-$FACTORY_ROOT/projects/disinto.toml}"
# shellcheck source=../lib/env.sh
source "$FACTORY_ROOT/lib/env.sh"
# shellcheck source=../lib/agent-session.sh
source "$FACTORY_ROOT/lib/agent-session.sh"
# shellcheck source=../lib/formula-session.sh
source "$FACTORY_ROOT/lib/formula-session.sh"
# shellcheck source=../lib/guard.sh
source "$FACTORY_ROOT/lib/guard.sh"
LOG_FILE="$SCRIPT_DIR/exec.log"
# shellcheck disable=SC2034 # consumed by run_formula_and_monitor
SESSION_NAME="exec-briefing-${PROJECT_NAME}"
PHASE_FILE="/tmp/exec-briefing-${PROJECT_NAME}.phase"
# shellcheck disable=SC2034
PHASE_POLL_INTERVAL=10
log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%S)Z] $*" >> "$LOG_FILE"; }
# ── Guards ────────────────────────────────────────────────────────────────
check_active exec
acquire_cron_lock "/tmp/exec-briefing.lock"
check_memory 2000
# Memory guard
AVAIL_MB=$(free -m 2>/dev/null | awk '/Mem:/{print $7}' || echo 9999)
if [ "${AVAIL_MB:-0}" -lt 2000 ]; then
log "SKIP: low memory (${AVAIL_MB}MB available)"
exit 0
fi
log "--- Exec briefing start ---"
# ── Load compass (required) ────────────────────────────────────────────
COMPASS_FILE="${EXEC_COMPASS:-${HOME}/.disinto/compass.md}"
if [ ! -f "$COMPASS_FILE" ]; then
log "FATAL: compass not found at ${COMPASS_FILE} — exec agent refuses to start without its compass"
exit 1
fi
COMPASS_BLOCK=$(cat "$COMPASS_FILE")
BRIEFING_PROMPT="Daily briefing request (automated, $(date -u '+%Y-%m-%d')):
# ── Load character (voice/relationships from repo) ────────────────────
CHARACTER_FILE="${EXEC_CHARACTER:-$SCRIPT_DIR/CHARACTER.md}"
CHARACTER_BLOCK=""
if [ -f "$CHARACTER_FILE" ]; then
CHARACTER_BLOCK=$(cat "$CHARACTER_FILE")
fi
Produce a concise morning briefing covering:
1. Pipeline status — blocked issues, failing CI, stale PRs?
2. Recent activity — what merged/closed in the last 24h?
3. Backlog health — depth, underspecified issues?
4. Predictions — any unreviewed from the predictor?
5. Concerns — anything needing human attention today?
# Merge: compass first, then character
CHARACTER_BLOCK="${COMPASS_BLOCK}
Check the forge API, git log, agent journals, and issue tracker.
Under 500 words. Lead with what needs action."
${CHARACTER_BLOCK}"
# ── Load memory ─────────────────────────────────────────────────────────
MEMORY_BLOCK="(no previous memory)"
MEMORY_FILE="$PROJECT_REPO_ROOT/exec/MEMORY.md"
if [ -f "$MEMORY_FILE" ]; then
MEMORY_BLOCK=$(cat "$MEMORY_FILE")
fi
# ── Gather factory state ───────────────────────────────────────────────
# Open issues count
OPEN_ISSUES=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
"${FORGE_API}/issues?state=open&type=issues&limit=1" 2>/dev/null \
| jq 'length' 2>/dev/null || echo "?")
# Open PRs
OPEN_PRS=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
"${FORGE_API}/pulls?state=open&limit=1" 2>/dev/null \
| jq 'length' 2>/dev/null || echo "?")
# Pending vault items
VAULT_PENDING=$(ls "$FACTORY_ROOT/vault/pending/" 2>/dev/null | wc -l || echo 0)
# Recent agent activity (last 24h log lines)
RECENT_ACTIVITY=""
for agent_dir in supervisor planner predictor gardener dev review; do
latest_log="$FACTORY_ROOT/${agent_dir}/${agent_dir}.log"
if [ -f "$latest_log" ]; then
lines=$(grep "$(date -u +%Y-%m-%d)" "$latest_log" 2>/dev/null | tail -5 || true)
if [ -n "$lines" ]; then
RECENT_ACTIVITY="${RECENT_ACTIVITY}
### ${agent_dir} (today)
${lines}
"
fi
fi
done
# ── Build briefing prompt ──────────────────────────────────────────────
# shellcheck disable=SC2034 # consumed by run_formula_and_monitor
PROMPT="You are the executive assistant for ${FORGE_REPO}. This is a morning briefing run.
## Your character
${CHARACTER_BLOCK}
## Your memory
${MEMORY_BLOCK}
## Current factory state
- Open issues: ${OPEN_ISSUES}
- Open PRs: ${OPEN_PRS}
- Pending vault items: ${VAULT_PENDING}
${RECENT_ACTIVITY}
## Task
Produce a morning briefing for the executive. Be concise — 10-15 lines max.
Cover:
1. What happened overnight (merges, CI failures, agent activity)
2. What needs attention today (blocked issues, vault items, stale work)
3. One observation or recommendation
Fetch additional data if needed:
- Open issues: curl -sf -H \"Authorization: token \${FORGE_TOKEN}\" '${FORGE_API}/issues?state=open&type=issues&limit=20'
- Recent closed: curl -sf -H \"Authorization: token \${FORGE_TOKEN}\" '${FORGE_API}/issues?state=closed&type=issues&limit=10&sort=updated&direction=desc'
- Prerequisite tree: cat ${PROJECT_REPO_ROOT}/planner/prerequisite-tree.md
Write your briefing between markers:
\`\`\`
---EXEC-RESPONSE-START---
Your briefing here.
---EXEC-RESPONSE-END---
\`\`\`
Then log the briefing to: ${PROJECT_REPO_ROOT}/exec/journal/\$(date -u +%Y-%m-%d).md
(append, don't overwrite — there may be interactive sessions later today)
Then: echo 'PHASE:done' > '${PHASE_FILE}'
## Environment
FACTORY_ROOT=${FACTORY_ROOT}
PROJECT_REPO_ROOT=${PROJECT_REPO_ROOT}
PHASE_FILE=${PHASE_FILE}"
# ── Run session ──────────────────────────────────────────────────────────
export CLAUDE_MODEL="${CLAUDE_MODEL:-sonnet}"
run_formula_and_monitor "exec-briefing" 600
bash "$SCRIPT_DIR/exec-inject.sh" \
"briefing-cron" \
"$BRIEFING_PROMPT" \
"" \
"$PROJECT_TOML" || {
log "briefing injection failed"
exit 1
}
log "--- Exec briefing done ---"