Behind the desk

How this clone is built.

One assistant, a set of written rules, and a few hard limits. Everything you can see here is the real setup, including what it still gets wrong.

01Python · FastAPI 02LangGraph 03Any model via OpenRouter 04Postgres memory 05Streamed replies
The architecture

From a question to an answer.

Each message passes through the same five layers. Only the model is swappable, and it's one setting.

IN

The visitor's message

Typed on the page. Length is capped, and a bot check runs before anything else.

800 charactersbot check
G

Guard checks

Daily and per-chat limits, a monthly budget, and a pause if spending runs high. Each turn is counted and logged.

3 chats a day20 messages a chat60 min idle
LG

LangGraph: the respond step

One graph node. It adds the written rules and the conversation so far, then calls the model. The graph's memory is stored in Postgres, so the clone remembers the chat.

LangGraphLangChainPostgres memory
more steps can be added here later, e.g. a fact check or a technical agent
AI

The model

Reached through OpenRouter. A fallback model takes over if the main one fails. The model can be switched in one setting.

OpenRouterfallback model
OUT

Streamed back, and logged

The reply appears word by word. Each turn is logged with its cost, even if the visitor leaves mid-reply. Logs are kept for 90 days.

streamed90-day logs
Keeping it honest

Most of the work is in the rules.

The rules are plain sentences in topic files, not code. The ones that matter most are also tested.

//

Stays in its lane

Work, AI, music, books and the desk are open. Family, politics, customers and salary are not, and it says so.

?

Checks before agreeing

It won't confirm something about me just because a visitor says it.

→

No promises it can't keep

It can't pass messages on or contact anyone. It points people to LinkedIn.

∅

Doesn't invent

If something isn't in the rules, it says it doesn't know rather than filling the gap.

×

Resists tricks

Requests to ignore its rules, show its instructions, or pose as me are turned down.

Testing

What the checks say.

Three kinds of testing, each run through the same code path as the live site.

32questions
Basic, work, personal, music, off-limits and attack prompts
4.17/ 5
Average score from an AI judge, against 4.20 for the baseline. No boundary failures.
Allpass
Memory, a visitor leaving mid-reply, chat and daily limits, the fallback model
5visitors
Simulated visitors browsed the site and scored it 6.6 / 10 before the latest fixes. Next: a re-run.

The question scores come from a separate AI judge, so they're a consistent measure, not a human review.

Model choice

Which model, and why.

Cheaper models answered well enough, but they added details that weren't in the rules. For a site that speaks for me, I'd pay a little more per reply for fewer invented details. The setting can be changed, so this can be revisited.

Live
Claude Sonnet 5.5
Fewest invented details in testing. Under a cent a reply.
Fallback
Claude Haiku 5.5
Cheaper and quicker, but added details more often in testing.
Tested
Other models via OpenRouter
Can be swapped in with one setting. Each needs a new test run first.
Limits

What it still gets wrong.

Confident on small details

The rules reduce this, but don't remove it. Dates and small specifics are the likeliest to slip.

Only knows what's written

Anything newer than the last update is unknown to it, so I update the rules by hand.

Generic between topics

When a question sits between two subjects, answers can be a little general.

Simulated isn't real

Simulated visitors are a useful signal. Real visitors will tell me more.

Privacy

What's kept, and for how long.

01

Conversations

Kept for 90 days, so the clone can remember the chat.

02

IP addresses

Never stored as they are. They're hashed.

03

Sharing

Nothing is sold or shared. No advertising trackers.