AAUL - Agent Auto Update Linux Permet de géré un agent a distance qui permet de recevoir les informations de update et de forcer les updates. Même de programmer quand le faire automatiquement ! / AAUL allows you to remotely manage an agent that reports available update information and lets you force updates when needed. You can also schedule updates to run automatically at a specific time.
  • JavaScript 62.3%
  • Python 18.2%
  • Go 15.1%
  • Shell 3.5%
  • CSS 0.6%
  • Other 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
aporler 18e29599f5 feat(commands): file d'attente de commandes par machine
Une machine n'acceptait qu'une commande à la fois : toute nouvelle demande
était refusée (409) tant que la précédente n'était pas terminée, et les actions
en masse ignoraient purement les machines occupées.

Chaque machine a désormais sa file : jusqu'à 10 commandes, exécutées l'une
après l'autre dans l'ordre d'envoi. L'essentiel existait déjà — le poll remet
la plus ancienne commande QUEUED une fois que rien n'est IN_PROGRESS, et
l'en-tête X-Skip-Command empêche de remettre une commande à un agent occupé.
La limite tenait à un seul contrôle, au moment de la création.

Ce contrôle est remplacé par trois règles, dans un module unique
(utils/command-queue.js) partagé par les routes, les actions de groupe et le
CLI, pour que les trois ne puissent plus diverger :
- une commande identique déjà en attente n'est pas ajoutée une seconde fois :
  l'appelant récupère l'existante et la suit comme la sienne ;
- plus rien n'est accepté derrière une désinstallation, la machine ne
  reviendra pas le chercher ;
- la file est plafonnée à 10 commandes.

La mise à jour des agents en masse, la vérification des mises à jour,
l'inventaire des paquets et les actions de groupe rejoignent la file des
machines occupées au lieu de les sauter.

Côté agent (0.13.0), la boucle est réveillée dès qu'une commande se termine,
au lieu d'attendre son intervalle : une file de cinq commandes à 15 s ne met
plus plus d'une minute rien qu'à démarrer. Le réveil est émis après la
libération du verrou — réveillé avant, le poll suivant montrerait encore
l'agent occupé et le reste de la file attendrait un intervalle entier. Un
agent plus ancien fonctionne avec la file, à raison d'une commande par
intervalle.

L'interface affiche « +N en file » dans la colonne des commandes, et une
commande qui attend son tour n'est plus annoncée comme un délai dépassé.

Dashboard 0.16.0 / agent 0.13.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 02:49:42 +00:00
agent feat(commands): file d'attente de commandes par machine 2026-09-11 02:49:42 +00:00
dashboard feat(commands): file d'attente de commandes par machine 2026-09-11 02:49:42 +00:00
dev-plugin chore: annule les changements de permissions inclus par erreur 2026-09-01 21:35:16 +00:00
docs feat(commands): file d'attente de commandes par machine 2026-09-11 02:49:42 +00:00
.gitignore fix(build): l'agent Windows doit atteindre la prod par git pull 2026-09-03 00:09:17 +00:00
AAUL Initial commit 2026-07-17 10:55:18 -04:00
CODE_OF_CONDUCT.md chore: annule les changements de permissions inclus par erreur 2026-09-01 21:35:16 +00:00
CONTRIBUTING.md chore: annule les changements de permissions inclus par erreur 2026-09-01 21:35:16 +00:00
install.sh refactor(version): une seule source par composant, tout le reste en dérive 2026-09-03 01:40:12 +00:00
LICENSE chore: annule les changements de permissions inclus par erreur 2026-09-01 21:35:16 +00:00
README.md feat(commands): file d'attente de commandes par machine 2026-09-11 02:49:42 +00:00
RELEASE.md feat(commands): file d'attente de commandes par machine 2026-09-11 02:49:42 +00:00
release.sh refactor(version): une seule source par composant, tout le reste en dérive 2026-09-03 01:40:12 +00:00
SECURITY.md chore: annule les changements de permissions inclus par erreur 2026-09-01 21:35:16 +00:00

Agent Auto Update Linux

Ce projet est Québecois et donc généralement programmer en Francais mais pour el rendre plus universel ici c'est en Anglais mais en bas vous aurez des lien vers le projet Auxinux et sont Wiki est en Francais

Agent Auto Update Linux, or AAUL, is a small fleet management project built around two parts:

  • dashboard/: the server-side dashboard and API used by administrators
  • agent/: the client-side agent installed on managed machines

The original project name says "Linux", but the current codebase also supports macOS and Windows for agent installation and update flows.

The dashboard is responsive: it is usable from a phone or tablet, not only from a desktop browser.

What the project does

AAUL lets you register a machine in the dashboard, generate a one-time installer URL, and let the agent poll the dashboard for work.

The dashboard can:

  • register agents and generate installation commands
  • queue commands such as RUN_NOW, SET_SCHEDULE, UPDATE_AGENT, UNINSTALL (up to ten per machine, run one after another in the order they were sent)
  • display machine state, package information, logs, and last-seen activity
  • show live CPU / memory / disk usage per host, with 24-hour history
  • aggregate pending updates across the whole fleet and flag the security ones
  • push a log-retention policy that every agent enforces locally
  • report antivirus health per host, check it hourly, start a remote scan, turn real-time protection back on (never off: that stays on the machine), and offer to install ClamAV on Linux hosts that have no antivirus
  • build and serve the latest agent bundle used for agent self-update

The agent can:

  • install on Debian/Ubuntu, Fedora/RHEL, Arch Linux, macOS, and Windows 11
  • report local system information back to the dashboard
  • report lightweight vital signs (CPU, memory, disk, load) on every check-in
  • apply operating system updates using the native package manager
  • report which pending updates come from a security channel
  • report antivirus health (product, real-time protection, signature freshness, last scan, detected threats), run a scan on demand, turn real-time protection on, and install ClamAV — each only when asked
  • prune its own log directory according to the dashboard's retention policy
  • update itself from the bundle exposed by the dashboard
  • run as a background service on each supported platform

Repository layout

agent/
  app/                    Python agent runtime (Linux, macOS)
  app/lib/metrics.py      Vital signs collected on every check-in
  app/lib/antivirus.py    Antivirus health and on-demand scans (ClamAV)
  app/lib/logs.py         Log listing, reading and retention
  systemd/                Linux service templates
  windows/                Go agent for Windows — one static binary, no runtime

dashboard/
  client/                 React + Vite frontend
  server/                 Express API and server-side logic
  public/agent/           Built agent bundle served to clients
  config/config.json      Static dashboard configuration

docs/
  ARCHITECTURE.md         High-level codebase tour
  SECURITY_AUDIT.md       Security notes and historical findings

install.sh                Production installer / updater for the dashboard
AAUL                      Local wrapper for the dashboard CLI during development

How it works

  1. An administrator creates an agent entry from the dashboard.
  2. The dashboard stores an install token and an agent API token.
  3. The generated /install?token=... URL returns a platform-specific installer script.
  4. The installer downloads the latest agent bundle from /agent/latest.tar.gz.
  5. The installed agent polls /api/agent/poll and executes queued commands.
  6. The agent reports results to /api/agent/command-result.

The agent never needs inbound access from the dashboard. The communication model is poll-based.

Supported platforms

Agent package updates are implemented for:

  • Debian and derivatives through apt
  • Fedora / RHEL families through dnf or yum
  • Arch Linux and derivatives through pacman
  • macOS through softwareupdate, plus Homebrew when present
  • Windows 11 through winget and Windows Update APIs

Windows agent

The Windows agent is a separate program: a single static Go binary that lives in agent/windows/. Linux and macOS keep the Python agent.

The split exists because the runtime, not the agent, was the problem. Getting a usable Python interpreter onto a fresh Windows machine took roughly 260 lines of PowerShell — working around the Microsoft Store alias stub under WindowsApps, installing Python through winget, locating it again outside the session PATH, creating a virtualenv, verifying pip really existed — and it kept breaking. A Go binary has nothing to bootstrap, so the installer is down to ~130 lines that place a file and register a service.

What that changes on a managed machine:

  • Prerequisites: administrator rights, and nothing else. No Python, no virtualenv, no pip, no tar.
  • Service: a real Windows service (AgentAutoUpdate), visible in services.msc, started at boot and restarted by the SCM on failure — instead of a SYSTEM scheduled task.
  • Daily updates: run by the service itself, and caught up if the machine was off when the window passed. There is no second scheduled task to drift out of sync with config.json.
  • CLI: the service binary is the CLI (aaul-agent status), added to the machine PATH at install. No wrapper .cmd.
  • Upgrading from the Python agent: the installer removes the old scheduled tasks and virtualenv, and keeps config.json and logs\. The machine stays the same agent on the dashboard, with its history.

winget is optional. It is resolved from the App Installer package under C:\Program Files\WindowsApps as well as from PATH, because the winget alias on PATH belongs to a user profile and does not exist for the LocalSystem account the service runs under.

Building the Windows agent

It is cross-compiled from the development machine — no Windows build host and no CI runner are involved:

cd dashboard && bash scripts/build-agent-bundle.sh

That produces both public/agent/latest.tar.gz (Python agent) and public/agent/windows/aaul-agent.exe (Go agent), stamped with the version from agent/app/VERSION. It needs the Go toolchain; set AAUL_SKIP_WINDOWS_AGENT=1 to skip it while working on the Python agent alone. release.sh refuses to publish without the binary.

Tests for the Go agent:

cd agent/windows
go test ./...                                   # signing, config, logs, winget parsing
GOOS=windows go vet ./... && GOOS=windows go build ./...

Testing the Windows installer

The PowerShell installer is generated, so it is checked rather than trusted. npm run check:install always enforces the static rules (pure ASCII, values interpolated through psAsciiQuote, no uncaptured external call inside a function, well-formed here-strings), and additionally — when pwsh is present — parses the generated script with PowerShell's own parser and runs scripts/test-windows-installer.ps1, which checks that the installer's integrity check agrees byte for byte with the dashboard's.

PowerShell is not required to install or run AAUL; the extra checks are simply skipped when it is missing. To enable them on a development machine:

curl -sL https://github.com/PowerShell/PowerShell/releases/latest/download/powershell-7.5.0-linux-x64.tar.gz \
  | tar -xz -C ~/.local/pwsh    # any recent 7.x release works

One limitation worth knowing: pwsh on Linux is PowerShell 7 and reads files as UTF-8. It cannot reproduce Windows PowerShell 5.1's ANSI decoding, which is why the ASCII rule is enforced statically instead of relying on the parser.

Service management is implemented through:

  • systemd on Linux
  • launchd on macOS
  • the Service Control Manager on Windows

Versioning

Two files hold a version, and they are the only two a human edits:

File Component
dashboard/VERSION dashboard
agent/app/VERSION agent — Python bundle and Go Windows binary

Everything else derives from them:

  • install.sh reads dashboard/VERSION for its install report;
  • client/vite.config.js reads it at build time and injects __APP_VERSION__, which is what the footer shows;
  • scripts/generate-release-md.mjs reads both to produce RELEASE.md;
  • scripts/build-agent-bundle.sh stamps agent/app/VERSION into the Go binary.

npm insists on carrying its own copy in package.json and the lockfiles. Nothing user-facing reads those, and scripts/sync-versions.mjs writes them:

echo 0.14.0 > dashboard/VERSION
cd dashboard && npm run sync:versions

release.sh does this for you. npm run check:versions (part of npm run check:client) fails if anything has drifted.

This is deliberate scar tissue. The version used to be duplicated across eight files; three releases in a row shipped with one of them missed — an install reporting v0.12.4 -> v0.12.4 while the release notes announced 0.13.0, then a footer a full version behind because a stale client/.env overrode the build. The rule is now: one file per component, everything else reads it.

Development

Install dashboard dependencies:

cd dashboard
npm install
npm --prefix client install

Run the server:

cd dashboard
npm run dev:server

Run the frontend:

cd dashboard
npm run dev:client

Or run both:

cd dashboard
npm run dev:all

Build the agent bundle used by /install and agent self-update:

bash dashboard/scripts/build-agent-bundle.sh

Production install / update

The intended production entrypoint is install.sh.

Fresh install or upgrade:

sudo ./install.sh

The installer:

  • copies the project to /opt/AAUL
  • verifies that the native modules (sqlite3, bcrypt) actually load, and rebuilds them if npm blocked their install scripts
  • preserves runtime data during upgrades
  • installs Node.js dependencies
  • builds the frontend
  • builds the agent bundle
  • installs the agentautoupdate-dashboard systemd service
  • installs the local AAUL CLI on the host

Using an installed agent

Once an agent is installed on a machine it is managed locally by a background service and by the dashboard. The quickest way to see the agent state from the host is the local CLI.

Agent CLI commands

On Linux and macOS the CLI is agentautoupdate, installed under /usr/local/bin/agentautoupdate. On Windows it is aaul-agent, the agent binary itself, installed under C:\ProgramData\AgentAutoUpdate\bin and added to the machine PATH. The subcommands below are the same on both, except where noted; run aaul-agent help for the Windows-specific ones (install-service, run --console).

# Show installed version and local config
agentautoupdate version
agentautoupdate status

# Send a heartbeat to the dashboard without running a command
agentautoupdate check-in

# Run operating-system updates immediately
sudo agentautoupdate update

# Update the agent itself from the dashboard bundle
sudo agentautoupdate update-agent

# Read the most recent agent log
agentautoupdate logs
agentautoupdate logs --tail 50

# Point the agent at a different dashboard address or host
sudo agentautoupdate config set-dashboard 192.168.1.10
sudo agentautoupdate config set-dashboard https://dashboard.example.com:3002

# Remove the agent from this machine
sudo agentautoupdate uninstall

The dashboard URL stored in /opt/agentautoupdate/config.json (Linux) or /Library/Application Support/AgentAutoUpdate/config.json (macOS) must be reachable by the agent. If the dashboard moves to a new host or port, use config set-dashboard on the agent.

Service control

The background poller is what keeps the agent talking to the dashboard.

Platform Service / task Useful commands
Linux (systemd) agentautoupdate.service sudo systemctl status agentautoupdate.service, sudo systemctl restart agentautoupdate.service
macOS (launchd) com.agentautoupdate.poller sudo launchctl print system/com.agentautoupdate.poller, sudo launchctl kickstart -k system/com.agentautoupdate.poller
Windows (SCM) service AgentAutoUpdate Get-Service AgentAutoUpdate, Restart-Service AgentAutoUpdate

When an agent stops talking to the dashboard

The dashboard shows an agent as offline when it has not received a poll for more than a few minutes. The machine can be powered on and healthy while the agent itself is unable to reach the dashboard. Here is the usual diagnostic order:

  1. Check the agent service on the machine

    • Linux: sudo systemctl status agentautoupdate.service --no-pager
    • macOS: sudo launchctl print system/com.agentautoupdate.poller
    • Windows: Get-Service AgentAutoUpdate, or aaul-agent status

    If the service is stopped, start or restart it. A freshly installed agent that has never connected will usually show an error here first.

  2. Read the agent log

    agentautoupdate logs --tail 100
    

    Common log errors:

    • Connection Error: ... Is the dashboard running? — the agent cannot reach the dashboard URL.
    • SSL Error: ... Check certificate configuration. — TLS mismatch, expired certificate, or self-signed certificate not allowed.
    • HTTP 401: Invalid token or Invalid request signature — the agent API token is wrong, rotated, or the agent clock is off.
    • Missing response signature — the agent expects signed dashboard responses but the dashboard did not sign them.
  3. Verify network reachability from the agent machine

    # Linux / macOS
    curl -v https://<dashboard-host>:<port>/health
    # or, if the dashboard is HTTP
    curl -v http://<dashboard-host>:<port>/health
    

    If this fails, the problem is network or firewall related, not AAUL related. Check DNS, routing, firewalls, and reverse-proxy rules.

  4. Check the dashboard URL configured on the agent

    agentautoupdate status | grep dashboardUrl
    sudo agentautoupdate config show
    

    If the dashboard was moved behind HTTPS, a new public IP, or a different port, update it:

    sudo agentautoupdate config set-dashboard https://<new-host>:3002
    

    Then restart the poller service.

  5. Check TLS / HTTPS settings

    The agent stores TLS policy in security.json next to config.json:

    {
      "verifyTls": true,
      "allowSelfSigned": false,
      "signRequests": true
    }
    
    • If the dashboard uses a self-signed certificate, set allowSelfSigned: true (development only) or, better, install the CA on the agent machine.
    • If HTTPS was disabled on the dashboard but the agent still points at https://..., the connection will fail.
    • The dashboard's dashboard/config/config.json defines defaultApiProtocol. Make sure the install URL matches the protocol the agent actually uses.
  6. Verify the agent API token

    The token lives in config.json as agentApiToken. If you regenerated or reinstalled the agent entry in the dashboard, the old token becomes invalid. The fastest fix is to reinstall the agent with a fresh install token, or to update agentApiToken in the agent's config.json to match the value shown in the dashboard for that agent.

  7. Check clock skew

    Request signatures have a five-minute validity window. Run date -u on the agent and on the dashboard host. If they differ by more than a couple of minutes, signing will fail and the dashboard will return 401.

  8. Force a manual check-in

    agentautoupdate check-in
    

    If this succeeds, the service restart above likely fixed it. If it fails, the error printed here is the real cause.

What the dashboard "online" status really means

The agent is poll-based: it calls /api/agent/poll at pollIntervalSeconds (default every 1560 seconds). The dashboard marks an agent online when last_seen_at is within the last ~5 minutes. There is no persistent connection, so if an agent stops polling, check the agent side first — the dashboard cannot initiate contact.

Agent file locations

Platform Runtime directory Config file Logs
Linux /opt/agentautoupdate config.json logs/agent-YYYY-MM-DD.log
macOS /Library/Application Support/AgentAutoUpdate config.json logs/agent-YYYY-MM-DD.log
Windows C:\ProgramData\AgentAutoUpdate config.json logs\agent-YYYY-MM-DD.log

Dashboard CLI

After a production install, the host gets an AAUL command for local administration.

Examples:

AAUL -status
AAUL -version
AAUL -reset-admin
AAUL -agent -list
AAUL -agent -update <AGENT_ID>
AAUL -agent -exec <AGENT_ID>
AAUL -agent -remove <AGENT_ID>

Fleet packages and security updates

Packages -> See the whole fleet aggregates every machine's pending updates into one list. For each package you get the number of hosts affected and whether the update comes from a security channel, so the page answers the two questions that actually drive patching: what must I fix and how much of my fleet does it touch.

Security detection is per-platform and best effort:

Platform Source of the security flag
Debian / Ubuntu the suite in apt list --upgradable (<codename>-security), cross-checked against apt-get -s dist-upgrade
Fedora / RHEL dnf updateinfo list security
openSUSE zypper list-patches --category security
Arch, macOS, Windows not available — these publish no per-package security metadata, so updates are reported as regular ones rather than guessed

A package is flagged as security-relevant as soon as one host reports it from a security channel: the same version can sit in -security on one distro release and in plain -updates on another, and under-reporting a security fix is the costlier mistake.

Use Security only to reduce the list, or Patch security updates to queue just those updates on every affected machine. Bulk updates still require the per-agent package-management opt-in; agents without it are skipped.

Host metrics

Every poll carries a small set of vital signs (CPU, load average, memory, swap, root filesystem and the fullest mounted filesystem, process and session counts). This is deliberately separate from the full inventory (collect_system_info()), which is expensive and still runs only on demand.

  • Fleet cards and the fleet-health panel show current usage at a glance.
  • The agent page adds 24-hour sparklines.
  • A host is listed as "under pressure" above 90% CPU, 90% memory or 85% disk. Disk pressure uses the fullest volume, not /: a machine can look healthy on / while /var is the one about to fill up.

History is sampled once per host every 5 minutes (not once per poll, which would add thousands of rows a day without adding visible detail) and pruned according to Admin -> Metric history retention, 30 days by default.

Agents older than 0.9.0 simply report no metrics; the dashboard shows "no metrics reported yet" rather than a misleading 0%.

Log collection and retention

Agents write one log file per day. Nothing used to delete them, so a long-lived machine accumulated hundreds of files.

Retention is configured centrally in Logs -> Log retention and pushed to every agent on its next check-in. Each agent then enforces it locally, at most once an hour:

  1. delete logs older than the age limit;
  2. delete the oldest remaining logs until the total fits the size limit.

Defaults are 30 days or 200 MB, whichever comes first. Two safety rules are hardcoded in the agent and cannot be overridden from the dashboard: the current day's log is never deleted, and only files the agent itself produced (agent-YYYY-MM-DD.log) are ever eligible for removal.

Clean up now applies the policy to one host immediately, which is what you want when a disk is filling up. The log viewer supports search, level highlighting (errors, warnings, success), line wrapping and download.

Version checking

RELEASE.md at the repository root publishes the versions that are currently released and the release notes in both French and English. It is generated, never hand-edited — release.sh rebuilds it from dashboard/client/src/lib/changelog.js and the VERSION files, so the published reference cannot lag behind a release.

The dashboard reads its release notes from that same file rather than from a copy baked into the bundle, and shows the section matching the interface language. Three sources are tried, in order:

  1. the cached copy of the last successful fetch — this is what lets you read what a newer version contains before installing it;
  2. the RELEASE.md shipped with the installation, which git pull always puts on disk, so an isolated install still has its notes;
  3. nothing, in which case the window says so instead of showing a blank list.

Each dashboard reads that file periodically and compares it with what it runs. When a newer version exists, a small amber badge appears next to the version in the footer, and the release-notes window shows what to run:

cd ~/AAUL && git pull && ./install.sh

Nothing is ever downloaded or installed automatically — the check only reports.

  • Interval and on/off switch live in Admin, default every 30 minutes.
  • Turn it off on an isolated network. Otherwise the dashboard attempts one outbound request per interval that can never succeed.
  • Version source accepts a custom URL if you mirror RELEASE.md internally.
  • The release-notes window has a Check now button that works even when the periodic check is disabled.

To regenerate the file by hand:

cd dashboard
npm run gen:release      # rewrite RELEASE.md
npm run check:release    # fail if it is out of date (useful in CI)

Beta status & known limitations

AAUL is currently released as a public beta (pre-1.0). It is usable and has been through a security review, but a few things are worth knowing before you deploy it on a fleet you care about:

  • Versioning. For as long as the project is in beta, both the dashboard and the agent stay on 0.x.x — pre-1.0 in the semver sense, meaning the API and behavior may still change between releases. 1.0.0 is reserved for the first stable release. Note that the agent auto-update compares version strings, not version order: any change to the agent version (in either direction) triggers an update on the next poll.

  • Metrics and log retention need agent 0.9.0+. Older agents keep working normally, but report no vital signs and do not prune their own logs. Push UPDATE_AGENT to the fleet to enable both.

  • Security flags depend on the package manager. Arch, macOS and Windows expose no per-package security metadata, so their updates are never marked as security updates. Absence of the flag on those platforms means "unknown", not "safe".

  • Run it over HTTPS. Agent tokens and admin sessions travel over the wire. Enable HTTPS (or put the dashboard behind a TLS-terminating reverse proxy) before exposing it beyond localhost. Plain-HTTP install is disabled by default.

  • The dashboard runs privileged commands on agents. Treat admin accounts as highly sensitive. The default admin password is generated at first launch and written to .initial-admin-password (mode 0600) next to the database — change it immediately and delete that file.

  • Agent services run as root. This is inherent to OS package management. Only install the agent on machines you administer.

  • The optional agent local web UI binds to all interfaces and is reachable on the LAN when enabled. It is off by default, requires PAM/system-user authentication, and is rate-limited — enable it only on trusted networks, and prefer HTTPS for it too.

  • Plugins run in the dashboard process. Install only plugins you trust.

  • Native modules must build. The dashboard depends on sqlite3 and bcrypt, which ship compiled binaries. Recent npm versions block dependency install scripts by default (install scripts blocked because they are not covered by allowScripts), in which case npm ci succeeds but the binary is never fetched and the server dies at boot with Could not locate the bindings file. Note that npm rebuild is blocked by the same policy and still reports success. install.sh detects this, runs each package's own install script directly (bypassing npm), and aborts with instructions rather than restarting a service that cannot start. If you install dependencies by hand, verify with:

    cd /opt/AAUL/dashboard
    node -e "require('sqlite3'); require('bcrypt')"   # must print nothing
    
  • A few remaining npm audit advisories are build-time-only transitive dependencies of native modules (tar/cacache via node-gyp/node-pre-gyp) and are not reachable at runtime. See docs/SECURITY_AUDIT.md.

Found a security issue? See SECURITY.md — please report privately.

Documentation

Current entry points:

The older docs/wiki/ pages were removed from this public tree because they no longer matched the current codebase.

Notes for contributors

This repository is meant to stay readable by contributors who are new to the project.

The code should prefer:

  • explicit names over short names
  • small helpers over repeated inline logic
  • comments that explain intent, not syntax
  • platform-specific code that is isolated instead of hidden in conditionals everywhere

See CONTRIBUTING.md for the maintainer-facing conventions used in this repository.

License

MIT — Copyright (c) 2026 André Porlier — Projet Auxinux