1(function () { 2 "use strict"; 3 4 const id = document.body.dataset.product; 5 const product = window.AnishBot && window.AnishBot.products ? window.AnishBot.products[id] : null; 6 const app = document.getElementById("product-page"); 7 8 const STORIES = { 9 lekhanam: { 10 accent: "#eea05f", mark: "L", tags: ["Writing", "Local AI", "Privacy"], 11 problem: "Long-form writing gets fragmented across editors, planning tools, AI chats, design apps, and export utilities. Each handoff interrupts the work and can expose private drafts.", 12 approach: "Lekhanam brings the book workflow into one native Mac studio. The product treats AI as an optional, local assistantânot the owner of the writingâand keeps the author in control from first note to final export.", 13 features: [["Write without context switching", "Draft, structure, revise, and organise a manuscript inside one focused workspace."], ["Use AI on your terms", "Choose local models or Apple Intelligence where supported, without sending the manuscript to a hosted writing service."], ["See the whole book", "Outliner, storyboard, character profiles, notes, goals, and snapshots keep long projects navigable."], ["Finish professionally", "Design a cover and export the manuscript as PDF, DOCX, or ePub when it is ready to leave the studio."]] 14 }, 15 thalam: { 16 accent: "#6fc7b9", mark: "T", tags: ["Planning", "Energy", "Apple Watch"], 17 problem: "Conventional task managers assume every hour is equal. They capture what must be done but ignore energy, focus, recovery, and the rhythm of a real day.", 18 approach: "Thalam frames planning as a rhythm rather than a queue. It connects intentions, routines, reflections, and optional health signals so the plan can adapt to the person doing the work.", 19 features: [["Plan around capacity", "Arrange work with attention to focus and energy instead of time alone."], ["Check in quickly", "Use lightweight reflections to learn what supported or disrupted the day."], ["Carry the plan with you", "iPhone and Apple Watch experiences keep the essential interaction close at hand."], ["Keep personal signals private", "iCloud and optional Apple Health access stay within Appleâs permission-controlled ecosystem."]] 20 }, 21 mozhima: { 22 accent: "#efad66", mark: "M", tags: ["AAC", "Accessibility", "Offline"], 23 problem: "Communication tools can become expensive, complicated, or dependent on connectivityâexactly when a person needs a fast, dependable way to express something.", 24 approach: "Mozhima is a free, offline-first AAC and visual-support app designed around large targets, clear choices, personalisation, and zero child-data collection.", 25 features: [["Build a sentence", "Combine tap-to-speak cards into useful phrases and everyday requests."], ["Make it personal", "Create cards and folders with familiar photos, words, and routines."], ["Support the whole day", "Picture Book, Social Stories, My Day, and Calm Down tools extend beyond a single conversation."], ["Reach more families", "Thirteen languages, high-contrast themes, large controls, and Switch Access support broaden usability."]] 26 }, 27 duet: { 28 accent: "#ea8c8c", mark: "D", tags: ["Shared life", "iCloud", "Encryption"], 29 problem: "A relationshipâs shared life is scattered across chats, calendars, notes, payment apps, and memory. Generic collaboration tools rarely feel private or personal enough for two people.", 30 approach: "MyDuet creates one shared space designed specifically for a pair. It combines daily coordination with journals and relationship rituals while keeping intimate information within the coupleâs iCloud setup.", 31 features: [["Coordinate the practical", "Share calendars, chores, shopping, expenses, rewards, and house rules."], ["Protect the personal", "Keep journals, messages, and other intimate content inside a private paired experience."], ["Build shared momentum", "Points, rewards, and gentle rituals make coordination feel less transactional."], ["Pair deliberately", "Start solo and connect two compatible iPhones through an intentional QR-code flow."]] 32 }, 33 aeroprompt: { 34 accent: "#69b8d5", mark: "A", tags: ["Prompts", "Templates", "On-device"], 35 problem: "Useful prompts disappear inside chat history, while repeatedly copying, editing, and adapting them wastes time and introduces inconsistency.", 36 approach: "AeroPrompt turns prompts into reusable working assets. Templates, variables, organisation, and one-click insertion support a repeatable AI workflow without requiring a prompt cloud.", 37 features: [["Build a prompt system", "Organise frequently used prompts into folders and searchable collections."], ["Adapt without rewriting", "Dynamic variables turn one prompt into a reusable template for many situations."], ["Work where the conversation is", "Insert prepared prompts directly into supported ChatGPT, Claude, and Gemini interfaces."], ["Keep control locally", "Store prompt content on the device and move it through explicit import and export."]] 38 }, 39 tabeconomist: { 40 accent: "#75caa7", mark: "T", tags: ["Browser memory", "Local AI", "Focus"], 41 problem: "Open tabs preserve intent but create clutter. Closing them loses context; keeping them consumes attention and eventually makes the browser unusable.", 42 approach: "Tab Economist treats an idle tab as information that can be archived and recalled. Local summaries make the archive useful without turning browsing history into a cloud dataset.", 43 features: [["Reduce tab pressure", "Archive tabs automatically after a configurable period of inactivity."], ["Remember why it mattered", "Create concise summaries where supported so an archived page remains understandable."], ["Find and restore", "Search the archive and reopen useful pages when the task returns."], ["Define exceptions", "Protect important sites and tune thresholds to match the userâs browsing habits."]] 44 }, 45 neuralfill: { 46 accent: "#8796df", mark: "N", tags: ["Forms", "Automation", "Encryption"], 47 problem: "People repeatedly type the same sensitive information into forms, yet conventional autofill can be rigid, opaque, or too dependent on synced cloud profiles.", 48 approach: "NeuralFill treats form completion as a private automation problem. Reusable encrypted profiles and on-device field matching reduce effort while keeping the user in control of the source data.", 49 features: [["Reuse trusted profiles", "Store the information needed for recurring forms in structured local profiles."], ["Match f
49ields intelligently", "Recognise varied labels and map them to the appropriate saved values."], ["Review before committing", "Keep the user in the browser flow instead of silently submitting information."], ["Protect stored details", "Use AES-256 encryption and avoid required network calls for the core experience."]] 50 }, 51 stepskript: { 52 accent: "#f19a5f", mark: "S", tags: ["SOP", "Documentation", "Workflow"], 53 problem: "Documenting a browser process is slow: repeat the workflow, capture every screen, mark each click, explain each step, and then format the result for sharing.", 54 approach: "StepSkript records the work while it happens and produces an editable guide. The human remains responsible for accuracy and redaction, while repetitive capture and layout are automated.", 55 features: [["Record the real workflow", "Capture browser clicks with a screenshot and visible highlight for each step."], ["Edit the explanation", "Reorder, duplicate, delete, or add manual steps before sharing."], ["Choose optional AI", "Generate descriptions through a user-selected provider and bring-your-own key."], ["Export for the audience", "Create self-contained PDF, HTML, Markdown, or raw JSON output."]] 56 }, 57 lumora: { 58 accent: "#79c9ba", mark: "L", tags: ["Wellbeing", "Breathing", "Local"], 59 problem: "Screen-break notifications are easy to dismiss because they arrive as another small interruption competing with the work already on screen.", 60 approach: "Lumora makes the break itself the interface. A calm page overlay, breathing rhythm, flexible timing, and fullscreen awareness make pausing gentler and harder to forget.", 61 features: [["Create a real pause", "Dim the page and guide a short 4-4-4 breathing cycle."], ["Respect the context", "Postpone interruptions during fullscreen video and meetings where possible."], ["Shape the routine", "Choose interval presets, custom timing, themes, sounds, snooze, and skip."], ["Build awareness locally", "Track streaks and lightweight history without accounts, analytics, or telemetry."]] 62 }, 63 snapspec: { 64 accent: "#77b8df", mark: "S", tags: ["Design systems", "Capture", "AI workflow"], 65 problem: "A screenshot shows how a page looks but hides the typography, spacing, responsive behaviour, assets, and structural decisions needed to reproduce it accurately.", 66 approach: "SnapSpec converts a rendered interface into both visual evidence and a structured Markdown blueprint that a designer or coding assistant can reason about.", 67 features: [["Choose the scope", "Capture an entire page, a specific element, or a selected region."], ["Expose the system", "Extract colours, typography, spacing, borders, shadows, structure, and useful CSS."], ["Preserve visual evidence", "Pair the written blueprint with a screenshot of the rendered result."], ["Hand off to an AI tool", "Copy portable Markdown for Claude, ChatGPT, Codex, Cursor, or another assistant."]] 68 }, 69 permissionpatrol: { 70 accent: "#e5aa5e", mark: "P", tags: ["Permissions", "Trackers", "Privacy"], 71 problem: "Browser permission controls are fragmented, trackers are invisible, and privacy settings use language that makes it difficult to understand what a site can actually do.", 72 approach: "Permission Patrol brings the current siteâs privacy posture into one side panel and translates technical signals into practical choices without sending browsing data to a service.", 73 features: [["See current access", "Review camera, microphone, location, notifications, and other site permissions together."], ["Read a useful score", "Turn permission, cookie, and tracker signals into a plain-language privacy summary."], ["Notice change", "Receive alerts when a siteâs permission state changes unexpectedly."], ["Keep inspection local", "Store baselines, sightings, and preferences on-device with no Cheppulabs server."]] 74 }, 75 docsift: { 76 accent: "#5ec7b4", mark: "D", tags: ["Documents", "Retrieval", "MCP"], 77 problem: "Large PDFs and Office files overwhelm AI context windows. Sending the whole document is slow, expensive, and often strips away the page or slide references needed to verify an answer.", 78 approach: "DocSift converts documents locally, indexes token-sized chunks, and retrieves only the passages relevant to a questionâwith source locations preserved.", 79 features: [["Convert useful formats", "Turn PDF, DOCX, XLSX, PPTX, HTML, CSV, and EPUB content into clean Markdown."], ["Retrieve within a budget", "Use cached SQLite full-text search to return focused chunks instead of an entire file."], ["Keep source references", "Carry page or slide locations into the result so an answer can be checked."], ["Fit different workflows", "Use the CLI, local HTTP API, stdio MCP server, Docker, or connector examples."]] 80 }, 81 whyline: { 82 accent: "#f09a63", mark: "W", tags: ["Agent handoff", "Decisions", "Git"], 83 problem: "When work moves between coding agents, the diff survives but the reasoning does not. The next agent repeats investigation, reverses decisions, or edits files already owned elsewhere.", 84 approach: "whyline adds a small repository-local coordination layer: durable decisions in Markdown, checkout-local ownership and handoff state, and concise context packets for the next agent.", 85 features: [["Record the why", "Capture a decision, rationale, and rejected alternatives beside the repository."], ["Coordinate active work", "Claim tasks and files, publish status, and make handoffs explicit."], ["Brief the next agent", "Create token-bounded sync packets with relevant decisions and current Git state."], ["Stay tool-neutral", "Work with Claude Code and Codex using their existing authentication and CLI workflows."]] 86 }, 87 sonde: { 88 accent: "#6ebad8", mark: "S", tags: ["Code graph", "Impact", "MCP"], 89 problem: "Coding agents spend tokens rediscovering structure through repeated search and still miss callers, tests, or dependencies that sit outside the visible snippet.", 90 approach: "Sonde indexes a repository into a local symbol graph so an agent can ask structural questions directly, see the evidence tier, and understand change impact before editing.", 91 features: [["Find the right symbols", "Search named code entities across TypeScript, Python, and Swift repositories."], ["Trace relationships", "Query callers, callees, imports, dependencies, and related tests as graph edges."], ["Measure blast radius", "Inspect direct and transitive impact with tier-labelled evidence and drift checks."], ["Document the architecture", "Generate reproducible architecture notes from the local SQLite graph."]] 92 } 93 }; 94 95 const SOURCES = { 96 lekhanam: [["Visit Lekhanam", "https://www.lekhanam.app/"], ["Mac App Store", "https://apps.apple.com/in/app/lekhanam/id6760804927?mt=12"]], 97 thalam: [["Download on App Store", "https://apps.apple.com/in/app/thalam-plan-track/id6761784957"]], 98 mozhima: [["Download on App Store", "https://apps.apple.com/in/app/mozhima/id6781443477"]
98], 99 duet: [["Download on App Store", "https://apps.apple.com/in/app/myduet/id6763341973"]], 100 aeroprompt: [["Chrome Web Store", "https://chromewebstore.google.com/detail/aeroprompt/hpdoliaenggfiokfjgmehandefcfnldj"], ["Microsoft Edge", "https://microsoftedge.microsoft.com/addons/detail/lkcchacknincfboighbjhhaifdocknlk"]], 101 tabeconomist: [["Chrome Web Store", "https://chromewebstore.google.com/detail/the-tab-economist/bdakmbobkeaedpeajagcgbdmijfmcoap"], ["Microsoft Edge", "https://microsoftedge.microsoft.com/addons/detail/aomcapiplplfbindaodifapaddbenanm"]], 102 neuralfill: [["Open NeuralFill site", "../neuralfill/index.html"]], 103 stepskript: [["Chrome Web Store", "https://chromewebstore.google.com/detail/stepskript-%E2%80%94-step-by-step/dekmoognaojocgmgibclnpkbnhbcdjio"], ["Microsoft Edge", "https://microsoftedge.microsoft.com/addons/detail/ekcmchpbmlhlhccbgdmhgfmhfinajbfl"]], 104 lumora: [["Chrome Web Store", "https://chromewebstore.google.com/detail/lumora/leodohcpjdmkhbhlfkldcmikmmhfpjip"], ["Microsoft Edge", "https://microsoftedge.microsoft.com/addons/detail/geipkapmhjbaedmjlioiigahkmmfbmmk"]], 105 snapspec: [["Chrome Web Store", "https://chromewebstore.google.com/detail/snapspec/elpjklflihlhjkoaadakojdbfjghnnan"], ["GitHub", "https://github.com/anishmoncivarghese/snapspec"]], 106 permissionpatrol: [["View on GitHub", "https://github.com/anishmoncivarghese/permission-patrol"]], 107 docsift: [["Install from PyPI", "https://pypi.org/project/docsift/"], ["GitHub", "https://github.com/anishmoncivarghese/docsift"]], 108 whyline: [["Install from PyPI", "https://pypi.org/project/whyline/"], ["GitHub", "https://github.com/anishmoncivarghese/whyline"]], 109 sonde: [["View on npm", "https://www.npmjs.com/package/@cheppulabs/sonde"], ["GitHub", "https://github.com/anishmoncivarghese/sonde"]] 110 }; 111 112 const ORDER = ["lekhanam", "thalam", "mozhima", "duet", "aeroprompt", "tabeconomist", "neuralfill", "stepskript", "lumora", "snapspec", "permissionpatrol", "docsift", "whyline", "sonde"]; 113 const escapeHtml = (value) => String(value).replace(/[&<>'"]/g, (char) => ({ "&": "&", "<": "<", ">": ">", "'": "'", '"': """ }[char])); 114 115 if (!product || !STORIES[id]) { 116 app.innerHTML = '<main class="pp-error"><div><h1>Product not found</h1><p><a href="../index.html#work">Return to the portfolio</a></p></div></main>'; 117 return; 118 } 119 120 const story = STORIES[id]; 121 const sources = SOURCES[id] || []; 122 const position = ORDER.indexOf(id); 123 const previous = ORDER[(position - 1 + ORDER.length) % ORDER.length]; 124 const next = ORDER[(position + 1) % ORDER.length]; 125 const products = window.AnishBot.products; 126 const actionHtml = sources.map(([label, href], index) => `<a class="pp-button${index === 0 ? " pp-button--primary" : ""}" href="${escapeHtml(href)}"${/^https?:/.test(href) ? ' target="_blank" rel="noopener"' : ""}>${escapeHtml(label)} <span aria-hidden="true">${/^https?:/.test(href) ? "â" : "â"}</span></a>`).join(""); 127 const featureHtml = story.features.map(([title, copy], index) => `<article class="pp-feature"><span class="pp-feature-index">0${index + 1}</span><h3>${escapeHtml(title)}</h3><p>${escapeHtml(copy)}</p></article>`).join(""); 128 129 document.documentElement.style.setProperty("--pp-accent", story.accent); 130 app.innerHTML = ` 131 <header class="pp-nav"> 132 <a class="pp-brand" href="../index.html">Anish</a> 133 <nav class="pp-nav-links" aria-label="Main navigation"><a href="../index.html#work">Products</a><a href="../about.html">About</a></nav> 134 </header> 135 <main> 136 <section class="pp-hero" aria-labelledby="product-title"> 137 <div class="pp-shell pp-hero-grid"> 138 <div> 139 <div class="pp-breadcrumb"><a href="../index.html#work">Portfolio</a><span>/</span><span>${escapeHtml(product.category)}</span></div> 140 <h1 class="pp-title" id="product-title">${escapeHtml(product.name)}</h1> 141 <p class="pp-summary">${escapeHtml(product.summary)}</p> 142 <div class="pp-actions">${actionHtml}</div> 143 </div> 144 <div class="pp-mark-wrap" aria-hidden="true">
145 <span class="pp-orbit-label">${escapeHtml(story.tags[0])}</span><span class="pp-orbit-label">${escapeHtml(story.tags[1])}</span><span class="pp-orbit-label">${escapeHtml(story.tags[2])}</span> 146 <div class="pp-mark">${escapeHtml(story.mark)}</div> 147 </div> 148 </div> 149 </section> 150 151 <div class="pp-facts-wrap"><div class="pp-facts"> 152 <div class="pp-fact"><div class="pp-fact-label">Platform</div><div class="pp-fact-value">${escapeHtml(product.category)}</div></div> 153 <div class="pp-fact"><div class="pp-fact-label">Pricing</div><div class="pp-fact-value">${escapeHtml(product.pricing)}</div></div> 154 <div class="pp-fact"><div class="pp-fact-label">Install</div><div class="pp-fact-value">${escapeHtml(product.install)}</div></div> 155 </div></div> 156 157 <section class="pp-section pp-section--paper"><div class="pp-shell pp-story-grid"> 158 <div><div class="pp-kicker">Product thinking</div><h2 class="pp-heading">Why this product exists.</h2></div> 159 <div class="pp-story-copy"><p>${escapeHtml(story.problem)}</p><p>${escapeHtml(story.approach)}</p></div> 160 </div></section> 161 162 <section class="pp-section"><div class="pp-shell"> 163 <div class="pp-feature-head"><div><div class="pp-kicker">Experience design</div><h2 class="pp-heading">What it helps people do.</h2></div><p>${escapeHtml(product.features)}</p></div> 164 <div class="pp-feature-grid">${featureHtml}</div> 165 </div></section> 166 167 <section class="pp-section pp-section--ink"><div class="pp-shell"> 168 <div class="pp-trust-head"><div class="pp-kicker">Practical details</div><h2 class="pp-heading">Built with clear boundaries.</h2></div> 169 <div class="pp-trust-grid"> 170 <article class="pp-trust-card"><span>Privacy</span><p>${escapeHtml(product.privacy)}</p></article> 171 <article class="pp-trust-card"><span>Compatibility</span><p>${escapeHtml(product.compatibility)}</p></article> 172 <article class="pp-trust-card"><span>Getting started</span><p>${escapeHtml(product.install)}</p></article> 173 </div> 174 </div></section> 175 176 <section class="pp-next"><div class="pp-shell pp-next-grid"> 177 <a class="pp-next-link" href="${previous}.html"><small>Previous product</small><strong>â ${escapeHtml(products[previous].name)}</strong></a> 178 <a class="pp-next-link" href="${next}.html"><small>Next product</small><strong>${escapeHtml(products[next].name)} â</strong></a> 179 </div></section> 180 </main> 181 <footer class="pp-footer"><div class="pp-footer-inner"><a href="../index.html">Anish Monci Varghese</a><span>Product management · Data · Automation · Software</span></div></footer>`; 182})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.