The Human platform: scheduling, classrooms, records, and billing for four kinds of people.
Designed for my own tutoring practice, built from March 2026, live with families since mid-June.
Classes ran on Whereby; parents were on three different chat apps.
Six disconnected apps, billing reconciled by hand, records about minors on third-party clouds.
Human is the small tutoring practice I run, and it existed long before its platform did, running the way small practices do: on whatever is closest to hand. Nothing connected, and nothing was bilingual by design, though most of these parents think in Mandarin.
| what it did | where it lived | what it cost |
|---|---|---|
| the class itself | Whereby | A lesson could end and leave no record anywhere. |
| scheduling | Google Calendar | A reschedule meant renegotiating across whichever threads were open. |
| files | Google Drive | Records about minors on a third-party cloud chosen for convenience. |
| talking to parents | WeChat · WhatsApp · iMessage | Every family on a different app, and nothing bilingual by design. |
| getting paid | e-Transfer · WeChat Pay | Me at month end, matching payments against a calendar by hand. |
| knowing how a student is doing | memory | An answer composed from recall, in English, in whatever thread was open. |
Underneath sat a harder constraint. I wanted AI in this service, because the clerical load on a solo teacher is exactly what a machine should carry, and I was not willing to let a machine speak to a child unsupervised. In March 2026 I stopped patching and started designing.
My role
I founded Human, I teach in it, and I designed and built the platform, so whoever specified the teacher gate also works behind it on a Tuesday night.
A parent and a teacher sign into the same address and land in different rooms.
One sign-on, four roles, and load-bearing walls between the rooms.
The service model starts from who is asking, and a parent's version is the shortest: is my kid okay, and what am I paying for. A student never sees billing, a parent never sees another family, a teacher sees their own students and no one else’s, and those boundaries are checked on every request rather than drawn in the interface.
Each account keeps its own way of reading, remembered per person on every device: text scale, high contrast, reduced motion, a dyslexia-friendly typeface. The family surfaces target WCAG 2.2 AA.
The parent room, full width 1 screen
Follow one family from the welcome message to the day everything is erased.
A family's whole arc, welcome message to erasure, fits on one blueprint.
Onboarding is eight steps that run as one, in order, the same way every time.
Accounts created for every member of the household, and the calendar feed wired up.
The rate and the session pack set; the recurring schedule seeded from them.
The family’s file folder and workspace opened.
A welcome sent, in both languages, in the same breath.
Checking the details, then pressing start. The order never varies, which is the point.
From there the rhythm is weekly. The schedule recurs on an open calendar standard, so lessons appear in whatever calendar app a household trusts, and a reschedule is a request with an approval queue rather than a negotiation across three chat threads. On class day the student knocks at a lobby, and there is no other way into a live classroom.
And when a family leaves, the platform is built to forget them. One erasure request cascades through every stack that ever held their data. PIPEDA grants families that right; this service draws it as a step on the blueprint like any other. I have run the cascade live and checked what it left behind.
→ scroll the lifecycle sideways on a narrow screen
Between the AI and the student, there is always a teacher.
A local model drafts the next steps; a teacher approves, edits or rejects each one. Nothing reaches a family unread.
Every lesson ends with the same question: what should this student work on before next time? Here a machine answers first. The recording becomes a transcript, a local model reads it, and out come drafted action items.
The student sees none of this. A draft exists in exactly one place, the teacher’s review queue, where the teacher signs off on it or it does not go out. Approval is the only door. An edit keeps the AI’s original wording beside the final version, so the gap between what the machine heard and what the teacher meant stays on the record. A rejection leaves no trace the student can see.
The rule is that strict because the practice sells a teaching relationship: someone who knows this student and catches what a transcript flattens. The AI makes the record cheap to produce. The teacher makes it true.
Where AI enters, and the six refusals 1 map, 1 table
→ scroll the map sideways on a narrow screen
the full board, with the trigger weights and the connectors this grid straightens out ↓
| the refusal | where it is enforced |
|---|---|
| Never reads a journalA student’s journal never enters a model’s input, and a parent cannot read one either. Both walls live in the query layer, so neither is a setting anybody can change. | not one reference in any prompt or input builder |
| Never transcribes a guestAnonymous visitors are skipped, because nobody asked them to consent. Only signed-in participants are transcribed. | should_transcribe_identity(), in the live agent and the recorder both |
| Never sends what a teacher has not approvedThe translator refuses a session a teacher has not accepted. Rendering unapproved words in a language a parent cannot proofread is worse than sending nothing. | processing_status must read approved before a word is sent |
| Never overwrites a teacherA plan a teacher approved, or wrote by hand, is never superseded by a drafted one. Not by the nightly sweep, and not by the teacher’s own request. | should_generate_plan(), plan_freshness.py |
| Never reaches a vendorNo third-party AI service ever sees a student, and no student data leaves for training. | both engines local; there is no model api key to leak |
| Never decidesThe models propose; a person accepts, edits, or throws it away. Nothing here runs to a conclusion on its own. | every output lands as a draft, marked pending |
Parents read this platform in the language they worry in.
Chinese sits beside English in the data model, so every notice to a parent arrives in both scripts.
Before the platform, everything official arrived in English anyway, and the nuance travelled by chat app when it travelled at all. Now Chinese fields sit beside the English ones in the data model, written together at the source, so a reschedule, an invoice or a welcome says itself in both scripts. Staff surfaces stay in English.
The difference is small and weekly. A schedule change reads the way the household speaks, and an invoice explains itself without a translation app.
The whole service runs on two machines I can point at.
About 14 self-hosted stacks on two machines for roughly $30 a month, the AI included.
Underneath the service sits a deliberately small build: ~14 self-hosted stacks, 30+ containers, two machines, one sign-on. Each job runs as its own stack, which keeps failures local.
Self-hosting was a privacy decision before it was a cost decision. A child’s voice never travels to a third-party API to become a lesson note. The cost argument holds too: it all runs for about $30 a month, where per-seat tools would have attached a fee to every student, per product, forever.
And it is operated by the same person who designed it, so any operational shortcut I take reaches my own students within days.
the NAS
the GPU workstation
Three reversals were big enough to change the build, and all three are still on the page.
Every finding stayed on file, and the one bug that mattered traced to a single root cause.
A platform for other people’s children should not run on its author’s confidence, so the method was audit-first. Findings land in a docs folder, and the docs are amended rather than rewritten, so the first version of a finding stays visible under the fix.
An audit trail that only ever says everything is fine is decoration.
| what I built | what replaced it | on file |
|---|---|---|
| the original video stack | Replaced mid-build, once the live-class requirements were clear. | both eras |
| a separate task tool | Retired when the platform’s own boards covered the job. | both eras |
| a contract-signature service | Removed entirely, once a simpler local wizard made it redundant. | both eras |
Two audits shaped the launch, and what they taught was about counting.
| June triage | 40 findings ranked, about 30 closed overnight |
|---|---|
| two customer-blocking failures | both traced to a single date-handling regression |
| the fix | patched that night, and a guard now runs in CI |
| adversarial audit, three days later | 78 findings confirmed, 2 critical, all fixed |
| backup restore | a full restore, performed and verified |
A few families, the full loop, no projections.
Soft-launched mid-June 2026, and still small.
A small number of families use it, and I am not going to dress that up. The whole loop runs in production: classes scheduled, taught, recorded into lesson notes a teacher approved, and billed, with no glue work in a chat thread at midnight.
I built the service before I built the ground it stood on.
Ransomware made that argument in April 2026.
Mallox encrypted the NAS after three months of root Telnet access through a port the DMZ had left open. No family lost anything, and only because there were no families yet: the launch came after the rebuild. Infrastructure first, next time.