386 lines
13 KiB
Markdown
386 lines
13 KiB
Markdown
---
|
||
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 (Monday–Sunday). 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
|
||
5. **Deadline Discussions** — Target dates, commitments, timeline changes
|
||
|
||
**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.
|
||
|
||
**Deadlines & Timeline Changes:** Search all data sources for:
|
||
- **Explicit deadlines**: "deadline is", "due by", "target date", "ship by X", "launch date"
|
||
- **ETAs and estimates**: "ETA", "expected by", "should be done"
|
||
- **Changes**: "pushed back", "extended", "delayed", "moved up", "ahead of schedule", "slipped"
|
||
- **Commitments**: Agreements on when something will be delivered
|
||
- **Uncertainty**: "not sure when", "TBD", "need to figure out timeline"
|
||
|
||
For each deadline discussion found, record:
|
||
- What deliverable/milestone is being discussed
|
||
- The date mentioned (if any)
|
||
- Whether it's a new commitment, change, or removal
|
||
- The source (which thread/meeting/commit)
|
||
- Any context about why the timeline changed
|
||
|
||
**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
|
||
6. **Deadline History** - Track timeline discussions, commitments, and changes
|
||
|
||
**Deadline Tracking:**
|
||
- Scan all week summaries for deadline-related discussions
|
||
- Add new entries to the "Timeline Evolution" table showing changes
|
||
- Update "Current Commitments" with latest target dates
|
||
- Note when deadlines are mentioned without specific dates (uncertainty)
|
||
- Capture the reasoning behind timeline changes when available
|
||
|
||
**Deadline History Format:**
|
||
```markdown
|
||
## Deadline History
|
||
|
||
### Current Commitments
|
||
| Deliverable | Current Target | Source | Confidence |
|
||
|-------------|---------------|--------|------------|
|
||
| Feature X | Mar 15, 2026 | Sprint planning meeting | High |
|
||
| Beta release | Q2 2026 | Roadmap discussion | Medium |
|
||
|
||
### Timeline Evolution
|
||
| Date | Change | Previous | New | Reason | Source |
|
||
|------|--------|----------|-----|--------|--------|
|
||
| Feb 10 | Extended | Feb 28 | Mar 15 | Additional testing needed | #dev channel |
|
||
| Jan 15 | Committed | - | Feb 28 | Initial sprint commitment | Sprint kickoff |
|
||
```
|
||
|
||
**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}
|
||
4. Timeline: {deadline changes or commitments made}
|
||
|
||
### 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
|