Alane Jaunet

Créer un CLI en Rust pour piloter son portfolio

Retour d'expérience sur la création de portfolio-cli : un outil en Rust pour gérer l'intégralité de mon portfolio depuis le terminal, avec upload d'images, intégration IA et authentification par token.

Par Alane Jaunet17 mars 2026

Pourquoi un CLI pour gérer un portfolio ?

Mon portfolio tourne sur une stack Next.js avec une API REST et un panel admin classique. Ça fonctionne, mais à chaque fois que je voulais ajouter un projet ou modifier une compétence, il fallait ouvrir le navigateur, naviguer dans l'interface, remplir des formulaires...

C'est en échangeant avec Oalacea que l'idée m'est venue : pourquoi ne pas tout faire depuis le terminal ? Il m'a montré l'approche CLI pour gérer du contenu, et j'ai tout de suite vu le potentiel.

Pourquoi Rust ?

J'ai rapidement convergé vers Rust — c'était la solution la plus directe pour ce que je voulais :

  • Un seul binaire — pas de runtime Node, pas de dépendances système. cargo install et c'est prêt.
  • La performance — le CLI démarre instantanément, les commandes s'exécutent sans latence perceptible.
  • L'écosystèmeclap pour le parsing de commandes, reqwest pour les requêtes HTTP, serde pour la sérialisation. Chaque crate fait bien son travail.

C'était aussi l'occasion d'apprendre Rust sur un projet concret avec de vrais appels API, plutôt que sur des exercices théoriques.

Architecture

La structure est volontairement simple :

src/
├── main.rs           # Routing des commandes (clap)
├── config.rs         # Config TOML persistante
├── api_client.rs     # Client HTTP générique avec Bearer token
├── ai_client.rs      # Client OpenAI-compatible
├── output.rs         # Formatage tableaux + couleurs
├── models/mod.rs     # Structs serde pour chaque entité
└── commands/         # Un module par ressource

Chaque entité du portfolio (projets, compétences, expériences, certifications...) a son module dans commands/. Le pattern est toujours le même : list, get, create, update, delete.

Le client API générique

Le cœur du CLI, c'est un client HTTP qui gère l'authentification et la sérialisation de manière générique :

pub fn get<T: DeserializeOwned>(&self, path: &str) -> Result<T> { let mut req = self.client.get(self.url(path)); if !self.token.is_empty() { req = req.bearer_auth(&self.token); } let resp = req.send().context("Erreur réseau")?; // ... Ok(resp.json()?) }

Un seul get() sert pour tous les types : Vec<Project>, PersonalInfo, SiteConfig... Rust infère le type de retour à partir du contexte d'appel. C'est propre et il n'y a aucune duplication.

La config persistante

La configuration (URL de l'API, token d'auth) est stockée dans ~/.config/portfolio-cli/config.toml. Le crate dirs gère les chemins spécifiques à chaque OS, et toml fait la sérialisation.

portfolio config set api https://pro.newalfox.fr portfolio login # Token stocké localement, réutilisé à chaque commande

Ce que ça donne au quotidien

Ajouter un projet :

portfolio projects create \ --title "Palnia" \ --year "2026" \ --description "SaaS de productivité" \ --state IN_PROGRESS

Lister mes compétences frontend :

portfolio skills list --category FRONTEND

Modifier une stat du site :

portfolio site-config update-stat --key projects --value "100+"

Chaque commande prend quelques secondes. Pas de navigateur, pas de formulaire, pas de clic.

Upload d'images

Un ajout récent : la possibilité d'uploader des images directement depuis le CLI vers Vercel Blob Storage.

portfolio projects update <id> \ --image-path ./screenshot.png \ --image-alt "Capture d'écran du projet"

Le CLI envoie le fichier en multipart à l'API, qui le stocke sur Vercel Blob et met à jour la référence en base.

Intégration IA

Le CLI intègre un module IA via claude-max-api-proxy, un proxy local qui expose une API OpenAI-compatible connectée à Claude.

# Générer une description de projet portfolio ai describe --title "Mon Projet" --techs "React, TypeScript" # Résumé exécutif du portfolio complet portfolio ai summary

Le proxy tourne sur localhost:3456 et utilise l'abonnement Claude existant — pas de clé API supplémentaire nécessaire.

Intégration Claude Code

La commande portfolio init génère un fichier d'instructions pour Claude Code. Résultat : Claude Code peut utiliser le CLI de manière autonome pour gérer le portfolio. On lui dit "ajoute ce projet", et il exécute les bonnes commandes.

C'est un cas d'usage concret de l'agent coding : au lieu de modifier du JSON ou de naviguer dans une UI, l'IA pilote directement le CLI.

Les crates qui font le travail

| Crate | Rôle | |-------|------| | clap | Parsing des commandes avec le derive macro | | reqwest | Client HTTP (mode blocking, suffisant pour un CLI) | | serde + serde_json | Sérialisation/désérialisation JSON | | toml | Config persistante | | tabled | Tableaux formatés dans le terminal | | colored | Couleurs pour les messages de succès/erreur | | anyhow | Gestion d'erreurs ergonomique | | dialoguer | Prompts interactifs (saisie du token) |

Ce que j'ai appris

  • Rust est idéal pour les CLI — le temps de compilation est le seul inconvénient, mais le résultat est un binaire rapide et sans dépendance.
  • Les generics de Rust brillent dans un client API — un seul get<T>() remplace des dizaines de fonctions spécifiques.
  • Un CLI bien fait change la façon de travailler — ce qui prenait 2 minutes dans un formulaire prend 5 secondes dans le terminal.
  • L'intégration avec un agent IA ouvre des possibilités intéressantes : le CLI devient une interface naturelle pour l'automatisation.