Skip to main content

kosha (कोश) — a treasury of your repo and environment context for coding agents. FTS5 + vector search + call graph, no LLMs required.

Project description

kosha

kosha (कोश) - A treasury of your repo and environment context for humans and coding assistants. > kosha gives you persistent knowledge of your codebase and installed packages — indexed with FTS5 + vector search + call graph, merged with Reciprocal Rank Fusion. Results include the code snippet, callers, callees, and PageRank. No LLMs required.

Install

kosha is a dev dependency — it runs at development time so your AI coding assistant can search your code. It does not ship with your application.

# uv (recommended)
uv add --dev koshas

# pip
pip install --group dev koshas

One-time project setup

Run this once to drop a SKILL.md into .agents/skills/kosha/ — the file your AI harness reads to know kosha exists and how to call it.

Kosha(install_skill=True)   # writes .agents/skills/kosha/SKILL.md at your repo root
# Commit this file so every contributor (and every AI) gets it automatically.

Sync once per session

Index your repo code, installed packages, and call graph in one call. Subsequent calls are incremental — only changed files and new package versions are re-indexed.

k = Kosha()   # auto-detects git repo root

k.sync(pkgs=['fasthtml', 'fastcore', 'litesearch'])
# Indexes:
#   .kosha/code.db   — your repo code chunks + embeddings
#   .kosha/graph.db  — call graph (callers, callees, PageRank)
#   ~/.local/share/kosha/env.db — installed packages (shared across repos)

Searching — context()

The main entry point. Parses optional key:value filters, auto-detects package names, fans out searches in parallel, and merges everything with chained RRF.

With graph=True (default) each result is enriched with call graph data from .kosha/graph.db.

results = k.context('how do I render a toast notification', limit=10)

for r in results:
    m = r['metadata']
    print(f"{m['mod_name']}  (line {m.get('lineno','?')})")
    print(f"  pagerank={r.get('pagerank',0):.5f}  callers={r['callers'][:2]}")
    print(f"  {r['content'][:100]}")
    print()

What each result contains

Every result is a plain dict — code snippet plus structural context from the call graph:

{
  # The code
  'content':  'def merge(*ds):\n    "Merge all dicts"\n    return {k:v for d in ds ...}',

  # Where it lives
  'metadata': {
      'mod_name': 'fastcore.basics.merge',   # fully-qualified — use in ni() / short_path()
      'path':     '/path/to/fastcore/basics.py',
      'lineno':   655,
      'type':     'FunctionDef',
      'package':  'fastcore',                # present on package results
  },

  # Structural position in the codebase
  'pagerank':      0.00027,  # centrality — higher = more load-bearing
  'in_degree':     8,        # number of callers
  'out_degree':    12,       # number of callees
  'callers':       ['fastcore.script.call_parse._f', ...],
  'callees':       ['fastcore.basics.NS.__iter__', ...],
  'co_dispatched': [],       # functions registered alongside this one
}

co_dispatched is particularly useful: it lists functions assigned together in the same list, dict, or route group at module level — the pattern to follow when adding a new handler or plugin.

Filter syntax

Add key:value tokens anywhere in your query to narrow results. Plural forms and comma-separated values are supported.

Token Example Effect
package:name package:fasthtml Restrict env search to one package
file:glob file:routes* Restrict repo results by filename
path:pattern path:api/* Restrict repo results by path
lang:ext lang:py Filter by language
type:node type:FunctionDef Filter by AST node type

Filters can be combined and stacked: "stripe webhook path:payments/ type:FunctionDef"

# parseq strips filter tokens from a query — fast, no DB needed
bare, filt = parseq('stripe webhook path:payments/ type:FunctionDef')
print(f'query:   {bare!r}')
print(f'filters: {dict(filt)}')
# Restrict to a specific package
results = k.context('render a table package:fasthtml', limit=5)

# Functions only, in the payments directory
results = k.context('handle stripe webhook type:FunctionDef path:payments/', limit=5)

# Multiple packages — fan-out in parallel, results merged
results = k.context('payments page packages:fasthtml,monsterui', limit=15)

The structural layer — CodeGraph

k.graph is a CodeGraph backed by .kosha/graph.db. After k.sync(), the graph covers your repo and every indexed package. You can traverse it directly, or let context() enrich results automatically.

# Full structural info for any node
k.ni('fastcore.basics.merge')
# → {node, flavor, file, pagerank, in_degree, out_degree, callers, callees, co_dispatched}

# Top nodes by PageRank within a module
k.graph.ranked(10, module='fastcore.basics')

# Shortest call chain between two nodes
k.short_path('apswutils.db.Table.upsert', 'apswutils.db.Table.insert_chunk')
# → ['...upsert', '...upsert_all', '...insert_all', '...insert_chunk']

# Everything within 2 hops of a node
k.neighbors('myapp.payments.verify_webhook', depth=2)

# Direct table queries
k.gn(where='node like "%stripe%"')    # graph_nodes
k.ge(where='caller like "%route%"')   # graph_edges

API discovery

Two functions for quickly surfacing what a package exposes.

pkg_url(pkg) — returns the best web URL for an installed package from its metadata (Source Code > Repository > Home-page). Useful when you need to fetch docs or browse source.

k.public_api(module, min_callees, limit) — queries the code graph for public entry points: functions with in_degree=0 (nothing in the indexed code calls them externally) and no underscore prefix. Returns each node’s name, graph metrics, and docstring pulled from the indexed content.

from kosha import pkg_url

# Package web URL — useful for WebFetch or browsing docs
pkg_url('fastcore')   # → 'https://github.com/fastai/fastcore'
pkg_url('httpx')      # → 'https://github.com/encode/httpx'

# Public API surface from the call graph
# Returns functions with in_degree=0 (no internal callers) + their docstrings
api = k.public_api(module='fastcore', min_callees=1, limit=20)
for fn in api:
    print(fn['node'], '|', fn.get('docstring', '')[:60])

# Without module filter — all public entry points across everything indexed
all_entry_points = k.public_api(min_callees=0)

Composing a plan — the full workflow

The highest-value pattern strings contextshort_pathni together. Each step narrows the search space and adds structural evidence before you write a line of code.

Step 1 — find the key functions (graph-enriched)

results = k.context('webhook signature verification payments', limit=20, graph=True)
# Sort by pagerank to find the structural load-bearers
key = sorted(results, key=lambda r: -r.get('pagerank', 0))

Step 2 — map the call chains

from itertools import combinations
nodes = [r['metadata']['mod_name'] for r in key[:8]]
paths = [p for a, b in combinations(nodes, 2) if (p := k.short_path(a, b))]
paths.sort(key=len)   # shortest = tightest coupling between your key nodes

Step 3 — drill into the join points

for node in nodes[:5]:
    info = k.ni(node)
    # callers       → where to hook in upstream
    # callees       → what you can reuse
    # co_dispatched → pattern to follow when adding a new handler alongside existing ones

Step 4 — write your plan, grounded in mod_name:lineno

for r in key[:5]:
    m = r['metadata']
    print(f"{m['mod_name']}  line {m.get('lineno','?')}  pagerank={r.get('pagerank',0):.5f}")

Quoting mod_name + lineno in each step of your plan anchors the plan to the actual code.

Using with Claude Code and other harnesses

Project-local (commit alongside code)

The Kosha(install_skill=True) call above writes .agents/skills/kosha/SKILL.md. Most agent harnesses (Claude Code, Continue.dev, Cursor, Copilot) auto-discover skills in .agents/skills/. Committing this file means every contributor — human and AI — gets it automatically.

Claude Code — global (all projects on this machine)

mkdir -p ~/.claude/skills/kosha
cp .agents/skills/kosha/SKILL.md ~/.claude/skills/kosha/SKILL.md

Once installed globally, Claude Code will load the kosha skill at the start of every session in every repo.

Other harnesses

Place SKILL.md wherever the harness discovers agent skills. Common locations: - .agents/skills/kosha/SKILL.md — general convention - .continue/skills/kosha/SKILL.md — Continue.dev - Configure in harness settings if the path differs

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

koshas-0.0.7.tar.gz (32.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

koshas-0.0.7-py3-none-any.whl (33.9 kB view details)

Uploaded Python 3

File details

Details for the file koshas-0.0.7.tar.gz.

File metadata

  • Download URL: koshas-0.0.7.tar.gz
  • Upload date:
  • Size: 32.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for koshas-0.0.7.tar.gz
Algorithm Hash digest
SHA256 bee8e6707f8464e31cca43b5f78276af8c19c3bbc0366f545a9fb9e941a8328c
MD5 6b98e754877415f5efc9ca307d2da23a
BLAKE2b-256 428271c83761b2ec9adbbcd32147661ff348a598490e8743d0432b65e74b6c9c

See more details on using hashes here.

File details

Details for the file koshas-0.0.7-py3-none-any.whl.

File metadata

  • Download URL: koshas-0.0.7-py3-none-any.whl
  • Upload date:
  • Size: 33.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for koshas-0.0.7-py3-none-any.whl
Algorithm Hash digest
SHA256 267cd4e133736860054ada188d6586508dbb46ebc106ffa4693feba4c9b538ff
MD5 19d623fd82bf2ac86bcf5b207cd17718
BLAKE2b-256 b8111f506a248f970fb46feda6305dd2e0702e87e58450c54c11eeede22d734f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page