Sentinel started as a single-user system. Every request was implicitly from me. Every session belonged to user 1. Every message went to the same Signal number.

That had to change. The contact registry was the first step — a proper model for who’s talking, how to reach them, and what they’re allowed to do. Ten phases: schema and store, contact resolver, user_id migration to integer foreign keys, store updates, intake layer wiring, recipient resolution in tool dispatch, unified messaging tools, contact management API, integration tests, and PII boundary verification.

The recipient resolution piece was important. Before, messaging tools had hardcoded destinations. Now the planner says “send to [person]” and the system resolves that to the right channel and address. Same interface whether it’s Signal, Telegram, or email.

The confirmation gate came next. When the router classifies a request as having side effects — sending a message, modifying a file, running a command — it pauses and shows a preview. The user sees what’s about to happen and confirms with “go” or cancels. On Signal and Telegram, the preview renders inline. On the web UI, it’s an approval card.

This was specifically designed for the fast path. The full pipeline already has constraint validation and scanning. But the fast path bypasses the planner, so the confirmation gate is its safety valve — a human checkpoint for anything that changes state.

Together, the contact registry and confirmation gate laid the foundation for multi-user support. The system now knows who’s asking, who to reply to, and when to check before acting.