Use case · Recruiting agent

A recruiting agent that turns a dead candidate database into a live pipeline

Candidate facts, objections, and the small true things from a coffee chat. Written down once by the agent. Re-surfaced the day a title bump, a new availability, or a layoff makes a past applicant placeable again.

The shape of the problem

Want to build a recruiting agent? Here is how, and where the memory part gets hard

Think about the best recruiter you ever worked with. The thing that made her great was not her ATS. It was her head. She would call you out of nowhere and say "you mentioned eight months ago you wanted to move closer to your parents in Lyon, a role just opened in Lyon." She remembered a throwaway line from a coffee chat a year earlier, connected it to a job that did not exist back then, and reached out the day it became real.

Most recruiting software cannot do this. It stores a resume and forgets the human. It keeps a status field and loses the reason someone said no, the offhand comment about wanting remote work, the former manager they admired. Your recruiting agent can be the recruiter who remembers, if it has a memory that holds onto the small true things and notices when the world changes.

Korely is that memory.

How you build it

Everyone has the tools to build the agent. Nobody wants to build the memory

  1. 1

    Wire up the agent brain

    Drop Claude Code or Cursor on top of your ATS and let it read job reqs, parse resumes, and draft outreach. This part is basically solved today, an afternoon of work.

  2. 2

    Give it a place to write down what it learns

    After every interview the agent saves notes as memories, scoped to that candidate: current title, salary expectation, what they are looking for, the offhand comment about wanting remote work, who they interviewed with.

  3. 3

    Let it remember the relationships, not just the rows

    When a candidate mentions a former manager, a tech stack, a company they admire, store those as connected facts so the agent can later ask "who in my pipeline knows Postgres and worked at a fintech" and actually get an answer.

  4. 4

    Make it answer from what is true now

    A candidate said no last spring because the salary was low. Six months later their title changed and they are open again. The agent needs to know the new fact is true and the old one is history, not just average them into mush.

  5. 5

    Re-surface old candidates the day they become placeable

    When a fact about a past applicant flips, a title bump, a new availability, a layoff at their company, the agent should treat that database row as a fresh lead instead of a dead one.

  6. 6

    Now the hard part

    To do steps 2 through 5 well you would need to build a bi-temporal fact store, an entity graph so candidates link to skills and companies, a way to detect when a new note contradicts an old one, and a retrieval layer fast enough to run on every outreach. That is months of infrastructure work, not a weekend.

  7. 7

    The part you skip

    With Korely you skip that entire build. You call korely.add() when the agent learns something and korely.search() when it needs to recall. The bi-temporal facts, the contradiction handling, the recency, and the graph are the product, hosted in the EU, the whole thing a bi-temporal graph-RAG memory layer starting at 19 euro a month.

The shape of the fix

One memory store feeds every write and every read, across time

March, after the interview

A candidate says no

  • Sara: "not open until I get a Staff title"
  • The agent records a candidate-scoped fact

Korely memory

A bi-temporal fact links into the graph

  • Candidate node ties to skills and companies
  • Valid-from and recorded-at timestamps
  • EU-hosted, no LLM on the read path

Months later, a sourcing pass

A fresh lead surfaces

  • Sara is now Staff, the old objection is history
  • search() returns her as placeable in under 50ms

The contradiction, the old objection versus the new title, is resolved by time, not by overwriting. The agent never re-reads the whole history. It asks the memory and gets back what is true about the candidate now.

How Korely fits

The agentic memory layer underneath the recruiting agent

What Korely saves you building is the part that is genuinely hard and genuinely boring. A bi-temporal fact store that tracks both when a fact was true in the real world and when you learned it, two-stage contradiction resolution so a new interview note can correctly supersede an old one without losing the audit trail, an entity graph that links candidates to skills, companies, and people, and a hybrid retrieval layer over FTS, vectors, RRF, and a reranker, Postgres only.

This matters specifically for recruiting because a candidate database is the worst kind of memory problem: it is huge, it changes constantly, most of it is stale, and the value is buried in the few records that just became relevant again. At an equal token budget a reader answers 76 percent of long-horizon memory questions correctly from Korely selected memory versus 42 percent from a same-size recency window, a 34 point gap, reproducible and significance-tested.

Reads come back in under 50 milliseconds with no LLM on the read path, so the agent can check memory on every single outreach without slowing down or running up a bill. And the facts are time-aware, so the agent answers from what is true about a candidate now, not from whatever you happened to write down first. Everything is EU-hosted. Building that yourself is months. Renting it is 19 euro to start.

Show me the code

A minimal write-then-recall flow

recruiting_agent.py python
# ── After the interview: the agent records why Sara said no ─────
from korely_memory import Korely

korely = Korely(api_key="kor_live_...")

# One candidate-scoped fact, written the moment it is learned
korely.add(
    "Sara Conti: current title Backend Engineer. Not open to a "
    "lateral move. Wants a Staff title before switching.",
    agent_id="client-acme-backend-search",
)

# ── Months later: a routine sourcing pass recalls the fact ─────
context = korely.search(
    "candidates who wanted a Staff title before moving",
    agent_id="client-acme-backend-search",
)
# context → Sara Conti, with her stated condition on top.

# The agent drafts warm outreach grounded in what she told you,
# not a cold note that re-reads a static resume row.

The same memory is reachable from any agent, Claude Code, Cursor, n8n, LangGraph, or a plain HTTP client. Scope memories with different agent_id values, one per client, role, or recruiter, so a fintech search never bleeds into a healthcare search.

When a candidate becomes placeable again

The day the fact flips, the dead row turns into a placement

A candidate, Sara, interviews for a senior backend role in March and turns it down. Her note in the agent memory says current title Backend Engineer, not open to a lateral move, wants a Staff title before switching. Eight months later Sara updates her LinkedIn to Staff Engineer, and your agent sees it during a routine sourcing pass. Because the memory is time-aware, the agent does not just see an old "not interested" flag.

It sees that the exact condition Sara named, getting to Staff, has now become true, and that her earlier objection is history, not the current fact. So the agent surfaces Sara as a warm lead the same day, with the outreach already written: "Last spring you said you wanted a Staff title before moving. Congrats on the promotion, the role we talked about is still open and now it is a real step up for you."

A recency-window memory would have either buried that note under eight months of newer activity or answered with the stale "not interested." The time-aware fact is what turns a dead database row into a placement.

timeline.py python
korely.add(
    "Sara Conti: Backend Engineer, wants Staff before moving.",
    agent_id="client-acme-backend-search",
    metadata={"effective_from": "2025-03-12"},
)

# Eight months later, her title changes
korely.add(
    "Sara Conti is now Staff Engineer. Condition met, open again.",
    agent_id="client-acme-backend-search",
    metadata={"effective_from": "2025-11-04"},
)

korely.search("is Sara open?", agent_id="client-acme-backend-search")
# → "Staff Engineer, open" (current). Old objection marked superseded.

# Retrieve the full timeline via the REST API:
# GET /v1/memories/{id}/history  -> every fact with effective_from

Frequently asked

Recruiting agent memory, common questions

My ATS already stores candidate data. Why do I need Korely? +

An ATS stores records. It does not remember the human. It keeps a resume and a status field, but it loses the offhand line from the screening call, the reason someone said no, and the day a past candidate's title changed and made them placeable again. Korely is the memory layer your agent writes those living facts to, scoped per candidate, time-aware, and searchable, so the agent recalls what is true about a person right now instead of re-reading a static row.

How does the agent know a past candidate is open again? +

Because the facts are bi-temporal. When a candidate's title, availability, or company changes, the agent writes the new fact and Korely marks the old one as superseded while keeping it in the timeline. On the next sourcing pass korely.search() returns the candidate with the current truth on top, so a row that was a dead "not interested" six months ago surfaces as a warm lead the day the condition they named comes true. Nothing is overwritten, nothing is lost, the agent just answers from what is true now.

Will checking memory on every candidate slow my pipeline down? +

No. Reads come back in under 50 milliseconds and there is no LLM on the read path, so the agent can hit memory on every outreach, every sourcing pass, and every interview prep without adding latency or running up a model bill. The expensive thinking happens in your agent. The recall is just a fast lookup.

How is this different from just stuffing my candidate notes into the prompt? +

A candidate database is too big and too stale to paste into a context window, and a plain recency window buries the few records that just became relevant under months of noise. We tested this directly: at an equal token budget, a reader answers 76 percent of long-horizon memory questions correctly from Korely selected memory versus 42 percent from a same-size recency window. Korely picks the right facts for the moment instead of the most recent ones.

Can I keep separate memory for different roles, teams, or clients? +

Yes. Scope memories with the agent_id parameter, one per client, per role, or per recruiter, so a fintech search does not bleed into a healthcare search and each client's pipeline stays separate and auditable. The same memory store serves every agent you plug in, whether that is Claude Code, Cursor, an n8n flow, or a plain HTTP call to the REST API.

Where does candidate data live, and can I delete it? +

In a managed Postgres store hosted in the EU, with a vector and graph index, nothing for you to run. Candidate data is sensitive, so export or erase everything for a person with one call when they ask, which keeps you on the right side of a deletion request. You do not build or host any of the memory infrastructure yourself.

Give your recruiting agent a memory that re-surfaces the right candidate

The Python and Node SDKs are live and the Hobby tier is free, so you can sign up, get an API key, and write your first candidate memory in minutes, then move up to 19 euro a month when your pipeline outgrows it.

Looking for a different shape? See the other nine use cases →