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;
--verboseenables debug logs. Sensitive fields should not be logged.
Related docs:
- Scheduling for reminder automation.
- Import/Export for vCard/ICS/JSON commands.
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 ofContactListItemDto)today(array ofContactListItemDto)soon(array ofContactListItemDto)dates_today(array ofDateReminderItemDto)
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,timezonenext_touchpoint_at,cadence_days,created_at,updated_at,archived_attags(array of strings)dates(array ofContactDateDto)recent_interactions(array ofInteractionDto)
InteractionDto fields:
id(string UUID)occurred_at(number)kind(string, one ofcall,text,hangout,email,telegram, orother:<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
Contactobject. - Interaction mutations return a serialized
InteractionDtoobject.
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,mailboxesmessages_seen,messages_importedcontacts_created,contacts_merged,contacts_matchedmerge_candidates_createdtouches_recordedwarnings(array of strings)dry_run(boolean)
knotter import telegram --json
Output: JSON object matching TelegramImportReport:
accounts,users_seenmessages_seen,messages_importedcontacts_created,contacts_merged,contacts_matchedmerge_candidates_createdtouches_recordedwarnings(array of strings)dry_run(boolean)
knotter merge
Manual merge workflow for contact following and deduplication.
knotter merge list --jsonreturns an array of merge candidates:id,created_at,status,reason,auto_merge_safe,source,preferred_contact_id,resolved_atcontact_a,contact_bobjects withid,display_name,email,archived_at,updated_at
knotter merge show <id> --jsonreturns a single merge candidate object (same shape as list items).knotter merge apply <id> --jsonreturns the mergedContactobject.knotter merge apply-all --jsonreturns a bulk apply report:considered,selected,applied,skipped,failed(numbers)dry_run(boolean)resultsarray withid,status,reason,source,primary_id,secondary_id,merged_contact_id,error
knotter merge dismiss <id> --jsonreturns the merge candidate object after dismissal.knotter merge contacts <primary> <secondary> --jsonreturns the mergedContactobject.knotter merge scan-same-name --jsonscans the local DB for duplicate display names and creates manual merge candidates (reasonname-duplicate, sourcescan:same-name) for review:considered_contacts,skipped_empty_name_contacts,duplicate_groups,groups_scannedcandidates_created,pairs_skipped_existing_opendry_run(boolean)resultsarray withdisplay_name,normalized_name,preferred_contact_id, andpairscontainingprimary_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:vcforics)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:
metadataobject:exported_at(number, unix seconds UTC)app_version(string)schema_version(number)format_version(number)
contactsarray 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 ofContactDateDto)interactions(array of objects):id,occurred_at,created_at,kind,note,follow_up_at- ordered by
occurred_atdescending
- contact fields:
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)
1for general failures (I/O, database, unexpected errors).2for missing resources (e.g., contact not found, missing TUI binary).3for invalid input (e.g., invalid filter syntax likedue:later, invalid dates, invalid flags).