What an open-source candidate sourcing agent has to remember
AI candidate sourcing tools are good at finding people
AI candidate sourcing tools are good at finding people. The bill arrives weeks later, when a candidate who already interviewed in March gets a fresh cold email from the same company or a second one from another recruiter on the same team. A daily agent has to answer a harder question than who matches the role: whom have we already contacted, and where is that written down? The candidate sourcing agent we run on Kortix, which is open source, is built around that record.
State lives outside the model
Kortix is the open-source CompanyOS: your agents, their skills, your company memory, and every connector in one git repo you own, with the agents working on real cloud computers. A sourcing run on it starts as a fresh session each morning, so the conversation begins empty. Each run gets its own isolated sandbox, scoped to one open role, so nothing carries over in the machine either. That is the right default for a job that touches the outside world: no leftover tab, no half-finished search.
What the run needs instead is input. It reads the role's sourcing profile and candidate criteria, then the role's Greenhouse pipeline: applicants, people already contacted, and anyone rejected or passed on. That read answers one half of the duplicate question. The other half is the batch the agent drafted yesterday and on the days before. A draft stays outside the ATS until a recruiter acts on it. Until then, the record of who was approached has to live somewhere the next run can read.
Skip the second record and a daily sweep becomes a machine for rediscovering the same people. Two open roles with overlapping profiles make it worse. A senior backend role and a platform role can both match the same engineer, and two sessions that never see each other's output will write two emails in one week. The model did nothing wrong: it answered the question it was given, with the state it was given. A candidate who receives two pitches in a week remembers the company name, not the agent that sent them.
What one sweep did
The use-case page for this job shows one run under the heading "Read the batch in the review inbox". It introduces the block as "This is what a run looks like in the session":
Reviewed 31 LinkedIn profiles and dropped 13 that were already in the pipeline. Drafted 18 personalized emails, each with the candidate's current role and the reason they matched. All 18 are in the review inbox, and nothing was sent.
Thirteen drops out of thirty-one is the number a buyer should look at first. A tool that only reports what it found hides the decision that kept thirteen people out of the outbox. The run states its mode in one line too: Sources and drafts only · recruiter reviews and sends. The connected systems are Greenhouse, LinkedIn and Email, and the trigger is a daily cron.
The guardrail is one sentence on that page: "The agent checks the role's Greenhouse pipeline before drafting anything." The search is a commodity; the check is what keeps the same person from receiving the same pitch twice.
The schedule itself is a trigger in the project manifest:
triggers:
- slug: daily-sourcing-sweep
name: Daily candidate-sourcing sweep
on:
cron: "0 0 7 * * *"
run:
agent: candidate-sourcing
prompt: Load the outbound-sourcing skill and run one complete sourcing sweep for the open role.
The block is small on purpose. It names the agent, the skill it loads, and the hour it runs. Nothing in it decides who gets an email. That decision happens inside the run, after the pipeline read. The run ends with a batch in the review inbox and no send. The recruiter edits, sends, and decides whether the candidate enters the ATS.
The rule is a file
The setup prompt is five numbered steps. It creates agents/candidate-sourcing.md for the prompt and skills/outbound-sourcing/SKILL.md for the sourcing profile and outreach angles. It adds the daily-sourcing-sweep trigger to kortix.yaml. It asks which connectors are not connected yet, then opens a change request without merging it. The person who owns the recruiting stack can read the dedupe step and the send boundary before the schedule starts.
An agent is one agents.<name> block in kortix.yaml. The job is a named object in the repo rather than a workflow inside a vendor's dashboard. Session work reaches main through a change request. Merge is default-deny for agents. A change to the sourcing profile arrives as a diff: a new exclusion, a tighter seniority band, a different outreach angle. The recruiter's ops lead can review it the way they review a job description.
For sourcing, the boundary between draft and send is the control that protects the employer brand. The agent has no send action and no write access to Greenhouse. Connector credentials are brokered server-side and never enter the machine. A rule that lives in a dashboard screenshot cannot be diffed when someone asks in April why a candidate was skipped.
Three checks before you trust a sourcing agent
The first check is the ATS read. Ask which objects the agent reads before it drafts. That means applicants, contacted candidates, rejected candidates, and people who passed on an earlier round. Read-only access is the right shape for the job. An agent that can write to the pipeline during a sourcing run has more access than the work needs.
The second check is the record of what it skipped. A run that reports eighteen drafts and not the thirteen drops cannot be audited. Neither can the next morning's run. Ask whether the drop reason survives the session, and whether a person can see it beside the batch. The count of skipped candidates is how you tell a careful dedupe from a search that simply returned less.
The third check is whether a person can end the loop. The agent should have no send action, no ATS write, and a review inbox the recruiter actually works. If the tool sends on its own, the duplicate question moves from sourcing to deliverability, where the cost is paid by the candidate and by the next recruiter who emails them.
What it does not replace
Kortix is not a recruiting product, and this sweep does not replace the ATS or the recruiter. The ATS stays the source of truth for the pipeline. The agent reads it, and a person updates it. The sourcing profile still comes from a recruiter who knows the role. On the use-case page, the sourcing profile and outreach angles live as skills and memory, which is why that person can edit the profile without touching the agent's code.
A database-first tool also keeps one advantage a per-role sweep does not have: breadth across a market you have not defined yet. Use that tool to learn a market. Put the recurring job where the dedupe rule and the send boundary are files your team can read and diff. That is the part of a daily sourcing agent that has to survive a year of runs. It is also the part a sourcing demo tends to skip.
The setup, the guardrails and the trigger are on the candidate sourcing use-case page. If you want that job running in a repo you own, try Kortix.