{"id":50638671,"url":"https://github.com/zaemyung/yunseul","last_synced_at":"2026-06-07T06:00:58.658Z","repository":{"id":362958423,"uuid":"1261438557","full_name":"zaemyung/yunseul","owner":"zaemyung","description":"Chat with your Obsidian vault using a local LLM (LM Studio, Ollama) or the Claude Code CLI. On-device retrieval, streaming, offline by default. 윤슬 — sparkling ripples on the water.","archived":false,"fork":false,"pushed_at":"2026-06-06T17:43:07.000Z","size":1003,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-06T19:14:50.061Z","etag":null,"topics":["ai","anthropic","bm25","chat","claude","claude-code","electron","llama-cpp","llm","lm-studio","local-first","local-llm","obsidian","obsidian-md","obsidian-plugin","ollama","privacy-friendly","rag","typescript","vault"],"latest_commit_sha":null,"homepage":"https://zaemyung.github.io/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zaemyung.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-06T17:26:20.000Z","updated_at":"2026-06-06T17:43:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/zaemyung/yunseul","commit_stats":null,"previous_names":["zaemyung/yunseul"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/zaemyung/yunseul","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaemyung%2Fyunseul","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaemyung%2Fyunseul/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaemyung%2Fyunseul/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaemyung%2Fyunseul/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zaemyung","download_url":"https://codeload.github.com/zaemyung/yunseul/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaemyung%2Fyunseul/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34010556,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-07T02:00:07.652Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","anthropic","bm25","chat","claude","claude-code","electron","llama-cpp","llm","lm-studio","local-first","local-llm","obsidian","obsidian-md","obsidian-plugin","ollama","privacy-friendly","rag","typescript","vault"],"created_at":"2026-06-07T06:00:53.228Z","updated_at":"2026-06-07T06:00:58.652Z","avatar_url":"https://github.com/zaemyung.png","language":"TypeScript","funding_links":["https://buymeacoffee.com/zaemyung"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/logo.png\" alt=\"Yunseul logo — a sun setting into rippling water beneath a single sparkle\" width=\"180\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/zaemyung/yunseul/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/zaemyung/yunseul?color=informational\" alt=\"MIT licensed\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/zaemyung/yunseul/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/zaemyung/yunseul?include_prereleases\u0026display_name=tag\" alt=\"Latest release\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://obsidian.md/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Obsidian-1.7.2%2B-7c3aed\" alt=\"Obsidian 1.7.2+\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://buymeacoffee.com/zaemyung\"\u003e\u003cimg src=\"https://img.shields.io/badge/buy_me_a-coffee-FFDD00?logo=buymeacoffee\u0026logoColor=000\" alt=\"Buy me a coffee\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Yunseul (윤슬)\n\n\u003e *Yunseul (윤슬)* — Korean for *sparkling ripples on the water*. Where your notes catch the light: brilliant insights amidst a chaotic web of notes.\n\nChat with your Obsidian vault using a local OpenAI-compatible LLM server (LM Studio, Ollama, llama.cpp server, vLLM, LocalAI) or the Claude Code CLI.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/screenshot.png\" alt=\"Yunseul chat panel showing the YUNSEUL wordmark, the status strip (model · bound note · context size), the logo, the tagline 'Where your notes catch the light.', four quick-start suggestion chips, and the composer with a 'Ask Yunseul' textarea\" width=\"640\" /\u003e\n\u003c/p\u003e\n\n**Status:** Pre-1.0 — actively developed; expect breaking changes between versions.\n\n## What it does\n\n- **Two backends, your choice.** Connect to a local LLM server (LM Studio, Ollama, llama.cpp, vLLM, LocalAI) for fully-offline chat, or ride your existing Claude Code subscription via the `claude` CLI subprocess.\n- **Vault-aware retrieval.** Optional on-device BM25 search pulls the most relevant notes for every question. A \"Top retrieved sources\" block under each reply shows what the model saw, with clickable wikilinks back to the originals.\n- **Tied to your current note.** Each session binds to the active file, so Append always lands where you started — even if you switch notes mid-conversation.\n- **Streaming everything.** Tokens appear as they're generated; Stop anytime; multi-turn conversations persist locally per session.\n- **Provider-aware diagnostics.** \"Test connection\" and the offline banner tell you *exactly* what went wrong (no model loaded, CORS off, `claude` not on PATH, etc.) and how to fix it.\n- **Safe by default.** Sanitized streaming render, sanitized writes to disk, injection-guarded vault excerpts, secret-redacted debug output. External images and unsafe URL schemes in assistant output never silently fetch.\n- **Operator's Console aesthetic.** Bubble-less, typographically driven, theme-aware. Plays well with Catppuccin, Things, Minimal, and stock Obsidian.\n\n## Providers\n\nYunseul ships two backends. The active one is selected under Settings → Yunseul → Provider.\n\n### LM Studio (and other OpenAI-compatible local servers)\n\nTalks to any server that implements the OpenAI `/chat/completions` SSE protocol — LM Studio, Ollama, llama.cpp server, vLLM, LocalAI. Configure the base URL, API key (if your server requires one), and the model id in Settings → Yunseul. Everything runs on your machine: prompts, vault excerpts, and retrieved chunks never leave the host.\n\n### Claude Code subprocess\n\nSpawns the local `claude` CLI binary. Yunseul does NOT manage an API key for this provider; it rides on your existing Claude Code authentication (Pro/Max OAuth, Anthropic Console, Bedrock, Vertex, etc.) as configured in your Claude Code install. Configure the binary path (optional — defaults to `claude` on `PATH`) and model in Settings → Yunseul → Provider: Claude Code subprocess. Writes (Edit/Write tools) are off by default; toggle \"Allow writes\" to let the assistant modify vault files.\n\n## Privacy \u0026 data flow\n\n- **LM Studio path:** prompts, vault excerpts, and retrieved chunks stay on your machine. No network calls leave the host beyond the local server URL you configured.\n- **Claude Code path:** prompts, vault excerpts, and retrieved chunks are sent to Anthropic via your authenticated `claude` CLI. See Anthropic's privacy policy: https://www.anthropic.com/legal/privacy\n- **BM25 index** stays in your vault at `\u003cvault\u003e/.yunseul/bm25-index.json`. It is never uploaded by Yunseul itself; any sync service watching the vault will see it (see \"Sync services\" below).\n- **Sessions** persist locally at `\u003cvault\u003e/.obsidian/plugins/yunseul/sessions/\u003cid\u003e.json`.\n- **API keys** for the LM Studio provider are stored in plain text in `\u003cvault\u003e/.obsidian/plugins/yunseul/data.json` (Obsidian's standard plugin data location).\n- **No telemetry, no analytics, no automatic network calls** without an explicit user action (sending a message, clicking Test Connection, or building the vault index).\n- **Persisted assistant output is sanitized.** When Append or Download writes assistant text to a vault note, external images, `data:` URIs, Obsidian `![[embed]]` syntax, and unsafe link schemes are rewritten as bracketed placeholder text (e.g., `[blocked external image: host]`, `[blocked data image]`, `[embed stripped: target]`). This applies to both Append-to-note and Download-as-Markdown paths, is independent of the in-chat \"Allow external images\" toggle, and cannot currently be disabled.\n\n## Installation\n\n### Community plugin store (recommended, when published)\n\n1. Open **Settings → Community plugins** in Obsidian.\n2. Turn **Restricted mode** off.\n3. Click **Browse**, search for \"Yunseul\", and install.\n4. Enable Yunseul.\n\n### Manual install\n\n1. Download `main.js`, `manifest.json`, and `styles.css` from the latest [release](https://github.com/zaemyung/yunseul/releases).\n2. Create a folder at `\u003cvault\u003e/.obsidian/plugins/yunseul/` and drop the three files into it.\n3. In Obsidian: **Settings → Community plugins → Restricted mode OFF → Yunseul**.\n\n## Vault search \u0026 the on-disk index\n\nWhen the \"Enable vault search\" toggle is on, Yunseul builds a BM25 inverted index over every markdown file in your vault. The index lives at:\n\n```\n\u003cvault\u003e/.yunseul/bm25-index.json\n```\n\nNotes on this file:\n\n- It is stored as a single JSON document under the vault root (NOT inside `.obsidian/`) so it survives plugin reinstall.\n- Size scales roughly with the total token count of the indexed bodies. A vault of 5,000 notes typically produces a 30-150 MB index; a vault of 50,000 notes can produce a multi-hundred-MB index.\n- The file is rewritten atomically (`*.tmp` sibling + rename) whenever an indexed note changes. The debounce window is 1.5 seconds.\n\n### Sync services\n\nThe index file lives under the vault root, so anything that watches the vault will see and potentially sync it. To exclude it:\n\n- **Obsidian Sync:** Obsidian Sync ignores hidden files (paths starting with `.`) by default, which covers `.yunseul/`. Verify in your sync settings.\n- **iCloud (macOS):** Append `.nosync` to the directory to opt out: rename `.yunseul` to `.yunseul.nosync`. Note this requires updating the path in the plugin code.\n- **Syncthing:** Add `.yunseul/` to the folder's `.stignore` file.\n- **Dropbox / OneDrive / Google Drive:** Most desktop clients do not provide per-folder ignore lists; consider moving your vault out of the synced folder if you don't want a multi-hundred-MB index uploaded.\n- **git:** Add `.yunseul/` to your vault's `.gitignore`.\n\n### Resetting the index\n\nTo remove the on-disk index, either:\n\n- Open Settings → Yunseul → Vault search → Reset index, or\n- Run the command \"Reset vault index\" from the command palette.\n\nBoth routes show a confirmation modal before deleting the file.\n\n## Contributing \u0026 building from source\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, code conventions, architecture overview, and how to add a provider or setting.\n\n## Support the work\n\nYunseul is built with care, in spare hours, by one person — alongside other small things that try to make a few minutes of someone's day a little brighter. If it's been useful to you, a coffee keeps the next small bright thing alive.\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://buymeacoffee.com/zaemyung\"\u003e\n    \u003cimg src=\"https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png\" alt=\"Buy me a coffee\" height=\"48\" /\u003e\n  \u003c/a\u003e\n  \u003cbr /\u003e\u003cbr /\u003e\n  \u003cimg src=\"assets/bmc_qr.png\" alt=\"Buy me a coffee QR code\" width=\"140\" /\u003e\n  \u003cbr /\u003e\n\u003c/p\u003e\n\nMore small things at [zaemyung.github.io](https://zaemyung.github.io/).\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzaemyung%2Fyunseul","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzaemyung%2Fyunseul","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzaemyung%2Fyunseul/lists"}