{"id":51111591,"url":"https://github.com/whiskeyjimbo/veska","last_synced_at":"2026-06-24T18:30:23.490Z","repository":{"id":365998906,"uuid":"1258483123","full_name":"whiskeyjimbo/veska","owner":"whiskeyjimbo","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-19T19:46:57.000Z","size":96581,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-19T21:12:44.372Z","etag":null,"topics":["ai-agents","code-graph","code-intelligence","developer-tools","embeddings","golang","llm","local-first","mcp","model-context-protocol","semantic-search","static-analysis","treesitter","vector-search"],"latest_commit_sha":null,"homepage":"https://whiskeyjimbo.github.io/veska/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/whiskeyjimbo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-03T16:11:01.000Z","updated_at":"2026-06-19T19:47:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/whiskeyjimbo/veska","commit_stats":null,"previous_names":["whiskeyjimbo/veska"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/whiskeyjimbo/veska","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whiskeyjimbo%2Fveska","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whiskeyjimbo%2Fveska/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whiskeyjimbo%2Fveska/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whiskeyjimbo%2Fveska/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/whiskeyjimbo","download_url":"https://codeload.github.com/whiskeyjimbo/veska/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whiskeyjimbo%2Fveska/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34745455,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","code-graph","code-intelligence","developer-tools","embeddings","golang","llm","local-first","mcp","model-context-protocol","semantic-search","static-analysis","treesitter","vector-search"],"created_at":"2026-06-24T18:30:15.893Z","updated_at":"2026-06-24T18:30:23.480Z","avatar_url":"https://github.com/whiskeyjimbo.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Veska\n\n\n[![Quickstart](https://img.shields.io/badge/Quick_Start-blue)](https://whiskeyjimbo.github.io/veska/getting-started/quickstart/)\n[![CI](https://github.com/whiskeyjimbo/veska/actions/workflows/ci.yml/badge.svg)](https://github.com/whiskeyjimbo/veska/actions/workflows/ci.yml)\n[![Docs](https://github.com/whiskeyjimbo/veska/actions/workflows/docs.yml/badge.svg)](https://github.com/whiskeyjimbo/veska/actions/workflows/docs.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/whiskeyjimbo/veska)](https://goreportcard.com/report/github.com/whiskeyjimbo/veska)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/whiskeyjimbo/veska)](go.mod)\n[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](LICENSE)\n\n\n\u003e **Give your AI coding agent real structural understanding of your codebase.**\n\u003e Veska parses your repo into a queryable code graph + semantic index and serves\n\u003e it to your agent (and you) over MCP - so answers come back as exact\n\u003e `file:line` spans, not grep-and-guess. Fully local, in-process, zero-setup.\n\n![Veska - natural-language query in, exact file:line answer out](docs/manual/assets/demo.gif)\n\n**Veska** is a local code-intelligence daemon. It runs on your laptop, parses\nyour repository into a code graph (nodes + edges), embeds that graph\nsemantically, and serves both to your editor and your AI agent over MCP - so\nthey reason from the same structural ground truth instead of guessing.\n\n## What it gives you\n\n- **Grounded structural answers.** Every function, type, file, and call traces\n  to a node, edge, or commit. Structural recall stays current within the\n  save → staging freshness budget.\n- **Eventually-consistent semantic search.** `semantic_search` embeds the graph\n  with an in-process embedder (model2vec by default - no external service);\n  during the indexing lag window it falls back to a BM25 lexical index and\n  flags the response `degraded_reasons`.\n- **Promotion checks.** On every commit, synchronous checks emit advisory\n  `Finding`s: dead code, contract drift, leaked secrets, and vulnerable\n  `go.mod` dependencies via the OSV.dev advisory database. All four ship on\n  by default: `veska init` writes an active `[vuln_source]` config block to\n  `~/.veska/config.toml` (see\n  [`docs/operations/CONFIG-SURFACE.md`](docs/operations/CONFIG-SURFACE.md))\n  unless you opt out with `veska init --no-vuln` (or answer \"no\" at the\n  interactive prompt). **Lifecycle:** the block is read at daemon start, so\n  it takes effect from the next `veska service start` (restart the service\n  after editing the block). New scans pick it up automatically; to scan\n  already-promoted repos retroactively, run `veska reindex \u003cpath\u003e`.\n- **Duplicate \u0026 similar-code detection.** Find copy-paste and drifted clones\n  for de-dupe triage: `eng_find_clones` for one symbol-group mode at a time\n  (`exact` byte-identical, or `near` fuzzy via stored similarity), and\n  `eng_find_clusters` for a whole-repo (or cross-repo) sweep across `exact`,\n  `structural` (Type-2, same shape after renaming), and `near` tiers, ranked\n  tightest first. Exact/structural are deterministic hashes; near reads the\n  similarity scores auto-link already stored (no new embedding sweep).\n- **Optional LLM features.** An off-by-default post-promotion review pipeline\n  and per-node summaries (Ollama-backed).\n- **Mechanical wiki.** Hot-zones and entry-points computed from the graph,\n  no LLM in the path. The `eng_get_hot_zone` and `eng_get_entry_points`\n  MCP tools return data in-memory and write nothing; the `veska wiki`\n  CLI renders the same data into `docs/veska/{hot_zones,entry_points}.md`\n  inside the repo (re-runnable, idempotent - bracket markers in each\n  page preserve any hand edits outside the managed block). A context-pack\n  tool sits alongside.\n- **Cross-actor attribution.** A single `actor_kind: human | agent | system`\n  enum distinguishes who changed what in the audit log.\n\n## Process topology - one binary, three personalities\n\n`make build` produces a single binary at `bin/veska`; `bin/veska-daemon` and\n`bin/veska-mcp` are symlinks to it. The argv[0] dispatcher in\n`cmd/veska/main.go` routes each invocation into its own package.\n\n| Invocation | Role |\n|---|---|\n| `veska` | CLI - `init`, `repo`, `reindex`, `service`, `doctor`, `backup`, `wiki`, … Run `veska --help` for the full list. |\n| `veska-daemon` (symlink) | Long-running process - owns the SQLite store, the fsnotify watcher, the embedder, and the post-promotion queue. Composition root: `internal/cli/daemon/wire.go`. |\n| `veska-mcp` (symlink) | Thin stdio shim proxying an editor's MCP connection to the daemon's Unix socket. Routes into `internal/cli/mcp`. |\n\n## Vector backends\n\nSemantic search and auto-linking find the nearest embeddings to a query. Two\nbackends do that, chosen with `VESKA_VECTOR_BACKEND`: **`memory`** (`memvec`, the\ndefault - exact linear scan, lowest RAM, no setup) and **`usearch`** (approximate\nHNSW - flat query latency at scale, needs `libusearch_c.so`). Measured across Go\nrepos (memvec is the exact-recall oracle; regenerate with `make eval-backend-matrix`):\n\n| repo    | symbols | q p95 memvec | q p95 usearch | usearch recall | RAM memvec | RAM usearch |\n|---------|--------:|-------------:|--------------:|---------------:|-----------:|------------:|\n| go-git  |  11,262 |       4.0 ms |        0.3 ms |         0.9990 |     34 MiB |      65 MiB |\n| veska   |  12,900 |       4.3 ms |        0.4 ms |         0.9994 |     39 MiB |      65 MiB |\n| grpc-go |  19,520 |       6.2 ms |        0.3 ms |         0.9979 |     59 MiB |     129 MiB |\n| consul  |  37,272 |      11.6 ms |        0.4 ms |         0.9965 |    113 MiB |     129 MiB |\n\nmemvec's query latency grows with repo size while usearch stays flat (~0.3 ms);\nusearch trades ~2x the RAM and a slower index build for that. Stick with the\ndefault until linear-scan latency is noticeable. Full discussion:\n**[Vector storage backends](docs/manual/concepts/vector-backends.md)**.\n\n## Requirements\n\n- **Go 1.26+**\n- **Go repositories only, for now.** The tree-sitter parser ships a single\n  Go grammar, so the code graph is built from `.go` files. Other languages\n  are a deliberate future step, not a current capability.\n- **No external services for core use.** SQLite, the vector index, and the\n  default embedder all run in-process. A fresh machine indexes and searches\n  with nothing else installed or running.\n\n### Embedder\n\nSemantic search needs an embedder. Veska **elects one at boot** in preference\norder - it never mixes vector spaces, so exactly one embedder owns the index\nat a time:\n\n1. **model2vec** (`potion-code-16M`) - a fast, in-process static *code*\n   embedder. The default and recommended choice. Get it either way:\n   - **Fat binary** (`make build`, default) - the model is compiled into the\n     binary. Zero setup: nothing to install, no download, no network.\n   - **Thin binary** (`make build-small`) + `veska install model2vec` - a\n     one-time ~62 MB download into `~/.veska/`.\n2. **static-v2** - an in-binary fallback that works with no model files at\n   all (lower quality). Used only when model2vec is unavailable.\n\nNo Ollama, no network, and no separate process is required for search.\n\n### Optional: Ollama\n\nOllama is **only** for the optional **LLM features** - the post-promotion\n**review pipeline** and per-node **summaries** (both off by default). It is\n**not** used for embeddings in the default config. (Power users can force an\nOllama embedding model with `VESKA_EMBEDDER=ollama`, but model2vec is faster\nand higher-quality on code, so this is rarely worthwhile.)\n\nInstall Ollama only if you want those LLM features:\n\n```sh\n# macOS:        brew install ollama \u0026\u0026 ollama serve \u0026\n# Linux (snap): sudo snap install ollama \u0026\u0026 ollama serve \u0026\n# Linux (curl): curl -fsSL https://ollama.com/install.sh | sh \u0026\u0026 ollama serve \u0026\n```\n\n## Build\n\n`make build` is the fat binary by default  - it embeds the\nmodel2vec weights into the binary so the install is zero-setup: no separate\ndownload, no network, no static-v2 fallback at boot.\n\n```sh\nmake build        # default: ~104 MB fat binary (model2vec ~62 MB embedded\n                  # into a ~42 MB thin build). Zero setup at runtime.\nmake build-small  # ~42 MB thin: veska, veska-daemon, veska-mcp (+ layercheck).\n                  # Use this only when you want size-sensitive binaries\n                  # (CI, containers); you must then run `veska install model2vec`\n                  # to avoid booting on the low-quality static-v2 fallback.\nmake test         # go test ./...\nmake all          # build-small + test + vet + lint + layercheck\n                  # (uses the thin build to keep the test loop fast)\n```\n\nBinaries land in `./bin/`. Either `export PATH=\"$PWD/bin:$PATH\"` or use the\n`./bin/` prefix in the Quick Start below.\n\n### Install into your `PATH`\n\nAfter a `make build`, drop the binaries into a user bin directory in one step:\n\n```sh\nmake install                         # → ~/.local/bin (default)\nVESKA_INSTALL_DIR=/usr/local/bin sudo make install   # system-wide\n```\n\nFor a self-contained tarball (the three fat binaries + `install.sh` + a\nREADME), run `make release-archive`. The archive at\n`dist/veska-\u003cversion\u003e-\u003cos\u003e-\u003carch\u003e.tar.gz` is the same shape a future\nGitHub release will ship - `./install.sh` from inside the extracted\ndirectory does the same thing as `make install` .\n\n## Quick start\n\n```sh\n# 1. Build veska (default: fat, zero-setup embedder).\nmake build\n# Size-sensitive builds can `make build-small` instead, then run\n# `./bin/veska install model2vec` to avoid the low-quality static-v2 fallback.\n\n# 2. Initialize veska's data directory at ~/.veska/.\n./bin/veska init\n\n# 3. Start the daemon.\n#\n#    Pick one:\n#      - Just kicking the tires? Background it:    ./bin/veska-daemon \u0026\n#      - Want it on every boot, auto-restart on\n#        crash, logs under ~/.veska/logs?           use the service form below.\n#\n#    For a real install, run it as an OS service (systemd --user on Linux,\n#    launchd on macOS). Uninstall with `./bin/veska service uninstall`.\n./bin/veska service install\n./bin/veska service start\n\n# 4. Register a repo. --wait blocks until the cold scan finishes (a few\n#    seconds for most repos) so the first search below is already hot.\n#    Without --wait the scan kicks off in the background; the next\n#    `eng_search_semantic` call may then return `[]` with\n#    `degraded_reasons=embeddings_pending` until indexing catches up.\n#    Tail ~/.veska/logs/daemon.log for the \"cold scan: complete\" line.\n./bin/veska repo add /path/to/your/repo --wait\n\n# 5. Sanity-check.\n./bin/veska doctor status\n```\n\nThe first `veska repo add` registers the repo, installs the git post-commit\nhook with an absolute path to the `veska` binary, and dispatches a cold scan\nthrough the daemon. Subsequent commits drive promotion via `eng_promote_repo`\non the daemon's MCP socket.\n\nTo force a re-scan of an already-registered repo (e.g. after a model swap):\n\n```sh\n./bin/veska reindex /path/to/your/repo\n```\n\nSafe to run while the daemon is up - the CLI dispatches the cold-scan\nthrough the daemon's `eng_reindex_repo` MCP tool , so your\neditor's MCP connection is not interrupted. With the daemon stopped, the\nsame command falls back to a direct in-process reparse.\n\n### Next steps\n\nPoint your editor's MCP client at `bin/veska-mcp` (a stdio command), and seed a\nper-agent instruction file with `veska init --agent \u003cname\u003e`. The full\nwalkthroughs - editor configs (Claude Desktop, Cursor, Zed, Continue), the shell\nJSON-RPC interface, and the first-call sanity check - live in the manual:\n**[Quickstart](https://whiskeyjimbo.github.io/veska/getting-started/quickstart/)**\nand **[Connecting your editor](https://whiskeyjimbo.github.io/veska/guides/editor-setup/)**.\n\n### Configuration\n\nState lives under `~/.veska/` (`VESKA_HOME`). Daemon config is\n`~/.veska/config.toml` - see [`docs/operations/CONFIG-SURFACE.md`](docs/operations/CONFIG-SURFACE.md).\nKey environment variables:\n\n| Var | Purpose | Default |\n|---|---|---|\n| `VESKA_HOME` | Data root | `~/.veska` |\n| `VESKA_EMBEDDER` | Embedder election: `auto` (model2vec→static-v2), or force `model2vec` / `static` / `ollama` | `auto` |\n| `VESKA_VECTOR_BACKEND` | `memory` (in-process `memvec` linear scan) or `usearch` (HNSW) | `memory` |\n| `VESKA_OLLAMA_URL` | Ollama endpoint - LLM review + summaries, and `VESKA_EMBEDDER=ollama` | `http://localhost:11434` |\n| `VESKA_EMBED_MODEL` | Ollama embedding model - only when `VESKA_EMBEDDER=ollama` | `nomic-embed-text` |\n\nThe elected embedder is recorded in `~/.veska/embedder.locked`. Switching\nembedders requires a re-index (`veska reindex`) since their vectors aren't\ncomparable.\n\n## Architecture\n\n```\ncmd/veska/            single binary entry point; argv[0] dispatcher in main.go\ninternal/\n  core/\n    domain/           pure entities: Node, Edge, Graph, Task, Finding\n    ports/            interface contracts (GraphStorage, VectorStorage, VulnSource, …)\n  application/        use-case services: ingester, promoter, embedder, checks, review, wiki\n  cli/                composition roots: daemon/wire.go and the mcp stdio shim\n  infrastructure/     adapters: sqlite, vector, embedding/{model2vec,static,ollama,elect}, treesitter, mcp, git\n  repo/               repos-table registry\n  platform/           cross-cutting operational concerns (config, doctor, health, …)\ndocs/                 user manual, architecture summary, and operational runbooks\n```\n\n## MCP tools\n\nThe daemon exposes 38 tools over a Unix-socket JSON-RPC server (forwarded to\neditors by `veska-mcp`). Tool names follow `eng_\u003cverb\u003e_\u003cobject\u003e`. Quick map:\n\n| Family | Tools |\n|---|---|\n| Admin | `eng_get_status`, `eng_get_config`, `eng_get_current_repo`, `eng_get_repo`, `eng_list_repos` |\n| Repo lifecycle | `eng_add_repo`, `eng_remove_repo`, `eng_promote_repo`, `eng_reindex_repo`, `eng_set_repo_alias`, `eng_remove_repo_alias` |\n| Graph | `eng_find_symbol`, `eng_get_node`, `eng_get_file_nodes`, `eng_get_call_chain` |\n| Search | `eng_search_semantic`, `eng_search_similar`, `eng_find_related` (semantic neighbors of the code at a `file_path`+`line`) |\n| Duplicates | `eng_find_clones` (duplicate groups for one mode: `exact` byte-identical or `near` fuzzy), `eng_find_clusters` (whole-repo / cross-repo de-dupe triage across `exact`/`structural`/`near` tiers, tightest first) |\n| Blast radius | `eng_get_blast_radius`, `eng_get_diff_blast_radius`, `eng_get_dirty_blast_radius` |\n| Context | `eng_get_context_pack`, `eng_find_changed_symbols` (takes `ref_a`/`ref_b` or aliases `base`/`head`; defaults to `HEAD~1..HEAD`; chunks filtered, comment-only diffs surface `non_symbol_changes_only` in `degraded_reasons`) |\n| Dependencies | `eng_list_dependencies` (external modules the repo CALLS into, ranked by call-site count) |\n| Misc | `eng_find_owner`, `eng_find_todos` |\n| Findings | `eng_list_findings`, `eng_get_finding`, `eng_close_finding`, `eng_reopen_finding` |\n| Suppressions | `eng_list_suppressions`, `eng_get_suppression`, `eng_suppress_finding`, `eng_close_suppression` |\n| Wiki | `eng_get_hot_zone`, `eng_get_entry_points` |\n\u003c!-- Parked task family (eng_get_active_task, eng_set_active_task, eng_get_task_history)\n     is intentionally omitted from this table - it is unregistered and would\n     return `method not found` if called. See \"Parked tools\" note further below. --\u003e\n\n\nSee the **[MCP tools reference](docs/manual/reference/mcp-tools.md)** for the\nfull response shape, `repo_id` aliasing, parameter aliases, cross-repo edges, and\nthe parked task-tool family.\n\n## Testing\n\n```sh\nmake test          # go test ./... - unit + integration suites\nmake test-mcp      # python pytest harness against a running daemon (fast)\nmake test-mcp-deep # add cross-validation against the live SQLite\n```\n\n`tests/mcp/` spawns `bin/veska-mcp` as a subprocess, drives every registered\ntool with happy/bad/edge inputs, and pretty-prints each call's transcript so\nthe suite doubles as a human-readable smoke. Requires `VESKA_HOME` to point\nat a running daemon's data dir and at least one `veska repo add`'d repo.\n\n## Documentation\n\n- [`docs/PRODUCT.md`](docs/PRODUCT.md) - What Veska is, in plain English.\n- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) - High-level system architecture and design.\n- [`docs/manual/`](docs/manual/) - User and operator manual (MkDocs source).\n- [`docs/operations/`](docs/operations/) - Config surface and runbooks.\n\n## License\n\nVeska is licensed under the **GNU Affero General Public License v3.0**\n(`AGPL-3.0-only`) - see [`LICENSE`](LICENSE). You may use, study, modify, and\nshare it freely; if you run a modified version as a network service, the AGPL\nrequires you to offer that version's source to its users.\n\nThird-party components (Go dependencies and, in `embed_model` builds, the\npotion-code-16M model weights) are redistributed under their own permissive\nlicenses, reproduced in [`THIRD_PARTY_NOTICES`](THIRD_PARTY_NOTICES).\nRegenerate that file with `make notices` after a dependency change.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwhiskeyjimbo%2Fveska","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwhiskeyjimbo%2Fveska","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwhiskeyjimbo%2Fveska/lists"}