Job Application Screener
AI evaluates job applications for fit, routes top candidates to human review, and sends rejections.
aiswitchemail
Source
/**
* Screens job applications. AI evaluates fit, human reviews top candidates.
*/
form job_application {
label: "Job Application"
visibility: public
schema: @json {
{
"type": "object",
"required": ["name", "email", "role", "resume_text"],
"properties": {
"name": { "type": "string", "title": "Full Name" },
"email": { "type": "string", "format": "email", "title": "Email" },
"role": { "type": "string", "title": "Role Applied For" },
"resume_text": { "type": "string", "title": "Resume (paste text)" },
"linkedin_url": { "type": "string", "title": "LinkedIn URL" }
}
}
}
}
workflow screen_application {
label: "Screen Application"
root {
type: code
label: "Extract application"
code: @ts { return context.nodes.root.input }
outputSchema: @json {
{
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" },
"role": { "type": "string" },
"resume_text": { "type": "string" },
"linkedin_url": { "type": "string" }
}
}
}
}
node evaluate {
type: ai
label: "Evaluate candidate"
kind: object
model: "google/gemini-2.5-flash"
prompt: @ts {
const app = context.nodes.root.output
return "Evaluate this candidate for the " + app.role + " role. Score their fit.\n\nName: " + app.name + "\n\nResume:\n" + app.resume_text
}
schema: @json {
{
"type": "object",
"required": ["score", "strengths", "concerns", "recommendation"],
"properties": {
"score": { "type": "number", "minimum": 0, "maximum": 100 },
"strengths": { "type": "array", "items": { "type": "string" } },
"concerns": { "type": "array", "items": { "type": "string" } },
"recommendation": { "type": "string", "enum": ["advance", "maybe", "pass"] }
}
}
}
}
node route {
type: switch
label: "Route by recommendation"
cases: ["advance", "maybe", "pass"]
router: @ts {
return context.nodes.evaluate.output.recommendation
}
}
node prepare_review {
type: code
label: "Human review"
code: @ts { return {} }
review: {
enabled: true
title: "Review candidate"
description: "Decide whether to advance this candidate to interview. See the evaluate node output for the AI screening summary. Submit your decision; rejected candidates are notified automatically."
schema: @json {
{
"type": "object",
"required": ["decision"],
"properties": {
"decision": { "type": "string", "enum": ["interview", "reject"], "title": "Decision" },
"notes": { "type": "string", "title": "Notes" }
}
}
}
actions: [
{ id: "submit", label: "Submit Decision", outcome: "approve" }
]
}
}
node review_decision {
type: switch
label: "Route on review decision"
cases: ["interview", "reject"]
router: @ts {
const review = context.reviews.prepare_review || {}
return review.decision === "interview" ? "interview" : "reject"
}
}
node schedule_interview {
type: code
label: "Schedule interview"
code: @ts {
const review = context.reviews.prepare_review || {}
return {
status: "interview",
name: context.nodes.root.output.name,
email: context.nodes.root.output.email,
role: context.nodes.root.output.role,
score: context.nodes.evaluate.output.score,
reviewer_notes: review.notes || ""
}
}
}
node review_rejection {
type: email
label: "Send rejection after review"
from: @ts { return "[email protected]" }
to: @ts { return context.nodes.root.output.email }
subject: @ts { return "Update on your application for " + context.nodes.root.output.role }
text: @ts {
return "Hi " + context.nodes.root.output.name + ",\n\nThank you for applying. After careful review, we have decided to move forward with other candidates. We appreciate your interest and wish you the best."
}
}
node send_rejection {
type: email
label: "Send rejection"
from: @ts { return "[email protected]" }
to: @ts { return context.nodes.root.output.email }
subject: @ts { return "Update on your application for " + context.nodes.root.output.role }
text: @ts {
return "Hi " + context.nodes.root.output.name + ",\n\nThank you for applying. After careful review, we have decided to move forward with other candidates. We appreciate your interest and wish you the best."
}
}
node maybe_pool {
type: code
label: "Add to maybe pool"
code: @ts {
return {
status: "maybe_pool",
name: context.nodes.root.output.name,
email: context.nodes.root.output.email,
role: context.nodes.root.output.role,
score: context.nodes.evaluate.output.score
}
}
}
flow {
root -> evaluate
evaluate -> route
route -["advance"]-> prepare_review
route -["pass"]-> send_rejection
route -["maybe"]-> maybe_pool
prepare_review -> review_decision
review_decision -["interview"]-> schedule_interview
review_decision -["reject"]-> review_rejection
}
}
trigger on_application {
form:job_application -> screen_application
enabled: true
}
Flow
Trigger to workflow
job_applicationform
screen_application
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Workflow nodes
CODE
Code Node
Extract application
AI
AI Node
Evaluate candidate
SWITCH
Switch Node
Route by recommendation
CODE
Code Node
Human review
SWITCH
Switch Node
Route on review decision
CODE
Code Node
Schedule interview
EMAIL
Email Node
Send rejection after review
EMAIL
Email Node
Send rejection
CODE
Code Node
Add to maybe pool
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.