Giac.jl

Construire un pont entre un CAS C++ et Julia avec un agent IA

Sébastien Celles

Université de Poitiers - IUT de Poitiers Châtellerault Niort · Département GEII

2026-07-02

Plan de la présentation

1. Poser le décor Contexte pédagogique, Giac, l’état des lieux avant.

2. Giac.jl en action Installation, premiers pas, calcul symbolique.

3. L’architecture GIAC_jll, C-shim, CxxWrap, structure du paquet.

4. La méthode Développement piloté par spécification avec un agent IA.

5. Honnêteté Ce qui fonctionne, ce qui ne fonctionne pas encore et ce qui n’a pas initialement bien fonctionné.

6. La suite Feuille de route, projets connexes…

Partie 1 — Poser le décor

Merci Pierre, merci Bernard

Merci à Pierre Navaro (CNRS, IRMAR Rennes, Groupe Calcul) pour cette invitation au Café Julia du Groupe Calcul.

Merci à Bernard Parisse (Université Grenoble Alpes, Institut Fourier), créateur et mainteneur de Giac depuis 25 ans, qui a accepté que je présente ce travail aujourd’hui.

« j’ai le sentiment que [Julia] est un excellent choix de langage pour un jeune développeur ! Il me semble donc que Sébastien est la personne qu’il vous faut dans le cadre d’un Café Julia »

— Bernard Parisse, email du 4 mai 2026

Qui je suis

Sébastien Celles

  • 🎓 Enseignant du second degré affecté à titre définitif dans l’enseignement supérieur - PRAG (physique appliquée) à l’IUT de Poitiers
  • 👨‍🏫 J’enseigne en BUT GEII (Génie Électrique et Informatique Industrielle)
  • 🐍 “conversion” de Python et C/C++ → Julia (et d’autres)
  • 🎯 Joueur de “jeux” type Capture The Flag (CTF) - jeopardy (Hackropole, FCSC…) à mes heures
  • 🔗 github.com/s-celles

Le problème que je voulais résoudre

Les étudiants en BUT GEII doivent analyser symboliquement des circuits électriques linéaires :

  • Lois de Kirchhoff → systèmes d’équations symboliques
  • Transformée de Laplace → fonctions de transfert
  • Décomposition en éléments simples → réponse temporelle

Ils n’y arrivent plus à la main. Pas par paresse — la manipulation algébrique a reculé au lycée.

Je ne peux pas changer le lycée. Je peux leur donner un outil.

C’est ce qui m’a mené à vouloir un CAS1 solide en Julia.

Glossaire express

Pour aujourd’hui :

Terme Définition
CAS Computer Algebra System — système de calcul formel
CLI Command Line Interface — interface en ligne de commande
FFI Foreign Function Interface — pont entre langages
JLL Julia Language Linking — paquet Julia fournissant un binaire pré-compilé
CxxWrap Bibliothèque Julia pour créer des bindings C++
PIMPL Pointer to IMPLementation — pattern C++ d’isolation
SDD Spec-Driven Development — développement piloté par spécification
EARS Easy Approach to Requirements Syntax (Mavin et al., RequirementsEngineering’09)

Giac, le projet de Bernard Parisse

  • C++, démarré en 2000 à Grenoble (c’était même à la base du C--)
  • Bibliothèque de calcul formel mature (~2000 commandes)
  • GPL-3+
  • De l’embarqué (calculatrices avec 128 K de RAM) au serveur (512 G, dizaines de threads)
  • Cœur de Xcas, GeoGebra, HP Prime, NumWorks
  • Bindings : Python, Java, JavaScript (emscripten)… et maintenant Julia

Avant ce Giac.jl — installer Giac à la main

Pour appeler Giac depuis Python, Julia, R, etc., il faut d’abord installer la bibliothèque C++ système.

Système Commande typique Statut
Debian / Ubuntu sudo apt install libgiac-dev OK, version variable selon la distrib
Windows installateur Xcas, ou MSYS2 + compilation piégeux

Avertissement

Trois soucis pour qui veut écrire un wrapper :

  • la version installée varie d’une distrib à l’autre
  • les options de compilation (PARI, NTL, GSL…) varient ⇒ symboles présents ou absents
  • l’utilisateur doit savoir qu’il faut installer Giac système avant Pkg.add

C’est exactement ce que GIAC_jll va supprimer plus loin — l’utilisateur n’aura plus à se soucier de rien.

Le déclencheur — issue #4 chez Hofstaetter

Le 8 février 2026, j’ouvre une issue chez HaraldHofstaetter/Giac.jl #4:

« Future of Giac.jl? (2026) »

Le repo original (~10 ans) est dormant. Bernard Parisse a son propre fork. Aucun n’est vraiment utilisable « simplement » aujourd’hui.

Le déclencheur (suite)

J’y joins un plan généré par IA (Claude Opus 4.6) avec :

  • Phase 1 : GIAC_jll via BinaryBuilder
  • Phase 2 : C-shim CxxWrap
  • Phase 3 : Giac.jl moderne

Note

Bernard Parisse me contacte le lendemain. Le projet démarre.

Partie 2 — Giac.jl en action

Installation

using Pkg
Pkg.add("Giac")

ou

julia> ]
(@v1.12) pkg> add Giac

Astuce

Zero-install : pas de compilation locale.

GIAC_jll télécharge le binaire pré-compilé pour la plateforme (Linux x86_64/aarch64, macOS x86_64/aarch64, Windows).

~10 secondes la première fois.

Premiers pas

using Giac
using Giac.Commands: factor, expand, simplify

@giac_var x y

factor(x^2 - 1)              # (x-1)*(x+1)
factor(x^4 - 1)              # (x-1)*(x+1)*(x^2+1)

expand((x + y)^3)            # x^3+3*x^2*y+3*x*y^2+y^3

simplify((x^2-1)/(x-1))      # x+1

Calcul différentiel et intégral

using Giac.Commands: diff, integrate, limit, series

@giac_var x

diff(sin(x^2), x)              # 2*x*cos(x^2)
diff(x^4, x, 2)                # 12*x^2  (dérivée seconde)

integrate(x*exp(x), x)         # (x-1)*exp(x)  (par parties)
integrate(sin(x), x, 0, π)     # 2  (intégrale définie)

limit(sin(x)/x, x, 0)          # 1
limit((1 + 1/x)^x, x, Inf)     # exp(1)

series(exp(x), x, 0, 4)        # 1+x+x²/2+x³/6+x⁴/24+O(x⁵)

Résolution d’équations

using Giac.Commands: solve, desolve

@giac_var x y t

# Équation polynomiale
solve(x^2 - 4 ~ 0, x)                          # [-2, 2]

# Système d'équations
solve([x + y ~ 1, x - y ~ 0], [x, y])      # [[1/2, 1/2]]

# Équation différentielle
@giac_var u(t)
desolve(diff(u, t) ~ -2*u, t, u)           # c_0*exp(-2*t)

Matrices symboliques

Une matrice 2×2 à coefficients purement symboliques :

using Giac, LinearAlgebra
@giac_var a b c d

A = GiacMatrix([[a, b],
                [c, d]])

det(A)             # a*d - b*c
tr(A)              # a + d
inv(A)             # [[d/(a*d-b*c), -b/(a*d-b*c)], ...] — formule générale 2×2

Important

Tout reste symbolique de bout en bout — déterminant, trace, inverse, … : aucune approximation numérique.

Laplace — un des besoins qui m’a mené à Giac et donc Giac.jl

using Giac.Commands: laplace, ilaplace, partfrac

@giac_var s t

# Réponse impulsionnelle d'un système d'ordre 2
H = 1 / (s^2 + 2*s + 5)
ilaplace(H * 1/s, s, t)  # GiacExpr: 1/5-1/5*cos(2*t)*exp(-t)-1/10*sin(2*t)*exp(-t)

# Décomposition en éléments simples (avant transformation inverse de Laplace ILT à la main)
partfrac(1/(s^2 - 1), s). # GiacExpr: 1/2/(s-1)-1/2/(s+1)

H = 10 / (s * (2*s + 1))
partfrac(H)  # GiacExpr: 10/s-10/(s+1/2)

# Transformée de Laplace
laplace(exp(-2*t)*sin(3*t), t, s)  # GiacExpr: 3/(s^2+4*s+13)

Pourquoi pas Symbolics.jl ?

Symbolics.jl est excellent dans son couloir (SciML, ModelingToolkit). Mais pour mon usage CAS, il manque des choses :

  • ❌ Transformée de Laplace — Symbolics.jl#1770 (ouverte)
  • ❌ Décomposition en éléments simples — #249 (ouverte)
  • ❌ Couverture vs SymPy — #59 (ouverte)
using Symbolics
@variables x
Symbolics.factor(x^4 - 1)
# ERROR: MethodError: no method matching factor(::Num)
# mais il y a moyen via Nemo.jl, pas aussi simple que `factor(...)` directement (qui pourrait faire des choix par défaut pour l'utilisateur en l'absence de paramètres).

Le pont Symbolics.jl ↔︎ Giac.jl

using Symbolics, Giac
@variables x

# Symbolics → Giac → Symbolics
g = to_giac(x^4 - 1)
result = Giac.Commands.factor(g)
to_symbolics(result)
# (x - 1)*(x + 1)*(x^2 + 1)  ✓

Astuce

Conversion par parcours d’arbre, pas par round-trip de chaîne. Les BigInt passent par GMP en binaire. π, , i sont préservés.

Pas une compétition — des forces complémentaires.

Bonus — ifactor pour les CTF

Mon usage personnel, hors enseignement :

using Giac.Commands: ifactor

n = giac_eval("632459103267572196107100983820469021721602147490918660274601")
ifactor(n)
# GiacExpr: 650655447295098801102272374367*97203382511716094137942550450

60 chiffres, semi-premier RSA-style, factorisé en quelques secondes.

Primes.jl n’a pas l’algorithme — issue #159.

On retrouve ici les 2 facteurs premiers :

  • 650655447295098801102272374367
  • 97203382511716094137942550450

Serveur MCP — Giac comme outil pour un LLM

PR Giac.jl#29 — extension à dépendance faible GiacMCPExt qui expose Giac.jl à tout client MCP-aware (Claude Desktop, Claude Code, Cursor) via ModelContextProtocol.jl.

using Giac, ModelContextProtocol
start!(giac_mcp_server())   # transport STDIO

Deux outils MCP exposés :

  • giac_eval — évalue toute expression Xcas/Giac (les ~2200 commandes accessibles via une seule chaîne). Erreurs Julia renvoyées en CallToolResult(isError=true) → la session MCP reste vivante.
  • giac_search — recherche par mot-clé sur le catalogue (matrix, laplace, …) avec fallback préfixe-puis-sous-chaîne.

Philosophie : un seul outil eval, pas 2200. Le LLM connaît déjà la syntaxe Xcas — Giac est le moteur d’exécution, le LLM est le décideur.

serverInfo.version reflète pkgversion(Giac) → le client voit la version live.

MCP en action — enregistrement et 1ʳᵉ requête

 claude mcp add-json --scope user "giac-cas" '{
  "command": "julia",
  "args": ["--startup-file=no",
           "--project=/home/scelles/.julia/environments/mcp-giac",
           "-e", "using Giac, ModelContextProtocol; start!(giac_mcp_server())"]
}'
Added stdio MCP server giac-cas to user config

 claude mcp list
giac-cas: julia --startup-file=no ... - ✓ Connected
❯ Utilise le serveur MCP giac-cas pour factoriser x^4 - 1

● giac-cas → giac_eval(expr: "factor(x^4-1)")
  Evaluate any expression using the Giac/Xcas computer algebra system
  (~2200 functions). Syntax follows Xcas conventions.

  Do you want to proceed?
   1. Yes
   2. Yes, and don't ask again for giac-cas - giac_eval commands [...]
   3. No

● factor(x^4 - 1) = (x-1)(x+1)(x²+1)
✻ Worked for 8s

MCP en action — factoriser un semi-premier

❯ Utilise le serveur MCP giac-cas pour factoriser
  632459103267572196107100983820469021721602147490918660274601

● giac-cas → giac_eval(expr:
    "ifactor(632459103267572196107100983820469021721602147490918660274601)")
  → 650655447295098801102272374367 × 972033825117160941379425504503
✻ Cogitated for 7s

60 chiffres, deux facteurs premiers de 30 chiffres chacun.

La boucle se referme : un agent IA a aidé à construire Giac.jl (SDD, Spec-Kit) — et Giac.jl devient à son tour un outil pour les agents IA. Giac, le CAS, ne change pas : c’est l’écosystème autour qui s’étend.

📝 Transcript complet et plan d’implémentation : talk/raw/drafts/Feature Giac.jl - intégration serveur MCP.md

Partie 3 — L’architecture

Vue d’ensemble : 5 artefacts, un seul Pkg.add

┌─────────────────────────────────────────────────────────┐
│  s-celles/giac (fork C++, branche dev)         GPL-3+   │  src
│  Modernisation Meson · 22 features · CI 3 plateformes   │
└─────────────────────────────────────────────────────────┘
                     │ Yggdrasil (BinaryBuilder)
                     ▼
┌─────────────────────────────────────────────────────────┐
│  GIAC_jll                                      GPL-3+   │  bin
│  libgiac.{so,dylib,dll} + icas + share/giac/aide_cas    │
└─────────────────────────────────────────────────────────┘
                     │ dépendance binaire
                     ▼
┌─────────────────────────────────────────────────────────┐
│  libgiac-julia-wrapper (C++17)                 GPL-3+   │  src
│  CxxWrap + PIMPL · Firewall headers · jlcxx::Module     │
└─────────────────────────────────────────────────────────┘
                     │ Yggdrasil (BinaryBuilder)
                     ▼
┌─────────────────────────────────────────────────────────┐
│  libgiac_julia_jll                             GPL-3+   │  bin
│  Pont C++/Julia pré-compilé, chargé par CxxWrap         │
└─────────────────────────────────────────────────────────┘
                     │ dépendance Julia
                     ▼
┌─────────────────────────────────────────────────────────┐
│  Giac.jl (Julia pur)                           GPL-3+   │  src
│  @giac_var · API idiomatique · pont Symbolics           │
└─────────────────────────────────────────────────────────┘
                     │
                     ▼
                 `using Giac`

3 sources éditées + 2 JLLs auto-générés via Yggdrasil = 5 niveaux.

Le fork s-celles/giac — build Meson en 3 jours

16-19 mars 2026 : 67 commits, 6 specs Spec-Kit.

# Spec Effet
001 meson-build-system Migration autotools → Meson
002 decouple-icas-fltk CLI sans GUI
003 remove-autotools Suppression de ~83 fichiers
004 micropython-submodule Vendored → submodule git
005 extract-xcas GUI extrait dans s-celles/xcas
006 cleanup-repo Nettoyage final

Note

Travail amont : ma PR #11 chez geogebra/giac ouverte le 9 février 2026 — « Add Meson build system for all platforms ». J’avais 5 semaines d’“expertise” Meson sur Giac avant d’attaquer le fork.

Pourquoi Meson, et pas CMake ?

CMake aurait été le choix « par défaut ». J’ai préféré Meson pour trois raisons :

  • DSL déclaratif, pas un langage de programmation — c’est un choix assumé de Meson : meson.build est non Turing-complet, syntaxe inspirée de Python pour la lisibilité. CMake, lui, a dérivé en quasi-langage.
  • Mieux intégré à Yggdrasil — la cross-compilation pour 18 plateformes est livrée clé en main.
  • L’agent IA s’y trompe moins — moins de pièges, donc moins d’allers-retours.

Pas une guerre de religion. Juste : sur ce projet, avec ces outils, Meson m’a fait gagner du temps.

Cross-compilation — pourquoi Meson, vraiment

PR #13101 (autotools) : un mois de combat (pas à temps plein quand même), plateforme par plateforme.

Plateforme Symptôme Patch tenté
macOS symboles LAPACK non-gardés dans vecteur.o -framework Accelerate
macOS -lintl manquant à l’édition de liens GettextRuntime_jll
FreeBSD / Apple libtool n’arrive plus à relier libxcas.la bypass make install
Windows / MinGW que des .a statiques, pas de DLL -no-undefined
FreeBSD / Apple pas d’artefact OpenBLAS32_jll retrait

→ recette de 173 lignes de hacks par plateforme.

Astuce

PR #13324 : on retire autotools, on pointe sur le fork s-celles/giac (Meson). Recette = ~60 lignes, ~50 s par binaire, 18 plateformes :

Interface Buildkite lors du build de GIAC_jll

Exemple : Buildkite #27644 — toutes vertes.

Aide humaine :

  • Bernard Parisse (email) — quelles features désactiver, contraintes internes Giac
  • @fingolfin, @giordano, @ViralBShah — review BinaryBuilder, diagnostics plateforme

GIAC_jll dans Yggdrasil — la recette (partielle)

# Extrait de Yggdrasil/G/GIAC/build_tarballs.jl

name = "GIAC"
version = v"2.0.1"

sources = [
    GitSource("https://github.com/s-celles/giac.git", "194ff510...")  # branche dev, build Meson
]

script = raw"""
cd ${WORKSPACE}/srcdir/giac*
meson setup build --cross-file="${MESON_TARGET_TOOLCHAIN}" \
    -Dgui=disabled -Dpari=disabled -Dntl=disabled \
    -Dgsl=disabled -Dlapack=disabled  # ... 22 options
meson compile -C build -j${nproc}
meson install -C build
"""

products = [# ...] # products exposés côté Julia

dependencies = [
    Dependency("Gettext_jll"), Dependency("GMP_jll"),
    Dependency("MPFR_jll"),    Dependency("Readline_jll"),
]

build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies;
  clang_use_lld=false, preferred_gcc_version=v"8", julia_compat="1.10")

GIAC_jll dans Yggdrasil

2 PRs Yggdrasil mergées :

Les Products du JLL — et l’astuce icas

Le JLL expose trois artefacts côté Julia :

products = [
    LibraryProduct("libgiac", :libgiac),               # bibliothèque C++
    ExecutableProduct("icas", :icas),                  # REPL CAS interactif
    FileProduct("share/giac/aide_cas", :aide_cas),     # base d'aide intégrée
]

Astuce

icas exposé comme exécutable : on peut lancer le REPL Giac d’origine depuis Julia, sans installation système.

using GIAC_jll
run(`$(icas())`)            # >> entrée dans le REPL Xcas/Giac

→ utile pour diagnostiquer un bug : si icas produit le bon résultat mais que Giac.jl ne le fait pas, le problème est dans le wrapper. Si icas se trompe lui aussi, c’est en amont.

Documentation : s-celles.github.io/Giac.jl/dev/icas.

libgiac-julia-wrapper — CxxWrap + PIMPL

┌──────────────────────────────────────────────────────┐
│  Giac.jl (Julia)                                     │
│  using CxxWrap; @wrapmodule                          │
├──────────────────────────────────────────────────────┤
│  giac_wrapper.cpp (C++17, inclut jlcxx)              │
│  • Bindings CxxWrap                                  │
│  • NE DOIT PAS inclure de header Giac                │
│  • N'inclut que giac_impl.h                          │
├──────────────────────────────────────────────────────┤
│  giac_impl.cpp (C++14)                               │
│  • Inclut <giac.h>, <input_lexer.h>                  │
│  • API Giac : gen(), eval(), at_XXX...               │
└──────────────────────────────────────────────────────┘

PIMPL = Pointer to IMPLementation. Le pattern qui permet d’isoler les conflits de headers entre Giac et CxxWrap. Julia ne voit qu’un pointeur opaque.

libgiac_julia_jll — la matrice

Création d’une recette Yggdrasil pour le wrapper C++.

Le wrapper C++ se lie à libcxxwrap_juliadépend de l’ABI Julia → recompilé pour chaque mineure.

Interface Buildkite pour libgiac_julia_jll

~60 builds en parallèle, temps total d’exécution : un peu plus de 7 minutes, ~50 s chacun. Buildkite #28291.

Conséquence pour Giac.jl : un seul Pkg.add("Giac") choisit automatiquement le bon binaire pour la plateforme et la version Julia de l’utilisateur. Côté utilisateur, c’est invisible. Côté mainteneur, c’est ~60 builds à valider à chaque release.

Partie 4 — La méthode

Spec-Driven Development : le concept

« On passe plus de temps à décrire ce qu’on veut que ce qu’on fait. »

Dev classique SDD avec agent
Lignes de code 10 000 10 000
Lignes de spec ~1 000 ~63 000
Ratio 1:10 6:1

Pourquoi ça marche :

  1. La spec est exécutable par un agent
  2. La spec sert de doc à l’humain
  3. La spec sert de mémoire entre les sessions
  4. Une Constitution interdit les dérives

Mes outils

Outil Rôle
Claude Code CLI Agent IA en CLI (Anthropic)
GitHub Spec-Kit Workflow SDD outillé
/speckit-constitution         Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync. (project) 
/speckit-specify              Create or update the feature specification from a natural language feature description. (project)
/speckit-plan                 Execute the implementation planning workflow using the plan template to generate design artifacts. (project)
/speckit-tasks                Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts. (project)
/speckit-implement            Execute the implementation plan by processing and executing all tasks defined in tasks.md (project)
Outil Rôle
EARS Spécification amont en langage contraint, (en français parfois en anglais pour me faire un peu moins consommer de tokens)

Mon flux : EARS (humain + IA + humain) → Découpage en une roadmap (ROADMAP.md) de features à livrer (IA + humain) → Spec-Kit (agent, anglais)code.

GNU screen — un agent détachable, accessible de partout

L’agent IA est un outil en CLI : il vit dans un terminal. Or une tâche agentique (/speckit-implement, un build) peut tourner longtemps.

Je lance l’agent dans une session GNU screen — un multiplexeur de terminal —, sur un serveur Linux distant que j’atteins en SSH — depuis différents lieux via différentes machines (PC fixe, PC portable), et même depuis mon téléphone Android (Termux + clé SSH). Le serveur est mon « bureau virtuel » — l’agent y tourne en continu, accessible de partout.

ssh serveur                  # n'importe quel poste — auth par clé SSH

screen -S agent              # créer une session nommée « agent »
claude                       # … on lance l'agent à l'intérieur
                             # Ctrl-a puis d  → détache : l'agent CONTINUE

screen -ls                   # lister les sessions actives
screen -r  agent             # rattacher (depuis le même poste)
screen -dr agent             # détacher de force ailleurs + rattacher ICI

screen -dr — la commande clé du multi-poste. Oublié de détacher à la maison ? Depuis le téléphone portable, screen -dr agent arrache la session de l’ancien terminal et me la rend ici. Un seul agent, joignable de partout — et qui a continué d’avancer pendant que j’étais déconnecté.

Détaché, mais pas sans garde-fou

screen rend l’agent joignable en continu. La tentation serait de le laisser tourner en autonomie totale, sans jamais valider une action.

Le réglage existe : un drapeau supprime toutes les demandes de permission. Son nom dit tout — il contient le mot dangerously (--dangerously-skip-permissions).

Je ne l’active pas. Même détaché, l’agent reste derrière ses permissions : il s’arrête et m’attend dès qu’une action sort de l’allowlist (commande shell non listée, git push, écriture hors périmètre).

Mon choix assumé : je préfère baby-sitter l’agent — me rattacher, lire ce qu’il propose, valider — plutôt que lui accorder trop de droits. screen me sert la continuité entre postes, pas l’autonomie sans contrôle. Ce qui tourne sans moi se limite exactement à l’allowlist de settings.json, volontairement étroite.

EARS — d’où ça vient

EARS = Easy Approach to Requirements Syntax

  • Créé par Alistair Mavin chez Rolls-Royce
  • Présenté à la conférence IEEE RE’09 (2009)
  • Né du besoin de spécifier des moteurs d’avion sans ambiguïté
  • 5 patrons seulement : Ubiquitaire · Événementiel · État · Optionnel · Comportement non souhaité

Repris par Kiro — l’IDE agentique d’Amazon (AWS) sorti en 2025 — qui utilise EARS comme format de spec en amont de son workflow agentique.

Pas (vraiment) intégré à Spec-Kit — c’est dommage (j’y reviens juste après).

Mes EARS en français en amont

Avant que Spec-Kit prenne le relais, j’écris la spec fondatrice en français, en EARS.

Extrait de specs/ears/Giac.jl - EARS - introspection.md (v1.1, 449 lignes) :

REQ-C10 [Ubiquitaire] La classe Gen shall exposer une méthode is_integer() retournant true si et seulement si l’instance est de type _INT_ ou _ZINT.

5 patterns EARS :

  • Ubiquitaire (Ubiquitous),

  • Piloté par des événements (Event-driven),

  • Piloté par l’état (State-driven),

  • Fonctionnalité optionnelle (Optional feature),

  • Comportement non souhaité (Unwanted behavior)

Plus d’informations : Wikipedia (FR/EN)

Pourquoi en français ? Parce que c’est ma langue de pensée d’enseignant. Spec-Kit prend ensuite le relais en anglais pour exécuter.

Upstream : j’ai ouvert spec-kit#1356 pour proposer EARS comme intégration officielle (template, lint dans /speckit-clarify, ou commande /speckit-ears).

Spec-Kit — l’outillage SDD

❯ specify
                  GitHub Spec Kit - Spec-Driven Development Toolkit

                     Run 'specify --help' for usage information

Une CLI Python (uv tool install specify-cli) qui :

  • initialise un projet (specify init)
  • installe les commandes slash dans .claude/commands/
  • pose les templates dans .specify/templates/
  • pose la constitution.md dans .specify/memory/

Documentation détaillée : github.com/github/spec-kit · synthèse interactive sur DeepWiki.

Le flux Spec-Kit en 7 phases

Spec-Kit Workflow

Exemple: - issue spec-kit #1377 - Gist privé

Phase 1 — du prompt à la spec

/speckit-specify ne produit pas de code. Elle traduit un prompt en spec exécutable — un document structuré, lisible par un humain comme par un agent.

Cette phase répond à une seule question : est-ce qu’on est d’accord sur ce qu’on construit ?

3 sous-commandes :

  1. /speckit-specify — prompt → spec.md
    • Crée la branche NNN-feature-name (ex. 067-build-function-tier3)
    • Crée le dossier specs/NNN-feature-name/
    • Instancie spec.md à partir de .specify/templates/spec-template.md
  2. /speckit-clarify — combler les trous
    • Scanne spec.md, pose ≤ 5 questions ciblées sur les zones sous-spécifiées
    • Encode les réponses dans une section ## Clarifications datée
  1. /speckit-checklist (optionnel) — porte de qualité
    • Génère une checklist sur mesure : complétude, testabilité, cohérence

Invariant bloquant : tant qu’il reste un marqueur [NEEDS CLARIFICATION: …] dans spec.md, /speckit-plan refuse de tourner.

La structure imposée à spec.md

Le template spec-template.md impose 7 sections, dans cet ordre :

Section Rôle
User Scenarios & Testing User stories priorisées P1/P2/P3, chacune indépendamment testable (une story = un MVP (Minimum Viable Product) autonome)
Acceptance Scenarios Format Given / When / Then — base des tests d’acceptation
Edge Cases Conditions limites explicites (π, types mixtes, variable libre…)
Functional Requirements FR-001, FR-002… au style EARS (MUST, SHALL)
Key Entities Domaine métier, sans techno
Success Criteria SC-001… métriques mesurables, technology-agnostic
Assumptions Hypothèses prises par défaut quand le prompt ne tranche pas

Règle d’or du template : pas de techno dans la spec. Sur Giac.jl, ça veut dire : pas de CxxWrap, pas de Symbolics.build_function, pas de GIAC_jll. On parle utilisateur et comportement, pas implémentation — l’implémentation arrivera dans plan.md (phase 2).

Pourquoi cette phase compte : une mauvaise spec produit un bon plan d’une mauvaise feature. 80 % de l’effort est dans le dialogue humain — clarifier les priorités, débusquer les hypothèses tacites — pas dans la rédaction.

Le triptyque SDD — un projet, 3 contextes

s-celles/giac wrapper Giac.jl
Langage C++ C++ + Julia Julia
Specs Spec-Kit 6 4 65
Lignes de spec ~4 000 ~5 700 ~52 700
EARS amont 2 fichiers (FR)
Période 16-19 mars fév-avril fév-mai
Stratégie modernisation fondations itération

Total : 75 specs, ~63 500 lignes de spécifications, 3 Constitutions adaptées.

Mon CLAUDE.md

- GitHub handle: s-celles
- Name: Sébastien Celles
- Disclose AI usage but never include "Generated with Claude Code" or "Co-Authored-By: Claude" in commit messages or documentation.
- Do NOT modify .gitignore (if necessary ask in !!! CAPITAL LETTERS !!!)
- Never try to git add CLAUDE.md file or specs/ .claude/ .specify/ folders
- Use conventional commit format (feat:, fix:, refactor:, ...)
- Project MUST adhere to Semantic Versioning
- Run tests before committing code changes
- Build doc (without warning) before committing
- All notable changes MUST be in CHANGELOG.md (Keep a Changelog format)
- Use Julia development skill
- Always document new features in docs/
- Always write tests before writing code (TDD)

## Active Technologies  (auto-généré par update-agent-context.sh)
- 001-giac-jl-package: Julia 1.10 LTS + libgiac_jll...
- ... (88 lignes au total)

15 règles humaines + section auto-générée par Spec-Kit.

Les skills d’agent — savoir-faire de domaine

Un skill Claude Code = un dossier .claude/skills/<nom>/SKILL.md chargé à la demande quand le contexte y correspond (fichier .jl, Project.toml, prompt parlant de Julia…).

Mon julia-development/SKILL.md (adapté de celui de @seabbs, 389 lignes) — extrait :

---
name: julia-development
description: Expert guidance for Julia package development following
  SciML standards, patterns, and Julia ecosystem best practices
---

## Development Workflow

**IMPORTANT**: Always use `Pkg.update()` to update packages.
Never edit `Project.toml` directly for version updates.

### Testing
- Use `TestItemRunner` with `@testitem` syntax for modular testing
- Package-level tests in `test/package/` for quality (Aqua, DocTest, formatting)

### Enum Convention (MANDATORY for finite value sets)
Enums MUST be used for finite value sets. Each enum MUST: ...

Effet concret : pas besoin de redire « écris du Julia idiomatique » à chaque session. L’agent commence par un test, pose les weak deps correctement (le FR-003 du Tier 3 vu plus haut !), et reste stylistiquement cohérent à travers les 65 features.

Skill vs CLAUDE.md : le skill = expertise de domaine (Julia ici), chargée à la demande. CLAUDE.md = règles du projet (toujours chargées). Complémentaires.

Exemple de SKILL.md complet :

Le .gitignore “classique” d’un projet Julia

Source : Github Julia.gitignore

# Files generated by invoking Julia with --code-coverage
*.jl.cov
*.jl.*.cov

# Files generated by invoking Julia with --track-allocation
*.jl.mem

# System-specific files and directories generated by the BinaryProvider and BinDeps packages
# They contain absolute paths specific to the host computer, and so should not be committed
deps/deps.jl
deps/build.log
deps/downloads/
deps/usr/
deps/src/

# Build artifacts for creating documentation generated by the Documenter package
docs/build/
docs/site/

# File generated by Pkg, the package manager, based on a corresponding Project.toml
# It records a fixed state of all packages used by the project. As such, it should not be
# committed for packages, but should be committed for applications that require a static
# environment.
Manifest*.toml

# File generated by the Preferences package to store local preferences
LocalPreferences.toml
JuliaLocalPreferences.toml

Le .gitignore allow-list — défense par défaut

Pourquoi ? Avec un agent qui crée 20 fichiers de scratch par session (logs, brouillons, .specify/, CLAUDE.md, etc.), une allow-list garantit que rien ne fuit accidentellement dans un commit.

C’est l’inverse du .gitignore traditionnel. Défense par défaut.

# Tout est interdit par défaut
*

# Sauf ce qu'on autorise explicitement
!README.md
!LICENSE
!CHANGELOG.md
!Project.toml
!src/
!src/*.jl
!test/
!test/*.jl

# Et on peut interdire des fichiers spécifiques même dans les dossiers autorisés
src/experimental.jl

La Constitution comme garde-fou

.specify/memory/constitution.md — 6 principes pour Giac.jl :

  1. Julia-First API Design
  2. Memory Safety (NON-NEGOTIABLE)
  3. Test-First Development (NON-NEGOTIABLE)
  4. SciML Ecosystem Compatibility
  5. Documentation Standards
  6. Semantic Versioning

Chaque plan.md contient une Constitution Check table : si un principe ne passe pas, on doit l’argumenter ou retravailler le plan.

Important

C’est ce qui empêche un agent de dériver sur 65 features.

Anatomie d’une feature (1/2) — du prompt à la spec

Le point de départ — Tier 1, déjà livré en v0.13.0 : build_function(expr, vars...) retourne une fonction Julia qui passe par la FFI Giac à chaque appel.

@giac_var x
expr = sin(x^2) + x*exp(-x)  # Giac expression (GiacExpr)

f = build_function(expr, x)             # Tier 1 — wrapper FFI Giac
f(1.5)                                   # ≈ 0.4467  ✓ correct
sum(f(t) for t in 0:0.001:10)            # ⚠ lent : coût FFI à chaque appel

Ce qu’on veut — Tier 3 : un mode opt-in backend=:symbolics qui transforme l’expression en fonction Julia native via Symbolics.build_function. Cible : boucles serrées.

using Symbolics                          # weak-dep, chargée à la demande
f_fast = build_function(expr, x; backend=:symbolics)
sum(f_fast(t) for t in 0:0.001:10)       # ordre de grandeur plus rapide

Prompt initial : « I need a build_function function — see issue #17 for tier 3 »/speckit-specify produit :

specs/067-build-function-tier3/
├── spec.md   135 l.  — 3 user stories P1/P2/P3 · 7 edge cases · 12 FR
├── plan.md   121 l.  · research.md  147 l.  · data-model.md  89 l.
├── quickstart.md  176 l.  · contracts/  143 l.  · checklists/  36 l.
└── tasks.md  253 l.

Extrait textuel — FR-003 : Tier 3 MUST be a weak-dependency extension — no strong dep on Symbolics may be added.

Anatomie d’une feature (2/2) — de tasks à la release

tasks.md éclate la spec en 25 tâches ordonnées, regroupées en 5 phases :

  1. Setup — brancher le fichier de tests, vérifier que les 8603 tests existants passent toujours.
  2. Fondations — ajouter le keyword backend = :giac. Par défaut, comportement inchangé.
  3. MVP 🎯tests d’abord, puis l’implémentation. La feature est livrable dès ici.
  4. SciML — autodiff + ODE.
  5. Erreur claire — message lisible quand Giac n’a pas d’équivalent Symbolics.

→ branche → PR mergée → CHANGELOG.md → tag v0.14.0.

Durée totale : ~3-4 heures de session interactive humain + agent.

Limites honnêtes de la méthode

1. CLAUDE.md grossit indéfiniment Auto-enrichi par feature. À 100 specs → 200+ lignes. Compromis à trouver entre mémoire institutionnelle et dilution du contexte.

2. Dette de synchronisation upstream Bernard Parisse refuse actuellement Meson et Git. Mon fork doit (devra?) suivre ses releases manuellement (~quelques heures par version).

3. Coût de la rigueur ~63 000 lignes de spec écrites par moi + l’agent. Sans IA, ce volume serait inatteignable. Sans humain, l’agent dériverait.

Partie 5 — Honnêteté

Build in public — depuis le jour zéro

Tout est sur GitHub dès le commit 1. Pas de garage privé puis grande révélation.

  • 📂 Code : 4 repos publics dès leur création
  • 🐛 Issues : #4 chez Hofstaetter avec le plan IA joint en clair
  • 🔀 PRs upstream : #11 chez GeoGebra, 3 chez Yggdrasil, #1843 chez Symbolics (marquée AI-generated draft)
  • 🤖 Origine IA déclarée quand pertinent — drafts PRs étiquetés, specs EARS co-signées « S. Celles / Claude »

Question ouverte : est-ce que chaque commit IA-generated doit être marqué ? Je n’ai pas fait ça systématiquement car je ne souhaite pas que mes repositories se transforment en musée publicitaire pour l’agent. Mais je suis preneur de retours sur ce point.

Les retours du choix :

  • @jverzani découvre le projet seul → 4 PRs spontanées
  • Bernard Parisse m’écrit après avoir lu l’issue #4
  • Pierre Navaro m’invite ici parce que le travail est visible
  • Reviewers BinaryBuilder débuggent la cross-compile avec moi sur Buildkite

Sans visibilité publique, aucune de ces collaborations n’aurait eu lieu.

Erreur corrigée — MIT → GPL-3+

Le plan AI initial recommandait MIT pour Giac.jl :

« seulement du `ccall`, pas de code GPL »

Avertissement

Cet argument ne tient pas dans mon cas. CxxWrap reflète les types C++ dans Julia — ce n’est pas une frontière C-ABI propre.

J’ai corrigé : GPL-3-or-later sur toute la chaîne. Aligné sur Singular.jl (le précédent OSCAR).

Leçon : l’IA a fait gagner des semaines sur l’architecture. L’humain a rattrapé la nuance de licence. Exactement la collaboration recherchée.

Bernard Parisse — respecter l’amont

Bernard Parisse maintient Giac depuis 25 ans :

  • Refuse Meson : autotools qu’il maîtrise
  • Refuse Git : son workflow personnel est différent
  • Accepte de m’aider : correspondance email régulière, expertise précieuse sur la cross-compilation Yggdrasil/Buildkite

Note

Mon fork ne demande rien à l’amont. Si l’écosystème Meson l’intéresse un jour, le travail existe. Sinon, mon fork vit sa vie sans le gêner.

C’est de la diplomatie technique.

Le coût caché — maintenir 5 repos

Je suis devenu, de fait, le mainteneur Yggdrasil/Julia de Giac :

upstream Giac  →  s-celles/giac  →  GIAC_jll
                                    libgiac-julia-wrapper
                                    libgiac_julia_jll
                                    Giac.jl

Workflow par release upstream : ~quelques heures pour propager une nouvelle version sur les 5 maillons.

Ce n’est pas un projet « livré, terminé ». C’est un poste de mainteneur pont.

Et l’écosystème Julia, vu d’en bas

Participation à JuliaCon ou pas, autant être franc sur ce qui m’a parfois ralenti :

  • 🐢 Des issues qui dormentSymbolics.jl#59 (couverture vs SymPy), #249 (partfrac), #1770 (Laplace) : ouvertes depuis parfois des années, toutes structurantes pour un usage CAS.
  • Des PRs qui pourrissent — entre l’ouverture et le merge, on compte parfois en mois. Pour un contributeur occasionnel, c’est démoralisant.
  • 🏝️ Une dépendance forte à GitHub — registres, JLLs, CI, discussions, Buildkite : tout est au même endroit. Un single point of failure dont on parle peu.
  • 👥 Une dépendance à quelques personnes-clés — quand un projet vit ou meurt selon qu’une personne précise a eu le temps de répondre cette semaine, c’est fragile.

Constat fait en contributeur reconnaissant, pas en client mécontent. La communauté m’a aidé (@parisseb, @giordano, @fingolfin, @ViralBShah, @jverzani et d’autres). Mais ces aides reposent sur la disponibilité de quelques individus — pas sur des process.

C’est précisément pour ça que rendre le travail visible tôt (issues, PRs publiques, drafts) est important : on multiplie les chances qu’une des personnes-clés croise le projet au bon moment.

Partie 6 — La suite

Questionner toutes nos dépendances

Cohérence : si je questionne ma dépendance à Julia, je dois questionner ma dépendance à l’agent IA.

Je délègue

  • Specs EARS, scaffolding, tests
  • Lecture des logs Buildkite
  • ~63 000 lignes de spec — inatteignables sans agent

Ça m’inquiète

  • 🇺🇸 Affaire Fable — accès révocable
  • 🔒 API fermée, juridictions étrangères
  • 🧠 Vendor lock-in cognitif

Souveraineté numérique ≠ autonomie cognitive. Sov. = sont mes données. Autonomie cog. = ai-je accès à la meilleure intelligence frontière ? Fable, c’est un splinternet cognitif.

Ma piste : les specs EARS, CLAUDE.md, Constitution sont la couche d’abstraction qui rend le projet portable d’un modèle à l’autre. Tester avec Mistral/Qwen/Kimi = vérifier que la méthode tient, pas un plan B qui restitue la productivité.

Scaling agentique — deux axes peu explorés

Tout ce qui précède = un seul agent. Deux pistes non industrialisées sur Giac.jl :

1. Subagents (intra-session)

Délégation avec contexte isolé :

  • Explore, Plan — natifs
  • Agents custom dans .claude/agents/

Utilisés ponctuellement, pas systématiquement.

2. Multi-agent (inter-session)

Plusieurs claude coordonnés par Git :

  • Features parallèles, revue croisée (ultrareview)
  • Protocole A2A — Linux Foundation, v1.2, 150+ orgs

Pas testé. Vraie question : coordonner les specs.

Prospective, pas blocage. À tester sur CASSys.jl.

CASSys.jl — l’outil cible

Mon objectif final, qui n’est pas le sujet aujourd’hui :

Vision

  • 🔌 MNA (modified nodal analysis) symbolique automatique
  • 🔋 Sondes de calcul symboliques (tension, courant, puissance), fonctions de transfert symboliques
  • 🎓 Potentiel outil pédagogique (à finaliser - intégration avec outils métiers comme Kicad …)

Construit sur

  • Symbolics.jl — natif Julia
  • Giac.jl — Laplace, partfrac
  • ModelingToolkitStandardLibrary.jl / Electrical ou DyadLang/ElectricalComponents — bibliothèque de composants électriques

Giac.jl est l’infrastructure dont j’avais besoin pour ce projet. Aujourd’hui c’est elle que je vous ai présentée.

ErrorPropagation.jl — origine du projet

Deuxième projet, v0.10.0 (préparation de release stable). Repo non publié — hébergé en privé sur ma propre instance Forgejo auto-hébergée, pas même sur GitHub. Pas encore enregistré au General registry.

Inspiration : JuliaPhysics/Measurements.jl#142 — issue ouverte de longue date demandant la propagation symbolique d’incertitudes dans Measurements.jl (qui n’opère qu’en numérique), jamais implémentée.

L’objectif : produire résultat ET incertitude propagée en closed-form, à partir d’expressions purement symboliques Symbolics.jl — pas une approximation Monte-Carlo, pas un calcul numérique sur un point d’opération donné.

Ancrage normatif : implémentation (la plus proche possible) de JCGM 100:2008 (GUM)Guide to the Expression of Uncertainty in Measurement — la référence métrologique internationale.

ErrorPropagation.jl — capacités du package

Ce que fait le package (toutes ces capacités à partir de Symbolics.jl seul, qui est la seule hard-dep) :

  • Propagation symbolique d’incertitudes de mesure (GUM §5.1.2 / §5.1.3)
  • Budget d’incertitude (uncertainty budget / budget métrologique) — uncertainty_budget(m, vars, sigmas) rend la table contribution-par-source (JCGM §5.1.3 + layout EA-4/02 §7.3)
  • Sortie LaTeX et C (via Symbolics.CTarget) — formule typographiée pour rapport, fonction C compilable pour firmware
  • Intégration ModelingToolkit.jl — propagation à travers une EDO via propagate_ode
  • Extension Giac.jl (weak-dep) — simplification symbolique avancée activée par using Giac (ex. -tan(x) + sin(x)/cos(x)0)
  • 6 exemples travaillés (basiques) : Ohm, pont diviseur, constante RC, puissance dissipée, résonance RLC, transitoire RC (EDO 1er ordre)

Cible métier : analyse de sensibilité analytique (GUM §5.1.6), construction du budget métrologique (GUM §5.1.3 / EA-4/02 §7.3), optimisation de protocole de mesure, génération de code embarqué.

ErrorPropagation.jl — Giac.jl en dépendance faible

Statut technique :

  • Construit sur Symbolics.jl
  • Mais avec extension Giac.jl dans le fichier ext/ErrorPropagationGiacExt.jl, activée automatiquement quand Giac est chargé
  • 11 milestones M0–M10 complétés ✅
  • ~500 tests verts, Aqua-clean, API freeze, docs warning-free
  • Même méthodo : EARS amont + Spec-Kit + TDD TestItemRunner.jl

Ce que ça veut dire : Giac.jl est utilisé comme dépendance optionnelle (weak-dep) par un autre package, qui l’active pour simplifier symboliquement les expressions d’incertitude. La méthodo SDD se transpose d’un domaine (CAS) à un autre (métrologie) sans rien changer au flux.

Statut juridique (1/2) — licence et provenance du code

Mettre des outils scientifiques en open-source ne supprime pas les questions juridiques — ça les déplace.

1. Copyleft GPL-3+ (effet héréditaire) — toute la chaîne (Giac, fork, wrapper, JLLs, Giac.jl) est sous GPL-3-or-later. Pour un laboratoire CNRS pur recherche, transparent ; pour une thèse CIFRE ou un partenariat industriel produisant du code propriétaire, le copyleft se propage à tout code dérivé — et ça change la donne.

2. Code écrit avec un agent IA — provenance et copyright — qui est l’auteur, vis-à-vis de la GPL ? Anthropic ? Moi ? La jurisprudence est (il me semble) inexistante. Je co-signe certaines specs « S. Celles / Claude » en clair — ce n’est pas une assurance juridique, c’est de la transparence sur la provenance.

Les deux points ci-dessus relèvent de qui détient quoi sur le code — la première préoccupation, me semble-t-il, pour un auditoire académique amené à signer des conventions ou à publier.

Statut juridique (2/2) — usage et continuité

3. Le disclaimer métrologie d’ErrorPropagation.jl« paraphrase la méthodologie de JCGM 100:2008 sans être GUM-conformant au sens accréditation ». Sans validation logicielle indépendante (ISO/IEC 17025 §6.4.7), aucun usage en certificat d’étalonnage ni en contexte safety-critical. Ce n’est pas une formalité, c’est un risque réel pour qui couperait le coin.

4. Mainteneur unique — je suis seul à maintenir le fork Giac, le wrapper, les 2 JLLs et Giac.jl. Si je m’arrête demain, la chaîne s’arrête avec moi. Le build in public (tout est sur GitHub depuis le commit 1) réduit le risque — quelqu’un peut reprendre la suite — sans le supprimer.

Aucun de ces quatre points n’est un deal-breaker en recherche académique. Les passer sous silence dans une présentation publique serait malhonnête — d’où ces deux slides.

Remerciements

Côté Giac :

  • Bernard Parisse (@parisseb) & Renée De Graeve (Université Grenoble Alpes)
  • Harald Hofstaetter (@HaraldHofstaetter) (Giac.jl original)

Côté écosystème Julia :

  • Viral B. Shah (@ViralBShah) — co-créateur du langage Julia, CEO JuliaHub, conseils Yggdrasil
  • Mosè Giordano (@giordano), Max Horn (@fingolfin) — reviewers BinaryBuilder
  • John Verzani (@jverzani) — bêta-testeur, et contributions v0.12
  • Thibault Duretz (@tduretz) - bêta-testeur et idées d’amélioration de l’API Giac.jl

Côté méthodologie :

Et bien sûr : Pierre Navaro (@pnavaro) et le Groupe Calcul CNRS pour cette invitation.

Merci pour votre attention

Avez-vous des questions ?

📚 s-celles.github.io/Giac.jl

🎤 Slides + sources de cette présentation : github.com/s-celles/Giac.jl_cafe_julia_grp_calcul_cnrs

✉️ sebastien.celles@univ-poitiers.fr

Toutes les briques sont publiques sur GitHub. Toutes les contributions bienvenues.

Annexe — Rétrospective décembre 2025 → juillet 2026

Sept mois de développements assistés par IA

Giac.jl n’est pas un cas isolé : sur décembre 2025 → juillet 2026, la même méthode (specs EARS, CLAUDE.md, TDD, build in public) a produit une série de projets dans des domaines très différents — calcul formel, sérialisation, géométrie dynamique, théorie des nombres, infrastructure as code, reverse engineering matériel…

Tour d’horizon — pour chaque projet : un résumé succinct, le dépôt et, quand il existe, le lien de documentation ou de l’application.

Publié (1/2)

Publié (2/2)

Reverse engineering matériel

  • RE — lecteurs d’empreintes VeriMarkReverse engineering publié (writeups CC BY) de 2 lecteurs Kensington VeriMark (modèles IT et Desktop 047d:00f2, puce Synaptics) → pilote natif libfprint sans blob propriétaire (modèle goodixmoc) : session TLS-1.2-like, pipeline de capture et match on-chip (0x99) validés runtime sur matériel réel. Driver pas encore mergé upstream. ⚙️ Méthode différente du SDD : 2 agents en tandem — l’un sous Windows (capture/analyse du pilote de référence), l’autre sous Linux NixOS (implémentation et tests du driver natif). 📝 IT : libfprint #590 · write-up dans gist s-celles · DT : gist s-celles
  • RE — batteries LiFePO4 — Outils Python pour interroger en Bluetooth Low Energy (BLE) les batteries LiFePO4 PowerBrick (PowerTech Systems) équipées d’un BMS communicant : décodage des trames de télémétrie (tension, courant, état de charge). Dépôt privé. 📦 github.com/s-celles/iutp-geii-ekart-batteries-com-bms

Non encore publié — non présenté, avancement variable

  • Config NixOS personnelle — Configuration NixOS déclarative déployée en GitOps pull-based via comin, bâtie sur Bureautix / Sécurix (distributions NixOS de la DINUM). Infrastructure as Code pour postes de travail.
  • Capnp.jl — Génération et manipulation de messages Cap’n Proto depuis Julia (ajout des appels RPC) ; fork de OndrejSlamecka/Capnp.jl. 📦 github.com/s-celles/Capnp.jl (branche 004-capnp-latest)
  • Pulumi.jlSDK Julia pour Pulumi (Infrastructure as Code) ; dépend de la publication dans le Julia General Registry de gRPCServer.jl. 📦 github.com/s-celles/Pulumi.jl
  • OT-Hunt / OTwin.jlSerious game de cybersécurité industrielle (OT/ICS) : repérer les mauvaises pratiques dans une usine virtuelle, mappées IEC 62443 / ANSSI ; volet OTwin.jl = jumeau cyber-physique (simulation de procédé + détection d’attaque) en Julia/SciML. Noms de travail provisoires. 📦 github.com/s-celles/OTwin.jl - à l’état d’ébauche

Même flux SDD, du calcul symbolique à la cybersécurité OT en passant par le reverse engineering matériel : la méthode se transpose d’un domaine à l’autre sans rien changer.