← Lusha Talent SourcingCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Lusha Talent Sourcing
Snapshot Sep 30, 2026 · 23:12 UTC · version 1.0.0
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"name": "keep-a-list-live",
"description": "Report what changed on a saved candidate list, and work the list. Use when the user asks what has changed, asks to refresh or update a list, asks whether anyone has moved or been promoted, returns to a list they saved earlier, or asks to take people off a list, rename it or add a column to it. Reports only the changes since their last check, each with a date, and stays silent on everyone unchanged.",
"included_files": [
{
"relative_path": "references/shared-reference.md",
"size_in_bytes": 27705
}
],
"skill_md_contents": "---\nname: keep-a-list-live\ndescription: Report what changed on a saved candidate list, and work the list. Use when the user asks what has changed, asks to refresh or update a list, asks whether anyone has moved or been promoted, returns to a list they saved earlier, or asks to take people off a list, rename it or add a column to it. Reports only the changes since their last check, each with a date, and stays silent on everyone unchanged.\n---\n\n# Keep a List Live\n\nRead `references/shared-reference.md` first. It carries the terminology, the twenty hard rules, the\ntenure mechanism, the ordering rules and the cost table. This file is the flow.\n\n## What this skill is for\n\nA recruiter built a talent pipeline weeks ago. They come back and want to know what\nchanged, not to read the whole roster again. This is the skill that makes the\nproduct worth opening twice.\n\n**Language.** A saved list is their **talent pipeline** once they have built it,\nand each person on it is a **candidate**. Say \"three candidates on your Berlin\npipeline moved\", not \"three talents moved\" and not \"three records changed\". Shared\nreference section 1.\n\nThree kinds of change matter, in roughly this order:\n\n1. Someone moved company or was promoted. Their situation changed.\n2. Someone newly crossed the tenure threshold. They were too fresh to approach\n last time and now they are not. Nobody else in the market is tracking this.\n3. Their employer had news. The reason to reach out changed.\n\n## Step 0. Confirm, and say what the read costs\n\nOnly ask what you cannot infer:\n\n- **Which list**, if the account has more than one plausible match. If there is\n one obvious candidate, use it and name it rather than asking.\n- **Since when**, if you have no record of a last check. Offer a default: \"I will\n look at the last three months unless you want a different window.\"\n\nThen say what you are about to read and what it costs, before reading it:\n\n> Your Berlin Backend list has 80 people. Reading it back costs 4 credits, then\n> checking for movement bills per event found plus one per request, so the cap I\n> set is what bounds it. I would expect somewhere between 30 and 60 in total and\n> I will tell you the exact number afterwards. Go ahead?\n\nFor a small list just say it and proceed. For a large one, wait.\n\n## Step 1. Find the list\n\n`list_find`. Free, verified. Never send an `email` parameter to it.\n\nIf several lists could match, name them and ask which. Do not guess between two\nplausible lists; reading the wrong one costs credits and wastes the turn.\n\n## Step 2. Read the rows you need\n\n`list_read`. **This costs 1 credit per 25 rows returned**, whether or not\nanything is revealed, and the values come back masked. Reading a list is not\nfree, so say the cost before you read.\n\nPage rather than pulling the whole list. If they asked about a handful of people,\nread the page those people are on and stop.\n\n## Step 3. Who moved\n\n**Resolve the signal types first.** `candidate_change_filters`. Free. It returns\nwhat actually exists right now rather than what this file thinks exists. Two types\nexist today, `promotion` and `companyChange`, but if Lusha adds a third the filter\ntool will show it and you should use it. Do not hardcode the list from this\ndocument.\n\nThen `candidate_changes`, batched at 25, windowed with `startDate` set to their\nlast check so you only get new movement.\n\nNothing beyond what the filter tool returns is available at person level, so do not\ngo looking for manager changes or job hunting signals just because a recruiter asks\nfor them.\n\nIdentify people by LinkedIn URL where you have it, otherwise email, otherwise full\nname plus company.\n\n## Step 4. What happened at their employers\n\n`employer_events` on the companies from the list, 25 per call, `startDate`\nset to the last check, `maxResultsPerSignal` set to 3. It bills 1 credit per event\nreturned plus 1, so the ceiling is employers × the cap + 1: quote that, keep the\ncap low, and report the `billing.creditsCharged` the response returns.\n\nFor a refresh the events that matter are the ones that make someone more\napproachable: contraction, restructure, acquisition, facility closure, executive\ndeparture. A hiring surge is worth reporting but it is weaker.\n\nThree things to check before reporting any of it. The employer that came back has\nto be the employer on the pipeline, per SHARED-REFERENCE section 6b. `startDate`\nfilters on when the article was published rather than when the event happened, so\nkeep an event only if `eventEffectiveDate` exists and falls inside the window.\nAnd never report an event from its `eventSummary`: the summary attaches a person\nand a role to whichever tracked company the article names, even when that company\nis only somebody's former employer, so read `articleTitle` and `articleHighlight`\nand describe the event yourself. If the article turns out to be about a different\ncompany, the event is not news about this pipeline. Section 6e has the three\nverdicts.\n\nCase-normalise `jobTitle.seniority` when you compare a pipeline read against a\nsearch, because the same field comes back capitalised from one and lower-case from\nthe other.\n\n## Step 5. Who newly became approachable\n\nThis is the step that earns the skill, and it is one call.\n\nBracket the window between the recruiter's last check and today, using both bounds\nof the job-change date. For a two-year threshold and a last check on 24 September:\n\n```json\n\"jobChangedAfterDate\": \"<last check minus 2 years>\",\n\"exclude\": { \"contacts\": { \"jobChangedAfterDate\": \"<today minus 2 years>\" } }\n```\n\nEveryone returned changed job inside that one-month band two years ago, which is\nexactly the set that crossed the two-year threshold since the recruiter last\nlooked.\n\nVerified twice, exactly, on two different populations for one search credit each.\nGerman engineering directors: 21,892 at the older threshold and 22,213 at the\nnewer, and the bracket returned 321. UK senior engineering: 136,500 and 138,742,\nand the bracket returned 2,242. Both match the difference to the person.\n\nRun step 3a's level post-filter and the id dedupe on this output too. It draws\nfrom the same index, so it carries the same off-level records and the same\nduplicates.\n\n**Do not re-run the full search and diff it against the pipeline.** That was the\nearlier instruction and it is the expensive way to the same answer. Finding 321\npeople inside 22,000 rows means paging hundreds of times. The bracket asks the API\nfor the cohort directly.\n\nDo not try to calculate this from stored dates either. The search filters on\ntenure but does not return it, so there is nothing stored to calculate from.\n\nIf you do not know the last check date, ask, or default to one month and say so.\nIf you do not have the original search criteria, say so and offer to rebuild them\nfrom the pipeline rather than guessing.\n\n## Step 6. Order the diff\n\nPer SHARED-REFERENCE section 6, adapted: order by how much each change matters to\na recruiter, not by the order the signals came back.\n\nSomeone who changed company outranks someone whose employer posted a job. Recency\nbreaks ties.\n\n## Step 7. Answer\n\n**Report only what changed.** Group by type, and put a date on every entry.\n\n> Four changes on your Berlin Backend pipeline since 2 July.\n>\n> **Moved company (2)**\n> Anna Weber left Delivery Hero for Zalando, 4 August. Worth a fresh look, she is\n> only two months in.\n> Tomas Novak moved to N26 as Staff Engineer, 22 July.\n>\n> **Promoted (1)**\n> Lukas Bauer is now Engineering Manager at Trade Republic, 1 August.\n>\n> **Newly approachable (3)**\n> Three candidates have now passed two years in seat: Maria Silva, Jonas Klein and\n> Petra Hoffmann. All three were too fresh when you built this pipeline.\n>\n> **Employer news (1)**\n> Zalando cut headcount 3% in July, which affects four candidates here.\n>\n> **No change for the other 69.**\n>\n> That was 4 credits to read the pipeline and 7 signal credits.\n\nThat closing count line matters. Without it the recruiter cannot tell whether you\nchecked everyone or ran out of budget.\n\nThen offer: open anyone worth acting on, take people off, add a column.\n\n## Working the list\n\nThe recruiter can curate in conversation instead of going to the UI.\n\n**Take people off.** `list_remove_candidates`. **Name them back first**, because\nthere is no undo through the API. \"Removing Anna Weber, Tomas Novak and Lukas\nBauer from Berlin Backend. Confirm?\"\n\n**Rename.** `list_update`. Metadata only, it does not touch contents.\n\n**Add a column.** `list_add_column`, after `list_columns` so you do not\ncreate a duplicate. A recruiter-owned column like Notes or Stage turns the list\ninto a working pipeline.\n\n**Populate a column.** `list_run_column`, then poll `list_run_status` because runs\nare asynchronous.\n\n> **`list_run_column` on a reveal column is the only call in this plugin that can\n> spend at list scale.** An email column across 500 rows is 500 credits in one\n> call. Phone is five each. State the per-row cost, get an explicit yes, and scope\n> to selected rows if the API allows it. Never run one as a side effect of a\n> request for something else.\n\nIf a run partially completes, report which rows populated and what was charged.\nNever re-run the whole column to fix a partial result.\n\n## The durable refresh, if it turns out to be possible\n\nIf a column can carry a Lusha signal, then the whole refresh can live in the\ntable: add the column once, re-run it against the saved rows whenever the\nrecruiter wants, and the result persists in their workspace instead of vanishing\nwith the conversation. That is a better product than a chat answer.\n\n**Nobody has established that signal columns exist.** It is being measured in\nINF-3038. Until it comes back, run the flow above and do not promise the in-table\nversion.\n\n## Never, in this skill\n\n- Re-list the whole roster. The point is the diff.\n- Reveal anything during a refresh.\n- Pull a 200-row list into the conversation to answer \"what changed\".\n- Tell the recruiter reading the list back is free.\n- Re-run the whole position search and diff it to find the newly approachable.\n Bracket it instead.\n- Run employer events without setting `maxResultsPerSignal`. It is the price of\n the call, not a response-size limit.\n- Leave `maxResultsPerSignal` at its default on a large employer set.\n- Remove anyone without naming them first.\n- Run a reveal column without an explicit yes and a stated cost.\n- Send an `email` parameter to any `list_*` tool.\n\n## Worked example\n\n**Recruiter:** what's changed on my Berlin list?\n\n**You:** Berlin Backend, 80 people, last checked 2 July. Reading it back is 4\ncredits, then signal checks on top. Running it.\n\n*(list_find, list_read paged, signals on people, signals on companies, one\nbracketed tenure search, order the diff)*\n\n**You:** *(the grouped diff above)*\n\n**Recruiter:** take the three who moved off the list\n\n**You:** Removing Anna Weber, Tomas Novak and Lukas Bauer from Berlin Backend.\nThere is no undo, confirm?\n\n**Recruiter:** yes\n\n**You:** Done, 77 people left. Want me to add the three newly approachable ones in\ntheir place?\n"
}SHA-256: 1c3bfabf43229ed11f6f78e36a7f0f05ffe6ed440cd229617a9d150cf92f7fb7