Inspiration

AI agents can execute quickly, but important work often reaches a point where only a human can supply the missing judgment. That might be a product tradeoff, an operational alert, a high-impact action, or context that is not available in a database. Chat notifications are easy to miss, and holding one tool request open for the length of a telephone call is fragile.

I built RingMyHuman to give agentic work a direct, controlled voice line to the person responsible for it. The agent can ask one bounded question, the human can answer by phone, and the agent can continue from a structured result.

What it does

RingMyHuman connects an authenticated AI agent to verified, consenting call contacts through MCP. An agent submits a concise request and immediately receives a durable request ID after the work is stored and queued. It then polls meaningful milestones while CALL-E places the call and conducts the conversation.

When the call finishes, RingMyHuman returns an agent-readable decision containing the selected action, a plain-language summary, any operating instructions supplied by the human, the terminal status, and timestamps. No answer, decline, expiration, cancellation, and provider failure remain explicit outcomes instead of being mistaken for approval.

Each account can save multiple verified contacts in priority order. A Ringflow defines which agent or workflow may call, when it should call, the contact sequence, and a daily maximum. Account-wide and per-Ringflow limits prevent an automated loop from creating unbounded calls. New accounts receive 20 free product calls, and phone-verification texts and calls do not consume those credits.

How I built it

I built the public dashboard with Next.js and TypeScript and deployed it through Amazon S3 and CloudFront. Amazon Cognito handles user signup and sign-in. The authenticated dashboard lets a user verify multiple contacts, order fallback recipients, create named Ringflows, control daily call limits, connect an MCP client, and inspect completed handoffs.

The backend is Python on AWS Lambda. DynamoDB stores accounts, contacts, Ringflows, idempotency records, call requests, status milestones, decisions, credit balances, and webhook-delivery state. Amazon SQS separates prompt acknowledgement from the asynchronous telephone lifecycle. The request is not reported as accepted until it has been durably stored and queued.

CALL-E is the telephone runtime. RingMyHuman creates the provider call, reconciles status changes, and maps the final structured result into its durable request model. Because CALL-E webhook deliveries are unsigned, RingMyHuman treats each delivery as a notification and re-fetches the authoritative call state with its API credential. Replay receipts, ownership checks, safe error shapes, cancellation, expiration, retry guidance, and dead-letter queues protect the lifecycle, while outbound customer callbacks are HMAC-signed.

The MCP endpoint exposes health, account, Ringflow, contact, request, cancellation, and status tools. It uses an OAuth authorization flow tied to the RingMyHuman account. Terraform defines the production infrastructure, alarms, permissions, queues, storage, authentication, and delivery resources.

Challenges I ran into

The hardest problem was separating acknowledgement from completion. A telephone call lasts far longer than a normal MCP request, so keeping the original request open was not a compatible design. I changed the protocol to return only after durable persistence and queueing, then made the request ID and polling tools the required lifecycle mechanism.

I also had to make queue delivery and provider updates safe under retries. Duplicate messages, out-of-order events, and ambiguous timeouts cannot create a second call or turn a valid in-progress request into a failure. Idempotency and guarded state transitions became core product behavior rather than optional cleanup.

The contact experience required similar care. A pending secondary phone must remain visibly separate from an already verified primary contact, and a user must always know which number a verification code belongs to. The production flow now preserves pending state, supports resend, masks phone numbers, and promotes a contact into the priority list only after successful verification.

Accomplishments that I am proud of

I deployed a working production product rather than a static demonstration. RingMyHuman has authenticated signup, multiple verified contacts, priority fallback, named Ringflows, account and flow limits, durable MCP requests, CALL-E integration, structured results, activity history, HMAC-signed customer callbacks, expiration, cancellation, credits, and production monitoring.

I also extracted the reusable human-context-handoff pattern into a public Agent Skill. The contribution documents preview-first behavior, bounded questions, durable acknowledgement, terminal-result handling, idempotency, cancellation, data minimization, and the boundary between ordinary context and protected authorization.

What I learned

I learned that a phone call for an autonomous agent is primarily a distributed-systems problem. The useful abstraction is not simply "make a call." It is "accept one bounded handoff exactly once, report honest milestones, and return a result that another agent can safely consume."

I also learned that the human experience and the agent protocol must agree. Verified recipients, visible priority order, call ceilings, plain-language status, and copyable structured results are as important as the provider integration. Safety is strongest when the interface makes the permitted behavior obvious.

What is next for RingMyHuman

Next I will finish the paid credit-purchase journey, add more judge and client compatibility testing, and continue improving the reusable contact and Ringflow management tools exposed through MCP. I also plan to refine quiet-hour controls, delivery reporting, and production analytics without turning an MVP into an unnecessarily large infrastructure project.

Built With

  • call-e
  • cloudfront
  • cloudwatch
  • cognito
  • dynamodb
  • lambda
  • mcp
  • next.js
  • oauth2
  • pkce
  • python
  • react
  • s3
  • sqs
  • terraform
  • webhooks
Share this project:

Updates