Qombra Python SDK
Programmatic access to Qombra: dataset statistics, AI-guided preprocessing (QAgent), Model training (QBrain), inference, and SHAP explainability.
pip install qombra
The qombra package is the supported way to use the Qombra API: it handles authentication, dataframe
transport, and long-running jobs for you. Requires Python ≥ 3.10; works with pandas DataFrames throughout.
All usage counts toward your account's usage limits.
Authentication
qombra.login() opens a browser window where you sign in on the Qombra web app and approve the SDK
session. The resulting token is kept in your OS keyring is valid for
12 hours, and is stored server-side only as a hash. Every SDK call runs through this authenticated
session.
import qombra
qombra.login() # browser opens; approve → "logged in as you@corp.com, expires at …"
… # work
qombra.logout() # revoke the token server-side + clear the keyring
- Scoped sessions:
with qombra.Qombra() as client: …— leaving thewithblock closes the session and revokes the token. - No browser (SSH, CI):
qombra.login(headless=True)prints the consent URL and prompts for the code shown after approval. - Automation: set
QOMBRA_API_TOKENin the environment to skip the keyring lookup. - Expiry: after 12 hours calls raise
AuthenticationError— just re-runqombra.login().
Quickstart
import pandas as pd
import qombra
qombra.login()
df = pd.read_csv("customers.csv")
report = qombra.analyze(df) # dataset statistics
result = qombra.preprocessing(df, "drop outliers in price") # AI preprocessing
model = qombra.fit(result.df, target="churn_30d") # trained by QBrain
preds = model.predict(new_rows) # inference
print(model.explain()) # SHAP bar chart
# later, in a new Python session — no retraining:
model = qombra.Model.from_id("<model.id>")
preds = model.predict(more_rows)
run = qombra.auto_run(df, "Predict which customers churn") # full pipeline in one call
qombra.logout()
Functions
Module-level functions share one default client; the Qombra class offers the
same methods on an explicit, closable session. Long-running calls (preprocessing, fit,
explain, auto_run) block while a server-side job runs and take a timeout
(seconds) — on JobTimeoutError the job continues server-side and its results still land in your account.
qombra.login(base_url=None, *, headless=False, open_browser=True, timeout=180.0) → TokenInfo
qombra.logout(base_url=None) → None
Open the browser to sign in, and hand the session back when you are done.
Parameters
- base_url str = None
- API base URL override. Defaults to the Qombra production API.
- headless bool = False
- No browser available (SSH, CI): print the consent URL and prompt for the code shown after approval.
- open_browser bool = True
- Set False to print the URL instead of opening a window; the local callback still runs.
- timeout float = 180.0
- Seconds to wait for the browser round-trip.
Returns
- TokenInfo
- The session that was opened. The token is stored in your OS keyring and valid for 12 hours; every later call
picks it up automatically.
.email·.expires_at
Raises
- LoginDeniedError
- You clicked Deny on the consent page.
- LoginTimeoutError
- The browser flow did not finish within
timeout. - AuthenticationError
- The sign-in could not be completed.
- NetworkError
- The server could not be reached.
Notes
Set QOMBRA_API_TOKEN in the environment to skip the browser entirely (CI, scheduled jobs).
logout() revokes the token server-side and clears the keyring; it is safe to call when not logged in.
qombra.analyze(df, excluded_columns=None) → AnalysisReport sync
Get statistics and data-quality warnings for a dataframe.
Parameters
- df DataFrame
- The data to analyze. The SDK uploads a sample of up to 1000 rows with the fewest NaN values, keeping their original order.
- excluded_columns list[str] = None
- Columns to leave out of the analysis.
Returns
- AnalysisReport
- Per-column statistics and histograms, MIC correlations between columns, and quality warnings (PII-like,
constant, ID-like, class imbalance, duplicate rows).
.features·.correlations·.warnings·.summary·.duplicates·.imbalances
Raises
- ValidationError
- The dataframe is empty or cannot be serialized (e.g. mixed-type object columns).
- AuthenticationError
- Not logged in, or the 12-hour session expired.
qombra.preprocessing(df, instruction, *, timeout=1500.0) → PreprocessingResult job
Clean and reshape a dataframe with QAgent, following your instruction in plain language. The result is directly usable with qombra.fit, i.e. QBrain.
Parameters
- df DataFrame
- The raw data.
- instruction str
- What to do, in plain language — e.g.
"drop duplicate rows and one-hot encode region". - timeout float = 1500.0
- Client-side wait limit in seconds. Expect minutes; the work continues server-side either way.
Returns
- PreprocessingResult
- A model-ready dataframe — leakage columns dropped, very-high-cardinality categoricals capped, and non-feature
columns (identifiers, raw dates) removed — so it can go straight into fit. Printed to the
console on completion and stored in your account.
.df·.summary·.warnings·.actions_taken·.excluded_columns·.job_id
Raises
- JobFailedError
- Preprocessing failed server-side;
.codesays why. - JobTimeoutError
timeoutelapsed — the job keeps running and its result lands in your account.- QuotaExceededError
- Chat-message or output-token quota exhausted.
Notes
The agent's work is charged to your account's LLM output-token limit, and the call also spends
one chat message — the same budget the web app's chat consumes. A single call is charged once, no matter how many
stages it runs internally. See qombra.whoami() for what is left.
Example
result = qombra.preprocessing(df, "drop outliers in price and one-hot encode region")
print(result.excluded_columns) # ['passenger_id', 'signup_ts']
model = qombra.fit(result.df, target="churn_30d")
qombra.fit(df, target, *, metric=None, effort=None, timeout=1800.0) → Model job
Train a QBrain model to predict one column, and get back a handle to it.
Parameters
- df DataFrame
- Training data including the target column. Rows whose target is missing are excluded from fitting automatically — they become the model's instant predictions.
- target str
- Name of the column to predict. Classification or regression is decided by the engine from the column itself.
- metric str | None = None
- Evaluation metric the engine tunes, selects and reports on. Unset keeps the task default —
accuracy for classification, MAPE for regression — together with an automatic class-imbalance
safeguard that an explicit metric disables.
Classification:
accuracy·roc_auc·f1_micro·log_loss·qwk. Regression:mape·rmse·rmsle·mae·median_ae·smape. The metric must fit the task the engine infers from the target column; a mismatch fails the training job with the reason. - effort str | None = None
- Compute budget for the run:
low·medium·high·auto(derived from data size and available resources). Higher levels train fewer candidates at greater depth and take longer. Unset keeps the server's default. - timeout float = 1800.0
- Client-side wait limit in seconds. Training can take many minutes on large data.
Returns
- Model
- A handle to the trained model. The model itself stays on the server and is addressed by its id, so you can
reconstruct it in any later session with
Model.from_id(...)..predict(df)·.explain()·.instant_predictions·.metrics·.id
Raises
- ValidationError
- The target column is missing, too few rows carry a target value, or
metric/effortis not one of the values above. - QuotaExceededError
- Analysis quota exhausted.
- JobFailedError
- Training failed server-side (including a
metricthat does not fit the inferred task). - JobTimeoutError
timeoutelapsed — training continues server-side.
Example
model = qombra.fit(train_df, target="churn_30d")
# a rare positive class: rank by ROC AUC, spend more compute
model = qombra.fit(train_df, target="churn_30d", metric="roc_auc", effort="high")
print(model.metrics["test_metric"]) # 0.87
predictions = model.predict(new_rows)
Notes
Training runs on QBrain, Qombra's proprietary tabular foundation model. This is the same engine behind every prediction in the web app. No manual model selection or tuning is needed.
Each call counts toward your analysis quota.
qombra.predict(model_or_id, df) → pandas.Series sync
Predict on new samples with a trained model.
Parameters
- model_or_id Model | str
- A model object, or the id string of one.
- df DataFrame
- Rows to score. Columns are aligned to training automatically: extras are ignored, missing feature columns are treated as NaN (with a warning), and a target column, if present, is dropped. Predict in batches for very large frames.
Returns
- pandas.Series
- One prediction per input row, named
"<target>_prediction"and aligned todf.index, so it can be assigned straight back onto your dataframe.
Raises
- ValidationError
- The dataframe shares no columns with the model's training features.
- NotFoundError
- The model does not exist for this account (e.g. it was deleted).
Example
new_rows["churn_risk"] = qombra.predict(model, new_rows)
# identical to model.predict(new_rows)
qombra.explain(model_or_id, df=None, *, timeout=900.0) → Explanation job
Find out which features drive a model's predictions.
Parameters
- model_or_id Model | str
- A model object, or the id string of one.
- df DataFrame = None
- Rows to explain. Omitted, the model's training data is used. SHAP runs on a representative sample with a fixed random seed, so repeated calls agree.
- timeout float = 900.0
- Client-side wait limit in seconds.
Returns
- Explanation
- SHAP values per feature, plus a console bar chart when printed.
print(...)·.mean_abs_shap·.to_frame()·.relationships·.base_value
Raises
- JobFailedError
- SHAP computation failed server-side.
- JobTimeoutError
timeoutelapsed — the job keeps running server-side.- NotFoundError
- The model does not exist for this account.
qombra.auto_run(df, prompt, *, user_context="", preprocessing_mode="deterministic", max_nudges=3, auto_approve=True, name=None, timeout=7200.0) → AutoRunResult job
Hand a dataframe and a question to the agent, and get a trained model back. This runs the full data science workflow as a user would do in the Qombra platform.
Parameters
- df DataFrame
- The raw data — preprocessing is part of the run.
- prompt str
- What to analyze or predict, in plain language.
- user_context str = ""
- Business context for the agent: what the data means, how it was collected, what matters.
- preprocessing_mode str = "deterministic"
"deterministic"for the standard pipeline,"rlm_only"for the AI agent.- max_nudges int = 3
- How often (0–5) a waiting agent is auto-answered before the run stops.
- auto_approve bool = True
- Approve the agent's analysis plan automatically instead of stopping for confirmation.
- name str = None
- Analysis name in the web app. Defaults to the start of the prompt.
- timeout float = 7200.0
- Client-side wait limit in seconds. Expect minutes to hours.
Returns
- AutoRunResult
- The run report, with a ready-to-use model when training succeeded. The analysis is fully browsable in the web
app afterwards.
.model·.confirmed_target·.metrics·.analysis_id·.timing
Raises
- JobFailedError
- The run stalled or trained no model; the partial report is on the exception's
.result. - JobTimeoutError
timeoutelapsed — the run continues server-side.- QuotaExceededError
- Analysis, chat-message, or output-token quota exhausted.
Example
run = qombra.auto_run(df, "Predict which customers churn in the next 30 days")
print(run) # phases, target, test metric
predictions = run.model.predict(new_rows)
qombra.list_models(created_via="sdk") → list[ModelInfo]
qombra.delete_model(model_or_id) → None
qombra.list_preprocessing_results() → list[PreprocessingResultInfo]
qombra.delete_preprocessing_result(job_id) → None
See what is stored in your account, and remove what you no longer need.
Parameters
- created_via str = "sdk"
- Which models to list:
"sdk"for models you trained through this package,"web"for those trained in the web app,"all"for both. - model_or_id Model | str
- The model to delete.
- job_id str
- The stored preprocessing result to delete —
results[i].job_id.
Returns
- list[ModelInfo]
- Newest first. An ordinary list that renders as a table when displayed — index and iterate it as usual, and use
models[i].model_idfor the full id. Long listings show the newest entries, an ellipsis, and the oldest one; the list itself always holds every row. - None
- Deletion is permanent — model files and stored result dataframes included — and does not refund quota.
Raises
- NotFoundError
- No such model or result for this account.
- ValidationError
created_viais not one of the three accepted values.
Example
>>> qombra.list_models(created_via="all")
2 models in your account
# id target task model metric train test rows created
─ ───────── ───────────── ────────────── ─────── ──────── ───── ───── ─────── ────────────────
0 0624f7fb… Final_Outcome classification qbrain accuracy 0.985 1.000 132/34 2026-08-17 19:07
1 ab12cd34… Survived classification qbrain accuracy 0.891 0.816 712/179 2026-08-24 11:12
qombra.whoami() → dict sync
Check who you are signed in as and what quota is left.
Returns
- dict
{"email", "expires_at", "limits": {"remaining_analyses", "remaining_chat_messages", "remaining_output_tokens"}}. A limit ofNonemeans unlimited. Also the cheapest way to confirm your session still works before starting a long run.
Classes
qombra.Qombra(base_url=None, token=None, timeout=30.0)
An explicit, closable session — the same calls as the module-level functions, scoped to a
with block.
Parameters
- base_url str = None
- API base URL override.
- token str = None
- Explicit API token, skipping the environment and keyring lookup.
- timeout float = 30.0
- Default per-request timeout in seconds. Uploads and long operations use larger internal limits.
Methods
- analyze · preprocessing · fit
predict · explain · auto_run - Identical to the module-level functions, bound to this session.
- list_models · delete_model
list_preprocessing_results - Inventory management — see list_* / delete_*.
- whoami() → dict
- Account email, session expiry, and remaining quota.
- close(revoke=True)
- Revoke the token server-side and clear the keyring.
revoke=Falseonly closes the connection pool and keeps the token usable.
Example
qombra.login()
with qombra.Qombra() as client:
model = client.fit(train_df, target="churn")
print(client.whoami())
# leaving the block revokes the token — the session is closed for good
Notes
Token resolution order: the token argument → QOMBRA_API_TOKEN → the OS keyring
written by login().
qombra.Model
A trained QBrain model living on the Qombra server. An instance doesn't contain the model itself but a reference to it.
A Model instance can be re-created using the model id (see below).
Attributes
- id str
- Stable model id. Pass it to
Model.from_id(...)in any later session. - target_column str
- The column this model predicts.
- task_type str
"classification"or"regression", decided by the engine from the target column.- model_type str
- The model behind this fit —
"qbrain"for anything trained through this package. - feature_columns list[str]
- Columns used at training time; prediction aligns incoming data to these.
- metrics dict
train_metric/test_metricwith their*_metric_name,n_train_samples,n_test_samples,training_time_sec, andmode_collapse(true when the model predicted a single class for everything).- instant_predictions DataFrame
- The predictions training made automatically for rows whose target was missing:
training_row(position in the training data), the feature columns, and<target>_prediction. Empty when no targets were missing. Fetched on first access, then cached. - created_at · created_via str
- When it was trained, and whether through the SDK or the web app.
Methods
- Model.from_id(model_id) → Model
- Reconstruct a model in a new session — no retraining.
- predict(df) → Series
- Score new rows; see predict.
- explain(df=None) → Explanation
- Feature attributions; see explain.
Example
model = qombra.Model.from_id("<model_id>") # any later session
preds = model.predict(new_rows)
print(model.explain())
qombra.PreprocessingResult
What preprocessing() did, and the dataframe it produced.
Attributes
- df DataFrame
- The model-ready data: leakage and non-feature columns removed, ready for fit.
- summary str
- What was done, in prose.
- warnings list[str]
- Issues raised during preprocessing.
- actions_taken list[str]
- The individual cleaning and merging steps, in order.
- excluded_columns list[str]
- Non-feature columns removed from
df— keep them from your original dataframe if you need to join predictions back to source rows. - job_id str
- Handle for delete_preprocessing_result().
Notes
print(result) renders the summary, actions, warnings, and resulting shape — done automatically when
preprocessing finishes.
qombra.AnalysisReport
What analyze() found in your data.
Attributes
- features list[dict]
- Per-column type, statistics, and histogram.
- correlations list[dict]
- MIC correlation per column pair:
{col1, col2, value}. - warnings list[dict]
- Quality issues:
{column, issue, severity, hint}. - summary dict
- Row, column, and per-type counts.
- duplicates dict
- Duplicate-row count and rate.
- imbalances list[dict]
- Binary columns with a very small minority class.
- n_rows_analyzed int
- Size of the analyzed sample.
qombra.Explanation
Which features drive a model's predictions, and in which direction.
Attributes
- mean_abs_shap Series
- Mean |SHAP| per feature, sorted — the headline importance ranking.
- relationships list[str]
- Human-readable direction hints, e.g. "sqft up → price up".
- feature_names list[str]
- Features in the order the value matrices use.
- shap_values · feature_values list[list[float]]
- Raw per-sample attributions and the feature values they belong to.
- base_value float
- The model's expected output before any feature contribution.
- n_samples int
- How many rows were explained.
Methods
- to_frame() → DataFrame
- SHAP values as a dataframe, one row per explained sample.
Example
>>> print(model.explain())
Feature importance (mean |SHAP|) — task: regression, target: price
sqft_living ████████████████████████ 0.4123
grade █████████████ 0.2210
lat ███████ 0.1187
base value: 540123.4
qombra.AutoRunResult
The report of an auto_run(), with the model it trained.
Attributes
- model Model | None
- Ready to predict with when training succeeded;
Nonewhen the run produced no model. - confirmed_target str
- The column the agent settled on predicting.
- metrics dict
- The winning model's scores.
- analysis_id int
- The analysis created by the run — open it in the web app to see the full conversation.
- status · current_phase · turns
- Where the agent ended up and how many turns it took.
- use_case_type str
- How the agent classified the problem.
- token_usage · timing dict
- LLM cost and a per-phase time breakdown.
Notes
print(run) gives a one-glance summary of phase, target, and test metric.
qombra.ModelInfo · qombra.PreprocessingResultInfo · qombra.TokenInfo
Lightweight rows returned inside the table-rendering lists (see list_models) and by login().
Attributes
- ModelInfo
model_id,target_column,task_type,model_type,metrics,created_at,created_via.- PreprocessingResultInfo
job_id,summary,n_rows,n_cols,created_at,has_data.- TokenInfo
token,expires_at,email.
Errors
Everything raised by the package derives from qombra.QombraError, so one
except qombra.QombraError catches it all; catch subclasses for targeted handling:
try:
model = qombra.fit(df, target="revenue")
except qombra.AuthenticationError:
qombra.login() # 12h session expired — sign in again, then retry
except qombra.QuotaExceededError as e:
print("usage limit reached:", e) # check qombra.whoami()["limits"]
except qombra.ValidationError as e:
print("bad input:", e.code, e) # machine code + human message
except qombra.JobTimeoutError as e:
print("still running server-side, job:", e.job_id)
| Exception | Raised when |
|---|---|
AuthenticationError | No token, or it expired / was revoked. Subclasses: LoginDeniedError (Deny clicked in the browser), LoginTimeoutError (consent flow timed out). |
QuotaExceededError | An account usage limit is exhausted (analyses, chat messages, output tokens). |
RateLimitedError | Too many requests in a short window; retry later. |
ValidationError | Invalid input — carries a machine-readable .code (e.g. missing_target, insufficient_rows, no_overlapping_features, unsupported_column_type) and .details. Subclass PayloadTooLargeError: the upload is too large — reduce or batch it. |
NotFoundError | The model / stored result does not exist for this account (e.g. deleted). |
JobFailedError | A server-side run failed — .code (e.g. preprocessing_failed, training_failed, auto_run_failed, job_lost after a server restart: retry), .job_id, and any partial .result. |
JobTimeoutError | Your client-side timeout elapsed; the job keeps running server-side (.job_id). |
NetworkError ServerError | Server unreachable / unexpected server failure. Read-style requests are retried automatically before this surfaces. |
Data format & metering
- Dataframes travel as parquet with plain scalar columns only — numbers, booleans, strings, dates,
timestamps, decimals; pandas categoricals are fine. Nested or binary columns are rejected with
unsupported_column_type; mixed-typeobjectcolumns should be cast (e.g.df[col].astype(str)) before upload. - Uploads are size-capped and calls are rate-limited; an oversized upload raises
PayloadTooLargeError— reduce or batch it — and rapid-fire calls raiseRateLimitedError. Row order is preserved end-to-end. - Metering — every call is charged to the same account limits the web app uses:
preprocessingspends LLM output tokens (the AI agent's work) plus one chat message, and is billed once per call however many stages it runs internally.fitcreates one analysis, counted against your analysis limit. QBrain is not an LLM, so training spends no output tokens.auto_runspends all three: one analysis, plus the chat messages and output tokens the agent consumes across the run.analyze,predict,explainand the listing calls spend no quota; they are rate-limited instead.
qombra.whoami().