Textual contacts TUI over khard (CardDAV)
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Joerg Ziefle 72256e1940
Some checks failed
check / check (push) Failing after 14s
feat(tui): E key — enrich current contact in-app
Press E on a contact: claude researches it in a background worker (UI stays
responsive), a review modal shows the proposed fills + confidence/source, a/Enter
applies (fill-blank + tags + sync), Esc cancels. Reuses build_prompt/run_claude/
parse_response/apply_enrichment. New EnrichReview modal. 4 tests (worker glue thin).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-25 00:17:41 +02:00
.forgejo/workflows refactor(theme): use shared ktui.theme; drop local copy 2026-06-24 18:44:43 +02:00
kard feat(tui): E key — enrich current contact in-app 2026-06-25 00:17:41 +02:00
tests feat(tui): E key — enrich current contact in-app 2026-06-25 00:17:41 +02:00
.gitignore docs: kard contacts TUI design spec 2026-06-21 00:18:47 +02:00
pyproject.toml refactor: use ktui keymap-core, config-base, and sync 2026-06-24 19:34:01 +02:00
README.md feat(tui): E key — enrich current contact in-app 2026-06-25 00:17:41 +02:00
uv.lock refactor: use ktui keymap-core, config-base, and sync 2026-06-24 19:34:01 +02:00

kard

A Textual contacts TUI built on khard's vCard store. Adds Tokyo Night theming, Space-leader/which-key keys, multi-select, category management, and duplicate detection/merge — while reusing khard for new-contact creation and $EDITOR for edits. Sync stays with vdirsyncer.

How it works

kard/engine.py is the only module that touches the contact store. It reads .vcf files directly via vobject (reads all addressbooks), exposes a frozen Contact dataclass, and performs category writes and merge construction in-place via vobject. new shells out to khard so UIDs and file naming are correct. edit opens the known file path in $EDITOR (more precise than khard edit which can match multiple). delete removes the file. Sync runs vdirsyncer on demand and auto-syncs after every write.

Every other module (widgets, screens, app) depends only on the Contact DTO and the Engine API — fully decoupled from vobject internals.

Install

pipx install ~/src/kard      # or: pipx install git+ssh://forgejo/jmz/kard.git
kard --version
kard                         # launch the TUI

kard reads your existing ~/.config/khard/khard.conf for addressbook paths. Its own UI state lives in ~/.config/kard/kard.toml. If khard isn't configured, kard exits with a message pointing you at https://github.com/lucc/khard rather than a traceback.

Keys

Press Space for the which-key menu:

Leader chords (Space then):

Chord Action
Space a add contact (opens khard new in terminal)
Space e edit contact ($EDITOR on the vCard file)
Space d delete contact (confirm prompt)
Space c f filter by category
Space c t tag / untag category (applies to selected or current)
Space c m manage categories (rename / delete across all contacts)
Space M merge / duplicates (auto-detect or merge multi-selected)
Space s sync now (runs vdirsyncer sync, then refreshes)
Space y copy primary email to clipboard (macOS pbcopy)
Space / search contacts

Direct keys:

Key Action
j / k (↓/↑) move cursor
E enrich current contact (claude research → review modal → apply)
x toggle multi-select on current contact
X clear selection
? show help screen (all keybindings)
q quit

Configuration

~/.config/kard/kard.toml (optional):

[keys]             # remap leader or direct actions (action = key)
sync = "S"

[theme]            # override Tokyo Night palette tokens (#rrggbb)
accent = "#bb9af7"

Remappable actions: add, edit, delete, cat_filter, cat_tag, cat_manage, merge, sync, copy_email, search (leader chords); show_help, quit (direct keys). Theme tokens: background, surface, panel, foreground, primary, accent, secondary, warning, error, success, dim. Invalid entries are ignored with a warning toast and fall back to defaults.

Enrich (LLM-assisted)

kard enrich researches contacts via the claude CLI (which uses your mail-archive MCP + web) and proposes fill-blank field/tag enrichments for review. Two phases, human-gated:

# 1) propose — research thin contacts (no title and no note) -> a review file
kard enrich --thin --file ~/contacts-enrich.toml   # also: --all / --uid U… / --category TAG
#    --batch N   contacts per claude call (default 5)
#    --limit N   cap how many are processed

# 2) review ~/contacts-enrich.toml — flip `apply = false` to skip, or edit values

# 3) apply — fill ONLY blank fields + union tags (additive), then vdirsyncer sync
kard enrich --apply --file ~/contacts-enrich.toml
kard enrich --apply --dry-run --file ~/contacts-enrich.toml   # preview, write nothing

Safety: never overwrites a non-blank field; tags are additive only (Archive only ever added); nothing applies without your review; --dry-run previews. Tags are constrained to kard's fixed taxonomy. Requires the claude CLI on PATH (only for enrich; the TUI never needs it) — enrichment research tools are pre-allowed for headless runs.

Runtime dependencies

  • khard — used for kard add (runs khard new -a <addressbook>)
  • vdirsyncer — used for kard sync / auto-sync after writes
  • vobject — vCard parsing and in-place CATEGORIES / merge writes (Python library, installed automatically)

Development

python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest          # runs all tests