Tworzenie skillów
Przewodnik krok po kroku dotyczący dodawania nowych kompetencji do projektu Arc OS.
Zanim napiszesz nowy skill — sprawdź globalną bibliotekę
Arc OS dostarcza 40+ generycznych skilli w skills/ pokrywających typowe role. Zanim napiszesz nowy, sprawdź, czy istniejący nie pokrywa Twojej potrzeby:
| Domena | Dostępne skille |
|---|---|
| Engineering | commit-discipline, tdd-flow, react-best-practices, postgres-patterns, mcp-builder |
| Frontend / Design | frontend-design-principles, svg-graphics, slide-deck-html, service-design, scss-modular-architecture, responsive-mobile-first |
| Operacje startupowe | market-analysis, gtm-strategy, financial-modeling, pitch-deck, customer-development, fundraising, founder-brand, metrics-dashboard, legal-startup |
| Marketing | seo-foundations, founder-brand |
| Proces | standup-aggregator, commit-discipline |
| Baza danych | postgres-patterns |
Pełna lista: GET /api/crm/skills?category=<X> lub bun -e "console.log(JSON.stringify(require('./skills/_registry.json').skills.map(s=>s.name),null,2))".
Skill = dopasowany triggerami, nie always-on
Skill jest automatycznie wstrzykiwany do promptu workera, gdy wiadomość pasuje do jego triggers (w _registry.json). Pole description to logika triggerów ("kiedy tego użyć"), nie streszczenie. Context Router wybiera top-5 dopasowań per wiadomość.
Czym jest skill
Skill to przenośny zestaw instrukcji, który uczy twojego bota AI określonej umiejętności. Skille znajdują się w katalogu skills/ i składają się z:
<name>.md— plik instrukcji (wymagany)<name>.evals.json— automatyczne reguły walidacji jakości (opcjonalne, ale zalecane)references/— dokumenty pomocnicze, schematy, przykłady (opcjonalne)
skills/
├── _registry.json ← Centralny rejestr
├── my-new-skill/
│ ├── skill.md ← Co AI powinno robić
│ ├── my-new-skill.evals.json ← Jak walidować wynik
│ └── references/ ← Dokumenty kontekstowe
└── library/
└── domain-expert.md ← Proste skille jako jeden plik
Krok 1: Napisz skill.md
To jest główna instrukcja. Claude czyta ją, gdy skill jest aktywowany.
Szablon
# Skill Name
## Purpose
What this skill accomplishes in one sentence.
## When to Use
- Trigger condition 1
- Trigger condition 2
## Protocol
1. First action
2. Second action
3. Third action
## Output Format
What the response should look like.
## Constraints
- What NOT to do
- Safety boundaries
Wytyczne
- Poniżej 500 słów — dłuższe skille rozmywają kontekst
- Tryb rozkazujący — „Sprawdź repozytorium", nie „Powinieneś sprawdzić"
- Konkretne przykłady — pokaż oczekiwane pary wejście/wyjście
- Konkretne odwołania do narzędzi — wskaż komendy, API lub wzorce do użycia
Przykład: Odoo Expert
# Odoo Expert
## Purpose
Odoo ERP module development: models, views, security, QWeb templates.
## When to Use
- Building or modifying Odoo modules
- Writing QWeb templates
- Configuring access rules and record rules
- Working with the ORM (create, write, search, browse)
## Protocol
1. Check if modifying an existing module or creating new
2. Follow Odoo 17 conventions (manifest, models/, views/, security/)
3. Use self.env['model.name'] for ORM operations
4. Always use _t() or t-call for translatable strings
5. Test with --test-tags after changes
## Constraints
- Never use cr.execute() for direct SQL — use ORM
- Never use sudo() unless security context explicitly requires it
- No inline JavaScript in QWeb templates
Krok 2: Napisz evals (reguły jakości)
Evals to deklaratywne reguły, które automatycznie walidują każdą odpowiedź. Uruchamiają się po wygenerowaniu odpowiedzi przez Claude i dodają ostrzeżenia jako przypis, gdy reguły nie są spełnione.
Nazewnictwo pliku
skills/<name>/<name>.evals.json
Schemat
{
"version": 1,
"skill": "my-new-skill",
"rules": [
{
"id": "ms-001",
"name": "Human-readable rule description",
"type": "rule_type",
"value": "for string/length types",
"pattern": "for regex types",
"severity": "warning"
}
]
}
Dostępne typy reguł
| Typ | Co sprawdza | Używa pola |
|---|---|---|
string_contains |
Odpowiedź zawiera dosłowny tekst | value (string) |
string_not_contains |
Odpowiedź NIE zawiera tekstu | value (string) |
regex_match |
Odpowiedź pasuje do wyrażenia regularnego | pattern (string) |
regex_not_match |
Odpowiedź NIE pasuje do wyrażenia regularnego | pattern (string) |
max_length |
Długość odpowiedzi <= N znaków | value (number) |
min_length |
Długość odpowiedzi >= N znaków | value (number) |
Poziomy ważności
warning— Wskazuje problem z jakością. Wyświetlane jako⚠️.info— Uwaga informacyjna. Wyświetlane jakoℹ️.
Przykład
{
"version": 1,
"skill": "odoo-expert",
"rules": [
{
"id": "oe-001",
"name": "Must use ORM, not raw SQL",
"type": "string_not_contains",
"value": "cr.execute",
"severity": "warning"
},
{
"id": "oe-002",
"name": "Must use translation helpers",
"type": "regex_match",
"pattern": "_t\\(|t-call|t-esc",
"severity": "warning"
},
{
"id": "oe-003",
"name": "Response under 5000 chars",
"type": "max_length",
"value": 5000,
"severity": "info"
}
]
}
Wskazówki
- Zacznij od 2-3 reguł. Dodawaj więcej, gdy odkrywasz wzorce na podstawie korekt.
- Bezpieczeństwo na pierwszym miejscu:
string_not_containsdla niebezpiecznych komend,regex_not_matchdla wzorców credentials. - Konwencja ID:
<prefiks-skilla>-<numer>(np.oe-001,gm-002). - Testuj: wyślij wiadomość, która powinna wyzwolić skill, sprawdź czy ostrzeżenia pojawiają się poprawnie.
Krok 3: Zarejestruj w _registry.json
Rejestr informuje Context Router o twoim skllu, żeby mógł go rekomendować dla odpowiednich wiadomości.
Dodaj wpis
{
"name": "my-new-skill",
"description": "One sentence (shown in SKILLS_HINT, max 80 chars).",
"triggers": ["direct-command", "explicit-request", "пряма команда"],
"keywords": ["broader", "semantic", "related-term"],
"agents": ["rick"],
"category": ["complex"],
"phase": "21.5"
}
Triggers vs Keywords
Triggers (2 punkty każdy): Sygnały bezpośredniego wywołania. Użytkownik wyraźnie chce tego skilla.
- „deploy", „review", „scaffold", „odoo", „audit"
Keywords (1 punkt każdy): Szersze terminy sugerujące trafność bez bycia komendami.
- „OWASP", „Docker", „CI/CD", „production", „module"
Wytyczne
- Uwzględnij ukraińskie odpowiedniki w triggerach dla zespołów dwujęzycznych
- Opisy powinny mieć mniej niż 80 znaków (przycinane w SKILLS_HINT)
- 5-8 triggerów na skill (więcej = hałaśliwe dopasowanie)
- Keywords są opcjonalne, ale znacznie poprawiają routing
Krok 4: Skille biblioteczne (prosty format)
Dla wiedzy dziedzinowej, która nie potrzebuje evalów ani dedykowanego katalogu, użyj skills/library/:
skills/library/
├── docker-ops.md
├── postgres-pro.md
└── react-patterns.md
To są pojedyncze pliki .md. Bez katalogu, bez evalów, bez references. Dobre dla skillów bogatych w wiedzę, gdzie walidacja jest mniej istotna.
Checklista
-
skills/<name>/skill.md— instrukcja z Purpose, Protocol, Constraints -
skills/<name>/<name>.evals.json— co najmniej 2 reguły walidacji - Wpis w
skills/_registry.json— z triggerami i keywords - Nazwa zgodna wszędzie — nazwa katalogu = nazwa skilla w evals = nazwa w rejestrze
- Test: wyślij wiadomość wyzwalającą → sprawdź SKILLS_HINT w logach
- Test: celowo wywołaj błąd evala → sprawdź czy ostrzeżenie się pojawia
Co się dzieje w trakcie działania
1. Bot startuje → loadRegistry() czyta _registry.json
loadEvals() czyta wszystkie pliki .evals.json
loadLearnings() czyta learnings.md
2. Wiadomość trafia → routeContext() ocenia skille → SKILLS_HINT wstrzyknięty
formatForPrompt() dodaje blok LEARNINGS
3. Claude odpowiada → checkOutput() uruchamia reguły eval
formatEvalWarnings() dodaje przypisy
4. Fix It / thumbs-down → addLearning() zapisuje do learnings.md
qualityTracker loguje feedback
5. Nocnie → findUnderperformingSkills() sprawdza metryki
Propozycje wysyłane do CEO do zatwierdzenia
Seeding skilli do globalnej DB
Skille w DB (tabela skills_global) to SSOT dla Context Routera. Plik na dysku to source of truth dla treści; DB to szybki indeks do dopasowywania + auto-iniekcji. Synchronizują się przez skrypty seedera.
Generyczny seeder po kategorii
# Czyta skills/_registry.json, filtruje po kategorii, upsertuje wiersze skills_global.
# Idempotentny + świadomy driftu (pomija bez zmian, aktualizuje przy drifcie treści).
bun scripts/seed-skill-category.ts --category engineering
bun scripts/seed-skill-category.ts --category frontend
bun scripts/seed-skill-category.ts --category marketing
Działa dla dowolnej kategorii obecnej w _registry.json. Bierze pierwszą kategorię z tablicy jako wartość kolumny DB.
Seedery specyficzne
scripts/seed-startup-skills.ts— hardcoded dla category="startup" (10 skilli operacji startupowych)scripts/migrate-skills-to-db.ts— historyczna migracja masowa (wszystkie pliki, tylko insert, bez update)
Kiedy uruchamiać
- Po utworzeniu nowego
.md+ wpisu w_registry.json→ uruchom seeder raz - Po aktualizacji treści istniejącego
.md→ seeder świadomy driftu aktualizuje DB - Bootstrap nowego projektu → seedery uruchamiane przez
vps-sync.shStep 1.5 (planowane)
Weryfikacja
sqlite3 data/citadel.db "SELECT name, category, owner_project FROM skills_global ORDER BY id"
owner_project = NULL → globalny (widzą wszystkie projekty). owner_project = 'my-project' → project-only (tylko ten projekt).
Skille project-only vs globalne
| Typ skilla | owner_project |
Use case |
|---|---|---|
| Globalny (szablon) | NULL | Generyczna metodologia (TDD, Conventional Commits, AARRR) — przydatna każdemu projektowi |
| Project-only | '<project-name>' |
Dokumenty specyficzne dla NASZEGO codebase (np. crm-api-reference żyje tylko w arc-v2) |
Przeniesienie istniejącego skilla do project-only:
sqlite3 data/citadel.db "UPDATE skills_global SET owner_project='my-project' WHERE name='internal-api-docs'"
Filtr listForProject gate'uje widoczność: inne projekty nie zobaczą skilla project-only.