Knotter CLI Output

This document defines the stable output surface for the CLI.

General rules

  • IDs are UUID strings (lowercase hex with dashes).
  • Timestamps are unix seconds (UTC) in JSON output.
  • Human output is intended for terminals and may evolve; JSON output is the stable interface.
  • Diagnostics are written to stderr; --verbose enables debug logs. Sensitive fields should not be logged.

Related docs:

JSON output

Enable JSON output with the global flag --json.

knotter list --json

Output: JSON array of contact list items.

Each item matches ContactListItemDto:

  • id (string UUID)
  • display_name (string)
  • due_state (string enum: unscheduled, overdue, today, soon, scheduled)
  • next_touchpoint_at (number|null, unix seconds UTC)
  • archived_at (number|null, unix seconds UTC)
  • tags (array of strings)

Archived contacts are excluded by default. Use --include-archived or --only-archived to change this behavior (or filter with archived:true|false).

knotter remind --json

Output: JSON object matching ReminderOutputDto:

  • overdue (array of ContactListItemDto)
  • today (array of ContactListItemDto)
  • soon (array of ContactListItemDto)
  • dates_today (array of DateReminderItemDto)

DateReminderItemDto fields:

  • contact_id (string UUID)
  • display_name (string)
  • kind (string enum: birthday, name_day, custom)
  • label (string|null)
  • month (number)
  • day (number)
  • year (number|null)

Note: due_state and reminder buckets depend on the current due_soon_days setting (CLI flag or config default). In JSON mode, notifications only run when --notify is provided explicitly. When notifications.backend = "stdout", --notify --json returns a non-zero exit code because stdout notifications cannot run without corrupting JSON output. When notifications.backend = "email", --notify sends email and failures return a non-zero exit code.

Reminder items include the archived_at field from ContactListItemDto, but it will always be null because archived contacts are excluded from reminders.

Note: When notifications.random_contacts_if_no_reminders > 0, notifications may include an additional "random contacts" section when reminders are otherwise empty. This is not represented in ReminderOutputDto, so knotter remind --json will not include those random picks.

knotter show <id> --json

Output: JSON object matching ContactDetailDto:

  • id, display_name, email (primary), emails (array), phone, handle, timezone
  • next_touchpoint_at, cadence_days, created_at, updated_at, archived_at
  • tags (array of strings)
  • dates (array of ContactDateDto)
  • recent_interactions (array of InteractionDto)

InteractionDto fields:

  • id (string UUID)
  • occurred_at (number)
  • kind (string, one of call, text, hangout, email, telegram, or other:<label>)
  • note (string)
  • follow_up_at (number|null)

ContactDateDto fields:

  • id (string UUID)
  • kind (string enum: birthday, name_day, custom)
  • label (string|null)
  • month (number)
  • day (number)
  • year (number|null)

knotter tag ls --json

Output: JSON array of tag counts:

  • name (string, normalized)
  • count (number)

knotter tag add/rm --json

Output: JSON object containing:

  • id (string UUID)
  • tag (string, normalized)

knotter date add --json

Output: JSON object matching ContactDateDto.

knotter date ls --json

Output: JSON array of ContactDateDto.

knotter date rm --json

Output: JSON object containing:

  • id (string UUID)

knotter loops apply --json

Output: JSON object containing:

  • matched (number of contacts that matched a loop rule or default)
  • updated (number of contacts updated)
  • scheduled (number of contacts scheduled from a missing touchpoint)
  • skipped (number of contacts skipped)
  • dry_run (boolean)
  • changes (array of objects):
    • id (string UUID)
    • display_name (string)
    • cadence_before (number|null)
    • cadence_after (number|null)
    • next_touchpoint_before (number|null)
    • next_touchpoint_after (number|null)
    • scheduled (boolean)

knotter sync

knotter sync runs all configured contact sources, email accounts, and telegram accounts (unless --no-telegram), then applies loops and runs reminders. It does not support --json; use individual commands (import, loops apply, remind) if you need machine-readable output. Sync is best-effort: it continues after failures, prints warnings to stderr, and returns a non-zero exit code if any step fails.

JSON for mutating commands

For add-contact, edit-contact, archive-contact, unarchive-contact, schedule, clear-schedule, add-note, and touch, JSON output includes the created/updated entity:

  • Contact mutations return a serialized Contact object.
  • Interaction mutations return a serialized InteractionDto object.

Note: This output shape may be expanded in the future, but existing fields are stable.

When default_cadence_days is set in config, add-contact uses it if --cadence-days is omitted. If loop rules are configured, they take precedence over the default cadence when --cadence-days is omitted.

Note: add-note and touch only reschedule the next touchpoint when --reschedule is used or interactions.auto_reschedule = true is set in config.

Note: next_touchpoint_at values provided via add-contact, edit-contact, or schedule must be now or later. Date-only inputs are treated as day-precision (today or later) and are saved as the end of that day.

knotter import vcf --json

Output: JSON object matching ImportReport:

  • created (number)
  • updated (number)
  • skipped (number)
  • merge_candidates_created (number)
  • warnings (array of strings)
  • dry_run (boolean)

The same output shape is used for import macos, import carddav, and import source.

knotter import email --json

Output: JSON object matching EmailImportReport:

  • accounts, mailboxes
  • messages_seen, messages_imported
  • contacts_created, contacts_merged, contacts_matched
  • merge_candidates_created
  • touches_recorded
  • warnings (array of strings)
  • dry_run (boolean)

knotter import telegram --json

Output: JSON object matching TelegramImportReport:

  • accounts, users_seen
  • messages_seen, messages_imported
  • contacts_created, contacts_merged, contacts_matched
  • merge_candidates_created
  • touches_recorded
  • warnings (array of strings)
  • dry_run (boolean)

knotter merge

Manual merge workflow for contact following and deduplication.

  • knotter merge list --json returns an array of merge candidates:
    • id, created_at, status, reason, auto_merge_safe, source, preferred_contact_id, resolved_at
    • contact_a, contact_b objects with id, display_name, email, archived_at, updated_at
  • knotter merge show <id> --json returns a single merge candidate object (same shape as list items).
  • knotter merge apply <id> --json returns the merged Contact object.
  • knotter merge apply-all --json returns a bulk apply report:
    • considered, selected, applied, skipped, failed (numbers)
    • dry_run (boolean)
    • results array with id, status, reason, source, primary_id, secondary_id, merged_contact_id, error
  • knotter merge dismiss <id> --json returns the merge candidate object after dismissal.
  • knotter merge contacts <primary> <secondary> --json returns the merged Contact object.
  • knotter merge scan-same-name --json scans the local DB for duplicate display names and creates manual merge candidates (reason name-duplicate, source scan:same-name) for review:
    • considered_contacts, skipped_empty_name_contacts, duplicate_groups, groups_scanned
    • candidates_created, pairs_skipped_existing_open
    • dry_run (boolean)
    • results array with display_name, normalized_name, preferred_contact_id, and pairs containing primary_id, secondary_id, status, merge_candidate_id
    • Preferred contact heuristic: active contacts are preferred; then the record with more identifiers (email/phone/handle); then the most recently updated; then the oldest created (stable canonical record).

Defaults: merges prefer the chosen primary contact for most fields, pick the earliest next_touchpoint_at, and keep the contact active if either side is active.

knotter export vcf/ics --json

Note: --json requires --out to avoid mixing JSON with exported data.

Output: JSON object:

  • format (string: vcf or ics)
  • count (number of exported entries)
  • output (string path)

knotter export json

If --out is omitted, the snapshot JSON is written to stdout (regardless of --json). If --out is provided, stdout contains a human message by default, or a JSON report when --json is set (same shape as other export commands).

Snapshot JSON output:

  • metadata object:
    • exported_at (number, unix seconds UTC)
    • app_version (string)
    • schema_version (number)
    • format_version (number)
  • contacts array of objects:
    • contact fields: id, display_name, email (primary), emails (array), phone, handle, timezone, next_touchpoint_at, cadence_days, created_at, updated_at, archived_at
    • tags (array of strings)
    • dates (array of ContactDateDto)
    • interactions (array of objects):
      • id, occurred_at, created_at, kind, note, follow_up_at
      • ordered by occurred_at descending

Archived contacts are included by default. Use --exclude-archived to omit them.

knotter backup --json

If --out is omitted, the backup is written to the XDG data dir using a timestamped filename.

Output: JSON object:

  • output (string path)
  • size_bytes (number)

Exit codes (selected)

  • 1 for general failures (I/O, database, unexpected errors).
  • 2 for missing resources (e.g., contact not found, missing TUI binary).
  • 3 for invalid input (e.g., invalid filter syntax like due:later, invalid dates, invalid flags).