PolicyKit

Overview
PolicyKit is a pre-publication review agent for recruiting teams. It checks each job description against shared company standards and local hiring requirements before it goes live.
Those policies can cover legal obligations, required content, terminology, and structure so every team and role present a clear, consistent picture of your company to candidates.
PolicyKit can identify problems, explains the relevant policy, and proposes edits. The recruiter can accept, reject, or replace each suggestion, and run another review until the posting is ready to publish.
The review flow
A recruiter starts with a job description and some additional details such as hiring locations and employment type. PolicyKit uses this information to select applicable local requirements, then reviews the posting against both those requirements and company-wide publishing standards.
If the agent finds a concern it:
- Highlights the text connected to each finding
- Explains the policy and why the posting does not meet it
- Proposes an edit when it has enough information, or asks the recruiter for more details
- Lets the recruiter accept, reject, or replace the proposed edit
- Checks the revised posting again
The recruiter can publish a posting once PolicyKit clears it. If there are unresolved findings, they can override the agent and publish the posting with a justification (which we store in our database for potential future reinforcement learning)!
Here's what the lifecycle of a review session looks like:
The Admin flow
Administrators can manage company-wide publishing standards and local requirements as policies here
1. Define the rule
An administrator creates a policy with rules and may provide examples of compliant postings and violations. They can also choose to either apply the policy to every posting or limit it by jurisdiction and employment type.
Here we are adding a company-wide policy that ensures all job-postings mention the company's core values:


2. Test it against a posting
Before publishing a policy, the administrator can test it against a sample job posting.
Here we are testing a New York compensation policy that ensures all job postings for roles in New York have a clear compensation range stated:

3. Publish a version
Published policies become part of the policy set used in future reviews.
System architecture
There's three main parts to the system:
- The Next.js web app is the frontend for the recruiter review flow and policy administration
- The FastAPI service is our server which handles requests and interacts with our database (PostgreSQL).
- The Python agent worker(s) claim queued sessions and run the reviews
When a recruiter submits a posting, our frontend makes a request to our server which creates a new session marked as queued in the database. Workers poll the database every second and when they find a queued session, they mark it as investigating and start the agent runtime.
There are two model roles:
- The orchestrator model sees the current state of the session and available tools. It chooses one action at a time.
- The classifier LLM is invoked by the
run_compliance_checktool call. For every batch of applicable policies (4 by default), the system makes a classifier LLM call with those policies supplied, and asked to return an assessment per policy.
Importantly, the orchestrator agent is driven by the available tools we provide it. (The classifiers have no access to tools)
Agent tools
The orchestrator receives a subset of these tools, depending on the current state:
| Tool | Purpose |
|---|---|
ask_recruiter | Asks the recruiter for more information |
set_hiring_locations | Saves a location supplied by the recruiter |
run_compliance_check | Spawns classifier agents (one per batch of 4 policies by default) to check every applicable policy |
read_policy | Loads a specific policy from the database |
propose_revision | Declares an edit to the draft |
finish_with_findings | Ends the review with findings for the recruiter |
complete_session | Available when no violations remain; Python then runs validate_publishable |
The runtime rejects multiple tool calls in one turn, overlapping edits, edits tied to the wrong finding, and changes outside the declared edit set.
Deployment and scaling
PolicyKit can run on one machine as separate processes:
- the Next.js app
- the FastAPI service
- the Python worker(s)
- the PostgreSQL Database
For a small deployment, the worker can also run inside the API process.
We currently handle concurrency with workers polling and claiming queued sessions with a row lock. This prevents two workers from taking the same enqueued session.
However, as this scales, and we support many worker processes, it will make sense to use a dedicated message queue instead!