Metadata-Version: 2.4
Name: climble
Version: 0.1.0
Summary: A thin Typer CLI wrapper around semble for instant code search.
Project-URL: Homepage, https://github.com/jesshart/climble
Project-URL: Source, https://github.com/jesshart/climble
Project-URL: Issues, https://github.com/jesshart/climble/issues
Project-URL: Changelog, https://github.com/jesshart/climble/blob/main/CHANGELOG.md
Author: Jesse Hartman
License: MIT
License-File: LICENSE
Keywords: agent,cli,code-search,rag,semantic-search,semble,typer
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Requires-Dist: semble>=0.1
Requires-Dist: tree-sitter-language-pack<1.6.3
Requires-Dist: typer>=0.12
Description-Content-Type: text/markdown

# climble

A thin Typer CLI wrapper around [`semble`](https://github.com/MinishLab/semble) — instant code search for any local or git repo, from your shell.

`climble` mirrors the two operations exposed by semble's MCP server (`search` and `find_related`) so its output is interchangeable with what an MCP-connected agent would see.

Some of the helpers in `src/climble/cli.py` are adapted from semble's `src/semble/mcp.py` under the MIT license — see [`THIRD_PARTY_LICENSES.md`](THIRD_PARTY_LICENSES.md).

## Install

```bash
# from PyPI (once published)
uv add climble
# or, in this repo:
uv sync
```

## Usage

```bash
# Search the current directory
uv run climble search "save model to disk"

# Search a remote repo (cloned to a temp dir; no cache between invocations)
uv run climble search "tokenizer chunking" --repo https://github.com/MinishLab/semble -k 10

# Pick a search mode (hybrid|semantic|bm25)
uv run climble search "BM25" --mode bm25

# Find chunks semantically similar to a specific location, using
# file_path:line from a prior `search` result
uv run climble find-related src/climble/cli.py 67
```

### Options

Both commands accept:

- `--repo, -r` — git URL or local path. Default: `.`
- `--top-k, -k` — number of results. Default: `5`
- `--ref` — branch/tag (git URLs only)

`search` additionally accepts:

- `--mode, -m` — `hybrid` (default), `semantic`, or `bm25`

## Notes

Each invocation re-indexes from scratch — there is no persistent on-disk cache. For repeated queries against the same repo, run [semble's MCP server](https://github.com/MinishLab/semble) directly, which caches indexes in-process for the lifetime of the session.

## Development

```bash
make install   # uv sync --group dev + pre-commit install
make test      # uv run pytest
make lint      # ruff check + format check + ty
make check     # lint + test
make format    # ruff --fix + format in place
```

### Releasing

Releases are cut through GitHub Releases — **not** a manual publish command. Publishing a release fires [`.github/workflows/publish.yml`](.github/workflows/publish.yml), which runs `uv build && uv publish --trusted-publishing always` inside the `pypi` environment via OIDC. There are no stored PyPI tokens to rotate.

The flow:

1. Land changes on `main`. Ensure CI is green (`style` + `test` workflows).
2. Bump `version` in [`pyproject.toml`](pyproject.toml) and `__version__` in [`src/climble/__init__.py`](src/climble/__init__.py). Keep them in sync. Pre-1.0: minor bump for new features, patch bump for fixes.
3. Promote the `## Unreleased` section in [`CHANGELOG.md`](CHANGELOG.md) to `## X.Y.Z — YYYY-MM-DD`. Add a fresh empty `## Unreleased` above it.
4. Commit as `chore(release): vX.Y.Z`. Duplicate the CHANGELOG section into the commit body so the commit stands alone.
5. Push: `git push origin main`.
6. Tag with the full release notes in the annotation. Write the new CHANGELOG entry's body to a temp file, then: `git tag -a vX.Y.Z --cleanup=verbatim -F notes.md && git push origin vX.Y.Z`.
7. Create the GitHub Release from the tag: `gh release create vX.Y.Z --notes-from-tag --title vX.Y.Z` (or use the web UI). Publication triggers the publish workflow.

**Why steps 6 and 7 look like this.** `gh release create --notes-from-tag` copies the tag annotation verbatim into the release body, so the annotation *is* the release notes — `-m vX.Y.Z` produces an effectively empty release body. `-F notes.md` fills the annotation from a real file. `--cleanup=verbatim` is required to keep `##` markdown headers — without it, git strips every line starting with `#` as a comment, so your section structure disappears before it ever reaches GitHub.

The `make pypi` target is a **manual fallback only**, not the canonical path. It runs `uv build && uv publish` locally and requires a PyPI token in the environment; it bypasses CI's clean build and the version/tag/changelog discipline above. Avoid it unless Trusted Publishing is down.

#### One-time setup before the first release

- **PyPI Trusted Publisher**: register this repo as a Trusted Publisher on PyPI for the `climble` project. Workflow filename: `publish.yml`. Environment: `pypi`. (Until this is configured, the publish workflow will fail with an OIDC error.)
- **GitHub Environment**: create an environment named `pypi` in the repo settings. No secrets needed (OIDC).
- **PyPI name availability**: `climble` is currently un-claimed on PyPI as of writing; if it gets taken, fall back to `climble-cli` for the distribution name (the import name and CLI command stay `climble`) — see how croc handles this in [`croc-cli`](https://github.com/jesshart/croc).

## License

MIT — see [`LICENSE`](LICENSE) and [`THIRD_PARTY_LICENSES.md`](THIRD_PARTY_LICENSES.md).
