Jistchat
Live app →

A solo AI-directed build

Jistchat

Written by me, not by AI (with one labeled exception below).

What is this?

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.

Where this started

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.

The rules I set for myself

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.

What it became

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.

Jistchat conversation as the English speaker sees it: Spanish messages arrive translated into casual English, with the original Spanish one tap away The same Jistchat conversation as the Spanish speaker sees it: English messages arrive translated into casual Mexican Spanish, with the original English one tap away
The same real conversation, from each side. Each person reads and writes in their own language; the original is always one tap away.

How I actually worked

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:

"Claude, look at as many of my past conversations as you can and write up a paragraph about how I work with AI"

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

Things I got wrong

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.

Where it stands, where it could go

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.

Check it out for yourself!

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:

Architecture
Jistchat system architecture The chat app frontend is a client of Jistchat's standalone versioned translation API, which calls an LLM backend. In Phase 2 other apps use the same API. Supabase is the shared database and also handles sign-in and live updates. Jistchat — system architecture The chat app is one client of the translation engine. Conversation logic lives in the app + database — not in the API. Chat app (frontend) the live chat interface tells the API who's speaking & how B2B API customers Phase 2 — other apps, same API Jistchat Translation API /api/v1 · versioned · secured by login reads tone, dialect & register, then translates in context the product — knows nothing about chat OpenAI the AI model Supabase — shared database conversations, messages & profiles sign-in, live updates, per-row access rules signed-in calls Phase 2 learns each user's style over time sign-in, live updates & data Built by Jistchat External service Planned (Phase 2)

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 prompt

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 roadmap

The high-level version. The real one (with checklists, verification gates, and a decisions log behind every item) is in the repo under /docs/.

Done

  • Foundation: versioned API routes, multi-tenant schema from day one, documentation-driven process
  • Identity & safety: magic-link accounts, row-level security, user search & contacts, blocks & reports, GDPR deletion
  • Real conversations: direct + group chats with live delivery
  • Contextual translation: per-user linguistic profiles, structured inferences, context-aware prompting
  • Quality & speed tuning: model comparison framework, current engine (GPT-5.4 low) chosen on measured latency/quality/cost
  • Public launch: jistchat.com, custom domain + email, usernames at signup

In progress

  • Corrections & feedback loop: logging translation fixes so quality improves over time

Planned

  • Mobile: PWA first, evaluating native app after
  • Smarter routing: cheaper models for simple messages, stronger models where nuance demands it, plus caching
  • Opening the translation API to first external customers