CLAUDE-clients.md
Language Markdown7.7 KB138 lines
---type: claude-instructionsscope: 03-Clientstags: [claude, outreach, clients, rag]created: 2026-06-16updated: 2026-08-12---# CLAUDE: 03-Clients (scoped rules)Governs everything under `03-Clients/`. Logged in root [[CLAUDE]]. Read this beforecreating, editing, or enriching anything in this folder.## Folder layout: what lives where```03-Clients/├── CLAUDE-clients.md ← this file (the only .md at this level)├── partner-client-master-list.xml ← Partner Program master list (schema 3.0)└── client-stubs/ ← ALL client stubs, one .md per client, flat```- **Every client stub lives in `client-stubs/`.** Never at the `03-Clients/` root, never innew subfolders. The root holds exactly two files: this one and the XML map.- Dataview rollups elsewhere (tier notes, outreach notes, [[00-Index]]) query`"03-Clients/client-stubs"`, so a stub saved anywhere else silently drops out of everyrollup. Keep the folder flat rather than "fixing" the queries.## The two layers, and which one you touch1. **Stubs (`client-stubs/*.md`):** the full per-client record. This is the write targetfor enrichment and human-facing work.2. **Master list (`partner-client-master-list.xml`):** the client-centered RAG-chunkedcensus of the Partner Program, derived from the stubs plus Bitrix. It never holdsinformation that contradicts a stub. **When the two disagree, the stub wins** and the XMLgets corrected.## Stub anatomy: the live shapeStubs are authored by `_create_stub()` in `07-Automation/weekly_partner_pipeline.py`.`_templates/client-stub.md` mirrors it (plus a `plinth_id` slot, see Known drift). Build anyhand-made stub from that template so hand-made and driver-made stubs stay identical.Sections, in order:`frontmatter` → `# First Last` → `## Snapshot` → `## Order History` →`## Research` (`### Company`, `### Person / LinkedIn`, `### Recent News & Signals`,`### Sources`) → `## Human Notes` → `## Outreach Log``## Outreach Log` uses the six-column header shared by all stubs:`| Date | Pipeline | Channel | Template | Outcome | Next step |`There is **no `## Links` section**, and stubs carry **no tier or outreach wikilinks**.Segmentation is frontmatter-driven: see below.### Frontmatter: universal keysIn this order (every key is on every stub except `plinth_id`; see Known drift):`type` · `bitrix_id` · `plinth_id` · `first_name` · `last_name` · `email` ·`user_group` · `user_group_correct` · `industry` · `company` · `phone` · `ltv` ·`repeat_revenue` · `title` · `company_website` · `total_orders_count` ·`last_order_date` · `source` · `last_modified` · `tags`### Conditional- `outreach_pipelines`: present only once a client enters a Bitrix funnel. Keys:`partner_outreach` (cat 24, Partner Tier Upgrade), `quarterly_checkin` (cat 36),`winback` (cat 26). Each carries `stage`, `status`, `entered`, `last_touch`, `next_step`,`next_date`. Omit the block entirely rather than writing an empty one; this mirrors`<pipelines count="0" />` in the XML.### Do not add these- `enrichment_status`, `email_one_status`, `email_two_status`: retired. Added 2026-06-16,dropped by the 2026-07-23 rebuild; the driver has never written them since. 0 stubs.- `updated`: an old `enrich_writeback.py` defect left it on some stubs of the live book (none in the sample). **The date key is`last_modified`.** Normalize it away if you touch a stub that has both.- `outreach_type`, `seniority`, `total_orders_usd`, `city`, `state`, `winback_done_before`,`linkedin`, `company_linkedin`: legacy pre-2026-07 fields. 0 stubs.## Segmentation: which field to trust- **`user_group_correct` is the tier.** Pipeline-computed. In the shipped sample:Palladium 86 / Platinum 29 / Iridium 8 / Rhodium 7. Filter and roll up on this.- **`user_group` is the raw Plinth store group and is blank on every sample stub (130 of130).** Never filter on it. It is kept only as a record of what Plinth reports.- **Outreach play comes from `outreach_pipelines`**, not from a field.## Master-list contract (schema 3.0)- **Root:** `<partner_client_master_list schema_version="3.0">`. One `<client>` element perpartner client = one self-contained retrieval chunk. Chunk at the `<client>` boundary;each `<pipeline>` repeats `<client_ref>` so per-pipeline sub-chunks stay self-identifying.- **Dual identifiers:** every `<client>` carries `<bitrix_id>` (CRM contact id) and`<plinth_id>` (Plinth backend user id) alongside the stable `id` attribute (the RAG key).A blank `<bitrix_id />` means the client isn't in the CRM yet.- **Stable key:** `id` = Bitrix contact / tracker id for pipeline-mapped clients; for apartner client not yet in Bitrix, `id` = `pl-<Plinth user_id>`. Never reuse or renumber.Reconcile when the client later gets a Bitrix contact and enters a pipeline.- **`<summary>` is auto-generated** from the other fields. Regenerate it whenever any fieldof that client changes; never hand-edit it in isolation.- **Stub pointers:** `<stub><relative_path>` is `/03-Clients/client-stubs/<file_name>`, andthe same path ends the `<summary>`. Rename or move a stub and both must be updated.- **Coverage:** every partner client (Palladium and up) should have a `<client>` chunkwhether or not they're in a pipeline. The weekly `refresh-xml` stage adds missing chunksand re-stamps the rest. Two Plinth accounts that are the same person (same name + email)share one chunk; colleagues on a shared company mailbox each get their own. Non-partnercustomers are not auto-added.- **Sync duty:** any change to a client's identity, tier, or pipeline placement in a stub mustbe mirrored into that client's chunk (fields + regenerated `<summary>`) in the samechange-set.- **Validate the XML parses after any edit**(`python3 -c "import xml.etree.ElementTree as ET; ET.parse(...)"`). A broken map is worsethan a stale one.## The scraping-dump contract- Append scraped/enriched data **only** under `## Research`, inside the labelled subsections(Company, Person / LinkedIn, Recent News & Signals, Sources).- Every scraped claim gets a source URL under `### Sources`. **No source, no claim.**- **Never** write into `## Human Notes`: that space is Matt's and Hazel's.- Update frontmatter (`title`, `industry`, `company_website`, `phone`) when scraping confirmsor corrects it, and bump `last_modified`.- If a field is unknown, leave the `[TBD]` marker. Do not invent it.## Linking- Link to a stub by **bare name** (`[[Celia Iverson]]`), not by path. Bare names resolvewherever the stub lives.- Exception: if the target filename is ambiguous (the same basename exists in more than onefolder), use a path-qualified link with an alias, or you may resolve to the wrong file.- Stubs do **not** link out to tier or outreach notes. Don't add such links; the rollupsread frontmatter.## Known drift: verified 2026-09-21Flagged, not fixed. Read around these until they're resolved:- **A stub's `## Order History` body can lag its frontmatter.** The driver writes the bodyonly when it creates the stub (`_create_stub()`); upgrades (`_upgrade_stub()`) refreshfrontmatter only (`ltv`, `repeat_revenue`, `total_orders_count`, `last_order_date`,`user_group_correct`, `last_modified`). **Frontmatter is the live record;** trust it overthe body. Example: [[Celia Iverson]] shows a higher `ltv` in frontmatter than in her body.- **The driver does not write `plinth_id` into stub frontmatter.** Stubs carry it only whereit was backfilled by hand (none of the sample stubs do). The census `<plinth_id>` is alwaysset, so resolve a stub's Plinth account through its XML chunk.## LedgerAny change in this folder (stub edits, XML updates, moves) is a vault change: one batchedentry in [[LEDGER]] before the turn ends.