Skip to content

v1 — Cameron is born

Latest

Choose a tag to compare

@IBJunior IBJunior released this 21 Jul 08:11

Meet Cameron: a personal finance agent you own and run yourself. This is the first release where Cameron stops being a generic chat starter and becomes itself — a named agent with a persona, its own system of record, and finance tools that never touch your money without asking.

Built in public alongside the Agentailor blog — one tagged release per article. v1 is the "Meet Cameron" chapter.

What's new in v1

🧑‍💼 Cameron's identity & hard rules
A pragmatic, numbers-first finance persona — never moralizes about spending. Three rules that never relax:

  1. Never moves money or mutates financial records without explicit human approval.
  2. Every capability — built-in, connector, or future skill — passes the same approval gate.
  3. Your financial data stays on infrastructure you control.

💸 A transaction store you own
Cameron's system of record: a Postgres-backed transaction table (amounts in minor units, expense/income, account, category, source + dedup provenance) plus categories. External sources normalize into it — they're never read live — so every tagged version stays reproducible on seed data.

🛠️ Finance tools (approval-gated where it matters)

  • log_expense — record a transaction (gated: pauses for your approval)
  • query_transactions — list/filter transactions (read-only)
  • describe_finance_schema + run_sql — answer analytical questions (totals, top-N, group-by) via guarded, SELECT-only SQL: static validation plus a real READ ONLY transaction with a statement timeout, always rolled back, row-capped (read-only)
  • list_categories / create_category — manage categories (create is gated)
  • inspect_csv + import_transactions_csv — a two-step CSV import handshake that never streams your rows through the model; the agent proposes a column mapping for approval, and the import runs entirely server-side (import is gated)

📥 Import that fails loud, not silent
Bank/export CSVs (including localized headers) import via an explicit, agent-proposed mapping. If a mapping names a column that isn't in your file, the import errors and writes nothing rather than silently dropping the field. Dates are parsed by a confirmed format — never guessed — and unparseable rows are reported, not quietly stamped with today's date.

🔒 Human-in-the-loop, narrowed to mutations
Reads and MCP tools run without interruption; only mutating tools pause for approve/deny. Approvals are batched and each denial can carry an explanation back to the agent.

Under the hood

  • Agent: LangChain/LangGraph v1 createAgent (prebuilt ReAct) + humanInTheLoopMiddleware
  • Persistence: Postgres via Drizzle behind a repository seam; conversation history via the LangGraph Postgres checkpointer
  • Providers: Anthropic (default), OpenAI, Google
  • Plus everything from the v0 foundation: dynamic MCP tool loading, SSE streaming, multimodal uploads (MinIO/S3), Langfuse observability, OpenAPI docs

Getting started

git clone https://github.com/agentailor/cameron.git
cd cameron
docker compose up -d      # Postgres + MinIO
pnpm install
pnpm db:migrate
pnpm db:seed              # 6 demo categories + a few months of sample transactions
pnpm dev                  # http://localhost:3100

Seeded from the fullstack-langgraph-nextjs-agent starter.

What's next

v2 — Memory: budgets and preferences as long-term memory, plus summarization of aging history.