FormView on GitHub
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
Workflow nodes