# Code

URL: https://docs.hanzo.ai/docs/openapi/code

> Search and symbols across your repos, for you and your agents.

Also for this capability: **API** · [CLI](https://docs.hanzo.ai/docs/cli/code) · [MCP](https://docs.hanzo.ai/docs/mcp-tools/code) · [SDKs](https://docs.hanzo.ai/docs/sdks)

Search and symbols across your repos, for you and your agents.

> [All API references →](https://docs.hanzo.ai/docs/openapi) · [Get started →](https://docs.hanzo.ai/docs/guides)

|                |                                        |
| -------------- | -------------------------------------- |
| **Base URL**   | `https://api.hanzo.ai`                 |
| **Operations** | 7                                      |
| **Auth**       | `Authorization: Bearer $HANZO_API_KEY` |

## Specification

> **HIP-1114 · Code — Search and Symbols** — Draft · [read the specification →](https://github.com/hanzoai/hips/blob/7ed737180339cd05b5f2935eafe7f7b83d2449a2/HIPs/hip-1114-code.md)

`/v1/code` is search and symbols across an org's repositories, for people and
for their agents: a per-org code-intelligence engine implemented in
`hanzoai/cloud` `apps/code`. Retrieval is hybrid — lexical, symbolic and
semantic tiers fused with reciprocal-rank fusion — because embeddings alone
under-serve code search (`apps/code/code.go:3-6`). This HIP states the three
tiers, the physical org boundary of the store, and how the one paid dependency
(embeddings) is attributed.

### Motivation

An agent editing code needs three different questions answered well: "where
does this string appear" (exact, including operators and case conventions),
"where is this symbol defined and used" (structural), and "what code means
this" (semantic). Each tier serves one of them and fails at the others; a
single-tier engine forces every question through the wrong index.

### Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted
as in RFC 2119.

#### §1 The three tiers

- **lexical** — FTS5 trigram over code-tokenized text: camelCase and
  snake\_case split, operators kept; substring and regex in the Zoekt model
  (`apps/code/store.go`, `tokenize.go`).
- **symbolic** — `go/parser` for Go, with real def→ref edges; compact lexical
  extractors for TS/JS, Python, Rust and Solidity (`apps/code/parse.go`).
- **semantic** — AST-boundary chunks embedded through the same gateway
  `/embeddings` the knowledge plane uses, ranked by cosine over a float32
  vector table; the schema is kept compatible with a `sqlite-vec` `vec0` KNN
  as a future seam, not a linked dependency today (`apps/code/store.go:561`).

`hybrid` fuses the tiers; a caller may also pin one with `type=`.

#### §2 The store

One SQLite file per org at `{DataDir}/orgs/{slug}/code.db` (HIP-0302): the org
boundary is physical, so a query in one org's file can never reach another
org's rows (`apps/code/code.go:17-19`). Stores open lazily through the shared
`cloud.OrgStore` cache, and `storeFor` is the one way the package reaches one
(`apps/code/code.go:91`, `code.go:141-150`). Bounds cap what one request can
amplify into the shared file or the gateway (`apps/code/code.go:47-58`).

#### §3 The addresses

Everything is under `/v1/code`: `search`, `context` (a budget-packed context
bundle), `ask` (a cited RAG answer), `index` (incremental, with prune), `file`
and `tree`. All operations are typed
(`apps/code/typed_wire_test.go`). `/v1/code/lsp` is NOT this capability: the
live language server is its own capability routed by prefix specificity
(`manifest/apps.go:315,325`), folded under this address because static index
and live server are two reads of one repository.

#### §4 Tenancy and money

Every request resolves its org through `principal.Org` (HIP-0026): no validated
principal, 403; a client `X-Org-Id` is never trusted. The surface itself is
free (`plugin/code/main.go:21`, `cloud.Free`). Its embedding calls are billed
where inference is always billed — on the AI plane — attributed to
`principal.Ledger` and the server-minted project, neither of which may be an
input field (`apps/code/code.go:176-189`). Off the HTTP path both are empty,
which is the unbilled default — and `principal.Acting` has already refused
before any op runs.

#### §5 Events, telemetry, stage, upstreams

It publishes no events on the bus and emits nothing to observability beyond the
request span. Its stage is `ga`: the manifest row (`manifest/apps.go:315`)
declares no stage, and absent means `ga`. It embeds no third-party engine: parsing is the Go
standard library plus this package's own extractors, storage is the
`hanzoai/sqlite` facade, and the lexical design follows the trigram model Zoekt
demonstrated without importing it.

### Rationale

The alternative to per-org files is one index with an org column — cheaper to
operate, and one forgotten predicate away from serving one tenant's source to
another. Source code is the asset tenants trust the platform with least
willingly, so the boundary is physical and the cost (an open file per active
org, amortized by the store cache) is accepted.

The alternative to fusing three tiers is picking one. Embeddings-only misses
exact identifiers; lexical-only cannot answer "what code does this"; fusion is
the measured lesson of code retrieval and each tier stays independently
testable (`apps/code/search.go`).

### Security Considerations

The store is an index of private source. The wrong implementation leaks it two
ways: across tenants (closed physically, §2) or through the paid seam — an
attacker who can set the billing org or project on an embedding call can charge
inference to a victim, which is why payer and project come only from validated,
server-minted values (§4). `ask` answers only from the caller's own org's
index, so the RAG surface cannot become a cross-tenant oracle.

## Four surfaces

| Surface  | Reaches this capability as                   | Coverage                                                                  |
| -------- | -------------------------------------------- | ------------------------------------------------------------------------- |
| **REST** | `code` at its own prefix                     | 7 operations                                                              |
| **CLI**  | `hanzo code …`                               | 7 of 7                                                                    |
| **SDK**  | `CodeApi` in every published client          | 7 methods                                                                 |
| **MCP**  | tool `code` on `https://api.hanzo.ai/v1/mcp` | 7 operations, 4 under the document's own id — ask `describe` for the rest |

## Quickstart

```bash
export HANZO_API_KEY=sk-...   # console.hanzo.ai → API keys
```

Then the first call — a read that needs nothing but the key. `GET /v1/code/ask`, operation `get_code_ask`:

**CLI**

```bash
hanzo code ask get
```

**SDK**

**.ts**

```ts
import { Configuration, CodeApi } from 'hanzoai';

const api = new CodeApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.getCodeAsk();
```

**.py**

```python
from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import CodeApi

client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = CodeApi(client).get_code_ask()
```

**.go**

```go
cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)

resp, _, err := client.CodeAPI.GetCodeAsk(context.Background()).Execute()
if err != nil {
	return err
}
```

**.rs**

```rust
use hanzo_client::apis::{configuration::Configuration, code_api};

let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();

let result = code_api::get_code_ask(&cfg, Default::default()).await?;
```

**.java**

```java
import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.CodeApi;

ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));

var result = new CodeApi(client).getCodeAsk();
```

**HTTP**

```bash
curl https://api.hanzo.ai/v1/code/ask \
  -H "Authorization: Bearer $HANZO_API_KEY"
```

**MCP**

Tool `code`, op `get_code_ask` — POST the JSON-RPC envelope to `https://api.hanzo.ai/v1/mcp`.

```bash
curl -X POST https://api.hanzo.ai/v1/mcp \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "jsonrpc": "2.0",
       "id": 1,
       "method": "tools/call",
       "params": {
         "name": "code",
         "arguments": {
           "op": "get_code_ask",
           "input": {}
         }
       }
     }'
```

Answers `200` with `object` — ok.

## Endpoints

| Endpoint                                                                             | What it does                                                                                                                                                                                                                                                             |
| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [`GET /v1/code/ask`](https://docs.hanzo.ai/docs/openapi/code/get-code-ask)           | Answers a question about the caller org's code with a CITED answer: retrieval packs grounding context, then the synthesizer writes the answer over exactly those spans, which come back alongside it.                                                                    |
| [`POST /v1/code/ask`](https://docs.hanzo.ai/docs/openapi/code/post-code-ask)         | Answers a question about the caller org's code with a CITED answer, taking the question from the request BODY, for a question too long or too awkward to put in a URL.                                                                                                   |
| [`POST /v1/code/context`](https://docs.hanzo.ai/docs/openapi/code/post-code-context) | Packs the most relevant code for a query into a token budget — THE primitive for a coding agent that has to decide what to put in a prompt.                                                                                                                              |
| [`GET /v1/code/file`](https://docs.hanzo.ai/docs/openapi/code/get-code-file)         | Returns the INDEXED content of one file — read\_file over the chunks the search tiers hold, for pulling up code an agent just found.                                                                                                                                     |
| [`POST /v1/code/index`](https://docs.hanzo.ai/docs/openapi/code/post-code-index)     | (re)indexes a repository for the caller's org, incrementally: files whose content hash is unchanged are skipped, so re-sending a whole tree is cheap.                                                                                                                    |
| [`GET /v1/code/search`](https://docs.hanzo.ai/docs/openapi/code/get-code-search)     | Finds code in the caller org's index across three orthogonal retrieval tiers fused by reciprocal-rank fusion: lexical (FTS5 trigram over code-tokenized text), symbolic (real definition and reference edges), and semantic (embedding cosine over AST-boundary chunks). |
| [`GET /v1/code/tree`](https://docs.hanzo.ai/docs/openapi/code/get-code-tree)         | Returns one repository's file structure with a per-file symbol count — get\_repo\_structure over the org's own index, with no git checkout involved.                                                                                                                     |

---

[All Hanzo APIs](https://docs.hanzo.ai/docs/openapi) · [Interactive reference](https://docs.hanzo.ai/docs/openapi/reference)
