Metadata-Version: 2.4
Name: koshas
Version: 0.0.12
Summary: kosha (कोश) — a treasury of your repo and environment context for coding agents. FTS5 + vector search + call graph, no LLMs required.
Project-URL: Repository, https://github.com/vedicreader/kosha
Project-URL: Documentation, https://vedicreader.github.io/kosha/
Author-email: Karthik <karthik.rajgopal@hotmail.com>
License: Apache-2.0
License-File: LICENSE
Keywords: code graph,code search,devtool,nbdev,repo-context
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Requires-Dist: fastprogress>=1.1.5
Requires-Dist: litesearch>=0.0.22
Requires-Dist: pyan3>=2.4.3
Requires-Dist: pyskills>=0.0.4
Requires-Dist: watchfiles>=1.1.1
Description-Content-Type: text/markdown

# kosha


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

kosha (कोश) — persistent knowledge of your codebase and installed
packages for humans and AI coding assistants.

> FTS5 + vector search + call graph, merged with RRF. Each result
> includes the snippet, callers, callees, and PageRank. No LLMs
> required.

## Install

kosha is a **dev dependency** — it indexes at development time so AI
coding assistants can search it.

``` sh
uv add --dev kosha
```

One-time project setup — installs `SKILL.md` so every agent picks up the
skill automatically:

``` python
Kosha(install_skill=True)   # writes .agents/skills/kosha/ and .claude/skills/kosha/
```

## Sync

Once per session; subsequent calls are incremental (only changed files
and new versions re-indexed).

``` python
k = Kosha()
k.sync(pkgs=['fastcore', 'litesearch'])
```

    syncing files [Path('/Users/71293/code/personal/orgs/kosha/kosha/cli.py'), Path('/Users/71293/code/personal/orgs/kosha/kosha/core.py'), Path('/Users/71293/code/personal/orgs/kosha/kosha/graph.py'), Path('/Users/71293/code/personal/orgs/kosha/kosha/skill.py')] .....
    synced repo
    loading pkgs {'fastcore', 'litesearch'} ......

    Updating packages:   0%|          | 0/2 [00:00<?, ?pkg/s]

    updating pkg: fastcore ...

    Updating packages: 100%|██████████| 2/2 [00:00<00:00,  5.41pkg/s]

    package {'name': 'fastcore', 'version': '1.12.43'} already loaded.
    updating pkg: litesearch ...
    package {'name': 'litesearch', 'version': '0.0.25'} already loaded.

    no action. pkgs empty

    [None, None, <kosha.graph.CodeGraph object>]

``` python
k.status()
```

    {'files': 3, 'packages': 81, 'graph_nodes': 78502, 'stale_files': 0}

Re-run `k.sync()` after `uv add`, version bumps, or significant code
changes. If `stale_files > 0` or `stale_pkgs` is non-empty, sync before
querying.

## 1 — Check before implementing

*Before writing any new function, verify it doesn’t already exist in a
dependency.*

``` python
results = k.env_context('atomic write temp file permissions', limit=5)
for r in results:
    print(r['metadata']['mod_name'])
    print(' ', r['content'].splitlines()[0])
    print()
```

    setuptools._core_metadata.write_pkg_info
      def write_pkg_info(self, base_dir):

    fastcore.xtras.atomic_save
      def atomic_save(fn, mode='wb', uid=-1, gid=-1, **kwargs):

    jupyter_server.services.contents.fileio.FileManagerMixin
      class FileManagerMixin(LoggingConfigurable, Configurable):

    anyio._core._tempfile.SpooledTemporaryFile.write
      async def write(self: SpooledTemporaryFile[bytes], b: ReadableBuffer) -> int: ...

    jupyter_server.services.contents.fileio.FileManagerMixin
      class FileManagerMixin(LoggingConfigurable, Configurable):

Package names in the query are auto-detected as filters. `package:`,
`path:`, `type:` tokens narrow further:

``` python
k.env_context('package:fastcore path:xtras atomic save', limit=8)
```

## 2 — Find existing patterns

*Any task that adds or modifies behaviour. Run before touching files.*

``` python
results = k.context('search code embeddings', limit=6, graph=True)
for r in results:
    m = r['metadata']
    print(f"{m['mod_name']}  L{m.get('lineno','?')}  "
          f"pr={r.get('pagerank',0):.4f}  callers={list(r.get('callers',[]))[:2]}")
```

    kosha.core.repo_context  L469  pr=0.0003  callers=['kosha.graph.context', 'kosha.core.Kosha']
    litesearch.core.vec_search  L42  pr=0.0001  callers=['litesearch.core.Table']
    kosha.core.env_context  L439  pr=0.0003  callers=['kosha.graph.context', 'kosha.core.Kosha']
    litesearch.core.vec_search  L42  pr=0.0001  callers=['litesearch.core.Table']
    kosha.core.repo_context  L364  pr=0.0003  callers=['kosha.graph.context', 'kosha.core.Kosha']
    chonkie.handshakes.pinecone.PineconeHandshake.search  L201  pr=0.0000  callers=['chonkie.chunker.slumber.SlumberChunker._extract_index_from_text', 'chonkie.handshakes.elastic.ElasticHandshake.search']

`pagerank` = blast radius — higher means more things depend on it, touch
carefully.

## 3 — Understand a node

*Who calls this? What does it call? What are its peers?*

``` python
info = k.ni('fastcore.basics.merge')
print('pagerank:', info.get('pagerank', 0))
print('callers: ', list(info.get('callers', []))[:5])
print('callees: ', list(info.get('callees', []))[:5])
print('co_dispatched:', list(info.get('co_dispatched', []))[:5])
```

    pagerank: 3e-05
    callers:  ['fastcore.script.call_parse._f']
    callees:  ['fastcore.basics.NS.__iter__', 'fastcore.nbio.Notebook.__iter__', 'fastcore.xtras.SaveReturn.__iter__', 'fastcore.xml.FT.__iter__', 'fastcore.docscrape.NumpyDocString.__iter__']
    co_dispatched: []

`co_dispatched` lists sibling functions registered together (route
groups, handler tables, plugin lists) — the pattern to follow when
adding a new one.

## 4 — Find where to add new code

``` python
pts = k.where_to_add('add dynamic ast parsing for patched functions', limit=3)
for p in pts:
    co = ', '.join(p['co_dispatched'][:3])
    print(f"{p['path']}:{p['insert_after']}  ({p['node']})")
    if co: print(f'  peers: {co}')
```

    /Users/71293/code/personal/orgs/kosha/kosha/graph.py:130  (kosha.graph._patch_edges)

## Triage — scan many results quickly

`compact=True` strips full code bodies and returns slim dicts for fast
scanning.

``` python
hits = k.context('database search filter package:litesearch', limit=10,repo=False, compact=True)
for r in hits:
    sig = r.get('sig', '')
    doc = (r.get('docstring') or '')[:60]
    print(f"{r['mod_name']}  L{r.get('lineno','?')}")  
    if sig: print(f'  {sig}')
    if doc: print(f'  # {doc}')
```

    litesearch.core.vec_search  L42
      def vec_search(self: Table,
    litesearch.core.vec_search  L42
      def vec_search(self: Table,
      # Vector similarity search on any table with an embedding colu
    litesearch.core.database  L75
      def database(pth_or_uri:str=':memory:',     # the database name or URL
    litesearch.core.database  L75
      def database(pth_or_uri:str=':memory:',     # the database name or URL
      # Set up a database connection and load usearch extensions.
    litesearch.core.search  L94
      def search(self: Database,  # database connection
      # Search the litesearch store with fts and vector search combi
    litesearch.data.pre  L243
      def pre(q:str,          # query to be passed for fts search
      # Preprocess the query for fts search.
    litesearch.core.search  L94
      def search(self: Database,  # database connection
    litesearch.data.pre  L240
      def pre(q:str,          # query to be passed for fts search
    litesearch.data.clean  L218
      def clean(q:str  # query to be passed for fts search
    litesearch.data.clean  L221
      def clean(q:str  # query to be passed for fts search
      # Clean the query by removing * and returning None for empty q

## Public API surface

``` python
api = k.public_api('fastcore', limit=12)
for e in api:
    name = e.get('mod_name', '')
    doc = (e.get('docstring') or '')[:55]
    print(f"{name}" + (f'  # {doc}' if doc else ''))
```

    fastcore.foundation.cycle
    fastcore.foundation.product
    fastcore.foundation.flatmap
    fastcore.foundation.unique
    fastcore.foundation.val2idx
    fastcore.foundation.range
    fastcore.foundation.enumerate
    fastcore.foundation.renumerate
    fastcore.foundation.split
    fastcore.foundation.splitlines
    fastcore.foundation.map
    fastcore.foundation.groupby

## CLI

Shell access to everything. Markdown by default; `--as_json` pipes into
`jq`.

``` bash
kosha install                         # install SKILL.md to .agents/ and .claude/
kosha sync  # index repo + env + call graph
kosha status # check index freshness
kosha context "embed a query" --as_json | jq '.[].metadata.mod_name'
kosha ni "fastcore.basics.merge" # node info
kosha where-to-add "new route handler"
kosha public-api fastcore
kosha api-paths kosha litesearch
kosha daemon # persistent kernel — warm for all session calls
```

## Harness install

``` python
Kosha(install_skill=True)   # installs to .agents/ and .claude/
```

Commit `.agents/skills/kosha/SKILL.md` so every contributor picks up the
skill automatically.

## pyskills

kosha registers as a [pyskill](https://github.com/AnswerDotAI/pyskills)
(`kosha.skill`) for Python-native LLM hosts.
