| Key |
Value |
| name |
veripath-pharmacy |
| description |
Practitioner-level pharmacy domain knowledge for analysing, assessing, and documenting the VeriPath Pharmacy App — clinical workflows, GPhC compliance, Responsible Pharmacist duties, NHS EPS (FHIR) integration, Controlled Drugs registries, OTC point of sale, and retail accounting. Load whenever reviewing, documenting, demoing, or mocking the pharmacy app, reviewing OpenCode's pharmacy implementation outcomes, or drafting pharmacy policy/GPhC/DSPT content. |
| version |
1.1.0 |
| author |
Hermes Agent |
| license |
MIT |
| platforms |
[linux] |
| metadata |
|
| hermes |
|
| tags |
[veripath, pharmacy, clinical, domain-knowledge, eps, fhir, gphc, ods, nhs-notify, counter-pos, stripe-terminal, erpnext, dspt] |
| category |
veripath |
| related_skills |
[veripath-docs, veripath-wiki-assets] |
Use this skill when asked to:
- Review, document, demo, or mock the VeriPath Pharmacy App (UI, models, workflows, screens)
- Assess implementation outcomes — check OpenCode's pharmacy work against how an independent
pharmacy actually operates, and against what the repository really implements
- Draft pharmacy-facing content — user manuals, wiki pages, marketing copy, DSPT/GPhC policy
material, counter/role documentation
- Design synthetic data — realistic pharmacy dummy data (drugs, batches, prescriptions, staff)
Equip Hermes to analyse and assess the VeriPath Pharmacy App as if a practitioner — NOT to give
clinical or medical advice. The app exists to assist independent pharmacy operations (dispensing,
retail inventory, compliance tracking) so staff can focus on clinical judgement and patient care.
This skill supplies the domain knowledge to judge whether features match real-world UK pharmacy
reality, to document them accurately, and to produce realistic (synthetic) data models.
What this skill is / is not:
- IS: Clinical reference + an assessment lens + structural terminology + realistic dummy-data
conventions for the community pharmacy domain.
- IS NOT: Medical advice, legal dispensing validation, or treatment recommendations. Never write
anything that reads as direct clinical guidance to a patient or pharmacist. The practitioner
decides; we describe what the software helps them do.
- Synthetic data only. Background knowledge for modelling, never a record of it. No real patient
data ever enters an output, a wiki page, a manual, or a demo.
- No secrets in any output. No passwords, API keys, DB credentials, or internal addresses in
manuals, wiki pages, screenshots or handoff notes.
- Document what exists. Verify every claimed capability against the repository; if a feature is
absent, publish a dated holding note (NOT YET AVAILABLE (checked YYYY-MM-DD)) rather than
describing aspirational behaviour. The research pages under development/projects/pharmacy_app/
are design intent, not shipped behaviour.
- Keep the SIAAS rule intact in descriptions. Central tiers hold metadata and routing only;
patient/clinical payloads, POS/stock and financial records live on the client-owned instance.
Apply to every pharmacy feature, model or screen:
- Which real-world operational task does this assist? (onboarding → login duty → spine polling →
assembly → check → sync stock → payment → hand over)
- Does it match how an independent practice actually works — terminology, sequence, legal roles?
- Who uses it at the counter or dispensary? (Responsible Pharmacist / Technician / Counter
Assistant / Business Manager) — does the UI + Keycloak permissions match that?
- Are the clinical and business terms correct? (GPhC, ODS code, FHIR bundles, SNOMED CT, FEFO
picking, zero-rated tax, NHSBSA endorsement…)
- Is the claimed value actually implemented? Verify against the repository codebase
(/root/work/gp_booking_app/); publish a holding note if the feature is absent — never document
aspirational behaviour.
- Data safety: Dummy data only, no PII, stateless central routing, strict SIAAS validation down
SSH tunnels to client-owned instances.
- Subdomain Mapping: Maps out
*.pharmacy.veripath.co.uk infrastructure. The central registry is
the existing tenancy.Sector / tenancy.Tenant pair — there is no PharmacySectorConfig (the
research pages proposed one; the project rejected it as redundant, because Tenant already carries
the subdomain, encrypted DB credentials, host/port and a config JSON field). Organisation
identifiers (ODS code, GPhC premises number) live in Tenant.config.
- Client-tier tenancy (shipped 2026-09-13): an independent pharmacy is a tenant in the client
sector, hosted at {slug}.pharmacy.veripath.co.uk (host prefix = tenant subdomain), with its own
database, its own login role and its own staff identities. Its rows route to the per-client database
alias; the apex tenant (pharmacy.veripath.co.uk) is a separate tenant in the pharmacy sector whose
rows live in the sector database. Full recipe, evidence and gotchas:
development/projects/pharmacy_app/operations/test-client.
- Responsible Pharmacist Log (RPL): Legally mandated under UK law. Tracks personal GPhC IDs,
precise timestamp entries for shift handovers, and demands digital signatures via the aes-portal
(Port 8004). Enforces a maximum rule of one active RP on duty per physical location site — enforced
in the tenant's own database, so the transaction wrapping a sign-on must follow the routing.
Verified 2026-09-14 — the rest of this section describes the destination, not the code. The
inherited EPS integration is prescriber-side only: issue_prescription / check_status /
cancel_prescription / search_prescriptions and the mock's clear_mock_data. There is no claim,
release, return, dispense or endorse operation anywhere in the layer, so the pharmacy-side surface is
new work (Phase 2 work item W3), never "wire up the existing client". Do not quote EPS work as
pure reuse.
Where pharmacy models may live: not clinical_data. That app sits in the router's GP_APPS
partition and routes to sector_gp, so anything modelled there ends up in the wrong database. Every
pharmacy capability gets its own app registered in PHARMACY_APPS (a data-driven
SECTOR_APP_PARTITIONS registry — one line plus its models) and its tables live on the client tier.
- Stateless Routing Engine: Incoming REST payloads from the NHS Spine (
https://national.nhs.uk)
must be parsed instantly in-memory on VPS2 and piped into the client's database via the designated
db_alias. Residual patient records or medical list text strings must never touch local storage on
the central gateway.
- Dispensing Lifecycles: Token statuses must map perfectly across standard operational
thresholds: CLAIMED (Locked from Spine) → ASSEMBLED (Medication packaged on shelf) →
DISPENSED (the clinical act is complete — not the same as handed over; the module map keeps
dispensed ≠ handed over, and collection/handover is a later phase, so "dispensed but not yet
collected" must be a legitimate resting state) → ENDORSED (the reimbursement claim is recorded;
NHSBSA transmission is later still).
- PII Data Segregation: Patient records, NHS numbers, and SNOMED CT medication display
identifiers are written purely into the pharmacy partition apps on the client-owned instance
(see the note above — not clinical_data), with application-level Fernet symmetric keys, and never
into a central table, log, audit row or error message.
- Cross-Database Hooks: ERPNext work runs through the proven frappe REST client
(integrations/erpnext_client.py: /api/resource/..., /api/method/..., including submit/cancel)
and is kicked off from Celery tasks, never from a post_save signal on the request path.
- Never write Frappe tables directly. The research draft's raw
tabBatch / tabBin /
tabStock Entry SQL is off-pattern and must not be implemented that way.
- FEFO Picking Logic: First-Expiry, First-Out consumption; block transactions whose lot has passed
its shelf life — expressed through ERPNext documents via the REST client, not raw table edits.
- Stock Balancing: Material Issue style stock entries and availability adjustments, same route.
- Counter Checkouts: Integrates client-side JavaScript SDK controllers with localized browser
modules to drive in-store card readers (Stripe Terminal) via the client's own merchant
configurations. Ownership is locked (2026-09-12): Django owns the payment configuration and the
payment intent; ERPNext owns the accounting document. Do not mix the ERPNext POS frontend with the
app's own payment routing.
- Tax Splits: Accounts separate standard 20% retail VAT items (OTC medicines, toiletries) from
zero-rated NHS prescription dispensations (tabStock Entry Detail).
Matthew authorises one phase at a time, and Hermes's deliverable is a specification page — the
pattern of development/projects/pharmacy_app/build-records/phase-1-onboarding-rp-log and
.../phase-2-dispensing; Phases 3–6 follow it. Sections that must be there:
- Why this phase now, from the module map's sequencing rationale.
- Scope in / explicitly out — naming the deferred items is what stops later phases creeping in.
- The boundary call the phase forces (Phase 2: dispensing stops before handover; Phase 3 will
need the stock equivalent).
- The data-boundary table restated for the new data: client-tier, central (routing metadata only),
and what must never appear centrally — plus the DSPT framing.
- What exists to build on, verified against the repository in that session. Spell every reuse
claim out and check it in the code; repeating a module-map reuse claim without checking is how the
EPS gap could have shipped as "wiring".
- Pre-work gates, then work items with owners (OpenCode builds; Hermes specifies, verifies
against artifacts, documents), then decisions held for Matthew each with a recommendation, then
phase acceptance as testable assertions, then risks.
- Measure the phase's own data position live before writing the spec, and put the numbers in it —
coverage, ceilings, and what cannot be reached. This has caught a real error twice: the Part II
count that dropped 139 controlled drugs (a one-shape parse of a block with two shapes), and the
phase-8 shorthand "the StockItem PIP → pack bridge", which was wrong because the central store
holds no PIP attribute at all.
- Pack identity, stated once because every pricing phase rests on it: a contractor's
StockItem
(free text + pip_code + barcode) → AMPP (the brand bought) → VMPP (the pack reimbursed).
PIP is commercial only — it matches a wholesaler price row to a stock item and can never reach
dm+d. Only a barcode/GTIN or a name + pack size match reaches a pack, and GTINs come in
both 13- and 14-digit widths (a one-width match loses packs silently); a name resolves to a VMP,
which holds several packs, so the free-text pack size must resolve to the VMPP or be queued.
- When Matthew delegates a decision ("do what you think is the best approach"), take it, record
the ruling and its reason on the spec marked as his to overrule, and prefer the option that needs
nothing external: a figure whose live rows already cite an ungated source (the NHSBSA notices, OGL v3)
can be shown to clients without waiting on a licensing task that is not ours to do.
- There is no front-end stack to lean on. The pharmacy app carries zero
<script> tags in every
pharmacy*/templates/, no static JS, and its own hand-written <style> in
pharmacy/templates/pharmacy/base.html (.card / .muted / .warning / .btn, green #0b5d4a,
max-width: 880px). So any UI addition is progressive enhancement: vanilla, inline, no framework, no
CDN, no build step, and the page must still work with JavaScript off. Style it in the pharmacy app's own
idiom — the Bootstrap components elsewhere in the repository (templates/core/, templates/clinical_data/)
are the GP app's and would drag a second styling system into these screens. Before adding an accept= or any
client-side rule, read the field's own help_text: the price-file field accepts .csv, .txt or .tsv,
and the obvious accept=".csv" would quietly narrow what the app takes.
- No effort estimates exist anywhere on this programme: give indicative relative sizes and say they
are not durations.
Then brief OpenCode via agents/handoff/from-hermes (newest on top, Status: OPEN) — point at the
spec page for detail instead of duplicating it, and state plainly what must not be assumed
authorised — and update index + module-map status.
- Names: Clearly synthetic British names (e.g., James Carter, Sarah Mitchell). Never real patient
names.
- NHS Numbers: 10 digits using the official 400-series test range (e.g.,
4000000001) with an
added explicit disclaimer label noting it as a "synthetic test number".
- System Identifiers: Mock ODS codes matching standard formatting parameters (e.g.,
FX123).
- Clinical Records: Valid SNOMED CT drug listing targets (e.g.,
324314004 for Amoxicillin
500mg capsules) and plausible dosage instructions.
- Instructions to OpenCode: Enforce strict spatial isolation rules when tasking the engine to
expand data views. Remind OpenCode to check permissions against Keycloak client roles
(rp_active_duty, access_pos_terminal) before modifying backend logic.
- User Guides: Group procedures by operational workflows (Dispensing, Inventory Control,
Accounting Handovers) and verify code behaviours against actual project structures before
publishing.
- Companion skills:
veripath-docs (manuals + Wiki.js), veripath-wiki-assets (faithful UI
screenshots), demo-agent (live walkthroughs). A pharmacy-app-guides companion — per-workflow
app guides mirroring dental-app-guides — does not exist yet; mint it once the pharmacy app is
implemented and testable.