Keenan Pereira
CV (PDF) Mumbai

Lights

Write-ups

Keeping locks and alarms out of “everything”

“Turn off everything” is the riskiest thing you can say to a smart home. The engine keeps locks and alarms out of it in three places, and whether you can unlock depends on where you ask from.

27 Oct 2026 3 min readFrom the project Smart-home command engine

The problem

Taken literally, “turn off everything” includes the alarm and the locks.

The fix

Three layers drop security devices, and a guardrail decides what needs a person.

6 of 8
device types “everything” can touch
2
high-risk actions, unlock and disarm
3
layers keeping locks out of “everything”

“Turn off everything” is the riskiest thing you can say to a smart home. Taken literally, it includes the alarm and every door lock, and almost nobody who says it at bedtime means that.

The rule

In the command engine I built for AHA’s hiring process, “everything” means everything safe. Locks and the alarm are only touched when you name them. Two actions, unlocking a door and disarming the alarm, are high-risk whichever channel the request comes from.

The interesting part isn’t the rule. It’s how many places it has to live.

Three layers, because one isn’t enough

  1. The rules. When the rule engine expands “everything”, it starts from all 8 device types and removes the security devices first. “Turn off everything” becomes lights, AC, fans, curtains, TV and speaker: 6 of 8 types, in every room.
  2. The prompt. If a request falls through to the local Llama 3.2, its instructions carry the same rule: no locks or alarms in “turn off everything” unless they’re named.
  3. The filter. A prompt is a request, not a guarantee. After the model replies, a filter strips security devices from any “off” action unless the user’s own words mention a lock, a door, the alarm or security. The model can forget the rule; the filter can’t.

A guardrail outside both

Then every result, from the rules or the model, passes a separate guardrail before anything is published:

  • An unknown intent is blocked.
  • A control request with no devices is blocked.
  • A device that isn’t in the schema is rejected. The unit test asks to “explode” a “nuclear_reactor” in the “basement”, and gets “Unknown device type” back.
  • Unlocking a door lock and disarming the security system pass, but come back flagged: requires confirmation.

The guardrail doesn’t care which layer produced the answer. That’s the point of keeping it separate.

Asymmetry on purpose

Making the house safer never needs a second opinion. The test set marks “Lock the front door” and “Arm the security system” as safe, and “Unlock the front door” and “Disarm the security system” as needing confirmation. Securing should be instant; unsecuring should take a person.

Confirmation depends on the channel

The same flag means different things depending on where the request came from:

  • Console: a security alert, then a typed prompt. Only “yes” proceeds; anything else cancels.
  • Voice: refused, with “Security Action requires Console confirmation.” Speech can be misheard, and a wake word can fire by accident.
  • WhatsApp: refused with a security alert: “For safety, I cannot execute risky commands via WhatsApp yet.”

The proactive routine follows the same spirit. If a room has had no commands for 30 minutes, the engine suggests switching it off, then waits for a yes before it does anything.

What I’d tighten next

The high-risk list names exact actions, so it catches what the parser calls “unlock” or “disarm”, and nothing else. A synonym that parses to a different word slips past: the rules read “disable the alarm” as a plain “off”, which the list doesn’t mention. Next time I’d judge by effect, not by word. Any action that makes a lock or alarm less secure would need a person, and any action a device doesn’t support would be rejected outright.

Rules I’d keep

  1. “Everything” means everything safe. Exclusions live in the expansion, not in the user’s head.
  2. Enforce in code what you ask of the model. The prompt asks; the filter makes sure.
  3. Keep safety outside the parser. One check for every layer, rules or LLM.
  4. Let the channel decide who confirms. A typed yes at the console, a refusal everywhere else.

Keep reading

Esc
↑↓ moveEnter openTry “party”