Everything You Ever Wanted to Know About Chidi.md
The Definitive Architectural Codex, System Internals, and Operating Manual
Every subsystem, interface boundary, and user control in this comprehensive manual answers three foundational architectural questions: What it does (observable inputs, state transitions, and behaviors), How it works (execution trace across the DOM, asynchronous event loop, and network protocols), and Why it works (software engineering invariants, threat mitigation, and architectural decisions).
Book I: Systems Philosophy & Origins
1. The Soul of a Local-First Terminal Reader
In a computational landscape increasingly dominated by invasive telemetry, opaque cloud services, and bloated electron runtimes, Chidi.md represents a deliberate return to clarity, restraint, and user sovereignty. Named after the indecisive moral philosopher who endlessly weighed every ethical ramification, Chidi.md approaches personal notes and document collections with unyielding respect for user privacy and data locality.
Chidi.md is a single-page, no-build web application designed to load, display, and analyze personal Markdown collections in a distraction-free, retro green/amber console environment. It enables users to browse extensive folder hierarchies of .md documents, synthesize summaries, brainstorm questions, converse through threaded follow-up dialogues, and conduct deep multi-document research queries across their entire knowledge base.
- Zero Build Step, Zero npm Tooling (D-001): Clone the repository and serve it immediately. The runtime requires only three core files—
index.html,main.js, andstyle.css—accompanied by pinned CDN libraries. - Absolute Local-Only AI (D-007): No hosted artificial intelligence APIs, no remote proxies, and no API keys. All model inference occurs on a user-controlled local server (such as Ollama or an OpenAI-compatible daemon) listening strictly on loopback interfaces.
- Untrusted Input Boundary (D-006, P1-01): Both user Markdown files and model responses are treated as untrusted inputs. They reach the DOM strictly through DOMPurify sanitization.
- View Invariance & Race Condition Immunity (P2-05): Model generation takes time. An answer is displayed only under the document view that requested it; late responses to discarded views are quarantined and dropped.
- Deterministic Session Durability (D-003): State persistence resides entirely under a single, well-defined
localStoragekey (chidiMdSession), protecting sessions across page reloads without external databases.
2. Air-Gapped AI & The Zero-Key Mandate
Originally conceived with support for remote hosted APIs, Chidi.md made a pivotal architectural shift documented in Decision D-007 (superseding D-002). Storing cloud API keys in browser storage poses inherent security risks: any Cross-Site Scripting (XSS) vulnerability or rogue extension could exfiltrate credentials, while transmitting sensitive personal notes across third-party endpoints compromises user privacy.
Under the Zero-Key Mandate, all API key fields, cloud endpoints, and credential prompts have been eradicated from the system. AI capabilities connect exclusively to local model servers running on the user's personal machine (such as http://localhost:11434 for Ollama or http://localhost:8080/v1 for llama.cpp, LM Studio, or vLLM). The browser enforces a strict localhost host check before dispatching requests, ensuring that your thoughts and notes never leave your hardware.
3. Runtimes & Browser Environment Capabilities
Chidi.md is engineered for modern desktop browsers with particular optimizations across platforms:
3.1 Desktop Chromium (Chrome, Brave, Edge)
Delivers the full-featured Chidi.md operating experience, including individual file selection, multi-file selection, and recursive folder scanning.
Leverages the modern W3C File System Access API (window.showDirectoryPicker()). When the user clicks "Scan Folder", the browser prompts for folder authorization and recursively traverses directory handles to stream every .md file into application memory.
Allows instant ingestion of large personal wikis, Obsidian vaults, and project documentation trees without manual file-by-file picking or compression archives.
3.2 Firefox & Safari (Standard Web Standards)
Provides complete document viewing, markdown parsing, local AI interaction, session saving, and multi-file loading.
File loading operates via the standardized HTML5 <input type="file" multiple accept=".md"> element. When showDirectoryPicker is absent, attempting to "Scan Folder" gracefully alerts the user with platform-specific instructions while preserving full multi-file selection via "ADD FILES".
Maintains cross-browser accessibility and deterministic behavior without forcing non-standard polyfills or breaking the no-build philosophy.
Book II: Core Architecture & Engine Room
4. The No-Build Single-Page Architecture
Adhering strictly to Decision D-001, Chidi.md avoids bundlers, transpilers, npm dependencies, and minification steps. The application source code is delivered directly to the browser as written:
index.html: Semantic HTML5 document containing all console containers, modal overlays, control groupings, and pinned CDN scripts.main.js: The complete application logic (~650 lines of modular ES2020+), organized into clear sections: element caching, state management, modal logic, sanitization, model transport, and DOM wiring.style.css: Custom responsive stylesheet implementing the retro terminal console theme, CRT glow effects, monospaced typography, and accessible high-contrast UI states.
5. Data Flow & Architecture Pipeline
The data flow through Chidi.md follows a unidirectional, strictly filtered pipeline:
+-----------------------------------------------------------------------------------------+
| USER INTERACTION |
| [ADD FILES] (File Input) | [Scan Folder] (DirectoryPicker) | [Ask Form] / [AI] |
+-----------------------------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------------------------+
| STATE MANAGER (main.js) |
| |
| +-----------------------+ +------------------------+ +--------------------+ |
| | state.loadedFiles | | state.history | | state.chatHistory | |
| | [{name, content},...] | | [0, 4, 1, 3...] | | [{role, content}] | |
| +-----------------------+ +------------------------+ +--------------------+ |
| | | | |
| v v v |
| +-----------------------+ +------------------------+ +--------------------+ |
| | state.modelSettings | | state.viewId (Counter) | | state.isAsking | |
| | {apiStyle, baseUrl} | | (Race condition guard) | | (Request lock) | |
| +-----------------------+ +------------------------+ +--------------------+ |
+-----------------------------------------------------------------------------------------+
| |
| (Document Markdown / Model Text) | (JSON Serialization)
v v
+-------------------------------------------------------+ +----------------------------+
| SAFE RENDERING PIPELINE | | PERSISTENCE |
| | | |
| [Raw String] | | localStorage |
| | | | ["chidiMdSession"] |
| v | +----------------------------+
| [marked.parse(content)] (Markdown AST -> HTML) |
| | |
| v |
| [DOMPurify.sanitize(html)] (Strips scripts/vectors) |
| | |
| v |
| [#markdownDisplay.innerHTML] (Verified Safe DOM) |
+-------------------------------------------------------+
^
| (Sanitized LLM Response)
+-------------------------------------------------------+
| LOCAL MODEL TRANSPORT ENGINE |
| |
| isLocalUrl() Check -> http://localhost:11434 |
| Ollama: POST /api/chat |
| OpenAI-Compatible: POST /v1/chat/completions |
+-------------------------------------------------------+
6. State Machine & Element Registry
Source: main.js:2-50
Caches all 37 distinct DOM element references into a single immutable elements dictionary and manages application lifecycle through an explicit, reactive state store.
- On
DOMContentLoaded,elementsqueries every ID defined inindex.html(verified at build time bytests/check_structure.py). stateholdsloadedFiles, navigation pointers (history,historyIndex), active markdown content, conversation turns (chatHistory), active model configuration (modelSettings), query status (isAsking), and view tracking (viewId).updateUI()inspects state conditions to dynamically enable or disable control buttons (disabling navigation when history bounds are reached, disabling AI features when no files are loaded, locking forms during generation).
Eliminates fragmented DOM lookups across functions. Centralizing state guarantees that UI rendering is a deterministic projection of current memory.
7. Markdown & Sanitization Engine
Source: main.js:254-261, index.html:7-8 (Decisions D-001, D-006, P1-01)
Transforms arbitrary Markdown syntax into clean HTML and aggressively neutralizes Cross-Site Scripting (XSS) vectors, malicious iframe injections, and JavaScript URLs before injection into the DOM.
- Input text is passed to
convertMarkdownToHtml(markdownText). marked.parse(markdownText)executes client-side AST tokenization and HTML generation via pinnedmarked@18.0.14.- The generated HTML string passes immediately through
DOMPurify.sanitize()via pinnedDOMPurify@3.4.16, stripping dangerous tags (<script>,<iframe>,<object>) and hostile attributes (onload,onerror,javascript:). - The sanitized markup is assigned to
markdownDisplay.innerHTML.tests/check_structure.pyenforces that no other dynamicinnerHTMLassignment exists inmain.js.
Guarantees zero script execution from untrusted Markdown documents or manipulated model replies. Pinned Subresource Integrity (SRI) hashes ensure CDN scripts cannot be compromised in transit.
8. Local LLM Protocol & Provider Adapters
Source: main.js:96-180, main.js:462-550 (Decision D-007, P1-06)
Bridges Chidi.md to any local Large Language Model server, supporting both Ollama's native REST endpoints and OpenAI-compatible completions APIs with automatic payload normalization.
- URL Verification:
isLocalUrl(url)validates that the configured URL targets a loopback interface (localhost,127.0.0.1,[::1], or*.localhost). Non-local addresses are rejected immediately. - Ollama Adapter: Formats requests to
{base}/api/chatwith{model, messages, stream: false}and extractsresponse.message.content. Models are queried viaGET {base}/api/tagsand capability-checked viaPOST {base}/api/show. - OpenAI-Compatible Adapter: Formats requests to
{base}/chat/completionswith{model, messages}and extractschoices[0].message.content. Compatible with LM Studio, llama.cpp server, LocalAI, and vLLM.
Decouples the user's interface from specific model vendors while ensuring that all inference traffic is air-gapped on the local machine.
9. View Invariance & Stale Response Guarding
Source: main.js:470-495 (Roadmap P2-05)
Prevents race conditions and late model responses from bleeding into newly opened documents when users navigate or restart while an AI query is in flight.
- Each time a file is displayed or a session restarts,
state.viewIdincrements:const displayFile = (index) => { state.viewId++; ... }; - When an AI request starts,
startRequest()captures the currentcapturedViewId = state.viewIdalong with a unique request ID. - Upon response resolution,
isStale(reqId, capturedViewId)checks ifstate.viewId !== capturedViewId. - If the view has drifted, the response text is dropped, the activity spinner hides, and the status bar alerts: "Late reply from <model> dropped (file changed)."
Local LLMs can take seconds or minutes to generate responses. View invariance ensures that answers never contaminate the wrong document, preserving conversation integrity.
10. Session Serialization & Storage HAL
Source: main.js:264-325 (Decisions D-003, D-007, P2-02)
Persists the entire active workspace (loaded files, view history stack, chat conversation turns, and model settings) to browser localStorage under chidiMdSession, complete with quota protection.
- Serialization:
saveSession()compiles{loadedFiles, history, historyIndex, chatHistory, modelSettings}into a JSON string and commits it tolocalStorage.setItem(SESSION_STORAGE_KEY, ...). - Quota Circuit Breaker: If the write throws a storage quota error (typically ~5 MB in modern browsers), the catch block measures payload size and reports: "Error: Session is ~X MB; browser storage is full. Your previous save is still kept."
- Hydration & Quarantine:
restoreSession()parses saved data, restores state pointers, and automatically purges any legacyapiKeyor Gemini data from earlier revisions.
Users can refresh their browser, close tabs, or return days later without losing their place or loaded files, with graceful degradation when quotas are exceeded.
Book III: Document Intelligence Workflows
11. Document-Grounded Prompt Engineering
Chidi.md enforces strict document grounding. The model is never queried as an ungrounded general chatbot; it is primed with explicit instructions to act as an objective, faithful document analyst. The text of the active file is injected as context, followed by the user's specific directive.
12. The Summarize Pipeline
Source: main.js:555-570
Generates a concise, structured executive summary of the currently viewed Markdown document, highlighting core arguments, conclusions, and key takeaways.
Constructs a single-turn prompt containing the document content and the directive: "Provide a concise summary of the following document. Highlight key points and main ideas." The reply is parsed through DOMPurify and appended to the display with an AI heading badge.
Enables instant scanning of lengthy technical documents or research notes without reading several thousand words manually.
13. The Suggestion Generator
Source: main.js:573-610
Analyzes the current document and synthesizes 3 to 5 insightful, probing questions that a reader might ask, rendering them as interactive, clickable buttons in the console.
- Directs the model: "Based on the following document, suggest 3-5 insightful questions a reader might ask to better understand or explore the content."
- Parses numbered list items from the response text into distinct question strings.
- Renders each question as an interactive button (
.suggested-question-btn). Clicking any button populates the query and automatically triggers the follow-up pipeline.
Sparks intellectual curiosity and helps readers discover blind spots or implicit assumptions in complex documentation.
14. Threaded Follow-Up Dialogue (Ask Form)
Source: main.js:510-550, index.html:27-31 (Roadmap P2-01)
Provides a persistent "Ask about this file..." input bar below the document, maintaining a multi-turn conversation thread scoped exclusively to the active file.
- Submitting a question pushes
{role: "user", content: question}tostate.chatHistory. - The conversation history is dispatched to the local model server. During inference, the input box, Ask button, and all AI controls are disabled.
- The model's reply is added to
state.chatHistoryas{role: "assistant", content: reply}and appended to the rendered output. Focus returns to the input box.
Provides a true conversational copilot experience where users can ask progressive questions, clarify specific clauses, and drill into document specifics.
15. Ask All: Cross-Document Corpus Synthesis
Source: main.js:612-640, index.html:46
Executes a single, comprehensive inquiry across every Markdown file loaded in the workspace, synthesizing facts from dozens or hundreds of files into one coherent answer.
- Clicking "Ask All" opens the asynchronous Input Modal prompting for the question.
- Concatenates all loaded files into a single context block:
File: notes/arch.md --- [Content] === File: notes/decisions.md --- [Content] - Directs the model to answer the query specifically citing evidence across the provided files. The synthesized result is appended to the active screen.
Eliminates the friction of manually searching across fragmented notes. Users can ask "Where did we decide our caching strategy?" and receive a cited synthesis instantly.
16. Dynamic Capability Probing
Source: main.js:115-180 (Roadmap P2-04)
Queries the local model server to list available models, dynamically detects their capabilities, and disables embedding-only models that cannot participate in conversational chat.
- On Ollama, queries
GET /api/tagsfor model names, then callsPOST /api/showfor each model to inspectcapabilities. Ifcapabilitieslackscompletion,chatis flaggedfalse. - On OpenAI-compatible servers, models with
embedin their ID are flaggedfalse. fillModelSelect()sorts capable models first and appends disabled options for embedding models, preventing accidental selection.
Prevents confusing runtime errors caused by querying embedding models (such as nomic-embed-text) for conversational text generation.
Book IV: Console Ergonomics & User Interface
17. Retro Console Aesthetic & CSS Design
Source: style.css, index.html:16-63
Styles Chidi.md as a vintage CRT terminal workstation with custom monospaced typography, amber/cyan accent highlights, and subtle terminal borders.
Loads Google Fonts (Space Mono for legible body reading, VT323 for CRT console titles). Uses a dark palette (#0d1117 background, #38bdf8 cyan borders) and fluid CSS grid/flexbox layouts that adapt seamlessly to various desktop viewport sizes.
Fosters a focused, distraction-free reading mindset reminiscent of early Unix workstations without sacrificing modern layout reliability.
18. Buffer Traversal & History Stack
Source: main.js:41-45, main.js:430-460
Maintains an explicit navigation history stack of loaded files, driving the PREV and NEXT buttons with boundary detection and duplicate skipping.
state.historystores an ordered array of file indexes representing viewed documents.state.historyIndextracks the current cursor position.- Clicking
PREVdecrementshistoryIndex; clickingNEXTincrements it. updateUI()disablesPREVwhen at index 0 and disablesNEXTwhen at the end of the history stack.
Provides predictable, browser-like forward/backward navigation across documents without losing state or reloading content.
19. Modal Promise Architecture
Source: main.js:59-94
Powers interactive dialog overlays (Input Modal, Model Settings, Restore Confirmation) using standard JavaScript Promises rather than blocking prompt() or confirm() calls.
showInputModal(config) returns a Promise. It unhides the modal, sets custom labels and placeholders, and binds Enter/Escape keyboard listeners. Confirming resolves with the string value; cancelling or pressing Escape resolves with null. The cleanup closure removes all listeners upon resolution.
Native browser prompts (window.prompt) freeze the execution thread and clash visually with custom themes. The Promise modal pattern allows clean await syntax while preserving theme consistency.
20. Status Readouts & Operational Feedback
Source: main.js:18-20, style.css:120-145
Provides real-time feedback via the footer status readout (loaded file count, system logs, error alerts) and a header activity loader spinner.
fileCountDisplay.textContentreflectsstate.loadedFiles.length.messageBox.textContentrenders standardized log prefixes (SYSTEM LOG: Standby.,SYSTEM LOG: Error: ...).loader.classList.remove('hidden')activates an animated CSS spinner in the header during asynchronous I/O or model inference.
Operators always have immediate visibility into application state, knowing precisely when operations are queued, active, or errored.
Book V: Security & Trust Boundaries
21. Threat Model & Untrusted Inputs
Defines the trust boundary between user files, external model outputs, and DOM execution contexts.
Both user-provided Markdown files and model responses are treated as hostile, untrusted data. Even if a Markdown file contains embedded <script>alert(1)</script>, <img src=x onerror=...>, or [click](javascript:...), it is filtered through DOMPurify before reaching the DOM.
Users frequently download Markdown files or repositories from the public internet. Defense-in-depth sanitization guarantees that opening a hostile Markdown file can never compromise the user's browser.
22. Strict Localhost Perimeter
Source: main.js:96-105 (Decision D-007)
Enforces that outbound network requests initiated by Chidi.md can only target local loopback network adapters on the user's machine.
isLocalUrl(value) parses the input via the browser's URL API and confirms:
- The protocol is
http:orhttps:. - The hostname is strictly
localhost,127.0.0.1,[::1], or ends with.localhost.
api.openai.com or evil-server.com) is rejected immediately with an error.
Eliminates SSRF vectors and ensures that sensitive document contents are never accidentally transmitted across the public internet.
23. Double-Pass Sanitization Boundary
Source: main.js:254-261, main.js:500-505 (Roadmap P1-01, P1-02)
Ensures that structural headings and content elements are assembled with DOM-safe APIs rather than raw template strings.
When appending model output, appendAiOutput() builds container elements, sets headings via heading.textContent = titleText, and processes body markdown through convertMarkdownToHtml(). Template strings are never directly assigned to innerHTML.
Prevents title or prompt injection attacks from escaping HTML boundaries, maintaining structural integrity across all dynamic content.
24. Storage Quarantine & Secret Scrubbing
Source: main.js:315-325 (Decision D-007)
Scans incoming session payloads for legacy credentials (e.g. older versions that stored Gemini API keys) and permanently purges them upon hydration.
When restoring from localStorage, restoreSession() checks for parsedData.apiKey or parsedData.geminiChatHistory. If detected, it immediately deletes those keys and saves the sanitized session back to disk.
Eliminates orphaned API secrets from user storage, ensuring adherence to the Zero-Key Mandate.
Book VI: Quality Assurance & Testing Engineering
In accordance with AGENTS.md and docs/TESTING.md, claims in documentation or code reviews are invalid until observed in execution. Chidi.md maintains an automated test harness covering DOM element wiring, documentation integrity, and dual-browser end-to-end smoke tests.
26. Structural Wiring Linting (tests/check_structure.py)
A fast, zero-dependency Python script that validates the structural agreement between index.html and main.js in under 100 milliseconds.
- Verifies that every ID queried via
document.getElementById()inmain.jsexists exactly once inindex.html. - Verifies that no duplicate IDs exist in
index.html. - Verifies that all local script and stylesheet paths exist on disk.
- Enforces that every
innerHTMLassignment inmain.jsis either a string literal or passes throughconvertMarkdownToHtml(). - Verifies that all CDN scripts include exact version numbers and valid SRI sha384 hashes.
Catches wiring bugs, typos, and security regressions before code ever reaches a browser or version control.
27. Documentation Truth Auditor (tools/check_docs.py)
An automated auditor that checks documentation files for link drift, stale roadmap items, invalid decision references, and unfulfilled template placeholders.
- Scans all project documentation in
docs/and the repository root. - Validates that every Markdown link targets an existing file on disk.
- Verifies that referenced Roadmap IDs (e.g.
P1-01) and Decision IDs (e.g.D-007) exist in their canonical files. - Audits
docs/HANDOFF.mdsession logs for proper formatting and limits.
Guarantees that documentation remains an accurate, living reflection of codebase reality rather than decaying over time.
28. Dual-Browser Playwright Smoke Suite (tests/e2e)
An offline end-to-end test suite running 34 automated browser tests across both Chromium and Firefox, simulating live user workflows and verifying network boundaries.
- Uses Playwright to spin up headless browser instances against an offline mock server. Pinned CDN libraries are served directly from
node_modules. - Tests file loading, duplicate skipping, and history navigation.
- Tests hostile Markdown sanitization (verifying that
onerrorpayloads are stripped). - Tests local URL validation (verifying that non-local URLs are refused).
- Tests live Ollama and OpenAI-compatible API mocking, model capability filtering, and late answer quarantine (P2-05).
- Tests storage quota exhaustion handling (P2-02).
Proves that the entire application operates seamlessly across major desktop rendering engines without relying on external network connectivity during CI runs.
29. Continuous Integration Automation (.github/workflows/checks.yml)
Runs the fast structural checks and dual-browser Playwright smoke test on every push and pull request.
Executes on GitHub Actions Ubuntu runners with pinned Node and Python environments. Actions are pinned to immutable commit SHAs for supply-chain security.
Enforces that no breaking change or security regression can be merged into main without passing automated verification.
Book VII: Interface Codex & Master Feature Matrix
Every button, input field, modal workflow, and utility script in Chidi.md is documented in exhaustive detail in our companion manual, featuring full What It Does, How It Works, and Why It Works breakdowns:
30. Master Feature & Control Directory
Quick reference catalog of all user interface controls and system functions across 9 functional categories:
| Category | Controls & Interfaces |
|---|---|
| 📂 File Ingestion & Loading (4) | ADD FILES, Scan Folder, FILES Count, File Drop |
| 🧭 Navigation & History Stack (4) | PREV Button, NEXT Button, Random Picker, Markdown Viewport |
| 🧠 Document Intelligence (6) | Summarize, Suggest, Ask Form, Ask Input, Ask Button, Question Buttons |
| 📚 Corpus Synthesis (2) | Ask All, Input Modal |
| ⚙️ Model Configuration (7) | Model Button, Server Type, Server URL, Model Selector, Refresh List, Save Model, Cancel Model |
| 💾 Session Persistence (5) | Save Session, Restart Session, Restore Confirm, Restore Deny, Quota Circuit Breaker |
| 🛡️ Security Boundaries (4) | DOMPurify Sanitizer, Local URL Enforcer, Stale Response Guard, Legacy Key Scrubber |
| 🖥️ Operational Feedback (3) | SYSTEM LOG, Activity Loader, Console Header |
| 🛠️ Tooling & Test Automation (4) | serve.py, check_docs.py, check_structure.py, Playwright Smoke Suite |
Technical Appendices & Reference
Appendix A: Dependencies & SRI Hashes
All third-party CDN scripts loaded in index.html are pinned to exact versions with Subresource Integrity (SRI) sha384 hashes:
| Library | Version | CDN Provider | SRI sha384 Integrity Hash |
|---|---|---|---|
| marked | 18.0.14 | jsDelivr | sha384-2vpGtuKqJvFlwJqYnf/wUMuzUfhUnYBt9oay0e2yaFcq0Dh6/aEbQ8YAOeKGzlYo |
| DOMPurify | 3.4.16 | jsDelivr | sha384-a7SzOxErzJ3ZpQz0zJ32d67dSitNzPcbfybc/ykU9KJhMgZkwqfSxlhhdJRS+XGL |
| Google Fonts | Space Mono & VT323 | Google Fonts CDN | Preconnected font stylesheet (styling only) |
Appendix B: Session Schema & Invariants
The chidiMdSession item in localStorage conforms to the following strict JSON specification:
{
"loadedFiles": [
{
"name": "filename.md",
"content": "# Document Title\n\nFull text..."
}
],
"history": [0, 2, 1],
"historyIndex": 2,
"chatHistory": [
{
"role": "user",
"content": "Full text of document..."
},
{
"role": "assistant",
"content": "Summary or answers..."
}
],
"modelSettings": {
"apiStyle": "ollama",
"baseUrl": "http://localhost:11434",
"model": "llama3.1:8b"
}
}
Appendix C: Local Model Server Setup Guide
Chidi.md requires a local model server. Follow these configuration guidelines:
Ollama Setup & CORS Configuration
Install Ollama from ollama.com and pull a model (e.g. ollama pull llama3.1:8b). Because Chidi.md runs in the browser, Ollama must allow browser Cross-Origin Resource Sharing (CORS):
- Linux / macOS: Run
OLLAMA_ORIGINS="*" ollama serveor configure your systemd service environment. - Windows: Add
OLLAMA_ORIGINS=*to User Environment Variables and restart Ollama.
OpenAI-Compatible Servers (LM Studio, llama.cpp)
For LM Studio, start the Local Server on port 1234 and ensure CORS is enabled. In Chidi.md, choose OpenAI-compatible and set the URL to http://localhost:1234/v1.
Appendix D: Troubleshooting & Failure Modes
| Observed Symptom | Underlying Cause | Resolution Procedure |
|---|---|---|
Error: Failed to fetch |
The local model server is offline, listening on a different port, or refusing CORS origins. | Verify the server is running. For Ollama, confirm OLLAMA_ORIGINS="*" is set. |
Error: Session is ~X MB; browser storage is full. |
The total size of loaded files and chat history exceeds the browser's ~5 MB localStorage quota (P2-02). |
Click Restart to begin a fresh session with fewer files, or load documents selectively. |
Late reply from <model> dropped |
The user switched documents or restarted while a generation was in flight (P2-05). | Expected safety behavior. The system quarantined the late reply to prevent cross-document contamination. |
| Scan Folder button displays alert | The browser does not support the File System Access API (e.g. Firefox or Safari). | Use the "ADD FILES" picker instead, or run Chidi.md in a desktop Chromium browser. |