.claude/skills/fhirpath/SKILL.md
Expert guidance for writing FHIRPath expressions - a path-based navigation and extraction language for FHIR data. Use this skill when writing FHIRPath expressions, navigating FHIR resource trees, filtering collections, performing date/time arithmetic, using FHIRPath functions, writing FHIR invariants, or understanding FHIRPath operators. Trigger keywords include "FHIRPath", "fhirpath", "path expression", "FHIR navigation", "where()", "select()", "exists()", "ofType()", "resolve()", "FHIR invariant", "collection filtering", "FHIRPath function".
npx skillsauth add aehrc/pathling fhirpathInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
FHIRPath is a path-based navigation and extraction language for hierarchical data models, used extensively in FHIR and CQL. All operations return collections.
Patient.name.given // Navigate to given names
Patient.name[0].given // First name's given (0-based indexing)
Patient.name.first().given // Equivalent using first()
Observation.value.ofType(Quantity).unit // Filter by type then navigate
Prefix with type name to restrict context: Patient.name.given only works on Patient resources.
| Type | Examples |
| -------- | ---------------------------------------------------------------- |
| Boolean | true, false |
| Integer | 42, -5 |
| Decimal | 3.14159 |
| String | 'hello', 'urn:oid:1.2.3' (single quotes, use \' to escape) |
| Date | @2024-01-15, @2024-01, @2024 (partial dates allowed) |
| DateTime | @2024-01-15T14:30:00Z, @2024-01-15T14:30:00+10:00, @2024T |
| Time | @T14:30:00, @T14:30 |
| Quantity | 10 'mg', 4 days, 100 '[degF]' (UCUM units in quotes) |
{ }name.exists() // true if any names
name.exists(use = 'official') // true if any official names
name.all(given.exists()) // true if all names have given
telecom.where(system='phone').empty() // true if no phone telecoms
name.count() // number of names
name.where(use = 'official') // Filter by criteria
entry.select(resource as Patient) // Project/transform
name.select(given.first() + ' ' + family) // Combine fields
telecom.distinct() // Remove duplicates
item.repeat(item) // Recursive traversal (unique)
expansion.repeat(contains) // Navigate tree structures
name[0] // First item (0-based)
name.first() // First item
name.last() // Last item
name.tail() // All but first
name.skip(2) // Skip first 2
name.take(3) // Take first 3
name.single() // Error if not exactly one
name.given | name.family // Union (removes duplicates)
a.union(b) // Same as |
a.combine(b) // Merge without removing duplicates
a.intersect(b) // Items in both
a.exclude(b) // Items in a but not b
value is Quantity // Type check (returns Boolean)
value as Quantity // Cast (empty if wrong type)
entry.resource.ofType(Patient) // Filter collection by type
'hello'.length() // 5
'hello'.substring(1, 3) // 'ell'
'hello'.startsWith('he') // true
'hello'.endsWith('lo') // true
'hello'.contains('ell') // true (different from contains operator)
'hello'.indexOf('l') // 2
'HELLO'.lower() // 'hello'
'hello'.upper() // 'HELLO'
'a-b-c'.replace('-', '_') // 'a_b_c'
'abc'.matches('[a-z]+') // true (partial match)
'abc'.matchesFull('[a-z]+') // true (full match)
'a,b,c'.split(',') // {'a', 'b', 'c'}
('a' | 'b' | 'c').join(',') // 'a,b,c'
' hello '.trim() // 'hello'
(-5).abs() // 5
1.5.ceiling() // 2
1.5.floor() // 1
1.5.round() // 2
1.5.truncate() // 1
2.power(3) // 8.0
9.sqrt() // 3.0
2.718.ln() // ~1.0
100.log(10) // 2.0
0.exp() // 1.0
'42'.toInteger() // 42
42.toString() // '42'
'3.14'.toDecimal() // 3.14
'true'.toBoolean() // true (also 't', 'yes', 'y', '1')
'2024-01-15'.toDate() // @2024-01-15
'10:30:00'.toTime() // @T10:30:00
'5 mg'.toQuantity() // 5 'mg'
value.convertsToInteger() // true if conversion would succeed
@2024-03-15.yearOf() // 2024
@2024-03-15.monthOf() // 3
@2024-03-15.dayOf() // 15
@2024-03-15T10:30:45.123.hourOf() // 10
@2024-03-15T10:30:45.123.minuteOf() // 30
@2024-03-15T10:30:45.123.secondOf() // 45
@2024-03-15T10:30:45.123.millisecondOf() // 123
@2024-03-15T10:30:00+10:00.timezoneOffsetOf() // 10.0
@2024-03-15T10:30:00.dateOf() // @2024-03-15
@2024-03-15T10:30:00.timeOf() // @T10:30:00
now() // Current DateTime
today() // Current Date
timeOfDay() // Current Time
iif(condition, true-result, else) // Conditional (short-circuit)
coalesce(a, b, c) // First non-empty (STU)
trace('label', projection) // Debug logging
defineVariable('name', expr) // Define variable for later use (STU)
(1 | 2 | 3).sum() // 6
(1 | 2 | 3).min() // 1
(1 | 2 | 3).max() // 3
(1 | 2 | 3).avg() // 2.0
values.aggregate($this + $total, 0) // Custom aggregation
a = b // Equal (empty if either empty)
a ~ b // Equivalent (false if precisions differ, case-insensitive for strings)
a != b // Not equal
a !~ b // Not equivalent
a > b // Greater than
a < b // Less than
a >= b // Greater or equal
a <= b // Less or equal
Comparison with different date/time precisions returns empty: @2024-01 > @2024-01-15 → { }
a and b // Three-valued AND
a or b // Three-valued OR
a xor b // Exclusive OR
a implies b // Implication
not() // Negation (function, not operator)
Three-valued logic: true and { } → { }, false and { } → false
5 + 3 // Addition (also string concatenation)
5 - 3 // Subtraction
5 * 3 // Multiplication
5 / 3 // Division (always Decimal)
5 div 3 // Integer division
5 mod 3 // Modulo
'a' & 'b' // String concat (empty → empty string)
item in collection // Membership
collection contains item // Containership (converse of in)
a | b // Union
. (path), [] (indexer)+, -*, /, div, mod+, -, &is, as|>, <, >=, <==, ~, !=, !~in, containsandxor, orimpliesAdd/subtract time-valued quantities from dates/times:
@2024-01-15 + 1 month // @2024-02-15
@2024-01-31 + 1 month // @2024-02-29 (last day of month)
@2024-03-15 - 10 days // @2024-03-05
now() - 1 year // One year ago
Calendar duration keywords: year(s), month(s), week(s), day(s), hour(s), minute(s), second(s), millisecond(s)
UCUM definite durations ('a', 'mo', 'd') are NOT equivalent for arithmetic above seconds.
%ucum // UCUM URL (http://unitsofmeasure.org)
%context // Original evaluation context
%`custom` // Custom variables (backtick-delimited)
When a function expects a single item but receives a collection:
name.where(use = 'official').exists() implies name.where(use = 'official').given.exists()
iif(gender = 'male', 'M', iif(gender = 'female', 'F', 'U'))
coalesce(name.where(use='official'), name.where(use='usual'), name.first())
subject.resolve().ofType(Patient).birthDate
generalPractitioner.all(resolve() is Practitioner)
code.coding.where(system = 'http://snomed.info/sct').code
code.coding.exists(system = 'http://loinc.org' and code = '12345-6')
Questionnaire.repeat(item) // All nested items
ValueSet.expansion.repeat(contains) // All expansion concepts
Observation.value.ofType(Quantity).value > 100
(Observation.value as Quantity).value > 100
FHIRPath is used to define constraints in FHIR profiles:
// Name must have family or given
name.family.exists() or name.given.exists()
// If dosage exists, it must have timing or asNeeded
dosage.exists() implies (dosage.timing.exists() or dosage.asNeeded.exists())
// All references must be resolvable as Practitioner
performer.all(resolve() is Practitioner)
Patient.name.given + ' ' + Patient.name.family fails if multiple names{ } = { } returns { }, not true@2024 = @2024-01 returns { } (unknown).contains('x') is string function; contains x is operator[0])tools
Expert guidance for using WireMock in Java applications for HTTP API mocking and testing. Use this skill when the user asks to mock HTTP APIs, create API stubs, test REST clients, simulate network faults, verify HTTP requests, or integrate WireMock with Spring Boot. Trigger keywords include "wiremock", "mock http", "stub api", "http mock", "api testing", "rest mock", "simulate fault", "verify request", "spring boot wiremock".
documentation
Expert guidance for implementing SQL on FHIR v2 ViewDefinitions and operations to create portable, tabular projections of FHIR data. Use this skill when the user asks to create ViewDefinitions, flatten FHIR resources into tables, write FHIRPath expressions for data extraction, implement forEach/forEachOrNull/repeat patterns for unnesting, create where clauses for filtering, use constants in view definitions, combine data with unionAll, execute ViewDefinitions with $run or $export operations, or implement SQL on FHIR server capabilities. Trigger keywords include "ViewDefinition", "SQL on FHIR", "flatten FHIR", "tabular FHIR", "FHIR to SQL", "FHIR analytics", "FHIRPath columns", "unnest FHIR", "$viewdefinition-run", "$export", "view runner", "repeat", "recursive", "QuestionnaireResponse".
development
Expert guidance for working with the Apache Spark Catalyst query optimisation framework. Use this skill when working with Spark SQL internals, creating custom expressions, implementing query optimisations, working with logical/physical plans, or extending Catalyst. Trigger keywords include "catalyst", "spark sql", "expression", "logical plan", "physical plan", "tree node", "query optimisation", "rule executor", "analyzer", "optimizer", "code generation".
development
Expert guidance for using the SonarCloud API to interact with code quality analysis, projects, issues, quality gates, and metrics. Use this skill when making API calls to SonarCloud, automating code quality workflows, retrieving analysis results, managing projects programmatically, or integrating SonarCloud with CI/CD pipelines. Trigger keywords include "SonarCloud", "SonarCloud API", "code quality API", "SonarQube Cloud", "quality gate", "code analysis API", "SonarCloud measures", "SonarCloud issues".