# Feature detail: Contacts sync + mutation (tie-in) **Parent roadmap:** [[../features-for-redmine_tickets-sync]] **Status:** Sync/search/show + draftable `contact-set` + `ticket-contact` bridge (2026-07-15) **Module:** `redmine_ticket_contacts.py` **Still separate from:** full `redmine_contacts.py` CRM CLI (batch/loops/custom-field tooling) ## Why not one tool - Tickets workbench wants co-located per-id JSON + draft/apply safety next to tickets. - `redmine_contacts.py` already owns heavy CRM workflows and a different cache layout. - Do not rewrite/delete the CRM CLI; add bridges so a ticket-started workflow can end on contacts. ## Implemented ```bash ./bin/rtl contacts-sync --max-contacts 100 ./bin/rtl contacts-search --query ada ./bin/rtl contact-show --contact-id 14 --fetch # Bridge ticket → contact id ./bin/rtl ticket-contact --issue-id 41934 ./bin/rtl ticket-contact --issue-id 41934 --show --fetch # CRM mutation (draft by default; same prod/LAN gates as ticket writes) ./bin/rtl contact-set --contact-id 4515 --add-tag maybe-customer ./bin/rtd contact-set --contact-id 2284 --add-tag maybe-customer --apply --refresh-cache ``` - Durable path: `/contacts/.json` + `manifest.json` - Draft kind: `contact_fields` (apply via `draft apply`) - Handoff hints print `redmine_contacts.py show …` for full CRM when needed ## Still open - Richer custom-field helpers (use `redmine_contacts.py` or extend `--set`) - Optional cron for contacts next to ticket sync - Shared library / single on-disk layout if dual-cache friction becomes painful