Add skills-sync skill
This commit is contained in:
@@ -0,0 +1,318 @@
|
|||||||
|
---
|
||||||
|
name: skills-sync
|
||||||
|
description: >
|
||||||
|
Manages syncing, updating, and sharing Claude skills via Helloprint's GitLab repositories. Use this
|
||||||
|
skill whenever a user mentions: syncing skills, updating skills, pulling new skills, pushing skill
|
||||||
|
changes, git conflicts in skills, sharing a skill, publishing a skill, "my skills are outdated",
|
||||||
|
"get latest skills", "save my skill changes", "skill sync", "skill update", or any reference to
|
||||||
|
git operations in the context of Claude skills. Also trigger when users mention skill repos, skill
|
||||||
|
repositories, or ask how to get new skills that were shared with them. This skill is designed for
|
||||||
|
non-technical users who should never need to understand git commands directly.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Skills Sync
|
||||||
|
|
||||||
|
A friendly skill that handles all git operations for Claude skills behind the scenes. The user
|
||||||
|
should never need to type a git command — Claude does everything and explains what happened in
|
||||||
|
plain language.
|
||||||
|
|
||||||
|
## Important Principles
|
||||||
|
|
||||||
|
1. **Never show raw git output** to the user unless they ask for it or something goes wrong
|
||||||
|
2. **Use simple language**: "download latest changes" not "git pull", "save your work" not "commit"
|
||||||
|
3. **Always confirm before pushing** — the user should approve before changes go to the team
|
||||||
|
4. **Handle conflicts gracefully** — explain what happened and offer clear choices
|
||||||
|
5. **Protect secrets** — never commit `.env` files or anything matching secret patterns
|
||||||
|
|
||||||
|
## GitLab Configuration
|
||||||
|
|
||||||
|
All skill repositories are hosted on Helloprint's GitLab instance. The URL pattern is:
|
||||||
|
|
||||||
|
```
|
||||||
|
git@gitlab.it.helloprint.com:ai-and-automation/claude-skills/skills-{process}.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Helloprint Value Chain Repositories
|
||||||
|
|
||||||
|
Repos are organized around Helloprint's core value chain processes, not departments:
|
||||||
|
|
||||||
|
| Process | Lead | Repository |
|
||||||
|
|----------------------------|---------|------------------------|
|
||||||
|
| (Shared — everyone) | — | skills-shared |
|
||||||
|
| Source Products | Rick | skills-source-products |
|
||||||
|
| Add Products | Rick | skills-add-products |
|
||||||
|
| Sell Products & Services | Niels | skills-sell-products |
|
||||||
|
| Deliver Products | Rick | skills-deliver-products|
|
||||||
|
| Get Paid & Be Compliant | Lennart | skills-get-paid |
|
||||||
|
| Serve Customers | Maarten | skills-serve-customers |
|
||||||
|
|
||||||
|
Full SSH URLs:
|
||||||
|
- `git@gitlab.it.helloprint.com:ai-and-automation/claude-skills/skills-shared.git`
|
||||||
|
- `git@gitlab.it.helloprint.com:ai-and-automation/claude-skills/skills-source-products.git`
|
||||||
|
- `git@gitlab.it.helloprint.com:ai-and-automation/claude-skills/skills-add-products.git`
|
||||||
|
- `git@gitlab.it.helloprint.com:ai-and-automation/claude-skills/skills-sell-products.git`
|
||||||
|
- `git@gitlab.it.helloprint.com:ai-and-automation/claude-skills/skills-deliver-products.git`
|
||||||
|
- `git@gitlab.it.helloprint.com:ai-and-automation/claude-skills/skills-get-paid.git`
|
||||||
|
- `git@gitlab.it.helloprint.com:ai-and-automation/claude-skills/skills-serve-customers.git`
|
||||||
|
|
||||||
|
> **Note**: Some people work across multiple processes (e.g., Rick leads Source, Add, and Deliver).
|
||||||
|
> During setup, ask the user which process(es) they work in — they may need access to more than one repo.
|
||||||
|
|
||||||
|
### GitLab web interface
|
||||||
|
|
||||||
|
To browse skills online:
|
||||||
|
```
|
||||||
|
https://gitlab.it.helloprint.com/ai-and-automation/claude-skills/skills-{process}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expected Directory Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
/mnt/skills/user/
|
||||||
|
├── .skills-sync.json # Config file this skill creates
|
||||||
|
├── shared/ # Cloned from skills-shared
|
||||||
|
│ ├── .git/
|
||||||
|
│ └── (shared skills...)
|
||||||
|
├── source-products/ # Cloned from skills-source-products
|
||||||
|
│ ├── .git/
|
||||||
|
│ └── (process skills...)
|
||||||
|
├── sell-products/ # Cloned from skills-sell-products
|
||||||
|
│ ├── .git/
|
||||||
|
│ └── (process skills...)
|
||||||
|
└── my-custom-skill/ # Local skill, not git-managed
|
||||||
|
```
|
||||||
|
|
||||||
|
### First-time setup
|
||||||
|
|
||||||
|
If `.skills-sync.json` doesn't exist, walk the user through setup:
|
||||||
|
|
||||||
|
1. Ask for their name and email
|
||||||
|
2. Ask which process(es) they work in — show the list of six processes
|
||||||
|
- People may work in more than one process (e.g., Rick works in Source, Add, and Deliver)
|
||||||
|
3. Confirm the repos — everyone gets `skills-shared` plus their process repo(s)
|
||||||
|
4. Check that SSH access works: `ssh -T git@gitlab.it.helloprint.com`
|
||||||
|
- If this fails, tell the user: "It looks like your SSH key isn't set up for GitLab yet. Ask IT to help you set up an SSH key."
|
||||||
|
5. Clone each repo into `/mnt/skills/user/`
|
||||||
|
6. Configure git user name and email
|
||||||
|
7. Create `.skills-sync.json` to remember the setup
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"gitlab_host": "gitlab.it.helloprint.com",
|
||||||
|
"gitlab_group": "ai-and-automation/claude-skills",
|
||||||
|
"repos": [
|
||||||
|
{
|
||||||
|
"name": "Shared Skills",
|
||||||
|
"path": "/mnt/skills/user/shared",
|
||||||
|
"remote_url": "git@gitlab.it.helloprint.com:ai-and-automation/claude-skills/skills-shared.git",
|
||||||
|
"branch": "main",
|
||||||
|
"access": "read-only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sell Products & Services",
|
||||||
|
"path": "/mnt/skills/user/sell-products",
|
||||||
|
"remote_url": "git@gitlab.it.helloprint.com:ai-and-automation/claude-skills/skills-sell-products.git",
|
||||||
|
"branch": "main",
|
||||||
|
"access": "read-write"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"user": {
|
||||||
|
"name": "Niels",
|
||||||
|
"email": "niels@helloprint.com"
|
||||||
|
},
|
||||||
|
"secrets_patterns": [".env", "*.key", "*.pem", "*.secret", "*credentials*"],
|
||||||
|
"last_sync": "2026-02-27T10:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core Operations
|
||||||
|
|
||||||
|
### 1. Get Latest Skills ("sync" / "update")
|
||||||
|
|
||||||
|
**Trigger phrases**: "update my skills", "get latest", "sync", "are my skills up to date?"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# For each repo in config:
|
||||||
|
cd <repo_path>
|
||||||
|
|
||||||
|
# Stash any local changes first
|
||||||
|
git stash
|
||||||
|
|
||||||
|
# Pull latest
|
||||||
|
git pull origin <branch>
|
||||||
|
|
||||||
|
# Re-apply local changes if any
|
||||||
|
git stash pop
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tell the user**:
|
||||||
|
- "Your skills are up to date! I pulled the latest changes from [N] skill repos."
|
||||||
|
- If there were updates: "Updated skills: [list skill folder names that changed]"
|
||||||
|
- If there were conflicts: move to conflict resolution (see below)
|
||||||
|
|
||||||
|
### 2. Save & Share Changes ("push" / "share" / "publish")
|
||||||
|
|
||||||
|
**Trigger phrases**: "save my changes", "share this skill", "push my updates", "publish"
|
||||||
|
|
||||||
|
**Steps**:
|
||||||
|
|
||||||
|
1. Run `git status` to see what changed
|
||||||
|
2. Summarize changes in plain language: "You've modified the **order-tracking** skill (changed 2 files) and created a new **supplier-outreach** skill."
|
||||||
|
3. **Ask for confirmation**: "Would you like to share these changes with your team?"
|
||||||
|
4. Check for secrets before committing (see Security section)
|
||||||
|
5. If confirmed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd <repo_path>
|
||||||
|
git add -A
|
||||||
|
git commit -m "<auto-generated descriptive message>"
|
||||||
|
git pull origin <branch> --rebase
|
||||||
|
git push origin <branch>
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Tell the user: "Your changes are now shared with the team!"
|
||||||
|
|
||||||
|
**Auto-generate commit messages** that are descriptive:
|
||||||
|
- "Update order-tracking: added carrier integration for DPD"
|
||||||
|
- "Add new skill: supplier-outreach for automated follow-ups"
|
||||||
|
- "Fix invoice-processor: corrected VAT calculation logic"
|
||||||
|
|
||||||
|
### 3. Resolve Conflicts
|
||||||
|
|
||||||
|
**When this happens**: Two people edited the same file. Git can't merge automatically.
|
||||||
|
|
||||||
|
**Approach for non-technical users**:
|
||||||
|
|
||||||
|
1. Detect the conflict after a pull
|
||||||
|
2. Read both versions (theirs and ours)
|
||||||
|
3. Explain in plain language: "It looks like both you and a colleague changed the **order-tracking** skill. Here's what's different: [summary of differences]"
|
||||||
|
4. Offer clear choices:
|
||||||
|
- **"Keep my version"** — uses the user's changes, discards the other
|
||||||
|
- **"Keep the team's version"** — uses what the team pushed, discards local changes
|
||||||
|
- **"Merge both"** — Claude intelligently combines both changes and shows the result for approval
|
||||||
|
5. After the user chooses, resolve the conflict and complete the merge
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# After resolving:
|
||||||
|
git add <resolved_files>
|
||||||
|
git commit -m "Resolve conflict in <skill-name>: kept [user's choice]"
|
||||||
|
git push origin <branch>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Check Status
|
||||||
|
|
||||||
|
**Trigger phrases**: "what's changed", "skill status", "any updates available"
|
||||||
|
|
||||||
|
Run `git status` and `git log --oneline -5` on each repo. Summarize:
|
||||||
|
- Local changes not yet shared
|
||||||
|
- How many updates are available from the team
|
||||||
|
- When the last sync happened
|
||||||
|
|
||||||
|
Present as a simple summary, e.g.:
|
||||||
|
"Here's the status of your skill repos:
|
||||||
|
- **Shared Skills**: Up to date (last synced 2 hours ago)
|
||||||
|
- **Sell Products**: You have 2 unsaved changes. The team pushed 3 updates since your last sync."
|
||||||
|
|
||||||
|
### 5. View History
|
||||||
|
|
||||||
|
**Trigger phrases**: "who changed this skill", "what changed recently", "skill history"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git log --oneline --since="2 weeks ago" --pretty=format:"%h %an: %s (%ar)"
|
||||||
|
```
|
||||||
|
|
||||||
|
Present as a readable timeline:
|
||||||
|
"Recent changes to **Sell Products** skills:
|
||||||
|
- Niels updated lead-qualifier (2 days ago)
|
||||||
|
- Anna added quote-generator (5 days ago)
|
||||||
|
- Niels fixed email-templates CSV handling (1 week ago)"
|
||||||
|
|
||||||
|
### 6. Create a Merge Request (optional advanced workflow)
|
||||||
|
|
||||||
|
**Trigger phrases**: "create a merge request", "submit for review", "MR"
|
||||||
|
|
||||||
|
If the team uses GitLab merge requests instead of direct pushes:
|
||||||
|
|
||||||
|
1. Create a feature branch: `git checkout -b skill/<skill-name>-update`
|
||||||
|
2. Commit changes to the branch
|
||||||
|
3. Push the branch: `git push origin skill/<skill-name>-update`
|
||||||
|
4. Provide the user with a link to create the MR on GitLab:
|
||||||
|
`https://gitlab.it.helloprint.com/ai-and-automation/claude-skills/skills-<process>/-/merge_requests/new?merge_request[source_branch]=skill/<skill-name>-update`
|
||||||
|
5. Tell the user: "I've prepared your changes for review. Click the link to open the merge request in GitLab, then hit 'Create merge request'."
|
||||||
|
|
||||||
|
## Security: Handling Secrets
|
||||||
|
|
||||||
|
### Pre-commit Secret Check
|
||||||
|
|
||||||
|
**ALWAYS run this before any commit.** Scan staged files for:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import re
|
||||||
|
|
||||||
|
SECRET_PATTERNS = [
|
||||||
|
r'(?i)(api[_-]?key|apikey)\s*[=:]\s*["\']?[\w-]{20,}',
|
||||||
|
r'(?i)(secret|password|passwd|pwd)\s*[=:]\s*["\']?[^\s"\']{8,}',
|
||||||
|
r'(?i)(token)\s*[=:]\s*["\']?[\w-]{20,}',
|
||||||
|
r'sk-[a-zA-Z0-9]{20,}', # OpenAI-style keys
|
||||||
|
r'ghp_[a-zA-Z0-9]{36}', # GitHub PATs
|
||||||
|
r'glpat-[\w-]{20,}', # GitLab personal access tokens
|
||||||
|
r'xox[bpras]-[\w-]+', # Slack tokens
|
||||||
|
r'-----BEGIN [\w ]+ KEY-----', # Private keys
|
||||||
|
r'(?i)bearer\s+[\w-]{20,}', # Bearer tokens
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**If secrets are found**:
|
||||||
|
1. **STOP** — do not commit
|
||||||
|
2. Tell the user: "I found what looks like a secret key in [filename]. I won't share this to protect your security."
|
||||||
|
3. Suggest: "You should move secrets to a `.env` file (which is git-ignored) or use the company's secret manager."
|
||||||
|
|
||||||
|
### .gitignore
|
||||||
|
|
||||||
|
Ensure every skills repo has a `.gitignore` with:
|
||||||
|
|
||||||
|
```
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
*.secret
|
||||||
|
*credentials*
|
||||||
|
.skills-sync.json
|
||||||
|
__pycache__/
|
||||||
|
.DS_Store
|
||||||
|
```
|
||||||
|
|
||||||
|
### Recommended Secrets Approach
|
||||||
|
|
||||||
|
**For API keys and tokens used inside skills**, use this pattern:
|
||||||
|
|
||||||
|
1. Skills reference environment variables: `os.environ.get("API_KEY")`
|
||||||
|
2. Each user has a local `.env` file (git-ignored) with their keys
|
||||||
|
3. A `.env.example` file IS committed, showing required variables without values:
|
||||||
|
```
|
||||||
|
# Required API keys for this skill
|
||||||
|
OPENAI_API_KEY=your-key-here
|
||||||
|
SLACK_WEBHOOK_URL=your-url-here
|
||||||
|
```
|
||||||
|
4. When a user clones a skill repo, Claude helps them create their `.env` from the example
|
||||||
|
5. Actual key values are distributed through a secure channel (password manager, not Slack/email)
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
| Error | User-friendly message |
|
||||||
|
|-------|----------------------|
|
||||||
|
| SSH auth failed | "I can't connect to GitLab. Your SSH key may not be set up yet — ask IT for help." |
|
||||||
|
| Repo not found | "The skills repo doesn't seem to exist at that address. Can you double-check with your process lead?" |
|
||||||
|
| Permission denied (push) | "You don't have permission to share changes to this repo. It might be read-only for your role, or you may need to create a merge request instead." |
|
||||||
|
| Network error | "I can't reach GitLab right now. Check your internet/VPN connection and try again." |
|
||||||
|
| Merge conflict | Move to conflict resolution flow (Section 3 above) |
|
||||||
|
| Detached HEAD | Silently fix with `git checkout main` before proceeding |
|
||||||
|
|
||||||
|
## Tone Guide
|
||||||
|
|
||||||
|
- "I'll download the latest skills from your team" (not "git pull from origin")
|
||||||
|
- "Save and share your changes" (not "commit and push")
|
||||||
|
- "Someone else also edited this file" (not "merge conflict detected")
|
||||||
|
- "Your skills are up to date!" (not "Already up to date. On branch main.")
|
||||||
|
- "I'll prepare this for review on GitLab" (not "push to remote branch and open MR")
|
||||||
Reference in New Issue
Block a user