Skip to main content

dhrishti

dhrishti gives you a live window into a running Python namespace. Point it at a kernel, a script, or a plain dict and it renders every variable as a tree you can expand, page through, and edit while the code keeps running. It sits in a browser tab or a terminal pane and updates as your program does, the way htop tracks processes.

The same window opens onto AI agents. An agent works your live namespace through a sandboxed overlay: it reads your variables and creates its own, you watch what it builds, and you promote the results worth keeping.

See it live

serve() opens a live panel in the browser for any process; inside Jupyter, inspector() drops the same panel into the notebook as an inline iframe. The tree refreshes as your variables change, an exec bar runs code against the namespace, and clicking a value edits it in place.

from dhrishti.serving import serve, inspector
# server, url = serve()   # background inspector for a script or process -> its URL
inspector()             # or, inside Jupyter, the same panel inline
<script> document.body.addEventListener('htmx:configRequest', (event) => { if(event.detail.path.includes('://')) return; htmx.config.selfRequestsOnly=false; event.detail.path = `${location.protocol}//${location.hostname}:8000${event.detail.path}`; }); </script>

Open in new tab

<iframe src="http://localhost:8000/" style="width: 100%; height: 520px; border: none;" onload="" allow="accelerometer; autoplay; camera; clipboard-read; clipboard-write; display-capture; encrypted-media; fullscreen; gamepad; geolocation; gyroscope; hid; identity-credentials-get; idle-detection; magnetometer; microphone; midi; payment; picture-in-picture; publickey-credentials-get; screen-wake-lock; serial; usb; web-share; xr-spatial-tracking"></iframe>

The inspector

A terminal client mirrors the same server, for when you live in a shell. You can also run a script straight under an inspector:

dhristi-serve train.py   # run a script under a live inspector
dhrishti-tui             # attach a terminal client to a running server

The terminal client

When an agent is driving the session the panel does more than show variables: it shows the ones the agent has created, next to yours, and the full transcript of its run, saved as a notebook you can read top to bottom and replay.

Install

pip install dhrishti

Or straight from source:

pip install git+https://github.com/vedicreader/dhrishti.git

What it shows

Everything starts from a namespace, a dict of names to values. snapshot turns one into inspector rows: a name, a type, a short value, and a shape.

import pandas as pd
from dhrishti.core import snapshot, expand, grid_page
hello='hi'
ns = dict(x=42, names=['ada','turing','hopper'], df=pd.DataFrame({'a':[1,2,3], 'b':[4,5,6]}))
for v in snapshot(ns): print(f'{v.name} = {v.value}  ({v.type})')
df = DataFrame [3×2]  (DataFrame)
names = ['ada', 'turing', 'hopper']  (list)
x = 42  (int)

Containers expand one level at a time, so a million-row frame costs nothing until you open it. A DataFrame expands into its metadata and columns; anything backed by numpy or pandas can also be paged as a grid.

for v in expand(ns, ('df',)): print(f'{v.name}: {v.value}')
shape: (3, 2)
size: 6
dtypes: Series [2] object
a: Series [3] int64
b: Series [3] int64
grid_page(ns, ('df',))['cells']
[['1', '4'], ['2', '5'], ['3', '6']]

Handing your namespace to an agent

This is where it pays off. Start a server with the agent surface on, and a tool-calling model can work the same namespace you are watching. Below drives it with rishi, whose Chat runs an on-device model, so no API keys are involved. The full walkthrough lives on the agent page.

from dhrishti.serving import serve, agent_session, AGENT_POLICY
from dhrishti.agent import agent_tools, run_coro, AgentSession

df = pd.DataFrame({'x': range(5), 'y': list('abcde')})   # your live data
server, url = serve(agent='restricted'); print(url)                  # inspector + agent surface
sess = agent_session()                                   # the shared, sandboxed session
<script> document.body.addEventListener('htmx:configRequest', (event) => { if(event.detail.path.includes('://')) return; htmx.config.selfRequestsOnly=false; event.detail.path = `${location.protocol}//${location.hostname}:8000${event.detail.path}`; }); </script>
http://127.0.0.1:8000

agent_tools(sess) hands the model two functions, list_vars and run_python, both bound to the session. conversation_logger(sess) mirrors every turn into a transcript notebook. Wire them into a Chat and ask for some work:

from fastcore.docments import docstring
sp = f'You are a Python assistant. you have a persistent session defined by {docstring(AgentSession)} Use builtins where possible. import only once. dont run same code again. check globals check if a module before using it. numpy and pandas are always be avilable. Call list_vars before writing code. tools available: {docstring(agent_tools)}'; sp
'You are a Python assistant. you have a persistent session defined by Sandboxed Python session over a shared owner namespace. You can read and access any owner variable freely; your writes land in your own layer and never touch the owner. Mutating or deleting owner variables is blocked. copy to a new name first (e.g. `df2 = df.copy()`, `lst2 = lst[:]`). Check available variables before writing code. Use builtins where possible. import only once. dont run same code again. check globals check if a module before using it. numpy and pandas are always be avilable. Call list_vars before writing code. tools available: Tools for a tool-calling agent over an AgentSession. `list_vars` shows what is available; call it first. `run_python` executes code in the session.'
from rishi import *
from litert_lm import set_min_log_severity, Backend
from dhrishti.agent import conversation_logger
from fastcore.docments import docstring
set_min_log_severity(5)

chat = Chat(model_id=gemma4_e4b, sp=sp, tools=agent_tools(sess), cbs=[conversation_logger(sess)], backend=Backend.GPU(),
            approve=hitl_policy({'list_vars':'approved', 'run_python':'approved'}))
chat('Scale the numeric columns of df to 0..1 as a new frame df_norm.')
/Users/71293/code/personal/orgs/dhrishti/.venv/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm

The numeric columns of df have been successfully scaled to the range of 0 to 1, and the resulting DataFrame is stored in df_norm. The output shows the first few rows of df_norm, confirming the scaling has been applied to the numeric columns (x and y in the example output).

Now, the agent_session will have df_norm created.

sess.layer['df_norm']
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
x y
0 0.00 a
1 0.25 b
2 0.50 c
3 0.75 d
4 1.00 e

df_norm is an agent variable. df is not modified.

list(sess.layer), list(df.columns)   # df_norm is the agent's; df keeps its original columns
(['np', 'numeric_cols', 'df_norm', 'col', 'min_val', 'max_val'], ['x', 'y'])

You can see the variables modified live in the webui and the tui. you can even edit variables inline

The live client

You can see the whole transcript of a session as it’s stored as a notebook in sess.log_path

from fastcore.nbio import read_nb
from IPython.display import display, Markdown
def show(cells):
    for c in cells: display(Markdown(f"```python\n{c['source']}\n```" if c['cell_type'] == 'code' else c['source']))
show(read_nb(sess.log_path)['cells'])

user

Scale the numeric columns of df to 0..1 as a new frame df_norm.

# error: ModuleNotFoundError: No module named 'sklearn'
from sklearn.preprocessing import MinMaxScaler
import pandas as pd

# Identify numeric columns
numeric_cols = df.select_dtypes(include=['number']).columns

# Initialize the scaler
scaler = MinMaxScaler()

# Fit and transform the numeric data
# We need to reshape the data for the scaler (it expects a 2D array)
df_norm_numeric = scaler.fit_transform(df[numeric_cols])

# Create a new DataFrame with the scaled numeric data
df_norm_numeric = pd.DataFrame(df_norm_numeric, columns=numeric_cols, index=df.index)

# Combine the scaled numeric columns with any non-numeric columns from the original df
# Assuming all columns in df are numeric based on the initial inspection, 
# but this handles mixed types robustly.
df_norm = df.copy()
df_norm[numeric_cols] = df_norm_numeric

print("df_norm created successfully.")
print(df_norm.head())
import numpy as np

# Identify numeric columns
numeric_cols = df.select_dtypes(include=np.number).columns

# Create a copy of the original DataFrame to store the normalized values
df_norm = df.copy()

# Apply Min-Max scaling to each numeric column
for col in numeric_cols:
    min_val = df[col].min()
    max_val = df[col].max()
    
    # Handle the case where max_val == min_val to avoid division by zero
    if max_val - min_val == 0:
        df_norm[col] = 0.0  # Or 1.0, or keep original, but 0.0 is standard for constant features
    else:
        df_norm[col] = (df[col] - min_val) / (max_val - min_val)

print("df_norm created successfully using manual Min-Max scaling.")
print(df_norm.head())

assistant

The numeric columns of df have been successfully scaled to the range of 0 to 1, and the resulting DataFrame is stored in df_norm. The output shows the first few rows of df_norm, confirming the scaling has been applied to the numeric columns (x and y in the example output).

What the agent can’t do

The session is sandboxed. The agent reads anything and binds its own names, but the moment it tries to change something you own, or reach for the filesystem or shell, the cell is refused and the reason comes back in place of a result.

print(sess.run("df['z'] = 0").error)   # mutating what you own is refused
print(sess.run("import shutil; shutil.rmtree('/nope')").error) # filesystem escapes are refused
list(df.columns)    # your df is exactly as it was
blocked: cannot modify owner variable 'df' in place; bind your result to a new name instead
blocked: 'shutil.rmtree' is a shell/filesystem escape and is not allowed in the agent session; use your own shell tool

['x', 'y']

Promote what you want to keep

A Client connects to the running server over HTTP. It can read the agent’s overlay and, with the owner token it picks up automatically, promote a variable the agent built into your own namespace.

from dhrishti.tui import Client

async def adopt():
    cli = Client(url)
    names = (await cli.agent_rows())['agent_names']   # what the agent has built
    res = await cli.promote(('df_norm',))             # adopt it into your namespace
    await cli.aclose()
    return names, res
run_coro(adopt())
(['col', 'df_norm', 'max_val', 'min_val', 'np', 'numeric_cols'],
 {'ok': True, 'error': None})
'df_norm' in globals()   # now it is yours, and shows up in your own inspector
True

Learn more

The documentation covers the inspection core, the serving layer, and the agent overlay in full.

dhrishti is built with nbdev: edit the notebooks under nbs/, then nbdev_prepare to compile the library, run tests, and rebuild the docs.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dhrishti-0.0.5.tar.gz (63.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dhrishti-0.0.5-py3-none-any.whl (67.6 kB view details)

Uploaded Python 3

File details

Details for the file dhrishti-0.0.5.tar.gz.

File metadata

  • Download URL: dhrishti-0.0.5.tar.gz
  • Upload date:
  • Size: 63.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for dhrishti-0.0.5.tar.gz
Algorithm Hash digest
SHA256 5c1d6692281cd36c875f457cb91cc432ea1629b038f144fead885c6fedec1590
MD5 62f518db45df361a9bb73d9ef5576221
BLAKE2b-256 652365ef2619f3178ef0f769d14a4bd4e11288344506aae3c5c2f8c420b022ab

See more details on using hashes here.

File details

Details for the file dhrishti-0.0.5-py3-none-any.whl.

File metadata

  • Download URL: dhrishti-0.0.5-py3-none-any.whl
  • Upload date:
  • Size: 67.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for dhrishti-0.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 f6a71e0fdaa91f537cf7b71b5b12ce43dccf25e93d108bffb494b9547c4a694d
MD5 cdc4797d74ad97aae9c592666376820b
BLAKE2b-256 83a915d367578307fd6a6eb35cc195b9974a486fd51e3ea943ee97bc731fd6c5

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.5

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

This release

0.0.5 This release

2 files

0.0.4

2 files

0.0.3

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page