python, plugin-based command router. third rebuild, and the first one that's actually structured like a plugin system instead of one file with a hundred if-statements.
text-mode assistant for now — no mic/speaker to test voice against on the machine i built this on, so it stayed text. the point of the rewrite wasn't the io layer anyway, it was making the routing sane: every plugin answers two questions, "can you handle this?" and "handle it," and a plugin manager finds anything that subclasses Plugin in the plugins/ folder automatically. no registry file to hand-edit when i add something new.
time — current time or datenotes — note: buy a charger saves one, persisted to a json file, not memorycalc — arithmetic, walks a parsed ast instead of calling eval() on user input like an animalsystem — read-only machine info. deliberately not wired to anything that changes statellm — optional fallback to claude for anything the other plugins don't claim, if an api key is setclass WeatherPlugin(Plugin):
name = "weather"
description = "'weather' — not actually wired to anything yet"
def can_handle(self, text, ctx):
return "weather" in text.lower()
def handle(self, text, ctx):
return "no weather api hooked up, this is just a demo plugin."
drop that in plugins/, nothing else to touch. the manager finds it on the next run.
no actual os automation — clicking things, opening apps, that kind of control surface. a voice assistant that pokes at your desktop by default is a bigger trust footprint than a portfolio demo needs. if i want that back later it's a plugin like any other, i'll just be more deliberate about what it's allowed to touch than i was the first two times i built this.
download the source (jarvis.zip)