A comprehensive guide to implementing intelligent AI agents in property management systems with human oversight, safety controls, and per-agency customization. Perfect for real estate agencies managing listings, inquiries, and tenant relationships.
Property management involves repetitive yet sensitive tasks that benefit from automation while requiring human oversight. AI agents can handle the heavy lifting while keeping humans in control of critical decisions.
A complete property management system typically includes these specialized agents working together:
Property management involves legal obligations, financial decisions, and sensitive tenant relationships. HITL ensures AI agents enhance productivity without compromising safety or compliance.
// Rental application workflow with HITL gates
import { createWorkflow, step, hitl } from "@/lib/workflows"
export const rentalApplicationWorkflow = createWorkflow({
id: "rental-application",
steps: [
// Step 1: AI validates application
step({
id: "validate-application",
agent: "application-agent",
action: async (ctx) => {
const { applicant, property } = ctx.trigger.data
// Check completeness
const completeness = await validateDocuments(applicant)
// Run credit check
const creditScore = await runCreditCheck(applicant)
// Calculate affordability
const affordability = calculateAffordability(
applicant.income,
property.rent
)
// Risk assessment
const riskScore = calculateRiskScore({
creditScore,
affordability,
rentalHistory: applicant.rentalHistory,
employment: applicant.employment
})
return {
completeness,
creditScore,
affordability,
riskScore,
recommendation: riskScore < 30 ? "approve" :
riskScore < 60 ? "review" : "reject",
reasoning: generateRecommendationReasoning({
creditScore,
affordability,
riskScore
})
}
}
}),
// Step 2: HUMAN APPROVAL GATE (REQUIRED)
hitl({
id: "application-review",
name: "Review Rental Application",
dependsOn: ["validate-application"],
// What the property manager sees
display: (ctx) => {
const analysis = ctx.steps["validate-application"].output
return {
title: `Application Review: ${ctx.trigger.data.applicant.name}`,
description: "AI has completed initial screening. Please review and make final decision.",
sections: [
{
title: "Property",
fields: {
"Address": ctx.trigger.data.property.address,
"Rent": `$${ctx.trigger.data.property.rent}/month`,
"Available": ctx.trigger.data.property.availableDate
}
},
{
title: "Applicant",
fields: {
"Name": ctx.trigger.data.applicant.name,
"Income": `$${ctx.trigger.data.applicant.income}/year`,
"Credit Score": analysis.creditScore,
"Affordability Ratio": `${(analysis.affordability * 100).toFixed(1)}%`
}
},
{
title: "AI Analysis",
fields: {
"Risk Score": `${analysis.riskScore}/100`,
"Recommendation": analysis.recommendation.toUpperCase(),
"Reasoning": analysis.reasoning
},
highlight: analysis.riskScore > 60 ? "warning" : "success"
}
],
// Show supporting documents
attachments: ctx.trigger.data.applicant.documents
}
},
// Who can approve
approvers: {
roles: ["property-manager", "agency-owner"],
minApprovals: 1
},
// Available actions
actions: [
{
id: "approve",
label: "Approve Application",
type: "approve",
variant: "default",
requiresNote: false
},
{
id: "conditional-approve",
label: "Conditional Approval",
type: "approve",
variant: "secondary",
requiresNote: true,
notePrompt: "What conditions must be met?"
},
{
id: "reject",
label: "Reject Application",
type: "reject",
variant: "destructive",
requiresNote: true,
notePrompt: "Reason for rejection (for internal records)"
},
{
id: "request-info",
label: "Request More Info",
type: "reject",
variant: "outline",
requiresNote: true,
notePrompt: "What additional information is needed?"
}
],
// Compliance & audit
audit: {
required: true,
retentionYears: 7, // Fair Housing compliance
includeAIDecision: true
},
// Timeout handling (applications shouldn't sit forever)
timeout: {
duration: "48h",
action: "escalate",
escalateTo: ["agency-owner"],
notificationMessage: "Application pending review for 48 hours"
},
// Notifications
notifications: {
channels: ["email", "push", "slack"],
onRequest: true,
onReminder: {
after: "8h",
repeat: "12h",
message: "Rental application awaiting your review"
}
}
}),
// Step 3: Process approval
step({
id: "process-approval",
dependsOn: ["application-review"],
condition: (ctx) => ["approve", "conditional-approve"].includes(
ctx.steps["application-review"].output.action
),
action: async (ctx) => {
const { applicant, property } = ctx.trigger.data
const { action, note } = ctx.steps["application-review"].output
// Generate lease document
const lease = await generateLease({
applicant,
property,
conditions: action === "conditional-approve" ? note : undefined
})
// Send approval email
await sendEmail({
to: applicant.email,
subject: "Rental Application Approved",
template: "application-approved",
data: { applicant, property, lease, conditions: note }
})
// Update property status
await updatePropertyStatus(property.id, "leased")
return { leaseId: lease.id, status: "approved" }
}
}),
// Step 4: Handle rejection
step({
id: "process-rejection",
dependsOn: ["application-review"],
condition: (ctx) => ["reject", "request-info"].includes(
ctx.steps["application-review"].output.action
),
action: async (ctx) => {
const { applicant } = ctx.trigger.data
const { action, note } = ctx.steps["application-review"].output
if (action === "request-info") {
// Request additional information
await sendEmail({
to: applicant.email,
subject: "Additional Information Required",
template: "info-request",
data: { applicant, requestedInfo: note }
})
} else {
// Send compliant rejection notice
await sendEmail({
to: applicant.email,
subject: "Rental Application Update",
template: "application-rejected-compliant",
// Note: Rejection reason NOT included per Fair Housing guidelines
data: { applicant }
})
}
return { status: action, notified: true }
}
})
]
})Each real estate agency has unique branding, processes, compliance requirements, and target markets. The RealAroha platform allows complete customization per agency while maintaining centralized infrastructure.
// Agency branding configuration
const agencyBranding = {
id: "agency_abc123",
name: "Premium Properties Ltd",
branding: {
primaryColor: "#1e40af",
secondaryColor: "#10b981",
logo: "https://cdn.agency.com/logo.png",
voice: {
tone: "professional-warm",
formality: "semi-formal",
style: "consultative",
keywords: ["premium", "exclusive", "trusted"]
},
signatures: {
email: "Premium Properties Ltd\n"
+ "Your Trusted Property Partner\n"
+ "REAA License: 2023-1234",
social: "#PremiumProperties #TrustedPartner"
}
},
// These settings apply to all agents in this agency
agentDefaults: {
systemPromptSuffix:
"You represent Premium Properties Ltd. " +
"Maintain our reputation for premium service " +
"and trusted expertise. Always sign communications " +
"with our brand name and license number."
}
}Step-by-step guide to implementing AI agents in your property management system.
Join property management agencies already using AI agents to handle more listings, respond faster to inquiries, and maintain complete human oversight of critical decisions.