Status: Items 1–6 implemented and verified on the
test-client-dentaltenant. Follow-up work (F1 nav cleanup, F2 per-skill context, F3 per-persona context) is now also implemented, tested, deployed and pushed. Sample context has been seeded into every skill and every persona ontest-client-dentalanddev-clientfor study + testing — next step is to explore/try out the skill areas and personas and replace the samples with the practice's real context.Linked pages:
- Research & design: Hermes — Client's Knowledge Base
- Infrastructure readiness (✅ complete): SIAAS Infrastructure Preparation for Hermes
This page is the build plan for the Hermes dental AI platform, derived from the
design research on the hermes_ai page. It links the research to an actionable,
sequenced implementation plan. The underlying infrastructure preparation is complete,
all six application-layer build items are implemented, deployed and verified on the
test-client-dental dev tenant, and the Control Centre follow-up items (navigation
cleanup, per-skill context, per-persona context) are implemented and pushed.
/root/work/dental_booking_app and /root/work/gp_booking_app (Django, package dsp_clinic).SectorDatabaseRouter (tenancy/routers.py) + Tenant model; dev tenants dev-client (172.18.0.1:5437, pgvector-enabled, DB test_client_dental_dev) and test-client-dental (172.18.0.1:5436, DB test_client_dental, host test-client-dental.dental.veripath.co.uk).integrations.AgentConfig (encrypted API keys via EncryptedCharField) + integrations/agent_service.py (provider routing: OpenAI / Anthropic / Google / DeepSeek / Ollama / Custom)./integrations/agents/ (management) — Control Centre at /integrations/agents/control-centre/./ws/echo/ verified end-to-end on both apps.dental-radiographs bucket configured in settings (MINIO_*)./opt/infra/agent-template (per-tenant Hermes deployment, image pinned by digest).client-postgres images (v1.2.0 / ssh-v1.2.0) — vector auto-enabled on tenant DBs, HNSW index ready to add.channels_redis + nginx /ws/ upgrade (echo verified).tenant-gateway@.service per tunnel port)./integrations/agents/control-centre/) — ✅ DONEAgentConfig.AgentService.test_connection).config_json (active_personas, enabled_skills, skill_context, persona_context, knowledge_sources) on AgentConfig.test-client-dental; save round-trip persists; role agents activated via ensure_role_agents; working DeepSeek API key configured on the tenant.dental/services/radiograph_ai.py: pixel-based embedding (512-d), generate_embedding, embed_radiograph, get_historical_vector_matches (cosine <=>, per-patient filter, similarity %), backfill_embeddings.0009_dentalradiograph_xray_embedding: xray_embedding vector(512) + HNSW index (vector_cosine_ops), idempotent (IF NOT EXISTS).dicom_ingest.py → embed_radiograph); backfill_radiographs_to_minio.py backfills MinIO + embeddings.test-client-dental produced an embedded radiograph; cosine query returns 100%/78% similarity matches.SurgeryStreamConsumer at /ws/surgery/stream/ (daphne + channels in place).dental/templates/dental/surgery_workspace.html: left patient chart/odontogram, right Hermes live workspace (draft note → CO/O/E/Rx/Advice, FDI highlights, inline compliance alerts, "Approve & Commit").test-client-dental.tooth_focus_changed → vector_analysis_ready with matches + LLM diagnostic synthesis.dental/services/agent_profiles.py + ensure_role_agents management command; data access constrained via the tenant router.test-client-dental; role-gated access to surgery workspace / Control Centre confirmed.dental/services/prompt_builder.py: 3-layer prompt builder (persistent guardrails → dynamic vector context → live transcript).agent_control_centre.html extends templates/dashboards/base_dashboard.html, which renders a {% block dashboard_nav %} listing all dashboards via get_dashboard_nav_items. The Control Centre never overrode the block, so the dashboard-nav buttons kept reappearing.{% block dashboard_nav %}{% endblock %} in the Control Centre template (matching receptionist_dashboard.html), applied to both /root/work/dental_booking_app and /root/work/gp_booking_app.config_json and is injected into the Hermes prompt when the skill is enabled.integrations/models.py, both apps): config_json schema extended with skill_context: {skill_key: {instructions, tags, category}}; _default_config_json(), ensure_config_json() (preserves existing), and get_skill_context() accessor added.integrations/views.py POST, both apps): reads skill_context_<key>_instructions, skill_context_<key>_tags (comma-separated), skill_context_<key>_category and persists into config_json['skill_context']._sync_role_agents(config) mirrors enabled_skills + skill_context to the same user's role agents so the runtime surgery assistant uses exactly what the manager configures.agent_control_centre.html Skills & Roles tab, both apps): each skill toggle gained a collapsible "Per-skill context" section — instructions textarea, tags input, category input.dental/services/prompt_builder.py): build_skill_context_block(hermes_config, role) emits an [ACTIVE SKILL: <label>] block (category, tags, instructions) for each enabled skill with non-empty context; wired into assemble_prompt() and assemble_vector_synthesis_prompt() (the latter now also receives hermes_config from dental/consumers.py).AgentSkillContextTests — schema defaults, preservation on ensure_config_json, block builder (incl. bare-toggle suppression), prompt injection, and role-agent propagation. Verified: Control Centre renders 200 with all 12 skill-context fields; E2E POST persisted + propagated to all 4 role agents.integrations/models.py, both apps): config_json schema extended with persona_context: {role: {instructions}}; preserved by ensure_config_json(); get_persona_context() accessor added.integrations/views.py POST, both apps): persists persona_context_<role>_instructions; _sync_role_agents(config) injects the persona's instructions into its role agent's system prompt as an idempotent [PERSONA CONTEXT FROM CONTROL CENTRE] … [END PERSONA CONTEXT] block (module helper _inject_persona_context, also strips any legacy PERSONA SAMPLE CONTEXT blocks).agent_control_centre.html Role Switchboard, both apps): each persona card gained a collapsible "Persona context" instructions textarea.To explore how the skills tools and the persona switchboard operate as context/knowledge is added, sample context has been seeded into every item on the test-client-dental (dental app) and dev-client (gp app) tenants:
category / tags / instructions:
Compliance · fp17, nhsbsa, gdc, audit)Clinical Imaging · pgvector, radiograph, cosine, fdi)Reception · triage, urgency, slots, dental)Operations · stock, inventory, reorder, supplier)[ACTIVE SKILL] blocks plus the persona context block; the Control Centre renders all 4 skill + 4 persona context fields.The samples are deliberately generic placeholders — the next phase is to replace them with the practice's real context/knowledge and try each skill out in the surgery workspace.
wss://gp.veripath.co.uk/ws/echo/ / wss://dental.veripath.co.uk/ws/echo/ (101 expected).test-client-dental.dental.veripath.co.uk as admin.test-client-dental / manager.test-client-dental (password test123).[ACTIVE SKILL] blocks appear in the assembled prompt.sector_client_test-client-dental — run the cosine smoke test (get_historical_vector_matches).test-client-dental dev tenant for UI walk-throughs before any real client VPS data.hermes_ai, then explore/try out the skill areas and the persona switchboard with the seeded samples, replacing them with the practice's real context and knowledge over time.requirements.txt; code under the bind-mounted /app applies on container recreate.deploy push token (docker-push-2026-08).develop (dental) / main (gp):
ea3fce76, 5ad9dd1, 31e842cc — items 1–6 + LLM off event-loop fix.49b260ea (dental) / a10c1b5 (gp) — F1 nav cleanup + F2 per-skill context.d8f10d4b (dental) / a9225f8 (gp) — F3 per-persona context.