🖥️ ezos — Easy OS
Control your Windows PC with one-line Python. Build your own Jarvis.
ezos is a single-file Python library that gives an AI (or you) a simple,
reliable toolbox to drive the operating system — open apps, control the browser,
research the web, manage files, control media, and more — with dead-simple
functions that read like plain English.
import ezos
ezos.open_app("spotify") # launches Spotify (Store app!)
ezos.play_on_youtube("lofi hip hop") # finds + opens the first video
ezos.search_web("weather", browser="chrome")
print(ezos.weather("London")) # "London: Overcast +12C, 84% humidity"
ezos.speak("All systems online, boss.")
✨ Why ezos?
When you point an AI at a computer, it needs simple, predictable verbs — not
40 lines of subprocess / ctypes / Win32 boilerplate per task. ezos gives it
85 of them, each named like plain English, each returning a structured result
so the AI always knows what happened.
- 🎯 It actually works. App launching uses Windows' own
Get-StartAppsresolver, so Store apps (Spotify, ChatGPT) and desktop apps (Zoom, Discord) really launch — not just the ones on your PATH. - 📦 Zero dependencies for the core. Launching, browser, media keys, window control, volume, weather, clipboard, speak — all work on a plain Python install.
- 🤖 Built for AI. Ships OpenAI-compatible + Claude tool formats, a config
builder, and a ready-made
Jarvisagent loop. Works with OpenAI, Gemini, Z.ai, Groq, and any OpenAI-format API. - 🔎 Real web research with DuckDuckGo + BeautifulSoup — your AI can find things out, not just open a search page.
- 😌 Readable both ways.
ezos.open_app()andezos.openApp()both work.
📦 Install
git clone https://github.com/<your-username>/ezos.git
cd ezos
pip install -r requirements.txt # optional extras; the core needs nothing
Or just drop ezos.py next to your script and import ezos.
| Package | Unlocks |
|---|---|
| (nothing) | app launch, browser, media, windows, volume, weather, clipboard, speak… |
ddgs + beautifulsoup4 |
web_search, read_webpage, research |
openai |
real-AI Jarvis mode (works with OpenAI/Gemini/Z.ai/Groq) |
psutil |
cpu_usage, ram_usage, battery_status |
pyautogui |
click, move_mouse, scroll |
pycaw + comtypes |
set_volume to an exact level |
🚀 Quick start
import ezos
# files
ezos.create_file("notes.txt", "hello world")
print(ezos.read_file("notes.txt"))
# apps & web
ezos.open_app("discord")
ezos.search_web("python tips", browser="chrome")
# system
print(ezos.system_info())
print(ezos.weather("Tokyo"))
ezos.volume_up(10)
# talk & notify
ezos.speak("Task complete")
ezos.reminder(600, "Take a break") # pops + speaks in 10 min
Every action returns a structured result, so you always know what happened:
ezos.open_app("spotify")
# -> {"ok": True, "message": "Opened 'Spotify'", "resolved": "Spotify"}
ezos.open_app("notarealapp")
# -> {"ok": False, "message": "Could not find an app called 'notarealapp'. ..."}
# (also prints a visible WARNING ezos: ... so failures aren't silent)
🤖 Build your own Jarvis
ezos is the toolbox; your LLM is the brain. It works with any
OpenAI-compatible provider — OpenAI, Google Gemini, Z.ai, Groq,
Together, OpenRouter, local servers — just point the client's base_url at them.
1. Configure the AI
aiRead() makes one instruction block. Stack as many as you like and feed them to
configure(), which also tells the AI which tools it has, with an instruction for
each.
import ezos
cfg = ezos.configure(
ezos.aiRead("Call me 'boss'."),
ezos.aiRead("Prefer Chrome for browsing."),
ezos.aiRead("Research before answering factual questions."),
provider="openai",
)
cfg["system_prompt"] # -> system message for your LLM
cfg["tools"] # -> tools in the OpenAI-compatible format
2. Use the ready-made Jarvis loop
from openai import OpenAI
import ezos
# Google Gemini (via the OpenAI-compatible endpoint)
client = OpenAI(
api_key="YOUR_GEMINI_KEY",
base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
)
jarvis = ezos.Jarvis(client, model="gemini-2.0-flash", instructions=[
ezos.aiRead("Call me boss."),
ezos.aiRead("Prefer Chrome."),
])
jarvis.chat("open spotify and search lofi on youtube")
jarvis.chat("what's the weather in Tokyo and who won the last F1 race?")
3. Or do raw tool-calling
tools = ezos.openai_tools() # or ezos.anthropic_tools() for Claude
resp = client.chat.completions.create(model=..., tools=tools, messages=[...])
msg = resp.choices[0].message
if msg.tool_calls:
messages.append(msg)
messages += ezos.handle_openai_tool_calls(msg.tool_calls) # ezos runs them
💡 A complete, runnable chatbot is in
test.py(Gemini) andjarvis_demo.py(any provider, with an offline keyword fallback that needs no API key).
🔎 Web research (no API key)
ezos.web_search("who won the match today") # -> [{title, url, snippet}, ...]
ezos.read_webpage("https://en.wikipedia.org/wiki/Mars") # clean text
info = ezos.research("python 3.13 new features") # search + read top pages
print(info["summary"]) # feed straight to your AI
👁️ Give the AI its own cursor (vision agents)
When commands aren't enough, hand a vision model its own eyes, mouse and
keyboard. grid_screenshot() takes a screenshot with a labelled x,y coordinate
grid drawn on top — the model reads a coordinate straight off the picture and
moves its own cursor there.
cur = ezos.give_cursor() # the AI's own mouse
kb = ezos.give_keyboard() # the AI's own keyboard
shot = cur.look() # screenshot + coordinate grid -> shot["path"]
# ...show shot["path"] to GPT-4o / Gemini / Claude, it replies "click 840,460"...
cur.click(840, 460) # click the search bar it saw
kb.type("karan aujla"); kb.press("enter")
Or let the built-in VisionAgent run the whole see → think → act loop for you:
from openai import OpenAI
import ezos
agent = ezos.VisionAgent(OpenAI(), model="gpt-4o")
agent.do("open spotify and play karan aujla")
# each step: grid screenshot -> model picks coordinates -> clicks & types -> repeat
More agent superpowers:
ezos.click_text("Sign in") # OCR-find on-screen text and click it
ezos.read_screen() # OCR everything on screen to text
ezos.remember("owner", "boss") # long-term memory (survives restarts)
ezos.recall("owner")
cmd = ezos.listen() # mic -> text ("play karan aujla on spotify")
ezos.api_call("https://api.github.com/repos/python/cpython") # hit any API
ezos.run_python("import ezos; ezos.open_app('spotify')") # AI runs its own code
job = ezos.every(60, "battery_status") # repeat in the background; job.stop()
For faster tool loops, batch a short sequence of known actions into one model tool call. It runs in order and stops at the first failure by default:
result = ezos.run_batch([
{"command": "open_app", "args": {"app_name": "spotify"}},
{"command": "wait_for_window", "args": {"app": "spotify", "timeout": 15}},
{"command": "look_at_screen", "args": {"app": "spotify"}},
])
wait_for_window(app, timeout=10) waits for a launched app to appear and
returns its title and process name. give_cursor(image, 0.5, 0.5) makes a cursor
half the normal 48px size; values above 10 set exact pixel dimensions, such as
give_cursor("cursor.png", 40, 40).
Use the real tool names in your instructions. A text model can use
look_at_screen() to read Windows controls; grid_screenshot() only returns
an image file path, so use it with a vision model that receives the image.
ai_say("reply") sets up a tag for Jarvis's spoken replies; call speak() to
say a startup greeting yourself. If Jarvis stops, inspect
jarvis.last_tool_trace to see which tools ran and whether they succeeded.
ezos.give_cursor("cursor.png", 0.5, 0.5)
jarvis = ezos.Jarvis(client, model="glm-4.5-flash", speak_replies=True, instructions=[
ezos.aiRead("You are Jarvis, a helpful assistant."),
ezos.ai_say("reply"),
ezos.aiRead("Open apps with ezos.open_app('name')."),
ezos.aiRead("Inspect an app with ezos.look_at_screen(app='name')."),
ezos.aiRead("Click named controls with ezos.click_on(target, app='name')."),
ezos.aiRead("Move with ezos.move_mouse(x, y); type with ezos.type_text(text)."),
])
ezos.speak("Welcome to Jarvis!")
After a reply, jarvis.last_speech_result reports whether audio playback worked.
speak_replies=True makes every final answer speak, even when the model omits
the optional <reply>...</reply> tag. Calling set_voice() also enables Jarvis
speech automatically; the default remains silent unless requested.
A team of AIs that talk to each other
Install the optional provider client with pip install ezos[ai], then set up a
team with the simple ezos.team(...) — give it a list of small configs
(a name, provider, model and API key each) and you get a pool whose agents run
in parallel on background threads. Supply API keys directly or through the
matching environment variable; providers with an OpenAI-compatible API can set
their own base_url and model. API keys are not printed or saved by ezos.
pool = ezos.team([
{"name": "planner", "provider": "openai", "api_key": OPENAI_KEY,
"model": "gpt-4o-mini"},
{"name": "coder", "provider": "groq", "api_key": GROQ_KEY,
"model": "llama-3.3-70b-versatile"},
])
# let the agents collaborate: one hands work to the other
plan = pool.ask("Plan a simple to-do web app.", agent="planner")
code = ezos.communicateAI(pool, "planner", "coder", plan) # planner -> coder
print(code)
# or put the whole team on the same task at once
answers = pool.broadcast("Give me one way to speed this up.") # {name: reply}
pool.close()
communicateAI(pool, sender, recipient, message) (also pool.communicate(...))
makes one agent send a message to another and returns the reply — the recipient
is told which teammate it's from, so they can pass work back and forth to finish
faster. pool.broadcast(msg) runs every agent on the same prompt in parallel.
ezos.create_agents(...) is the same thing under a longer name, and
pool.submit(...) returns a Future if you'd rather not wait.
Agents run quietly in the Python process and do not open their own windows.
They have no ezos tools by default, so they can draft and reason without
controlling the computer. Give an agent a narrow allowlist such as
"tools": ["web_search", "read_webpage"] only when it needs those actions.
Tools that control apps or the desktop can still affect your session when
explicitly enabled. Call pool.status() to inspect jobs without waiting.
Hidden OS layer — let the agent work off your screen
ezos.isHiddenOS() runs the agent's work on a separate, off-screen Windows
desktop, so it can launch and drive apps while you keep using your own screen,
undisturbed.
ezos.isHiddenOS() # on -> new launches go off-screen
ezos.open_app("notepad") # opens on the hidden desktop, not over your work
ezos.run_hidden("notepad") # or launch one thing there explicitly -> {pid}
ezos.peek_hidden_os(seconds=4) # switch your screen to it for a look, then back
ezos.isHiddenOS(False) # back to your visible desktop
This is ordinary Windows desktop isolation — the same mechanism UI-test
runners use — not a way to hide activity from you: it's your desktop, every
process stays visible in Task Manager, and peek_hidden_os() shows it any time.
It works best for classic .exe programs, scripts and CLI tools. Store apps
that Windows activates through the running shell (Spotify, WhatsApp, ChatGPT, …)
may still appear on your main desktop, since the shell lives there — launch
those normally. Windows only.
Voice input
Install microphone support with pip install ezos[speech]. voice.take()
returns the recognized words; pass an agent to transcribe and immediately send
the words to its chat loop:
words = ezos.voice.take(language="en-US")
reply = ezos.voice.take(agent=jarvis) # transcribe, then jarvis.chat(words)
voice.take() uses the existing listen() speech recognizer and accepts
timeout, phrase_limit, and language options. Recognition requires a
working microphone and an internet connection for Google's speech service.
For Windows UI inspection and cursor rendering, install
pip install ezos[agent].pip install ezos[all]also gets youPillow(the grid),pyautogui, OCR (pytesseract— plus the Tesseract engine) and voice (SpeechRecognition). The mouse/keyboard still work dependency-free on Windows via a built-in ctypes fallback.
📚 The ezos commands
Open index.html in a browser for a searchable reference with
an example for every function. Categories:
| Category | Examples |
|---|---|
| Files & Folders (17) | create_file, read_file, copy_file, zip_files, find_file, open_folder |
| Apps & Processes (5) | open_app, close_app, is_app_running, run_command |
| Hidden OS layer | isHiddenOS, run_hidden, peek_hidden_os (work off-screen on a separate Windows desktop) |
| Browser & Web (9) | open_browser, search_web, open_website, weather, download_file |
| Media (6) | play_on_youtube, play_on_spotify, play_pause_media, next_track |
| Web Research (3) | web_search, read_webpage, research |
| System Info (9) | system_info, cpu_usage, ram_usage, disk_space, wifi_name |
| System Control (7) | shutdown, restart, lock_screen, sleep_pc, set_brightness |
| Window Management (6) | minimize_window, maximize_window, show_desktop, switch_window |
| Clipboard (2) | copy_to_clipboard, paste_from_clipboard |
| Sound & Wallpaper (6) | volume_up, mute, set_volume, screenshot, set_wallpaper |
| Keyboard & Mouse (8) | type_text, press_key, hotkey, click, scroll, scroll_down, scroll_up |
| Vision & Autonomy | give_cursor, give_keyboard, grid_screenshot, VisionAgent, click_text, read_page, read_screen, remember, listen, api_call, run_python, every, wait_for_window, run_batch |
| Extras (9) | notify, toast, speak, reminder, set_timer, whatsapp_message |
| AI Integration | aiRead, configure, openai_tools, run, Jarvis, team, communicateAI, … |
See everything at runtime:
ezos.help_me() # printed overview
ezos.list_commands() # list of names
ezos.describe_commands() # name + params + doc (great for feeding an LLM)
🛠️ How it works
- App launching uses
Get-StartApps+explorer.exe shell:AppsFolder\<AppID>, which resolves any Start-menu app (Store or desktop), not just PATH entries. - Browser finds the real
chrome.exe/msedge.exe/firefox.exeso the URL opens in the browser you ask for. - Media keys, window control, volume use
ctypes— no third-party deps. - Web/weather use the standard-library
urllib; research adds DDGS + BS4.
⚠️ Safety
- Built and tested on Windows 11. File/web helpers also work on macOS/Linux; app-launch / volume / window / wallpaper helpers are Windows-first.
- Destructive verbs (
delete_file,delete_folder,shutdown,empty_recycle_bin) do exactly what they say — have your AI confirm before calling them.whatsapp_messageonly opens the chat; you press Send.
🤝 Contributing
Contributions are welcome! To add a command:
- Write a function in
ezos.pythat returns_ok(...)/_fail(...). - Add a
camelCasealias in the aliases block. - Add an entry to
index.htmlso it shows in the docs. - Open a PR. 🎉
Found a bug or want a feature? Open an issue.
📄 License
Released under the MIT License — see LICENSE. Free to use, modify, and share.
Built for makers who want to build their own Jarvis. ⭐ Star it if it helped!
Metadata
Release files for ezos 2.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ezos-2.6.0.tar.gz | 72.2 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ezos-2.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 141.7 kB
Release files / ezos-2.6.0.tar.gz
| Download URL | ezos-2.6.0.tar.gz |
|---|---|
| Size | 72.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2a38c3b2b146c6ac8d3de28432905d59290610b4d7b1601b40555241156ea39f
|
|
BLAKE2b-256 checksum How to use checksums |
deae275a8952367f8c9581980246b11a9f93b2a20d905e883a9835f39b815a57
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.7
|
Release files / ezos-2.6.0-py3-none-any.whl
| Download URL | ezos-2.6.0-py3-none-any.whl |
|---|---|
| Size | 69.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e06daa3739eaecae494b9a775c0a90c0973834e756592e4799b26ddf4801b773
|
|
BLAKE2b-256 checksum How to use checksums |
f0018bbd477e65a68a51a52be882ade7e60f173bf38e9f1f51c1788ebb5a9383
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.7
|
Security for ezos 2.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.