No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
manu e88b79c3a4 fix(skills): read app tokens through ais-op, never sudo
AI agents on an ai-server now run under no-new-privs: sudo never works
for them, and /run/secrets is root-only. Every skill that read a token
with `sudo grep|cat … /run/secrets/…` (30 files) now reads one declared
key with `ais-op secret <app> <KEY>` (`ais-op list` shows what exists).

Most of those reads named keys or files no code writes (OUTLINE_API_TOKEN,
STALWART_API_KEY, POSTIZ_API_TOKEN, MM_BOT_TOKEN, ODOO_API_KEY…): the keys
now come from what each app declares in its meta.nix. For apps that
provision no token, the person creates one in the app and stores it with
`mask secrets create <app>-api`; the skill says so when the read fails.

Root-only steps (occ, mmctl --local, the garage CLI, docker exec, rebuilds,
writing under /run/secrets) are handed to the person with the exact
command. vaultwarden logs in to /admin with the plaintext password and a
cookie (ADMIN_TOKEN is an Argon2 verifier); stalwart uses Basic auth as
admin; nextcloud's auth header was never sent correctly and is fixed.
2026-11-04 05:07:03 +01:00
scripts refactor(apps): move apps to folder 2026-09-25 03:04:00 +02:00
skills fix(skills): read app tokens through ais-op, never sudo 2026-11-04 05:07:03 +01:00
.woodpecker.yml feat: declare skill dependencies as tags and publish a generated hub index 2026-09-24 18:18:38 +02:00
README.md docs: describe the one-call install from main and the public repository 2026-09-25 05:52:02 +02:00
skillshare-hub.json feat(agenda): free/busy skill, and radicale points to it 2026-11-04 04:51:45 +01:00

skills

La bibliothèque de skills livrée sur chaque serveur ai-server. Un dossier par skill, chacun avec son SKILL.md.

Comment elle arrive chez un client

Elle n'est pas copiée par un rebuild. Le provisionneur provision.d/skills.sh (dépôt ai-server) lit l'index skillshare-hub.json de main, choisit d'après les tags les skills qui valent pour ce serveur, et les installe en un seul appel, dans un groupe ai-server/, chez chaque utilisateur qui a un profil home :

skillshare install https://git.serveur-ia.fr/dist/skills.git \
  -s n8n,pages,server-apps,server-config --into ai-server --force
skillshare hub add https://git.serveur-ia.fr/dist/skills/raw/branch/main/skillshare-hub.json -l ai-server

--force réinstalle par-dessus la version en place (c'est ainsi que les mises à jour arrivent) et saute l'audit de skillshare. Le hub permet à l'utilisateur de parcourir le reste de la bibliothèque (skillshare search --hub ai-server). Puis skillshare sync projette le groupe dans le dossier de chaque agent installé (~/.claude/skills/, ~/.agents/skills/).

Les mises à jour arrivent au provisioning suivant (mask provision config skills). Un skill dont l'app est désactivée reste installé. Un skill écrit par l'utilisateur ou livré par un profil home vit à côté du groupe et n'est jamais touché.

Côté serveur, la source de vérité est server.skillLibraries.ai-server (url, index), déclarée par défaut dans ai-server. Le dépôt est public : le provisioning n'envoie aucun identifiant.

Tout ce qui est poussé sur main atteint les serveurs au provisioning suivant. Un skill qui dépend d'une capacité d'ai-server récente casse chez un serveur qui n'a pas encore rebuild : ne le pousser qu'une fois cette capacité déployée.

Tags : ce qui décide où un skill est installé

Chaque SKILL.md déclare ses dépendances dans son frontmatter, par ses tags :

---
name: matrix-bot
tags: app:tuwunel
description: …
---
  • app:<nom> : installé seulement là où l'app <nom> est activée. Plusieurs tags app: = il faut toutes les apps (tags: app:n8n, app:nocodb).
  • server : installé sur tout serveur (server-config, server-apps).
  • Aucun tag : installé nulle part. Un oubli se voit, il ne fuit pas.

Forme imposée : virgules, sur une ligne. Le parseur de skillshare est naïf : tags: [a, b] donne les tags [a et b], et une liste YAML à tirets est ignorée sans erreur. La CI refuse les deux.

L'index skillshare-hub.json

C'est le catalogue que lit le provisioning : il est généré, jamais écrit à la main, et commité.

scripts/hub-index.sh           # régénère après avoir ajouté/modifié un skill
scripts/hub-index.sh --check   # ce que fait la CI (bloquante)

Il faut skillshare (la version livrée par ai-server, pkgs/skillshare) et jq. La CI (.woodpecker.yml) échoue si l'index n'est pas à jour, si un skill n'a pas de tag valide, ou si un dossier de skill manque à l'index.

Ce qui n'est PAS ici

  • Les skills propres à un intégrateur → son profil dans ai-server-home, sous <profil>/.config/skillshare/skills/<nom>/. Même bibliothèque, autre producteur, aucun conflit.
  • Les skills qu'un utilisateur écrit lui-même → skillshare new <nom> chez lui. Rien ici ne peut les effacer.
  • Les skills de développement d'ai-server lui-même (create-app, ci…) → ai-server/.claude/skills/, qui ne quitte pas le poste de dev.

Contribuer

$EDITOR <skill>/SKILL.md
scripts/hub-index.sh
git add -A && git commit -m "…" && git push

La mise à jour atteint un serveur au mask provision config skills suivant. La bibliothèque livrée est déclarée trusted côté serveur (--force) : l'audit de skillshare, qui lit chaque curl … $TOKEN d'une doc d'API comme une exfiltration, est sauté pour elle.

Documentation : server/docs/skills.md (admin, EN) et ../dev-docs/docs/skills.md (conception, FR) dans le dépôt ai-server.