feat: migrate to skills-based approach

This commit is contained in:
2026-02-19 11:36:32 -06:00
parent 42a9b5289f
commit eefac81e57
15 changed files with 2565 additions and 224 deletions

View File

@@ -0,0 +1,344 @@
---
name: project-sync
description: Sync a project timeline using subagents for parallelism. Splits work by week and datasource to stay within context limits. Handles both first-time and incremental syncs.
disable-model-invocation: true
argument-hint: [project-name]
---
# Project Sync
**When to use:** Keep a project timeline up to date. Works whether the project has been synced before or not.
**Precondition:** `projects/$0/datasources.md` must exist. If it doesn't, run `/project-init $0` first.
## Architecture: Coordinator + Subagents
This skill is designed for **subagent execution** to stay within context limits. The main agent acts as a **coordinator** that delegates data-intensive work to subagents.
```
Coordinator
├── Phase 1: Gather (parallel subagents, one per datasource)
│ ├── Subagent: Zulip → writes tmp/$0-sync/zulip.md
│ ├── Subagent: Git → writes tmp/$0-sync/git.md
│ └── Subagent: Meetings → writes tmp/$0-sync/meetings.md
├── Phase 2: Synthesize (parallel subagents, one per week)
│ ├── Subagent: Week 1 → writes timeline/{year-month}/week-{n}.md
│ ├── Subagent: Week 2 → writes timeline/{year-month}/week-{n}.md
│ └── ...
└── Phase 3: Finalize (coordinator directly)
├── timeline/index.md (add links to new weeks)
├── project.md (update living document)
└── sync-state.md (update sync status)
```
---
## Coordinator Steps
### Step 1: Determine Sync Range
Check whether `projects/$0/sync-state.md` exists.
**Case A — First sync (no sync-state.md):**
Default range is **last 12 months through today**. If the user provided explicit dates as extra arguments (`$1`, `$2`), use those instead.
**Case B — Incremental sync (sync-state.md exists):**
Read `last_sync_date` from `projects/$0/sync-state.md`. Range is `last_sync_date` to today.
### Step 2: Read Datasources
Read `projects/$0/datasources.md` to determine:
- Zulip stream IDs and search terms
- Git repository URL
- Meeting room names
- Entity types to prioritize
### Step 3: Prepare Scratch Directory
```bash
mkdir -p tmp/$0-sync
```
This directory holds intermediate outputs from Phase 1 subagents. It is ephemeral — delete it after the sync completes.
### Step 4: Compute Week Boundaries
Split the sync range into ISO calendar weeks (MondaySunday). Produce a list of `(week_number, week_start, week_end, year_month)` tuples. This list drives Phase 2.
---
## Phase 1: Gather Data (parallel subagents)
Launch **one subagent per datasource**, all in parallel. Each subagent covers the **full sync range** and writes its output to a scratch file. The output must be organized by week so Phase 2 subagents can consume it.
### Subagent: Zulip
**Input:** Sync range, PRIMARY stream IDs and search terms from datasources.md.
**Important:** `threaded_conversation` entities only contain the **last 50 messages** in a topic. To get complete message history for a week, you must query `conversation_message` entities.
**Task:** Two-step process for each PRIMARY stream:
**Step 1:** List all thread IDs in the stream using `id_prefix`:
```
GET /api/v1/query
entity_types=threaded_conversation
connector_ids=zulip
id_prefix=zulip:stream:{stream_id}
limit=100
offset=0
```
This returns all thread entities (e.g., `zulip:stream:155:topic_name`). Save these IDs.
**Step 2:** For each week in the sync range, query messages from each thread:
```
GET /api/v1/query
entity_types=conversation_message
connector_ids=zulip
parent_id={thread_id} # e.g., zulip:stream:155:standalone
date_from={week_start}
date_to={week_end}
limit=100
offset=0
```
Paginate through all messages for each thread/week combination.
**Output:** Write `tmp/$0-sync/zulip.md` with results grouped by week:
```markdown
## Week {n} ({week_start} to {week_end})
### Stream: {stream_name}
- **Topic:** {topic} ({date}, {message_count} messages, {participant_count} participants)
{brief summary or key quote}
```
### Subagent: Git
**Input:** Sync range, git repository URL from datasources.md.
**Task:**
**Important:** Git commands may fail due to gitconfig permission issues. Use a temporary HOME directory:
```bash
# Set temporary HOME to avoid gitconfig permission issues
export HOME=$(pwd)/.tmp-home
mkdir -p ./tmp
# Clone if needed, pull if exists
if [ -d ./tmp/$0-clone ]; then
export HOME=$(pwd)/.tmp-home && cd ./tmp/$0-clone && git pull
else
export HOME=$(pwd)/.tmp-home && git clone --depth 500 {url} ./tmp/$0-clone
cd ./tmp/$0-clone
fi
# Get commits in the date range
export HOME=$(pwd)/.tmp-home && git log --since="{range_start}" --until="{range_end}" --format="%H|%an|%ae|%ad|%s" --date=short
# Get contributor statistics
export HOME=$(pwd)/.tmp-home && git log --since="{range_start}" --until="{range_end}" --format="%an" | sort | uniq -c | sort -rn
```
**Output:** Write `tmp/$0-sync/git.md` with results grouped by week:
```markdown
## Week {n} ({week_start} to {week_end})
**Commits:** {count}
**Contributors:** {name} ({count}), {name} ({count})
### Key Commits
- `{short_hash}` {subject} — {author} ({date})
```
### Subagent: Meetings
**Input:** Sync range, meeting room names from datasources.md.
**Task:** For each PRIMARY room, query meetings and run semantic search:
```
GET /api/v1/query
entity_types=meeting
date_from={range_start}
date_to={range_end}
room_name={room-name}
limit=100
POST /api/v1/search
search_text={project-name}
entity_types=["meeting"]
date_from={range_start}
date_to={range_end}
limit=50
```
**Output:** Write `tmp/$0-sync/meetings.md` with results grouped by week:
```markdown
## Week {n} ({week_start} to {week_end})
### Meeting: {title} ({date}, {room})
**Participants:** {names}
**Summary:** {brief summary}
**Key points:**
- {point}
```
---
## Phase 2: Synthesize Week Files (parallel subagents)
After all Phase 1 subagents complete, launch **one subagent per week**, all in parallel. Each produces a single week file.
### Subagent: Week {n}
**Input:** The relevant `## Week {n}` sections extracted from each of:
- `tmp/$0-sync/zulip.md`
- `tmp/$0-sync/git.md`
- `tmp/$0-sync/meetings.md`
Pass only the sections for this specific week — do NOT pass the full files.
**Task:** Merge and analyze the data from all three sources. Categorize into:
1. **Key Decisions** — Technology migrations, architecture changes, vendor switches, security incidents, strategic pivots
2. **Technical Work** — Feature implementations, bug fixes, infrastructure changes
3. **Team Activity** — Core vs. occasional contributors, role changes
4. **Blockers** — Issues, delays, dependencies
**Milestones:** When documenting milestones, capture BOTH:
- **WHAT** — The technical achievement (e.g., "PostgreSQL migration")
- **WHY** — The business objective (e.g., "to improve query performance from 107ms to 27ms and enable concurrent access for scaling")
Search for business objectives in: meeting discussions about roadmap, Zulip threads about planning, PR descriptions, release notes, and any "why are we doing this" conversations.
**Skip unless meaningful:** Routine check-ins, minor documentation updates, social chat.
**Output:** Write `projects/$0/timeline/{year-month}/week-{n}.md` using the week file template from [project-history](../project-history/SKILL.md). Also return a **3-5 line summary** to the coordinator for use in Phase 3.
Create the month directory first if needed: `mkdir -p projects/$0/timeline/{year-month}`
---
## Phase 3: Finalize (coordinator directly)
The coordinator collects the summaries returned by all Phase 2 subagents. These summaries are small enough to fit in the coordinator's context.
### Step 5: Update Timeline Index
Add links to new week files in `projects/$0/timeline/index.md`. Append entries under the appropriate year/quarter sections. Update milestones if any were reached.
### Step 6: Update Project Dashboard (project.md)
**File:** `projects/$0/project.md`
This is the **living document** — update it with current status from the week summaries:
**Update these sections:**
1. **This Week's Focus** - What the team is actively working on now
2. **Last Week's Focus** - What was completed in the most recent week
3. **Team** - Current contributors and their focus areas
4. **Milestones** - Update status and add new ones with business objectives
5. **Recent Decisions** - Key decisions from the last 2-3 weeks
**Milestone Format:**
```markdown
### In Progress 🔄
| Milestone | Target | Business Objective |
|-----------|--------|-------------------|
| Standalone deployment | Feb 2026 | Enable non-developers to self-host without complex setup |
### Recently Completed ✅
| Milestone | Date | Business Objective |
|-----------|------|-------------------|
| PostgreSQL migration | Mar 2025 | Improve performance (107ms→27ms) and enable scaling |
### Lost in Sight / Paused ⏸️
| Milestone | Status | Reason |
|-----------|--------|--------|
| Feature X | Paused | Resources reallocated to higher priority |
```
**Note:** Milestones in this company change frequently — update status (in progress/done/paused) as needed.
### Step 7: Update Sync State
Create or update `projects/$0/sync-state.md`:
**First sync (Case A):**
```markdown
# Sync State
status: synced
created_at: {today's date}
last_sync_date: {today's date}
initial_history_from: {range_start}
initial_history_to: {range_end}
last_incremental_sync: {today's date}
```
**Incremental sync (Case B):**
```markdown
# Sync State
status: synced
created_at: {original value}
last_sync_date: {today's date}
initial_history_from: {original value}
initial_history_to: {original value}
last_incremental_sync: {today's date}
```
### Step 8: Cleanup
```bash
rm -rf tmp/$0-sync
```
### Step 9: Summary Report
Output a brief summary:
```markdown
## Sync Summary: {Date}
### Period Covered
{range_start} to {range_end}
### Key Changes
1. Decision: {brief description}
2. Feature: {what was built}
3. Team: {who joined/left}
### Metrics
- {n} new commits
- {n} active contributors
- {n} weeks analyzed
- {n} new Zulip threads
- {n} meetings recorded
### Current Status
[Status description]
```
---
## Key Rules
- **Link to sources**: Always reference commit hashes, PR numbers, Zulip topic names, meeting dates
- **Be explicit about exclusions**: Document what you're NOT analyzing and why
- **Write once**: Week files are historical records — don't modify existing ones, only create new ones
- **Paginate all queries**: Always loop through all pages of results
- **Distinguish contributor types**: Core (regular activity) vs. occasional (sporadic)
- **Subagent isolation**: Each subagent should be self-contained. Pass only the data it needs — never the full scratch files
- **Fail gracefully**: If a datasource subagent fails (e.g., git clone errors, API down), the coordinator should continue with available data and note the gap in the summary