fix: feat(20g): migrate all remaining agents to .profile + remove ops repo journal dirs (#90) #111

Closed
dev-qwen wants to merge 2 commits from fix/issue-90 into main
8 changed files with 103 additions and 19 deletions

View file

@ -926,6 +926,8 @@ ${ops_name}/
└── RESOURCES.md # accounts, tokens (refs), infra inventory └── RESOURCES.md # accounts, tokens (refs), infra inventory
\`\`\` \`\`\`
> **Note:** Journal directories (journal/planner/ and journal/supervisor/) have been removed from the ops repo. Agent journals are now stored in each agent's .profile repo on Forgejo.
## Branch protection ## Branch protection
- \`main\`: 2 reviewers required for vault items - \`main\`: 2 reviewers required for vault items

View file

@ -64,10 +64,19 @@ check_memory 2000
log "--- Gardener run start ---" log "--- Gardener run start ---"
# ── Resolve agent identity for .profile repo ────────────────────────────
if [ -z "${AGENT_IDENTITY:-}" ] && [ -n "${FORGE_GARDENER_TOKEN:-}" ]; then
AGENT_IDENTITY=$(curl -sf -H "Authorization: token ${FORGE_GARDENER_TOKEN}" \
"${FORGE_URL:-http://localhost:3000}/api/v1/user" 2>/dev/null | jq -r '.login // empty' 2>/dev/null || true)
fi
# ── Load formula + context ─────────────────────────────────────────────── # ── Load formula + context ───────────────────────────────────────────────
load_formula "$FACTORY_ROOT/formulas/run-gardener.toml" load_formula_or_profile "gardener" "$FACTORY_ROOT/formulas/run-gardener.toml" || exit 1
build_context_block AGENTS.md build_context_block AGENTS.md
# ── Prepare .profile context (lessons injection) ─────────────────────────
formula_prepare_profile_context
# ── Read scratch file (compaction survival) ─────────────────────────────── # ── Read scratch file (compaction survival) ───────────────────────────────
SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE") SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE")
SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE") SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE")
@ -105,7 +114,10 @@ You have full shell access and --dangerously-skip-permissions.
Fix what you can. File vault items for what you cannot. Do NOT ask permission — act first, report after. Fix what you can. File vault items for what you cannot. Do NOT ask permission — act first, report after.
## Project context ## Project context
${CONTEXT_BLOCK} ${CONTEXT_BLOCK}${LESSONS_INJECTION:+## Lessons learned
${LESSONS_INJECTION}
}
${SCRATCH_CONTEXT:+${SCRATCH_CONTEXT} ${SCRATCH_CONTEXT:+${SCRATCH_CONTEXT}
} }
## Result file ## Result file
@ -334,5 +346,8 @@ else
rm -f "$SCRATCH_FILE" rm -f "$SCRATCH_FILE"
fi fi
# Write journal entry post-session
profile_write_journal "gardener-run" "Gardener run $(date -u +%Y-%m-%d)" "complete" "" || true
rm -f "$GARDENER_PR_FILE" rm -f "$GARDENER_PR_FILE"
log "--- Gardener run done ---" log "--- Gardener run done ---"

View file

@ -350,6 +350,17 @@ ${lessons_content}"
return 0 return 0
} }
# formula_prepare_profile_context
# Pre-session: loads lessons from .profile repo and sets LESSONS_CONTEXT for prompt injection.
# Single shared function to avoid duplicate boilerplate across agent scripts.
# Requires: AGENT_IDENTITY, FORGE_TOKEN, FORGE_URL (via profile_load_lessons).
# Exports: LESSONS_CONTEXT (set by profile_load_lessons).
# Returns 0 on success, 1 if agent has no .profile repo (silent no-op).
formula_prepare_profile_context() {
profile_load_lessons || true
LESSONS_INJECTION="${LESSONS_CONTEXT:-}"
}
# profile_write_journal ISSUE_NUM ISSUE_TITLE OUTCOME [FILES_CHANGED] # profile_write_journal ISSUE_NUM ISSUE_TITLE OUTCOME [FILES_CHANGED]
# Post-session: writes a reflection journal entry after work completes. # Post-session: writes a reflection journal entry after work completes.
# Returns 0 on success, 1 on failure. # Returns 0 on success, 1 on failure.

View file

@ -45,12 +45,6 @@ WORKTREE="/tmp/${PROJECT_NAME}-planner-run"
log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%S)Z] $*" >> "$LOG_FILE"; } log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%S)Z] $*" >> "$LOG_FILE"; }
# Ensure AGENT_IDENTITY is set for profile functions
if [ -z "${AGENT_IDENTITY:-}" ] && [ -n "${FORGE_PLANNER_TOKEN:-}" ]; then
AGENT_IDENTITY=$(curl -sf -H "Authorization: token ${FORGE_PLANNER_TOKEN}" \
"${FORGE_URL:-http://localhost:3000}/api/v1/user" 2>/dev/null | jq -r '.login // empty' 2>/dev/null || true)
fi
# ── Guards ──────────────────────────────────────────────────────────────── # ── Guards ────────────────────────────────────────────────────────────────
check_active planner check_active planner
acquire_cron_lock "/tmp/planner-run.lock" acquire_cron_lock "/tmp/planner-run.lock"
@ -58,8 +52,14 @@ check_memory 2000
log "--- Planner run start ---" log "--- Planner run start ---"
# ── Resolve agent identity for .profile repo ────────────────────────────
if [ -z "${AGENT_IDENTITY:-}" ] && [ -n "${FORGE_PLANNER_TOKEN:-}" ]; then
AGENT_IDENTITY=$(curl -sf -H "Authorization: token ${FORGE_PLANNER_TOKEN}" \
"${FORGE_URL:-http://localhost:3000}/api/v1/user" 2>/dev/null | jq -r '.login // empty' 2>/dev/null || true)
fi
# ── Load formula + context ─────────────────────────────────────────────── # ── Load formula + context ───────────────────────────────────────────────
load_formula "$FACTORY_ROOT/formulas/run-planner.toml" load_formula_or_profile "planner" "$FACTORY_ROOT/formulas/run-planner.toml" || exit 1
build_context_block VISION.md AGENTS.md ops:RESOURCES.md ops:prerequisites.md build_context_block VISION.md AGENTS.md ops:RESOURCES.md ops:prerequisites.md
# ── Build structural analysis graph ────────────────────────────────────── # ── Build structural analysis graph ──────────────────────────────────────
@ -78,9 +78,8 @@ $(cat "$MEMORY_FILE")
" "
fi fi
# ── Load lessons from .profile repo (pre-session) ──────────────────────── # ── Prepare .profile context (lessons injection) ─────────────────────────
profile_load_lessons || true formula_prepare_profile_context
LESSONS_INJECTION="${LESSONS_CONTEXT:-}"
# ── Read scratch file (compaction survival) ─────────────────────────────── # ── Read scratch file (compaction survival) ───────────────────────────────
SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE") SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE")
@ -96,8 +95,7 @@ build_sdk_prompt_footer "
PROMPT="You are the strategic planner for ${FORGE_REPO}. Work through the formula below. PROMPT="You are the strategic planner for ${FORGE_REPO}. Work through the formula below.
## Project context ## Project context
${CONTEXT_BLOCK}${MEMORY_BLOCK} ${CONTEXT_BLOCK}${MEMORY_BLOCK}${LESSONS_INJECTION:+## Lessons learned
${LESSONS_INJECTION:+## Lessons learned
${LESSONS_INJECTION} ${LESSONS_INJECTION}
} }

View file

@ -53,13 +53,22 @@ check_memory 2000
log "--- Predictor run start ---" log "--- Predictor run start ---"
# ── Resolve agent identity for .profile repo ────────────────────────────
if [ -z "${AGENT_IDENTITY:-}" ] && [ -n "${FORGE_PREDICTOR_TOKEN:-}" ]; then
AGENT_IDENTITY=$(curl -sf -H "Authorization: token ${FORGE_PREDICTOR_TOKEN}" \
"${FORGE_URL:-http://localhost:3000}/api/v1/user" 2>/dev/null | jq -r '.login // empty' 2>/dev/null || true)
fi
# ── Load formula + context ─────────────────────────────────────────────── # ── Load formula + context ───────────────────────────────────────────────
load_formula "$FACTORY_ROOT/formulas/run-predictor.toml" load_formula_or_profile "predictor" "$FACTORY_ROOT/formulas/run-predictor.toml" || exit 1
build_context_block AGENTS.md ops:RESOURCES.md VISION.md ops:prerequisites.md build_context_block AGENTS.md ops:RESOURCES.md VISION.md ops:prerequisites.md
# ── Build structural analysis graph ────────────────────────────────────── # ── Build structural analysis graph ──────────────────────────────────────
build_graph_section build_graph_section
# ── Prepare .profile context (lessons injection) ─────────────────────────
formula_prepare_profile_context
# ── Read scratch file (compaction survival) ─────────────────────────────── # ── Read scratch file (compaction survival) ───────────────────────────────
SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE") SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE")
SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE") SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE")
@ -82,9 +91,13 @@ Use WebSearch for external signal scanning — be targeted (project dependencies
and tools only, not general news). Limit to 3 web searches per run. and tools only, not general news). Limit to 3 web searches per run.
## Project context ## Project context
${CONTEXT_BLOCK} ${CONTEXT_BLOCK}${LESSONS_INJECTION:+## Lessons learned
${LESSONS_INJECTION}
}
${GRAPH_SECTION} ${GRAPH_SECTION}
${SCRATCH_CONTEXT} ${SCRATCH_CONTEXT:+${SCRATCH_CONTEXT}
}
## Formula ## Formula
${FORMULA_CONTENT} ${FORMULA_CONTENT}
@ -98,5 +111,8 @@ formula_worktree_setup "$WORKTREE"
agent_run --worktree "$WORKTREE" "$PROMPT" agent_run --worktree "$WORKTREE" "$PROMPT"
log "agent_run complete" log "agent_run complete"
# Write journal entry post-session
profile_write_journal "predictor-run" "Predictor run $(date -u +%Y-%m-%d)" "complete" "" || true
rm -f "$SCRATCH_FILE" rm -f "$SCRATCH_FILE"
log "--- Predictor run done ---" log "--- Predictor run done ---"

View file

@ -13,8 +13,16 @@ source "$(dirname "$0")/../lib/env.sh"
source "$(dirname "$0")/../lib/ci-helpers.sh" source "$(dirname "$0")/../lib/ci-helpers.sh"
# shellcheck source=../lib/guard.sh # shellcheck source=../lib/guard.sh
source "$(dirname "$0")/../lib/guard.sh" source "$(dirname "$0")/../lib/guard.sh"
# shellcheck source=../lib/formula-session.sh
source "$(dirname "$0")/../lib/formula-session.sh"
check_active reviewer check_active reviewer
# Resolve agent identity for .profile repo
if [ -z "${AGENT_IDENTITY:-}" ] && [ -n "${FORGE_TOKEN:-}" ]; then
AGENT_IDENTITY=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
"${FORGE_URL:-http://localhost:3000}/api/v1/user" 2>/dev/null | jq -r '.login // empty' 2>/dev/null || true)
fi
REPO_ROOT="${PROJECT_REPO_ROOT}" REPO_ROOT="${PROJECT_REPO_ROOT}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"

View file

@ -27,6 +27,8 @@ source "$(dirname "$0")/../lib/env.sh"
source "$(dirname "$0")/../lib/ci-helpers.sh" source "$(dirname "$0")/../lib/ci-helpers.sh"
source "$(dirname "$0")/../lib/worktree.sh" source "$(dirname "$0")/../lib/worktree.sh"
source "$(dirname "$0")/../lib/agent-sdk.sh" source "$(dirname "$0")/../lib/agent-sdk.sh"
# shellcheck source=../lib/formula-session.sh
source "$(dirname "$0")/../lib/formula-session.sh"
# Auto-pull factory code to pick up merged fixes before any logic runs # Auto-pull factory code to pick up merged fixes before any logic runs
git -C "$FACTORY_ROOT" pull --ff-only origin main 2>/dev/null || true git -C "$FACTORY_ROOT" pull --ff-only origin main 2>/dev/null || true
@ -56,6 +58,14 @@ if [ -f "$LOGFILE" ] && [ "$(stat -c%s "$LOGFILE" 2>/dev/null || echo 0)" -gt 10
mv "$LOGFILE" "$LOGFILE.old" mv "$LOGFILE" "$LOGFILE.old"
fi fi
# =============================================================================
# RESOLVE AGENT IDENTITY FOR .PROFILE REPO
# =============================================================================
if [ -z "${AGENT_IDENTITY:-}" ] && [ -n "${FORGE_TOKEN:-}" ]; then
AGENT_IDENTITY=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
"${FORGE_URL:-http://localhost:3000}/api/v1/user" 2>/dev/null | jq -r '.login // empty' 2>/dev/null || true)
fi
# ============================================================================= # =============================================================================
# MEMORY GUARD # MEMORY GUARD
# ============================================================================= # =============================================================================
@ -180,6 +190,11 @@ else
log "WARN: build-graph.py failed — continuing without structural analysis" log "WARN: build-graph.py failed — continuing without structural analysis"
fi fi
# =============================================================================
# LOAD LESSONS FROM .PROFILE REPO (PRE-SESSION)
# =============================================================================
formula_prepare_profile_context
# ============================================================================= # =============================================================================
# BUILD PROMPT # BUILD PROMPT
# ============================================================================= # =============================================================================
@ -193,6 +208,7 @@ FORMULA=$(cat "${FACTORY_ROOT}/formulas/review-pr.toml")
"$PR_BODY" "$FILES" "$DNOTE" "$DIFF" "$PR_BODY" "$FILES" "$DNOTE" "$DIFF"
[ -n "$PREV_CONTEXT" ] && printf '%s\n' "$PREV_CONTEXT" [ -n "$PREV_CONTEXT" ] && printf '%s\n' "$PREV_CONTEXT"
[ -n "$GRAPH_SECTION" ] && printf '%s\n' "$GRAPH_SECTION" [ -n "$GRAPH_SECTION" ] && printf '%s\n' "$GRAPH_SECTION"
[ -n "$LESSONS_INJECTION" ] && printf '\n## Lessons learned\n%s\n\n' "$LESSONS_INJECTION"
printf '\n## Formula\n%s\n\n## Environment\nREVIEW_OUTPUT_FILE=%s\nFORGE_API=%s\nPR_NUMBER=%s\nFACTORY_ROOT=%s\n' \ printf '\n## Formula\n%s\n\n## Environment\nREVIEW_OUTPUT_FILE=%s\nFORGE_API=%s\nPR_NUMBER=%s\nFACTORY_ROOT=%s\n' \
"$FORMULA" "$OUTPUT_FILE" "$API" "$PR_NUMBER" "$FACTORY_ROOT" "$FORMULA" "$OUTPUT_FILE" "$API" "$PR_NUMBER" "$FACTORY_ROOT"
printf 'NEVER echo the actual token — always reference ${FORGE_TOKEN} or ${FORGE_REVIEW_TOKEN}.\n' printf 'NEVER echo the actual token — always reference ${FORGE_TOKEN} or ${FORGE_REVIEW_TOKEN}.\n'
@ -298,4 +314,7 @@ case "$VERDICT" in
;; ;;
esac esac
# Write journal entry post-session
profile_write_journal "review-${PR_NUMBER}" "Review PR #${PR_NUMBER} (${VERDICT})" "${VERDICT,,}" "" || true
log "DONE: ${VERDICT} (re-review: ${IS_RE_REVIEW})" log "DONE: ${VERDICT} (re-review: ${IS_RE_REVIEW})"

View file

@ -58,6 +58,12 @@ log "--- Supervisor run start ---"
# ── Housekeeping: clean up stale crashed worktrees (>24h) ──────────────── # ── Housekeeping: clean up stale crashed worktrees (>24h) ────────────────
cleanup_stale_crashed_worktrees 24 cleanup_stale_crashed_worktrees 24
# ── Resolve agent identity for .profile repo ────────────────────────────
if [ -z "${AGENT_IDENTITY:-}" ] && [ -n "${FORGE_SUPERVISOR_TOKEN:-}" ]; then
AGENT_IDENTITY=$(curl -sf -H "Authorization: token ${FORGE_SUPERVISOR_TOKEN}" \
"${FORGE_URL:-http://localhost:3000}/api/v1/user" 2>/dev/null | jq -r '.login // empty' 2>/dev/null || true)
fi
# ── Collect pre-flight metrics ──────────────────────────────────────────── # ── Collect pre-flight metrics ────────────────────────────────────────────
log "Running preflight.sh" log "Running preflight.sh"
PREFLIGHT_OUTPUT="" PREFLIGHT_OUTPUT=""
@ -68,9 +74,12 @@ else
fi fi
# ── Load formula + context ─────────────────────────────────────────────── # ── Load formula + context ───────────────────────────────────────────────
load_formula "$FACTORY_ROOT/formulas/run-supervisor.toml" load_formula_or_profile "supervisor" "$FACTORY_ROOT/formulas/run-supervisor.toml" || exit 1
build_context_block AGENTS.md build_context_block AGENTS.md
# ── Prepare .profile context (lessons injection) ─────────────────────────
formula_prepare_profile_context
# ── Read scratch file (compaction survival) ─────────────────────────────── # ── Read scratch file (compaction survival) ───────────────────────────────
SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE") SCRATCH_CONTEXT=$(read_scratch_context "$SCRATCH_FILE")
SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE") SCRATCH_INSTRUCTION=$(build_scratch_instruction "$SCRATCH_FILE")
@ -91,7 +100,10 @@ Fix what you can. File vault items for what you cannot. Do NOT ask permission
${PREFLIGHT_OUTPUT} ${PREFLIGHT_OUTPUT}
## Project context ## Project context
${CONTEXT_BLOCK} ${CONTEXT_BLOCK}${LESSONS_INJECTION:+## Lessons learned
${LESSONS_INJECTION}
}
${SCRATCH_CONTEXT:+${SCRATCH_CONTEXT} ${SCRATCH_CONTEXT:+${SCRATCH_CONTEXT}
} }
Priority order: P0 memory > P1 disk > P2 stopped > P3 degraded > P4 housekeeping Priority order: P0 memory > P1 disk > P2 stopped > P3 degraded > P4 housekeeping
@ -105,5 +117,8 @@ ${PROMPT_FOOTER}"
agent_run --worktree "$WORKTREE" "$PROMPT" agent_run --worktree "$WORKTREE" "$PROMPT"
log "agent_run complete" log "agent_run complete"
# Write journal entry post-session
profile_write_journal "supervisor-run" "Supervisor run $(date -u +%Y-%m-%d)" "complete" "" || true
rm -f "$SCRATCH_FILE" rm -f "$SCRATCH_FILE"
log "--- Supervisor run done ---" log "--- Supervisor run done ---"