mech.app
Financial

Ask Your Life: How a Personal Finance Agent Turns SQL Queries into Natural Language Risk Alerts

A Coral-based agent translates natural language into cross-source SQL joins, surfacing financial deadlines and spending risks from Gmail, Calendar, and...

Source: dev.to
Ask Your Life: How a Personal Finance Agent Turns SQL Queries into Natural Language Risk Alerts

Most personal finance tools give you dashboards. This one gives you a SQL engine that runs across your Gmail, Google Calendar, and transaction history, then answers questions like “what can cost me money this week?” with joined data and actionable alerts.

Life Risk Radar is a Coral-based agent that treats your life as a queryable database. It translates natural language into SQL, executes cross-source joins, and surfaces risks like expiring free trials, missed return windows, or KYC deadlines that could freeze your bank account. The plumbing is straightforward: Coral provides the schema layer and query execution, Claude handles the natural language to SQL translation, and a priority scoring function ranks the alerts.

The interesting part is not the AI. It’s the orchestration between schema inference, query generation, and result presentation in a domain where wrong answers have real financial consequences.

The schema problem: turning life into tables

Coral’s job is to expose Gmail, Calendar, and transaction data as SQL-queryable tables. The agent doesn’t need to know OAuth flows or API pagination. It just needs a stable schema.

The schema looks like this:

  • emails: subject, sender, body, timestamp, labels
  • calendar_events: title, start_time, end_time, location, attendees
  • transactions: amount, merchant, category, date, card_last_four

Coral maintains these schemas and handles the API calls. The agent sees a unified database. The user asks a question. The agent writes SQL. Coral executes it.

The hard part is schema drift. Gmail labels change. Calendar event structures vary. Transaction categorization is inconsistent. The agent needs to handle missing fields, null values, and ambiguous column names without hallucinating joins.

Query translation: Claude writes SQL, Coral validates it

The agent loop is a three-step cycle:

  1. User query arrives (“what subscriptions renew this week?”)
  2. Claude generates SQL based on the schema and query intent
  3. Coral executes and returns results or throws a schema error

Claude gets a system prompt with the full schema, example queries, and constraints. The constraints matter:

  • No DELETE or UPDATE statements
  • No cross-table joins without explicit foreign keys
  • Date filters must use ISO 8601 format
  • Amount comparisons must handle currency precision

The prompt also includes failure examples. “If you see ‘subscription’ in the subject line, join emails to transactions by matching the merchant name in the body to the transaction merchant field.” This prevents the agent from writing joins that return empty sets.

Here’s a simplified version of the SQL generation flow:

def generate_sql(user_query: str, schema: dict) -> str:
    prompt = f"""
    You are a SQL query generator. The user has access to these tables:
    {json.dumps(schema, indent=2)}
    
    User question: {user_query}
    
    Generate a SQL query that answers the question. Rules:
    - Use explicit JOINs with matching keys
    - Filter by date ranges when time is mentioned
    - Return only the columns needed to answer the question
    - Include evidence columns (email subject, transaction merchant)
    """
    
    response = claude.complete(prompt)
    return extract_sql_from_response(response)

The agent doesn’t execute the SQL directly. It sends it to Coral, which validates the query against the schema, checks for injection risks, and runs it in a sandboxed environment.

Risk detection: temporal logic and threshold rules

The agent doesn’t just return query results. It scores them by financial risk.

Risk scoring uses three signals:

  • Time urgency: days until a deadline (free trial expiration, return window, KYC cutoff)
  • Financial impact: dollar amount at risk (subscription cost, refund value, account freeze)
  • Action complexity: steps required to resolve (one-click cancel vs. multi-step document upload)

The scoring function is a weighted sum:

risk_score = (impact_dollars / 100) + (10 / days_remaining) + (complexity_factor * 2)

A $96/year subscription renewing tomorrow scores higher than a $10/month charge renewing in two weeks. A passport appointment missing a document scores higher than a calendar reminder with no financial consequence.

The agent surfaces the top five risks, each with:

  • Evidence: the email subject, transaction merchant, or calendar event title
  • Deadline: the exact date and time
  • Action: a drafted email, cancellation link, or document upload reminder

State management: no conversation memory, just schema cache

The agent is stateless between queries. It doesn’t remember your last question. It doesn’t build a conversation graph. Every query is independent.

This is a deliberate trade-off. Stateless queries are easier to debug, easier to audit, and harder to exploit. If the agent hallucinates a schema or generates bad SQL, the failure is isolated to one query.

The only state the agent maintains is a schema cache. Coral fetches the schema once per session and caches it in memory. This avoids repeated API calls to Gmail, Calendar, and the transaction provider.

The cache expires after 24 hours or when the user explicitly refreshes it. Schema drift is rare enough that daily refresh is acceptable.

Security boundaries: read-only SQL and scoped OAuth

The agent has three security layers:

  1. Read-only SQL: Coral rejects any query with INSERT, UPDATE, DELETE, or DROP
  2. Scoped OAuth: Gmail and Calendar tokens are scoped to read-only access
  3. Query sandboxing: SQL executes in a Coral-managed sandbox with no access to the underlying database

The agent never sees raw OAuth tokens. Coral handles token refresh and revocation. The agent only sees query results.

The biggest risk is SQL injection through natural language. If a user asks “show me all emails where subject contains ’; DROP TABLE emails; —”, Claude might generate a malicious query. Coral’s query parser strips comments and validates syntax before execution.

Failure modes: schema mismatches and empty joins

Three things broke during development:

1. SQL comments that weren’t comments

Claude sometimes generates SQL with inline comments using --. Coral’s parser treated -- as a comment delimiter and stripped everything after it, breaking multi-line queries. The fix was to escape -- in string literals and validate the full query before stripping comments.

2. Cloudflare 403 on Gmail API calls

Coral’s Gmail connector hit Cloudflare rate limits when fetching large inboxes. The agent was making one API call per email to check for subscription keywords. The fix was to batch email fetches and filter on the server side using Gmail’s search syntax.

3. Joins that returned nothing

The agent generated syntactically valid SQL that joined emails to transactions by merchant name, but the merchant names didn’t match. “Amazon.com” in the email didn’t match “AMZN*MARKETPLACE” in the transaction. The fix was to add a fuzzy matching function to the schema and teach Claude to use it in joins.

Deployment shape: Coral backend, Next.js frontend, Vercel hosting

The stack is:

  • Coral: schema management, query execution, OAuth handling
  • Claude (Sonnet 3.5): natural language to SQL translation
  • Next.js: frontend for query input and result display
  • Vercel: hosting and serverless functions for the agent loop

The agent runs as a Vercel serverless function. The user submits a query through the Next.js frontend. The function calls Claude to generate SQL, sends it to Coral for execution, scores the results, and returns the top risks.

The entire query loop takes 2-4 seconds. Most of the latency is in Claude’s SQL generation (1-2 seconds) and Coral’s API calls to Gmail and Calendar (1-2 seconds).

Trade-offs and alternatives

ApproachProsCons
Coral + Claude SQLUnified schema, deterministic queries, easy to auditRequires schema stability, limited to SQL-compatible sources
LangChain + function callingFlexible tool use, supports non-SQL sourcesHarder to validate, more hallucination risk, complex state management
Zapier-style webhooksNo code, easy setupNo cross-source joins, manual rule creation, limited query flexibility
Custom Python scriptsFull control, no vendor lock-inHigh maintenance, no natural language interface, schema drift requires code changes

Coral’s schema layer is the key trade-off. It constrains the agent to SQL-compatible data sources, but it also makes query validation and result auditing straightforward. If you need to query unstructured data (PDFs, images, voice memos), Coral won’t help. If your data fits in tables, it’s a clean abstraction.

Observability: query logs and error traces

The agent logs every query, the generated SQL, the execution time, and the result count. Logs go to Vercel’s logging backend and are queryable via their CLI.

Error traces include:

  • Schema validation errors: missing tables, unknown columns
  • SQL syntax errors: malformed joins, invalid date formats
  • API errors: OAuth token expiration, rate limits, network timeouts

The agent doesn’t retry failed queries automatically. If a query fails, the user sees the error message and can rephrase the question. This avoids retry loops that burn API quota or generate duplicate alerts.

Technical verdict

Use this approach when:

  • Your data sources have stable, SQL-compatible schemas
  • You need cross-source joins (email + transactions + calendar)
  • Query correctness matters more than query flexibility
  • You want deterministic outputs and easy auditability

Avoid it when:

  • Your data is unstructured (PDFs, images, voice)
  • You need real-time streaming or sub-second latency
  • Your schema changes frequently (daily or weekly)
  • You need complex multi-turn conversations with memory

The Coral + Claude pattern works well for personal finance because the schema is stable, the queries are deterministic, and the cost of a wrong answer is high. If you’re building a general-purpose personal assistant, you’ll need more flexible tooling. If you’re building a financial risk detector, this is a solid starting point.

Tags

agentic-ai orchestration infrastructure

Primary Source

dev.to