Property management

Reliable voice agents look more like code than conversations.

A maintenance request and a work-order status call share most of their skeleton
— verify the resident, read the unit and open WOs from the PMS, log the outcome
— but the middle is completely different. One captures the issue and triages emergencies. The other relays the vendor ETA and what to expect.

Below: the thesis, the primitives, and how the same agent fabric handles both.

5 min read · concrete example included
The thesis

A reliable voice agent is composed, not prompted.

ElevenLabs, Vapi, Bland start from one capable agent you steer with a prompt, then add workflows and tools on top. We start from the other end — a library of small, specialized sub-agents that compose into the call.

An orchestrator picks the right ones for each role. Cross-cutting listeners run across the whole call to score things like communication skill.

Workflow
orchestrator picks
sub-agent
verify_identity
Greets the resident by name, confirms they’re an authorized occupant, confirms the unit. Catches the common case where a guest, family member, or unauthorized roommate is calling about a unit they don’t live in.
Build
/speakgreeting
"Hi, you've reached the maintenance line for {property_name}. Am I speaking with {resident_name} in unit {unit_number}?"
/conditional_collectoccupancy_check
If caller name not in authorized_occupants: "Are you a resident on the lease, or are you calling on behalf of someone here?"
Transcript
Agent
"Hi, you've reached the maintenance line for Riverbend Apartments. Am I speaking with Priya in unit 312?"
Resident
"Yes, this is Priya."
silent
Authorized occupant confirmed · safe to take the request
Agent
"Hi Priya, this is Feliciti calling from Riverbend Apartments maintenance about your dishwasher work order. Is now a good time for a quick update?"
Resident
"Yeah, go ahead."
→ if not an authorized occupant, route to request_callback. Property manager decides what to disclose.
Plus a global listener for communication skill, scoring across the entire call.
The primitives

Nine primitives. Compose them. Ship reliable agents.

Voice agents in Feliciti are built like Notion documents — slash commands compose into blocks, blocks compose into sub-agents, sub-agents compose into the full call flow.

Nine primitives are all you need — one runs before the call connects, the rest run during.

  • /pre-call

    Read state before speaking.

    Match the customer, fetch their record, load context — all before the first hello.

  • /speak

    Speak a turn.

    One bounded utterance. Variables interpolate, tone is set per sub-agent.

  • /collect

    Ask and capture an answer.

    A scripted question that records a typed value back into the call state.

  • /conditional_collect

    Branch on a prior value.

    Asks only if a condition holds. The branch is explicit, not a prompt heuristic.

  • /set

    Write to a system of record.

    Commit a value to the DMS, ATS, or TMS. Triggers fire on side-effects.

  • /end

    Close the call.

    Wrap up cleanly with a final line and end the session.

  • /transfer

    Hand off to a human.

    Warm-transfer to the right queue or advisor when escalation is needed.

  • /prompt

    Free-form generation.

    When a step needs a small LLM call — kept narrow, kept testable.

  • /condition

    Route between sub-agents.

    The orchestrator's decision point — composition, not a chain of prompts.

composition

Stack the primitives into a sub-agent.

A sub-agent is a named, reusable unit — a linear sequence of these primitives. Tested in isolation against its own scenarios. Composed with other sub-agents to form the full call flow.

Compared to

What composition gives you that general-purpose platforms don't.

ElevenLabs, Vapi, and Bland are excellent general-purpose voice platforms — they have workflows, branching, and tool-calling. The difference is what you assemble yourself versus what comes built for the work.

General-purpose voice platforms

ElevenLabs, Vapi, Bland

  • Workflows layer on top of a base agent. Composition is a feature you configure, not the unit you build from.
  • Integrations are yours to wire and maintain — the PMS connection, the vendor dispatch API, the SMS gateway, the auth, the retries.
  • Test coverage is on you. Emergency triage is a prompt instruction, not a sub-agent with its own latency budget and test suite.
Composable sub-agents

Feliciti

  • The sub-agent is the unit. You compose from small, named, reusable pieces — edits are local, downstream effects explicit.
  • In-house iPaaS: Yardi, AppFolio, Buildium, RealPage, vendor dispatch, lockbox vendors, and telephony are built and maintained for you, not left as an exercise.
  • One-click test-suite generation. Capture a maintenance request? It writes that suite. Catch an emergency before the call goes anywhere else? That one too.
Send us your use case

Want this for your calls?

Tell us the call you want to automate — recruiting or otherwise. We'll send back a working prototype within 48 hours, wired to your actual use case. Same composition pattern you just read about.

A founder reads every one. No sales calls unless you ask.