"description": "Native, Claude-first AI for LevelCode — chat with your code, no middle-man backend.",
"publisher": "levelcode",
"version": "0.1.0",
"license": "MIT",
"engines": {
"vscode": "^1.126.0"
},
"categories": [
"Other"
],
"capabilities": {
"virtualWorkspaces": true,
"untrustedWorkspaces": {
"supported": true
}
},
"activationEvents": [
"onStartupFinished"
],
"main": "./extension.js",
"contributes": {
"walkthroughs": [
{
"id": "welcome",
"title": "Welcome to LevelCode",
"description": "Your AI-native, hackable, Notepad++-powered editor — set it up in a couple of minutes.",
"steps": [
{
"id": "ai",
"title": "Connect your AI",
"description": "Native Claude, built into the editor — chat with your files as context, inline completions as you type, and an agent that reads, edits, and runs commands across your project. **Sign in and you're on your plan** — no API key to manage. Prefer your own? BYOK speaks Claude, OpenAI, Groq, Mistral, Ollama and more.\n[Sign in to LevelCode](command:levelcode.ai.account)\n[Use your own key (BYOK)](command:levelcode.ai.setApiKey)\n[Pick a model](command:levelcode.ai.pickModel)\n[Open the chat](command:levelcode.ai.focus)",
"media": {
"svg": "media/walkthrough/ai.svg",
"altText": "Native AI chat, inline completions, and an agent built into the editor"
},
"completionEvents": [
"onCommand:levelcode.ai.setApiKey",
"onCommand:levelcode.ai.account"
]
},
{
"id": "look",
"title": "Make it yours",
"description": "Signature **One Dark / One Light** themes, **Atom · Notepad++ · Sublime** keymaps so your muscle memory just works, and Notepad++ power-editing — macros, column edit, big-file mode. Make it feel like home.\n[Choose a theme](command:workbench.action.selectTheme)\n[Apply a keymap preset](command:levelcode.keymap.apply)",
"media": {
"svg": "media/walkthrough/look.svg",
"altText": "Signature themes, keymap presets, and Notepad++ power-editing"
},
"completionEvents": [
"onCommand:levelcode.keymap.apply"
]
},
{
"id": "updates",
"title": "Stay up to date",
"description": "LevelCode checks for new releases in the background and tells you the moment one's ready — one click to download. That's the tour. Happy hacking.\n[Check for updates](command:levelcode.update.check)",
"media": {
"svg": "media/walkthrough/updates.svg",
"altText": "LevelCode checks for new releases and downloads them in one click"
"markdownDescription": "Which AI provider chat, inline completion and edit use. Every provider except Anthropic speaks the OpenAI-compatible `/v1/chat/completions` protocol, so one key + one setting unlocks it. **Agent mode currently runs on Anthropic (Claude) only.** Pick a model with **LevelCode: AI: Select Model…** — it sets the provider and model together."
},
"levelcode.ai.model": {
"type": "string",
"default": "",
"markdownDescription": "Active model id for the selected provider (used by every provider except Claude and Ollama, which keep their own `levelcode.ai.claude.model` / `levelcode.ai.ollama.model`). Usually set for you by **LevelCode: AI: Select Model…**; you can also type any model id your provider serves (e.g. `gpt-4o`, `anthropic/claude-sonnet-4-6` on OpenRouter)."
},
"levelcode.ai.baseURL": {
"type": "string",
"default": "",
"markdownDescription": "Base URL for the **OpenAI-compatible (custom)** provider — must end in `/v1` (e.g. `http://localhost:8000/v1` for vLLM, `http://localhost:1234/v1` for LM Studio). Only used when `levelcode.ai.provider` is `custom`. Prefer `https` (or explicit localhost) — your key is sent as a Bearer token to this host."
},
"levelcode.ai.cloudModel": {
"type": "string",
"default": "moonshotai/kimi-k2.7-code",
"markdownDescription": "Which **LevelCode Cloud** (gateway) model to run on a paid plan — chosen from your plan's roster via **LevelCode: AI: Select Model…** (the picker shows the live models with their credit multiplier + turns-left). Ignored on the free plan (always gpt-oss-120b) and in BYOK mode. The backend re-checks entitlement, so this can't over-reach your plan."
},
"levelcode.ai.includeActiveFile": {
"type": "boolean",
"default": true,
"description": "Automatically send the currently open file to the AI as context with each chat message."
},
"levelcode.ai.chat.autoContext": {
"type": "boolean",
"default": true,
"description": "Automatically find and include workspace files relevant to your chat question (via filename + symbol search)."
},
"levelcode.ai.chat.autoContextMaxFiles": {
"type": "number",
"default": 4,
"minimum": 0,
"description": "Maximum number of files auto-included as context per chat message."
},
"levelcode.ai.chat.scopeToActiveProject": {
"type": "boolean",
"default": true,
"description": "Limit auto-context search to the active file's top-level sub-folder, so unrelated sibling projects in the same workspace don't pollute results."
},
"levelcode.ai.chat.workspaceMap": {
"type": "boolean",
"default": false,
"description": "Include a list of all project file paths with each chat message, so the AI knows the repo structure. Uses more tokens."
},
"levelcode.ai.chat.startLocation": {
"type": "string",
"enum": [
"editor",
"none"
],
"enumDescriptions": [
"Open the chat as a centred editor tab.",
"Do not open the chat automatically."
],
"default": "editor",
"markdownDescription": "Where the chat opens when a window opens.\n\nThe default puts it in the centre, where the transcript gets the full reading column. This is only the *starting* position \u2014 **AI: Move Chat to Sidebar** (a button on the chat tab) and **AI: Open Chat in Editor** (a button in the sidebar) move it either way at any time, without changing this setting."
},
"levelcode.ai.chat.fontSize": {
"type": "number",
"default": 0,
"minimum": 0,
"maximum": 24,
"markdownDescription": "Font size for chat **prose** (message bodies), in pixels. `0` tracks the editor's UI font size, one step larger for reading — a 13px workbench gives 14px prose.\n\nThe workbench size is tuned for menu labels and tree rows; message bodies read a step above it so a long answer is comfortable. Controls, cards and the composer always match the workbench exactly. Values are clamped to 8–24."
},
"levelcode.ai.chat.proseWidth": {
"type": "number",
"default": 0,
"minimum": 0,
"maximum": 2000,
"markdownDescription": "Maximum width of the chat transcript, in pixels. `0` uses the default reading measure (680px) — it does **not** mean unconstrained.\n\nOnly has an effect when the panel is wider than the measure: in a narrow sidebar the container already bounds the line length. Raise it to let the transcript spread across a wide editor tab. Values are clamped to 320–2000."
},
"levelcode.ai.chat.groupActivity": {
"type": "boolean",
"default": true,
"description": "Fold consecutive agent actions (reads, edits, commands) into one collapsible activity card in the chat — the header shows the live step while running and a summary when done. Turn off for the flat, ungrouped timeline."
},
"levelcode.cloud.endpoint": {
"type": "string",
"default": "https://levelcode.ai",
"markdownDescription": "Base URL of your LevelCode Cloud host (Rails on Elastic Beanstalk) — one host serves sign-in, the account dashboard, AND the metered AI gateway. **Dev:** set to your ngrok URL, e.g. `https://thinly.ngrok.app`. **Prod:** `https://levelcode.ai`. Set to empty to make sign-in inert. In **BYOK** mode your keys never leave your machine."
},
"levelcode.cloud.apiUrl": {
"type": "string",
"default": "",
"markdownDescription": "Advanced: override the **backend API** base (metered gateway + token exchange) only if you split the API onto a different host from the website. Leave empty to use `levelcode.cloud.endpoint` (the normal one-host setup)."
},
"levelcode.ai.providerMode": {
"type": "string",
"enum": [
"byok",
"gateway"
],
"enumDescriptions": [
"Bring your own key — AI requests always go direct from your machine to your provider with your own key, even when you're signed in; your keys never touch LevelCode Cloud.",
"LevelCode Cloud gateway (default) — when you're signed in, AI runs through your metered LevelCode plan (no provider key needed) and automatically falls back to your own key (BYOK) when you're signed out."
],
"default": "gateway",
"markdownDescription": "How AI requests are routed. **gateway** (default): when you're signed in to LevelCode Cloud, requests run through your metered LevelCode plan via `levelcode.cloud.apiUrl` (the Rails backend) — no provider key required — and **automatically fall back to BYOK when you're signed out**, so simply signing in puts you on your plan with nothing to toggle. **byok**: always go direct to your provider with your own key, even when signed in. (The gateway is only ever used while signed in, so this default is safe when signed out.)"
},
"levelcode.ai.commandTimeout": {
"type": "number",
"default": 120000,
"description": "Backstop timeout in milliseconds before an approved shell command is force-killed (its whole process group). The Stop button on the terminal card is the primary control; set 0 to disable the backstop so long-running servers run until you stop them."
},
"levelcode.ai.contextWindow": {
"type": "number",
"default": 200000,
"description": "The model's context window in tokens, used for the in-chat context-usage meter and warning. Claude 4 models are 200000; raise to 1000000 if you've enabled the 1M-token context beta."
},
"levelcode.ai.debug": {
"type": "boolean",
"default": false,
"description": "Print detailed debug logs (every agent/chat action) inline in the chat, prefixed with 🐛 DEBUG. For diagnosing agent/chat issues. Off by default — when on, logs may include file contents, tool arguments, and full model responses, so avoid enabling it during screen-shares or recorded demos."
},
"levelcode.ai.agent.maxSteps": {
"type": "number",
"default": 25,
"minimum": 1,
"description": "Maximum tool-use steps the AI agent may take for one goal before stopping."
},
"levelcode.ai.agent.maxTokens": {
"type": "number",
"default": 8192,
"minimum": 1024,
"maximum": 32768,
"description": "Maximum output tokens per agent turn (agent mode only; chat/completions use levelcode.ai.claude.maxTokens). If a turn hits this cap mid-output the agent automatically continues in the next turn (so long answers/files aren't truncated), but raising it lets more come out in one turn. Capped at 32768 to bound worst-case spend across continuation turns."
},
"levelcode.ai.agent.autopilot": {
"type": "boolean",
"default": false,
"description": "Autopilot: let the agent run commands without asking, and prefer verifying its own work over pausing to ask you. It still stops and asks before anything hard to undo — deleting files, sudo, force-push / history rewrite, piping a remote script into a shell, publishing a package, or writing outside the project. File edits stay reviewable with Keep/Undo either way. Off by default."
},
"levelcode.ai.skills.enabled": {
"type": "boolean",
"default": true,
"description": "Let the agent self-select bundled skills (expert playbooks) for matching tasks like code review, bug fixes, and test writing. Each skill is a SKILL.md the agent loads on demand."
},
"levelcode.ai.sessions.enabled": {
"type": "boolean",
"default": true,
"description": "Save each chat/agent session to History so you can browse and reopen past work. Sessions are stored as plain-text JSONL files under levelcode.ai.sessions.dir (default ~/.levelcode/sessions), one folder per project, and listed with /sessions or the Sessions panel. Turn off to stop recording new sessions (existing files are left untouched)."
},
"levelcode.ai.sessions.dir": {
"type": "string",
"default": "",
"description": "Folder to store session History in. Empty = ~/.levelcode/sessions. Each project gets its own subfolder; the files are append-only JSONL you can back up, diff, or delete by hand.",
"scope": "machine"
},
"levelcode.ai.sessions.memory.enabled": {
"type": "boolean",
"default": true,
"description": "Project memory: as each session finishes, record a one-line outcome (what it did, which files, its state) to a per-project journal at memory/journal.jsonl, so future sessions can recall what past ones achieved. Plain text you own — greppable, editable, local. Turn off to stop recording outcomes."
},
"levelcode.ai.sessions.memory.summarize": {
"type": "boolean",
"default": true,
"description": "When a substantive session finishes, make one small, fast-model call to refine its journal outcome into a concrete sentence (what was built/fixed/decided) instead of just its goal headline. Runs in the background and only summarizes outcomes and actions, never quoted code. Turn off to skip the model call and keep the plain headline (no cost)."
},
"levelcode.ai.sessions.memory.recallTool": {
"type": "boolean",
"default": true,
"description": "Give the agent a recall_sessions tool so it can search this project's past-session outcomes on demand — e.g. when you ask \"what did we do about refunds?\" it looks up the earlier work instead of guessing. Read-only, searches only the local journal. Turn off to remove the tool."
},
"levelcode.ai.sessions.memory.facts": {
"type": "boolean",
"default": true,
"description": "Let the session summarizer also note durable project facts it observes — stable truths like \"the changelog is RELEASE-NOTES.md\" or a convention. Facts stay marked (inferred) and low-trust until they recur across sessions or you confirm them in the Memory panel, and are only ever outcomes/decisions, never secrets or code. Turn off to record outcomes only."
},
"levelcode.ai.sessions.autoArchiveDays": {
"type": "number",
"default": 30,
"minimum": 0,
"description": "Automatically archive sessions you haven't touched in this many days, to keep History focused on recent work. Archived sessions are hidden from the list but never deleted (the JSONL stays on disk), and pinned sessions are always kept. Set to 0 to turn auto-archiving off."
},
"levelcode.ai.sessions.resumeBudgetPct": {
"type": "number",
"default": 40,
"minimum": 5,
"maximum": 100,
"description": "When you resume a session, the share of the model's context window its restored transcript may fill before it is summarized to fit. Lower = resume with less history (cheaper, faster); higher = carry more of the past conversation verbatim. The full transcript is always kept on disk and shown in the replay regardless."
},
"levelcode.ai.verify.enabled": {
"type": "boolean",
"default": true,
"description": "After the agent finishes editing, automatically verify its work — pull editor diagnostics (type/lint errors) for the files it changed and, if a verify command is set, run it — then feed any failures back so the agent self-corrects until clean (bounded by levelcode.ai.verify.maxRounds)."
},
"levelcode.ai.verify.command": {
"type": "string",
"default": "",
"markdownDescription": "Optional one-shot command run to verify the agent's edits (e.g. `npm run typecheck`, `npm test`, `npm run lint`). It MUST exit on its own — do **not** use a dev server or watch command (those block; the `commandTimeout` backstop force-kills them). Leave empty to verify with editor diagnostics only."
},
"levelcode.ai.verify.maxRounds": {
"type": "number",
"default": 2,
"minimum": 0,
"description": "How many times the agent may be sent back to fix failing verification before it stops and hands the remaining problems to you. 0 = report-only (verification still runs and is shown, but the agent won't auto-retry)."
},
"levelcode.ai.verify.includeWarnings": {
"type": "boolean",
"default": false,
"description": "Treat editor warnings (not just errors) as verification failures the agent must fix. Off by default — only errors block."
},
"levelcode.ai.preview.autoOpen": {
"type": "boolean",
"default": true,
"markdownDescription": "When the agent starts a web server in the background, automatically open the site in LevelCode's built-in browser, beside the chat.\n\nOnly **local** addresses are ever opened — `localhost`, `127.0.0.1`, or the IPv6 loopback `[::1]`. The bind addresses `0.0.0.0` and `[::]` count as local and are shown as `localhost`, since a browser can't resolve them. A remote URL printed by a dev script is ignored, never opened.\n\nEach address opens at most once per session, so closing the tab is respected, and your focus is never taken. Turn this off to open previews yourself with **Simple Browser: Show**."
},
"levelcode.ai.mcp.servers": {
"type": "object",
"default": {},
"scope": "application",
"markdownDescription": "MCP servers the agent may use, as `{ \"name\": { \"command\": \"…\", \"args\": […], \"env\": {…} } }` (a `mcpServers` wrapper is also accepted). Each entry names **a process LevelCode will run with your privileges**, so add only servers you trust.\n\nExample:\n```json\n{ \"filesystem\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/path\"] } }\n```\n\n**User-settings only** (application-scoped): a repo's committed `.vscode/settings.json` cannot set this, so opening an untrusted repo can never make LevelCode spawn a process. Servers defined in a repo's `.levelcode/mcp.json` are likewise read and listed but **never started** — its approval step ships in a later release."
},
"levelcode.ai.mcp.toolPolicy": {
"type": "object",
"default": {},
"scope": "application",
"markdownDescription": "Which MCP tools may run, as `{ \"server__tool\": \"allow\" | \"ask\" }` — use `\"*\": \"allow\"` for all of them. Tool names are namespaced `server__tool` exactly as they appear in the chat.\n\n**User-settings only** (application-scoped): a repo cannot set this to auto-allow its own tools. Anything not allow-listed is **refused**, including under Autopilot: an MCP tool is third-party code, so Autopilot deliberately does not relax this. A server's own `destructiveHint` overrides an `allow` here — server hints may only ever tighten, never loosen."
},
"levelcode.ai.completions.enabled": {
"type": "boolean",
"default": true,
"description": "Show inline AI code completions (ghost text) as you type. Accept with Tab."
},
"levelcode.ai.completions.model": {
"type": "string",
"enum": [
"claude-haiku-4-5-20251001",
"claude-sonnet-4-6",
"claude-opus-4-8"
],
"enumDescriptions": [
"Claude Haiku 4.5 (fastest — recommended)",
"Claude Sonnet 4.6 (balanced)",
"Claude Opus 4.8 (most capable, slower)"
],
"default": "claude-haiku-4-5-20251001",
"description": "Claude model used for inline completions. A fast model is recommended for low latency."
},
"levelcode.ai.completions.debounce": {
"type": "number",
"default": 150,
"minimum": 0,
"description": "Idle time in milliseconds before requesting an inline completion (lower = snappier but more requests)."
},
"levelcode.ai.claude.model": {
"type": "string",
"enum": [
"claude-opus-4-8",
"claude-sonnet-4-6",
"claude-haiku-4-5-20251001"
],
"enumDescriptions": [
"Claude Opus 4.8 (most capable)",
"Claude Sonnet 4.6 (balanced)",
"Claude Haiku 4.5 (fastest)"
],
"default": "claude-sonnet-4-6",
"description": "Claude model to use."
},
"levelcode.ai.claude.maxTokens": {
"type": "number",
"default": 4096,
"minimum": 256,
"description": "Maximum tokens in a Claude chat/completion response. (Agent turns use the separate levelcode.ai.agent.maxTokens setting.)"
},
"levelcode.ai.ollama.url": {
"type": "string",
"default": "http://localhost:11434",
"description": "Base URL of your local Ollama server."
},
"levelcode.ai.ollama.model": {
"type": "string",
"default": "llama3.1",
"description": "Ollama model name (must be pulled locally, e.g. `ollama pull llama3.1`)."