# Query layer

> Documentation index: [llms.min.txt](https://caseyrfsmith.github.io/scull/llms.min.txt) · Document manifest: [documents.json](https://caseyrfsmith.github.io/scull/documents.json)

Breadcrumbs: Reference > Query layer

Scull's query layer reads a local schemaset and its compatible index. It has no account, hosted
service, or remote-provider dependency.

```python
from scull.query import get_schema_provider

provider = get_schema_provider()
field = provider.get("schema", "schema_version")
context = provider.context("schema", ["schema_version"])
concepts = provider.list_concepts()
```

`get_schema_provider()` returns a `FileSchemaProvider`. Set `SCULL_SCHEMA_PATH` to select a schema
directory; otherwise Scull discovers `schemas/` from conventional local locations. CLI and
Python readers use the same loader and fail closed on malformed YAML, unsupported versions, invalid
schema structure or attachments, and duplicate concepts; invalid files are not silently skipped.

## Operations

### `get(concept, field=None)`

Returns a complete schema or one field definition. This is a local YAML lookup.

### `context(concept, fields, situations=None, *, detailed=False)`

Returns selected field definitions plus attached and concept-wide caveats. Situation tags are
explicit lowercase dot-delimited metadata—not semantic matching. Omitting them conservatively
returns all applicable attached and general caveats.

The default is compact for agent use. JSON Schema fields retain qualified names, types,
descriptions, required scopes, concise constraint strings, examples/default annotations,
completeness, and rule links without complete interpretation records. Pass `detailed=True` for
those records, or follow a rule link with `inspect_schema()` for bounded original evidence.
Artifact warnings are likewise grouped by kind and count in compact mode; detailed mode retains the
complete warning objects.

The bundle also exposes `needs_review`, `warnings`, `conflicts`, and `release_ready` alongside the
schema hash and version. `release_ready` reflects the mechanical release contract, including a
current approval fingerprint; it is not a claim that the documentation is factually correct.

```python
provider.context(
    "deployment_config",
    ["values"],
    situations=["payload.size"],
)
```

### `list_concepts()` and `list_fields(concept)`

Return local schemaset inventory. No index or network is required.

### `search(query, top_k=5, concepts=None)`

Search uses a snapshot-pinned `SearchEngine` shared by the CLI, schemafier search command, and local
server. It combines cosine similarity with deterministic lexical overlap:

```text
score = cosine_similarity + provider_lexical_weight × lexical_overlap
```

The document vectors are pre-baked into the index. Each uncached query is embedded by the
configured provider to produce a compatible query vector. Voyage and OpenAI make a network call;
the opt-in local providers run on-device. Exact provider identity and vector dimensions must match
the index manifest unless both sides declare the reviewed `voyage-4` compatibility family. That
family permits Large-built indexes to use hosted Lite or explicitly selected pinned Nano queries at
the same dimension. Unknown families and Voyage Code 4 remain exact-identity only, so equal-width
vectors from unrelated models cannot be mixed accidentally.
Search also recomputes actual schema content hashes and compares them with the pinned manifest
before embedding a query. A separately edited or deployed schemaset therefore fails with a rebuild
message before any hosted query text is sent.
If a compatible provider cannot embed the query, search returns lexical matches only rather than
blocking. Those results have `degraded: true`, `degraded_reason: "query_embedding_failed"`, and
`cosine_score: null`; a query with no lexical match returns an empty list. This fallback does not
hide index/provider incompatibility, which remains a hard error.

Use `concepts` to restrict ranking to an explicit domain:

```python
provider.search("how does retry backoff work?", concepts=["job_runtime"])
```

Programmatic callers can inspect `provider.search_degraded` after each search. The CLI also writes a
degraded-mode warning to stderr.

`FileSchemaProvider` and `SearchEngine` pin their loaded artifacts. Recreate or reload long-lived
instances after deploying a matching schemaset/index pair.

## Agent tool adapter

`scull.agent.SCULL_CONTEXT_TOOL` is an SDK-neutral function-tool definition for field-triggered
context lookup. `invoke_context_tool(provider, arguments)` validates its arguments and returns the
same compact deterministic JSON bundle as `provider.context()`. Register the separate
`SCULL_INSPECT_SCHEMA_TOOL` when an agent needs bounded access to complete mechanical evidence.

The public tool name is `scull_context`. Related integrations use `scull_search`,
`scull_get`, and `scull_caveats`.

## Environment

| Variable                  | Purpose                     | Default                  |
| ------------------------- | --------------------------- | ------------------------ |
| `SCULL_SCHEMA_PATH`       | Local schemaset directory   | Auto-discover `schemas/` |
| `SCULL_EMBED_PROVIDER`    | Query embedding provider    | `voyage`                 |
| `SCULL_EMBED_MODEL`       | Provider model override     | Provider default         |
| `SCULL_EMBED_CACHE_DIR`   | Local model cache directory | FastEmbed default        |
| `SCULL_EMBED_TIMEOUT`     | Provider request timeout    | `10` seconds             |
| `SCULL_EMBED_MAX_RETRIES` | Client retry count          | `1`                      |

Voyage and OpenAI use a lexical weight of `0.3`. The benchmarked local MiniLM provider uses `0.1`;
the lower value preserved semantic ordering better in its fixed development sweep.

There is intentionally no remote `SchemaProvider` in v0.1. Schemasets remain portable local
artifacts, and a future managed build service would deliver artifacts rather than become a query
runtime dependency.
