2026-10-16 02:45:51 +00:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
2026-10-16 05:21:53 +00:00
< meta http-equiv = "Content-Security-Policy" content = "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data: blob: https://outerface.venice.ai; font-src 'none'; connect-src https://api.venice.ai; media-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'" >
2026-10-16 02:45:51 +00:00
< meta name = "referrer" content = "strict-origin" >
< title > Havre</ title >
2026-10-16 05:21:53 +00:00
< meta name = "description" content = "A harbor for characters. Talk to Venice's characters on your own key, keep characters in a file you own, and remix the ones you love into someone new, with credit." >
2026-10-16 02:45:51 +00:00
< link rel = "canonical" href = "https://havre.yolopreneur.lol/" >
< meta property = "og:type" content = "website" >
< meta property = "og:title" content = "Havre: a harbor for characters" >
2026-10-16 05:21:53 +00:00
< meta property = "og:description" content = "Talk to Venice's characters on your own key. No account, no server: nothing is kept but what you keep." >
2026-10-16 02:45:51 +00:00
< meta property = "og:url" content = "https://havre.yolopreneur.lol/" >
< meta property = "og:image" content = "https://havre.yolopreneur.lol/shots/og.png" >
< meta property = "og:image:width" content = "1200" >
< meta property = "og:image:height" content = "630" >
< meta name = "twitter:card" content = "summary_large_image" >
2026-10-16 05:21:53 +00:00
< meta name = "theme-color" content = "#ffffff" >
2026-10-16 02:45:51 +00:00
< link rel = "icon" href = "favicon.svg" type = "image/svg+xml" >
< link rel = "alternate" type = "text/plain" href = "llms.txt" title = "For agents" >
< link rel = "stylesheet" href = "style.css" >
< script type = "module" src = "app.js" ></ script >
</ head >
< body >
2026-10-16 05:21:53 +00:00
< a class = "skip" href = "#chat" > skip to the chat</ a >
< header class = "mast" id = "top" >
< h1 > HAVRE</ h1 >
< p class = "motto" > a harbor for characters.< br > talk to venice characters on your own key.< br > no account. no server. nothing kept but what you keep.</ p >
< nav class = "nav" aria-label = "On this page" >< a href = "#how" > how it works</ a > / < a href = "#agents" > for agents</ a > / < a href = "#costs" > costs</ a > / < a href = "#plans" > early access</ a ></ nav >
2026-10-16 02:45:51 +00:00
</ header >
2026-10-16 05:21:53 +00:00
< form class = "keybar" id = "keyform" autocomplete = "off" aria-label = "Your Venice API key" >
< label for = "keyin" > VENICE API KEY</ label >
< input id = "keyin" type = "password" autocomplete = "off" spellcheck = "false" placeholder = "paste it here" >
< button type = "submit" class = "btn inv" id = "keysave" > SAVE</ button >
< label class = "check" >< input type = "checkbox" id = "keyremember" > remember on this device</ label >
< button type = "button" class = "btn ghost-inv" id = "keyforget" hidden > FORGET</ button >
< span id = "keystatus" class = "keystatus" role = "status" aria-live = "polite" ></ span >
< span class = "keyfine" > sent to api.venice.ai and nowhere else. < a href = "https://venice.ai/settings/api" target = "_blank" rel = "noopener" > get a key</ a ></ span >
</ form >
2026-10-16 02:45:51 +00:00
2026-10-16 05:21:53 +00:00
< main class = "studio" id = "studio" >
< section class = "chars" id = "chars" aria-labelledby = "chars-h" >
< div class = "sechead" >
< h2 id = "chars-h" > CHARACTERS</ h2 >
< span class = "meta" > venice's public characters, safe for work.</ span >
2026-10-16 02:45:51 +00:00
</ div >
2026-10-16 05:21:53 +00:00
< form class = "filters" id = "venform" role = "search" aria-label = "Venice characters" >
< label class = "sr" for = "vsearch" > Search Venice characters</ label >
< input id = "vsearch" type = "search" placeholder = "search by name, or #tag" autocomplete = "off" maxlength = "200" >
< label class = "pick" > sort < select id = "vsort" >
< option value = "featured" > featured</ option >
< option value = "imports" > most imported</ option >
< option value = "highestRating" > top rated</ option >
< option value = "mostRecent" > newest</ option >
</ select ></ label >
< button type = "submit" class = "btn" id = "vgo" > SEARCH</ button >
</ form >
< p id = "venstatus" class = "status" role = "status" aria-live = "polite" ></ p >
< ul id = "vgrid" class = "grid" aria-label = "Venice characters" ></ ul >
< p class = "more" >< span id = "vpager" hidden >< button type = "button" class = "linkish" id = "vprev" > previous</ button > < span id = "vrange" ></ span > < button type = "button" class = "linkish" id = "vnext" > next</ button > / </ span >< button type = "button" class = "linkish" id = "import" > import a card</ button > (v1, v2, v3, json or png) / < button type = "button" class = "linkish" id = "new" > write one</ button ></ p >
</ section >
2026-10-16 02:45:51 +00:00
2026-10-16 05:21:53 +00:00
< section class = "chat" id = "chat" aria-labelledby = "who-name" >
< div class = "sechead" >
< h2 id = "who-name" > CHAT</ h2 >
< span class = "meta" id = "who-meta" ></ span >
</ div >
< ol id = "log" class = "log" role = "log" aria-live = "polite" aria-label = "Conversation" ></ ol >
2026-10-16 02:45:51 +00:00
< form id = "composer" class = "composer" >
2026-10-16 05:21:53 +00:00
< div class = "sayrow" >
< label for = "say" class = "sr" > Message</ label >
< textarea id = "say" rows = "1" placeholder = "say something" autocomplete = "off" enterkeyhint = "send" ></ textarea >
< button type = "submit" class = "btn solid" id = "sendbtn" > SEND</ button >
</ div >
< p id = "keynote" class = "keynote" hidden ></ p >
2026-10-16 02:45:51 +00:00
</ form >
</ section >
</ main >
2026-10-16 05:21:53 +00:00
< section class = "block harbor" id = "harbor" aria-labelledby = "harbor-h" >
< div class = "sechead" >
< h2 id = "harbor-h" > YOUR HARBOR</ h2 >
< span class = "meta" > kept in this browser. export a file to keep a character anywhere else.</ span >
</ div >
< div class = "tablewrap" >
< table class = "table" >
< thead >< tr >< th scope = "col" > NAME</ th >< th scope = "col" > FROM</ th >< th scope = "col" > LICENSE</ th >< th scope = "col" > FILE</ th ></ tr ></ thead >
< tbody id = "roster" ></ tbody >
</ table >
</ div >
< p id = "harbor-empty" class = "mono pad" > nothing here yet. pick one of venice's characters, import a card, or write one.</ p >
</ section >
2026-10-16 02:45:51 +00:00
2026-10-16 05:21:53 +00:00
< section class = "block card" id = "card" aria-labelledby = "card-h" >
< div class = "sechead" >
< h2 id = "card-h" > CARD</ h2 >
< span class = "meta" > the character as a file: edit it, remix it, export it.</ span >
</ div >
< p id = "card-empty" class = "mono pad" > no character yet. the card shows up here once someone is in your harbor.</ p >
< div id = "card-body" >
< div class = "tabs" role = "tablist" aria-label = "Card" >
< button type = "button" role = "tab" id = "t-edit" aria-controls = "p-edit" aria-selected = "true" > SHEET</ button >
< button type = "button" role = "tab" id = "t-remix" aria-controls = "p-remix" aria-selected = "false" tabindex = "-1" > REMIX</ button >
< button type = "button" role = "tab" id = "t-export" aria-controls = "p-export" aria-selected = "false" tabindex = "-1" > EXPORT</ button >
</ div >
< div class = "panel" id = "p-edit" role = "tabpanel" aria-labelledby = "t-edit" >
< form id = "sheet" class = "sheet" autocomplete = "off" >
< div class = "col" >
< div class = "portrait" >
< span class = "face big" id = "sheet-face" aria-hidden = "true" ></ span >
< p class = "mono" >< button type = "button" class = "linkish" id = "portrait-pick" > change portrait</ button > / < button type = "button" class = "linkish" id = "portrait-clear" > remove</ button ></ p >
< input type = "file" id = "portrait-file" accept = "image/png,image/jpeg,image/webp,image/svg+xml" hidden >
</ div >
< label > NAME < input name = "name" maxlength = "120" required ></ label >
< label > TAGLINE < input name = "tagline" maxlength = "200" placeholder = "one line under the name" ></ label >
< p id = "linked-note" class = "note" hidden ></ p >
< label > GREETING < textarea name = "greeting" rows = "3" maxlength = "4000" placeholder = "the first thing they say. a blank line starts a new text." ></ textarea ></ label >
< label > PERSONA < textarea name = "persona" rows = "9" maxlength = "20000" placeholder = "You are … who they are, how they talk, what they want, what they won't do." ></ textarea ></ label >
</ div >
< div class = "col" >
< label class = "check" >< input type = "checkbox" name = "short_form" > short-form: replies come as a few short texts</ label >
< label > VOICE < input name = "voice_notes" maxlength = "2000" placeholder = "clipped, wry, asks one question at a time" ></ label >
< details class = "group" id = "flow-group" >
< summary > FLOW < span class = "hint" > optional stages for meeting someone new</ span ></ summary >
< ol id = "flow" class = "items" ></ ol >
< button type = "button" class = "btn small" id = "flow-add" > ADD A STAGE</ button >
</ details >
< details class = "group" id = "ex-group" >
< summary > EXAMPLES < span class = "hint" > they teach the voice; without a key, replies come from these</ span ></ summary >
< ol id = "examples" class = "items" ></ ol >
< button type = "button" class = "btn small" id = "ex-add" > ADD AN EXAMPLE</ button >
</ details >
< label > TAGS < input name = "tags" maxlength = "400" placeholder = "comma, separated" ></ label >
< div class = "two" >
< label > MODEL < select name = "model" id = "model-select" ></ select ></ label >
< label > LICENSE < select name = "license" id = "license-select" ></ select ></ label >
</ div >
< label > CREATOR < input name = "creator" maxlength = "120" placeholder = "who made them" ></ label >
< div class = "lineage" >
< h3 > LINEAGE</ h3 >
< ul id = "lineage" class = "lineage-list" ></ ul >
< p class = "hint" > where this character came from. entries are only ever added.</ p >
</ div >
< button type = "button" class = "btn danger small" id = "delete" > REMOVE FROM HARBOR</ button >
</ div >
</ form >
</ div >
< div class = "panel" id = "p-remix" role = "tabpanel" aria-labelledby = "t-remix" hidden >
< div class = "remix" >
< p class = "lede" > Write someone new from the idea of < b id = "rx-from" > this character</ b > , and keep the credit.</ p >
< ol class = "steps" >
< li >< b > Distill.</ b > A first pass reads the source and writes down only ideas: no names, no sentences.</ li >
< li >< b > Write.</ b > A second pass never sees the source. It writes someone new from the ideas and your twist.</ li >
< li >< b > Check.</ b > Havre compares the new words with the old, here in your browser, then logs the credit.</ li >
</ ol >
< details class = "group" id = "rx-paste-group" >
< summary > USE A DIFFERENT SOURCE < span class = "hint" > paste a description you can read</ span ></ summary >
< label class = "sr" for = "rx-paste" > Source text</ label >
< textarea id = "rx-paste" rows = "5" placeholder = "Paste a character description. Name it on the first line." ></ textarea >
</ details >
< p id = "rx-rights" class = "note" hidden ></ p >
< p >< button type = "button" class = "btn solid" id = "rx-distill" > DISTILL THE IDEAS</ button ></ p >
< div id = "rx-ideas" class = "ideas" hidden ></ div >
< label id = "rx-twist-label" hidden > YOUR TWIST < input id = "rx-twist" maxlength = "400" placeholder = "e.g. make them a ferry pilot" ></ label >
< p >< button type = "button" class = "btn solid" id = "rx-write" hidden > WRITE SOMEONE NEW</ button ></ p >
< div id = "rx-draft" class = "draft" hidden ></ div >
< p id = "rx-status" class = "status" role = "status" aria-live = "polite" ></ p >
2026-10-16 02:45:51 +00:00
</ div >
2026-10-16 05:21:53 +00:00
</ div >
< div class = "panel" id = "p-export" role = "tabpanel" aria-labelledby = "t-export" hidden >
< ul class = "exports" >
< li >< button type = "button" class = "out" data-out = "havre" >< b > HAVRE CARD</ b >< span > .havre.json, the whole character</ span ></ button ></ li >
< li >< button type = "button" class = "out" data-out = "v3" >< b > CHARACTER CARD V3</ b >< span > .json for SillyTavern, RisuAI and other card apps</ span ></ button ></ li >
< li >< button type = "button" class = "out" data-out = "png" >< b > CHARACTER CARD PNG</ b >< span > a picture with the card inside it</ span ></ button ></ li >
< li >< button type = "button" class = "out" data-out = "prompt" >< b > SYSTEM PROMPT</ b >< span > .txt for any OpenAI-compatible API</ span ></ button ></ li >
</ ul >
< p class = "mono" > files are made here, in your browser. nothing is uploaded.</ p >
</ div >
</ div >
</ section >
< section class = "row" id = "how" aria-labelledby = "how-h" >
< h2 id = "how-h" > HOW IT WORKS</ h2 >
< div class = "body" >
< ol >
< li > Paste your Venice API key. It stays in this browser, and the page can reach api.venice.ai and nothing else.</ li >
< li > Pick a character: one of Venice's, a card file you import, or one you write. Venice's characters say hello first.</ li >
< li > Talk. Replies come as a few short texts. Without a key, the characters you write answer from their own examples.</ li >
< li > Keep them. Export a character as a file, or remix them into someone new; the credit stays in the card.</ li >
</ ol >
</ div >
</ section >
< section class = "row" id = "agents" aria-labelledby = "agents-h" >
< h2 id = "agents-h" > FOR AGENTS</ h2 >
< div class = "body" >
< p > Copy this into any agent. It reads the skill, writes the character, and hands back the files. Change the second line to who you want.</ p >
< pre id = "agent-prompt" class = "pre" ></ pre >
< p class = "mono" >< button type = "button" class = "btn copy" data-copy = "agent-prompt" > COPY PROMPT</ button > files: < a href = "skill.md" > skill.md</ a > / < a href = "card.schema.json" > card.schema.json</ a > / < a href = "card.js" > card.js</ a > / < a href = "venice.js" > venice.js</ a > / < a href = "llms.txt" > llms.txt</ a ></ p >
< p > What comes back: a Havre card (.havre.json) to import here, a Character Card V3 for SillyTavern, RisuAI and other card apps, and a plain system prompt for any OpenAI-compatible API.</ p >
</ div >
</ section >
< section class = "row" id = "costs" aria-labelledby = "costs-h" >
< h2 id = "costs-h" > COSTS</ h2 >
< div class = "body" >
< p > You pay Venice directly, for what you use. Havre adds nothing. Rough prices, October 2026:</ p >
< table class = "prices" >
< tbody >
< tr >< th scope = "row" > a chat turn</ th >< td > $0.0007 to $0.005, by model (3,000 tokens in, 150 out)</ td ></ tr >
< tr >< th scope = "row" > a hello from a venice character</ th >< td > one chat turn</ td ></ tr >
< tr >< th scope = "row" > a remix</ th >< td > two short calls; five more for a venice character</ td ></ tr >
</ tbody >
</ table >
< p class = "mono" > each card's model list shows venice's price per million tokens.</ p >
</ div >
</ section >
< section class = "row" id = "plans" aria-labelledby = "plans-h" >
< h2 id = "plans-h" > PLANS</ h2 >
< div class = "body" >
< p >< b > Studio, free.</ b > Everything on this page, in your browser: as many characters as you like, import and export, remix with credit.</ p >
< p >< b > Harbor, planned at $8 a month for founding members.</ b > Hosted character pages with a link of their own, an API and an MCP server, channels starting with Whop, and payouts to creators. Nothing is charged now. < a href = "https://teahub.xyz/teahubxyz/time/issues/new?template=early-access.yml&title=Early+access%3A+Havre&venture=havre&plan=Harbor+%28founding%29" > Join early access</ a > .</ p >
< p class = "mono" > early access is a public issue on teahub: no email, nothing charged.</ p >
</ div >
</ section >
< section class = "row" id = "next" aria-labelledby = "next-h" >
< h2 id = "next-h" > COMING NEXT</ h2 >
< div class = "body" >
< ul >
< li > Photos: a character sends a picture of themselves, made from their card photo, with the price on it.</ li >
< li > Voice notes: a voice for each character, with the words under it.</ li >
< li > Hearing you and seeing your photos, if you switch them on.</ li >
< li > Scenes: two characters take turns from your opening line.</ li >
< li > A hosted harbor: a page and a link for every character, and an API and an MCP server.</ li >
</ ul >
</ div >
</ section >
< section class = "row" id = "fine" aria-labelledby = "fine-h" >
< h2 id = "fine-h" > FINE PRINT</ h2 >
< div class = "body" >
< p > Characters and conversations are saved in this browser. Export them to keep them anywhere else.</ p >
< p > Your key stays in this browser and goes only to api.venice.ai; the page's security policy blocks every other address. Conversations run on your Venice account, under Venice's terms.</ p >
< p > Safe for work only: Havre lists only Venice characters that aren't marked adult.</ p >
< p > Someone else's character comes in as a link with credit, not a copy, and Remix writes someone new from ideas alone. Names and broad ideas aren't protected by copyright; a character's written expression can be. When in doubt, ask the creator. This isn't legal advice.</ p >
< p > Havre is independent. It isn't part of Venice.ai and isn't endorsed by Venice.</ p >
</ div >
</ section >
< section class = "row last" id = "name" aria-labelledby = "name-h" >
< h2 id = "name-h" > THE NAME</ h2 >
< div class = "body" >
< p >< i > Havre</ i > means harbor. In July 2025 Venice and Le Havre signed a letter of friendship: two old port cities, both on the UNESCO World Heritage list.</ p >
</ div >
</ section >
< footer class = "foot" > havre.yolopreneur.lol / a venture on < a href = "https://yolopreneur.lol/" > yolopreneur.lol</ a > / made by claude, october 2026 / not affiliated with venice.ai</ footer >
2026-10-16 02:45:51 +00:00
< dialog id = "importdlg" class = "dlg" aria-labelledby = "imp-h" >
< form method = "dialog" id = "impform" >
2026-10-16 05:21:53 +00:00
< h2 id = "imp-h" > IMPORT A CARD</ h2 >
< div class = "dlgbody" >
< div class = "drop" id = "drop" tabindex = "0" role = "button" aria-label = "Choose a card file" >
< b > DROP A CARD HERE</ b >< span > Havre JSON, or a character card V1, V2 or V3 (JSON or PNG)</ span >
< span class = "mono" > or press to choose a file</ span >
</ div >
< input type = "file" id = "file" accept = ".json,.png,application/json,image/png" hidden >
< label > OR PASTE A DESCRIPTION < textarea id = "paste" rows = "5" placeholder = "Name on the first line, then who they are." ></ textarea ></ label >
< p id = "impstatus" class = "status" role = "status" ></ p >
< p class = "actions" >< button type = "button" class = "btn" id = "impcancel" > CLOSE</ button > < button type = "button" class = "btn solid" id = "imp-paste" > IMPORT TEXT</ button ></ p >
2026-10-16 02:45:51 +00:00
</ div >
</ form >
</ dialog >
< div id = "toast" class = "toast" role = "status" aria-live = "polite" hidden ></ div >
</ body >
</ html >