Communitygithub.com

d1-cli — Tiendas D1 von der Kommandozeile

Durchsuche das Sortiment von Tiendas D1 (Kolumbien, d1.com.co) von der Kommandozeile, finde die nächste Filiale, kalkuliere einen Warenkorb basierend auf dem tatsächlichen Lagerbestand und erstelle eine Bestellung zur Zahlung.

Was ist d1-cli — Tiendas D1 von der Kommandozeile?

Dieses Skill ermöglicht es einem AI-Agenten (oder Entwickler), vollständig mit der kolumbianischen Supermarktkette Tiendas D1 über die Kommandozeile zu interagieren. Es nutzt die öffentliche VTEX-IO-API des Shops (Account `d1tiendas`), ohne dass Administrator-Anmeldedaten erforderlich sind – Katalogabfragen und Warenkorboperationen funktionieren vollständig anonym. Das Skill adressiert zwei kritische Fallstricke der D1-Automatisierung: Die Verfügbarkeit ist regionalisiert (eine Abfrage ohne Region liefert einen nationalen Katalog, den niemand kaufen kann) und Preise werden in zwei verschiedenen Einheiten ausgegeben (Suche in ganzen Pesos, Bestellabwicklung in Hundertsteln – ein stiller Faktor 100). Es kann Warenkörbe erstellen und bepreisen, explizit aber nicht bezahlen; stattdessen gibt es eine Checkout-URL an einen Menschen aus. Es ist für die Suche nach Produkten und Preisen, die Prüfung der Lieferbarkeit, die Zusammenstellung und Kostenberechnung von Einkaufslisten, den Vergleich von Artikeln und die Einsicht in Bestellhistorien konzipiert. Nicht geeignet ist es für andere kolumbianische Einzelhändler (Éxito, Jumbo, Ara, Alkosto) und nicht für Zahlungsvorgänge.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/broomva/skills/tree/HEAD/skills/commerce/d1-cli

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Was macht d1-cli — Tiendas D1 von der Kommandozeile?

D1 ist die größte Hard-Discount-Supermarktkette Kolumbiens. Der Onlineshop läuft auf VTEX IO (Account d1tiendas), das bedeutet, die eigene öffentliche API der Website ist die Integrationsoberfläche – kein Scraping, keine Admin-Zugangsdaten.

Aufruf

cd skills/commerce/d1-cli

# 1. Bestimme ZUERST deinen Lieferort – alles andere hängt davon ab
bun run src/cli.ts region --lat 4.6486 --lng=-74.0628

# 2. Dann suchen: Preise und Verfügbarkeit beziehen sich jetzt auf deinen Markt, nicht auf das ganze Land
bun run src/cli.ts search leche entera --count 5
bun run src/cli.ts search --facets category-1/lacteos-y-huevos --sort price:asc

# 3. Warenkorb bepreisen, ohne den echten Warenkorb zu verändern
bun run src/cli.ts quote 262:2 892:1

# 3b. Oder ein Budget bestimmt den Inhalt – Suchbegriffe, nicht SKUs
bun run src/cli.ts basket --budget 30000 arroz leche aceite huevos

# 4. Oder einen echten Warenkorb zusammenstellen, dann an einen Menschen zur Zahlung übergeben
bun run src/cli.ts cart add 262 --qty 2
bun run src/cli.ts cart deliver-to
bun run src/cli.ts cart checkout      # gibt eine URL aus; bezahlt nicht

Hänge --json an jeden Befehl an, um eine für Agenten lesbare Ausgabe zu erhalten. Exit-Codes sind ein Vertrag, und diese Liste ist die einzige Kopie davon:

CodeBedeutungWiederholen?
0Erfolg—
1D1 abgelehnt oder nicht erreichbar – nicht lieferbarer Ort, nicht verfügbarer oder unbekannter Artikel, Ausfallja, kann helfen
2Befehl falsch aufgerufenhilft nie
3Erfolg, aber die Antwort ist „keine“ (substitute, basket)hilft nie

Ein Agent, der diese nicht unterscheiden kann, wiederholt entweder einen Tippfehler endlos oder gibt bei einer vorübergehenden Störung auf. 3 existiert, weil eine leere Kategorie keins von beidem ist.

Beachte, dass cart add die Zeile auf --qty setzt; es wird nicht addiert. Das ist D1s eigene Semantik, live verifiziert.

Die zwei Dinge, die naive D1-Automatisierung falsch macht

Verfügbarkeit ist regionalisiert. Wird der Katalog ohne Region abgefragt, antwortet D1 aus dem nationalen Katalog und meldet bequeme 10.000 Einheiten beim fiktiven Verkäufer 1. Wird dieselbe SKU durch eine Checkout-Simulation für eine echte Adresse geschickt, kommt sie als withoutStock zurück, weil der physische Markt, der sie versenden würde, sie nicht führt. Immer zuerst d1 region; die CLI warnt im Klartext, wann immer sie nationale Preise anzeigt.

Die Region zu bestimmen ist auch der am wenigsten erratbare Teil der API: die Koordinaten werden als geoCoordinates={lon};{lat} – Semikolon-getrennt, Längengrad zuerst übergeben. Ein Komma, wie es VTEXs eigene JSON-Objekte für dasselbe Paar verwenden, wird mit CHK0119 („Adressen müssen eine Postleitzahl oder Geokoordinaten haben“) abgelehnt – eine Meldung, die klingt, als fehle der Parameter, nicht als sei er fehlerhaft. test/region.test.ts stellt dies sicher, damit eine Bereinigung es nicht rückgängig machen kann.

Preise kommen in zwei Einheiten. Für SKU 262 (Leche Entera Latti 900 ml, COP 3.500 im Regal):

APIFeldWertEinheit
intelligent-searchPrice3500ganze Pesos
catalog_systemPrice3500.0ganze Pesos
checkout orderFormsellingPrice350000Hundertstel

Keine der Einheiten ist beschriftet. catalog.ts normalisiert an der Grenze alles auf Hundertstel, sodass der Rest des Codes genau eine Einheit hat, und ein Test stellt sicher, dass ein aus der Suche stammender Preis identisch zu einem aus dem Checkout stammenden Preis dargestellt wird.

Was es nicht tun wird

d1 stellt Warenkörbe zusammen und bepreist sie. Es bezahlt nicht. d1 cart checkout gibt die URL aus, unter der ein Mensch den Gesamtbetrag prüft und die Zahlung abschließt.

Diese Grenze wird an zwei Stellen anhand einer Liste (src/endpoints.ts) geprüft: Zur Laufzeit lehnt D1Client.request jede Anfrage ab, deren aufgelöste URL nicht D1s eigener Ursprung plus einer von 18 genehmigten Pfaden ist – noch bevor die Anfrage den Prozess verlässt; statisch schlägt test/safety.test.ts fehl, wenn irgendein /api/-Literal irgendwo in src/ nicht genehmigt ist. Das Hinzufügen eines Endpunkts – für Zahlungen oder andere Zwecke – schlägt fehl, bis er gelistet ist, sodass die Entscheidung getroffen wird, nicht versehentlich übergangen.

Der Laufzeitteil ist tragend und wurde hinzugefügt, nachdem eine Überprüfung gezeigt hatte, dass eine statische Prüfung nicht ausreicht: --facets '../../../..' löste sich aus dem Such-Endpunkt heraus und landete in der Auftragsabwicklung, während jedes Quellliteral genehmigt blieb.

Präzise formuliert, weil frühere Versionen dieser Datei übertrieben haben: Nichts hier hindert einen Autor mit Schreibzugriff daran, die Whitelist zu bearbeiten. Kein test im Repository kann das überprüfen.

Die einzigen Anmeldedaten, die gespeichert werden, sind ein Storefront-Sitzungstoken – dasselbe, das ein eingeloggter Browser hält, beschränkt auf die eigenen Bestellungen und den eigenen Warenkorb des Besitzers – geschrieben in ~/.config/d1-cli/session.json mit Modus 0600. Es wird nirgendwo ein VTEX-Admin-AppKey/AppToken gelesen. Der Login erfolgt über einen einmalig per E-Mail zugesandten Code; Passwort-Authentifizierung ist bewusst nicht implementiert.

Das Checkout-Gate – immer hiermit enden

Beende jeden Warenkorb mit d1 cart checkout und reagiere auf den Exit-Code. Nicht als Formsache: Es ist der einzige Befehl, der den gesamten Warenkorb erneut gegen D1 prüft, wie er jetzt ist, und Warenkörbe werden auf eine Weise alt, die kein anderer Befehl offenlegt.

0  jede Zeile ist lieferbar – die URL kann gefahrlos übergeben werden
1  mindestens eine Zeile KANN NICHT geliefert werden; die URL wird ausgegeben, aber der Warenkorb ist defekt
2  der Befehl wurde falsch aufgerufen

Dies existiert, weil jeder dieser Fälle bei einem echten Warenkorb aufgetreten ist:

  • Ein Artikel war über Nacht ausverkauft. PAN ARTESANAL INTEGRAL hatte Stunden nach dem Hinzufügen no tiene inventario. Der Warenkorb wurde trotzdem angezeigt, hatte noch eine Gesamtsumme – eine Summe, die stillschweigend um 6.490 zu niedrig war, weil die tote Zeile aus ihr herausgefallen war.
  • Eine Adressänderung machte jede Zeile unzustellbar. Neun Artikel kamen als cannotBeDelivered zurück, während jeder noch eine gültige SLA hatte und der Warenkorb noch einen zahlbaren Gesamtbetrag anzeigte.
  • Die Versandkosten wurden um das 12-fache zu niedrig ausgewiesen durch eine zeilenweise Zuordnung, die wie ein Gesamtbetrag aussah.

In allen drei Fällen sah der Warenkorb gut aus. Ein früher in der Sitzung erstelltes Angebot ist kein Beleg für den aktuellen Warenkorb. Übergebe daher niemals eine Checkout-URL, die du vor der letzten Änderung erhalten hast – führe das Gate erneut aus.

Wenn der Exit-Code 1 zurückgibt, liefert --json undeliverable[] mit den betreffenden Zeilen und readyToCheckout: false. Entferne oder ersetze diese Zeilen und führe es erneut aus.

Ersetzen einer von D1 nicht lieferbaren Zeile

d1 substitute 192 --limit 5        # bewertet vorrätige Produkte aus derselben Kategorie

Exit 0 bedeutet, dass ein Vorschlag existiert; 3 bedeutet, dass es keinen gibt – einer von zwei Befehlen, die 3 verwenden, zusammen mit d1 basket.

Drei, nicht eins, und der Unterschied ist der Punkt: 1 bedeutet „D1 abgelehnt oder nicht erreichbar“ überall sonst in dieser CLI und lädt zu einem erneuten Versuch ein. Eine leere Kategorie wird durch einen erneuten Versuch niemals nicht-leer, daher würde ein Agent mit einer „Wiederhole bei 1“-Richtlinie für immer darin schleifen. Exit 0 mit einer leeren Liste ist die andere falsche Antwort – sie wird als Erfolg gelesen und darauf reagiert.

Jeder Kandidat nennt was sich ändert: Marke, Packungsgröße, $/kg oder $/L, Packungspreis und alle gewonnenen oder verlorenen Ley-2120-Warnhinweise. Das ist die Ausgabe, nicht die Bewertung. Ein -12% pro Liter bei gleichen 900 ml und gleichem Etikett ist eine andere Aussage als einer, der mit Exceso en Azúcares daherkommt, und nur die Deltas unterscheiden sie.

Schlage es vor; nimm es nicht vor. substitute schreibt nie – es gibt das d1 cart add für einen Menschen zur Freigabe aus. Dies ist keine Vorsicht um ihrer selbst willen: Der Kunde hat zweimal eine gestrichene Zeile einem falschen Ersatz vorgezogen, dies explizit gesagt und hatte beide Male recht. Präsentiere die Kandidaten und die Abwägungen; lass die Person entscheiden und sei bereit, die Zeile zu streichen.

Drei Dinge, die es dir sagt und die lesenswert sind:

  • „Dies ist in deinem Markt noch auf Lager.“ Die Verfügbarkeit ist marktabhängig, daher kann eine Zeile, die woanders fehlschlug, hier in Ordnung sein. Überprüfe dies, bevor du etwas ersetzt. Ohne --lat/--lng sagt es dies, anstatt zu raten – es gibt keinen Markt, um eine marktbezogene Aussage zu treffen.
  • „erweitert auf Ebene 2 von 3“ – die Blattkategorie hatte nichts auf Lager, daher stammen die Vorschläge aus einem breiteren Regalbereich und sind entsprechend ungenauer.
  • „nur N wurden verglichen“ – die Kategorie ist größer als eine Seite. Erhöhe --count. Dies wird auch beim leeren Ergebnis ausgegeben, denn „nichts hier ist auf Lager“, behauptet über eine teilweise Durchsuchung, braucht den Vorbehalt mehr, nicht weniger.

Dinge finden, wenn die Anfrage vage ist

Für „wir brauchen Reis“ statt „kauf SKU 1092“ sind zwei Achsen wichtig, und keine ist die Standardeinstellung:

Sortiere nach Stückpreis, nicht nach Packungspreis. --sort per-unit verwendet die PUM-Daten, die D1 nach kolumbianischem Recht veröffentlichen muss. Die beiden Rangfolgen stimmen tatsächlich nicht überein: ARROZ ESTÁNDAR 500 GRS ist die günstigste Packung mit 1.550 $ und kostet 3.100 $/kg, während der beste Wert in denselben Ergebnissen 2.775 $/kg beträgt – in einer 5.550 $-Tüte, die in den Top 5 nach Packungspreis überhaupt nicht vorkommt. Die Sortierung nach Packungspreis liefert eine schlechtere Antwort, während sie richtig aussieht.

Da D1s Suche nicht nach diesem Kriterium sortieren kann, sortiert --sort per-unit die Seite, die du abgerufen hast, nicht die gesamte Ergebnismenge. Erhöhe --count (max. 50), um sie zu verbreitern. Die Ausgabe sagt dies, anstatt eine Übertreibung zu implizieren, die sie nicht stützen kann, und nennt, wie viele Ergebnisse keine Größe angeben und daher überhaupt nicht verglichen werden können.

Eine Mehrfachpackung deklariert die Größe der Packung, nicht eines einzelnen Artikels – „korrigiere“ dies nicht. Eine Erhebung aller 1.600 Produkte ergab, dass bei den namensmäßig vergleichbaren Mehrfachpackungen 44 der 46, bei denen D1 genug sagt, um zu entscheiden, die Packungsgesamtmenge angeben. Das Parsen von N UN aus einem Produktnamen und Multiplizieren würde diese 44 korrumpieren, um 2 zu korrigieren. Die Anzahl in einem Namen ist kein Beleg dafür, was der PUM bedeutet.

resolvePackSize liest daher Beschreibungen statt Namen. Von allen 1.548 Produkten mit einem PUM wird bei den 10 eingegriffen, deren Beschreibung sowohl eine Einzelgröße als auch eine Anzahl angibt: Drei werden korrigiert (SKU 718, 510, 1008), sieben werden bestätigt, dass sie bereits die Packung angeben, und alles andere bleibt wie deklariert.

Lies die Warnhinweise. Produkte tragen Kolumbiens Front-of-Pack-Warnungen (Exceso en Azúcares, Exceso en sodio, Exceso en grasas saturadas, Exceso en grasas trans, Contiene Edulcorantes) in warnings[] unter --json. Die Abdeckung ist partiell – etwa 70–90 % je nach Kategorie – daher bedeutet Abwesenheit „nicht deklariert“, niemals „sicher“.

Verfeinere dann mit d1 facets <query> (Kategorie, Marke, Unterkategorie mit Anzahl), bevor du Seiten durchblätterst: Die Suche ist auf 50 Seiten begrenzt, daher ist eine breite Abfrage besser durch Facetten eingegrenzt als durch Durchblättern.

Befehle

BefehlFunktion
region --lat --lngLieferort bestimmen und speichern
search <query>Produkte finden (--facets --sort --count --page --available)
suggest <teil> · trendingAutovervollständigung · wonach Kolumbien sucht
categories · facets [query]Abteilungsbaum · Filter für eine Abfrage
substitute <sku>Was stattdessen kaufen, und was sich ändert (--limit --count)
quote <sku>[:anz]...Warenkorb bepreisen, keine Veränderung
cart [show|add|set|clear|deliver-to|checkout]Warenkorb zusammenstellen
login --email / --from-cookie · whoami · logoutKonto
orders · order <id>Bestellhistorie (Details sind auf eine Whitelist reduziert; --raw aktiviert die volle Ausgabe)
stores nearD1-Filialen in der Nähe eines Ortes – nur Standorte, D1 bietet keine Abholung an

Tests

bun test        # Geldeinheiten, das Semikolon-Spezifikum, Menge-im-Angebot,
                # Unbekannte-SKU-Vakuum, Warenkorb-Normalisierung, Bestellungs-Redaktion und
                # die Endpunkt-Whitelist, die die Zahlungsoberfläche begrenzt
bun run lint && bun run typecheck

Exit-Codes sind ein Vertrag, keine Dekoration – die Tabelle unter Aufruf oben ist die einzige Kopie davon.

Siehe README.md für die vollständige Endpunktkarte, das Versandstufenverhalten und was die öffentliche API dir nicht geben wird.

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

broomva/skills

Local TTS, voice cloning, voice design, and video dubbing via the OmniVoice Studio MCP server (open-source ElevenLabs alternative; nothing leaves the machine, runs on MPS/CUDA/CPU). Use when: (1) generating speech from text in any of 646 languages, (2) cloning a voice from a 3-second reference clip, (3) designing a voice by gender/age/accent/pitch/style, (4) dubbing a video into another language, (5) listing voice profiles or personality presets, (6) producing narration where privacy, cost, or absent API keys matter, (7) non-English narration where Edge TTS/kokoro fall short, (8) batch audio for blog posts or content pipelines. Triggers: 'omnivoice', 'voice clone', 'clone this voice', 'tts', 'narrate', 'generate speech', 'voice synthesis', 'dub video', 'voice design', 'local tts', 'multilingual voice', 'narrate this post', 'elevenlabs alternative'.

broomva/skills

>- Speak an explanation out loud while working in any project — tiered text-to-speech with a pluggable backend (ElevenLabs by default and quota-guarded, macOS `say` via `--fast` for free instant local speech, local OmniVoice as an unlimited private tier). Markdown-aware, so code fences, URLs and deep paths collapse to short spoken placeholders instead of being dictated character by character, while snake_case identifiers survive intact so the listener can still search for them. Every utterance is saved to disk for later replay. Also carries a **talk mode** toggle: turn it on and the agent speaks a full readback of every turn, for as long as that session lasts — the whole response, not a summary of it, with `brief` and `marker` levels for when you want less. Talk mode is off by default and scoped to the single session that enabled it, so parallel agents in other worktrees stay silent. Use when the user asks to hear something rather than read it — an explanation of a change, a walkthrough of what just happen...

broomva/skills

Stateful, local-first household toxics inventory + swap engine. Identify the items in a home that carry endocrine disruptors and persistent chemicals (BPA/BPS, phthalates, PFAS/PTFE, parabens, flame retardants, VOCs, microplastics), score each by *real* exposure (severity x presence x how it's used x condition), and track the swap to a safer alternative from "flagged" -> "sourced" -> "swapped". Ships a grounded, cited knowledge graph of ~20 hazards, ~40 item-classes, and ~40 alternatives. Hands sourcing off to the `procurer` skill. The skill's state is the source of truth — the agent is the app.

broomva/skills

Tekton — the shared architecture-intent substrate for co-designing systems with the agent. One typed graph across six tiers (system / journey / data / infra / decisions / qualities); views are queries, not separate diagrams. The canonical artifact is a diff-friendly YAML model both human and agent read and write; it renders to Mermaid (agent-legible, GitHub-native) and a self-contained tabbed HTML viewer (human-visual). Cross-tier traceability (`tekton query <from> <to>`) answers "which infra does this user-journey step touch?" as a path query. USE WHEN: designing or thinking deeply about architecture, a system, a data model, user journeys/flows, or a technical plan WITH the agent; when a Category-C HTML doc isn't enough because you need to see AND edit AND traverse the design across tiers; "let's design X", "architect this", "model the system", "draw the flow", "how does this fit together", "diagram this", "/tekton". NOT FOR: a one-off throwaway diagram (use Mermaid inline); prose-only ADRs (write the ADR...

broomva/skills

Generate a polished Remotion video and X thread showcasing the full agent skills inventory. Use when creating social media content about skills, rendering category-based skill visualizations, or producing animated showcases of agent capabilities. Triggers on "skills video", "showcase skills", "skills thread", "render skills", "social content for skills", or requests to visualize the skills inventory.

broomva/skills

OpenCaptions extension for Content Engine — adds intent-driven CWI (Caption With Intent) captions to the post-production pipeline. Hooks into the grade → caption → final stage. Generates captions that understand video intent (pitch, volume, emotion, emphasis) and style themselves accordingly with variable font weight, size, and color. Uses the OpenCaptions CLI or MCP server. Triggers on: 'add captions', 'opencaptions', 'CWI captions', 'intent captions'.

broomva/skills

Produce polished product launch videos using the Liquid Glass aesthetic — dark void backgrounds, 3D perspective floating UI panels, particle effects, spring animations, and cinematic pacing. Built on Remotion with Imagen 4.0 for frames and Veo 3.1 for B-roll. Use when: (1) creating a product demo or launch video, (2) showcasing a UI/app/tool with cinematic polish, (3) building a social-ready video from screenshots and renders, (4) applying the liquid glass floating panel style, (5) composing Remotion videos with 3D transforms and spring animations. Triggers on: 'launch video', 'product video', 'liquid glass video', 'demo video', 'showcase video', 'remotion video', 'floating panel', 'glass aesthetic'.

Verwandte Skills