#!/bin/bash # Agent Factory — export-system.sh # Packages an agent system into a portable tarball with checksums. # Usage: bash export-system.sh # Bash 3.2 compatible. set -e EXPORT_NAME="${1:-agent-system}" DATE=$(python3 -c "import datetime; print(datetime.date.today().strftime('%Y-%m-%d'))") OUTPUT_FILE="agent-system-${EXPORT_NAME}-${DATE}.tar.gz" STAGING_DIR="/tmp/agent-export-$$" MANIFEST_FILE="${STAGING_DIR}/MANIFEST.md" # Determine project root (directory containing .claude/) PROJECT_ROOT="$(pwd)" if [ ! -d "${PROJECT_ROOT}/.claude" ]; then echo "ERROR: No .claude/ directory found in $(pwd)" >&2 echo "Run this script from your project root." >&2 exit 1 fi echo "[export] Starting export: ${EXPORT_NAME}" echo "[export] Date: ${DATE}" echo "[export] Output: ${OUTPUT_FILE}" mkdir -p "${STAGING_DIR}" # Collect files — explicit inclusions only collect_files() { local dir="$1" local dest="$2" if [ -d "${PROJECT_ROOT}/${dir}" ]; then mkdir -p "${STAGING_DIR}/${dest}" cp -r "${PROJECT_ROOT}/${dir}/." "${STAGING_DIR}/${dest}/" 2>/dev/null || true echo "[export] Collected: ${dir}" fi } collect_files ".claude/agents" ".claude/agents" collect_files ".claude/skills" ".claude/skills" collect_files ".claude/hooks" ".claude/hooks" collect_files "hooks" "hooks" collect_files "automation" "automation" collect_files "scripts" "scripts" # Copy settings.json if it exists if [ -f "${PROJECT_ROOT}/.claude/settings.json" ]; then mkdir -p "${STAGING_DIR}/.claude" cp "${PROJECT_ROOT}/.claude/settings.json" "${STAGING_DIR}/.claude/settings.json" echo "[export] Collected: .claude/settings.json" fi # Copy CLAUDE.md if it exists if [ -f "${PROJECT_ROOT}/CLAUDE.md" ]; then cp "${PROJECT_ROOT}/CLAUDE.md" "${STAGING_DIR}/CLAUDE.md" echo "[export] Collected: CLAUDE.md" fi # Remove excluded files from staging echo "[export] Removing excluded files" rm -f "${STAGING_DIR}/.env" 2>/dev/null || true find "${STAGING_DIR}" -name "*.local.*" -delete 2>/dev/null || true find "${STAGING_DIR}" -name "audit.log" -delete 2>/dev/null || true find "${STAGING_DIR}" -name "cost-events.jsonl" -delete 2>/dev/null || true find "${STAGING_DIR}" -name ".git" -prune -o -print | grep "\.git$" | xargs rm -rf 2>/dev/null || true rm -rf "${STAGING_DIR}/memory" 2>/dev/null || true # Generate MANIFEST.md with checksums echo "[export] Generating manifest" COMPONENT_ROWS="" find "${STAGING_DIR}" -type f | sort | while read -r fpath; do rel="${fpath#${STAGING_DIR}/}" checksum=$(python3 -c "import hashlib; print(hashlib.sha256(open('${fpath}','rb').read()).hexdigest()[:16])") filetype="other" case "$rel" in .claude/agents/*) filetype="agent" ;; .claude/skills/*) filetype="skill" ;; .claude/hooks/*|hooks/*) filetype="hook" ;; .claude/settings.json) filetype="settings" ;; automation/*) filetype="automation" ;; CLAUDE.md) filetype="context" ;; esac echo "| ${filetype} | ${rel} | ${checksum} |" >> "${MANIFEST_FILE}.rows" done cat > "${MANIFEST_FILE}" << MANIFEST # Agent System Manifest Export name: ${EXPORT_NAME} Export date: ${DATE} Generated by: Agent Factory export-system.sh ## Components | Type | File | Checksum (SHA256, first 16) | |------|------|---------------------------| MANIFEST if [ -f "${MANIFEST_FILE}.rows" ]; then cat "${MANIFEST_FILE}.rows" >> "${MANIFEST_FILE}" rm "${MANIFEST_FILE}.rows" fi cat >> "${MANIFEST_FILE}" << MANIFEST ## Requirements | Requirement | Value | |-------------|-------| | Claude Code version | 1.x or later | | MCP servers | List any required MCP servers here | | Tools | List any required tools (Bash, WebSearch, etc.) | | Environment | List required env vars (ANTHROPIC_API_KEY, etc.) | ## Notes Add any project-specific setup notes here. MANIFEST echo "[export] Manifest written" # Create tarball cd "${STAGING_DIR}" tar -czf "${PROJECT_ROOT}/${OUTPUT_FILE}" . cd "${PROJECT_ROOT}" # Cleanup rm -rf "${STAGING_DIR}" echo "[export] Done: ${OUTPUT_FILE}" echo "[export] Size: $(du -sh "${OUTPUT_FILE}" | cut -f1)"