Re-synchronizes the vault with external sources. In default mode, scans the `sources` field of all entities, deduplicates URLs, fetches updated content from each source (Confluence, GDocs, GitHub, Markdown), performs incremental diff and delegates writing to /bedrock:preserve.
Installs just this skill. Get the whole plugin for auto-invocation.
โก How it fires
How this skill gets triggered: by you, by Claude, or both.
Fires itselfClaude auto-loads it when your prompt matches the work.
You can call itInvoke it directly when you want it.
Slash command/sync
๐๏ธ Context preview
The summary Claude sees to decide when to auto-load this skill.
Re-synchronizes the vault with external sources. In default mode, scans the `sources` field of all entities, deduplicates URLs, fetches updated content from each source (Confluence, GDocs, GitHub, Markdown), performs incremental diff and delegates writing to /bedrock:preserve.
๐ Stats
Stars83
Forks8
LanguageHTML
LicenseMIT
๐ฆ Ships with bedrock
</> SKILL.md
sync.SKILL.md
---name: sync
description: >
Re-synchronizes the vault with external sources. In default mode, scans the `sources`
field of all entities, deduplicates URLs, fetches updated content from each source
(Confluence, GDocs, GitHub, Markdown), performs incremental diff and delegates writing to
/bedrock:preserve. With --people, scans actor repositories via GitHub API and
identifies active contributors. With --github, detects relevant activity in
repositories and correlates PRs with topics/projects via LLM semantic matching.
Use when: "bedrock sync", "bedrock-sync", "/bedrock:sync", "synchronize",
"update sources", "sync people", "sync github".
user_invocable: true
allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Skill, Agent, mcp__plugin_github_github__*, mcp__plugin_atlassian_atlassian__*
---# /bedrock:sync โ Vault Synchronization
## Plugin Paths
Entity definitions and templates are in the plugin directory, not in the vault root.
Use the "Base directory for this skill" provided at invocation to resolve paths:
- Entity definitions: `<base_dir>/../../entities/`
- Templates: `<base_dir>/../../templates/{type}/_template.md`
- Plugin CLAUDE.md: `<base_dir>/../../CLAUDE.md` (already injected automatically into context)
Where `<base_dir>` is the path provided in "Base directory for this skill".
Resolve which vault to sync. This skill can be invoked from any directory.
**Step 1 โ Parse `--vault` flag:**
Check if the input arguments include `--vault <name>`. If found, extract the vault name and remove it from the arguments before parsing `--people` or `--github`.
**Step 2 โ Resolve vault path:**
1. **If `--vault <name>` was provided:**
Read the vault registry at `<base_dir>/../../vaults.json`. Find the entry matching the name.
If not found: error โ "Vault `<name>` is not registered. Run `/bedrock:vaults` to see available vaults."
If found: set `VAULT_PATH` to the entry's `path` value. Store the resolved vault name as `VAULT_NAME`.
2. **If no `--vault` flag โ CWD detection:**
Read `<base_dir>/../../vaults.json`. Check if the current working directory is inside any registered vault path
(CWD starts with a registered vault's absolute path). If multiple match, use the longest path (most specific).
If found: set `VAULT_PATH` to the matching vault's `path`. Store its name as `VAULT_NAME`.
3. **If CWD detection fails โ default vault:**
From the registry, find the vault with `"default": true`.
If found: set `VAULT_PATH` to the default vault's `path`. Store its name as `VAULT_NAME`.
4. **If no resolution:**
Error โ "No vault resolved. Available vaults:" followed by the registry listing.
"Use `--vault <name>` to specify, or run `/bedrock:setup` to register a vault."
**Step 3 โ Validate vault path:**
```bash
test -d "<VAULT_PATH>" && echo "exists" || echo "missing"
```
If missing: error โ "Vault path `<VAULT_PATH>` does not exist on disk. Run `/bedrock:setup` to re-register."
**Step 4 โ Read vault config:**
```bash
cat <VAULT_PATH>/.bedrock/config.json 2>/dev/null
```
Extract `language`, `git.strategy`, and other relevant fields for use in later phases.
**From this point forward, ALL vault file operations use `<VAULT_PATH>` as the root.**
- Entity directories: `<VAULT_PATH>/actors/`, `<VAULT_PATH>/people/`, etc.
- Git operations: `git -C <VAULT_PATH> <command>`
- When delegating to `/bedrock:preserve`, pass `--vault <VAULT_NAME>`
---
## Overview
This skill synchronizes the vault with external sources. It operates in three modes:
| Mode | Flag | Description |
|---|---|---|
| **Sources (default)** | _(none)_ | Re-synchronizes entities with a populated `sources` field |
| **People** | `--people` | Scans actor repositories and identifies active contributors |
| **GitHub** | `--github` | Detects activity in repos and correlates PRs with topics/projects |
---
## Routing
Analyze the argument passed by the user:
1. If argument contains `--people` โ go to **Mode: Sync People** (below)
2. If argument contains `--github` โ go to **Mode: Sync GitHub** (below)
3. Otherwise โ go to **Mode: Sync Sources (default)** (below)
> **Note:** If no argument is passed, or the argument does not contain recognized flags,
> execute the default mode (Sync Sources).
---
---
# Mode: Sync Sources (default)
## Overview
This skill scans the `sources` field of all vault entities, deduplicates by URL,
fetches updated content from each external source, compares with existing entities
in the vault (incremental diff), and delegates all changes to `/bedrock:preserve` for centralized writing.
`/bedrock:sync` **does NOT write entities directly** โ all entity writing goes through `/bedrock:preserve`.
After re-sync, `/bedrock:preserve` updates `synced_at` in the `sources` field of affected entities.
`/bedrock:sync` **does NOT ingest new sources** โ for that, use `/bedrock:learn`.
**You are an execution agent.** Follow the phases below in order, without skipping steps.
---
## Phase 0 โ Synchronize the Vault
Execute:
```bash
git -C <VAULT_PATH> pull --rebase origin main
```
If the pull fails:
- No remote configured: warn "No remote configured. Working locally." and proceed.
- Pull conflict: `git -C <VAULT_PATH> rebase --abort` and warn the user. Do NOT proceed without resolving.
- Otherwise: proceed.
---
## Phase 1 โ Collect Syncable Sources
Provenance is recorded in the `sources` field of each entity's frontmatter.
Scan all entities to collect unique URLs.
1. Use Grep to find entities with a non-empty `sources` field:
6. Store the valid commits associated with the actor
At the end of this phase, report: "Phase 2: N repositories accessed, M with commits, K inaccessible (list). Total of L commits from P unique contributors."
---
## Phase 3 โ Aggregation
1. Group all commits by `author.login` (lowercase)
2. For each unique person, build:
- `github`: login in lowercase
- `name`: `commit.author.name` from the most recent commit (fallback: login if name is empty)
- `focal_points`: list of canonical actor names where the person has commits (no duplicates)
- `team`: squad with most commits; in case of tie, first alphabetically
- `filename`: derived from `name` โ lowercase, no accents (normalize NFD and remove combining marks), spacesโhyphens, special characters removed, kebab-case
- E.g.: `Alice Smith` โ `alice-smith.md`
- E.g.: `Josรฉ Marรญa` โ `jose-maria.md`
- Fallback: if name not available, use login as filename
3. **Duplicate detection by filename:**
- If two contributors (different logins) generate the same filename: append `-2`, `-3`, etc. to the second
- If a file `people/{filename}` already exists with a different `github`: treat as different person, append suffix
At the end of this phase, report: "Phase 3: N unique contributors identified. Distribution by squad: [list]."
---
## Phase 4 โ Write people
For each person:
### If `people/{filename}` does NOT exist โ CREATE:
Use Write to create the file with this exact content (replace the placeholders):
```markdown
---
type: person
name: "{display_name}"
role: ""
team: "[[{team_slug}]]"
focal_points: [{focal_points_yaml}]
github: "{github_login}"
jira: ""
updated_at: {today_date_YYYY-MM-DD}
updated_by: "sync-people"
tags: [type/person]
---
# {Display Name}
> Active contributor identified via commits in the last 30 days.
## Team
Member of [[{team_slug}]].
## Focal Points
{focal_points_list}
## Active Topics
_No topics linked yet._
```
Where:
- `{focal_points_yaml}` = YAML array of wikilinks, e.g.: `["[[billing-api]]", "[[notification-service]]"]`
- `{focal_points_list}` = markdown list, e.g.:
```
- [[billing-api]] โ recent commits
- [[notification-service]] โ recent commits
```
- `{today_date_YYYY-MM-DD}` = today's date in `YYYY-MM-DD` format
### If `people/{filename}` ALREADY exists โ UPDATE:
1. Use Read to read the existing file
2. **Merge focal_points:** add new actors to the existing YAML array, without removing those already there
3. **Update team:** overwrite with the new calculation (squad with most commits)
4. **Update updated_at:** today's date
5. **Update updated_by:** `"sync-people"`
6. Update the "Focal Points" section in the markdown body to reflect the merged list
7. Use Edit to apply the changes (do not rewrite the entire file โ preserve manual content)
**Identification by login:** Before creating a new file, use Grep to search for `github: "{login}"` in `<VAULT_PATH>/people/*.md`. If found, update that file instead of creating a new one (even if the filename does not match).
At the end of this phase, report: "Phase 4: N people created, M updated."
---
## Phase 5 โ Update teams
For each squad that received new people:
1. Use Read to read `teams/{team_slug}.md`
2. Extract the `members` array from the YAML frontmatter
3. For each person in the squad: add `"[[{person_filename_without_ext}]]"` to the array if it does not exist
4. Update `updated_at` and `updated_by: "sync-people"` in the frontmatter
5. Use Edit to apply the changes to the frontmatter
**Do not modify** any other section of the team file.
At the end of this phase, report: "Phase 5: N teams updated. [list of squads โ number of members added]."
---
## Phase 6 โ Final report
Print a consolidated summary:
```
## Sync People โ Report
| Metric | Value |
|---|---|
| Actors scanned | N |
| Repositories accessed | N |
| Inaccessible repositories | N |
| Commits analyzed | N |
| Contributors found | N |
| People created | N |
| People updated | N |
| Teams updated | N |
### People by squad
| Squad | People |
|---|---|
| squad-payments | alice, bob |
| squad-notifications | carol |
| ... | ... |
### Inaccessible repositories
- owner/repo โ error (if any)
```
---
## General rules
- **Language:** Use the vault's configured language for content, technical terms in English
- **Filenames:** kebab-case, no accents, lowercase
- **Wikilinks:** no path โ `[[name]]`, never `[[people/name]]`
- **Frontmatter:** valid YAML, double quotes for strings with special characters
- **Idempotency:** identify people by `github` login, not by filename
- **Errors:** log and continue โ never fail the entire execution for one repo or person
- **No git:** do not commit, push, or perform any git operations
- **No topics:** do not create/update files in `topics/`
- **No actors:** do not modify files in `actors/`
---
---
# Mode: Sync GitHub (--github)
## Overview
This is an **autonomous agent** designed to run in background without human interaction.
It traverses all actors with `status: active` and a populated `repository` field,
fetches recent PRs via GitHub MCP, filters noise, uses LLM semantic matching to correlate
PRs with existing topics/projects in the vault, and delegates updates to `/bedrock:preserve`.
**Operating mode: autonomous.**
- Does NOT ask for confirmation โ processes and writes automatically
- Safety guaranteed by: (1) only HIGH confidence correlations generate updates,
(2) topics/projects receive informational notes (append), never status overwrite,
(3) medium confidence correlations are recorded in the report for human review
- Generates a report in `fleeting/` at the end of each execution
**For recurring execution:**
- Via `/loop`: `/loop 6h /bedrock:sync --github`
- Via `/schedule`: configure cron with this skill
`/bedrock:sync --github` **does NOT write entities directly** โ all entity writing goes through `/bedrock:preserve`.
Exception: watermark fields (`last_synced_at`, `last_synced_sha`) in actor frontmatter are written
directly via Edit (they are not new entities, they are sync metadata).
`/bedrock:sync --github` **does NOT create new topics or projects** โ it only updates existing ones.
**You are an autonomous execution agent.** Follow the phases below in order, without skipping steps.
Do NOT ask for user confirmation in any phase.
---
## Phase 0 โ Synchronize the Vault
Execute:
```bash
git -C <VAULT_PATH> pull --rebase origin main
```
If the pull fails:
- No remote configured: log "No remote configured. Working locally." and proceed.
- Pull conflict: `git -C <VAULT_PATH> rebase --abort`, log the error and **ABORT** the entire execution.
Record in the report: "Aborted โ git conflict on initial pull."
- Otherwise: proceed.
---
## Phase 1 โ Collect Syncable Actors
1. Use Glob to list all files `<VAULT_PATH>/actors/*.md`
2. Exclude `<VAULT_PATH>/actors/_template.md`
3. For each file, use Read to extract from the YAML frontmatter:
- `status` โ actor status
- `repository` โ GitHub repository URL
- `name` โ actor name
- `last_synced_at` โ date of last GitHub sync (may not exist)
- `last_synced_sha` โ SHA of last sync (may not exist)
4. **Filter syncable actors:**
- Keep only actors with `status: active` (or `in-development`)
- Keep only actors with a populated `repository` field containing `github.com`
- Ignore actors with `status: deprecated` (log: "Actor X ignored โ deprecated")
- Ignore actors without `repository` or with an invalid URL (log: "Actor X ignored โ no GitHub repository")
5. For each syncable actor, extract `owner/repo` from the URL:
- Parse the URL: `https://github.com/<owner>/<repo>/` โ `owner`, `repo`
- Remove trailing slashes and `.git` suffix if present
6. Store the list of syncable actors with: `{filename, name, owner, repo, last_synced_at, last_synced_sha}`
Log: "Phase 1: N actors found, M syncable, K ignored (deprecated/no repo)."
---
## Phase 2 โ Fetch PRs via GitHub MCP
For each syncable actor, fetch recent PRs:
1. Use GitHub MCP directly (NOT via Agent tool โ MCP permissions are not inherited by subagents):
- `mcp__plugin_github_github__list_pull_requests` with parameters:
- `owner`: repo owner
- `repo`: repo name
- `state`: "all" (open, merged, closed)
- `sort`: "updated"
- `per_page`: 20
2. **Filter by watermark:**
- If the actor has `last_synced_at`: keep only PRs with `updated_at` >= `last_synced_at`
- If the actor does NOT have `last_synced_at`: keep only PRs from the last 30 days
> Based on PR #15 merged in orders-api that resolves blocker Y.
> Project status reflects a management decision โ review this suggestion.
> Automatically detected by sync-github@agent.
source: "github"
```
**For actors with relevant activity (all, not just those with correlation):**
```yaml
- type: actor
name: "actor-name"
action: update
content: |
## Recent Activity (sync-github YYYY-MM-DD)
| PR | Title | Status | Author | Date |
|---|---|---|---|---|
| #42 | Feature X | merged | alice | 2026-04-10 |
| #34 | Refactoring Y | open | bob | 2026-04-09 |
source: "github"
```
**Compilation rules:**
- Content for topics/projects: append-only. Add "GitHub Activity" section with `[!info]` callout suggesting status. NEVER overwrite the `status` field directly.
- Content for actors: merge-ok. The "Recent Activity" section replaces the previous version (if it exists).
- `source: "github"` for all entities
- Bare wikilinks: `[[actor-name]]`, never `[[actors/actor-name]]`
### 5.2 Invoke /bedrock:preserve
Use the Skill tool to invoke `/bedrock:preserve --vault <VAULT_NAME>` passing the structured list as argument.
The `--vault <VAULT_NAME>` flag ensures preserve writes to the same vault.
> **IMPORTANT for background execution:** When invoking `/bedrock:preserve`, include in the
> instruction that `/bedrock:preserve` must also operate without human confirmation.
> Add to the prompt: "Autonomous mode โ do not ask for confirmation, process directly."
`/bedrock:preserve` handles:
- Textual matching with existing entities
- Updating existing entities (merge/append-only)
- Bidirectional linking (wikilinks)
- Git commit of entities
### 5.3 Update actor watermarks
After `/bedrock:preserve` completes, update the frontmatter of EACH processed actor (with or without correlation):
1. Use Read to read the actor file
2. Use Edit to update in the frontmatter:
- `last_synced_at`: today's date (YYYY-MM-DD)
- `last_synced_sha`: SHA of the most recent commit from the most recent PR (or keep previous if no PRs)
- `updated_at`: today's date
- `updated_by`: `"sync-github@agent"`
3. If the fields `last_synced_at` and `last_synced_sha` do not exist: add them to the frontmatter (before `updated_at`)