Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .claude/rules/install-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ paths:
./install.sh --with-design-clis # + bundle design (imagemagick · ffmpeg · svgo · sharp-cli)
./install.sh --with-devops-clis # + bundle devops (terraform · ansible · pulumi · act)
./install.sh --with-mobile-clis # + bundle mobile (xcrun · bundler · fastlane · expo · eas-cli)
./install.sh --with-obscura # + Obscura headless browser Rust (required, depuis 2026-05-07) — scraping JS-rendered, JS eval, multi-URL parallèle, serveur CDP · coexiste avec shot-scraper
./install.sh --dry-run # Simuler sans modifier
./install.sh --wizard # Forcer le wizard interactif même sur reinstall
```
Expand All @@ -63,9 +64,16 @@ Pandoc — Convertisseur universel de documents. Promu en base ulk depuis 2026-0
Install : `brew install pandoc` · `apt install pandoc` · `winget install pandoc`. Vérifier : `pandoc --version`.
Règle : à invoquer dès qu'un agent lit/produit un format non-Markdown (`.docx`, `.pdf`, `.rst`, `.org`, `.epub`, `.tex`, `.odt`, HTML riche). Ne JAMAIS réécrire un parser ad-hoc. Voir protocole `framework/agents/_shared/obsidian-doc-protocol.md` (section *CLI Pandoc*).

Shot-Scraper (simonw) — Capture web headless : screenshots, JS execution, arbre d'accessibilité. **Adopté en base ulk depuis 2026-05-06** (priority `required` dans `framework/tools/cli-registry.json`). **Remplace `mcp__chrome-devtools__*` pour tous les agents.** Source : https://github.com/simonw/shot-scraper (MIT).
Shot-Scraper (simonw) — Capture web headless : screenshots, PDF, arbre d'accessibilité, auth interactive. **Adopté en base ulk depuis 2026-05-06** (priority `required` dans `framework/tools/cli-registry.json`). **Remplace `mcp__chrome-devtools__*` pour tous les agents.** Source : https://github.com/simonw/shot-scraper (MIT).
Install : `pip install shot-scraper && shot-scraper install` (télécharge Chromium via Playwright). Vérifier : `shot-scraper --version`.
Usage : `shot-scraper <url> -o file.png [--width W --height H --full-page]` · `shot-scraper javascript <url> "js"` · `shot-scraper accessibility <url>` · `shot-scraper multi shots.yml` · `shot-scraper auth <url> auth.json`. Protocole : `framework/agents/_shared/shot-scraper-protocol.md`. Agents : visual-auditor (03), frontend-qa (02), seo-auditor (32), agamotto (17).
Usage : `shot-scraper <url> -o file.png [--width W --height H --full-page]` · `shot-scraper accessibility <url>` · `shot-scraper pdf <url> file.pdf` · `shot-scraper multi shots.yml` · `shot-scraper auth <url> auth.json`.
Depuis 2026-05-07, **les use cases JS eval (`shot-scraper javascript`) et scraping multi-URL sont délégués à Obscura** (voir ci-dessous). Shot-scraper conserve le rôle visuel : screenshots, PDF, arbre d'accessibilité, auth.
Protocole : `framework/agents/_shared/shot-scraper-protocol.md`. Agents : visual-auditor (03), frontend-qa (02), seo-auditor (32), agamotto (17).

Obscura (h4ckf0r0day) — Headless browser engine en Rust, alternative légère à Chrome headless. **Adopté en base ulk depuis 2026-05-07** (priority `required` dans `framework/tools/cli-registry.json`). V8 + Chrome DevTools Protocol (CDP), compatible Puppeteer/Playwright, stealth mode anti-fingerprinting. Bench : 30 MB RAM (vs 200+ MB Chrome), binaire 70 MB (vs 300+ MB), 85 ms page load (vs ~500 ms). Source : https://github.com/h4ckf0r0day/obscura (Apache-2.0).
Install : binaires releases (`curl -fsSL -o /tmp/obscura.tar.gz https://github.com/h4ckf0r0day/obscura/releases/latest/download/obscura-{aarch64-macos|x86_64-macos|x86_64-linux}.tar.gz && tar -xzf /tmp/obscura.tar.gz -C /tmp && sudo mv /tmp/obscura /usr/local/bin/`) ou `cargo install --git https://github.com/h4ckf0r0day/obscura` (Rust 1.75+). Activation ulk : `./install.sh --with-obscura`. Vérifier : `obscura --version`.
Usage : `obscura fetch <url> --eval "<js>" [--selector S --wait-until networkidle --timeout 10000 --stealth]` · `obscura scrape urls.txt --concurrency N --eval "<js>" --format json` · `obscura serve --port 9222 --stealth`.
Règle : *shot-scraper pour ce qui est visuel, Obscura pour ce qui est donnée*. Obscura prend les use cases scraping JS-rendered, JS eval, multi-URL parallèle (workers natifs Rust ~5-10× plus rapides que `shot-scraper multi`), serveur CDP (clients Puppeteer/Playwright). Protocole : `framework/agents/_shared/obscura-protocol.md`. Agents : visual-auditor (03), frontend-qa (02), seo-auditor (32), agamotto (17).

RTK (Rust Token Killer) — proxy CLI qui compresse la sortie des commandes verbose (-60 à -90% tokens). Adopté en base ulk depuis 2026-04-27 (priority `required` dans `framework/tools/cli-registry.json`).

Expand Down
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ Options et community skills : @.claude/rules/install-reference.md

**Priority rule**: CLI available → use it (0 tokens). No CLI + MCP configured → use MCP. Neither → inform user.

Key CLIs: `gh` (GitHub), `vercel` (deploy), `neonctl` (DB), `gws` (Google), `resend` (email), `rtk` (token compression), `notesmd-cli` (vault Obsidian), `defuddle` (web → Markdown), `pandoc` (conversions de format), `shot-scraper` (captures web, JS, accessibilité).
Shot-Scraper : **obligatoire** depuis 2026-05-06 (priority `required`). Source : https://github.com/simonw/shot-scraper (Simon Willison, MIT). Install : `pip install shot-scraper && shot-scraper install`. Usage : `shot-scraper <url> -o file.png [--width W --height H --full-page]` · `shot-scraper javascript <url> "js"` · `shot-scraper accessibility <url>` · `shot-scraper multi shots.yml`. **Remplace `mcp__chrome-devtools__*` pour tous les agents**. Protocole : `framework/agents/_shared/shot-scraper-protocol.md`. Agents concernés : visual-auditor (03), frontend-qa (02), seo-auditor (32), agamotto (17).
Key CLIs: `gh` (GitHub), `vercel` (deploy), `neonctl` (DB), `gws` (Google), `resend` (email), `rtk` (token compression), `notesmd-cli` (vault Obsidian), `defuddle` (web → Markdown), `pandoc` (conversions de format), `shot-scraper` (captures web visuelles), `obscura` (headless browser Rust — scraping/JS eval/CDP).
Shot-Scraper : **obligatoire** depuis 2026-05-06 (priority `required`). Source : https://github.com/simonw/shot-scraper (Simon Willison, MIT). Install : `pip install shot-scraper && shot-scraper install`. Usage : `shot-scraper <url> -o file.png [--width W --height H --full-page]` · `shot-scraper accessibility <url>` · `shot-scraper pdf <url> file.pdf` · `shot-scraper multi shots.yml` · `shot-scraper auth <url> auth.json`. **Remplace `mcp__chrome-devtools__*` pour tous les agents**. Depuis 2026-05-07, **les use cases JS eval / scraping multi-URL sont délégués à Obscura** (voir ci-dessous) — shot-scraper conserve screenshots, PDF, arbre d'accessibilité, auth interactive. Protocole : `framework/agents/_shared/shot-scraper-protocol.md`. Agents concernés : visual-auditor (03), frontend-qa (02), seo-auditor (32), agamotto (17).
Obscura : **obligatoire** depuis 2026-05-07 (priority `required`). Source : https://github.com/h4ckf0r0day/obscura (Apache-2.0). Install : binaires releases (`curl -fsSL .../obscura-{aarch64-macos,x86_64-linux,x86_64-macos}.tar.gz`) ou `cargo install --git https://github.com/h4ckf0r0day/obscura` (Rust 1.75+). Activation ulk : `./install.sh --with-obscura`. Usage : `obscura fetch <url> --eval "<js>" [--selector S --wait-until networkidle --stealth]` · `obscura scrape urls.txt --concurrency N --eval "<js>" --format json` · `obscura serve --port 9222 --stealth`. Headless browser engine en Rust (V8 + CDP, compatible Puppeteer/Playwright) : 30 MB RAM (vs 200+ MB Chrome), 85 ms page load (vs ~500 ms). **Coexiste avec shot-scraper** : règle simple — *shot-scraper pour ce qui est visuel, Obscura pour ce qui est donnée*. Obscura prend les use cases scraping JS-rendered, JS eval (`--eval`), multi-URL parallèle (`obscura scrape`, workers natifs Rust ~5-10× plus rapides que `shot-scraper multi`) et CDP (clients Puppeteer/Playwright). Protocole : `framework/agents/_shared/obscura-protocol.md`. Agents concernés : visual-auditor (03), frontend-qa (02), seo-auditor (32), agamotto (17).
NotesMD CLI : **obligatoire** depuis 2026-04-29 (priority `required`). Source : https://github.com/Yakitrak/notesmd-cli (Go, MIT). Install : `brew tap yakitrak/yakitrak && brew install yakitrak/yakitrak/notesmd-cli`. Tous les agents qui touchent `docs/spec*` et `docs/todo.md` doivent privilégier `notesmd-cli daily|create|print|search|frontmatter|move` quand la CLI est dispo, et fallback fichier sinon. Avantage majeur sur la CLI officielle Obsidian : **n'exige pas que l'app desktop soit ouverte** (utilisable CI/headless). Voir `framework/agents/_shared/obsidian-doc-protocol.md`.
Defuddle CLI : **obligatoire** depuis 2026-04-29 (priority `required`). Source : https://github.com/kepano/defuddle (MIT, kepano). Install : `npm install -g defuddle`. Usage : `defuddle parse <url|file.html> [--markdown|--json]` — pour toute extraction Markdown depuis le web (preferred over `WebFetch` quand la sortie doit être réutilisée). Skill associée : `kepano-defuddle`.
Pandoc : **obligatoire** depuis 2026-04-29 (priority `required`). Source : https://pandoc.org (GPL-2.0+). Install : `brew install pandoc` · `apt install pandoc` · `winget install pandoc`. À invoquer dès qu'un agent lit/produit un format non-Markdown : `.docx`, `.pdf`, `.rst`, `.org`, `.epub`, `.tex`, `.odt`, HTML riche. Jamais de parser ad-hoc. Exemples : `pandoc -f docx -t markdown brief.docx -o docs/brief.md` · `pandoc -f markdown -t pdf docs/spec.md -o docs/exports/spec.pdf`. Voir `framework/agents/_shared/obsidian-doc-protocol.md` (section *CLI Pandoc*).
Expand Down
196 changes: 196 additions & 0 deletions framework/agents/_shared/obscura-protocol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
---
name: obscura-protocol
type: protocol
description: Protocole partagé Obscura CLI — headless browser Rust pour scraping JS-rendered, JS eval, parallel multi-URL et CDP. Coexiste avec shot-scraper (qui garde screenshots/PDF/a11y).
---

# Obscura Protocol

> Source : https://github.com/h4ckf0r0day/obscura (Apache-2.0)
> Headless browser engine en Rust — alternative légère à Chrome headless.
> 30 MB RAM (vs 200+ MB Chrome) · binaire 70 MB (vs 300+ MB) · 85 ms page load (vs ~500 ms).
> V8 + Chrome DevTools Protocol (CDP) · compatible Puppeteer/Playwright · stealth mode.

## Principe

**CLI-first** : Obscura est la CLI standard pour le **scraping**, **JS eval**, **multi-URL parallèle** et les scénarios **CDP** dans ulk.
**Coexiste avec shot-scraper** : shot-scraper reste la CLI canonique pour les **screenshots**, **PDF** et l'**arbre d'accessibilité**.

### Décision Obscura vs shot-scraper

| Use case | Outil | Raison |
|---------|-------|--------|
| Screenshot PNG/JPEG (single ou multi-viewport) | **shot-scraper** | API dédiée, presets viewport, `multi shots.yml` |
| PDF d'une page | **shot-scraper** | `shot-scraper pdf URL output.pdf` |
| Arbre d'accessibilité (rôles, labels, JSON sémantique) | **shot-scraper** | `shot-scraper accessibility URL` — Obscura n'a pas d'équivalent |
| Auth interactive enregistrée (cookies/session) | **shot-scraper** | `shot-scraper auth URL auth.json` |
| **JS eval / extraction DOM** (titre, h1, meta, listes, computed styles) | **Obscura** | `obscura fetch URL --eval "…"` — démarrage 4-6× plus rapide, RAM /6 |
| **Scraping multi-URL parallèle** (>5 URLs avec extraction) | **Obscura** | `obscura scrape urls.txt --concurrency N --eval "…"` — workers natifs |
| **CDP serveur** (client Puppeteer/Playwright se connecte) | **Obscura** | `obscura serve --port 9222 --stealth` |
| **Scraping JS-rendered protégé** (anti-bot léger, fingerprint) | **Obscura** | `--stealth` actif par défaut côté Obscura |
| **Page navigation + extraction** (un seul flow) | **Obscura** | `obscura fetch --selector --eval --wait-until networkidle` |

> Règle simple : **shot-scraper pour ce qui est visuel, Obscura pour ce qui est donnée**.

## Installation

```bash
# macOS Apple Silicon
curl -fsSL -o /tmp/obscura.tar.gz \
https://github.com/h4ckf0r0day/obscura/releases/latest/download/obscura-aarch64-macos.tar.gz
tar -xzf /tmp/obscura.tar.gz -C /tmp && sudo mv /tmp/obscura /usr/local/bin/

# Linux x86_64
curl -fsSL -o /tmp/obscura.tar.gz \
https://github.com/h4ckf0r0day/obscura/releases/latest/download/obscura-x86_64-linux.tar.gz
tar -xzf /tmp/obscura.tar.gz -C /tmp && sudo mv /tmp/obscura /usr/local/bin/

# Source (Rust 1.75+)
cargo install --git https://github.com/h4ckf0r0day/obscura

# Vérifier
obscura --version
```

Activation ulk : `./install.sh --with-obscura` (ou installé automatiquement en base — voir `priority: required`).

## Commandes Clés

### `obscura fetch` — page unique

```bash
# Page brute (HTML après rendu JS)
obscura fetch https://example.com

# Extraction JS (résultat sur stdout)
obscura fetch https://example.com --eval "document.title"

# Extraction structurée (JSON multi-champs)
obscura fetch https://example.com --eval "JSON.stringify({
title: document.title,
h1: [...document.querySelectorAll('h1')].map(h => h.textContent.trim()),
description: document.querySelector('meta[name=description]')?.content,
canonical: document.querySelector('link[rel=canonical]')?.href,
wordCount: document.body.innerText.split(/\s+/).filter(Boolean).length
})"

# Dump du DOM rendu d'un sélecteur (article, .content, etc.)
obscura fetch https://example.com --selector ".article" --dump

# Attendre networkidle puis extraire
obscura fetch https://example.com --wait-until networkidle --timeout 10000 \
--eval "document.querySelectorAll('a').length"

# Stealth (anti-fingerprinting)
obscura fetch https://example.com --stealth --eval "navigator.webdriver"
```

### `obscura scrape` — multi-URL parallèle

```bash
# urls.txt = une URL par ligne
obscura scrape urls.txt \
--concurrency 8 \
--eval "JSON.stringify({ url: location.href, title: document.title, h1: document.querySelector('h1')?.textContent })" \
--format json > results.json

# CSV pour ingestion tableur
obscura scrape urls.txt --concurrency 4 --eval "document.title" --format csv > titles.csv
```

> Avantage net sur `shot-scraper multi` : workers Rust natifs (`obscura-worker`), pas de fork Python par URL → débit 5-10× supérieur sur des batches > 20 URLs.

### `obscura serve` — serveur CDP

```bash
# Démarrer le serveur CDP (port 9222 par défaut)
obscura serve --port 9222 --stealth --workers 4

# Avec proxy upstream
obscura serve --port 9222 --proxy http://127.0.0.1:8080
```

Un client Puppeteer/Playwright peut alors se connecter via CDP :
```javascript
const browser = await puppeteer.connect({ browserURL: 'http://localhost:9222' });
```

---

## Patterns ulk fréquents

### Audit SEO (titres, descriptions, canonicals)
```bash
obscura fetch "$URL" --eval "JSON.stringify({
title: document.title,
description: document.querySelector('meta[name=description]')?.content,
canonical: document.querySelector('link[rel=canonical]')?.href,
ogTitle: document.querySelector('meta[property=\"og:title\"]')?.content,
ogImage: document.querySelector('meta[property=\"og:image\"]')?.content,
jsonLd: [...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s => s.textContent)
})" > "docs/audits/seo-$DATE.json"
```

### Audit images sans alt
```bash
obscura fetch "$URL" --eval "JSON.stringify(
[...document.querySelectorAll('img')]
.filter(i => !i.alt || i.alt.trim() === '')
.map(i => ({ src: i.src, parent: i.parentElement?.tagName }))
)"
```

### Liens cassés (extraction + check externe)
```bash
obscura fetch "$URL" --eval "JSON.stringify(
[...document.querySelectorAll('a[href]')].map(a => a.href)
)" | jq -r '.[]' | sort -u | xargs -P 8 -I {} curl -sI -o /dev/null -w "%{http_code} {}\n" {}
```

### Crawl + extraction (visual-auditor URL list)
```bash
# 1. Extraire les URLs internes depuis sitemap
obscura fetch "$BASE/sitemap.xml" --eval "[...document.querySelectorAll('loc')].map(l => l.textContent).join('\n')" > urls.txt

# 2. Scraper en parallèle
obscura scrape urls.txt --concurrency 8 \
--eval "JSON.stringify({ url: location.href, title: document.title })" \
--format json > pages.json
```

---

## Limitations

- **Screenshots** : Obscura sait rendre la page (V8) mais shot-scraper reste la voie canonique pour les fichiers PNG/PDF (workflow + presets viewport éprouvés).
- **Arbre d'accessibilité** : pas d'équivalent à `shot-scraper accessibility` — utiliser shot-scraper.
- **Console / Network monitoring** : pas de capture native. Utiliser `obscura serve` + client CDP pour un contrôle fin, ou Lighthouse pour les Core Web Vitals.
- **Auth interactive** : pas d'équivalent direct à `shot-scraper auth`. Workaround : démarrer `obscura serve --stealth` et piloter via Puppeteer/Playwright.

---

## Règle agents ulk

Tout agent qui faisait `shot-scraper javascript URL "…"`, `shot-scraper multi shots.yml` (sans screenshots) ou avait besoin d'un serveur CDP **doit** :

1. Garder `Bash` dans `tools:`
2. Ajouter `extends: _shared/obscura-protocol.md` (en plus de `shot-scraper-protocol.md` si screenshots conservés)
3. Remplacer :
- `shot-scraper javascript URL "JS"` → `obscura fetch URL --eval "JS"`
- `shot-scraper multi shots.yml` (sans screenshots) → `obscura scrape urls.txt --eval "JS"`
4. **Conserver** `shot-scraper` pour : screenshots, PDF, accessibility tree, auth.

Agents directement concernés : **visual-auditor (03)**, **frontend-qa (02)**, **seo-auditor (32)**, **agamotto (17)**.

## Fallback si Obscura absent

Si `obscura` n'est pas dans le `PATH`, l'agent doit tomber sur shot-scraper avec un avertissement explicite :

```bash
if command -v obscura >/dev/null 2>&1; then
obscura fetch "$URL" --eval "$JS"
else
echo "⚠️ obscura absent — fallback shot-scraper (4-6× plus lent sur multi-URL)" >&2
shot-scraper javascript "$URL" "$JS"
fi
```
5 changes: 3 additions & 2 deletions framework/agents/audit/32-seo-auditor.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extends:
- _shared/auditor-base.md
- _shared/checklists/seo-report-template.md
- _shared/shot-scraper-protocol.md
- _shared/obscura-protocol.md
---

# Agent SEO & GEO Auditor
Expand Down Expand Up @@ -250,10 +251,10 @@ find . -path "*/locales/*" -o -path "*/i18n/*" -o -path "*/translations/*" 2>/de

### 3.1 - ANALYSE DU CONTENU

Si URL de production disponible, utiliser shot-scraper javascript :
Si URL de production disponible, utiliser **Obscura** (extraction donnée — démarrage 4-6× plus rapide que shot-scraper, idéal pour multi-URL via `obscura scrape`) :

```bash
shot-scraper javascript "$URL" "JSON.stringify(
obscura fetch "$URL" --eval "JSON.stringify(
(function() {
const h1 = document.querySelectorAll('h1');
const title = document.title;
Expand Down
9 changes: 5 additions & 4 deletions framework/agents/docs/17-agamotto.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extends:
- _shared/design-source-protocol.md
- _shared/update-protocol.md
- _shared/shot-scraper-protocol.md
- _shared/obscura-protocol.md
context_budget: 14000
loads_files: docs/design.md, docs/design-wireframe/_index.md
loads_skills: figma-use, figma-implement-design
Expand Down Expand Up @@ -161,14 +162,14 @@ Demarrage de l'analyse...
→ Capture visuelle globale
```

#### Penpot (via shot-scraper)
#### Penpot (capture via shot-scraper, extraction via Obscura)

```bash
# 1. Capture generale du fichier Penpot
# 1. Capture generale du fichier Penpot (visuel → shot-scraper)
shot-scraper "$PENPOT_URL" -o penpot-capture.png --width 1920 --height 1080

# 2. Extraire les donnees via l'API Penpot
shot-scraper javascript "$PENPOT_URL" "JSON.stringify(
# 2. Extraire les donnees via l'API Penpot (JS eval → Obscura, ~5× plus rapide)
obscura fetch "$PENPOT_URL" --eval "JSON.stringify(
window.app?.main?.store?.state ?? 'Penpot state non accessible'
)"
```
Expand Down
Loading
Loading