Project Files
README.md
vibeLM is a local-first agentic plugin for LM Studio.
It gives a model practical tooling for real work:
The goal is simple: keep the model useful in long, read-heavy sessions without forcing the user to switch tools or lose important context.
vibeLM turns a local LM Studio model into a real agent instead of a chat-only assistant. It is built to do multi-step work, manage files, inspect a workspace, and keep track of what happened without relying on cloud infrastructure.
That matters because the workflow is different from cloud LLMs. With a smaller model like Qwen3 4B, the agent can still execute useful tool flows, but the work is more fragmented and the context has to be managed carefully. With a stronger local model like GLM 4.6 Flash, Qwen3.5, or Gemma 4 E, vibeLM can sustain more reliable multi-step orchestration and keep the session moving.
It doesn't pretend local models behave like hosted frontier systems โ it makes them genuinely useful for agentic work, with scoped memory, explicit workspace access, compact session handoff, and a prompt budget gate that fails early instead of blowing up mid-session.
| Area | Tools |
|---|---|
| Workspace | set_workspace, get_config |
| Files | list_files, read_file, write_file, append_file, rename_file, search_files, delete_file |
| Shell | bash_terminal |
| Memory | save_memory, search_memory, list_memories, update_memory, delete_memory, clear_memories |
| Context |
create_plan registers a structured, ordered list of steps toward a goal instead of leaving the model to narrate a plan in prose and stop. The model is expected to execute each step itself with its other tools (bash_terminal, file tools, etc.), calling update_plan_step as it goes:
vibe_bridge keeps the session alive without user input by periodically injecting a prompt into the chat. Enabling the tools.vibe_bridge toggle in plugin settings auto-starts it with the configured defaults below โ no chat message needed. The tool is still available for starting it with different one-off settings, checking status, or stopping it early.
In LM Studio plugin settings (tools.*):
| Setting | Type | Default | Description |
|---|---|---|---|
tools.maxEffectiveContextTokens | number | 0 | Optional hard cap on the budgeting window. 0 = use the model's actual loaded context length (read automatically). Raise it only if your machine can't sustain even the configured length. |
tools.reasoningEffort | select | off | Calibrates model thinking: off/low/medium/high, each level a distinct directive. gpt-oss uses native Harmony tiers (off floors to low, Harmony has no lower tier), Qwen uses the /no_thinkยท/think switch with a graduated brief/moderate/thorough qualifier appended, others get a graduated natural-language nudge. |
tools.compactionTriggerPercent | number | 30 | How full the context gets (% of the loaded window) before vibeLM auto-compacts older history into memory (10โ90). Higher keeps more live context; lower compacts earlier. |
tools.maxThinkingSteps | number | 8 | Max prediction rounds per unattended vibe_bridge tick, so a model stuck reasoning without calling a tool can't run unbounded (1โ50). |
Each keep-alive tick can call a curated set of tools (explore/list/read/write/append/search files, save/search memory, web fetch/search). bash_terminal is intentionally excluded from unattended ticks until it has a command allowlist (see Security below). Each tick is capped at Max Thinking Steps prediction rounds (default 8, configurable via tools.maxThinkingSteps) and a 3-minute timeout, so a model stuck reasoning without calling a tool is canceled and counted as a failed tick rather than blocking subsequent ticks indefinitely.
vibeLM stores its runtime config, session state, and memory log in extensions/data, not extensions/plugins โ the plugin install directory gets wiped on every lms dev --install, so persistent data lives outside it:
Example config.json:
Set it from the plugin with set_workspace.
See CHANGELOG.md for the full release history.
v0.1.0. The release workflow should build, test, and attach a plugin artifact.lms push from the plugin directory after logging in to LM Studio.vibe-lm because LM Studio expects kebab-case.owner field in manifest.json before pushing.../ are rejected.read_file.calculate uses , not raw code execution.compact_context |
| Web | web_fetch, web_search |
| Math & Time | calculate (mathjs), get_current_datetime |
| Utilities | generate_uuid, generate_password, encode_base64, decode_base64 |
| Infrastructure | ssh_exec, check_service |
| Response control | amend |
| Planning | create_plan, update_plan_step, get_plan โ structured multi-step execution, enforced before amend can close out |
| Autonomy | vibe_bridge โ self-recalling autonomous loop for keep-alive sessions |
amend refuses to close out the session while the plan still has untouched (pending) steps โ it points the model back at its own tools instead of letting it hand off a plan it never executed. Steps already attempted and marked in_progress or blocked do not block amend, so a model that got genuinely stuck can still report back.create_plan accepts autoStart (default true): if vibe_bridge is enabled, creating a plan starts it automatically so unattended ticks keep making progress on the plan's next pending step โ this is the "long-running execution" path for multi-step work.vibe_bridge tick that runs while a plan is active gets the next pending step named explicitly in its prompt, and has update_plan_step/get_plan available so it can mark progress. bash_terminal is still excluded from unattended ticks (see Security below), so shell-dependent plan steps need an interactive turn to execute.thinking override (off/low/medium/high, same values as tools.reasoningEffort) as either { description, thinking } in create_plan or a thinking argument to update_plan_step. While a step is current โ the first in_progress step, or failing that the first pending one โ its override wins over the session-wide tools.reasoningEffort setting, so a plan can mark mechanical steps off and a genuinely tricky step high instead of applying one uniform level to every step.tools.vibe_bridge | boolean | false | Enable the tool and auto-start it with the settings below |
tools.vibe_bridge_prompt | string | "Check progress to reach your goal, if you are failing adjust trajectory." | Default injection prompt |
tools.vibe_bridge_interval | number | 600 | Seconds between injections |
tools.vibe_bridge_maxDuration | number | 21600 | Max total runtime in seconds (0=unlimited) |
compact_context compresses long sessions into reusable state for memory, not live chat deletion.compact_context returns a copy-paste handoff block for starting a fresh chat with the summary.session, workspace, research, or all.get_config shows the current prompt-budget estimate, safety margin, and overflow risk.tools section.maxOrchestratorTurns defaults to 50, accepts values from 0 to 100, and 0 disables the hard turn cap.Rolling Window Trigger Limit (prompt tokens) controls the maximum prompt size before vibeLM switches to rolling-window behavior. Set it to 0 to auto-derive the trigger from the selected model's context window minus a safety margin.loaded_context_length in the REST API), not the model's larger max ceiling. This is what makes auto-compaction fire in time: e.g. a model loaded at 40K compacts around 12K and warns around 20K, instead of never triggering because it assumed a 256K window.Max Effective Context (tokens) is an optional hard cap on top of that. Default 0 uses the loaded window as-is. Set it only if your machine can't sustain even the configured length (e.g. a large vision model whose KV cache exhausts unified memory โ note KV-cache quantization is not available for VLMs); vibeLM will then compact against this lower ceiling.Reasoning Effort calibrates how much the model "thinks" before answering: off suppresses extended reasoning (leanest sessions, avoids reasoning-loop hangs), low/medium/high each produce a distinct, increasingly explicit directive to reason more thoroughly. Qwen models honor the /no_think//think soft switch (with a graduated qualifier for the three "on" tiers, since the chat template itself only has a binary toggle); other architectures receive an equivalent graduated natural-language directive. The directive is applied to both interactive turns and unattended vibe_bridge ticks.
reasoning_tokens: 1 under /no_think), but some newer architectures โ Gemma-4-thinking, the Phi-4-reasoning family, Nemotron-H โ keep reasoning through a separate reasoning_content channel regardless of the directive, NVIDIA's own "detailed thinking off" convention, or even LM Studio's native reasoning REST setting (which outright rejects "off" for phi-4-mini-reasoning: "Supported settings: 'on'"). For these, off won't reduce latency โ but vibe_bridge still gives them a generous maxTokens floor (6000) so a long reasoning phase can't crowd out the tick's actual answer.tools section also exposes on/off toggles for the individual tools, so you can disable capabilities you do not want the orchestrator to use.amend is gated so the orchestrator does not stop too early.mathjsbash_terminal runs with user-level permissions, through your login shell ($SHELL -ilc) so it
sees the same PATH a real terminal would โ including anything added by nvm, Homebrew, asdf, etc.create_plan({
goal: "Set up a nightly backup of /data",
steps: [
"Check what's installed: which cron crontab",
{ description: "Design the backup retention policy", thinking: "high" },
"Write backup script to /data/backup.sh",
"Register the crontab entry",
"Verify with crontab -l",
],
})
update_plan_step({ index: 0, status: "done" })
update_plan_step({ index: 2, status: "blocked", note: "crontab requires sudo, need user confirmation" })
get_plan()
# Start with custom settings (overrides the auto-started defaults for this run)
vibe_bridge({
action: "start",
prompt: "Continue implementing the feature",
interval: 600, # every 10 minutes
maxDuration: 21600 # stop after 6 hours
})
# Check status
vibe_bridge({ action: "status" })
# Stop
vibe_bridge({ action: "stop" })
lms clone drunkktoys/vibe-lm
# or clone from source:
git clone https://github.com/DrunkkToys/vibeLM.git
npm install
npm run build
npm run dev # lms dev (hot reload)
npm test # unit + integration coverage
~/.lmstudio/extensions/data/drunkktoys/vibe-lm/config.json
~/.lmstudio/extensions/data/drunkktoys/vibe-lm/runtime-state.json
~/.lmstudio/extensions/data/drunkktoys/vibe-lm/session-log.jsonl
{ "workspacePath": "/Users/you/my-project" }