CLI
@agreely/cli est la barrière de consentement sous forme d'outil en ligne de
commande. Un seul binaire, deux modes :
- Les humains obtiennent une sortie en couleur et un assistant interactif (à un TTY).
- Les agents obtiennent du JSON pur sur stdout et des codes de sortie stables
(un tube ou
--json).
C'est une fine coquille par-dessus @agreely/sdk : elle ne
réimplémente jamais la logique HTTP, de décision ou de normalisation. Elle résout
l'authentification, choisit un mode, appelle le SDK, et mappe le résultat vers un
code de sortie.
Paquet @agreely/cli v0.1.0, binaire agreely, ESM, Node >=18.
Installer
npm install -g @agreely/cli
agreely --help
agreely --version # -> 0.1.0
Agent-native : une variable d'environnement + --json
export AGREELY_API_KEY=agr_live_xxx # le seul réglage dont un agent a besoin
agreely check cust-42 "Email Address" "Marketing Outreach" --json
# -> {"decision":"allow","status":"active","consentRef":"0x…"} exit 0
Définissez la clé une fois via AGREELY_API_KEY (aucune invite, aucun
trousseau requis), passez --json (ou redirigez simplement par un tube : un stdout
qui n'est pas un TTY déclenche automatiquement le mode agent), et branchez sur le
code de sortie. category / purpose sont envoyés bruts; le serveur les
normalise.
Drapeaux globaux
Acceptés avant ou après la sous-commande :
--json: force le mode agent (JSON pur sur stdout).--api-key <key>: déconseillé, visible dansps.--base-url <url>: remplace l'URL de base de l'API.
Variables d'environnement
AGREELY_API_KEY: le chemin d'authentification agent.AGREELY_BASE_URL: l'URL de base de l'API.AGREELY_RPC_URL: le repli RPC pourverify --onchain.XDG_CONFIG_HOME: relocalise le dossier de configuration.
Le tableau des codes de sortie (le contrat agent)
Le code de sortie est le contrat. Il sépare proprement une panne d'un refus et une vérification échouée d'une panne, ce qui est tout l'intérêt d'une barrière de consentement agent-native.
| code | signification |
|---|---|
0 |
succès, ou une vérification ALLOW |
10 |
une vérification DENY propre, un négatif attendu, pas une erreur |
2 |
erreur d'usage : arguments mauvais/manquants, entrée invalide, une erreur de validation serveur, une erreur de config, et une ressource introuvable |
3 |
authentification : la clé est absente, invalide, révoquée ou dépourvue de la portée requise |
4 |
indisponible : une panne d'Agreely (distincte d'un refus), et une expiration de sondage côté client |
5 |
limite de débit : la fenêtre par entreprise a été dépassée |
6 |
vérification échouée : un reçu a été vérifié et n'a pas été validé (une falsification). Un verdict, pas une erreur |
1 |
un échec inattendu / non catégorisé |
check résout ALLOW vers 0 et DENY vers 10. La CLI fonctionne en refus par
défaut : lors d'une panne, le SDK lève une exception et la CLI sort avec 4, de
sorte qu'un appelant peut toujours distinguer « panne » de « refusé ». Le JSON d'un
DENY va tout de même sur stdout; une véritable erreur garde stdout propre et écrit
une enveloppe {"error":{"code","message"}} sur stderr.
Modes (détectés automatiquement)
| condition | mode | comportement |
|---|---|---|
stdout est un TTY et pas de --json |
humain | couleurs, l'assistant, confirmations |
stdout n'est pas un TTY, ou --json |
agent | jamais d'invite, JSON pur sur stdout, journaux/erreurs sur stderr |
En mode agent, stdout ne transporte que du JSON pur et rien d'autre; chaque
journal, indice ou erreur va sur stderr, sous l'enveloppe
{"error":{"code","message"}} en cas d'erreur. En mode humain, la sortie est
colorée avec assistants et confirmations, et une erreur s'affiche en rouge sous la
forme x message. picocolors désactive automatiquement la couleur hors TTY. Un
argument requis manquant en mode agent est une erreur claire assortie d'une sortie
d'usage (2); il ne reste jamais bloqué à attendre une invite.
Commandes
agreely check <customerId> <category> <purpose>
agreely check --batch <file.json>
agreely catalog
agreely whoami
agreely requests [--status <s>] [--cursor <id>]
agreely request create [--customer <id>] [--to <email>] [--item <item>]... [--valid-until <YYYY-MM-DD>] [--idempotency-key <key>]
agreely request show <requestId>
agreely request cancel <requestId>
agreely request wait <requestId> [--interval <ms>] [--timeout <ms>]
agreely manual-consent create [--customer <id>] [--document-version <id>] [--effective-date <YYYY-MM-DD>] [--valid-until <YYYY-MM-DD>] [--item <item>]... [--pdf <path>] [--upload]
agreely manual-consent claim-link [--customer <id>] [--reference <ref>]
agreely manual-consent revoke <consentRef> [--reason <text>]
agreely manual-consent erase <consentRef> [--reason <text>]
agreely relationship end <customerRef> --reason <text>
agreely verify <receipt.json> [--ipfs] [--onchain] [--rpc-url <url>] [--did-doc <file>]...
agreely login
agreely config set [--api-key <k>] [--base-url <url>]
check
Décision synchrone. category / purpose sont envoyés bruts (le serveur
normalise). Sortie 0 = ALLOW, 10 = DENY, 4 = panne.
agreely check cust-42 "Email Address" "Marketing Outreach" --json
# {"decision":"allow","status":"active","consentRef":"0x…"} exit 0
# {"decision":"deny","status":"revoked","consentRef":"0x…"} exit 10
En mode humain : OK ALLOW … ou DENY …. En mode agent, le JSON est
{decision, status, consentRef?}.
Mode lot : --batch <file.json> lit un tableau JSON d'objets
{customerRef, category, purpose}, appelle checkBatch() une fois, et imprime
une table de décisions (humain) ou un tableau JSON (agent, un objet
{customerRef, category, purpose, decision, status, consentRef?} par cellule). La
sortie est 0 quand toutes les cellules autorisent, 10 dès qu'une refuse,
4 en cas de panne. C'est l'outil pour protéger l'affichage d'une liste (N clients
x M champs = N x M vérifications) en un seul aller-retour.
agreely check --batch ./cells.json --json
# [{"customerRef":"cust-42","category":"Email Address","purpose":"Marketing Outreach","decision":"allow","status":"active","consentRef":"0x…"}]
catalog
Liste le catalogue actif de l'entreprise. JSON {catalog: entries}.
whoami
Vérifie la clé côté serveur en appelant GET /v1/whoami : la commande rapporte
les portées réellement vérifiées par le serveur, et non une déduction locale.
Une clé invalide sort avec 3. La commande n'imprime jamais le secret (masqué :
les 8 premiers + les 4 derniers caractères). JSON :
{authenticated, apiKeyMasked, apiKeySource, baseUrl, scopes}.
requests
Liste les demandes, pagination par curseur. --status accepte
pending|approved|refused|expired|revoked_before_action (une valeur invalide est
une erreur d'usage). Le JSON émet la page brute {items, nextCursor}.
request create
Double mode. Non interactif lorsque le mode agent est actif ou qu'un drapeau
scriptable est présent : la CLI valide alors (client requis, courriel valide, date
YYYY-MM-DD, au moins un item). À un TTY humain sans drapeau, un assistant guide
la sélection dans le catalogue, recueille le client, le destinataire et la date
d'expiration, valide chacun, et confirme avant d'émettre.
agreely request create \
--customer cust-42 --to [email protected] \
--item "Email Address:Marketing Outreach" --item 4b082452-… \
--valid-until 2030-01-01 --idempotency-key issue-2026-001 --json
# -> l'IssuedRequest brut
Un --item est soit l'id d'une entrée de catalogue, soit category:purpose.
Réutilisez --idempotency-key pour rendre une nouvelle tentative sûre : un rejeu
renvoie la demande d'origine, sans double émission ni double courriel.
request show
requestId doit correspondre à ^0x[0-9a-f]{64}$. JSON : l'enregistrement brut.
request cancel
Annule une demande en attente par son requestId (portée issue). L'appel est
idempotent : une demande déjà terminale n'est pas une erreur, la sortie reste
0 avec cancelled: false. JSON :
{requestId, status, cancelled}.
agreely request cancel 0x… --json
# {"requestId":"0x…","status":"revoked_before_action","cancelled":true} exit 0
request wait
Sonde jusqu'à ce que la demande soit réglée
(approved|refused|expired|revoked_before_action). Une expiration sort avec 4.
--interval vaut 2000 ms par défaut, --timeout vaut 120000 ms. JSON :
l'enregistrement réglé brut.
agreely request wait 0x… --timeout 300000 --json
manual-consent
Portée attest. Enregistre un consentement obtenu hors ligne (papier ou PDF signé).
create : le PDF est haché localement (sha256); par défaut seul
pdfSha256 ("0x" + hash) est envoyé. Les octets bruts (base64) ne quittent la
machine qu'avec --upload. Tous les éléments sont requis :
--customer, --document-version, --effective-date, --valid-until, au moins
un --item, et --pdf. JSON : le ManualConsentResult brut.
agreely manual-consent create \
--customer cust-42 --document-version dv-2026-05 \
--effective-date 2026-05-01 --valid-until 2031-05-01 \
--item "Email Address:Marketing Outreach" \
--pdf ./signed.pdf --json
# le hash seul part; ajoutez --upload pour envoyer aussi les octets
claim-link : --customer requis. JSON : le ClaimLink brut
{claimUrl, token, expiresAt}.
revoke : consentRef correspond à ^0x[0-9a-f]+$ (insensible à la casse).
JSON : la révocation brute {consentRef, revoked, alreadyRevoked}.
erase : efface (crypto-broyage) un consentement manuel. JSON : l'effacement
brut {consentRef, erased, alreadyErased}.
relationship end
Portée relationship. Atteste qu'une relation client est terminée (Loi 25 art. 23,
« les fins sont accomplies »). <customerRef> est votre propre référence client
(la même que pour check), rattachée à l'entreprise de la clé. --reason est
requis : un motif absent ou vide sort en erreur, jamais une fin silencieuse.
L'appel est idempotent (re-finir une relation déjà terminée est un succès;
endedAt et endedBy d'origine sont préservés). C'est une surcouche de cycle de
vie : elle ne révoque ni n'efface aucun consentement. JSON :
{customerRef, status, endedAt, endedBy}.
agreely relationship end cust-42 --reason "Compte fermé, fins accomplies" --json
# {"customerRef":"cust-42","status":"ended","endedAt":"2026-06-26T15:04:05Z","endedBy":"company"} exit 0
verify
Vérification de reçu hors ligne d'abord. Une fine enveloppe autour de la
méthode statique Agreely.verifyReceipt du SDK, qui expose les mêmes statuts
honnêtes : elle ne redérive pas les verdicts.
En mode humain, verify imprime une matrice d'honnêteté à cinq lignes,
companySignature, citizenAssertion, disclosureCopy, documentAnchor et
cellLabelBinding, chacune pass / fail / unavailable / unsupported /
skipped, plus un verdict global (VERIFIED / PARTIAL / UNAVAILABLE /
FAILED) et des notes. La ligne cellLabelBinding est le champ à lire avant de
faire confiance à une étiquette affichée. En mode agent, elle émet le
ReceiptVerification brut.
agreely verify ./receipt.json --json
Drapeaux :
--ipfs: active la vérificationdisclosureCopy(récupère la copie IPFS et la compare àdisclosureHash); autrementskipped.--onchain: active la vérificationdocumentAnchoren chaîne et exige une URL RPC via--rpc-urlouAGREELY_RPC_URL(sinon erreur d'usage).--did-doc <file>(répétable) : installe un résolveur de document DID local, rendantverifyentièrement hors réseau. Un DID inconnu se résout alors versunavailable(sortie4) plutôt que d'atteindre le réseau. Sans--did-doc, les vérifications de signature et d'assertion effectuent par défaut une seule résolution DID par HTTPS.
Sortie 4 (indisponible) contre sortie 6 (échec)
C'est le cœur honnête du vérificateur. Un DID irrésoluble (le DID de l'émetteur ou du citoyen ne peut être résolu) est sortie 4 (indisponible), pas sortie 6. La sortie 6 est réservée à un échec cryptographique actif : une falsification ou une mauvaise clé. Un reçu valide, durant une panne de résolution DID, ne doit jamais ressembler à une contrefaçon.
login
Interactif uniquement. En mode agent, login échoue et vous renvoie vers
config set ou AGREELY_API_KEY. Il demande la clé et une URL de base optionnelle,
vérifie la clé contre l'API en direct avant de la persister (il ne stocke jamais
une clé qui ne fonctionne pas), puis la range dans le trousseau du système d'exploitation, avec repli vers le fichier de configuration 0600.
config set
Non interactif : il ne demande jamais rien et ne vérifie rien. Il exige au moins un
drapeau parmi --api-key et --base-url, et stocke les identifiants.
agreely config set --api-key agr_live_xxx --base-url https://api.agreely.ca
Préséance d'authentification
La CLI ne demande jamais de clé. Ordre de résolution :
--api-key flag (déconseillé, visible dans `ps`)
> AGREELY_API_KEY env (le chemin agent : une variable, aucune invite)
> trousseau du SE (keytar, service « agreely »)
> ${XDG_CONFIG_HOME|~/.config}/agreely/config.json (mode 0600)
Une clé absente lève une erreur d'usage (sortie 2) : « No API key. Set
AGREELY_API_KEY, run 'agreely login', or pass --api-key. » L'URL de base par défaut
affichée est https://api.agreely.ca.
URL de base : --base-url > AGREELY_BASE_URL > configuration stockée > valeur
par défaut du SDK. Si le module natif optionnel keytar est indisponible,
login / config set se rabattent sur le fichier de configuration 0600.
La dégradation est omise (à dessein)
La CLI fonctionne en refus par défaut et mappe une panne vers le code de sortie
4. La politique de dégradation (ouverture en cas de panne / double barrière /
bris de glace) est intentionnellement omise de la CLI v1 : c'est une
préoccupation d'intégration application/SDK de longue durée (avec un collecteur
d'audit et une fenêtre bornée), pas quelque chose qu'une invocation ponctuelle de
CLI peut persister ou auditer sensément. Configurez-la là où le
SDK est intégré.