-
Notifications
You must be signed in to change notification settings - Fork 7
Scaffold DAK AI Skill Library infrastructure with BPMN support #288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
7252166
Initial plan
Copilot fc517b2
Scaffold DAK AI Skill Library infrastructure
Copilot dd6bca0
Fix BPMN namespace check verbosity and keyword classifier false posit…
Copilot 03effd5
Address code review feedback
Copilot d03e79f
Fix critical security issue in pr-validate-slash.yml
Copilot 6020568
Replace SmartLLMFacade with direct LiteLLM usage via llm_utils.py
Copilot e169208
chore: update translation templates (.pot) [2026-03-06 02:35 UTC]
github-actions[bot] 4051f58
Merge branch 'main' into copilot/create-skills-infrastructure-bpmn
litlfred 3f3f4be
Move labels/ to .github/skills/labels/, improve .env.example docs, cl…
Copilot 7d0ac86
chore: update translation templates (.pot) [2026-03-06 13:29 UTC]
github-actions[bot] efb28e4
Merge upstream main: incorporate .pot translation templates and trans…
Copilot ac83148
Update .github/skills/common/ig_errors.py
litlfred e91966d
fix: use --tx for Python runner, -tx for Java JAR in ig_publisher_ifa…
Copilot c87fd25
fix: address automated review feedback — missing __init__.py, prompt …
Copilot 057c33a
fix: correct format_issues typo in ig_errors.py docstring
Copilot 4dc6239
Merge upstream main: resolve run_ig_publisher.py conflict (take upstr…
Copilot b7f744d
Update .github/skills/bpmn_author/actions/bpmn_author_action.py
litlfred File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # DAK Skill Library — local config. Copy to .env (never commit .env). | ||
| # | ||
| # LLM features (authoring, error interpretation, classification): | ||
| # Leave blank → LLM steps skipped, structural validation still runs. | ||
| # Billed to YOUR account, not WHO. | ||
| # | ||
| # ─── API KEY ──────────────────────────────────────────────────────────── | ||
| # Get a key from your LLM provider: | ||
| # OpenAI: https://platform.openai.com/api-keys → starts with sk- | ||
| # Anthropic: https://console.anthropic.com/settings/keys → starts with sk-ant- | ||
| # Google AI: https://aistudio.google.com/app/apikey → starts with AI... | ||
| # Azure: Azure Portal → your OpenAI resource → Keys | ||
| # | ||
| # LiteLLM routes to the right provider based on the model name below. | ||
| # Leave blank to skip all LLM steps (structural validation still runs). | ||
| DAK_LLM_API_KEY= | ||
|
|
||
| # ─── MODEL ────────────────────────────────────────────────────────────── | ||
| # LiteLLM model identifier. Format: [provider/]model-name | ||
| # | ||
| # Popular options (as of 2025): | ||
| # OpenAI: gpt-4o, gpt-4o-mini, gpt-4-turbo, o1-mini | ||
| # Anthropic: claude-sonnet-4-20250514, claude-3-5-haiku-20241022 | ||
| # Google: gemini/gemini-2.0-flash, gemini/gemini-1.5-pro | ||
| # Azure: azure/your-deployment-name | ||
| # | ||
| # Master list of all supported models and provider prefixes: | ||
| # https://docs.litellm.ai/docs/providers | ||
| # | ||
| # Default: gpt-4o (requires OpenAI key above) | ||
| DAK_LLM_MODEL=gpt-4o | ||
|
|
||
| # ─── IG PUBLISHER (optional) ─────────────────────────────────────────── | ||
| # Custom FHIR terminology server. Leave blank for default (tx.fhir.org). | ||
| DAK_TX_SERVER= |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # DAK Skill Library — Local Development Image | ||
| # Mirrors ghbuild.yml CI environment exactly. | ||
| # Base: hl7fhir/ig-publisher-base (Jekyll, Ruby, Java 17, Node.js) | ||
|
|
||
| FROM hl7fhir/ig-publisher-base:latest | ||
|
|
||
| LABEL org.opencontainers.image.title="DAK Skill Library" | ||
| LABEL org.opencontainers.image.source="https://github.com/WorldHealthOrganization/smart-base" | ||
|
|
||
| # Python packages — identical to ghbuild.yml | ||
| # --break-system-packages is required because the base image uses Debian's | ||
| # externally-managed Python; a venv is unnecessary inside a disposable container. | ||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| python3 python3-pip python3-venv \ | ||
| && ln -sf /usr/bin/python3 /usr/bin/python \ | ||
| && pip3 install --break-system-packages \ | ||
| "GitPython>=3.1.40" \ | ||
| "PyYAML>=6.0" \ | ||
| "requests>=2.28.0" \ | ||
| "lxml" \ | ||
| "litellm>=1.0.0" \ | ||
| "pdfplumber" \ | ||
| "pandas" \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # SUSHI — identical to ghbuild.yml | ||
| RUN npm install -g fsh-sushi | ||
|
|
||
| # IG Publisher jar — pre-baked so local runs don't need network | ||
| # Override: -v /local/publisher.jar:/app/publisher.jar | ||
| RUN mkdir -p /app/input-cache \ | ||
| && curl -L \ | ||
| https://github.com/HL7/fhir-ig-publisher/releases/latest/download/publisher.jar \ | ||
| -o /app/input-cache/publisher.jar | ||
|
|
||
| # DAK skill library | ||
| COPY . /app/skills/ | ||
|
|
||
| # Workspace — mount IG repo here: -v $(pwd):/workspace | ||
| WORKDIR /workspace | ||
|
|
||
| ENV PUBLISHER_JAR=/app/input-cache/publisher.jar | ||
| ENV DAK_IG_ROOT=/workspace | ||
|
|
||
| ENTRYPOINT ["python3", "/app/skills/cli/dak_skill.py"] | ||
| CMD ["--help"] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| # DAK Skill Library | ||
|
|
||
| The DAK Skill Library provides AI-assisted and structural validation tools | ||
| for authoring WHO Digital Adaptation Kit (DAK) content. | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ### Local Development (Docker) | ||
|
|
||
| ```bash | ||
| # 1. Build the image | ||
| docker build -t dak-skill .github/skills/ | ||
|
|
||
| # 2. Copy environment template | ||
| cp .env.example .env | ||
| # Edit .env to add your LLM API key (optional — structural validation works without it) | ||
|
|
||
| # 3. Run skills | ||
| docker compose -f .github/skills/docker-compose.yml run --rm validate | ||
| docker compose -f .github/skills/docker-compose.yml run --rm validate-ig | ||
| docker compose -f .github/skills/docker-compose.yml run --rm import-bpmn | ||
| docker compose -f .github/skills/docker-compose.yml run --rm shell | ||
|
|
||
| # Shortcut alias: | ||
| alias dak='docker compose -f .github/skills/docker-compose.yml run --rm' | ||
| dak validate | ||
| dak import-bpmn | ||
| ``` | ||
|
|
||
| ### CI (GitHub Actions) | ||
|
|
||
| Skills run automatically via GitHub Actions workflows: | ||
|
|
||
| | Trigger | Workflow | What it does | | ||
| |---|---|---| | ||
| | Issue opened/edited | `classify-issue.yml` | Auto-labels issues with `content:L1/L2/L3/translation` | | ||
| | Label `content:L1` | `skill-l1-review.yml` | L1 guideline review (placeholder) | | ||
| | Label `content:L2` | `skill-l2-dak.yml` | L2 DAK content authoring | | ||
| | Label `content:L3` | `skill-l3-review.yml` | L3 adaptation review (placeholder) | | ||
| | Label `content:translation` | `skill-translation.yml` | Translation management (placeholder) | | ||
| | PR comment `/validate` | `pr-validate-slash.yml` | Structural + IG validation | | ||
|
|
||
| ## One-Time Repository Setup | ||
|
|
||
| ``` | ||
| 1. Create labels (Issues → Labels → New label): | ||
| content:L1 #0075ca "WHO source guideline content" | ||
| content:L2 #e4e669 "DAK FHIR assets" | ||
| content:L3 #d73a4a "Implementation adaptations" | ||
| content:translation #0e8a16 "Translation of any content layer" | ||
| (Label definitions also stored in .github/skills/labels/*.json for reference.) | ||
|
|
||
| 2. Add secret (Settings → Secrets and variables → Actions → New repository secret): | ||
| DAK_LLM_API_KEY = sk-... | ||
|
|
||
| 3. Add variable (Settings → Secrets and variables → Variables → New variable): | ||
| DAK_LLM_MODEL = gpt-4o (or gpt-4o-mini to reduce cost) | ||
| See .env.example for the full list of supported model identifiers, | ||
| or https://docs.litellm.ai/docs/providers for the master list. | ||
|
|
||
| 4. Build local Docker image (optional, for local development): | ||
| docker build -t dak-skill .github/skills/ | ||
| ``` | ||
|
|
||
| ## Security Model | ||
|
|
||
| - **API keys MUST NOT appear** in dispatch inputs, issue comments, PR comments, or any user-visible UI | ||
| - Two legitimate locations only: **repo secret** (CI) or **local `.env` file** (Docker/local) | ||
| - LLM steps skip gracefully when no key present — non-LLM validation always runs | ||
| - **Zero WHO infrastructure cost; zero WHO AI cost** | ||
|
|
||
| ### Graceful Degradation | ||
|
|
||
| | Skill | No key | With key | | ||
| |---|---|---| | ||
| | BPMN structure validation | ✅ runs | ✅ runs | | ||
| | Swimlane ↔ ActorDef validation | ✅ runs | ✅ runs | | ||
| | IG Publisher build/validate | ✅ runs | ✅ runs | | ||
| | Issue classification | keyword fallback | LLM classification | | ||
| | LLM BPMN authoring | ⚠️ skipped | ✅ runs | | ||
| | LLM error interpretation | ⚠️ skipped | ✅ runs | | ||
|
|
||
| ## Directory Structure | ||
|
|
||
| ``` | ||
| .github/skills/ | ||
| ├── Dockerfile # FROM hl7fhir/ig-publisher-base — mirrors CI | ||
| ├── docker-compose.yml # Service aliases: validate, author, import, shell | ||
| ├── README.md # This file | ||
| ├── skills_registry.yaml # All registered skills | ||
| ├── cli/ | ||
| │ └── dak_skill.py # CLI entry point | ||
| ├── common/ | ||
| │ ├── llm_utils.py # LLM helpers — thin wrappers around LiteLLM | ||
| │ ├── prompt_loader.py # load_prompt() — .md templates with {variable} | ||
| │ ├── ig_errors.py # FATAL/ERROR/WARNING/INFORMATION format | ||
| │ ├── fsh_utils.py # FSH file utilities | ||
| │ ├── ig_publisher_iface.py | ||
| │ └── prompts/ # Shared prompt templates | ||
| ├── bpmn_author/ # Author/edit BPMN | ||
| ├── bpmn_import/ # Import BPMN → FSH, validate lanes | ||
| ├── ig_publisher/ # IG Publisher validation and build | ||
| ├── dak_authoring/ # Issue classification and L2 content review/authoring | ||
| │ ├── actions/ | ||
| │ │ ├── classify_issue_action.py # Keyword + LLM issue classifier | ||
| │ │ └── dak_authoring_action.py # L2 content review skill (→ content:L2 label) | ||
| │ └── prompts/ | ||
| ├── labels/ # GitHub label definitions (JSON, for reference) | ||
| ├── l1_review/ # (placeholder v0.2) | ||
| ├── l3_review/ # (placeholder v0.3) | ||
| └── translation/ # (placeholder v0.3) | ||
| ``` | ||
|
|
||
| ## LLM Provider | ||
|
|
||
| LLM features use [LiteLLM](https://github.com/BerriAI/litellm) (MIT License) — | ||
| a well-maintained multi-provider library (OpenAI, Anthropic, Google, etc.) | ||
| with 20k+ GitHub stars. The `common/llm_utils.py` module adds only DAK-specific | ||
| environment variable bridging and JSON-extraction helpers on top of LiteLLM; | ||
| there is no custom LLM facade to maintain. |
Empty file.
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| """ | ||
| BPMN Author action — creates or edits BPMN files via LLM, | ||
| then validates the result structurally. | ||
|
|
||
| Environment variables: | ||
| DAK_LLM_API_KEY — LLM API key (optional; LLM steps skipped if absent) | ||
| DAK_LLM_MODEL — LLM model name (default: gpt-4o) | ||
| GITHUB_TOKEN — GitHub API token for issue/PR interaction | ||
| ISSUE_NUMBER — GitHub issue number | ||
| ISSUE_TITLE — Issue title | ||
| ISSUE_BODY — Issue body text | ||
| """ | ||
|
|
||
| import os | ||
| import sys | ||
| from pathlib import Path | ||
|
|
||
| # Ensure the skills root is on sys.path | ||
| _SKILLS_ROOT = Path(__file__).resolve().parent.parent.parent | ||
| if str(_SKILLS_ROOT) not in sys.path: | ||
| sys.path.insert(0, str(_SKILLS_ROOT)) | ||
|
|
||
| from common.ig_errors import format_issues, has_errors | ||
| from bpmn_author.validators.bpmn_xml_validator import validate_bpmn_xml | ||
| from bpmn_author.validators.swimlane_validator import validate_swimlanes | ||
|
|
||
|
|
||
| def main() -> None: | ||
| api_key = os.environ.get("DAK_LLM_API_KEY", "") | ||
| if not api_key: | ||
| print("⚠️ DAK_LLM_API_KEY not set — LLM step skipped (structural validation still runs)") | ||
| sys.exit(0) | ||
|
|
||
| from common.llm_utils import dak_completion | ||
| from common.prompt_loader import load_prompt | ||
|
|
||
| issue_title = os.environ.get("ISSUE_TITLE", "") | ||
| issue_body = os.environ.get("ISSUE_BODY", "") | ||
| model = os.environ.get("DAK_LLM_MODEL", "gpt-4o") | ||
|
|
||
| # Load additional prompt components required by the create_or_edit_bpmn template | ||
| _prompts_dir = _SKILLS_ROOT / "common" / "prompts" | ||
| dak_bpmn_constraints = (_prompts_dir / "dak_bpmn_constraints.md").read_text(encoding="utf-8") | ||
| bpmn_xml_schema = (_prompts_dir / "bpmn_xml_schema.md").read_text(encoding="utf-8") | ||
| actor_context = (_prompts_dir / "actor_context.md").read_text(encoding="utf-8") | ||
|
|
||
| # Load additional prompt components required by the create_or_edit_bpmn template | ||
| dak_bpmn_constraints_path = _SKILLS_ROOT / "common" / "prompts" / "dak_bpmn_constraints.md" | ||
| bpmn_xml_schema_path = _SKILLS_ROOT / "common" / "prompts" / "bpmn_xml_schema.md" | ||
| actor_context_path = _SKILLS_ROOT / "common" / "prompts" / "actor_context.md" | ||
|
|
||
| with dak_bpmn_constraints_path.open(encoding="utf-8") as f: | ||
| dak_bpmn_constraints = f.read() | ||
| with bpmn_xml_schema_path.open(encoding="utf-8") as f: | ||
| bpmn_xml_schema = f.read() | ||
| with actor_context_path.open(encoding="utf-8") as f: | ||
| actor_context = f.read() | ||
|
|
||
| prompt = load_prompt( | ||
| "bpmn_author", | ||
| "create_or_edit_bpmn", | ||
| user_request=f"{issue_title}\n\n{issue_body}", | ||
| current_bpmn="(none — creating new BPMN)", | ||
|
litlfred marked this conversation as resolved.
|
||
| dak_bpmn_constraints=dak_bpmn_constraints, | ||
| bpmn_xml_schema=bpmn_xml_schema, | ||
| actor_context=actor_context, | ||
| dak_bpmn_constraints=dak_bpmn_constraints, | ||
| bpmn_xml_schema=bpmn_xml_schema, | ||
| actor_context=actor_context, | ||
| ) | ||
|
|
||
| print(f"🤖 Requesting BPMN from {model}...") | ||
| bpmn_xml = dak_completion(prompt, api_key=api_key, model=model) | ||
|
|
||
| # Validate the generated BPMN | ||
| issues = validate_bpmn_xml(bpmn_xml, filename="generated.bpmn") | ||
| issues.extend(validate_swimlanes(bpmn_xml, filename="generated.bpmn")) | ||
|
|
||
| print(format_issues(issues)) | ||
|
|
||
| if has_errors(issues): | ||
| print("❌ Generated BPMN has validation errors.") | ||
| sys.exit(1) | ||
|
|
||
| print("✅ Generated BPMN passed structural validation.") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # Create or Edit BPMN | ||
|
|
||
| You are a BPMN 2.0 authoring assistant for WHO Digital Adaptation Kits (DAKs). | ||
|
|
||
| ## Your Task | ||
|
|
||
| {user_request} | ||
|
|
||
| ## Constraints | ||
|
|
||
| {dak_bpmn_constraints} | ||
|
|
||
| ## BPMN XML Schema | ||
|
|
||
| {bpmn_xml_schema} | ||
|
|
||
| ## Actor Context | ||
|
|
||
| {actor_context} | ||
|
|
||
| ## Current BPMN (if editing) | ||
|
|
||
| ```xml | ||
| {current_bpmn} | ||
| ``` | ||
|
|
||
| ## Instructions | ||
|
|
||
| 1. Generate valid BPMN 2.0 XML following the constraints above. | ||
| 2. Use meaningful lane IDs that can serve as FSH instance identifiers. | ||
| 3. Ensure every task is assigned to exactly one lane. | ||
| 4. Include sequence flows connecting all elements. | ||
| 5. Return ONLY the BPMN XML — no explanation, no markdown fences. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| # Validate BPMN | ||
|
|
||
| Review the following BPMN XML for compliance with WHO DAK constraints. | ||
|
|
||
| ## BPMN XML | ||
|
|
||
| ```xml | ||
| {bpmn_xml} | ||
| ``` | ||
|
|
||
| ## Validation Results (structural) | ||
|
|
||
| {validation_results} | ||
|
|
||
| ## Instructions | ||
|
|
||
| Summarize the validation findings. For each issue: | ||
| 1. Explain what is wrong and why it matters for DAK compliance. | ||
| 2. Suggest a specific fix. | ||
|
|
||
| If there are no issues, confirm the BPMN is valid. | ||
| Return your analysis as JSON: | ||
| ```json | ||
| {{ | ||
| "valid": true/false, | ||
| "summary": "...", | ||
| "issues": [ | ||
| {{"code": "...", "severity": "...", "message": "...", "fix": "..."}} | ||
| ] | ||
| }} | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # bpmn_author skill | ||
| name: bpmn_author | ||
| version: "0.1.0" | ||
| description: Author and edit standard BPMN 2.0 XML for DAK business processes | ||
|
|
||
| commands: | ||
| - name: create-bpmn | ||
| description: Create a new BPMN file from a natural-language description | ||
| requires_llm: true | ||
| - name: edit-bpmn | ||
| description: Edit an existing BPMN file based on instructions | ||
| requires_llm: true | ||
| - name: validate-bpmn | ||
| description: Validate BPMN structure and DAK constraints (no LLM needed) | ||
| requires_llm: false | ||
|
|
||
| validators: | ||
| - bpmn_xml_validator | ||
| - swimlane_validator | ||
|
|
||
| prompts: | ||
| - create_or_edit_bpmn | ||
| - validate_bpmn |
Empty file.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.