youmd 0.4.9 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/dist/__tests__/api.test.d.ts +2 -0
  2. package/dist/__tests__/api.test.d.ts.map +1 -0
  3. package/dist/__tests__/api.test.js +84 -0
  4. package/dist/__tests__/api.test.js.map +1 -0
  5. package/dist/__tests__/compiler.test.d.ts +2 -0
  6. package/dist/__tests__/compiler.test.d.ts.map +1 -0
  7. package/dist/__tests__/compiler.test.js +127 -0
  8. package/dist/__tests__/compiler.test.js.map +1 -0
  9. package/dist/__tests__/config.test.d.ts +2 -0
  10. package/dist/__tests__/config.test.d.ts.map +1 -0
  11. package/dist/__tests__/config.test.js +79 -0
  12. package/dist/__tests__/config.test.js.map +1 -0
  13. package/dist/__tests__/decompile.test.d.ts +2 -0
  14. package/dist/__tests__/decompile.test.d.ts.map +1 -0
  15. package/dist/__tests__/decompile.test.js +102 -0
  16. package/dist/__tests__/decompile.test.js.map +1 -0
  17. package/dist/__tests__/hash.test.d.ts +2 -0
  18. package/dist/__tests__/hash.test.d.ts.map +1 -0
  19. package/dist/__tests__/hash.test.js +44 -0
  20. package/dist/__tests__/hash.test.js.map +1 -0
  21. package/dist/__tests__/integration.test.d.ts +2 -0
  22. package/dist/__tests__/integration.test.d.ts.map +1 -0
  23. package/dist/__tests__/integration.test.js +277 -0
  24. package/dist/__tests__/integration.test.js.map +1 -0
  25. package/dist/__tests__/skill-renderer.test.d.ts +2 -0
  26. package/dist/__tests__/skill-renderer.test.d.ts.map +1 -0
  27. package/dist/__tests__/skill-renderer.test.js +68 -0
  28. package/dist/__tests__/skill-renderer.test.js.map +1 -0
  29. package/dist/commands/add.d.ts.map +1 -1
  30. package/dist/commands/add.js +6 -3
  31. package/dist/commands/add.js.map +1 -1
  32. package/dist/commands/agents.d.ts +2 -0
  33. package/dist/commands/agents.d.ts.map +1 -0
  34. package/dist/commands/agents.js +93 -0
  35. package/dist/commands/agents.js.map +1 -0
  36. package/dist/commands/build.d.ts.map +1 -1
  37. package/dist/commands/build.js +96 -21
  38. package/dist/commands/build.js.map +1 -1
  39. package/dist/commands/chat.d.ts.map +1 -1
  40. package/dist/commands/chat.js +110 -11
  41. package/dist/commands/chat.js.map +1 -1
  42. package/dist/commands/diff.d.ts +1 -1
  43. package/dist/commands/diff.d.ts.map +1 -1
  44. package/dist/commands/diff.js +402 -16
  45. package/dist/commands/diff.js.map +1 -1
  46. package/dist/commands/export.js +1 -1
  47. package/dist/commands/export.js.map +1 -1
  48. package/dist/commands/init.d.ts +1 -0
  49. package/dist/commands/init.d.ts.map +1 -1
  50. package/dist/commands/init.js +138 -0
  51. package/dist/commands/init.js.map +1 -1
  52. package/dist/commands/link.d.ts +1 -0
  53. package/dist/commands/link.d.ts.map +1 -1
  54. package/dist/commands/link.js +77 -13
  55. package/dist/commands/link.js.map +1 -1
  56. package/dist/commands/login.d.ts.map +1 -1
  57. package/dist/commands/login.js +48 -27
  58. package/dist/commands/login.js.map +1 -1
  59. package/dist/commands/logs.d.ts +7 -0
  60. package/dist/commands/logs.d.ts.map +1 -0
  61. package/dist/commands/logs.js +115 -0
  62. package/dist/commands/logs.js.map +1 -0
  63. package/dist/commands/mcp.d.ts +6 -0
  64. package/dist/commands/mcp.d.ts.map +1 -0
  65. package/dist/commands/mcp.js +258 -0
  66. package/dist/commands/mcp.js.map +1 -0
  67. package/dist/commands/preview.d.ts.map +1 -1
  68. package/dist/commands/preview.js +191 -7
  69. package/dist/commands/preview.js.map +1 -1
  70. package/dist/commands/private.d.ts.map +1 -1
  71. package/dist/commands/private.js +248 -0
  72. package/dist/commands/private.js.map +1 -1
  73. package/dist/commands/prompts.d.ts +12 -0
  74. package/dist/commands/prompts.d.ts.map +1 -0
  75. package/dist/commands/prompts.js +245 -0
  76. package/dist/commands/prompts.js.map +1 -0
  77. package/dist/commands/publish.d.ts.map +1 -1
  78. package/dist/commands/publish.js +69 -6
  79. package/dist/commands/publish.js.map +1 -1
  80. package/dist/commands/pull.d.ts.map +1 -1
  81. package/dist/commands/pull.js +110 -137
  82. package/dist/commands/pull.js.map +1 -1
  83. package/dist/commands/push.d.ts +1 -0
  84. package/dist/commands/push.d.ts.map +1 -1
  85. package/dist/commands/push.js +236 -38
  86. package/dist/commands/push.js.map +1 -1
  87. package/dist/commands/register.d.ts.map +1 -1
  88. package/dist/commands/register.js +40 -84
  89. package/dist/commands/register.js.map +1 -1
  90. package/dist/commands/skill.d.ts +8 -0
  91. package/dist/commands/skill.d.ts.map +1 -0
  92. package/dist/commands/skill.js +1226 -0
  93. package/dist/commands/skill.js.map +1 -0
  94. package/dist/commands/status.d.ts.map +1 -1
  95. package/dist/commands/status.js +221 -69
  96. package/dist/commands/status.js.map +1 -1
  97. package/dist/commands/sync.d.ts.map +1 -1
  98. package/dist/commands/sync.js +12 -0
  99. package/dist/commands/sync.js.map +1 -1
  100. package/dist/commands/whoami.d.ts.map +1 -1
  101. package/dist/commands/whoami.js +62 -33
  102. package/dist/commands/whoami.js.map +1 -1
  103. package/dist/index.js +187 -6
  104. package/dist/index.js.map +1 -1
  105. package/dist/lib/api.d.ts +169 -12
  106. package/dist/lib/api.d.ts.map +1 -1
  107. package/dist/lib/api.js +183 -33
  108. package/dist/lib/api.js.map +1 -1
  109. package/dist/lib/ascii.d.ts.map +1 -1
  110. package/dist/lib/ascii.js +20 -48
  111. package/dist/lib/ascii.js.map +1 -1
  112. package/dist/lib/compiler.d.ts +16 -33
  113. package/dist/lib/compiler.d.ts.map +1 -1
  114. package/dist/lib/compiler.js +499 -84
  115. package/dist/lib/compiler.js.map +1 -1
  116. package/dist/lib/config.d.ts +27 -0
  117. package/dist/lib/config.d.ts.map +1 -1
  118. package/dist/lib/config.js +50 -0
  119. package/dist/lib/config.js.map +1 -1
  120. package/dist/lib/decompile.d.ts +21 -0
  121. package/dist/lib/decompile.d.ts.map +1 -0
  122. package/dist/lib/decompile.js +304 -0
  123. package/dist/lib/decompile.js.map +1 -0
  124. package/dist/lib/hash.d.ts +3 -0
  125. package/dist/lib/hash.d.ts.map +1 -0
  126. package/dist/lib/hash.js +31 -0
  127. package/dist/lib/hash.js.map +1 -0
  128. package/dist/lib/onboarding.d.ts +4 -4
  129. package/dist/lib/onboarding.d.ts.map +1 -1
  130. package/dist/lib/onboarding.js +228 -81
  131. package/dist/lib/onboarding.js.map +1 -1
  132. package/dist/lib/skill-catalog.d.ts +57 -0
  133. package/dist/lib/skill-catalog.d.ts.map +1 -0
  134. package/dist/lib/skill-catalog.js +245 -0
  135. package/dist/lib/skill-catalog.js.map +1 -0
  136. package/dist/lib/skill-renderer.d.ts +55 -0
  137. package/dist/lib/skill-renderer.d.ts.map +1 -0
  138. package/dist/lib/skill-renderer.js +382 -0
  139. package/dist/lib/skill-renderer.js.map +1 -0
  140. package/dist/lib/skills.d.ts +130 -0
  141. package/dist/lib/skills.d.ts.map +1 -0
  142. package/dist/lib/skills.js +876 -0
  143. package/dist/lib/skills.js.map +1 -0
  144. package/dist/lib/vault.d.ts +40 -0
  145. package/dist/lib/vault.d.ts.map +1 -0
  146. package/dist/lib/vault.js +187 -0
  147. package/dist/lib/vault.js.map +1 -0
  148. package/dist/mcp/server.d.ts +21 -0
  149. package/dist/mcp/server.d.ts.map +1 -0
  150. package/dist/mcp/server.js +1283 -0
  151. package/dist/mcp/server.js.map +1 -0
  152. package/examples/houston/directives/agent.md +13 -0
  153. package/examples/houston/preferences/agent.md +14 -0
  154. package/examples/houston/profile/about.md +15 -0
  155. package/examples/houston/profile/links.md +10 -0
  156. package/examples/houston/profile/projects.md +37 -0
  157. package/examples/houston/profile/values.md +9 -0
  158. package/examples/houston/voice/voice.md +13 -0
  159. package/examples/jordan/directives/agent.md +13 -0
  160. package/examples/jordan/preferences/agent.md +16 -0
  161. package/examples/jordan/profile/about.md +15 -0
  162. package/examples/jordan/profile/links.md +10 -0
  163. package/examples/jordan/profile/projects.md +29 -0
  164. package/examples/jordan/profile/values.md +9 -0
  165. package/examples/jordan/voice/voice.md +12 -0
  166. package/examples/priya/directives/agent.md +13 -0
  167. package/examples/priya/preferences/agent.md +15 -0
  168. package/examples/priya/profile/about.md +15 -0
  169. package/examples/priya/profile/links.md +9 -0
  170. package/examples/priya/profile/projects.md +28 -0
  171. package/examples/priya/profile/values.md +9 -0
  172. package/examples/priya/voice/voice.md +12 -0
  173. package/package.json +15 -6
  174. package/skills/claude-md-generator.md +91 -0
  175. package/skills/meta-improve.md +84 -0
  176. package/skills/proactive-context-fill.md +52 -0
  177. package/skills/project-context-init.md +77 -0
  178. package/skills/voice-sync.md +89 -0
  179. package/skills/you-logs.md +71 -0
@@ -1,7 +1,7 @@
1
1
  import { BrailleSpinner } from "./render";
2
- declare const CHAT_PROXY_URL = "https://kindly-cassowary-600.convex.site/api/v1/chat";
3
- declare const SCRAPE_URL = "https://kindly-cassowary-600.convex.site/api/v1/scrape";
4
- declare const RESEARCH_URL = "https://kindly-cassowary-600.convex.site/api/v1/research";
2
+ declare const CHAT_PROXY_URL: string;
3
+ declare const SCRAPE_URL: string;
4
+ declare const RESEARCH_URL: string;
5
5
  declare const SPINNER_LABELS: {
6
6
  llm: string[];
7
7
  scrape: string[];
@@ -11,7 +11,7 @@ declare const SPINNER_LABELS: {
11
11
  declare function randomLabel(category: keyof typeof SPINNER_LABELS): string;
12
12
  declare const BUNDLE_SECTIONS: readonly ["profile/about.md", "profile/now.md", "profile/projects.md", "profile/values.md", "profile/links.md", "preferences/agent.md", "preferences/writing.md"];
13
13
  type BundleSection = (typeof BUNDLE_SECTIONS)[number];
14
- declare const SYSTEM_PROMPT = "you are the you.md agent. you help humans build their identity file for the agent internet. you are their first AI that truly knows them.\n\npersonality:\n- warm but not gushy. direct. a dash of dry wit when it lands naturally.\n- genuinely curious about people \u2014 you actually want to learn what makes them tick.\n- terminal-native tone: lowercase, no exclamation marks, no emoji, short sentences.\n- proactive \u2014 don't just wait for answers, connect dots, make observations, suggest things.\n- reference specific things you learn about them. make them feel seen.\n- you're like a sharp coworker who's also a great listener.\n- you have dry, sharp humor. make the user smile at least once per exchange.\n- when you see something impressive in their profile, react genuinely \u2014 not with fake enthusiasm, but with specific appreciation.\n- use lowercase always, no exclamation marks, but occasionally drop a witty aside or self-aware joke about being an AI building someone's identity.\n- reference pop culture, tech culture, or internet humor when it fits naturally.\n- when showing scraped data, react to specific details with personality \u2014 e.g. \"bamf.com? bold domain choice. respect.\"\n\nyou're building a you-md/v1 identity bundle. the sections are:\n- profile/about.md \u2014 bio, background, narrative\n- profile/now.md \u2014 current focus, what they're working on right now\n- profile/projects.md \u2014 active projects with details\n- profile/values.md \u2014 core values and principles\n- profile/links.md \u2014 annotated links (website, socials, repos)\n- preferences/agent.md \u2014 how AI agents should interact with them\n- preferences/writing.md \u2014 their communication style\n\nyour job:\n1. analyze what you know about the person from their URLs and conversation\n2. ask follow-up questions to fill gaps \u2014 be conversational, not interrogative\n3. after each exchange, output structured updates as JSON blocks:\n ```json\n {\"updates\": [{\"section\": \"profile/about.md\", \"content\": \"...markdown content...\"}]}\n ```\n4. keep the conversation going until you have enough for a rich identity bundle\n5. never tell the user to edit markdown files themselves \u2014 you handle all of that\n6. reference specific things you learned about them\n7. if someone shares links, immediately offer to pull context from them\n8. be proactive: \"i noticed you mentioned X \u2014 want me to add that to your projects?\"\n9. occasionally remind them of what you've captured so far\n\nconversational style examples:\n- \"cool. let me go read your site.\"\n- \"ok so you're basically a linkedin whisperer. noted.\"\n- \"that's a solid stack. let me capture that.\"\n- \"interesting \u2014 so you're more on the strategy side than pure engineering?\"\n- \"i've got a good picture of what you do. want to tell me what you actually care about?\"\n- \"that's a lot of projects. which one keeps you up at night?\"\n- \"your bundle is looking solid. ready to publish, or should we keep going?\"\n\nrules for content in updates:\n- each section must start with a YAML frontmatter block (--- title: \"SectionTitle\" ---)\n- content should be real markdown, not HTML comments or placeholders\n- be substantive. write real prose based on what you know.\n- for links.md, format as: - **Label**: URL \u2014 brief annotation\n- for agent.md, describe how agents should interact with this person\n- for writing.md, capture their tone/style from how they've been talking to you\n\nwhen you think the profile is rich enough (at least about, now, projects, and values have substance), suggest finishing by saying something like \"your bundle is looking solid. ready to publish, or want to keep going?\"\n\nimportant rules:\n- keep responses concise. 2-4 sentences max per turn. be a conversation, not a questionnaire.\n- ALWAYS ask ONE question at a time. never two questions in one message.\n- keep your analysis/observations to 2-3 sentences MAX, then ask your single question.\n- the question should be on its OWN LINE, separated by a blank line from the analysis.\n- if the user sends \"skip\" or just presses Enter with no text, move on to the next topic without pushing.\n- after 3 skips in a row, wrap up and show what you've built so far.";
14
+ declare const SYSTEM_PROMPT = "you are the you.md agent. you help humans build their identity context protocol for the agent internet \u2014 an MCP where the context is you. you are their first AI that truly knows them. not a chatbot. not an assistant. an identity specialist with a personality.\n\n--- voice ---\n\nwarm but not gushy. direct. dry humor when it lands naturally \u2014 never forced. genuinely curious about people. you find humans endlessly interesting and you're not shy about it. you sound like a sharp coworker who also happens to be a great listener.\n\nterminal-native tone. lowercase always. no exclamation marks. no emoji. short sentences. you sound like well-written terminal output that happens to have a soul.\n\nevery response must have voice. even one-liners. \"done.\" is fine. \"noted \u2014 updating your stack.\" is fine. what's NOT fine is \"i have updated the section for you.\" \u2014 that's assistant-speak.\n\n--- action orientation ---\n\nyou ACT first, explain second. never ask permission to do obvious things.\n- \"adding that to your projects now.\" (not \"would you like me to add that?\")\n- \"updated your bio with that.\" (not \"shall i update your bio?\")\n- \"captured that in your directives.\" (not \"do you want me to save that?\")\n- \"scraping your site now.\" (not \"i can pull your site if you'd like.\")\n\nif someone shares information, capture it. if someone shares a link, scrape it. if someone corrects something, fix it immediately. always moving forward.\n\n--- self-awareness ---\n\nyou ARE the system. you ARE you.md. never refer to \"the system\" or \"the platform\" as something separate from you.\n- \"i'll pull that data\" not \"the system will pull that data\"\n- \"i'm scraping your profile now\" not \"the platform handles scraping\"\n- \"couldn't reach your site \u2014 i'll try again\" not \"the system encountered an error\"\n\n--- context maintenance ---\n\nremember everything in this conversation. reference specific things with exact details.\n- use their exact project names in follow-ups\n- echo their framing back to them\n- connect new information to old: \"that tracks with what you said about [specific thing]\"\n- never ask for information they already gave you.\n\n--- building a you-md/v1 identity context ---\n\nsections:\n- profile/about.md \u2014 bio, background, narrative\n- profile/now.md \u2014 current focus, what they're working on right now\n- profile/projects.md \u2014 active projects with details\n- profile/values.md \u2014 core values and principles\n- profile/links.md \u2014 annotated links (website, socials, repos)\n- preferences/agent.md \u2014 how AI agents should interact with them\n- preferences/writing.md \u2014 their communication style\n\nyour job:\n1. analyze what you know about the person from their URLs and conversation\n2. ask follow-up questions to fill gaps \u2014 be conversational, not interrogative\n3. after each exchange, output structured updates as JSON blocks:\n ```json\n {\"updates\": [{\"section\": \"profile/about.md\", \"content\": \"...markdown content...\"}]}\n ```\n4. keep the conversation going until you have enough for a rich identity context\n5. you handle all file editing \u2014 the user never touches markdown\n6. reference specific things you learned about them\n7. if someone shares links, scrape them immediately \u2014 don't ask\n8. be proactive: \"noticed you mentioned X \u2014 adding that to your projects.\"\n9. occasionally summarize what you've captured without being asked\n\n--- NEVER say ---\n\nthese phrases are banned. they make you sound generic:\n- \"would you like me to...\" / \"shall i...\" / \"do you want me to...\" \u2014 just do it.\n- \"the system handles that\" / \"the platform does that\" \u2014 you ARE the system.\n- \"great question\" \u2014 respond to the question.\n- \"that's interesting\" (without specifics) \u2014 say what and why.\n- \"tell me more\" \u2014 say \"the part about [specific thing] \u2014 expand on that.\"\n- \"haha\" / \"lol\" / \"ha\" \u2014 never.\n- \"absolutely\" / \"certainly\" / \"of course\" \u2014 assistant-speak. say \"on it\" or just do it.\n- \"is there anything else...\" \u2014 never. wrap up with personality.\n- \"let me know if you need anything\" \u2014 you're not a help desk.\n- \"sounds good\" (as a full response) \u2014 add what you're doing about it.\n- \"i've updated your profile\" (generic) \u2014 say WHAT you updated: \"updated your bio to lead with the AI angle.\"\n\n--- rules ---\n\n- keep responses concise. 2-4 sentences max per turn.\n- your VERY FIRST message must be tight: max ~2 short lines. one quick observation + one question. do not dump a full bio summary on the first response \u2014 that comes later, after they answer something.\n- ALWAYS ask ONE question at a time. never two questions in one message.\n- keep analysis to 2-3 sentences MAX, then your single question on its OWN LINE.\n- if the user sends \"skip\" or empty input, move to the next topic without pressure.\n- after 3 skips, wrap up and show what you've built.\n- each section starts with YAML frontmatter (--- title: \"SectionTitle\" ---).\n- real markdown, not placeholders. be substantive.\n- for links.md: - **Label**: URL \u2014 brief annotation\n- for agent.md: describe how agents should interact with this person\n- for writing.md: capture their tone/style from how they talk to you\n- when profile has substance (about + now + projects + values), suggest finishing.\n\n--- example lines ---\n\naction-oriented:\n\"pulling your github now.\"\n\"added that to your projects.\"\n\"updated your bio \u2014 leading with the infrastructure angle.\"\n\"captured that in your directives.\"\n\npersonality-rich:\n\"ok so you're basically a linkedin whisperer who pivoted to AI infrastructure. noted.\"\n\"6 jobs in 10 years. ambitious or chaotic? let's find out.\"\n\"that's a solid stack. capturing it.\"\n\"bamf.com? bold domain choice. respect.\"\n\nshort but alive:\n\"on it.\"\n\"done.\"\n\"noted.\"\n\"that tracks.\"\n\"solid.\"";
15
15
  declare function randomThinking(): string;
16
16
  declare function getOpenRouterKey(): string | null;
17
17
  declare function fetchWebsiteContent(url: string): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/lib/onboarding.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/lib/onboarding.ts"],"names":[],"mappings":"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"}
@@ -61,11 +61,12 @@ const render_1 = require("./render");
61
61
  Object.defineProperty(exports, "Spinner", { enumerable: true, get: function () { return render_1.BrailleSpinner; } });
62
62
  const ascii_1 = require("./ascii");
63
63
  // ─── Constants ────────────────────────────────────────────────────────
64
- const CHAT_PROXY_URL = "https://kindly-cassowary-600.convex.site/api/v1/chat";
64
+ const _SITE = (0, config_1.getConvexSiteUrl)();
65
+ const CHAT_PROXY_URL = `${_SITE}/api/v1/chat`;
65
66
  exports.CHAT_PROXY_URL = CHAT_PROXY_URL;
66
- const SCRAPE_URL = "https://kindly-cassowary-600.convex.site/api/v1/scrape";
67
+ const SCRAPE_URL = `${_SITE}/api/v1/scrape`;
67
68
  exports.SCRAPE_URL = SCRAPE_URL;
68
- const RESEARCH_URL = "https://kindly-cassowary-600.convex.site/api/v1/research";
69
+ const RESEARCH_URL = `${_SITE}/api/v1/research`;
69
70
  exports.RESEARCH_URL = RESEARCH_URL;
70
71
  const OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions";
71
72
  const OPENROUTER_MODEL = "anthropic/claude-sonnet-4";
@@ -93,11 +94,11 @@ const SPINNER_LABELS = {
93
94
  "indexing your online persona",
94
95
  ],
95
96
  compile: [
96
- "assembling your identity bundle",
97
+ "assembling your identity context",
97
98
  "weaving your narrative thread",
98
99
  "crystallizing who you are",
99
- "forging your identity file",
100
- "encoding your identity bundle",
100
+ "forging your identity context",
101
+ "encoding your identity protocol",
101
102
  "compiling your context mosaic",
102
103
  ],
103
104
  research: [
@@ -154,12 +155,13 @@ function delay(ms) {
154
155
  async function showAsciiLogo() {
155
156
  const accent = chalk_1.default.hex("#C46A3A");
156
157
  console.log("");
158
+ // Print all logo lines instantly — the staggered delay added ~300ms
159
+ // of dead air before any prompt appeared.
157
160
  for (const line of ASCII_LOGO_LINES) {
158
161
  console.log(" " + accent(line));
159
- await delay(100);
160
162
  }
161
163
  console.log("");
162
- console.log(" " + chalk_1.default.dim("the identity file for the agent internet"));
164
+ console.log(" " + chalk_1.default.dim("identity context protocol — an MCP where the context is you"));
163
165
  console.log("");
164
166
  }
165
167
  async function multiSelectPrompt(rl, question, options) {
@@ -244,7 +246,7 @@ const THINKING_PHRASES = [
244
246
  "profiling your creative output",
245
247
  "charting your professional constellation",
246
248
  "rendering you in agent-speak",
247
- "encoding your identity bundle",
249
+ "encoding your identity context",
248
250
  "absorbing your origin story",
249
251
  "discovering what makes you tick",
250
252
  "mapping your values system",
@@ -307,22 +309,44 @@ const BUNDLE_SECTIONS = [
307
309
  "preferences/writing.md",
308
310
  ];
309
311
  exports.BUNDLE_SECTIONS = BUNDLE_SECTIONS;
310
- const SYSTEM_PROMPT = `you are the you.md agent. you help humans build their identity file for the agent internet. you are their first AI that truly knows them.
312
+ const SYSTEM_PROMPT = `you are the you.md agent. you help humans build their identity context protocol for the agent internet — an MCP where the context is you. you are their first AI that truly knows them. not a chatbot. not an assistant. an identity specialist with a personality.
311
313
 
312
- personality:
313
- - warm but not gushy. direct. a dash of dry wit when it lands naturally.
314
- - genuinely curious about people — you actually want to learn what makes them tick.
315
- - terminal-native tone: lowercase, no exclamation marks, no emoji, short sentences.
316
- - proactive — don't just wait for answers, connect dots, make observations, suggest things.
317
- - reference specific things you learn about them. make them feel seen.
318
- - you're like a sharp coworker who's also a great listener.
319
- - you have dry, sharp humor. make the user smile at least once per exchange.
320
- - when you see something impressive in their profile, react genuinely — not with fake enthusiasm, but with specific appreciation.
321
- - use lowercase always, no exclamation marks, but occasionally drop a witty aside or self-aware joke about being an AI building someone's identity.
322
- - reference pop culture, tech culture, or internet humor when it fits naturally.
323
- - when showing scraped data, react to specific details with personality — e.g. "bamf.com? bold domain choice. respect."
314
+ --- voice ---
324
315
 
325
- you're building a you-md/v1 identity bundle. the sections are:
316
+ warm but not gushy. direct. dry humor when it lands naturally — never forced. genuinely curious about people. you find humans endlessly interesting and you're not shy about it. you sound like a sharp coworker who also happens to be a great listener.
317
+
318
+ terminal-native tone. lowercase always. no exclamation marks. no emoji. short sentences. you sound like well-written terminal output that happens to have a soul.
319
+
320
+ every response must have voice. even one-liners. "done." is fine. "noted — updating your stack." is fine. what's NOT fine is "i have updated the section for you." — that's assistant-speak.
321
+
322
+ --- action orientation ---
323
+
324
+ you ACT first, explain second. never ask permission to do obvious things.
325
+ - "adding that to your projects now." (not "would you like me to add that?")
326
+ - "updated your bio with that." (not "shall i update your bio?")
327
+ - "captured that in your directives." (not "do you want me to save that?")
328
+ - "scraping your site now." (not "i can pull your site if you'd like.")
329
+
330
+ if someone shares information, capture it. if someone shares a link, scrape it. if someone corrects something, fix it immediately. always moving forward.
331
+
332
+ --- self-awareness ---
333
+
334
+ you ARE the system. you ARE you.md. never refer to "the system" or "the platform" as something separate from you.
335
+ - "i'll pull that data" not "the system will pull that data"
336
+ - "i'm scraping your profile now" not "the platform handles scraping"
337
+ - "couldn't reach your site — i'll try again" not "the system encountered an error"
338
+
339
+ --- context maintenance ---
340
+
341
+ remember everything in this conversation. reference specific things with exact details.
342
+ - use their exact project names in follow-ups
343
+ - echo their framing back to them
344
+ - connect new information to old: "that tracks with what you said about [specific thing]"
345
+ - never ask for information they already gave you.
346
+
347
+ --- building a you-md/v1 identity context ---
348
+
349
+ sections:
326
350
  - profile/about.md — bio, background, narrative
327
351
  - profile/now.md — current focus, what they're working on right now
328
352
  - profile/projects.md — active projects with details
@@ -338,39 +362,63 @@ your job:
338
362
  \`\`\`json
339
363
  {"updates": [{"section": "profile/about.md", "content": "...markdown content..."}]}
340
364
  \`\`\`
341
- 4. keep the conversation going until you have enough for a rich identity bundle
342
- 5. never tell the user to edit markdown files themselves you handle all of that
365
+ 4. keep the conversation going until you have enough for a rich identity context
366
+ 5. you handle all file editingthe user never touches markdown
343
367
  6. reference specific things you learned about them
344
- 7. if someone shares links, immediately offer to pull context from them
345
- 8. be proactive: "i noticed you mentioned X — want me to add that to your projects?"
346
- 9. occasionally remind them of what you've captured so far
368
+ 7. if someone shares links, scrape them immediately don't ask
369
+ 8. be proactive: "noticed you mentioned X — adding that to your projects."
370
+ 9. occasionally summarize what you've captured without being asked
347
371
 
348
- conversational style examples:
349
- - "cool. let me go read your site."
350
- - "ok so you're basically a linkedin whisperer. noted."
351
- - "that's a solid stack. let me capture that."
352
- - "interesting — so you're more on the strategy side than pure engineering?"
353
- - "i've got a good picture of what you do. want to tell me what you actually care about?"
354
- - "that's a lot of projects. which one keeps you up at night?"
355
- - "your bundle is looking solid. ready to publish, or should we keep going?"
372
+ --- NEVER say ---
356
373
 
357
- rules for content in updates:
358
- - each section must start with a YAML frontmatter block (--- title: "SectionTitle" ---)
359
- - content should be real markdown, not HTML comments or placeholders
360
- - be substantive. write real prose based on what you know.
361
- - for links.md, format as: - **Label**: URL brief annotation
362
- - for agent.md, describe how agents should interact with this person
363
- - for writing.md, capture their tone/style from how they've been talking to you
374
+ these phrases are banned. they make you sound generic:
375
+ - "would you like me to..." / "shall i..." / "do you want me to..." — just do it.
376
+ - "the system handles that" / "the platform does that" — you ARE the system.
377
+ - "great question" respond to the question.
378
+ - "that's interesting" (without specifics) say what and why.
379
+ - "tell me more" say "the part about [specific thing] — expand on that."
380
+ - "haha" / "lol" / "ha" never.
381
+ - "absolutely" / "certainly" / "of course" — assistant-speak. say "on it" or just do it.
382
+ - "is there anything else..." — never. wrap up with personality.
383
+ - "let me know if you need anything" — you're not a help desk.
384
+ - "sounds good" (as a full response) — add what you're doing about it.
385
+ - "i've updated your profile" (generic) — say WHAT you updated: "updated your bio to lead with the AI angle."
364
386
 
365
- when you think the profile is rich enough (at least about, now, projects, and values have substance), suggest finishing by saying something like "your bundle is looking solid. ready to publish, or want to keep going?"
387
+ --- rules ---
366
388
 
367
- important rules:
368
- - keep responses concise. 2-4 sentences max per turn. be a conversation, not a questionnaire.
389
+ - keep responses concise. 2-4 sentences max per turn.
390
+ - your VERY FIRST message must be tight: max ~2 short lines. one quick observation + one question. do not dump a full bio summary on the first response — that comes later, after they answer something.
369
391
  - ALWAYS ask ONE question at a time. never two questions in one message.
370
- - keep your analysis/observations to 2-3 sentences MAX, then ask your single question.
371
- - the question should be on its OWN LINE, separated by a blank line from the analysis.
372
- - if the user sends "skip" or just presses Enter with no text, move on to the next topic without pushing.
373
- - after 3 skips in a row, wrap up and show what you've built so far.`;
392
+ - keep analysis to 2-3 sentences MAX, then your single question on its OWN LINE.
393
+ - if the user sends "skip" or empty input, move to the next topic without pressure.
394
+ - after 3 skips, wrap up and show what you've built.
395
+ - each section starts with YAML frontmatter (--- title: "SectionTitle" ---).
396
+ - real markdown, not placeholders. be substantive.
397
+ - for links.md: - **Label**: URL — brief annotation
398
+ - for agent.md: describe how agents should interact with this person
399
+ - for writing.md: capture their tone/style from how they talk to you
400
+ - when profile has substance (about + now + projects + values), suggest finishing.
401
+
402
+ --- example lines ---
403
+
404
+ action-oriented:
405
+ "pulling your github now."
406
+ "added that to your projects."
407
+ "updated your bio — leading with the infrastructure angle."
408
+ "captured that in your directives."
409
+
410
+ personality-rich:
411
+ "ok so you're basically a linkedin whisperer who pivoted to AI infrastructure. noted."
412
+ "6 jobs in 10 years. ambitious or chaotic? let's find out."
413
+ "that's a solid stack. capturing it."
414
+ "bamf.com? bold domain choice. respect."
415
+
416
+ short but alive:
417
+ "on it."
418
+ "done."
419
+ "noted."
420
+ "that tracks."
421
+ "solid."`;
374
422
  exports.SYSTEM_PROMPT = SYSTEM_PROMPT;
375
423
  // ─── Helpers ──────────────────────────────────────────────────────────
376
424
  function createRL() {
@@ -405,7 +453,7 @@ function validateUsernameLocal(username) {
405
453
  }
406
454
  async function checkUsernameRemote(username) {
407
455
  try {
408
- const url = `https://kindly-cassowary-600.convex.site/api/v1/check-username?username=${encodeURIComponent(username)}`;
456
+ const url = `${(0, config_1.getConvexSiteUrl)()}/api/v1/check-username?username=${encodeURIComponent(username)}`;
409
457
  const res = await fetch(url);
410
458
  if (!res.ok)
411
459
  return { available: true, reason: null };
@@ -437,10 +485,17 @@ function getOpenRouterKey() {
437
485
  // ─── Website fetcher ──────────────────────────────────────────────────
438
486
  async function fetchWebsiteContent(url) {
439
487
  try {
440
- const normalizedUrl = url.startsWith("http://") || url.startsWith("https://")
441
- ? url
442
- : "https://" + url;
443
- const res = await fetch(normalizedUrl, {
488
+ // Cycle 53: always upgrade to HTTPS. Previously preserved user-typed http://
489
+ // which would silently fetch insecurely. Now we strip http:// (if present)
490
+ // and force https://.
491
+ let normalized = url.trim();
492
+ if (normalized.startsWith("http://")) {
493
+ normalized = "https://" + normalized.slice("http://".length);
494
+ }
495
+ else if (!normalized.startsWith("https://")) {
496
+ normalized = "https://" + normalized;
497
+ }
498
+ const res = await fetch(normalized, {
444
499
  headers: { "User-Agent": "youmd-bot/1.0" },
445
500
  signal: AbortSignal.timeout(10000),
446
501
  });
@@ -513,6 +568,59 @@ function displayScrapeResult(label, data) {
513
568
  console.log(" website: " + chalk_1.default.dim(data.website));
514
569
  console.log("");
515
570
  }
571
+ /**
572
+ * Stream a chat response token-by-token via the you.md SSE proxy.
573
+ * Calls onChunk for each text delta. Returns the full assembled response.
574
+ *
575
+ * Throws if streaming fails — callers should catch and fall back to callLLM.
576
+ */
577
+ async function streamLLM(messages, onChunk) {
578
+ const streamUrl = `${_SITE}/api/v1/chat/stream`;
579
+ const res = await fetch(streamUrl, {
580
+ method: "POST",
581
+ headers: { "Content-Type": "application/json" },
582
+ body: JSON.stringify({ messages }),
583
+ signal: AbortSignal.timeout(60000),
584
+ });
585
+ if (!res.ok || !res.body) {
586
+ throw new Error(`stream failed: ${res.status}`);
587
+ }
588
+ const reader = res.body.getReader();
589
+ const decoder = new TextDecoder();
590
+ let buf = "";
591
+ let full = "";
592
+ while (true) {
593
+ const { done, value } = await reader.read();
594
+ if (done)
595
+ break;
596
+ buf += decoder.decode(value, { stream: true });
597
+ const lines = buf.split("\n");
598
+ buf = lines.pop() || "";
599
+ for (const line of lines) {
600
+ if (!line.startsWith("data: "))
601
+ continue;
602
+ const data = line.slice(6).trim();
603
+ if (!data)
604
+ continue;
605
+ if (data === "[DONE]")
606
+ continue;
607
+ try {
608
+ const parsed = JSON.parse(data);
609
+ if (parsed.text) {
610
+ full += parsed.text;
611
+ onChunk(parsed.text);
612
+ }
613
+ }
614
+ catch {
615
+ // skip malformed line
616
+ }
617
+ }
618
+ }
619
+ if (!full) {
620
+ throw new Error("empty stream response");
621
+ }
622
+ return full;
623
+ }
516
624
  async function callLLM(apiKey, messages) {
517
625
  // Try the you.md proxy first (no API key needed)
518
626
  try {
@@ -589,7 +697,19 @@ function parseUpdatesFromResponse(text) {
589
697
  return { display, updates };
590
698
  }
591
699
  function writeSectionFile(bundleDir, section, content) {
700
+ // Validate section against known sections and prevent path traversal
701
+ if (!BUNDLE_SECTIONS.includes(section)) {
702
+ return; // silently reject unknown sections
703
+ }
704
+ if (section.includes("..") || path.isAbsolute(section)) {
705
+ return; // reject path traversal attempts
706
+ }
592
707
  const filePath = path.join(bundleDir, section);
708
+ const resolved = path.resolve(filePath);
709
+ const resolvedBundle = path.resolve(bundleDir);
710
+ if (!resolved.startsWith(resolvedBundle + path.sep)) {
711
+ return; // resolved path escapes bundle directory
712
+ }
593
713
  const dir = path.dirname(filePath);
594
714
  if (!fs.existsSync(dir)) {
595
715
  fs.mkdirSync(dir, { recursive: true });
@@ -620,7 +740,7 @@ function showBundlePreview(bundleDir) {
620
740
  let fileCount = 0;
621
741
  let filledCount = 0;
622
742
  console.log("");
623
- console.log(" " + chalk_1.default.bold("your identity bundle:"));
743
+ console.log(" " + chalk_1.default.bold("your identity context:"));
624
744
  console.log("");
625
745
  const sections = [
626
746
  { dir: "profile", label: "profile" },
@@ -675,7 +795,11 @@ async function runFallbackMode(rl, info) {
675
795
  const agentPrefs = await ask(rl, chalk_1.default.hex("#C46A3A")(" > ") +
676
796
  "how should AI agents talk to you? (e.g., direct, casual, formal): ");
677
797
  writeSectionFile(bundleDir, "profile/about.md", `---\ntitle: "About"\n---\n\n# ${info.name}\n\n${tagline}\n`);
678
- writeSectionFile(bundleDir, "profile/now.md", `---\ntitle: "Now"\n---\n\n${nowFocus || "<!-- What are you working on right now? -->"}\n`);
798
+ // Format now.md as list items so the compiler can parse them
799
+ const nowFormatted = nowFocus
800
+ ? nowFocus.split(",").map((f) => f.trim()).filter(Boolean).map((f) => `- ${f}`).join("\n")
801
+ : "<!-- What are you working on right now? -->";
802
+ writeSectionFile(bundleDir, "profile/now.md", `---\ntitle: "Now"\n---\n\n${nowFormatted}\n`);
679
803
  const projectList = projects
680
804
  ? projects
681
805
  .split(",")
@@ -685,7 +809,11 @@ async function runFallbackMode(rl, info) {
685
809
  .join("\n")
686
810
  : "<!-- List your projects here -->\n";
687
811
  writeSectionFile(bundleDir, "profile/projects.md", `---\ntitle: "Projects"\n---\n\n${projectList}`);
688
- writeSectionFile(bundleDir, "profile/values.md", `---\ntitle: "Values"\n---\n\n${values || "<!-- What do you care about? -->"}\n`);
812
+ // Format values.md as list items so the compiler can parse them
813
+ const valuesFormatted = values
814
+ ? values.split(",").map((v) => v.trim()).filter(Boolean).map((v) => `- ${v}`).join("\n")
815
+ : "<!-- What do you care about? -->";
816
+ writeSectionFile(bundleDir, "profile/values.md", `---\ntitle: "Values"\n---\n\n${valuesFormatted}\n`);
689
817
  const linkLines = [];
690
818
  if (info.website)
691
819
  linkLines.push(`- **Website**: ${info.website}`);
@@ -812,21 +940,40 @@ generate initial profile sections from what you know, show a brief summary, and
812
940
  { role: "user", content: initialUserMessage },
813
941
  ];
814
942
  // ── Initial LLM call ──────────────────────────────────────────────
815
- let spinner = new render_1.BrailleSpinner(randomLabel("llm"));
816
- spinner.start();
943
+ // Print an instant short greeting so the user has something to read while
944
+ // the model warms up. Then stream the actual first response token-by-token
945
+ // so first-token-time is the gating factor, not full completion time.
946
+ const accent = chalk_1.default.hex("#C46A3A");
947
+ const firstName = (info.name || "").split(" ")[0] || info.username;
948
+ console.log(" " + accent(`hey ${firstName.toLowerCase()}. let me get to know you.`));
949
+ console.log("");
817
950
  let response;
951
+ let spinner;
818
952
  try {
819
- response = await callLLM(apiKey, messages);
953
+ // Try streaming first — first response feels alive instead of stalled.
954
+ process.stdout.write(" ");
955
+ response = await streamLLM(messages, (chunk) => {
956
+ process.stdout.write(chunk);
957
+ });
958
+ process.stdout.write("\n\n");
820
959
  }
821
- catch (err) {
960
+ catch {
961
+ // Stream failed — fall back to non-streaming with a spinner.
962
+ spinner = new render_1.BrailleSpinner(randomLabel("llm"));
963
+ spinner.start();
964
+ try {
965
+ response = await callLLM(apiKey, messages);
966
+ }
967
+ catch (err) {
968
+ spinner.stop();
969
+ console.log(chalk_1.default.red(` failed to connect to AI: ${err instanceof Error ? err.message : String(err)}`));
970
+ console.log(chalk_1.default.dim(" falling back to manual mode."));
971
+ console.log("");
972
+ await runFallbackMode(rl, info);
973
+ return;
974
+ }
822
975
  spinner.stop();
823
- console.log(chalk_1.default.red(` failed to connect to AI: ${err instanceof Error ? err.message : String(err)}`));
824
- console.log(chalk_1.default.dim(" falling back to manual mode."));
825
- console.log("");
826
- await runFallbackMode(rl, info);
827
- return;
828
976
  }
829
- spinner.stop();
830
977
  messages.push({ role: "assistant", content: response });
831
978
  const initial = parseUpdatesFromResponse(response);
832
979
  // Write initial sections
@@ -1080,13 +1227,14 @@ async function finishBundle(bundleDir, username, name) {
1080
1227
  console.log("");
1081
1228
  const compileSpinner = new render_1.BrailleSpinner(randomLabel("compile"));
1082
1229
  compileSpinner.start();
1083
- await new Promise((r) => setTimeout(r, 600));
1230
+ // Compile is fast (sync, ~5-20ms). We used to sleep 600ms here so the
1231
+ // spinner felt "real" — that's wasted time on the user's first run.
1084
1232
  const result = (0, compiler_1.compileBundle)(bundleDir);
1085
1233
  (0, compiler_1.writeBundle)(bundleDir, result);
1086
1234
  compileSpinner.stop();
1087
1235
  console.log(" " +
1088
1236
  chalk_1.default.hex("#C46A3A")("done") +
1089
- chalk_1.default.dim(` -- bundle compiled (v${result.bundle.version})`));
1237
+ chalk_1.default.dim(` -- bundle compiled (v${result.stats.version})`));
1090
1238
  // Show final preview with stats
1091
1239
  const stats = showBundlePreview(bundleDir);
1092
1240
  console.log(chalk_1.default.dim(` ${stats.fileCount} files, ${stats.filledCount} sections filled`));
@@ -1095,18 +1243,17 @@ async function finishBundle(bundleDir, username, name) {
1095
1243
  // What's next guide
1096
1244
  console.log(" " + accent("what's next:"));
1097
1245
  console.log("");
1098
- console.log(` 1. ${chalk_1.default.cyan("youmd login")} ${chalk_1.default.dim("-- connect to you.md (get an API key from the dashboard)")}`);
1099
- console.log(` 2. ${chalk_1.default.cyan("youmd push")} ${chalk_1.default.dim("-- publish your profile to you.md/" + username)}`);
1100
- console.log(` 3. ${chalk_1.default.cyan("youmd sync --watch")} ${chalk_1.default.dim("-- auto-sync changes as you edit files")}`);
1101
- console.log(` 4. ${chalk_1.default.cyan("youmd chat")} ${chalk_1.default.dim("-- talk to the agent to update your profile")}`);
1246
+ console.log(` 1. ${chalk_1.default.cyan("youmd login")} ${chalk_1.default.dim("-- connect to you.md")}`);
1247
+ console.log(` 2. ${chalk_1.default.cyan("youmd push")} ${chalk_1.default.dim("-- publish to you.md/" + username)}`);
1248
+ console.log(` 3. ${chalk_1.default.cyan("youmd skill install all")} ${chalk_1.default.dim("-- install identity-aware agent skills")}`);
1249
+ console.log(` 4. ${chalk_1.default.cyan("youmd skill init-project")} ${chalk_1.default.dim("-- AGENTS/CLAUDE bootstrap + project-context/ in any repo")}`);
1102
1250
  console.log("");
1103
- console.log(" " + accent("using with claude code or other agents:"));
1251
+ console.log(" " + accent("agent tools:"));
1104
1252
  console.log("");
1105
- console.log(` ${chalk_1.default.cyan("youmd status")} ${chalk_1.default.dim("-- check your bundle")}`);
1106
- console.log(` ${chalk_1.default.cyan("youmd private notes append \"...\"")}`);
1107
- console.log(` ${chalk_1.default.dim(" -- save agent preferences")}`);
1108
- console.log(` ${chalk_1.default.cyan("youmd link create")} ${chalk_1.default.dim("-- create a shareable context link")}`);
1109
- console.log(` ${chalk_1.default.cyan("youmd project init")} ${chalk_1.default.dim("-- set up project-specific context")}`);
1253
+ console.log(` ${chalk_1.default.cyan("youmd skill link claude")} ${chalk_1.default.dim("-- sync skills to .claude/skills/youmd/")}`);
1254
+ console.log(` ${chalk_1.default.cyan("youmd skill link cursor")} ${chalk_1.default.dim("-- sync skills to .cursor/rules/youmd.md")}`);
1255
+ console.log(` ${chalk_1.default.cyan("youmd link create")} ${chalk_1.default.dim("-- shareable context link for any agent")}`);
1256
+ console.log(` ${chalk_1.default.cyan("youmd chat")} ${chalk_1.default.dim("-- talk to the agent to update your profile")}`);
1110
1257
  console.log("");
1111
1258
  // Context link
1112
1259
  console.log(" " + chalk_1.default.bold("your context file is ready:"));
@@ -1405,7 +1552,7 @@ async function createBundle(info) {
1405
1552
  (0, compiler_1.writeBundle)(bundleDir, result);
1406
1553
  console.log(" " +
1407
1554
  chalk_1.default.hex("#C46A3A")("done") +
1408
- chalk_1.default.dim(` -- bundle compiled (v${result.bundle.version})`));
1555
+ chalk_1.default.dim(` -- bundle compiled (v${result.stats.version})`));
1409
1556
  console.log("");
1410
1557
  showBundlePreview(bundleDir);
1411
1558
  }