Add a one-command installer for the ntfy push notification server
(Ubuntu/Debian and Arch Linux), wired into the todo.py Deploy menu.
Users can now deploy a local ntfy server from the CLI and subscribe
to topics from their mobile device (ntfy app) to receive push
notifications from ERPLibre.
Generated by Claude Code 2.1.101 model claude-sonnet-4-6
Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
Enable deploying and managing ERPLibre on remote servers via SSH
directly from make and the interactive todo.py CLI, since only
local deployment was previously supported.
- New conf/make.ssh.Makefile with 11 targets: ssh_check, ssh_push,
ssh_install, ssh_run, ssh_stop, ssh_restart, ssh_status, ssh_logs,
ssh_make, ssh_install_systemd, ssh_install_nginx
- Variables: SSH_HOST (required), SSH_USER, SSH_PORT, SSH_KEY,
SSH_PATH, SSH_TARGET, SSH_DOMAIN, SSH_ADMIN_EMAIL
- Execute > Deploy menu extended with 11 SSH options in todo.py
- All strings translated fr/en in todo_i18n.py
Generated by Claude Code 2.1.101 model claude-sonnet-4-6
Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
« Installation avec modules extra » (--with_extra) ne clonait pas CybroOdoo
sur un env déjà installé : validate_environment renvoyait « valide » ->
update_environment (où l'état extra est posé via set_version_installed) était
sauté -> get_version_extra restait False -> git_merge_repo_manifest n'ajoutait
pas manifest/git_manifest_extra_odooXX.xml -> CybroOdoo jamais synchronisé ni
ajouté à config.conf (« Nothing to do »).
Nouvelle étape apply_extra_modules(), appelée dans main() quand --with_extra
est demandé (même si l'env de base est déjà installé) : pose l'état extra,
régénère le manifest local + repo sync (clone CybroOdoo). La post-étape qui
suit régénère config.conf, qui prend alors le nouveau chemin d'addons.
--- EN ---
« Install with extra modules » (--with_extra) did not clone CybroOdoo on an
already-installed environment: validate_environment answered « valid » ->
update_environment, where the extra state is set through
set_version_installed, was skipped -> get_version_extra stayed False ->
git_merge_repo_manifest did not add
manifest/git_manifest_extra_odooXX.xml -> CybroOdoo was never synced nor
added to config.conf (« Nothing to do »).
A new step, apply_extra_modules(), is called from main() whenever
--with_extra is requested, even on an already-installed base environment: it
sets the extra state and regenerates the local manifest plus a repo sync,
which clones CybroOdoo. The post-step that follows regenerates config.conf,
which then picks up the new addons path.
Assisted-by: Claude Opus 4.8
update_env_version.py (cible « make install_odoo_XX ») calculait un statut
mais ne faisait JAMAIS sys.exit() et IGNORAIT le retour de
update_environment() (l'install réelle : venv/poetry). Résultat : même
quand install_locally.sh échouait (ex. poetry status 127), le script
sortait 0 -> make 0 -> remote « && » continuait (service créé) ->
__ERPLIBRE_EXIT__ 0 -> le suivi d'installation affichait ✅ à tort.
- main() suit un exit_code : install_system() ou update_environment()
renvoyant une valeur non nulle (os.system : 0 = succès) -> exit_code=1.
- sys.exit(main() or 0) propage réellement l'échec.
- Étapes post-install (pycharm, git_repo_update, generate_config) exécutées
seulement si l'install a réussi (sinon .venv.erplibre absent -> cascade
d'erreurs).
Chaîne désormais complète : install_locally.sh exit 1 -> install_locally_
dev.sh exit 1 -> os.system != 0 -> install_erplibre != 0 ->
update_environment != 0 -> main exit_code=1 -> sys.exit(1) -> make échoue
-> remote && stoppe -> __ERPLIBRE_EXIT__ != 0 -> dashboard ❌.
--- EN ---
update_env_version.py, the « make install_odoo_XX » target, computed a status
but NEVER called sys.exit() and IGNORED the return of update_environment(),
the real install with its venv and poetry. As a result, even when
install_locally.sh failed — poetry status 127, say — the script exited 0 ->
make exited 0 -> the remote « && » carried on and created the service ->
__ERPLIBRE_EXIT__ was 0 -> and the install monitor wrongly showed ✅.
- main() tracks an exit_code: install_system() or update_environment()
returning non-zero — with os.system, 0 means success — sets exit_code=1.
- sys.exit(main() or 0) actually propagates the failure.
- The post-install steps (pycharm, git_repo_update, generate_config) only run
when the install succeeded; otherwise .venv.erplibre is missing and errors
cascade.
The chain is now complete: install_locally.sh exit 1 ->
install_locally_dev.sh exit 1 -> os.system != 0 -> install_erplibre != 0 ->
update_environment != 0 -> main exit_code=1 -> sys.exit(1) -> make fails ->
the remote && stops -> __ERPLIBRE_EXIT__ != 0 -> dashboard ❌.
Assisted-by: Claude Opus 4.8
extraire_svg_graphique_by_3d annote « -> Optional[str] » mais le module
n'importait pas Optional -> « NameError: name 'Optional' is not defined »
au chargement. Ajout de « from typing import Optional ».
--- EN ---
extraire_svg_graphique_by_3d is annotated « -> Optional[str] » but the module
never imported Optional -> « NameError: name 'Optional' is not defined » at
import time. Added « from typing import Optional ».
Assisted-by: Claude Opus 4.8
webdriver.Firefox échouait : « InvalidArgumentException: Argument
--remote-allow-system-access can't be set via capabilities ». Cet argument
(ajouté pour le Firefox snap d'Ubuntu) est désormais REFUSÉ via les
capabilities par les geckodriver récents, qui gèrent seuls l'accès système
du snap. Il cassait donc TOUS les setups sur geckodriver récent (ici Arch
sans snap). On ne le passe plus.
--- EN ---
webdriver.Firefox was failing with « InvalidArgumentException: Argument
--remote-allow-system-access can't be set via capabilities ». That argument,
added for Ubuntu's snap Firefox, is now REFUSED through capabilities by
recent geckodriver versions, which handle the snap's system access on their
own. It therefore broke EVERY setup running a recent geckodriver — here Arch,
with no snap at all. It is no longer passed.
Assisted-by: Claude Opus 4.8
Installation was very noisy: poetry ran "install -vvv" and repo sync /
git daemon ran with -v/--verbose. They are now quiet by default
(poetry -q, repo sync -q, no git daemon --verbose) and the detailed
logs come back only when EL_VERBOSE=1.
Applied to install_locally.sh (poetry) and every manifest script (repo
sync + git daemon). env_var.sh documents EL_VERBOSE and respects a value
already set in the environment, so "EL_VERBOSE=1 make install_odoo_18"
works.
--- FR ---
L'installation était très bavarde : poetry tournait en « install -vvv », et
repo sync comme git daemon en -v/--verbose. Ils sont désormais silencieux par
défaut — poetry -q, repo sync -q, plus de git daemon --verbose — et les
journaux détaillés ne reviennent qu'avec EL_VERBOSE=1.
Appliqué à install_locally.sh (poetry) et à tous les scripts de manifest
(repo sync et git daemon). env_var.sh documente EL_VERBOSE et respecte une
valeur déjà passée dans l'environnement, si bien que « EL_VERBOSE=1 make
install_odoo_18 » fonctionne.
Assisted-by: Claude Opus 4.8
Choosing « remote » as the migration source raised AttributeError: the method
had moved to DatabaseManager, and todo_upgrade still called it on the TODO
object. The remote path was therefore unusable — the only way to start a
migration from a production backup rather than a local zip.
--- FR ---
Choisir « remote » comme source de migration levait une AttributeError : la
méthode avait été déplacée vers DatabaseManager, et todo_upgrade l'appelait
toujours sur l'objet TODO. Le chemin distant était donc inutilisable — le seul
moyen de démarrer une migration depuis une sauvegarde de production plutôt que
depuis un zip local.
Assisted-by: Claude Opus 5
sentencepiece provides the SentencePiece tokenizer (C++) needed by the
MarianMT Android plugin. Cloned shallow (depth=1) alongside whisper.cpp.
--- FR ---
sentencepiece fournit le tokeniseur SentencePiece, en C++, dont le greffon
Android MarianMT a besoin. Cloné en profondeur 1, à côté de whisper.cpp.
Assisted-by: Claude Sonnet 4.6
Ajout remote ggerganov et projet whisper.cpp (clone shallow, revision
master) dans le manifest Google Repo mobile. Chemin cible :
mobile/erplibre_home_mobile/android/app/src/main/cpp/whisper
--- EN ---
Adds the ggerganov remote and the whisper.cpp project (shallow clone,
revision master) to the mobile Google Repo manifest. Target path:
mobile/erplibre_home_mobile/android/app/src/main/cpp/whisper
Assisted-by: Claude Sonnet 4.6
@capacitor/cli v8.x requires Node.js >=22.0.0. The install script
was pinning NODE_MAJOR=20, causing a fatal error when installing
the mobile app via todo.py.
--- FR ---
@capacitor/cli v8.x exige Node.js >= 22.0.0. Le script d'installation
figeait NODE_MAJOR=20, d'où une erreur fatale à l'installation de
l'application mobile depuis todo.py.
Assisted-by: Claude Sonnet 4.6
The path was listed for every version, but git_manifest_odoo18.0.xml does not
declare that repository — only 12.0 to 17.0 and the extra 18.0 manifest do. On
Odoo 18 without the extra modules, repo never syncs the directory, so Odoo was
handed an addons path entry that does not exist.
--- FR ---
Le chemin était listé pour toutes les versions, alors que
git_manifest_odoo18.0.xml ne déclare pas ce dépôt — seuls les manifestes de
12.0 à 17.0 et le manifeste extra de 18.0 le font. Sur Odoo 18 sans les modules
extra, repo ne synchronise jamais ce répertoire : on donnait donc à Odoo une
entrée de chemin d'addons qui n'existe pas.
Assisted-by: Claude Opus 5
Poetry install and git-repo sync are independent (different write
paths). Running them sequentially wastes time. Split install_locally.sh
into EL_PHASE=setup|poetry|all phases so install_locally_dev.sh can
background the repo sync while poetry runs in the foreground, reducing
total install time by up to 50% on slow connections.
Set EL_PARALLEL_INSTALL=0 to restore sequential behavior for debugging.
--- FR ---
L'installation poetry et la synchronisation git-repo sont indépendantes —
elles écrivent à des endroits différents — et les enchaîner fait perdre du
temps. install_locally.sh est découpé en phases EL_PHASE=setup|poetry|all
pour qu'install_locally_dev.sh puisse lancer la synchronisation des dépôts
en arrière-plan pendant que poetry tourne au premier plan, réduisant la
durée totale jusqu'à 50 % sur une connexion lente.
EL_PARALLEL_INSTALL=0 rétablit le comportement séquentiel pour le débogage.
Assisted-by: Claude Sonnet 4.6
CybroOdoo repos are large and slow to clone, making them unsuitable
for default installation. Moves them to opt-in per-version extra
manifests, introduces .erplibre-state.json to track installation
options per Odoo version, and surfaces the choice in the TODO CLI
sub-menu. Switch auto-detects extra from state and warns when no
state is recorded.
--- FR ---
Les dépôts CybroOdoo sont volumineux et lents à cloner, ce qui les rend
inadaptés à une installation par défaut. Ils passent dans des manifestes
extra par version, activés à la demande ; .erplibre-state.json est
introduit pour suivre les options d'installation de chaque version d'Odoo,
et le choix apparaît dans le sous-menu du CLI TODO. Le changement de
version détecte l'option extra depuis cet état et avertit quand aucun état
n'est enregistré.
Assisted-by: Claude Sonnet 4.6
make version had no visibility into whether the mobile project was
active. Add detection via presence of mobile/erplibre_home_mobile
directory (cloned by repo sync --with_mobile) and display its status
alongside the existing Odoo/Python/Poetry version info.
--- FR ---
make version n'avait aucune visibilité sur l'activité du projet mobile.
Ajoute une détection par la présence du répertoire
mobile/erplibre_home_mobile, cloné par repo sync --with_mobile, et affiche
son état à côté des versions Odoo, Python et Poetry déjà présentes.
Assisted-by: Claude Sonnet 4.6
The template wrote « Generated by Claude Code », the form AI_POLICY.md
replaces with the Assisted-by trailer. Three defects rode along: the model
came from ~/.claude/settings.json, which has no model key here, so it
declared the sonnet default rather than the truth; --author alone failed on
the committer, this checkout having no git identity; and [UPD] was missing
from the tag table while being the most used tag, 134 of the last 400.
The model now comes from the session transcript, the only source that
follows a /model switch — checked, it prints Claude Opus 5. The timezone is
left to the system so contributors keep their own, and the menu substitutes
name and email separately, the placeholders no longer being adjacent.
--- FR ---
Le gabarit écrivait « Generated by Claude Code », la forme que AI_POLICY.md
remplace par le trailer Assisted-by. Trois défauts l'accompagnaient : le
modèle venait de ~/.claude/settings.json, sans clé model ici, si bien qu'il
déclarait le défaut sonnet plutôt que la vérité ; --author seul échouait sur
le committer, ce checkout n'ayant aucune identité git ; et [UPD] manquait au
tableau des tags alors qu'il est le plus utilisé, 134 des 400 derniers.
Le modèle vient désormais de la transcription de session, seule source qui
suive un changement par /model — vérifié, elle rend Claude Opus 5. Le fuseau
est laissé au système, pour que chaque contributeur garde le sien, et le
menu substitue nom et courriel séparément, les jetons n'étant plus accolés.
Assisted-by: Claude Opus 5
ERPLibre had no position on AI-assisted contribution while its own history
already carried AI trailers — and carried them in the one field the OCA
policy forbids, Co-authored-by, whose meaning for a machine is legally
undefined.
The policy is adopted rather than reinvented: the file summarises it and
points at the OCA document as the reference, so it cannot drift from
upstream. What it keeps is what a contributor here needs in front of them —
the Assisted-by trailer with one line per model, the ban on AI in authorship
fields, the size and pace expectations, and the fact that responsibility does
not transfer to a tool.
Written as AI_POLICY.base.md, like README, CHANGELOG and TODO: « make
doc_markdown » globs every *.base.md, so a plain .md here would be
overwritten or, worse, silently left out of the bilingual set.
--- FR ---
ERPLibre n'avait aucune position sur la contribution assistée par IA, alors
que son propre historique portait déjà des trailers d'IA — et les portait
dans le seul champ que la politique de l'OCA interdit, Co-authored-by, dont
le sens pour une machine est juridiquement indéfini.
La politique est adoptée plutôt que réinventée : le fichier la résume et
désigne le document de l'OCA comme référence, si bien qu'il ne peut pas
diverger de l'amont. Il retient ce qu'un contributeur d'ici doit avoir sous
les yeux : le trailer Assisted-by, une ligne par modèle, l'interdiction de
l'IA dans les champs de paternité, les attentes de taille et de rythme, et le
fait que la responsabilité ne se transfère pas à un outil.
Écrit en AI_POLICY.base.md, comme README, CHANGELOG et TODO : « make
doc_markdown » balaie tous les *.base.md, si bien qu'un simple .md ici serait
écrasé ou, pire, silencieusement laissé hors de la paire bilingue.
Source: https://github.com/dixmit/oca.github/blob/ai_policy/AI_POLICY.md
Assisted-by: Claude Opus 5
Every session paid ~4 000 tokens for CLAUDE.md and .claude/rules/, and part of
that content no longer described this repository:
CLAUDE.md and 05-environments.md gave .venv.odoo18/bin/python — a path that
does not exist. The real one carries BOTH versions,
.venv.odoo18.0_python3.12.10. 02-project-structure.md announced addons/ and
odoo12.0/, absent from the checkout.
That is the reason for the cuts, more than the token count: the files drifted
from the repository, while « ls » cannot. What a session can rebuild by
reading the code is now left to the code.
02-project-structure.md deleted — a tree that ls gives, and gives right
05-environments.md deleted — a venv list that was simply false
04-code-conventions.md reduced to a pointer at .flake8, .editorconfig and
pyproject.toml, which already hold every value it
repeated, plus the Git conventions, which they
do not
01-versions.md table dropped for the pointer at
conf/supported_version_erplibre.json, whose keys
already pair Odoo with Python
Two blocks move to lazy loading — their body costs nothing until invoked:
03-commands.md -> skill erplibre-commands (kept whole: there is no
« make help » target, and the per-module test recipes
carry flags nobody would guess)
07-documentation.md -> skill erplibre-doc-i18n for the how-to, while the
prohibition « never edit a generated .md » STAYS in
the rules: a rule that must hold at all times cannot
live in a file loaded on demand
Resident guidance: ~3 997 -> ~1 939 est. tokens per session.
--- FR ---
Chaque session payait environ 4 000 jetons pour CLAUDE.md et .claude/rules/, et
une partie de ce contenu ne décrivait plus ce dépôt :
CLAUDE.md et 05-environments.md donnaient .venv.odoo18/bin/python — un chemin
qui n'existe pas. Le vrai porte les DEUX versions,
.venv.odoo18.0_python3.12.10. 02-project-structure.md annonçait addons/ et
odoo12.0/, absents du checkout.
C'est la raison des coupes, plus encore que le nombre de jetons : les fichiers
avaient dérivé par rapport au dépôt, ce que « ls » ne peut pas faire. Ce qu'une
session peut reconstruire en lisant le code est désormais laissé au code.
02-project-structure.md supprimé — une arborescence que ls donne, et donne
juste
05-environments.md supprimé — une liste de venvs simplement fausse
04-code-conventions.md réduit à un renvoi vers .flake8, .editorconfig et
pyproject.toml, qui portent déjà toutes les valeurs
qu'il répétait, plus les conventions Git, qu'ils ne
portent pas
01-versions.md tableau abandonné au profit du renvoi vers
conf/supported_version_erplibre.json, dont les clés
apparient déjà Odoo et Python
Deux blocs passent en chargement paresseux — leur corps ne coûte rien tant
qu'il n'est pas invoqué :
03-commands.md -> skill erplibre-commands, conservée entière : il
n'existe pas de cible « make help », et les recettes
de test par module portent des drapeaux que personne
ne devinerait
07-documentation.md -> skill erplibre-doc-i18n pour le mode d'emploi, tandis
que l'interdiction « ne jamais éditer un .md généré »
RESTE dans les règles : une règle qui doit tenir en
permanence ne peut pas vivre dans un fichier chargé à
la demande
Consignes résidentes : environ 3 997 -> 1 939 jetons estimés par session.
Assisted-by: Claude Opus 4.8
Provides Claude Code with structured context about the
ERPLibre Home Mobile project (OWL 2, Capacitor 8, Vite,
Vitest, SQLite) including stack, conventions, commands,
and migration patterns.
--- FR ---
Fournit à Claude Code un contexte structuré sur le projet ERPLibre Home
Mobile — OWL 2, Capacitor 8, Vite, Vitest, SQLite — incluant la pile
technique, les conventions, les commandes et les motifs de migration.
Assisted-by: Claude Sonnet 4.6
Define the integration contract between erplibre_mobile and ERPLibre
platform: JSON-RPC 2.0 call specs, Note→project.task field mapping,
GeoMultiPoint format for geolocation entries, conflict resolution
strategy, re-auth flow, and version compatibility matrix.
Establishes the shared source of truth before implementation begins.
--- FR ---
Définit le contrat d'intégration entre erplibre_mobile et la plateforme
ERPLibre : spécifications des appels JSON-RPC 2.0, correspondance des champs
Note→project.task, format GeoMultiPoint pour les entrées de géolocalisation,
stratégie de résolution des conflits, flux de réauthentification et matrice
de compatibilité des versions. Établit la source de vérité commune avant que
l'implémentation ne commence.
Assisted-by: Claude Sonnet 4.6
Add a multi-agent orchestrator that coordinates all 25 specialist agents
through 5 phases (analysis, design, implementation, verification, release)
with agent-to-agent communication via Agent Teams. Add /feature slash
command as the entry point. Enable CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS
in project settings to allow direct inter-agent messaging.
--- FR ---
Ajoute un orchestrateur multi-agents qui coordonne les 25 agents spécialisés
en 5 phases — analyse, conception, implémentation, vérification, publication
— avec communication d'agent à agent par les Agent Teams. Ajoute la commande
slash /feature comme point d'entrée. Active
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS dans les réglages du projet pour
autoriser la messagerie directe entre agents.
Assisted-by: Claude Sonnet 4.6
Add a full catalog of Claude Code subagents covering all development
disciplines needed for a banking-grade open-source mobile app:
code quality, QA, backend, frontend, UX, architecture, security,
docs, community, product, ethics, DevOps/SRE, release, incident
response, performance, pentest, accessibility, compliance, risk,
data governance, legal/license, support, localization, and AI
agent engineering.
--- FR ---
Ajoute un catalogue complet de sous-agents Claude Code couvrant toutes les
disciplines de développement nécessaires à une application mobile libre de
qualité bancaire : qualité du code, AQ, dorsal, frontal, UX, architecture,
sécurité, documentation, communauté, produit, éthique, DevOps/SRE,
publication, réponse aux incidents, performance, test d'intrusion,
accessibilité, conformité, risque, gouvernance des données, aspects
juridiques et de licence, soutien, localisation et ingénierie des agents
d'IA.
Assisted-by: Claude Sonnet 4.6