Skip to content

About

Local-first AI coding workspace. Chat with your codebase, propose safe patches, iterate — without your code leaving your machine. Ollama · Tauri · React · Rust.

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

CODEYANTRA — Your AI pair-programmer that runs entirely on your laptop.

CodeYantra reads your codebase, proposes safe patches, and iterates with you — without a single byte ever leaving your machine.

"Walk me through this repo." · "Why does every item show up as 'other' in @categorize.py?" · "Add a --csv flag and update the summary." · "Review my current git diff — anything wrong?" CodeYantra answers, refactors, writes tests, and drafts patches from prompts like these using a local coder model (Qwen / DeepSeek / CodeLlama) via Ollama. It has file-tree awareness, git awareness, an approval-gated patch engine, and a quality checker that runs before every apply — all on your device.

License: MIT Shell UI Core LLM Privacy

Free local AI · No cloud · No accounts · No telemetry · No token bill. Part of the Free AI. Real Problems. Every Sunday. series.

Repo layout: apps/desktop/ (Tauri + React shell), packages/shared/ (types, zod validation), packages/agent/ (prompts, tool spec, patch quality engine), crates/localcode-core/ (Rust — workspace, git, patch, search, security, terminal), docs/ (capabilities, guardrails, install, architecture), scripts/ (dev-clean, reinstall).


Table of contents


What CodeYantra solves

The best AI coding tools (Cursor, GitHub Copilot, Claude Code) are excellent — but every keystroke, every open file, every prompt goes to someone else's servers. And they cost $10–$20 per developer, per month, forever. For anyone working on private repos, client codebases, health / finance / defence code, or just anyone tired of the running bill, that's a non-starter.

CodeYantra is the same class of tool — chat with your codebase, refactor across files, write tests, review your diff — running entirely on your laptop through Ollama. Your code stays where it is. The only network traffic the app produces is to localhost:11434.


Why local AI matters (especially for code)

Your codebase is the most sensitive data you own — credentials in comments, business logic, algorithms, client secrets, unshipped features. CodeYantra is built so this data never leaves your device:

  • No OpenAI / Anthropic / cloud APIs. No hosted LLM. No hosted database. No telemetry.
  • The only "AI" is a local Ollama model on localhost:11434.
  • Nothing writes to disk without your explicit click. Nothing overwrites without a rollback snapshot first.
  • The Rust core enforces path-safety, size caps, and binary rejection before the model ever sees a byte.

Local isn't a limitation — it's the whole point.


How local AI coding works

                  ┌─────────────── you type a prompt ───────────────┐
                  │  "Fix the case-sensitivity bug in @categorize.py" │
                  └─────────────────────┬─────────────────────────────┘
                                        ▼
     ┌───────────────────────────────────────────────────────────────────┐
     │ 1. PRELOAD workspace overview   → file tree + extension histogram  │
     │                                 + README + git status              │
     │ 2. RESOLVE @-mentions           → paste referenced file contents   │
     │ 3. STREAM from local Ollama     → assistant reasoning + tool calls │
     │ 4. RUN tools (read/list/search) → up to 14 iterations per turn     │
     │ 5. PARSE fenced patch envelope  → auto-normalise EOL/newline       │
     │ 6. QUALITY-CHECK the patch      → imports, defs, brackets, no-ops  │
     │ 7. SHOW Review modal + diff     → you approve, reject, or partial  │
     │ 8. SNAPSHOT then atomic write   → rollback-able, crash-safe        │
     └───────────────────────────────────────────────────────────────────┘

Every step is deterministic Rust or pure-JS. The LLM only proposes; it never writes.


Ollama context vs. workspace overview

CodeYantra does not stream your whole repo to the model. The model sees only the overview + files you @-mention + files it explicitly reads. Everything else stays on disk, indexed by the Rust workspace walker.

Local coder models have context windows of 8K–32K tokens — enough for a handful of files, not a whole repo. So CodeYantra treats Ollama purely as a reasoning layer. On every turn, the app preloads a compact workspace overview (file tree summary, extension histogram, README preview, git status) into the system prompt. The model can then request specific files via read_file — up to the iteration budget for that mode. Anything you @-mention in the chat gets pasted verbatim (with a per-file budget) into that same prompt, so the model doesn't waste a turn reading it.


The seven agent modes

Every mode reshapes the system prompt and iteration budget for its job. Pick from the dropdown above the chat.

Mode Writes? Best for
ask ✗ Read-only Q&A. "What does this project do?"
edit ✓ Focused single-file / few-file edits.
agent ✓ Multi-step: read → plan → patch. Chains up to 14 tool calls.
review ✗ Reads current git diff, comments on correctness and risk.
test ✓ Writes tests matching your framework.
refactor ✓ Behaviour-preserving structural improvements.
explain ✗ Long-form walkthroughs — great for onboarding and docs generation.

Architecture

   You type a prompt in the chat ──┐
                                    ▼
   ChatPanel (React)  ── loads workspace overview + @-mentions
        │
        ▼
   agentRunner (TS)   ── streams from Ollama, parses tool calls / fenced patch
        │  emits events: assistant_delta · tool_call_start · tool_call_done · patch_proposal
        ▼
   Tauri IPC bridge (invoke)
        │
        ▼
   Rust command layer  (apps/desktop/src-tauri/src/lib.rs)
        │
        ▼
   localcode-core  (crates/localcode-core)
        ├── workspace.rs    file tree + read_file (5 MiB cap, binary reject)
        ├── security.rs     PathPolicy — canonicalised path guard
        ├── patch.rs        atomic writes + snapshot + rollback
        ├── git.rs          status + diff
        ├── search.rs       ripgrep-backed workspace search
        └── terminal.rs     approval-gated command runner
        │
        ▼
   Local filesystem  +  Ollama @ localhost:11434
       (path-guarded)         (qwen3-coder / deepseek / codellama)

Two design choices anchor everything:

  • Deterministic math, LLM for words. Filesystem writes never go through the model — they go through the Rust patch engine. Every write is atomic (tmp + fsync + rename) and preceded by a snapshot.
  • Policy checks before action. PathPolicy::check runs on every fs op; rm -rf / doesn't get past terminal.rs risk classification.

Tech stack

Layer Technology
Desktop shell Tauri 2 (Rust bootloader + WebKit web view)
UI React 18, Vite 5, TypeScript 5, Tailwind CSS, Zustand + persist middleware
Fonts Inter (UI), JetBrains Mono (code) — loaded from Google Fonts
Core Rust 1.75+ — ignore (gitignore walker), diffy (unified diff apply), git2 (git status/diff), tokio (async), serde, sha2
Shared types Zod (runtime validation of assistant JSON + fenced patch envelope)
Local LLM Ollama on localhost:11434 — defaults to qwen3-coder:latest, any model works
Packaging Tauri bundler → .dmg (macOS), .msi + NSIS .exe (Windows), .deb + .AppImage (Linux)
CI GitHub Actions (tauri-apps/tauri-action@v0) — matrix over mac/win/linux

No cloud APIs. No hosted DB. No telemetry.


Folder structure

codeyantra/
├── apps/
│   └── desktop/
│       ├── src/                     # React UI
│       │   ├── App.tsx              # layout + rehydration
│       │   ├── components/          # ChatPanel · EditorPane · ExplorerPanel ·
│       │   │                         # PatchApprovalModal · WorkspaceSwitcher · Logo
│       │   ├── lib/                 # tauri.ts · store.ts (Zustand) · ollama.ts ·
│       │   │                         # agentRunner.ts · tools.ts · mentions.ts ·
│       │   │                         # workspaceOverview.ts
│       │   └── styles/index.css
│       ├── src-tauri/               # Rust command layer
│       │   ├── src/lib.rs           # #[tauri::command] fns
│       │   ├── icons/               # app icons (baked into installers)
│       │   └── tauri.conf.json
│       └── public/logos/            # favicon + brand mark PNGs
├── packages/
│   ├── shared/                      # Types + zod validators (PatchProposal, ToolCall, ...)
│   └── agent/                       # Prompts, tool spec, fenced patch parser,
│                                    # patch quality engine (patchChecks.ts)
├── crates/
│   └── localcode-core/              # workspace · git · patch · search ·
│                                    # security · terminal
├── docs/                            # CAPABILITIES · GUARDRAILS · INSTALL · architecture
├── scripts/                         # dev-clean · reinstall (macOS daily driver)
├── .github/workflows/build.yml      # cross-platform installer matrix
├── CLAUDE.md                        # project engineering rules
├── LICENSE                          # MIT
└── README.md

Setup

0) Prerequisites

  • Node.js 18+ and pnpm 9+
  • Rust 1.75+ (rustup default stable)
  • Ollama installed and running (ollama serve)
  • A pulled coder model: ollama pull qwen3-coder

One command (dev)

pnpm install
pnpm dev

This installs JS deps, boots Vite dev server, and launches the Tauri shell with live HMR. The first launch triggers a full Rust build of localcode-core and the Tauri command layer — expect 5–15 minutes. Subsequent launches are near-instant.

One command (production install on your machine)

./scripts/reinstall.sh

Kills any running instance, runs pnpm tauri build, swaps /Applications/CodeYantra.app, and relaunches. From then on: Cmd+Space → "CodeYantra".

One command (share it with someone)

pnpm tauri build also produces installers for the current platform under apps/desktop/src-tauri/target/release/bundle/. For cross-platform builds, use the checked-in GitHub Actions workflow — see docs/INSTALL.md.


Supported operating systems

OS Installer Status
macOS .dmg (Apple Silicon + Intel via CI matrix) ✓
Windows .msi + NSIS .exe ✓
Linux .deb + .AppImage ✓

Unsigned installers show a one-time "unidentified developer" dialog (macOS Gatekeeper) or "Windows protected your PC" (SmartScreen). Both have documented bypass steps in docs/INSTALL.md.


Privacy model

  • No outbound network calls except to http://localhost:11434 (Ollama) and to your local filesystem. Grep the Rust crate for reqwest / hyper::Client — there are none besides the OS-level git binary.
  • No telemetry, no crash reporters, no analytics.
  • No auth, no accounts, no sign-in.
  • Fonts (Inter, JetBrains Mono) load once from Google Fonts and cache; disable via the Tauri CSP if you want zero external requests.
  • Persistent app state lives in localStorage (workspace, tabs, chat per workspace, mode, AI config) — inside the Tauri WebKit sandbox, on your device only.

Data storage

  • Snapshots per patch: every applied patch writes the previous state to .codeyantra/snapshots/<snapshot-id>/ inside your workspace, so a bad apply can be rolled back.
  • Persisted UI state: last-opened workspace, per-workspace open tabs and chat history, agent mode, model / temperature, activity view — stored in the Tauri WebKit localStorage under key codeyantra:v1.
  • No workspace content stored outside your project. File contents are read on demand and not persisted anywhere by CodeYantra.

Guardrails

Every safety mechanism is documented and grep-able. Full deep-dive: docs/GUARDRAILS.md.

Vector Defence
Path escaping the workspace security::PathPolicy — canonicalised, descendant-of-root
Reading ~/.ssh, ~/.aws, etc. Blocked by default in PathPolicy.blocked
rm -rf /, mkfs, dd if= Hard-blocked in terminal.rs command classifier
git push, terraform apply Requires explicit user approval per invocation
Half-written files on crash atomic_write — tmp file → fsync → rename
Bad patch destroying files Snapshot before touch; auto-rollback on any per-file error
File > 5 MiB entering context read_file command hard-caps
Binary file entering context Null-byte scan on first 8 KiB rejects
Model exfiltration to cloud Provider layer only calls Ollama on localhost
Prompt injection via file contents System prompt tells the model to treat file contents as data
Model hallucinating dropped code Quality engine checks imports + top-level defs preserved
React error crashing the app RootErrorBoundary + window.onerror + unhandledrejection

Hard limits

Limit Value Enforced in
Max file size (read/edit) 5 MiB apps/desktop/src-tauri/src/lib.rs::read_file
File-tree crawl depth 6 apps/desktop/src/lib/tools.ts::listFiles
Search results per call 200 apps/desktop/src/lib/tools.ts::searchText
Tool result truncation 12 000 chars apps/desktop/src/lib/tools.ts::MAX_RESULT_CHARS
@-mention per-file budget 6 000 chars apps/desktop/src/lib/mentions.ts
@-mention total budget 20 000 chars apps/desktop/src/lib/mentions.ts
Agent iterations per turn 10–14 (mode) apps/desktop/src/components/ChatPanel.tsx
Workspace overview sample 80 tree entries apps/desktop/src/lib/workspaceOverview.ts

Full spec: docs/CAPABILITIES.md.


Demo script

A ready-made demo repo lives at ~/codeyantra-demo/receipts — a small Python CLI that parses grocery receipts and applies loyalty discounts. It has a deliberate case-sensitivity bug in categorize.py, a giant if/elif chain that begs to be refactored, no docstrings in summary.py, no tests for discount.py. Open it in CodeYantra and walk through the seven modes in order — the full tour takes 10–15 minutes.


Example prompts

"What does this project do? Walk me through main.py and how the modules fit together." ask mode — one answer from the preloaded workspace overview, no tool spree.

"Look at @categorize.py — how does it decide which category an item belongs to?" @-mention picker opens; pick the file; contents inject straight into the prompt.

"When I run python main.py sample_receipts/receipt1.txt, every item shows up as 'other'. Something in @categorize.py is wrong. What is it and why?" explain mode — traces the bug, no patches.

"Fix the case-sensitivity bug in @categorize.py by lowercasing the item name before matching. Keep the existing structure." edit mode — patch proposed, Review modal opens with before/after diff, quality engine flags any dropped imports or definitions.

"Refactor @categorize.py — the giant if/elif chain should be a dict lookup for clarity." refactor mode — behaviour-preserving. The quality engine's "top-level definitions preserved" check protects against the model dropping categorize() by accident.

"Write pytest tests for @discount.py covering bronze, silver, gold, platinum, and the >$50 gold bonus." test mode — creates a new test file.

"Add a --csv <path> flag to @main.py that also writes the summary as CSV. Update parse.py/summary.py if needed. Don't break the existing text output." agent mode — chains up to 14 tool calls; single multi-file patch.

"Review my current git diff. Any bugs, unclear names, or missed edge cases?" review mode after you make a change — read-only commentary.


Roadmap

  • Phase 1 — Tauri shell, seven modes, Ollama streaming
  • Phase 2 — Human-gated patch engine + snapshots + rollback
  • Phase 3 — @-mention picker, workspace overview preload, patch quality engine
  • Phase 4 — Multi-workspace switcher, per-workspace state persistence
  • Phase 5 — Auto-run tests / lints and close the loop (terminal exists; agent wiring pending)
  • Phase 6 — Language server integration (jump-to-def, types, live diagnostics)
  • Phase 7 — Live SQL / execution oracle (DuckDB row-diff for SQL edits)
  • Phase 8 — Command palette + custom keyboard shortcuts
  • Phase 9 — Cross-repo transformations
  • Phase 10 — Signed installers (silence Gatekeeper / SmartScreen)

Limitations

  • Model-bound quality. CodeYantra is a workspace, not a model. Output quality depends on your Ollama model. Tier 1 languages (TS/JS/Py/SQL/HTML/CSS/JSON/YAML) work great; Tier 3 (Kotlin/Scala/Dart/Haskell) work but need smaller, well-scoped asks.
  • No cross-repo refactors yet. Workspace scope is a single folder. You can switch between recent workspaces, but one turn = one repo.
  • No auto-run tests yet. The terminal exists and commands respect the approval gate, but the agent doesn't automatically kick off pytest after applying a patch. Coming in Phase 5.
  • Not a real code editor. The editor pane is a plain textarea with a line-number gutter, not Monaco / CodeMirror. Fine for reading and small edits; use your usual editor for extended work.
  • Unsigned installers. First launch on macOS shows a Gatekeeper warning (right-click → Open bypasses it), Windows shows SmartScreen. Signing certificates cost money.

Contributing

PRs welcome. Design rules any PR must respect:

  1. Deterministic math, LLM for words. Filesystem writes never go through the model — they go through the Rust patch engine.
  2. Local-first. No new outbound network call without an explicit user toggle.
  3. Policy checks before action. Every filesystem or shell operation goes through security.rs first.
  4. Small patches. Bias toward many small, verifiable changes over one big rewrite.

Setup:

pnpm install
pnpm --filter @localcode/desktop typecheck
cargo check -p localcode-core
pnpm dev

Full engineering rules: CLAUDE.md.


License

MIT — see LICENSE. Free to use, modify, fork, sell.


Built as part of the Free AI. Real Problems. Every Sunday. series. Made with Rust, TypeScript, and stubbornness about privacy.

About

Local-first AI coding workspace. Chat with your codebase, propose safe patches, iterate — without your code leaving your machine. Ollama · Tauri · React · Rust.

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages