Files
compass_teams_nhs/AGENTS.md

16 KiB

Compass / NHS (school)

Build spec for Paperclip. Follow the phases in section 11 in order. Do not skip a phase's Definition of Done. When something is unclear, ask Sam — do not guess.


1. Purpose and outcome

Compass carries everything we need, for Harry and Finn: the daily timetable, the learning tasks (what is due), and notices.

Store it, surface overdue and pending work, write the day's periods and due work to a dedicated Home Assistant calendar, and send the morning briefs.

Teams is DEFERRED — do not build it. The Phase 2 fetch proved Compass's Learning Tasks already carries the due work: learning-tasks-all.json holds 70 structured tasks with names, dates and descriptions. Teams is not on the critical path.

Outcome (the single success statement):

Sam sees, in one page, what each child has due and what is overdue — without logging into Compass — and the family is told before work is late.

2. Scope

In scope

  • Scan Compass per child: the daily schedule, notices, and due dates.
  • Scan Compass Learning Tasks per child: what is due, overdue, and coming up.
  • Store and display per child.
  • Detect overdue and pending work.
  • Write important events to Sam's Home Assistant calendar.
  • Send the morning briefs via Apprise.
  • Answer the Hub.

Out of scope

  • The React calendar — that is a separate project. Do not build a calendar UI here.
  • Teams — deferred. Revisit only if work is found that exists nowhere in Compass.
  • The school's own systems. Read-only.

2a. Prerequisites (verify before Phase 1)

Check these first. The values come from the prerequisite check on .13 (AUD-102). Items marked not verified need a decision or a test.

Need Status / note
Go toolchain MISSING on .13 — go is not in the PATH, not in nix-env, and not in /etc/nixos/configuration.nix. Sam must add go to environment.systemPackages and run nixos-rebuild switch. Phase 1 can build in the golang Docker image instead.
Docker + compose Present on .13. Docker client and server 29.6.2, Compose 5.3.1. Run as user sam (in the docker group, no sudo).
Port 8792 Free on .13. No listener and no container maps this port. Ports 8790 and 8791 are in use by other services.
Caddy route on .35 Caddy runs as the Docker container caddy (v2.8.4) on sam-Ubuntu1 (.35). Routes are site blocks in /Docker/Containers/caddy/Caddyfile, bind-mounted to /etc/caddy/Caddyfile. Use school.lab.audasmedia.com.au { import basic-auth; reverse_proxy 192.168.20.13:8792 }. No school.* block exists yet — Phase 1 must add one. Reload with docker exec caddy caddy reload --config /etc/caddy/Caddyfile. DNS for the name resolves (wildcard) to 144.6.86.11.
pi-browser-harness Present on .13 at /home/sam/.agents/extensions/pi-browser-harness, version 0.11.0. It is a pi extension, not a CLI. Load it as a package extension, then use the commands /browser-setup and /browser-profile. It exposes browser_* tools and drives a long-lived headless Chrome over CDP (--user-data-dir=/home/sam/.chrome-pi, debug port 9222). Session reuse works. The extension is not enabled in this repo's .pi/settings.json — Phase 2 must enable it before the login proof.
Compass URL + reachability https://nhs-vic.compass.education/login.aspx (Northcote High School). DNS goes to Cloudflare. TCP and TLS reach the edge, but the page returns HTTP/2 403 with cf-mitigated: challenge (Cloudflare bot challenge). A real browser session is necessary. This is the Phase 2 risk.
Compass credentials + 2FA NOT AVAILABLE — no Compass, school, or child key exists in ~/.config/environment.d/10-secrets.conf or its backups, and no school-named secret is in the instance config. Sam must supply the account name, the username, and the password as a Paperclip secret (or in 10-secrets.conf). Never write them in this file. 2FA is not verified — no login was attempted. Confirm whether Compass enforces 2FA or new-device email verification, and define the manual step.
Apprise Running on .35:8210 (container apprise, host 8210 to container 8000). GET / and GET /status return 200. The Caddy route apprise.lab.audasmedia.com.au has basic auth.

Gating read-out

  • Phase 1 is unblocked except for Go. Build in the golang Docker image, or ask Sam to install Go on the host.
  • Phase 2 is blocked until Sam supplies a Compass credential and confirms the 2FA step. Phase 2 must also enable the pi-browser-harness extension in this repo.
  • The Cloudflare challenge is the main technical risk. Prove it first.

Not verified

  • Whether Compass enforces 2FA.
  • The exact per-child account model.
  • Whether the headless Chrome profile clears the Cloudflare challenge (no login was attempted).

3. Users and roles

User Can do
Sam Everything. Session login.
Jo / Harry / Finn Receive notifications. Read-only.

4. Functional requirements

ID Requirement
FR-1 Scan Compass with the pi-browser-harness on an n8n schedule, once per child.
FR-2 Log in and reuse a stored session. A manual step is allowed when the school demands it.
FR-3 Parse messages, homework, due dates, and calendar events into structured items.
FR-4 Use JEV or the LLM to structure the page content and classify importance.
FR-5 Store every item with its child, source page, type, subject, due date, and link.
FR-6 Detect overdue work and work due today and this week.
FR-7 Show a per-child view: overdue, due today, due this week, and messages.
FR-8 Write to a dedicated Home Assistant calendar (suggested name School), per child: (a) that day's periods, (b) work due today, (c) overdue work, (d) major events (excursions, exams). Idempotent — an item already in the calendar is never re-inserted.
FR-9 Send a morning brief to each boy (Harry, Finn) by email: (a) today's classes — period, subject, room, teacher, decoded; (b) overdue work; (c) due today; (d) due this week; (e) notices. Overdue first. Lists only, no fluff.
FR-10 Provide a Delete action and a Send action on items and summaries.
FR-11 Hub API: GET /capabilities, POST /ask (read-only), POST /notify.
FR-12 Fail loudly on a scrape failure. Never report "nothing due" when the scan failed.
FR-13 Log every scan: time, child, pages, items, errors.
FR-14 Send a combined brief for both boys to Jo and Sam via Apprise.
FR-15 Teams — DEFERRED. Do not build. Compass Learning Tasks supplies the due work (see §13).

5. Screens and UX flow

Screens

  1. Login — session form.
  2. Child dashboard — a tab per child: overdue, due today, due this week, messages.
  3. Item detail — subject, teacher, due date, link, and full text.
  4. Send panel — choose recipients, preview the brief, send.
  5. Scan history — last scans, items found, errors.

Main flow

n8n triggers the morning scan → items stored
   → each boy gets his own morning brief (today, overdue, pending, notices)
   → Jo and Sam get one combined brief
   → important events are written to Sam's Home Assistant calendar

Output style: brief, concise, lists only. No fluff. Overdue first.

6. Look and feel

Reuse the Family Home Lab design system.

  • Source: /home/sam/Docker/Containers/family-home-lab/DESIGN.md
  • Tokens: /home/sam/Docker/Containers/family-home-lab/portal/static/tokens.css
  • Copy tokens.css into this project.

Canvas #f6f5f4, one action blue #0075de, Inter, 8px grid, pill CTAs, hairline borders. Dark mode. Works on a phone browser.

7. Data model

SQLite inside the service. Suggested tables:

Table Holds
children id, name, year, compass id
items child, type (message, task, event), subject, teacher, title, body, due-at, url
scans started-at, child, pages fetched, items found, error
notifications recipient, summary text, sent-at
session harness session state per child
calendar_index what has already been written to the HA calendar (child, kind, uid, date) — this is what keeps writes idempotent
codes the editable decode map — subject codes, room codes, teacher initials. Never hardcode these; they change.

Retention: keep items while the term is current. Scans are append-only and size-capped.

How to read a Compass timetable entry

Format:

[Period Number] - [Subject Code] - [Room Code] - [Teacher Initials]

Real examples from the Phase 2 capture:

8:55: 1 - 11XMUSA6 - A1 - JBR
9:54: 2 - 11XMUSA6 - A1 - JBR
11:23: 3 - 11SBIOA1 - M4 - AFR
1:07: RLE GROUP D - IM1 - RLE
1:07: 4 - 11HLEGB5 - D8 - LHT
Component Meaning Example
Period The slot in the school day. Text blocks like C or RLE GROUP D are tutorials, Connect, or assembly. 1, 2, C, 3
Subject code VCE unit / class identifier. <year><faculty><subject><block>. 11MGMAC2
Room code <wing letter><room number>. B11, M6, A1
Teacher initials Internal 3-letter staff code. GT, ANE, JBR

Decoding 11MGMAC2: 11 = Year level · M = Faculty (Maths) · GM = Subject (General Maths) · AC2 = timetable block.

Store this as the editable codes map. Do not hardcode it — teacher initials and room codes change between years, and new subject codes appear each term.

8. Integrations

System Use
pi-browser-harness Log in and fetch Compass pages. Already built and working.
JEV Structure page content; classify importance. HTTP API.
OmniRoute All other models.
n8n Triggers the daily scan.
Apprise Per-boy morning briefs, and one combined brief to Jo and Sam. Running on .35:8210.
Calendar Sam's Home Assistant calendar. The Hub or Jervis pushes into HA.
Hub POST /ask, POST /notify, GET /capabilities.

The Hub interface is frozen in central_ai_llm_master/docs/ask-contract.md. /ask is read-only.

9. Technology (locked)

Item Value
Backend Go
UI HTMX + server-rendered HTML
Database SQLite
Scraper patchright (headless Playwright). The pi-browser-harness cannot do the daily scan — Cloudflare 403 managed challenge on the login POST.
Data source Structured JSON, not HTML scraping: learning-tasks-all.json (~70 tasks: name, start, description, category) plus the timetable string time: period - SUBJECT - ROOM - TEACHER.
Design Family Home Lab tokens.css
Host .13, Docker
Container This project's own image and compose file.
Port Allocate one (suggest 8792). Record it once chosen.
URL school.lab.audasmedia.com.au via Caddy on .35
Auth Separate session login.

10. Rules and constraints

  1. Read-only against the school. Never post, message, or submit anything.
  2. A failed scan must be loud. Never show an empty day as "nothing due".
  3. School credentials and session state are secrets. Never commit them.
  4. Models go through OmniRoute, except JEV.
  5. /ask is read-only.
  6. Output is brief: lists, no fluff, overdue first.
  7. Writing a calendar event needs no approval.
  8. Own folder, own container, own port.

11. Build order

Phase 1 — Skeleton Go service, SQLite, config, session login, Dockerfile, compose, Caddy route. DoD: the app runs on .13, login works, /health returns ok.

Phase 2 — Prove the login and the fetch Point the pi-browser-harness at Compass. Log in once. Fetch the pages needed for one child. Store the raw pages. DoD: a real Compass page for one child is fetched and stored. This is the risk phase — a failed login stops the project, so prove it early.

Phase 3 — Parse into items Turn pages into structured items: messages, tasks, events, due dates, links. DoD: real homework and messages for one child appear as structured rows.

Phase 4 — Both children Repeat for Harry and Finn, with per-child sessions. DoD: both children's items are stored and separated.

Phase 5 — Dashboard Per-child view with overdue, due today, due this week, and messages. DoD: Sam can see, per child, what is overdue and due, on a phone.

Phase 6 — Calendar write Write to a dedicated HA calendar (suggested School), per child:

  • that day's periods
  • work due today
  • overdue work
  • major events (excursions, exams)

Idempotent: never re-insert something already present. Track what has been written in calendar_index.

DoD: a real day's periods and due work appear in the calendar, and running the scan twice adds nothing the second time.

NOTE: this calendar is not spoken by Jervis — it will only speak if Sam creates an automation for it. Google Calendar is separate and already speaks.

Phase 7 — Notify and send Apprise notifications, recipient selection, and the Send panel. DoD: a brief is sent to a real recipient.

Phase 8 — Hub /capabilities, /ask, /notify. DoD: the Hub asks "what does Harry have on today at school?" and gets a correct answer.

Phase 9 — Documentation DoD: project-docs run; Gitea, Obsidian, Outline, Vikunja, and the map are updated.

12. Acceptance criteria

  • The scan runs daily and stores real items for both children.
  • Overdue work is detected and shown first.
  • A failed login shows an error, not an empty day.
  • A school event can be written to the calendar.
  • A brief can be sent to a real recipient from the app.
  • The Hub answers a school question correctly.
  • Runs in its own container on its own port, behind Caddy.

13. Decisions and remaining questions

Resolved:

  1. React calendar dropped. Separate project.
  2. Login is on-screen, via the pi-browser-harness or JEV.
  3. Go + HTMX + SQLite, own container, school.lab.audasmedia.com.au, session login.
  4. Calendar = Home Assistant (Sam's). Important events are written there.
  5. Recipients: each boy gets his own morning brief; Jo and Sam get one combined brief.
  6. Focus: Compass gives the daily schedule; Teams gives homework and assignments.
  7. Trigger time: 6:00 am.
  8. Apprise channels: Email and WhatsApp.
  9. Scraper = patchright. The daily scan uses patchright (headless Playwright). The pi-browser-harness cannot pass the Cloudflare managed challenge on the login POST.
  10. Teams dropped from v1. Compass Learning Tasks already carries the due work (learning-tasks-all.json, 70 structured tasks). Teams is deferred, not cancelled.
  11. Calendar rule. A dedicated HA calendar gets: the day's periods, due work, overdue work, and major events — per child, and idempotently. The timetable is written to the calendar (not brief-only).
  12. Not spoken unless asked. The HA calendar stays silent unless Sam adds an automation. Google Calendar is separate and already speaks.
  13. Email is the report channel. Each boy gets his own by email; Jo and Sam get one combined brief. WhatsApp is optional.
  14. 2FA: the Compass parent login required no two-factor or one-time code during the Phase 2 proof.

Remaining:

  1. Teams scope: find the smallest section that answers "what is overdue". Teams may be hard to reach. This is a decision for the brief and for Phase 2.
  2. Teams two-factor auth: not verified. Confirm whether Teams needs 2FA, then define the manual step.