A privacy-first, AI-native development environment for your local machine.
Code. Chat. Terminal. Browser. All in one window — no cloud required.
nolock's opinionated feature set is crafted to preserve cognitive load and maintain engineers' full ownership of their codebase. It leverages AI assistance without fostering over-reliance on LLM outputs — designed especially for Computer Science, Software Engineering, and technically-focused students who want to stay firmly in the driver's seat while avoiding excessive automation.
nolock is a desktop IDE that puts you in full control. It combines a full-featured code editor (powered by Monaco), a real terminal emulator, an AI agent chat panel, a native web browser, and a workspace-wide file search — all running locally with no telemetry, no accounts, and no lock-in.
Connect it to your preferred AI backend (Ollama, llama.cpp, OpenRouter, or OpenCode Zen) for inline code completions and agentic chat with tool-calling capabilities (web search, file read, directory listing).
nolock is built on the shoulders of many incredible open-source projects. Below is a breakdown of what each one does and how it's used.
| Technology | What it is | How nolock uses it |
|---|---|---|
| React 18 | A declarative, component-based UI library for building interactive user interfaces. | Drives the entire user interface — file explorer, editor tabs, chat panel, settings modals, and status bar. |
| TypeScript | A typed superset of JavaScript that compiles to plain JavaScript. | All frontend code is written in TypeScript for better developer experience, type safety, and maintainability. |
| Vite | A fast build tool and development server with hot module replacement. | Serves the frontend during development and produces optimized production bundles. |
| Monaco Editor | The same code editor that powers VS Code — a browser-based code editor with syntax highlighting, IntelliSense, and multi-language support. | Provides the main code editing experience with file-type detection, bracket colorization, minimap, and inline AI completions. |
| xterm.js | A fully-featured terminal emulator implemented in JavaScript that runs in the browser. | Renders the integrated terminal panel with full VT100/xterm escape sequence support, themes, and cursor handling. |
| marked | A low-level Markdown compiler built for speed. | Renders AI assistant responses with rich formatting — code blocks, headings, lists, inline code, and links. |
| js-tiktoken | A JavaScript port of OpenAI's tiktoken tokenizer, using the cl100k_base encoding. | Counts tokens in file contents and chat messages to provide context window awareness in the AI chat panel. |
| Vitest | A blazing-fast unit test framework powered by Vite. | Runs the frontend test suite (components, utilities, and integration tests). |
| @testing-library/react | Lightweight utilities for testing React components in a user-centric way. | Provides DOM-based testing utilities for React component tests. |
| Technology | What it is | How nolock uses it |
|---|---|---|
| Tauri 2 | A framework for building desktop applications with a web frontend and a Rust backend. | The core application framework — manages windows, system tray, native menus, IPC between frontend and backend, and application lifecycle. |
| serde / serde_json | A serialization/deserialization framework for Rust. | Handles all JSON serialization for IPC commands, AI API requests/responses, and configuration persistence. |
| reqwest | An ergonomic, batteries-included HTTP client for Rust. | Makes HTTP requests to AI backends (Ollama, llama.cpp, OpenRouter, OpenCode Zen) for chat completions, code completions, and model information. |
| portable-pty | A cross-platform PTY (pseudo-terminal) library for Rust that works on Linux, macOS, and Windows. | Spawns and manages real interactive shell sessions (bash, zsh, etc.) with proper terminal dimensions, resizing, and signal handling. |
| regex | A Rust library for regular expression matching. | Powers workspace-wide file search with regex mode, case-insensitive matching, and batch find-and-replace across files. |
| wry | A cross-platform webview rendering library used by Tauri. | On Linux, creates a native GTK-based webview overlay for the in-app browser panel (supporting sites that block iframes). |
| GTK3 (gtk-rs) | Rust bindings for the GTK 3 toolkit. | On Linux, manages a GtkOverlay + GtkFixed widget setup to position the native browser webview precisely within the application layout. |
| Technology | What it is | How nolock uses it |
|---|---|---|
| Ollama | A local server for running large language models on your own machine with a simple REST API. | Supports both inline code completions (via /api/generate with Fill-In-The-Middle) and multi-turn chat (via /api/chat) with tool calling. |
| llama.cpp | A C/C++ implementation of LLM inference optimized for consumer hardware. | Supports code completions via its /completion endpoint with Fill-In-The-Middle support. |
| OpenRouter | A unified API gateway that provides access to dozens of AI models from multiple providers. | Supports chat completions and tool calling through the OpenAI-compatible /chat/completions endpoint. |
| OpenCode Zen | An AI inference service with some models offering a generous free tier. | Supports code completions and chat via its /api/generate endpoint. |
| Technology | What it is | How nolock uses it |
|---|---|---|
| DuckDuckGo Instant Answer API | A free, no-API-key search API that returns topic summaries, definitions, and related topics as JSON. | Powers the web_search tool in Agent Chat — enables the AI to discover relevant URLs before fetching page content with web_fetch. No signup, no cost, privacy-respecting. |
| Brave Search API | A privacy-focused web search API that returns real web search results (titles, URLs, descriptions). | Optional alternative to DuckDuckGo for the web_search tool — provides full web search results with better coverage for technical queries. Requires a free API key from Brave Search API. |
- Code Editor — Full-featured Monaco editor with syntax highlighting for 100+ languages, bracket colorization, minimap, word wrap, and inline linting (ESLint for TypeScript/JavaScript, Ruff for Python, Clippy for Rust) with configurable rules via Ctrl+E, S.
- File Search & Replace — Search across all workspace files with regex support, match-case toggles, debounced live results, grouped by file with inline match previews, and batch replace-all with confirmation.
- AI Inline Completions — Fill-In-The-Middle (FITM) code suggestions from your local AI backend, debounced and triggered on typing pauses.
- Agent Chat — Multi-turn conversational AI chat with file referencing (
@mentions), tool calling (web search, web fetch, file read, directory listing, grep, edit, write_file), custom tools via.tools/, and context token tracking. - AI Agent Manager — Create and manage specialized AI agents (e.g., code-reviewer, doc-writer) stored as
.mdfiles (Markdown with YAML frontmatter) in the.agents/directory with custom system prompts. Legacy.jsonformat is still supported. - Hooks — Project-local automation rules (
.hooks/) that trigger AI agent runs on CLI commands (e.g.git commit), cron schedules, or manual!hook-namesignals. Open via Ctrl+A, H. - Human Feedback (RLHF) — Collect thumbs-up/thumbs-down (KTO) and pairwise preference (DPO) feedback on AI chat responses. KTO and DPO data live in separate top-level directories under
.rlhf/, each partitioned by model configuration, ready for downstream RLHF training. Enable/disable via Ctrl+A, R. - Integrated Terminal — Real PTY-based shell sessions with multiple tabs, resize support, and command history tracking.
- Terminal Memory — Automatically records commands, tracks frequency, and lets you organize commands into categories for quick recall.
- File Explorer — Tree-based file browser with directory expansion, refresh, file-type color coding, and file/directory CRUD operations (create, rename, delete, copy).
- Native Browser Panel — Embedded web browser using a native OS webview (not an iframe) — browse any site without leaving the app.
- Resizable Panels — All panels (explorer, editor, terminal, browser, chat) are fully resizable with drag handles.
- Multi-Backend AI — Switch between Ollama, llama.cpp, OpenRouter, and OpenCode Zen for completions and chat.
- Privacy-First — No telemetry, no accounts, no cloud dependency. Everything runs on your machine.
Large language models are typically fine-tuned on general internet text, not on your coding preferences. Out of the box, an AI assistant might be too verbose, too terse, too eager to generate boilerplate, or simply wrong in domain-specific ways. The most effective way to align a model to your standards is to show it what you consider good and bad — but collecting that feedback is usually the bottleneck.
nolock's RLHF system solves this by instrumenting the AI chat panel with two lightweight feedback mechanisms that integrate directly into your natural coding workflow. The collected data is stored in a structured, portable format that can be used to fine-tune any compatible model.
RLHF is a family of techniques that use human preference data to align language model outputs with human values, style, and correctness. The core idea is simple: instead of trying to write a perfect system prompt that covers every edge case, you let the model generate responses and then tell it which ones are better. Over enough examples, the model learns to prefer the patterns you reward.
nolock's RLHF system collects training data in two complementary formats:
KTO (named after psychologists Daniel Kahneman and Amos Tversky) is a binary preference method. For each AI response, you give a simple thumbs-up or thumbs-down:
- Thumbs-up → saved as a "good" example (label:
true) - Thumbs-down → saved as a "bad" example with an optional correction describing what was wrong (label:
false)
KTO is lightweight and requires no extra AI calls — it piggybacks on your normal chat usage. Every rating you give becomes a training example. The optional correction text serves as a natural-language signal for what a better response would look like.
DPO (Direct Preference Optimization) is a pairwise preference method that captures more nuanced judgements. Instead of rating a single response, you compare two alternative responses and pick the better one:
- What happens: Every N user messages (configurable in RLHF settings), the AI generates two responses instead of one. The second response uses a slightly higher temperature (+0.2) to produce meaningful diversity.
- You choose: A side-by-side comparison UI lets you pick which response is better (Response A or Response B). The pair (chosen + rejected) is saved as a DPO training example.
- Why it matters: Pairwise comparisons are statistically more reliable than absolute ratings. DPO also avoids the complexity of training a separate reward model (as used in traditional RLHF with PPO), making it practical for individual developers and small teams.
All feedback is stored as JSONL (one JSON object per line) under the project's .rlhf/ directory. KTO and DPO data live in separate top-level directories with independent structures, mirroring the formats expected by their respective training frameworks:
<project>/.rlhf/
kto/ ← Thumbs-up/down (KTO) data
good/
<provider>_<model>/data.jsonl ← KTO desirable examples
bad/
<provider>_<model>/data.jsonl ← KTO undesirable examples
dpo/ ← Pairwise preference (DPO) data
<provider>_<model>/data.jsonl ← DPO chosen/rejected pairs
Each model configuration gets its own subdirectory (e.g., ollama_qwen3_8b), making it easy to train on data from specific models. The JSONL schemas follow the standard formats expected by KTO and DPO training scripts:
KTO entry:
{
"prompt": "What is Rust?",
"completion": "Rust is a systems language.",
"label": true,
"model_provider": "ollama",
"model_name": "qwen3.5:0.8b-mlx",
"model_configurations": { "temperature": 0.7, "max_tokens": 2048, "system_prompt": "" },
"timestamp": "2026-06-26T12:00:00.000Z"
}DPO entry:
{
"prompt": "What is Rust?",
"chosen": "Rust is a systems language focused on safety.",
"rejected": "Rust is a programming language.",
"model_provider": "ollama",
"model_name": "qwen3.5:0.8b-mlx",
"model_configurations": { "temperature": 0.7, "max_tokens": 2048, "system_prompt": "" },
"timestamp": "2026-06-26T12:00:00.000Z"
}-
Privacy-first, always: All feedback data stays on your machine — in your project's
.rlhf/directory. There is no telemetry, no cloud upload, and no third-party access. You own your preference data completely. -
No extra workflow burden: Thumbs-up/down buttons appear naturally on every AI response. DPO prompts happen at configurable intervals. Feedback collection is woven into the chat experience, not a separate chore.
-
Portable and framework-ready: The JSONL format matches the DPO and KTO dataset schemas used by Hugging Face TRL (v1.8.0). Export your
.rlhf/directory to TRL, Axolotl, or LLaMA Factory — no conversion needed. -
Model-configuration aware: Because data is partitioned by provider + model (e.g.,
ollama_qwen3_8bvsopenrouter_gpt-4o), you can train separate adapters for different models or analyze which backends produce the most preferred responses. KTO and DPO data are stored independently, so you can use each method on its own or combine them sequentially. -
Aligned with nolock's philosophy: nolock is designed to keep you in the driver's seat. RLHF isn't about automating away your judgement — it's about amplifying it. The AI learns from your preferences, not from generic alignment data collected by a corporation.
Press Ctrl+A, R to open the RLHF settings panel. There you can:
- Toggle feedback collection on/off
- Configure the root directory and category subdirectories
- Enable DPO pairwise mode and set the prompt interval
- Review the expected file structure for your settings
Every AI chat response will then show thumbs-up and thumbs-down buttons. If DPO is enabled, the system will automatically generate two responses at the configured interval for you to compare.
The collected JSONL data is ready for fine-tuning with Hugging Face TRL (trl==1.8.0). See .rlhf/README.md for complete DPO and KTO training guides with example scripts.
Hooks are project-local YAML files in .hooks/ that automatically invoke an AI agent run when a trigger fires. They let you automate repetitive agentic workflows without leaving the editor — for example, reviewing your code right after git commit, generating a daily standup summary, or running a custom routine whenever you type a particular command.
Hooks come in three trigger flavors:
| Trigger | When it fires |
|---|---|
| Command | After a CLI command whose leading words match a pattern — whether you run it in the terminal or the AI agent runs it via its bash_sandbox tool. |
| Cron | On a repeating schedule (5-field cron expression) while nolock is open. |
| Manual | When you type !hook-name in the chat panel, or press Run now in the Hooks panel. |
Open the Hooks panel with Ctrl+A, H (AI Integrations → Hooks) and click New Hook. Give it a name, choose a trigger, optionally attach an agent/prompt/skills/tools, and save. The backend writes a .hooks/<name>.yaml file into your project.
name: commit-review
description: Review what you are about to commit.
trigger:
type: command # command | cron
command: git commit
# type: cron
# schedule: "0 9 * * 1-5"
agent:
name: code-reviewer # optional: reuse an existing agent's system prompt
prompt: | # optional: inline system prompt (takes precedence)
You are a git-review hook...
skills: [code-review]
tools: [read_file, grep]Field reference:
| Field | Description |
|---|---|
name |
Hook identifier (letters, numbers, -, _, .). Becomes the file name. |
description |
Optional human-readable description. |
trigger.type |
command or cron. |
trigger.command |
(command) Word-prefix pattern — git commit matches git commit -m "x", not git committed. |
trigger.schedule |
(cron) 5-field cron: minute hour day-of-month month day-of-week. |
agent.name |
Optional existing agent from .agents/ whose system prompt is reused. |
agent.prompt |
Optional inline system prompt; takes precedence over agent.name. |
agent.skills |
Skill names from .skills/ to inject into the run context. |
agent.tools |
Explicit tool ids to enable. Empty = use your currently enabled tools. |
- Runs execute through the
ai_chatcommand using your configured chat model and backend. They are non-streamed — while a hook runs you'll see a live "hook run card" (spinner) in the chat panel, and the chat input is temporarily disabled. - Hook runs and chat generations are serialized: a hook waits in the queue while a chat response is in flight, and chat is paused while a hook runs. This avoids collisions on the shared stream event.
- A finished run's output is appended to the chat thread as a "Hook result" message (showing the hook name, trigger reason, and the agent's output rendered as markdown). Failed runs appear as a "Hook failed" error block. These messages stay in the conversation and are sent back to the model as system context on later messages, so you can ask follow-up questions about what a hook produced.
- Cron hooks are checked every ~10 seconds while the app is open and fire at most once per matching minute. They do not run when nolock is closed.
- Command triggers match whole leading words, so scope them deliberately:
git pushmatchesgit push origin main, while a hook forgitalone would fire on every git command. - Use
!hook-namein the chat panel to trigger any hook manually without opening the Hooks panel.
nolock would not exist without the following open-source projects and communities:
-
Hugging Face TRL — The Transformer Reinforcement Learning library that provides state-of-the-art implementations of alignment methods (DPO, KTO, PPO, and more). nolock's RLHF dataset formats are designed to be directly compatible with TRL's DPOTrainer and KTOTrainer.
-
OpenCode Zen — For providing an AI inference service with a generous free tier that made autonomous development workflows possible without any API costs. This project was built primarily using the Big Pickle model (
opencode/big-pickle).Cost Tracker: This project has incurred $0.00 USD in AI API costs to date. All development was powered entirely by OpenCode Zen's free Big Pickle model.
-
OpenRouter — For building a unified API that makes dozens of AI models accessible from a single endpoint.
-
Ollama — For making local LLM deployment as simple as a single command, enabling private and offline AI-powered development.
-
llama.cpp — For the incredible engineering achievement of running state-of-the-art LLMs efficiently on consumer hardware.
-
DuckDuckGo — For providing a free, no-API-key Instant Answer API that powers the
web_searchtool in Agent Chat. Results from DuckDuckGo. -
Brave Search — For providing a privacy-focused web search API with real web search results, enabling the optional
web_searchtool backend for more comprehensive coverage.
And to all the open-source projects listed above — Monaco Editor, React, Tauri, xterm.js, and every other library that makes this possible. Thank you.
Before installing nolock, ensure you have the following:
- Node.js 18+ — Download
- Rust toolchain — Install Rust
- Tauri system dependencies — See Tauri prerequisites
# Clone the repository
git clone https://github.com/your-username/nolock.git
cd nolock
# Install JavaScript dependencies
npm install
# Build and bundle the application
npm run tauri build| Application | Package Type | Size | vs. nolock |
|---|---|---|---|
| nolock | .deb |
8.3 MB | — |
| VS Code | .deb |
~100 MB | ~12× larger |
| OpenCode Desktop | .deb |
~107 MB | ~13× larger |
| OpenCode CLI | .tar.gz |
~49 MB | ~6× larger |
nolock is significantly smaller than comparable development tools. The .deb package is only 8.3 MB — roughly the size of a single high-resolution photo — while the uncompressed binary is 21 MB. This tiny footprint is achieved through a lean technology stack (Tauri + Rust + webview) that avoids bundling an entire browser runtime, unlike Electron-based editors.
After building, install the .deb package:
# Install the deb package
sudo dpkg -i src-tauri/target/release/bundle/deb/nolock_0.1.0_amd64.deb
# If there are missing dependencies, fix them:
sudo apt-get install -fOr run the binary directly without installing:
./src-tauri/target/release/nolockThe application will be available in your app launcher as nolock after installation.
Note: On Linux, the native browser panel uses a GTK overlay widget for precise positioning. This works on all major Linux desktop environments (GNOME, KDE, XFCE, etc.).
After building on a Mac, you have two options:
Option A — Drag-and-drop DMG:
# Open the DMG installer
open src-tauri/target/release/bundle/dmg/nolock_0.1.0_x64.dmg
# Then drag nolock into the Applications folderOption B — Direct .app bundle:
# Copy the app bundle to Applications
cp -R src-tauri/target/release/bundle/macos/nolock.app /Applications/Then open nolock from your Applications folder or Spotlight.
Note: macOS builds require a Mac with Xcode installed. If you're on Linux but want a macOS build, you can use GitHub Actions with a macOS runner (see the CI workflow).
After installation, configure your preferred AI backend:
- Open nolock and press
Ctrl+A, I(or go to AI Integrations → Settings). - Select your backend:
- Ollama — Default, runs locally at
http://localhost:11434 - llama.cpp — Runs locally at
http://localhost:8080 - OpenRouter — Requires an API key from openrouter.ai
- OpenCode Zen — Remote at
https://opencode.ai/zen/v1, some models available with a free tier
- Ollama — Default, runs locally at
- Enter your model names and save.
For the best experience with nolock, here are the recommended Ollama models for each AI feature:
| Feature | Recommended Model | Size | Notes |
|---|---|---|---|
| Code Completions (FITM) | qwen2.5-coder:0.5b |
0.5B params | Fast, lightweight fill-in-the-middle completions. Runs on CPU or low-end GPU. |
| Agent Chat (Tool Calling) | qwen3.5:0.8b-mlx |
0.8B params | Reliable tool-calling with strong reasoning. Good for web search, file read, directory listing, and multi-step agent tasks. |
Installation:
ollama pull qwen2.5-coder:0.5b
ollama pull qwen3.5:0.8b-mlxThen in nolock's AI Settings (Ctrl+A, I):
- Set Completion Model to
qwen2.5-coder:0.5b - Set Chat Model to
qwen3.5:0.8b-mlx
Note: For agent chat with tool calling, the model must support the
toolsparameter in Ollama's/api/chatendpoint. Theqwen3.5:0.8b-mlxmodel provides a good balance of capability and resource usage. Larger models will provide better results at the cost of higher resource usage.
| Shortcut | Action |
|---|---|
Ctrl+E, O |
Toggle file explorer |
Ctrl+E, S |
Open editor settings (linter configuration) |
| Shortcut | Action |
|---|---|
Ctrl+F, S |
Toggle file search |
Ctrl+F, O |
Open folder |
Ctrl+F, E |
Toggle file explorer |
Ctrl+F, R |
Refresh explorer |
Within the search panel (Ctrl+F, S):
| Key | Action |
|---|---|
Escape |
Close search panel |
Enter |
Trigger search immediately (bypasses debounce) |
| Click result line | Open file at that line |
| Shortcut | Action |
|---|---|
Ctrl+T, O |
New terminal |
Ctrl+T, M |
Open terminal memory overlay |
| Shortcut | Action |
|---|---|
Ctrl+A, O |
Toggle agent chat panel |
Ctrl+A, P |
Model providers |
Ctrl+A, M |
Chat model settings |
Ctrl+A, F |
FITM model settings |
Ctrl+A, T |
Agent tools |
Ctrl+A, G |
Manage AI agents |
Ctrl+A, K |
Manage skills |
Ctrl+A, R |
Human feedback (RLHF) |
Ctrl+A, H |
Manage hooks |
Ctrl+A, I |
Open AI settings |
| Shortcut | Action |
|---|---|
Ctrl+B, O |
Toggle browser panel |
| Shortcut | Action |
|---|---|
Ctrl+O |
Open folder |
Ctrl+R |
Refresh explorer |
Ctrl+S / Cmd+S |
Save current file |
Escape |
Close overlays / panels |
Built with ❤️ for local-first, privacy-respecting development.