The picture in one paragraph
Every child the Foundation supports gets one structured profile on a private Foundation Shared Drive: identity, programme, progress notes, and benefits delivered. A small set of Python tools in this repo writes to that store; a tiny FastAPI dashboard lets principals and trustees read the cohort and add light updates; Claude assists with entry drafting and report writing. No public surface; the Drive's membership list is the access boundary. The 8-petal model is the spine that runs through every record — every note and benefit row carries a petal anchor, so storytelling and Area-4 reporting can both surface it.
Architecture · what lives where
Private Foundation Drive
- profiles/journey-NNNN.mdFour-block markdown profile per child. Canonical record.
- benefits-ledger/journey-NNNN/Dated entries + receipts + handover photos.
- intake/<YYYY-Www>/Raw inbox: notebook write-ups, Zalo exports, scanned letters.
- indexes/by-cohort, by-school, by-child/_search.md
- registry-beneficiary.sqlitechild / benefit / profile_entry tables. WAL.
- cohort-dashboard/<YYYY-Qn>.mdQuarterly trustee summary, generated.
- funding_sources.yamlEnum of contribution refs. Area-3-maintained.
This repo · tools/
- beneficiary_registry_migrate.pyCreates the 3 SQLite tables. One-shot, idempotent.
- beneficiary_validate.pySchema check on a profile file. bundle_validate analogue.
- beneficiary_promote.pyPromote an intake item to a profile entry + SQL row.
- benefit_record.pyWrite a ledger entry + benefit row. Enum-validates funding_source.
- benefit_report.pySQL views → markdown for Area-4. HXL-CSV emitter.
- beneficiary_index_rebuild.pyNightly indexes + quarterly cohort dashboard.
- beneficiary_consistency_check.pyDrift between SQL rows ↔ markdown files.
- media_sanitise.py --verifyExisting media-line tool, reused at promotion boundary.
UI + AI
- app/ (FastAPI)Internal dashboard. Cohort view + child detail + add-note + analytics.
- beneficiary-recorder agentClaude Opus structures a raw drop into a profile entry.
- report-writer (Claude)Drafts the monthly Area-4 narrative from benefit_report SQL output.
- journey-writer (Stream C)Reads Block 3 + ledger; drafts long-form progress narrative.
- HMT Foundation WorkspaceGoogle Workspace; Drive desktop client mounts the private Drive locally.
The five-step pathway
The same shape as the media line's intake → curate → draft → QC → review-queue, scoped to a child's record. Steps 1–3 run weekly; step 4 only on escalation; step 5 quarterly.
intake/<YYYY-Www>/<journey-id>/. EXIF stripped here._review.md notes which items get promoted, kept as context, or escalated.beneficiary_promote.py commits it.intake/ → intake-archive/<YYYY-Qn>/. Profiles are living docs, never archived.AI + automation · what runs unattended
Entry drafting (Claude)
claude-opus-4-7 · beneficiary-recorder · on demand
Reads a raw drop (notebook scan, Zalo thread, report-card PDF) and returns a markdown progress-note in the canonical shape. Factual structuring, not tone.
Report writing (Claude)
claude-opus-4-7 · report_child / cohort / school · on demand + monthly
Composes the narrative wrapper around the SQL view for per-child, per-cohort, and per-school reports. Claims trace back to the structured sections; no invented detail. Audience filter narrows what's included.
Stream-C journeys (Claude)
claude-opus-4-7 · journey-writer · on demand
Reads Block 3 + benefits ledger only; drafts a long-form progress narrative. The format choice when the Coordinator wants a journey-shaped piece, not an event piece.
Safeguarding watchlist (signal job)
safeguarding_watchlist.py · monthly + daily-keyword
Scheduled job, no AI. Seven simple rules — absence >60d, followup overdue, benefit anomaly, status drift, keyword hit, coordinator drift, sibling cluster — surface items into the lead's triage queue. Job never signs off gate 8; the named human still decides.
Build sequence
Seven phases, in increasing operational risk. The hand-rolled pilot (B-zero) runs in parallel with the first two coding phases — the data shape gets stress-tested by a real coordinator on real cases before the code locks.
Operational pilot · one school, five children
Pick one partner school + one coordinator + five children. The coordinator drafts five profiles by hand in the canonical markdown shape, drops five weeks of intake material, walks the pathway end-to-end on paper.
Data shapes + registry migration
The schema lands. SQLite on the private Drive gets the three tables; the profile validator runs against fixture profiles.
beneficiary_registry_migrate.py— createschild,benefit,profile_entrybeneficiary_validate.py— frontmatter + petal + append-only checks- 2 example synthetic profiles in
tests/fixtures/beneficiary/
Intake + promotion (Claude-assisted)
A coordinator can take a raw drop, get a Claude-drafted entry, edit it, and commit it to the profile + SQL.
beneficiary-recorderagent +/recordskill — the Claude-Opus promptbeneficiary_promote.py— the operational verb (commit + index update)- Pre-commit hook:
media_sanitise.py --verifyon intake files - Fake-API tests via the
CaptionEngine-style protocol pair
Benefits ledger + Area-4 hooks
The Foundation can write a benefit, query by month/programme/school/funding-source/petal, and emit a draft narrative for the monthly report.
benefit_record.py— write a ledger entry; validatesfunding_sourceagainstfunding_sources.yamlbenefit_report.py— SQL views → markdown for Area-4; HXL-CSV emitter- Claude drafts the narrative wrapper around the numbers
funding_source = X) are one query.Indexes + cohort dashboard
The three indexes (by-cohort, by-school, by-child) and the quarterly cohort dashboard regenerate nightly. Drift between SQL rows ↔ markdown files surfaces in a daily check.
beneficiary_index_rebuild.py— nightly rebuildbeneficiary_consistency_check.py— selftest exits zero on a clean run
Parameterised reports (per-child / per-cohort / per-school)
Three CLI tools sharing one backbone: SQL view → Claude-drafted narrative → markdown / PDF / HXL-CSV. Same code path runs from the dashboard and from the scheduled monthly publication run.
tools/report_child.py— singlejourney-NNNN; case review, hand-off, sponsor viewtools/report_cohort.py— programme × cohort year (e.g. Cùng em tiến bước 2026)tools/report_school.py— partner school; the principal's monthly read- Audience filter (
coordinator/safeguarding/principal/trustee/sponsor) narrows what each output includes
reports/<YYYY>/ for diffable comparison over time.Safeguarding watchlist (monthly autonomous signal run)
The named safeguarding sign-off stays manual; what becomes autonomous is the signal detection that feeds the lead's triage queue. The job reads the registry monthly + profile markdown, applies seven independent rules, surfaces items the lead reviews.
tools/safeguarding_watchlist.py— runs monthly (full sweep) + daily (keyword-only narrower pass)- Seven signals: absence (60d), followup overdue (45d), benefit anomaly (90d zero), status drift, keyword hit, coordinator drift, sibling cluster
- Each item lands in the
watchlist_itemSQL table with an audit trail 01_Beneficiaries/watchwords.yaml— lead reviews quarterly- Job never clears gate 8. Surfaces signals, never makes decisions.
FastAPI dashboard for principals + trustees + safeguarding lead
A small internal web app on top of the SQLite store. Read the cohort, see one child's full record, add a progress note, generate reports, triage the safeguarding watchlist. Two-way sync: the app writes to the same store the markdown tools do; coordinators still own the canonical markdown.
app/— FastAPI + a typed schema layer over the SQLite- Read + light data entry: progress notes, followups, benefits
- Reports surface: per-child / per-cohort / per-school generation with audience picker
- Safeguarding watchlist screen: each item is a card the lead acts on (dismiss / coord-followup / escalate / re-surface)
- Login via Google Workspace; charts via CSS + light JS
Stack summary
| Layer | Choice | Why |
|---|---|---|
| Storage | Markdown profiles + SQLite (WAL) | Human-readable canonical record + fast queryable shape. No Postgres / no SaaS DB at this scale. |
| Hosting | Private Google Shared Drive + Drive desktop client | Foundation already lives in Google Workspace; the Drive's own membership list is the access boundary. |
| Tools | Python 3.11; 6–8 small CLI scripts | Each < 200 LOC; matches the media-line discipline; selftest on every tool. |
| AI | Claude Opus 4.7 · Anthropic SDK · prompt caching | Already wired for the media line; reuses the CaptionEngine pattern. |
| App | FastAPI + HTMX, server-rendered HTML | No SPA build pipeline; a single Python developer can run the whole stack; Cloud Run or a single VM deploys it. |
| Auth | Google Workspace SSO | Principals + trustees already have Workspace accounts; no separate user DB. |
| Backup | Drive revision history + nightly SQLite snapshot | Drive gives version history on every file; SQLite snapshot rotated weekly. |