In practice

One person, one always-on computer, and a household that runs itself

A running system, not a sketch: one engine instance, one extension, and a set of agents that each own a corner of a household. It needs somewhere always-on that both people can reach, and nothing more than that. This one runs on a cluster because the person who built it is a platform engineer. A spare desktop on the home network would carry the same extension unchanged.

What follows is a slice. The real system carries around thirty agents and dozens of jobs, grown over years, and no page could hold all of it. It did not start there: the same shape works for a single project, a side business, or one job you are tired of doing by hand, beginning with one tool and one schedule. The code below is scaffolding and will not compile as-is.

Deployment

One always-on host. A cluster here, by preference

Reachable from

Anywhere, behind an identity provider

Surfaces

Web, Discord, macOS, iOS, Android

Agents

Around thirty, across five models

Integrations

Calendar, mail, tasks, home, maps, more

Scheduled jobs

Dozens, plus interval checks

Engine instances

One, shared by two people

Hosted by anyone else

Nothing. It is all his.

Where it runs

People

Web UI, behind SSO
Discord, where briefings land
macOS, iOS, and Android clients

Somewhere always-on

ion serve, one instance
jarvis extension
Postgres with pgvector

Reached out to

A hosted model, for hard turns
Local model, for the rest
Calendar, mail, tasks, maps
Home Assistant, camera NVR, sensors

One engine instance serves both people. Sessions are separate and the memory store is deliberately shared. Where it lives is the least interesting decision here: a cluster, a small server or a spare desktop all work, and only the last one changes is how you reach it from outside the house.

Three ways in

Nothing here is a chat product with extras bolted on. Work reaches the engine three different ways, and only one of them involves a person typing.

Somebody asks

A conversation

From the web UI, a phone browser, Discord or one of the desktop clients. This is the smallest share of what the system does.

The clock

A scheduled job

No conversation, no context, nobody present. A briefing assembles itself at seven and a cleanup runs at two.

Something happened

An inbound call

A sensor, a controller or an API posts to a webhook. The brine tank reports low salt and it lands on the grocery list without anyone being asked.

Who does what

One orchestrator routes. Below it, each area has an owner, and the busiest owner has specialists of its own. Every one of them carries a different tool list, which is the containment. This hierarchy is who does the work; it is not the same thing as how work arrives.

Jarvis

claude-sonnet-4-5

The orchestrator. Works out whose work this is and hands it to whoever owns that area.

tools: jarvis · route, recall, remember

The Estate Manager

claude-sonnet-4-5

Owns the house and the property. Keeps track of what was done, what is due, and what is about to be.

tools: estate.chief · recall, remember, calendar, home_assistant, delegate

The Cook

qwen2.5:14b

Meal plans, the grocery list that falls out of them, and what the pantry is actually short of.

tools: estate.cook · meal_plan, recipes, grocery, pantry

The Caretaker

qwen2.5:14b

Periodic property work. Told once that the well was shocked, it knows when that comes round again.

tools: estate.caretaker · recall, remember, calendar

The Groundskeeper

qwen2.5:14b

Mowing, seeding, fertilizing and the irrigation itself. It holds a cycle when the rain says so and puts it back when the forecast moves.

tools: estate.groundskeeper · weather, irrigation, calendar, recall

The Taskmaster

qwen2.5:14b

Reminders, habits and anything handed to somebody. Chases what has not come back and escalates on a schedule rather than a whim.

tools: taskmaster · reminders, habits, todoist, delegate, geo_reminder

The Chief of Communications

claude-sonnet-4-5

Takes the mailbox as an input: reads it, summarizes it, and writes replies into the drafts folder. It has no way to send one.

tools: comms.chief · mail_search, mail_read, mail_draft

The Accountant

claude-sonnet-4-5

Reads the local Quicken file and answers questions about it. Analysis only, and nothing leaves the machine.

tools: accountant · quicken_read, recall

The Watchman

qwen2.5-vl:7b

Looks at a camera frame when the NVR says someone is at the door, and decides whether that is worth a notification.

tools: watchman · vision_describe, notify, recall

The extension, file by file

Ten files. Agents are markdown with frontmatter, tools and triggers are code, and two config files decide where it all runs.

jarvis/extension.ts

The whole registration surface. Everything the engine knows about this system is declared here.

import { createIon } from 'ion-sdk'
import { mailTools } from './tools/mail'
import { memoryTools } from './tools/memory'
import { homeTools } from './tools/home'
import './schedules'
import './webhooks'

const ion = createIon()

// Agents are markdown in ./agents. This turns each one into a
// dispatch tool the orchestrator can call.
ion.registerAgentTools()

// Tools are ordinary functions. The list IS the permission model.
mailTools(ion)      // search, read, draft. No send.
memoryTools(ion)    // recall, remember, forget
homeTools(ion)      // weather, irrigation, calendar

// One hook, for one reason: everything gets written down.
ion.on('agent_end', async (ctx, info) => {
  await memory.append(ctx.sessionKey, info.name, info.task)
})

A day of it running

Most of what this system does happens with nobody watching. The chat window is the smallest part of it.

02:00

Schedule

Four cleanup jobs run between two and five: memories that have aged out, sensor data past two years, metrics and events past ninety days. Nobody has ever thought about them.

06:30

Schedule

Two briefings post to Discord, one per person, each assembled from their own calendar, the forecast, anything due on the property and overnight mail that looks like it needs an answer.

09:12

Webhook

The irrigation controller reports precipitation over the threshold. The groundskeeper cancels tonight’s cycle, takes the mow off the calendar, and books itself a re-check in an hour in case the forecast turns again.

11:40

Chat

"Did we ever get the well shocked?" Recall finds it from eight months ago, and maintenance answers with the date and when it is due again.

10:14

Schedule

The hour is up and the forecast has moved. Irrigation goes back on, the mow returns to the calendar, and nobody asked for either.

16:05

Chat

Josh says he will be home late. Jarvis works out who arrives first, checks what is planned for dinner, and messages the other person: he is running behind, here is tonight’s meal, and here is what to take out of the freezer now. One remark, two people, four tools.

every 15m

Interval

Between seven and nine, a check on anything handed to somebody: has it come back, and is it time to say something about it yet.

20:00

Schedule

The evening digest: what happened, what slipped, and what is waiting tomorrow.

21:30

Chat

"What did we spend on the house this quarter?" The finance agent reads the local Quicken file and answers. Nothing about that question left the building.

Seeing what it did

The engine ships nothing anywhere by default, which means the operator has to decide where it goes. Here it goes to a stack running two namespaces over in the same cluster.

Logs

engine → OTLP → Alloy → Loki

Everything the engine writes, from every extension, in one place with the session and the agent attached.

Metrics

engine → OTLP → Grafana

Cost per run, tokens by model, tool call counts and durations, and which extension is responsible for each.

Traces

device → ingress → engine → tool

A request from a phone on the sofa is followed through the web API to the engine, the agent that took it, and the tool it ended up calling.

Alloy, Loki and Grafana are a preference, not a requirement. The engine speaks OTLP, so any collector that does works the same way. What matters is that a request from a phone can be followed all the way to the tool call it caused.

What it cannot do

  • ×Send an email. Search, read and draft exist; send was never written.
  • ×Touch a bank. The finance agent reads a local file, and has no network tool at all.
  • ×Spend money. Nothing here can buy, book or pay for anything; it can add to a list.
  • ×Run a shell command. There is no shell in the container and no tool that reaches one.
  • ×Reach a network address nobody allowed. A short allow-list, and everything else refused.
  • ×Talk to anything outside itself. There is no tool for messaging other systems or other agents, so there is nothing to negotiate its way out through.

None of these are instructions in a prompt. The tools that would do them were never written, so there is nothing to talk anyone out of.

Deployment notes

  • +One engine instance serves both people. Sessions are keyed per person, so context does not bleed between them, while the memory store is deliberately shared: what one person tells it, the other can be told about.
  • +The only real requirement is a machine that stays on and that both people can reach. This one is a pod behind an ingress and an identity provider because that is what was already there. A spare desktop serving the same container on the LAN would run the identical extension, and most of this page would still be true.
  • +The volume holds everything that matters: sessions, logs and configuration. The container itself is disposable.
  • +The local model handles the volume and the hosted one is reached only when an agent that names it is woken, so cost tracks the number of hard questions rather than the number of runs.
  • +Most of the integrations are MCP servers rather than tools written into the extension: calendar, mail, maps, tasks, home automation and the cluster itself. Adding one is engine configuration, not a code change.
  • +The web interface speaks the socket protocol and has no privileged access. It could be replaced with a CLI, a phone app or a cron script without the extension changing.
  • +The interface is reachable from anywhere, and everything it talks to is not. The NVR and the irrigation controller reach the engine over the LAN only, and the model provider is the sole outbound destination.

Neither of these is the entry price. One tool and one schedule is a real extension, and it is where both of these started. More will land here: a warehouse receiving line and a finance close, both end to end.