Back to Brain Lab Skill · Pipeline State · pipeline-state/
Skill Claude

Pipeline State

pipeline-state/

2 views 0 downloads

A small file-backed handoff bus for multi-agent runs: each phase records its outputs and evidence paths, so later phases look them up instead of re-pasting them. Survives context compression.

Pipeline State: Brain Lab skill for Claude Code

A durable, file-backed handoff bus so multi-agent runs pass references, not giant inlined dumps.

Why use it

  • Phase 4 re-pastes everything phase 3 produced, and the context window pays for it twice.
  • A long run gets compressed and the earlier phases' outputs are simply gone.
  • "What did the last phase actually produce?" has no machine-readable answer.

What it does

  • One per-run, git-ignored JSON file holding the run's variables, each phase's outputs, and paths to its evidence.
  • Read-on-START / write-on-COMPLETION protocol: pull your inputs by lookup, record your outputs as fields + PATHS.
  • A small shell script, init / set / append / get / clear, plus the state schema.
  • Coexists with your committed reports: it references them, it never replaces them.

Benefits

  • Small prompts, long runs. Handoffs become lookups instead of re-pasted dumps.
  • Survives context compression: nothing from phase 2 is lost by phase 8.
  • Gates you can trust. The orchestrator validates from evidence, not from a summary.
  • One script, any pipeline. No service, no database, no dependencies.

Install

Download this skill and copy the pipeline-state folder to .claude/skills/pipeline-state/ in your project, or to ~/.claude/skills/pipeline-state/ to use it in every project. Claude Code finds it on its own; you can also call it with /pipeline-state.

Part of the Context Engineering bundle. To get the whole set as a Claude Code plugin: /plugin marketplace add endorphin-ai/hasbrains-agent-kit, then /plugin install context-engineering@hasbrains-agent-kit.

Source: endorphin-ai/hasbrains-agent-kit. License: MIT.

Files (7)

Files

pipeline-state.sh
#!/usr/bin/env bash
# pipeline-state.sh — durable run-wide handoff-bus state (the orchestrator + every worker agent)
# Usage: pipeline-state.sh <init|set|append|get|clear> <session_id> [field] [value]
#
# State file (PER-SESSION, git-ignored): .ai_log/session-<session_id>.json  (one per run; the
#   orchestrator `init`s it at session start and passes its PATH as state_file to every agent). It
#   lives under .ai_log/, so it is git-ignored (never committed) by the /.ai_log/* rule — the ephemeral
#   machine handoff bus, NOT a durable record (durable records live in committed docs/).
# <session_id> is the run LABEL (convention: <YYYY-MM-DD>-<epic-slug> = <id>-<name>); the file PATH is
#   DERIVED from it (session-<session_id>.json), so every command resolves the same per-session file.

set -euo pipefail

REPO_ROOT="$(git rev-parse --show-toplevel)"
AI_LOG="$REPO_ROOT/.ai_log"

CMD="${1:-}"
SESSION="${2:-}"
FIELD="${3:-}"
VALUE="${4:-}"

if [ -z "$CMD" ] || [ -z "$SESSION" ]; then
  echo "Usage: $0 <init|set|append|get|clear> <session_id> [field] [value]" >&2
  exit 1
fi

# Per-session, git-ignored state file under .ai_log/ — DERIVED from the session label.
# The orchestrator `init`s it and passes this exact PATH as state_file to every agent.
FILE="$AI_LOG/session-${SESSION}.json"

case "$CMD" in
  init)
    mkdir -p "$AI_LOG"
    # Clean stale .ai_log/ artifacts from prior runs (R15: .ai_log/ is temporary-only).
    # Preserve the tracked .gitkeep so the folder stays committed. Runs BEFORE writing $FILE,
    # so the fresh per-session state file is written into a clean .ai_log/.
    find "$AI_LOG" -mindepth 1 ! -name .gitkeep -exec rm -rf {} + 2>/dev/null || true
    jq -n --arg s "$SESSION" '{session: $s, phases: {}}' > "$FILE"
    echo "pipeline-state: initialized $FILE (session=$SESSION)"
    ;;

  set)
    [ -z "$FIELD" ] && { echo "Error: field required" >&2; exit 1; }
    [ -f "$FILE" ] || { mkdir -p "$AI_LOG"; echo '{}' > "$FILE"; }
    tmp=$(mktemp)
    jq --arg k "$FIELD" --arg v "$VALUE" '.[$k] = $v' "$FILE" > "$tmp" && mv "$tmp" "$FILE"
    ;;

  append)
    [ -z "$FIELD" ] && { echo "Error: field required" >&2; exit 1; }
    [ -f "$FILE" ] || { mkdir -p "$AI_LOG"; echo '{}' > "$FILE"; }
    tmp=$(mktemp)
    jq --arg k "$FIELD" --arg v "$VALUE" '.[$k] = ((.[$k] // []) + [$v])' "$FILE" > "$tmp" && mv "$tmp" "$FILE"
    ;;

  get)
    [ ! -f "$FILE" ] && { echo "Error: no state file at $FILE (run 'init' first)" >&2; exit 1; }
    if [ -z "$FIELD" ]; then
      jq . "$FILE"
    else
      jq -r --arg k "$FIELD" '.[$k] // empty' "$FILE"
    fi
    ;;

  clear)
    rm -f "$FILE"
    echo "pipeline-state: cleared $FILE"
    ;;

  *)
    echo "Unknown command: $CMD" >&2
    echo "Usage: $0 <init|set|append|get|clear> <session_id> [field] [value]" >&2
    exit 1
    ;;
esac