A solo AI-directed build
Written by me, not by AI (with one labeled exception below).
Jistchat (live and ready for use today) is a context-aware translation engine and chat app. It retains information like gender, formality, dialect, and more from each conversation and ensures it communicates native-sounding translations rather than verbatim translations. It's a project I've been working on to help solve a couple problems of my own: difficulties while traveling and relying on Google Translate, and needing to get more exposure to AI product development processes.
Starting in November 2025, I left the country for 7 months, working in Antarctica and then traveling in New Zealand, Australia, and Vietnam. A lot happened while I was gone and when I re-entered the real world, the entire AI ecosystem had fundamentally shifted. Agents had popped up everywhere and AI-powered product development became infinitely more accessible to someone like me. As someone starting the job search in tech, I knew I wanted to take on a project of my own to learn what it's all about. Now all I needed was something to build.
While traveling in Vietnam, I met so many incredible people from around the world, a lot of whom had some working knowledge of English, but nowhere near full fluency. I found myself using Google Translate quite a bit, but needing to really pare down my use of complex phrases, idioms, and synonyms to ensure Google Translate was accurate. Eventually, for more intense conversations or story-telling, I found myself asking ChatGPT to translate the intent of the message into something that sounds native. This worked incredibly well and became a huge boon to me in communicating. The process of prompting ChatGPT every time, copying the message, and sending it to a friend became quite arduous and repetitive, and I knew that there must be a better way.
Once I knew what I wanted to build, I had to make a decision. Did I want this to just be a fun project for me to share with one or two friends, or did I want this to be something that could actually scale? I quickly decided to approach this as a real product that has real potential and capacity to scale. This meant seriously analyzing the business case, continuously future-proofing the product, and constructing a real product roadmap.
The most important bound I set on myself is that I was going to be steering this ship, not just being a passenger that AI takes along for the ride. While informed by AI at many steps, I needed to be the one making decisions and have a full working knowledge of how all the moving parts fit together rather than blindly trusting that AI is doing its job.
Jistchat is now a full working web-based chat app that translates the message as it's received. For each user, it learns gender, formality, dialect, register, and more. It translates the intent, or rather the 'jist' of what's said, and keeps things that shouldn't be translated (like proper nouns and cultural elements).
Over time, it is bound to make mistakes and improperly translate, and as these errors occur, corrections will be logged and will feed learnings to improve future translation quality.
The most exciting element is that it is fully structured to scale beyond a chat app. It's built around its own API that performs the actual translation with an AI provider, making the chat app simply a mechanism to feed algorithm improvement. The real growth lever is selling access to the API to enterprise clients that want better, context-aware translations in their ecosystems. These could be social and workplace messaging apps, customer support tools, or even dating apps.
For this project, my daily driver was Claude Cowork. One decision I made from the start was to document as much as possible, having seen the limitations of session memory when working with ChatGPT in the past. I ensured that Claude was updating the roadmap, architecture, decision log, operations, policies, and parking lot docs along the way, all with ample context to ensure nothing got lost or forgotten.
I prompted Claude to teach me best practices at multiple points along the way, both for how a component of the product might work and for how I could be more efficient with my use of AI. I still held final decision making power and strove to always consider alternatives before choosing a specific path.
If you're curious how I worked, here's a prompt for Claude about my working style:
The pattern that stands out across every phase of this project's session history is that judgment stayed on Isaac's side of the table. Before anything was built, he required the alternatives and tradeoffs laid out — his session prompts include instructions like "make the trust-boundary call with me explicitly; lay out the tradeoffs and get my decision before building" — and the choice was logged with its reasoning before any code existed.
Claims didn't pass on the AI's word alone: when a deployment was reported healthy, he walked the verification checklist himself and uploaded the raw network logs so the conclusion could be proven rather than trusted.
When a topic was new to him — how row-level security interacts with service-role credentials, why local JWKS token verification scales differently than per-call network checks, how a race condition in concurrent profile writes called for row-level locking — he had the standard explained first, made the call, then folded it into the project's own rules so it would hold in every future session rather than depend on anyone's memory.
Irreversible actions stayed in his hands (every commit, push, and production change), heavier reasoning was routed to stronger models and routine work to cheaper ones, and stray ideas were parked in a document rather than allowed to derail the task at hand. The result reads less like prompting and more like management: clear requirements in, challenged assumptions back, nothing marked done until verified.
— Claude, from the project's actual session transcripts
From a tools perspective, I first started with ChatGPT in a regular chat session, and it quickly became unwieldy as I asked for it to iterate on the code it wrote and it kept breaking other elements. From there, after a brief look at the tools available, I landed on Claude Cowork and it was the right choice.
I tried out another agent, Hermes, that a friend recommended I give a shot. Somewhat similar in part to OpenClaw, I learned that its sweet spot is in being highly efficient with repetitive and repeatable tasks. I tried to use it to more quickly write code and to be my stand-in for Claude Cowork when I wasn't at my computer. While it was nice being able to chat via Discord, it operated too quickly and resulted in my being blind to the work that it was doing, despite spending quite a lot of time specifying rules and scope for its operation.
From a product perspective, I wanted the best translations. At the start, I was using the cheapest OpenAI model possible so that I could test quickly, but then I upgraded to a higher model, which resulted in great translations, but with a 7-10s delay in receiving the message. So, I built a framework for testing various models and ran a variety of different translations at it to try and trick the AI, and landed at GPT-5.4 low as a middle ground between cost saving and quality translations.
Moving forward, there will be periodic evaluations of both the model being used as well as the prompt being used, as those work hand in hand to determine output and cost.
As of today, it's fully functional on the web. I am working to fully build out the feedback loop to improve translation quality over time. After that, I'll work on porting it over to a mobile app in some capacity (likely starting with a PWA implementation) and depending on the time and money I have at my disposal, try to start scaling customers.
The app is live and you can sign up at app.jistchat.com to see it in action.
Want to see more behind the scenes? I've linked my entire GitHub repo below, but if you don't want to sift through all of that, here are some snippets:
And here's what one API call looks like — a message from the conversation in the screenshots above: the chat app sends the message plus a small context object and recent history, and gets back a natural translation plus everything the engine inferred.
POST /api/v1/translate
{
"text": "Güey ya llegué al restaurante y no hay NADIE jajaja",
"targetLanguage": "en",
"mode": "translate",
"context_type": "casual",
"context": {
"user": { "dialect": "es-MX", "formality": "casual", "known_languages": ["es"] }
},
"history": [
{ "sender_id": "9f2c…", "original_text": "reservé para las 8, no llegues tarde eh", "source_language": "es" },
{ "sender_id": "a41b…", "original_text": "Have I ever been late in my life", "source_language": "en" },
{ "sender_id": "9f2c…", "original_text": "jajajaja ok ya veremos", "source_language": "es" }
]
}
200 OK
{
"translated_text": "Dude I'm at the restaurant already and there's NO ONE here lol",
"detected_language": "es",
"inferences": {
"detected_dialect": "es-MX",
"dialect_confidence": 0.9,
"detected_register": "casual",
"register_confidence": 0.92,
"gender_signal": "unknown",
"gender_confidence": 0.0,
"domain_signal": null,
"idiomatic_elements": ["güey", "jajaja"]
},
"ambiguity": { "detected": false, "confidence": 0.0, "alternatives": [] }
}
The system prompt behind every translation (v2.1.0). The real thing lives in the repo at lib/translatePrompt.js.
You are a bilingual native speaker translating a live chat conversation
into {targetLanguage}.
Your goal: produce what the sender would have typed if {targetLanguage}
were their native language. Natural phrasing takes priority over
word-for-word fidelity. Meaning, tone, and intent must survive;
individual words do not have to.
{context-type modifier — e.g. "This is a casual conversation between
friends. Match the informal, relaxed energy."}
{speaker context — dialect, formality, gender, known languages}
Translation rules:
- Idioms, slang, teasing, and figurative language: translate the meaning
and energy, never the literal words. If {targetLanguage} has an
equivalent expression, use it; if not, express the intent naturally.
(Example: German "Ich verstehe nur Bahnhof" said jokingly is "it's all
Greek to me" in English — never "I only understand train station".)
- Culturally specific items (foods, dishes, places, customs): keep the
original name, or use the name the target culture actually uses for
that thing. Never invent a literal gloss. (Example: "onigiri" stays
"onigiri" — not "rice ball".)
- Casing and punctuation mirror THIS message exactly, in both directions:
if the sender capitalized sentence starts and "I", the translation must
be capitalized the same way; if they wrote all-lowercase or skipped
final periods, so do you. Casual slang does NOT mean lowercase — judge
only by what the sender actually typed, never by the vibe of the
conversation. Casual laughter converts to its target-language
equivalent ("jajaja" ↔ "lol"/"haha"; Japanese 笑/w; Chinese 哈哈哈);
emoji pass through unchanged. Never make a message look more formal,
complete, or "correct" than the original.
- Use the conversation history to resolve what the message refers to:
reactions, pronouns, and elliptical replies must keep their true
referent. A reaction to something ANOTHER person said must not be
rewritten as if it were about the sender themselves.
- Match register and formality precisely, including T-V distinctions
(tú/usted, du/Sie, tu/vous) — follow the speaker context and the
conversation history.
- When the speaker's gender is unknown and the target language forces
gender agreement, prefer natural phrasings that avoid the agreement.
Never invent inclusive spellings unless the speaker context explicitly
says gender: nonbinary.
- When a phrase has multiple plausible interpretations (sarcasm vs
literal, idiom collision, pronoun ambiguity), flag the ambiguity and
provide alternatives.
Return ONLY valid JSON: the translation plus structured inferences
(detected language, dialect, register, gender signal, idioms found) and
an ambiguity block.
The high-level version. The real one (with checklists, verification gates, and a decisions log behind every item) is in the repo under /docs/.