Miriel Docs

Python

The official Python client, miriel-python, wraps the REST API with keyword arguments, job helpers, streaming and conversation support.

Python Client

This is the official Python client library for interacting with the Miriel API.

Installation

bash
pip install miriel-python

# update
pip install --upgrade miriel-python

Basic Usage

Initialize the client with the API key from Settings → Developers, learn something, and ask about it:

python
import os
from miriel import Miriel

miriel_client = Miriel(api_key=os.environ["MIRIEL_API_KEY"])

# Add data (string example)
miriel_client.learn(
    "The Founders of Miriel are David Garcia, Josh Paulson, and Andrew Barkett",
    wait_for_complete=True
)

# Query the documents
query_response = miriel_client.query("Who are the founders of Miriel?")
print(query_response["results"]["llm_result"])

Miriel accepts many types of data: strings, file paths, directories, URLs, S3 buckets, RTSP feeds, and more.

Before you can query data, it must first be fully ingested with learn(). This can take less than a second or be a few minutes depending on the data. You can run learn() and query() as separate steps (recommended), or use wait_for_complete=True to ensure the learn job finishes before proceeding in a script.

Each query returns documents ranked by relevance. You can control the maximum number of results that are returned using the num_results parameter (default is 10). Note: This includes any pinned documents (see priority below). Any other REST query field (project, metadata_query, model, want_graph …) can be passed as a keyword argument too.

python
# Query with more results
query_response = miriel_client.query(
    "Who are the founders of Miriel?",
    num_results=20
)

Using Learn

Running Multiple Jobs and Waiting for Completion

You can enqueue multiple learn() jobs quickly, then block until only those jobs are finished before running queries:

python
from miriel import Miriel

m = Miriel(api_key="your_api_key")

# Enqueue two files without waiting
job_ids = []
for inp in ["https://example.com/a.pdf", "https://example.com/b.pdf"]:
    job_ids.extend(m.learn(inp, wait_for_complete=False)["job_ids"])

# Wait for exactly these jobs to complete
m.wait_for_jobs(job_ids, polling_interval=2)

# Now safely query
print(m.query("your query")["results"]["llm_result"])

This avoids waiting on unrelated jobs and keeps scripts fast and predictable.

Setting Metadata

You can attach metadata to any document using the learn() function. Metadata is stored as key-value pairs and must be passed as a Python dictionary.

Metadata can be used to tag documents by category, source, access level, version, or any other custom label. Miriel also assigns certain metadata fields automatically—such as priority, project, image data, document permissions, and other information—unless they are explicitly overwritten. You can view metadata fields in the Miriel dashboard.

These fields can be used for filtering results or managing documents during queries.

python
# Adding a custom metadata field to a string
miriel_client.learn(
    "The document ID is 12345",
    metadata={"internal_docs": True}
)

# Adding multiple metadata fields
miriel_client.learn(
    "The celebration is on the forest moon",
    metadata={"department": "engineering", "team": "83"}
)

You can assign any field name and value, as long as the key is a string and the value is a valid JSON-compatible type (e.g., string, number, boolean).

Document Priority and Pinning

Miriel uses a priority field, attached as metadata to a document, to influence how documents are ranked during retrieval. By default, every document is assigned priority=100 and this allows Miriel to determine each document's relative importance when ranking the results from a query. Overriding priority to set a higher value will slightly increase a document's ranking, while lower values will slightly decrease it.

Miriel supports two special priority values:

  • Setting -1 or "norank" forces the document to not be ranked or returned in ranked results unless no other higher-ranked content exists. The document is still indexed and retrievable via metadata filters.
  • Setting -2 or "pin" forces the document to always rank above non-pinned documents. Within the pinned group, documents are still ranked by relevance.
Important
The num_results limit applies across all documents, including pinned ones. For example, if num_results=10 and 11 documents have priority="pin", only the 10 highest-ranking pinned documents will be returned. No unpinned content will appear unless the total pinned is less than num_results.
python
# Add data that should not show up in ranked results
miriel_client.learn(
    "archived version of this doc",
    priority="norank"
)

# Add data that should always be ranked highest
miriel_client.learn(
    "important reminder relevant for all queries",
    priority="pin"
)

Updating a Document in Place

Pass upsert_ids (one per input) to replace a resource instead of adding a duplicate — useful for content you re-learn on a schedule. expiration_seconds gives items a time to live.

python
miriel_client.learn(
    "Status page: all systems operational",
    upsert_ids=["status-page"],
    command="upsert",
    expiration_seconds=86400,
)

Using Query

Adding an Image to the Query

python
query_response = miriel_client.query(
    "What does this image show?",
    input_images="https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
)
print(f"Query response: {query_response}")

Setting a Structured Output for the LLM Response

python
import json

# Define a schema for the structured output
output_schema = {
    "founders": ["string"],
    "number_of_founders": "integer"
}

query_response = miriel_client.query(
    "Who are the founders of Miriel?",
    response_format=output_schema
)
# result is a json string with the given output schema
llm_result = query_response['results']['llm_result']
result_obj = json.loads(llm_result)

Only "integer", "float", "string", "boolean", "array" (list), and "object" (dict) are supported. Default values are not yet supported.

Filtering Query Results by Metadata

You can filter query results using metadata fields by passing a string to the metadata_query parameter. This lets you narrow results based on metadata values set during the learn() step.

The format uses key=value (also supports >, <, >=, <=) with support for AND, OR, and simple grouping.

Important
AND / OR must be surrounded by spaces (e.g., a=1 AND b=2). Keys and values are matched case-sensitively.
python
# Query only internal documents
query_response = miriel_client.query(
    "What is the document ID?",
    metadata_query="internal_docs=True"
)

# Limit your query to the engineering department and team 83
query_response = miriel_client.query(
    "Where is the party?",
    metadata_query="department=engineering AND team=83"
)

Conversation Mode

By default, each query is independent. Set conversation_mode=True and the response includes results.conversation_history, a round-trippable list of turns — pass it back on the next query. The client is stateless, so you can persist the history as JSON and resume later.

python
r1 = miriel_client.query("What is our refund policy?", conversation_mode=True)
print(r1["results"]["llm_result"])

r2 = miriel_client.query(
    "Does it apply to annual plans?",
    conversation_mode=True,
    conversation_history=r1["results"]["conversation_history"],
)
print(r2["results"]["llm_result"])

Streaming

streaming=True returns an iterator of text chunks as the answer is generated; add yield_events=True for the full event dicts (metadata, start, chunk, done, error). voice_mode=True adds synthesized audio.

python
for chunk in miriel_client.query("Summarize the Q3 report", streaming=True):
    print(chunk, end="", flush=True)

Exhaustive Queries

Sometimes a query requires processing a large or exhaustive volume of documents in order to determine the proper answer. For example, "How many of my contracts mention sales tax?" To ensure the LLM has the proper context, Miriel supports exhaustive query mode, where every relevant document is reviewed.

python
import time
from miriel import Miriel

miriel_client = Miriel(api_key='my_key')
response = miriel_client.query(
    'How many of my contracts mention sales tax?',
    query_type='exhaustive',   # or 'auto' to let Miriel decide
)

# exhaustive queries can take a long time, so a query id is returned
result = response['results']
query_id = result['query_id']
status = result['status']

# check query until it is complete
while status != 'complete':
    time.sleep(10)
    query_response = miriel_client.get_query_result(query_id)
    status = query_response['status']

print(query_response)

When an exhaustive query is executed, a response is dispatched immediately with the query id, and the client must fetch the full response later. query_type takes "search" (the default: answer from the best passages), "exhaustive" (read every matching document), or "auto" (let Miriel choose — so always check status).

force_exhaustive
Older examples pass force_exhaustive=ExhaustiveOptions.FORCE_ON. The API now reads query_type instead; use that.

The /query endpoint returns results wrapped in a results object with a status field, whereas /query/<query_id> returns the query result object directly with the status at the top level.

Email Query Results

Use the email_results argument (a list of addresses) to automatically email a query result when the query is complete.

python
miriel_client.query("Weekly pipeline summary", email_results=["team@example.com"])

Projects

Projects let you group documents into logical collections for scoping, organization, and access control. In the workspace they appear as tags.

  • Add documents to a project at learn() time.
  • Scope queries to one or more projects.
  • List projects you've used before.

Notes and behavior

  • The project parameter accepts a string (single project) or a list of strings (multiple projects).
  • Project values are stored in document metadata and used for filtering.
  • A query without project searches every project.
  • Project names can be listed with get_projects().

Examples

Add and query within a single project:

python
from miriel import Miriel

m = Miriel(api_key="your_api_key")

# Add documents to a project
m.learn("Welcome to Miriel!", project="onboarding_docs")
m.learn("Runbook: Reset primary DB", project="eng_docs", metadata={"doc_type": "runbook", "team": "eng-docs"})

# Query only within that project
resp = m.query("What is Miriel?", project="onboarding_docs")
print(resp)

Add to multiple projects:

python
m.learn(
    "SRE handbook: incident workflow",
    project=["eng_docs", "sre_docs"],
    metadata={"doc_type": "handbook", "team": "eng-docs"}
)

List known projects:

python
print(m.get_projects())  # → [{'name': 'eng_docs'}, {'name': 'onboarding_docs'}, ...]

Combining Projects with Metadata Filters

You can scope a query to a project and narrow results by metadata. The example below adds engineering docs with meaningful metadata, then queries within the eng_docs project for runbooks owned by eng-docs:

python
resp = m.query(
    "How do I reset the database?",
    project="eng_docs",
    metadata_query="doc_type=runbook AND team=eng-docs"
)
print(resp["results"]["llm_result"])

Method reference

MethodDoes
Miriel(api_key, base_url=…)Create a client
learn(input, …, project=, metadata=, priority=, wait_for_complete=, upsert_ids=, expiration_seconds=)Add text, URLs, files or directories
query(query, **params)Ask a question — any REST query field as a keyword; streaming=, conversation_mode=, response_format=, query_type=, email_results=
wait_for_jobs(job_ids, polling_interval=None)Block until those learn jobs complete
get_query_result(query_id)Fetch a stored or still-running query
get_all_documents(project=, metadata_query=)List resources
remove_resource(resource_id) / remove_all_documents(project=)Forget
get_projects() / create_project(name) / delete_project(name)Projects
list_resources / upsert_resource / delete_resource / list_changesProject sync for tools that mirror a local folder
Python — Miriel Docs