A customer assistant that cannot be talked into a price
ElixirPhoenixPostgreSQLpgvectorLive
I replaced LiveChat at Sportsafe UK with an in-house live chat and AI support
assistant. It has answered customers on its own since August 2026 and hands over as
soon as someone asks for a person. Retrieval is PostgreSQL full-text search with
pgvector, so there is no separate search service.
The rule that matters is enforced in code. The assistant never states a price, stock
level, lead time or delivery date from its own knowledge. That check runs before the
model is called, so no prompt can argue it out of the rule. The scope guard's
vocabulary came from ten years of real customer chats, 11,606 conversations, measured both ways, for what it would wrongly refuse as well as what it catches. The AI agent it
replaced got 4 of its 14 refusals wrong, and that was the bar.
An eval suite runs in CI. Its judge model sees the facts the assistant was entitled
to use but not the rules that shaped the reply, and it was checked in both directions
before its scores were trusted, scoring 5 out of 5 for a known-good reply and 1 out of 5 for a known-bad one. It is also my first Elixir project.
An MCP server that proposes and never commits
TypeScriptNext.jsPostgreSQLMCPLive
I built the product and supplier-pricing system behind the shop, covering 4,268
products and kept in sync with WooCommerce, then added an MCP server so Claude can
work with the catalogue directly. Its five tools search products, read one in full,
list what is waiting for review, summarise the catalogue and propose changes.
The write tool cannot write. Every change it is given, whether a cost, a price, a
stock level or a status, becomes a draft that waits in the system's own review
screens for a person to approve. The model does the tedious part, such as finding
every product with no supplier cost, and a person still owns the decision that
reaches a trading shop.
A business platform built by a governed team of agents
GoPostgreSQLReactTypeScriptIn progress
I am designing an operations platform that covers quoting, field service with an
offline engineer app, purchasing, a double-entry ledger with VAT, HR and marketing email. It is one Go application on one PostgreSQL database with a React front end, so every
piece of data has exactly one owner. Before any business code there was a register of
101 problems it has to solve, 29 architecture decision records, and an architecture
map that CI enforces with 23 fitness rules.
It is built by agents I direct, with a principal-engineer agent as technical lead and
specialist agents for backend, frontend, QA, data and operations, each with its own
model and brief. Review is in proportion to risk. Anything touching money, VAT,
permissions, security or a database migration gets a design review before it is
built, then QA, a code review and a fresh verifier, and only I can merge it. The
agents run under a separate account with no keys or secrets, and records from the
most sensitive customer accounts are filtered out before any data reaches an AI tool.
The foundations phase merged 49 pull requests in its first eight days.
One working setup for Claude Code and Codex
BashPowerShellGitClaude CodeCodex
2,241 of my 2,937 commits across 44 repositories carry a Claude co-author line, and
that undercounts, because Codex adds none. Work at that volume needs the discipline
of a team, so I built the setup both agents run inside and keep it in version control, with 1,000 commits since July 2026.
Both CLIs load the same written standards, the same six skills I wrote (about 2,100
lines, from Cloudflare deploys to WordPress builds), the same per-project memory and a
shared worklog, so either one picks up where the other stopped. Every sync ends in a
secret scan that blocks the commit if anything resembling a key is in the repository,
and the settings deny the commands that would make a repository or gist public. A
review by a second model found two ways the sync could lose data, and both are fixed.
The first test I wrote for one of them passed on the broken code, so I ran old and new
against the same fixture until the old one actually failed.
Choosing a model gets measured too. I scored Claude Code running on Z.ai's GLM models across five tasks, three attempts each, with every check proven to fail before it
was trusted. GLM-5.3-Flash passed all 15 attempts for $0.09. The free GLM-4.7-Flash
passed 3 of 5 tasks and produced a false pass that sent me back to fix the check. I
still keep employer and client code off it, because the provider's parent company is
on the US Entity List and where inference actually runs could not be confirmed.