{"slug": "two-real-vs-code-extensions-built-with-vsceasy-and-what-each-feature-does", "title": "Two Real VS Code Extensions, Built with vsceasy (and What Each Feature Does)", "summary": "A developer built two real VS Code extensions using vsceasy, a CLI and framework that scaffolds projects with a React webview, a typed RPC bridge between the extension host and webview, and file-based routing for panels, commands, menus and tree views. The framework also provides a mini-ORM, an LLM client, editor-surface helpers and a language project type for grammar-based extensions. One of the extensions, Code Trainer, verifies every model-generated exercise by running its tests against both a reference solution (must pass) and a starter (must fail), rejecting and regenerating anything else.", "body_md": "That 90-second video isn't a mockup. Every VS Code frame in it is a real screen recording: two extensions I built with [**vsceasy**](https://vsceasy.dev), running in VS Code, doing real work. Real keystrokes, real tests, a real local LLM answering.\n\nThis post walks through what you see in the video and which part of the framework makes each piece possible.\n\nvsceasy is a CLI and a small framework for building VS Code extensions. It scaffolds a project with a **React webview**, a **typed RPC bridge** between the extension host and the webview, and **file-based routing** for panels, commands, menus and tree views. On top of that come a mini-ORM, an LLM client, editor-surface helpers (ghost text, typing guards, decorations) and a `language` project type for grammar-based extensions.\n\n```\nbunx @vsceasy/cli create my-extension\n```\n\nThat gives you a working extension: a palette command, a webview panel, an RPC contract and a React UI, with `package.json#contributes` wired for you.\n\nThis is the layout the scaffold generates:\n\n```\nsrc/\n  extension/extension.ts\n  commands/hello.ts                  → palette command\n  panels/dashboard.ts                → webview panel\n  shared/api.ts                      → RPC contract\n  webview/panels/dashboard/App.tsx   → React UI\n```\n\nDrop a file into `panels/`, `commands/`, `menus/` or `treeViews/` and the generator registers it and updates `contributes`. You never hand-edit that block again.\n\nThe piece I'm happiest with. You declare one interface:\n\n```\n// shared/api.ts\nexport interface DashboardApi {\n  listFiles(pattern: string): Promise<string[]>;\n}\n```\n\nImplement it on the extension side:\n\n```\n// panels/dashboard.ts\nexport default definePanel<DashboardApi>({\n  title: 'Dashboard',\n  rpc: (vscode) => ({\n    async listFiles(pattern) {\n      const uris = await vscode.workspace.findFiles(pattern);\n      return uris.map((u) => vscode.workspace.asRelativePath(u));\n    },\n  }),\n});\n```\n\nAnd call it from React:\n\n``` js\nconst files = await api.listFiles('**/*.ts'); // string[], fully typed\n```\n\nNo `postMessage`, no message-name strings, no `switch (msg.type)`. Rename a method and TypeScript tells you everywhere it breaks, on both sides.\n\n`type: ui`)\n[Code Trainer](https://github.com/jairoFernandez/code-coach) teaches algorithms by making you actually type them. In the video, each vsceasy feature shows up in order:\n\n`bun test` in a captured terminal: 3 pass.\nOne idea from this project worth stealing: **generated exercises are verified by running them.** Every problem the model generates is written to a scratch directory and its tests run twice, against the reference solution (must pass) and against the starter (must fail). Anything else is rejected and regenerated. A model will happily produce tests that don't compile or that pass against an empty function, and no static check catches that.\n\n`type: language`)\nNot every extension needs a webview. [The TOML extension](https://github.com/jairoFernandez/toml_extension) was scaffolded with:\n\n```\nvsceasy create toml-support --type language\n```\n\nThat generates a TextMate grammar, `language-configuration.json`, snippets and a file icon, with no React and no RPC. In the video:\n\n`.toml`, plus `Cargo.lock`, `poetry.lock`, `Pipfile` and friends.`table`, `kvstr`, `inline`: type the prefix and tab through the placeholders.\n`vsceasy doctor` checks that every grammar, snippet and icon referenced in `package.json` actually exists before you package.\n\nIf you build with Claude, Codex or Cursor, two entry points give the agent everything it needs:\n\n`https://vsceasy.dev/llms.txt`\n`npx @vsceasy/cli ai-guide` prints every command, flag, type and default as JSON.\nSo you can literally say *\"help me build a VS Code extension, read [https://vsceasy.dev/llms.txt](https://vsceasy.dev/llms.txt)\"* and the agent scaffolds with real commands instead of guessing at boilerplate.\n\n```\nbunx @vsceasy/cli create my-extension\ncd my-extension && bun install\nbun run launch\n```\n\nIf you build something with it, open an issue or PR with the repo link and it goes on the showcase page. I'd love to see it.", "url": "https://wpnews.pro/news/two-real-vs-code-extensions-built-with-vsceasy-and-what-each-feature-does", "canonical_source": "https://dev.to/jairofernandez/two-real-vs-code-extensions-built-with-vsceasy-and-what-each-feature-does-3opc", "published_at": "2026-09-27 21:13:37+00:00", "updated_at": "2026-09-27 22:01:04.751517+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "large-language-models", "ai-agents"], "entities": ["vsceasy", "VS Code", "Code Trainer", "Claude", "Codex", "Cursor", "TypeScript", "React"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/two-real-vs-code-extensions-built-with-vsceasy-and-what-each-feature-does", "markdown": "https://wpnews.pro/news/two-real-vs-code-extensions-built-with-vsceasy-and-what-each-feature-does.md", "text": "https://wpnews.pro/news/two-real-vs-code-extensions-built-with-vsceasy-and-what-each-feature-does.txt", "jsonld": "https://wpnews.pro/news/two-real-vs-code-extensions-built-with-vsceasy-and-what-each-feature-does.jsonld"}}