Skip to main content

g6-ctx-elastic

Use when an agent must search, read or count documents in an Elasticsearch server the person runs, over fields the index's mapping really holds, so a query that cannot match is refused instead of answered with no hits, a partial answer says so, and every hit comes back as untrusted text with its address on the server.

Source facts

Repository
basicisabc1994/g6solver
Last source activity
October 26, 2026 at 01:52
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
g6-ctx-elastic
description
Use when an agent must search, read or count documents in an Elasticsearch server the person runs, over fields the index's mapping really holds, so a query that cannot match is refused instead of answered with no hits, a partial answer says so, and every hit comes back as untrusted text with its address on the server.
# G6 Elasticsearch reader Reads the Elasticsearch you run on this machine: searches chosen fields with exact filters, gets one document, counts and reads the mapping. Before a query is sent, every field and filter is checked against the index's mapping, because Elasticsearch answers a query on a field it does not hold with no hits rather than an error. Nothing is ever written to the server. ## When to use it - An agent needs documents from an Elasticsearch index you run (a handbook, tickets, logs) and must cite them. - You are not sure which fields an index holds: `mapping` lists them, and `search` refuses a field the index does not hold, an exact filter on analysed text and a field inside a nested object, each with what would work. - To use the index as a `g6.grounding` retriever from Python (`ElasticIndex`). ## When not to use it - To write, delete, reindex or administer an index: nothing here writes, by design. Use your own tools. - For a natural-language question turned into a query by a model: the query is built here from your words, fields and filters, never from query JSON. - For passages you hold yourself: `knowledge_indexer` keeps them under G6's state folder. ## Ops - `search`: search(index, query, fields, filters, top_k): the caller's words over chosen fields (every text field when none is named) with exact filters, each field checked against the mapping first; hits as untrusted passages with es_bm25 scores and the server's own count. Sensitive. - `get_doc`: get_doc(index, id): one document's _source, as untrusted text with its address on the server. Sensitive. - `count`: count(index, query, fields, filters): how many documents match (all of them with no query). Sensitive. - `mapping`: mapping(index): the index's fields and their types, so a search names fields it holds. Sensitive. ## Reading the result - `G6_E_KNOWLEDGE_ELASTIC_SEARCHED` (`qualified-draft`): `hits` (`rank`, `score`, `score_scale` `es_bm25`, `passage`: the chosen fields' text, its `source` the document's address on your server and the hash of its `_source`), `total` and `total_relation` (the server's count), `fields` searched and `complete`. `G6_E_KNOWLEDGE_ELASTIC_PARTIAL` (`qualified-draft`): some shards failed or the search timed out on the server, so the hits and the count are not the whole of the index. `G6_E_KNOWLEDGE_ELASTIC_NO_MATCH` (`qualified-draft`): the server answered with no match. - Refusals, each `blocked-escalated`: `G6_E_OUTSIDE_PROGRAM_MISSING` (nothing answering, with how to run it), `G6_E_KNOWLEDGE_ELASTIC_DENIED` (401 or 403), `_NOT_FOUND` (no such index or document), `_REJECTED` (the server refused the request), `_SERVER_ERROR`, `_TIMEOUT`, `_REDIRECTED` (never followed), `_PARSE_FAILED` (a reply that is not Elasticsearch's, or hits with none of the fields' text), `_COUNT_PARTIAL` (a count whose shards did not all answer: what they counted is in the evidence, never as `count`), `G6_E_KNOWLEDGE_FIELD_NOT_IN_MAPPING`, `G6_E_KNOWLEDGE_FILTER_ON_TEXT`, `G6_E_KNOWLEDGE_NESTED_FIELD`, `G6_E_KNOWLEDGE_NO_TEXT_FIELDS` and `G6_E_KNOWLEDGE_ELASTIC_INPUT` (an index name that is a pattern, a list, a path or a hidden index). ## Alone and composed Over MCP each op runs only when the person who runs the server lists it in `G6_MCP_SENSITIVE`: `g6_invoke("ctx_elastic", "mapping", {"index": "handbook"})`, then `g6_invoke("ctx_elastic", "search", {"index": "handbook", "query": "parental leave", "fields": ["title", "body"], "filters": {"team": "hr"}})`. There is no field for a host, a key or a query in Elasticsearch's own language. From Python: `from g6.knowledge.ctx_elastic import ElasticIndex`; `ElasticIndex("handbook", fields=("title", "body"))` has `find` (a `Searched`) and `search` (the `g6.grounding` retriever); it is also the `elastic` backend of `g6.knowledge._index.index_backends`, read only. `g6.knowledge.ctx_elastic.elastic` has `search`, `get_doc`, `count` and `mapping`, each taking `caller=` (a stand-in for `g6.core.outside.call_service` in your own tests). Composed: `g6.grounding` checks a claim against the hits; `knowledge_manifest` records a hit's passage and re-checks it later against the document as `get_doc` reads it again. ## Failure modes it catches - `under_retrieval` (relevant passages that retrieval never finds): a field the mapping does not hold, an exact filter on analysed text (which matches only one lower-cased word) and a field inside a nested object are refused before the query is sent, with the fields that would work; a reply from shards that did not all answer is partial, and a failed request is never "no match". ## Blind spots - `prompt_injection`: a hit is outside text and can carry instructions. It is untrusted data (its `trust` is always `untrusted`), instruction-like phrasing is named on the card, and nothing here acts on it. - `_score` is Elasticsearch's own relevance for one query (BM25 unless the index says otherwise); it is not a measure of truth, and it is comparable only within that query. - An analyser that does not suit the text (stemming, stop words, another language) can still miss what a person would find; the mapping check sees fields and types, not analysers. - Only a server on this machine is reached; a remote cluster needs a tunnel to a local port. Plain http only. ## What it needs Elasticsearch, which you run yourself on this machine (its licence is Elastic's own; G6 talks to it over HTTP and never imports, bundles or starts it): `http://127.0.0.1:9200`, or set `G6_ELASTIC_URL` to the local address it listens on. A server with security on needs its API key in your key file, `~/.g6/.env`, as `G6_ELASTIC_API_KEY=<key>`; it is sent to that server only. No extra and no model. ## Examples ```g6-example op=mapping {"index": "handbook"} ``` ```g6-example op=search {"index": "handbook", "query": "parental leave", "fields": ["title", "body"], "filters": {"team": "hr"}, "top_k": 5} ``` ```g6-example op=count {"index": "handbook", "query": "leave", "filters": {"team": "hr"}} ``` ```g6-example op=get_doc {"index": "handbook", "id": "leave-1"} ``` Each is sensitive: over MCP it runs only when the server's owner allows it. ```python from g6.core import outside from g6.knowledge.ctx_elastic import elastic def server(program, method, path, **_): # your Elasticsearch, in this example: its index holds title and body body = b'{"handbook": {"mappings": {"properties": {"title": {"type": "text"}, "body": {"type": "text"}}}}}' return outside.ServiceReply(200, {}, body) try: elastic.search("handbook", "parental leave", fields=["content"], caller=server) except elastic.ElasticError as refused: # a field the index does not hold: refused, never "no hits" assert refused.code == "G6_E_KNOWLEDGE_FIELD_NOT_IN_MAPPING" and "body (text)" in refused.reason ``` ## The four open problems - **Learning signals**: each reply records the fields searched and their types, the server's shard counts, its count and its relation, and every refusal's code. Not yet: nothing learns from them. - **Evaluators the model cannot influence**: the field check compares the request with the server's own mapping, and the partial flag reads the server's shard counts; no model is called and a hit's words change no outcome. - **Transfer by failure mode**: the checks are bound to `under_retrieval` and hold for every index; the typed refusals follow the family's rule that a failure is never read as empty. - **Enough held-out cases**: Not yet: the tests run against a local server answering as Elasticsearch does, not a frozen set of real cluster replies with relevance judgements.
View on GitHub