{"id":51591664,"url":"https://github.com/clement-tourriere/codebeam","last_synced_at":"2026-07-11T15:02:03.773Z","repository":{"id":369049324,"uuid":"1281501211","full_name":"clement-tourriere/codebeam","owner":"clement-tourriere","description":"Local-first code search engine with a web UI, MCP server, and JSON API — lexical (Zoekt), symbol (ctags), and structural (ast-grep) search across your GitHub, GitLab, and local repositories. Single self-contained binary.","archived":false,"fork":false,"pushed_at":"2026-07-03T10:34:43.000Z","size":1551,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-03T11:27:57.245Z","etag":null,"topics":["ast-grep","code-navigation","code-search","coding-agents","ctags","developer-tools","github","gitlab","golang","htmx","mcp","mcp-server","self-hosted","sourcegraph","zoekt"],"latest_commit_sha":null,"homepage":"https://clement-tourriere.github.io/codebeam/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clement-tourriere.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"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-26T16:08:41.000Z","updated_at":"2026-07-03T10:34:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/clement-tourriere/codebeam","commit_stats":null,"previous_names":["clement-tourriere/codebeam"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/clement-tourriere/codebeam","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clement-tourriere%2Fcodebeam","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clement-tourriere%2Fcodebeam/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clement-tourriere%2Fcodebeam/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clement-tourriere%2Fcodebeam/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clement-tourriere","download_url":"https://codeload.github.com/clement-tourriere/codebeam/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clement-tourriere%2Fcodebeam/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35365809,"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-07-11T02:00:05.354Z","response_time":104,"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":["ast-grep","code-navigation","code-search","coding-agents","ctags","developer-tools","github","gitlab","golang","htmx","mcp","mcp-server","self-hosted","sourcegraph","zoekt"],"created_at":"2026-07-11T15:02:03.093Z","updated_at":"2026-07-11T15:02:03.744Z","avatar_url":"https://github.com/clement-tourriere.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Codebeam\n\nCodebeam is a local-first Sourcegraph-style code search prototype backed by Zoekt.\n\n## Install\n\nReleased binaries are fully self-contained (web UI assets included). Pick one:\n\n**Install script** (Linux and macOS, amd64/arm64):\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/clement-tourriere/codebeam/main/install.sh | sh\ncodebeam            # web UI on http://localhost:8080\n```\n\n**Docker**:\n\n```sh\ndocker run -d --name codebeam -p 8080:8080 \\\n  -v codebeam-data:/data -v codebeam-config:/config \\\n  ghcr.io/clement-tourriere/codebeam:latest\n```\n\n**Runtime requirements**: `git` must be on `PATH` — Codebeam shells out to it to clone, fetch, and read repositories (the Docker image ships it). [Universal Ctags](https://github.com/universal-ctags/ctags) is optional and enables symbol search.\n\nBinaries for each platform are also on the [releases page](https://github.com/clement-tourriere/codebeam/releases).\n\n## CLI\n\nThe release archive also ships `cb`, a client for any Codebeam server — the same cited, permission-scoped results the MCP tools return, from any terminal:\n\n```sh\ncb login codebeam.example.com     # one-time browser sign-in (OAuth, like an MCP client)\ncb search \"func NewServer\" --lang go\ncb def NewServer                  # where is it defined?\ncb read local/app:cmd/main.go:1-40\n```\n\nAgents and CI skip the login entirely: set `CODEBEAM_URL` and `CODEBEAM_TOKEN` (a personal access token from **Settings → API tokens**) and every command works headless. See the [CLI documentation](https://clement-tourriere.github.io/codebeam/cli/).\n\n## Documentation\n\nThe full setup and operations documentation is published at **\u003chttps://clement-tourriere.github.io/codebeam/\u003e** (OAuth, environment variables, indexing, integrations, deployment). It lives in the Astro Starlight site under `docs/`:\n\n```sh\nmise run docs:dev\nmise run docs:build\n```\n\n## Develop\n\nUse `mise` to install the pinned toolchain and run the app. The dev task installs missing frontend npm dependencies automatically:\n\n```sh\nmise install\nmise run dev\n```\n\nThe app defaults to `http://localhost:8080` and stores data under `.codebeam/`.\n\n## OAuth\n\nLocal development login is enabled by default. To connect real code hosts with OAuth, create an OAuth app on the host and put its credentials in `.env` (loaded automatically by `mise`):\n\n```sh\ncp .env.example .env\n$EDITOR .env\nmise run dev\n```\n\nGitHub OAuth app setup:\n\n1. Open GitHub → **Settings** → **Developer settings** → **OAuth Apps** → **New OAuth App**.\n2. Use:\n   - **Application name:** `Codebeam`\n   - **Homepage URL:** `http://localhost:8080`\n   - **Authorization callback URL:** `http://localhost:8080/auth/github/callback`\n3. Copy the client ID and generate a client secret into `.env`:\n\n```dotenv\nCODEBEAM_BASE_URL=http://localhost:8080\nCODEBEAM_GITHUB_CLIENT_ID=...\nCODEBEAM_GITHUB_CLIENT_SECRET=...\n```\n\nGitLab callback URL: `http://localhost:8080/auth/gitlab/callback`\n\nGitHub can also be connected from the Sources page with a personal access token, which avoids configuring OAuth env vars for local use.\n\nFor self-managed GitLab, either set `CODEBEAM_GITLAB_BASE_URL` before starting the app for OAuth, or sign in locally and use the \"Self-managed GitLab\" card on the Repositories page with a personal access token that has `read_api` and `read_repository`.\n\n## V0 Flow\n\n1. Log in locally or with GitHub/GitLab OAuth.\n2. Paste a public GitHub URL, sync GitHub/GitLab repositories, or add a local repository path.\n3. Select repositories and run indexing (public GitHub repos can be added and indexed without OAuth).\n4. Search with Zoekt query syntax plus repo/branch/path/language filters and result facets.\n5. Open results in the code viewer.\n\n## Live local freshness\n\nSelected local repositories are watched by default. Codebeam queues a debounced background reindex when files change on disk, so local search stays fresh without pressing the reindex button. Local search results also show a `dirty` badge when the matching file has uncommitted changes. Set `CODEBEAM_WATCH_LOCAL_REPOS=false` to disable the watcher.\n\n## Remote auto-indexing\n\nSelected remote repositories (public GitHub, GitHub OAuth, GitLab, self-managed GitLab) are re-pulled and reindexed on a schedule, so their search stays fresh without manual reindexing. A background scheduler periodically enqueues a reindex for any selected remote repo whose last index attempt is older than the refresh interval — which also picks up newly-selected repos and naturally backs off ones that recently failed. Private repos fetch with the token of a user who has access; public GitHub repos work without a token, so they can be added from the Sources page by URL.\n\n- `CODEBEAM_REMOTE_REFRESH_INTERVAL` (default `30m`) — how stale a repo may get before it is refreshed. Accepts Go durations (`15m`, `1h`, …).\n- `CODEBEAM_AUTO_INDEX_REMOTE=false` — disable the scheduler.\n- `CODEBEAM_AUTO_EXCLUDE_INACCESSIBLE` (default `true`) — when a remote repo fails to index with an access/permission error (e.g. a GitLab project the token can't read), drop it from the selection so the scheduler stops retrying it. Re-select it once access is restored. Overridable on the `/settings` page.\n- `CODEBEAM_INDEX_CONCURRENCY` — maximum repository indexing jobs to run at once (default: bounded by CPU, up to 4).\n- `CODEBEAM_INDEX_FILE_CONCURRENCY` — per-repository document/blob reader concurrency (default: bounded by CPU, up to 8).\n\n## Branch indexing\n\nRemote repositories can index one, many, or all branches. Leave the branch field empty to use the host's default branch; set comma-separated names or glob patterns to include branches (`main,release/*`); use `*`/`all` for every remote branch; and prefix patterns with `!` to exclude branches (`*,!wip/*,!dependabot/*`). Codebeam records the resolved branch set on each successful index, so deleted branches disappear on the next refresh; if an explicitly requested branch is missing, the repo is marked as needing reindex instead of silently serving stale results. Search facets expose indexed branches, and `branch:`/`branch=` filters scope searches to a branch. Search results deduplicate equivalent hits across branches and show branch locations as badges with `+N` overflow.\n\nWhen a branch pattern (such as `*`) matches more branches than `CODEBEAM_MAX_INDEXED_BRANCHES` (default `20`), Codebeam indexes only the most recently updated branches — the default branch is always kept — instead of cloning and indexing thousands of stale branches. Ranking uses a metadata-only fetch of branch tips, so it stays cheap even on repos with many branches. Admins can change the limit on the `/settings` page; the search index (Zoekt) supports at most **64 branches per repository**, so values above 64 (or `0`) mean that maximum. A selection of explicitly named branches that exceeds the limit fails with a clear error instead of silently dropping branches.\n\n## Agent-facing retrieval\n\n- `GET /api/search?q=...` returns JSON search results and facets. Authenticate with a browser session or `Authorization: Bearer \u003ctoken\u003e` using a personal access token from **Settings → API tokens**. It accepts the same `repo`, `branch`, `path`, `top`, `ext`, `lang`, `source`, `provider`, `dirty`, `symbol_kind`, `freshness`, and `sort` controls as the web UI. Repeat `repo` to search multiple repositories with boolean OR. Add `mode=structural\u0026lang=\u003clanguage\u003e` to run a structural (AST) search instead of a lexical one; the response then carries `engine: \"structural\"` and per-line `meta_vars` captures.\n- `GET /api/read?repo=local/repo\u0026path=main.go\u0026start=1\u0026end=80` returns a bounded JSON file range; add `branch=...` for indexed remote branches.\n- `codebeam ctx \"how is auth wired?\"` prints a citation-style context bundle from the local indexed repos. Use `--max-chars`, `--max-files`, `--repo`, `--path`, and `--lang` to control the bundle.\n\n## Authentication \u0026 roles\n\nThe first user to sign in becomes the instance **admin** (settings, local repository paths, user management); later users join as **members** and see only repositories they have access to. Company deployments can plug in OIDC single sign-on (Okta, Entra ID, Google Workspace, Keycloak, …) with an optional email-domain allowlist — set `CODEBEAM_OIDC_ISSUER`/`CLIENT_ID`/`CLIENT_SECRET`. Agents and scripts authenticate with personal access tokens (`Authorization: Bearer cbp_…`), and MCP clients can walk a full OAuth 2.1 flow (dynamic client registration + PKCE) against the built-in authorization server — point them at `/mcp` and approve the browser consent page. See the integrations doc for details.\n\n## MCP server\n\n`codebeam mcp` runs a Model Context Protocol server over stdio so coding agents can use your local Codebeam index as a retrieval toolbox instead of `grep`. A shared deployment additionally serves the streamable-HTTP transport at `POST /mcp`, bearer-authenticated and scoped to each user's repositories (`claude mcp add --transport http codebeam https://your-host/mcp`). It exposes eight tools backed by the same engines the web UI uses:\n\n- `search_code` — lexical/regex search across every indexed repository, returning ranked snippets with `repo:path:line` citations and a `dirty` flag for uncommitted working-tree matches. Accepts `query`, `repo`, `path`, `lang`, and `max_results`.\n- `structural_search` — AST-shape search with ast-grep patterns (`$VAR` captures one node, `$$$` any number), e.g. `if $ERR != nil { $$$ }`. Runs fully in-process (embedded WASM engine, no external binary) and reports captured metavariables with each match. Accepts `pattern`, `lang` (required), `repo`, `branch`, `path`, and `max_results`.\n- `symbol_search` — find where a symbol is **defined** (function, type, method, …) via Zoekt's ctags-backed symbol index, instead of every textual mention. Accepts `symbol`, `repo`, `lang`, and `max_results`. Requires symbol indexing (see below).\n- `find_references` — find **usages** of a symbol with word-boundary precision (so `Get` does not also match `Getter`); the companion to `symbol_search` for code navigation. Accepts `symbol`, `repo`, `lang`, and `max_results`.\n- `read_file` — a bounded line range from an indexed file, with provenance. Accepts `repo`, `path`, `start`, `end`.\n- `file_tree` — list files and directories in a repository (optionally under a sub-path) to orient before reading or searching. Accepts `repo`, `path`, and `max_entries`.\n- `list_repos` — the repositories that are currently indexed and searchable.\n- `repo_stats` — per-repository statistics with fleet-wide totals: language breakdown (percentages by bytes), file/line/size counts, last commit date, and indexed branches/commit. Covers the primary branch's indexed content, so numbers match what search sees.\n\nRegister it with Claude Code:\n\n```sh\nclaude mcp add codebeam -- codebeam mcp\n```\n\nor add it to any MCP client config (for example `.mcp.json` / Cursor):\n\n```json\n{\n  \"mcpServers\": {\n    \"codebeam\": { \"command\": \"codebeam\", \"args\": [\"mcp\"] }\n  }\n}\n```\n\nThe server reads the same `.codebeam/` data the app indexes, so point it at a custom data dir with `CODEBEAM_DATA_DIR` (or `CODEBEAM_DB_PATH` / `CODEBEAM_INDEX_DIR`) if you moved it.\n\n## Symbol search\n\nCodebeam can search **symbol definitions** (functions, types, methods, constants, …) rather than raw text, across 100+ languages:\n\n- In the web UI, tick **Symbols only** on the search form.\n- Over the JSON API, add `\u0026sym=1` to `/api/search`.\n- For agents, use the `symbol_search` MCP tool.\n\nThe file viewer also shows a **Symbols** outline for the open file (jump to any definition; \"refs\" links run a word-boundary find-references search scoped to the repo). The outline uses live ctags, so it reflects the file on disk even before re-indexing. Identifiers in the code body that are defined in the same file are **click-to-definition** links (they keep their syntax colour and only underline on hover).\n\nSymbol search needs [Universal Ctags](https://github.com/universal-ctags/ctags) to be available **when a repository is indexed**. Codebeam auto-detects `universal-ctags` (or a `ctags` that is really Universal Ctags) on your `PATH`. On macOS the system `/usr/bin/ctags` is BSD ctags, which does not work, and Homebrew installs Universal Ctags keg-only, so point Codebeam at it explicitly and re-index:\n\n```sh\nbrew install universal-ctags\nexport CODEBEAM_CTAGS_PATH=\"$(brew --prefix universal-ctags)/bin/ctags\"\nmise run dev   # then re-index repositories so symbols are captured\n```\n\nWhen no Universal Ctags binary is configured, symbol search simply returns no matches — every other feature is unaffected.\n\n## Structural search\n\nCodebeam can search code by **AST shape** instead of text, using [ast-grep](https://ast-grep.github.io/) patterns — find `if $ERR != nil { $$$ }` regardless of variable names or formatting:\n\n- In the web UI, tick **Structural (AST)** on the search form and pick a language.\n- Over the JSON API, add `\u0026mode=structural\u0026lang=go` to `/api/search`.\n- For agents, use the `structural_search` MCP tool.\n\nPatterns are ordinary code plus metavariables: `$VAR` captures one AST node, `$$$` captures any number (`$$$ARGS` to name the capture). The pattern must itself parse as valid code in the chosen language. Captured metavariables are shown with each match.\n\nThe engine is **built into the Codebeam binary**: ast-grep's Rust core and its tree-sitter grammars are compiled to a WebAssembly module (see `wasm/astgrep/`) and executed in-process on wazero. Nothing to install, no subprocess, `CGO_ENABLED=0` and the single-binary deploy story are preserved. Bundled languages: bash, c, go, java, javascript, json, python, rust, tsx, typescript, yaml.\n\nStructural search scans the **live worktree** for local repositories (uncommitted changes included) and the primary indexed branch for remote clones. Pass `branch=\u003cname\u003e` to search any other indexed branch — file contents are read straight from the git object store, without touching the working tree. Scans are bounded by `CODEBEAM_STRUCTURAL_TIMEOUT` (15s), `CODEBEAM_STRUCTURAL_MAX_FILES` (5000), and `CODEBEAM_STRUCTURAL_MAX_MATCHES` (1000); truncated results are flagged. It is deliberately a separate, slower tool than lexical search (roughly 5–7 ms per file) — narrow with repo/path filters for large sweeps.\n\nTo rebuild the WASM engine after changing `wasm/astgrep/` (requires Rust with the `wasm32-wasip1` target; wasi-sdk is fetched automatically):\n\n```sh\nmise run wasm:build\n```\n\n## VS Code Extension\n\nThe extension scaffold lives in `extensions/vscode`. It adds `Codebeam: Search Selection` and opens the selected text in the configured Codebeam instance.\n\n## Releasing\n\nVersioning follows [Conventional Commits](https://www.conventionalcommits.org/) via [commitizen](https://commitizen-tools.github.io/commitizen/) (installed by `mise install`). Git tags are the single source of truth for the version — the binary gets it injected at build time.\n\n```sh\nmise run release\n```\n\nThis runs `cz bump` (computes the next semver from the commit history, updates `CHANGELOG.md`, creates the `vX.Y.Z` tag) and pushes with `--follow-tags`. The pushed tag triggers the release workflow, which:\n\n- cross-compiles self-contained binaries for linux/darwin × amd64/arm64 with the version injected,\n- publishes them (plus SHA-256 checksums) as a GitHub Release with generated notes, and\n- builds and pushes the multi-arch Docker image to `ghcr.io/clement-tourriere/codebeam` (`latest`, `X.Y`, `X.Y.Z`).\n\n## License\n\n[MIT](LICENSE). Codebeam depends on permissively licensed components, notably [Zoekt](https://github.com/sourcegraph/zoekt) (Apache-2.0), [wazero](https://github.com/tetratelabs/wazero) (Apache-2.0), [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) (BSD-3-Clause), and [ast-grep](https://github.com/ast-grep/ast-grep) (MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclement-tourriere%2Fcodebeam","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclement-tourriere%2Fcodebeam","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclement-tourriere%2Fcodebeam/lists"}