Skill: joe3112/project-context-sync (version 1.0.0)

# project-context-sync Keep a living project state document updated after each commit, so any agent (or future session) can instantly understand where things stand. ## What It Does ``` ┌─────────────┐ ┌──────────────────┐ ┌─────────────────────┐ │ Git Commit │ ──▶ │ Post-commit Hook │ ──▶ │ PROJECT_STATE.md │ │ │ │ │ │ (auto-updated) │ └─────────────┘ └──────────────────┘ └─────────────────────┘ ``` After each commit, the hook: 1. Gathers git info (last commit, recent history, branch, changed files) 2. Optionally calls an LLM to generate a smart summary 3. Updates `PROJECT_STATE.md` in the repo root ## Installation ```bash # From the repo you want to enable: cd /path/to/your/repo /path/to/skills/project-context-sync/scripts/install.sh ``` Or if you have the skill in your path: ```bash project-context-sync install ``` This will: 1. Install a post-commit hook in `.git/hooks/` 2. Create `.project-context.yml` with default config 3. Create initial `PROJECT_STATE.md` 4. Add `PROJECT_STATE.md` to `.gitignore` ## Uninstall ```bash cd /path/to/your/repo /path/to/skills/project-context-sync/scripts/uninstall.sh ``` ## Manual Update Trigger an update without committing: ```bash cd /path/to/your/repo /path/to/skills/project-context-sync/scripts/update-context.sh ``` ## Configuration Edit `.project-context.yml` in your repo root: ```yaml project_context: # Use AI to generate smart summaries (default: true) ai_summary: true # How many recent commits to include recent_commits: 5 # Include diff stats in context include_diff_stats: true # Sections to include sections: - last_commit - recent_changes - current_focus # AI-generated - suggested_next # AI-generated ``` ### AI Summary Mode **With `ai_summary: true`** (default): - Generates intelligent summaries of what changed - Infers current focus from recent commit patterns - Suggests next steps - Costs tokens but provides rich context - **Requires:** Gateway HTTP API enabled (see below) **With `ai_summary: false`**: - Just logs raw git info - Fast and free - Less intelligent but still useful ### Enabling the Gateway HTTP API AI mode uses Clawdbot's OpenAI-compatible endpoint (`/v1/chat/completions`). This is **disabled by default** for security. To enable: ```json5 // ~/.clawdbot/clawdbot.json { "gateway": { "http": { "endpoints": { "chatCompletions": { "enabled": true } } } } } ``` **Security notes:** - The endpoint inherits gateway auth (requires bearer token) - With `bind: "loopback"` (default), only local processes can connect - The script reads the token from `~/.clawdbot/clawdbot.json` automatically - Risk is minimal for local development setups ## Output `PROJECT_STATE.md` will contain: ```markdown # Project State *Auto-updated by project-context-sync* ## Last Commit - **Hash:** abc123 - **Message:** Implement isPro check for app blocking - **Branch:** feature/subscription-gating - **When:** 2026-01-29 12:34 - **Files changed:** 3 ## Recent Changes - abc123: Implement isPro check for app blocking - def456: Add PaywallPrompt component - ... ## Current Focus [AI-generated summary of what's being worked on] ## Suggested Next Steps [AI-suggested based on commit patterns] ``` ## Notes - `PROJECT_STATE.md` is gitignored by default (regenerated locally) - The hook requires Clawdbot to be running for AI summaries - Without Clawdbot, falls back to raw git info mode

path: README.md
content: # project-context-sync

Keep a living `PROJECT_STATE.md` updated after each commit, so any agent (or future session) can instantly understand where things stand.

## How It Works

```
┌─────────────┐     ┌──────────────────┐     ┌─────────────────────┐
│ Git Commit  │ ──▶ │ Post-commit Hook │ ──▶ │ PROJECT_STATE.md    │
│             │     │                  │     │ (auto-updated)      │
└─────────────┘     └──────────────────┘     └─────────────────────┘
```

After each commit, the hook:
1. Gathers git info (last commit, recent history, branch, changed files)
2. Optionally calls an LLM to generate a smart summary
3. Updates `PROJECT_STATE.md` in the repo root

## Installation

```bash
# Clone this repo (or download it)
git clone https://github.com/Joe3112/project-context-sync.git

# From the repo you want to enable:
cd /path/to/your/project
/path/to/project-context-sync/scripts/install.sh
```

This will:
- Install a post-commit hook in `.git/hooks/`
- Create `.project-context.yml` with default config
- Create initial `PROJECT_STATE.md`
- Add `PROJECT_STATE.md` to `.gitignore`

## Uninstall

```bash
cd /path/to/your/project
/path/to/project-context-sync/scripts/uninstall.sh
```

## Manual Update

Trigger an update without committing:

```bash
/path/to/project-context-sync/scripts/update-context.sh
```

## Configuration

Edit `.project-context.yml` in your repo root:

```yaml
project_context:
  # Use AI to generate smart summaries (requires Clawdbot)
  ai_summary: true
  
  # How many recent commits to include
  recent_commits: 5
  
  # Include diff stats in context
  include_diff_stats: true
```

### AI Mode vs Raw Mode

| Mode | `ai_summary` | What You Get |
|------|--------------|--------------|
| **AI** | `true` | Intelligent summaries, inferred focus, suggested next steps |
| **Raw** | `false` | Just git info — fast, free, no dependencies |

## AI Mode Setup (Clawdbot)

AI summaries require [Clawdbot](https://github.com/clawdbot/clawdbot) with the HTTP API enabled:

```json
{
  "gateway": {
    "http": {
      "endpoints": {
        "chatCompletions": { "enabled": true }
      }
    }
  }
}
```

The script reads your gateway config from `~/.clawdbot/clawdbot.json` automatically.

**Security:** The endpoint uses bearer token auth and binds to localhost by default — only local processes can access it.

## Example Output

```markdown
# Project State
*Auto-updated: 2026-01-29 12:34:01*

## Last Commit
- **Hash:** 3c95bad
- **Message:** fix: use OpenAI-compatible endpoint for AI summaries
- **Author:** Joe3112
- **Date:** 2026-01-29 12:34:01 +0100
- **Changes:** 2 files changed, 29 insertions(+), 4 deletions(-)

## Recent Changes
- `3c95bad` fix: use OpenAI-compatible endpoint for AI summaries
- `bd2a8c3` feat: AI mode reads gateway config
- `ddb0024` fix: improve raw mode messaging

## Current Focus
Developing the project-context-sync skill with AI-powered summaries...

## Suggested Next Steps
- Test AI summary generation end-to-end
- Add error handling when AI endpoint is unavailable
- Document configuration options
```

## License

MIT


path: scripts/install.sh
content: #!/bin/bash
# project-context-sync: Install hook in current repo

set -e

SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
    echo "❌ Not in a git repository"
    exit 1
}

echo "🔧 Installing project-context-sync in: $REPO_ROOT"

# 1. Install post-commit hook
HOOKS_DIR="$REPO_ROOT/.git/hooks"
HOOK_FILE="$HOOKS_DIR/post-commit"

if [ -f "$HOOK_FILE" ]; then
    # Check if it's our hook
    if grep -q "project-context-sync" "$HOOK_FILE"; then
        echo "   ✓ Hook already installed"
    else
        echo "   ⚠️  Existing post-commit hook found, appending..."
        echo "" >> "$HOOK_FILE"
        echo "# project-context-sync" >> "$HOOK_FILE"
        echo "\"$SKILL_DIR/scripts/update-context.sh\" \"$REPO_ROOT\"" >> "$HOOK_FILE"
    fi
else
    cp "$SKILL_DIR/scripts/post-commit-hook.sh" "$HOOK_FILE"
    # Replace placeholder with actual paths
    sed -i '' "s|__SKILL_DIR__|$SKILL_DIR|g" "$HOOK_FILE"
    sed -i '' "s|__REPO_ROOT__|$REPO_ROOT|g" "$HOOK_FILE"
    chmod +x "$HOOK_FILE"
    echo "   ✓ Hook installed"
fi

# 2. Create config if not exists
CONFIG_FILE="$REPO_ROOT/.project-context.yml"
if [ ! -f "$CONFIG_FILE" ]; then
    cp "$SKILL_DIR/templates/project-context.yml" "$CONFIG_FILE"
    echo "   ✓ Config created: .project-context.yml"
else
    echo "   ✓ Config exists: .project-context.yml"
fi

# 3. Create initial PROJECT_STATE.md if not exists
STATE_FILE="$REPO_ROOT/PROJECT_STATE.md"
if [ ! -f "$STATE_FILE" ]; then
    cp "$SKILL_DIR/templates/PROJECT_STATE.md" "$STATE_FILE"
    echo "   ✓ Created: PROJECT_STATE.md"
else
    echo "   ✓ Exists: PROJECT_STATE.md"
fi

# 4. Add to .gitignore if not already there
GITIGNORE="$REPO_ROOT/.gitignore"
if [ -f "$GITIGNORE" ]; then
    if ! grep -q "PROJECT_STATE.md" "$GITIGNORE"; then
        echo "" >> "$GITIGNORE"
        echo "# project-context-sync (auto-generated, local only)" >> "$GITIGNORE"
        echo "PROJECT_STATE.md" >> "$GITIGNORE"
        echo "   ✓ Added PROJECT_STATE.md to .gitignore"
    else
        echo "   ✓ Already in .gitignore"
    fi
else
    echo "# project-context-sync (auto-generated, local only)" > "$GITIGNORE"
    echo "PROJECT_STATE.md" >> "$GITIGNORE"
    echo "   ✓ Created .gitignore with PROJECT_STATE.md"
fi

echo ""
echo "✅ project-context-sync installed!"
echo ""
echo "Next steps:"
echo "  • Edit .project-context.yml to customize"
echo "  • Make a commit to trigger the first update"
echo "  • Or run: $SKILL_DIR/scripts/update-context.sh"


path: scripts/post-commit-hook.sh
content: #!/bin/bash
# project-context-sync: Post-commit hook
# Installed by project-context-sync skill

SKILL_DIR="__SKILL_DIR__"
REPO_ROOT="__REPO_ROOT__"

# Run update in background to not block commit
"$SKILL_DIR/scripts/update-context.sh" "$REPO_ROOT" &


path: scripts/uninstall.sh
content: #!/bin/bash
# project-context-sync: Remove hook from current repo

set -e

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
    echo "❌ Not in a git repository"
    exit 1
}

echo "🧹 Uninstalling project-context-sync from: $REPO_ROOT"

# Remove hook
HOOK_FILE="$REPO_ROOT/.git/hooks/post-commit"
if [ -f "$HOOK_FILE" ]; then
    if grep -q "project-context-sync" "$HOOK_FILE"; then
        # Check if it's entirely our hook or just appended
        if head -n 3 "$HOOK_FILE" | grep -q "project-context-sync"; then
            rm "$HOOK_FILE"
            echo "   ✓ Removed post-commit hook"
        else
            # It was appended to existing hook, remove our lines
            sed -i '' '/# project-context-sync/d' "$HOOK_FILE"
            sed -i '' '/update-context.sh/d' "$HOOK_FILE"
            echo "   ✓ Removed our lines from post-commit hook"
        fi
    else
        echo "   ⚠️  Hook exists but wasn't ours"
    fi
else
    echo "   ✓ No hook to remove"
fi

echo ""
echo "✅ Uninstalled!"
echo ""
echo "Note: .project-context.yml and PROJECT_STATE.md were left in place."
echo "Remove manually if you don't need them."


path: scripts/update-context.sh
content: #!/bin/bash
# project-context-sync: Update PROJECT_STATE.md with current git state
# Usage: update-context.sh [repo_path]

set -e

# Determine repo root
if [ -n "$1" ]; then
    REPO_ROOT="$1"
else
    REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
        echo "❌ Not in a git repository and no path provided"
        exit 1
    }
fi

cd "$REPO_ROOT"

CONFIG_FILE="$REPO_ROOT/.project-context.yml"
STATE_FILE="$REPO_ROOT/PROJECT_STATE.md"

# ─────────────────────────────────────────────────────────────────────────────
# Parse config (simple bash parsing, falls back to defaults)
# ─────────────────────────────────────────────────────────────────────────────

AI_SUMMARY="true"
RECENT_COMMITS=5
INCLUDE_DIFF_STATS="true"

if [ -f "$CONFIG_FILE" ]; then
    # Very basic YAML parsing - just grep for values
    if grep -q "ai_summary: false" "$CONFIG_FILE"; then
        AI_SUMMARY="false"
    fi
    
    RC=$(grep "recent_commits:" "$CONFIG_FILE" 2>/dev/null | awk '{print $2}' | tr -d '[:space:]')
    if [ -n "$RC" ]; then
        RECENT_COMMITS="$RC"
    fi
    
    if grep -q "include_diff_stats: false" "$CONFIG_FILE"; then
        INCLUDE_DIFF_STATS="false"
    fi
fi

# ─────────────────────────────────────────────────────────────────────────────
# Gather git information
# ─────────────────────────────────────────────────────────────────────────────

# Last commit
LAST_HASH=$(git log -1 --format="%h" 2>/dev/null || echo "none")
LAST_MSG=$(git log -1 --format="%s" 2>/dev/null || echo "No commits")
LAST_DATE=$(git log -1 --format="%ci" 2>/dev/null || echo "")
LAST_AUTHOR=$(git log -1 --format="%an" 2>/dev/null || echo "")
BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")

# Files changed in last commit
if [ "$LAST_HASH" != "none" ]; then
    # For first commit, diff-tree needs special handling
    PARENT_COUNT=$(git rev-list --count HEAD 2>/dev/null || echo "0")
    if [ "$PARENT_COUNT" = "1" ]; then
        # First commit: list all files
        FILES_LIST=$(git ls-tree --name-only -r HEAD 2>/dev/null | head -10)
        FILES_CHANGED=$(git ls-tree --name-only -r HEAD 2>/dev/null | wc -l | tr -d ' ')
    else
        FILES_LIST=$(git diff-tree --no-commit-id --name-only -r HEAD 2>/dev/null | head -10)
        FILES_CHANGED=$(git diff-tree --no-commit-id --name-only -r HEAD 2>/dev/null | wc -l | tr -d ' ')
    fi
else
    FILES_CHANGED=0
    FILES_LIST=""
fi

# Recent commits
RECENT=$(git log -"$RECENT_COMMITS" --format="- %h: %s" 2>/dev/null || echo "No commits yet")

# Diff stats (optional)
if [ "$INCLUDE_DIFF_STATS" = "true" ] && [ "$LAST_HASH" != "none" ]; then
    DIFF_STAT=$(git diff --stat HEAD~1 HEAD 2>/dev/null | tail -1 || echo "")
else
    DIFF_STAT=""
fi

NOW=$(date "+%Y-%m-%d %H:%M:%S")

# ─────────────────────────────────────────────────────────────────────────────
# Generate output (raw mode)
# ─────────────────────────────────────────────────────────────────────────────

generate_raw_output() {
    cat << EOF
# Project State

*Auto-updated by [project-context-sync](https://github.com/clawdbot/skills/project-context-sync)*  
*Last updated: $NOW*

---

## Last Commit

- **Hash:** $LAST_HASH
- **Message:** $LAST_MSG
- **Branch:** $BRANCH
- **Author:** $LAST_AUTHOR
- **When:** $LAST_DATE
- **Files changed:** $FILES_CHANGED
EOF

    if [ -n "$DIFF_STAT" ]; then
        echo ""
        echo "**Stats:** $DIFF_STAT"
    fi

    if [ -n "$FILES_LIST" ]; then
        echo ""
        echo "**Changed files:**"
        echo "\`\`\`"
        echo "$FILES_LIST"
        echo "\`\`\`"
    fi

    cat << EOF

## Recent Changes

$RECENT

## Current Focus

*Raw mode — set \`ai_summary: true\` and ensure CLAWDBOT_TOKEN is set for AI summaries.*

## Suggested Next Steps

*Run with AI mode for intelligent suggestions.*
EOF
}

# ─────────────────────────────────────────────────────────────────────────────
# Generate output (AI mode) - calls gateway API for smart summaries
# ─────────────────────────────────────────────────────────────────────────────

generate_ai_output() {
    # Build context for AI
    PROMPT="You are updating a PROJECT_STATE.md file for an agent workspace. Be concise and practical.

REPO: $(basename "$REPO_ROOT")
BRANCH: $BRANCH

LAST COMMIT:
- Hash: $LAST_HASH
- Message: $LAST_MSG
- Author: $LAST_AUTHOR  
- Date: $LAST_DATE
- Files: $FILES_CHANGED changed

Changed files:
$FILES_LIST

RECENT COMMITS:
$RECENT

${DIFF_STAT:+STATS: $DIFF_STAT}

Generate PROJECT_STATE.md with EXACTLY this structure:

# Project State
*Auto-updated: $NOW*

## Last Commit
(format the commit info cleanly)

## Recent Changes  
(the commit list)

## Current Focus
(2-3 sentences: what's being actively worked on, inferred from commits)

## Suggested Next Steps
(2-3 bullet points: logical next actions based on the work pattern)

Output ONLY the markdown. No preamble, no explanation."

    # Read gateway config from clawdbot config file
    CLAWDBOT_CONFIG="$HOME/.clawdbot/clawdbot.json"
    
    if [ -f "$CLAWDBOT_CONFIG" ] && command -v jq &> /dev/null; then
        CONFIG_PORT=$(jq -r '.gateway.port // empty' "$CLAWDBOT_CONFIG" 2>/dev/null)
        CONFIG_TOKEN=$(jq -r '.gateway.auth.token // empty' "$CLAWDBOT_CONFIG" 2>/dev/null)
    fi
    
    # Use config values or fall back to env/defaults
    GATEWAY_PORT="${CONFIG_PORT:-${CLAWDBOT_GATEWAY_PORT:-19000}}"
    GATEWAY_TOKEN="${CONFIG_TOKEN:-${CLAWDBOT_TOKEN:-}}"
    GATEWAY_URL="http://localhost:$GATEWAY_PORT"
    
    if [ -n "$GATEWAY_TOKEN" ]; then
        # Escape the prompt for JSON
        ESCAPED_PROMPT=$(echo "$PROMPT" | jq -Rs .)
        
        # Call gateway's OpenAI-compatible endpoint
        RESULT=$(curl -s -X POST "$GATEWAY_URL/v1/chat/completions" \
            -H "Authorization: Bearer $GATEWAY_TOKEN" \
            -H "Content-Type: application/json" \
            -H "x-clawdbot-agent-id: main" \
            -d "{\"model\": \"clawdbot\", \"messages\": [{\"role\": \"user\", \"content\": $ESCAPED_PROMPT}]}" \
            --max-time 60 2>/dev/null | jq -r '.choices[0].message.content // empty' 2>/dev/null) || RESULT=""
        
        if [ -n "$RESULT" ] && [ "$RESULT" != "null" ]; then
            echo "$RESULT"
            return
        fi
    fi
    
    # Fallback to raw if gateway not available
    generate_raw_output
}

# ─────────────────────────────────────────────────────────────────────────────
# Main
# ─────────────────────────────────────────────────────────────────────────────

if [ "$AI_SUMMARY" = "true" ]; then
    generate_ai_output > "$STATE_FILE"
else
    generate_raw_output > "$STATE_FILE"
fi

echo "✅ Updated: $STATE_FILE"


path: skill.json
content: {
  "name": "project-context-sync",
  "version": "0.1.0",
  "description": "Auto-update project context documentation after each commit for agent continuity",
  "author": "Joe & George",
  "keywords": ["git", "context", "documentation", "memory", "commits"],
  "scripts": {
    "install": "scripts/install.sh",
    "uninstall": "scripts/uninstall.sh",
    "update": "scripts/update-context.sh"
  }
}


path: templates/PROJECT_STATE.md
content: # Project State

*Auto-updated by [project-context-sync](https://github.com/clawdbot/skills/project-context-sync)*  
*Last updated: Never*

---

## Last Commit

No commits recorded yet. Make a commit to populate this file.

## Recent Changes

*No history yet.*

## Current Focus

*Waiting for first commit...*

## Suggested Next Steps

1. Make your first commit
2. This file will auto-update with project context


path: templates/project-context.yml
content: # project-context-sync configuration
# See: https://github.com/clawdbot/skills/project-context-sync

project_context:
  # Use AI to generate smart summaries
  # true: Rich context with inferred focus and suggestions (uses tokens)
  # false: Raw git info only (fast, free)
  ai_summary: true
  
  # How many recent commits to show
  recent_commits: 5
  
  # Include file change stats in output
  include_diff_stats: true
  
  # Sections to include in PROJECT_STATE.md
  sections:
    - last_commit       # Always included
    - recent_changes    # Recent commit list
    - current_focus     # AI-generated (requires ai_summary: true)
    - suggested_next    # AI-generated (requires ai_summary: true)


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)