Skip to main content

shalya

A host is an object that answers what it can: read a file, search an index, run a command, remember a page. tools_for asks one what it supports and hands back those tools as plain functions, each with the type hints and docstring a model reads. Nothing here runs an agent loop or talks to a model.

Install

pip install shalya
from shalya.core import failed
from shalya.host import LocalHost
from shalya.tools import tools_for, read_only
from shalya.skills import Skill, Registry, skill_index

A host

LocalHost touches only the folders you open, and reports the capability groups it can serve. A group with no installed backend goes absent rather than broken.

import shutil
from pathlib import Path

d = Path('/tmp/shalya-demo')
shutil.rmtree(d, ignore_errors=True); d.mkdir(parents=True)
(d/'greet.py').write_text('def hi(n): return f"hi {n}"\n')

host = LocalHost(roots=[d], index=False, web=False)
host.can('file'), host.can('memory'), sorted(host.without)
(True, False, ['api', 'ask', 'memory', 'watch', 'web'])

The tools

tools_for returns one flat list, built from the groups this host answers. Every tool takes and returns strings: a harness can pass them to a model without knowing what a host is.

ts = {t.__name__: t for t in tools_for(host)}
len(ts), sorted(ts)
(28,
 ['add_cell',
  'add_root',
  'create_file',
  'edit_cell',
  'git_checkout',
  'git_commit',
  'git_diff',
  'git_divergence',
  'git_log',
  'git_remote',
  'git_stash',
  'git_status',
  'grep',
  'inspect_python',
  'ls',
  'notebook_cells',
  'outline',
  'read_terminal',
  'replace_text',
  'restart_kernel',
  'run_python',
  'run_shell',
  'run_shell_bg',
  'search_code',
  'shell_output',
  'shell_stop',
  'view_cell',
  'view_file'])

A tool answers with the text a model reads. view_file numbers and hashes each line; replace_text edits by exact text, a list of {oldText, newText} that all apply or none do; edit_file, the hash-addressed editor, is the opt-in exhash group (tools_for(host, optin=('exhash',))).

print(ts['view_file']('greet.py'))
1|f8c6|def hi(n): return f"hi {n}"
print(ts['replace_text']('greet.py', [{'oldText': 'hi {n}', 'newText': 'hey {n}'}]))
replaced 1 block(s) in /private/tmp/shalya-demo/greet.py
--- a//private/tmp/shalya-demo/greet.py
+++ b//private/tmp/shalya-demo/greet.py
@@ -1 +1 @@
-def hi(n): return f"hi {n}"
+def hi(n): return f"hey {n}"

A refusal is a string that begins with ERROR:. failed is the one function that checks for it.

r = ts['view_file']('missing.py')
failed(r), r
(True, 'ERROR: no such file: /private/tmp/shalya-demo/missing.py')

A browser

LocalHost has no browser. A host that inherits BrowserHost can offer the opt-in browser group (optin=('browser',)): browse, screenshot, page_text and page_reload look at a page and act without writing; page_click, page_type and page_eval act on it and go to a person. screenshot returns the path of the PNG it saved, because a tool result is text.

Opting in

optin names the groups nobody gets by default: exhash (edit_file), research (a cited digest of the top web results), author (create_skill), browser (see above) and legacy, one release of shims for the names an MCP client may still send (list_files, list_vars, environment, memory_tree, git_rebase_preview, set_reminder, watch_url; gone in 0.2.0). An opt-in the host cannot back is empty rather than broken.

sorted({t.__name__ for t in tools_for(host, optin=('exhash', 'legacy'))} - set(ts))
['edit_file', 'environment', 'git_rebase_preview', 'list_files', 'list_vars']

With a vault (vishalakshi 0.1.17) the host also answers memory_read(ref=''), which browses the roots, a document’s headings or one section by doc#n; remember(key=), which replaces the note filed under the same key; and one watch(target, kind=) for a url, a reminder, a web search or a folder. Git writes answer in JSON with gheasy’s undo token beside summary, head and moved, so a harness can rewind what a turn did.

Tools for a sub-agent

read_only filters a list for a sub-agent that must not change anything. It drops every write tool, unless that tool publishes a read-only twin. read_url publishes one, and the twin reads a page without saving it to memory.

sorted(set(ts) - {t.__name__ for t in read_only(ts.values())})
['add_cell',
 'add_root',
 'create_file',
 'edit_cell',
 'git_checkout',
 'git_commit',
 'git_remote',
 'git_stash',
 'replace_text',
 'restart_kernel',
 'run_python',
 'run_shell',
 'run_shell_bg']

Skills

skill_index renders the block that goes in the system prompt: names and clipped descriptions, never bodies. discover collects installed pyskills and every SKILL.md under the open folders.

ks = [Skill(name='exhash', source='md', description='Hash-verified text editing.', where='', _text='View, then edit by address.'),
      Skill(name='ghapi', source='md', description='GitHub REST access through `GhApi`.', where='', _text='Issues, pull requests, releases.')]
print(skill_index(ks))
## Skills

Use `read_skill(name)` before doing the work a skill covers. Installed tool code is also searchable with `search_code`.

- `exhash`: Hash-verified text editing.
- `ghapi`: GitHub REST access through `GhApi`.

Extensions

A Python file with setup(reg) may add tools, skills, lifecycle hooks and an approval policy. An unknown event name raises rather than hooking nothing.

reg = Registry()

@reg.tool
def weather(city: str) -> str:
    "Today's weather in `city`."
    return f'sunny in {city}'

reg.skill('house-style', 'Short sentences. No headings.')
[t.__name__ for t in reg.tools], [s.name for s in reg.skills]
(['weather'], ['house-style'])

Develop

uv sync --all-extras --group dev
uv run nbdev-export
uv run nbdev-test
uv run pytest
uv run nbdev-clean

Metadata

Release files for shalya 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for shalya 0.1.4
File Size Uploaded
shalya-0.1.4.tar.gz 54.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for shalya 0.1.4
File Interpreter ABI Platform
shalya-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 112.6 kB

Release files / shalya-0.1.4.tar.gz

Download URL shalya-0.1.4.tar.gz
Size 54.5 kB
Tags Source
SHA-256 checksum
How to use checksums
1d5079fe4c916b5e0bcdd16e4089afa2a0cafdefbb5e67b4fc7a8aea2e2faf6e
BLAKE2b-256 checksum
How to use checksums
a20fbdd5abf5be7d1ad502566711537cf77221a807c6f0dd259d12ded7cf0a7a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / shalya-0.1.4-py3-none-any.whl

Download URL shalya-0.1.4-py3-none-any.whl
Size 58.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
74150dd8c48764616eab832b38812ca3f12ab3b713e01196b1af9e302dae3529
BLAKE2b-256 checksum
How to use checksums
55ea84a273f66cf467a6fcf96d0cb9fa6a0834e30d221fba0992a3c70fd4b869
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release history Release notifications | RSS feed

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

This release

0.1.4 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.11

2 release files

0.0.10

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.1

2 release 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