Skip to main content

jeff

jeff

Your contacts live in CardDAV. Your CRM lives in Markdown.

PyPI version Python versions License: MIT Build Publish codecov Docstring coverage Quality Gate Status Maintainability Rating Reliability Rating Security Rating Bugs Vulnerabilities Code Smells Technical Debt

jeff syncs contacts from a Baikal CardDAV server into clean Markdown files with YAML frontmatter, then publishes a static HTML site. No database, no SaaS, no vendor lock-in — just files, Git, and a fast static site.

Quick start

pip install jeff-contacts
jeff init                # creates .jeff config file
# Edit .jeff with your CardDAV credentials
jeff sync                # fetch contacts
jeff publish             # build HTML site
open public/index.html

Workflow

Le workflow jeff se fait en 5 étapes. Les 4 premières sont à faire une fois lors de la mise en place, la dernière tourne quotidiennement.

1. jeff sync — Récupérer les contacts

jeff sync           # sync incrémental (seuls les changements)
jeff sync --full    # force un re-sync complet

Connecte le serveur CardDAV (Baikal), détecte les contacts modifiés via ctag/etag, télécharge les vCards et les transforme en fichiers Markdown avec frontmatter YAML. Chaque contact devient un fichier .md dans content/contacts/.

Le sync est incrémental : seuls les contacts ajoutés, modifiés ou supprimés depuis le dernier sync sont traités. Un --full force la régénération de tous les fichiers.

2. jeff triage — Trier les contacts

jeff triage
  [1/559] ──────────────────────────────────────────
  Jean Dupont
    tags: ami, ski, photo
    note: Photographe amateur
    addr: Avenue des Alpes 109, Geneve, Suisse
    email: jean@example.com
    phone: +41791234567

  > a a h H    # actif, ami, haute priorité, homme
  ✓ Jean Dupont → actif

Passe en revue chaque contact non trié et permet de décider rapidement :

  • a = actif (garder dans le CRM) avec relation, priorité et genre
  • r = archivé (masqué du dashboard mais conservé)
  • s = skip (on décide plus tard)
  • q = quitter (reprend où on s'est arrêté la prochaine fois)

Relations : a=ami, c=collègue, f=famille, k=connaissance. Priorités : h=haute, m=moyenne, b=basse. Genre : H=homme, F=femme.

3. jeff genre — Assigner le genre

jeff genre
  [1/204] Jean Dupont: h
  [2/204] Marie Martin: f
  [3/204] Acme Corp: n

Passe rapidement sur tous les contacts sans genre. Utile pour :

  • Les liens familiaux (distinguer père/mère automatiquement)
  • L'affichage dans le dashboard (♂️/♀️)
  • Le writeback vers CardDAV (X-GENDER)

Codes : H=homme, F=femme, N=none (entreprise), Enter=skip, q=quit.

4. jeff famille — Liens familiaux

jeff famille              # tous les contacts famille
jeff famille dupont       # filtrer par nom
jeff famille --check      # vérifier la cohérence
── [1/54] Jacques Dupont (homme) ──
    ↳ (aucun lien)

    1. Anne Dupont (femme)
    2. Jean Dupont (homme)
    3. Luc Dupont (homme)

    f=père m=mère w=conjoint c=enfant b=frère/sœur
    ?texte=chercher  Enter=skip  q=quit

  > 1w 2c 3c
  ✓ Jacques Dupont: conjoint=anne-dupont enfants=[jean-dupont, luc-dupont]
  ↔ Anne Dupont: conjoint=jacques-dupont
  ↔ Jean Dupont: pere=jacques-dupont
  ↔ Luc Dupont: pere=jacques-dupont

Pour chaque contact famille, affiche les membres du même nom de famille numérotés. On tape les numéros avec le code de relation. Les liens sont écrits réciproquement — assigner un père ajoute automatiquement l'enfant chez le père, et le genre détermine si c'est père ou mère.

jeff famille --check vérifie que tous les liens sont bidirectionnels et propose de corriger les incohérences.

5. jeff note — Consigner une interaction

jeff note antoine                       # note pour aujourd'hui
jeff note antoine --date 2025-05-06     # date passée
  Antoine Martin
  type (w=whatsapp  t=tel  m=mail  v=visite  n=note): t
  note: Pris des nouvelles, on planifie une rando pour juin.
  ✓ 2025-05-06.md

Crée un fichier d'interaction daté dans le dossier du contact. La recherche est partielle — jeff note ant trouve "Antoine Martin". Chaque interaction est un .md avec date et type, visible dans le dossier du contact :

content/contacts/antoine-martin/
  antoine-martin.md     # fiche contact
  2025-05-06.md         # interaction WhatsApp
  2025-04-01.md         # interaction téléphone

6. jeff cron — Automatisation quotidienne

jeff cron
── Sync ──
Discovering addressbooks...
Addressbook: Contacts
Already up to date.

── Birthdays ──
  🎂 Jean Dupont (recorded)

── Publish ──
Published 204 contact(s) to public/

Enchaîne automatiquement : sync → détection des anniversaires → publication du site HTML. Conçu pour tourner dans un crontab :

0 7 * * * cd /path/to/project && jeff cron

Le site publié inclut :

  • Dashboard avec contacts groupés par relation et triés par priorité
  • Section anniversaires du jour avec bouton WhatsApp pré-rempli
  • Arbre généalogique (Graphviz SVG)
  • Fiches contact avec coordonnées, liens familiaux et signe astrologique

Autres commandes

Commande Description
jeff delete Marquer des contacts archivés pour suppression du CardDAV
jeff check Détecter et nettoyer les doublons (même UID)
jeff export Exporter au format SquirrelMail (.abook)
jeff birthday-mail Envoyer un rappel anniversaire par email
jeff sync --writeback-gender Pousser le genre vers CardDAV (X-GENDER)
jeff sync --writeback-famille Pousser les liens familiaux vers CardDAV (RELATED)

Architecture

src/jeff/
  cli.py                  CLI commands (click)
  domain/                 Business objects
    carddav.py            CardDAV client
    config.py             Configuration (.jeff file)
    transform.py          vCard → Markdown
    urlback.py            vCard injection (URL, gender, RELATED)
  services/               Business logic
    sync.py               Sync orchestration
    publish.py            Static site builder
    triage.py             Contact triage
    famille.py            Family link management
    genealogy.py          Family tree (Graphviz)
    birthday.py           Birthday detection
    birthday_mail.py      Email reminders
    genre.py              Gender assignment
    duplicates.py         Duplicate detection
    export.py             Address book export

License

MIT

Metadata

Release files for jeff-contacts 0.1.29

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jeff-contacts 0.1.29
File Size Uploaded Provenance Actions
jeff_contacts-0.1.29.tar.gz 248.6 kB Without provenance Details for jeff_contacts-0.1.29.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for jeff-contacts 0.1.29
File Interpreter ABI Platform Actions
jeff_contacts-0.1.29-py3-none-any.whl Python 3 none any Details for jeff_contacts-0.1.29-py3-none-any.whl

Total release size: 482.8 kB

Release files / jeff_contacts-0.1.29.tar.gz

Download URL jeff_contacts-0.1.29.tar.gz
Size 248.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8b05a2fcc630c809efecd37e7a046d7adbe8bb3fc5a2916994bfec8423c963d8
BLAKE2b-256 checksum
How to use checksums
666680653f54234e29bceeda3c70bc19d9bc8a9e9187c4e1d5a5e1c4424a6039
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via pdm/2.28.0 CPython/3.13.14 Linux/6.17.0-1020-azure

Release files / jeff_contacts-0.1.29-py3-none-any.whl

Download URL jeff_contacts-0.1.29-py3-none-any.whl
Size 234.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f3050ececb73f61927a4b1cd99541cc4f46db89e24b6c5fecda2f59e7c5dcfee
BLAKE2b-256 checksum
How to use checksums
a101a51ed4b6d1399a20b615e29525d8152377b3c9f4ca0d7a87646de6375e33
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via pdm/2.28.0 CPython/3.13.14 Linux/6.17.0-1020-azure

Security for jeff-contacts 0.1.29

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page